++
+ static NSArray *getLovesInDocuments();
+ static bool deleteFileInDocuments(NSString *filename);
+
+@@ -391,10 +393,40 @@ std::string getExecutablePath()
+ }
+ }
+
+-void vibrate()
++void vibrate(const double seconds)
+ {
+ @autoreleasepool
+ {
++ struct utsname systemInfo;
++ uname(&systemInfo);
++ NSString *deviceString = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
++ NSRange iPhoneRange = [deviceString rangeOfString:@"iPhone"];
++ if (iPhoneRange.length == 6) {
++ NSRange commaRange = [deviceString rangeOfString:@","];
++ NSString *iPhone = [deviceString substringWithRange:iPhoneRange];
++ NSRange numRange = NSMakeRange(iPhoneRange.location + iPhoneRange.length, commaRange.location - iPhoneRange.location - iPhoneRange.length);
++ NSString *num = [deviceString substringWithRange:numRange];
++
++ if ([num intValue] >= 9) {
++ // iPhone 7 and above, see: https://gist.github.com/adamawolf/3048717#file-apple_mobile_device_types-txt-L22
++
++ if (@available(iOS 10.0, *)) {
++ // iOS 10.0 and above
++ UIImpactFeedbackGenerator *impact = nil;
++ if (seconds >= 0.5 && seconds < 1.5) {
++ impact = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight]; // 轻
++ } else if (seconds >= 1.5 && seconds < 2.5) {
++ impact = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleMedium]; // 中
++ } else if (seconds >= 2.5) {
++ impact = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleHeavy]; // 重
++ } else {
++ return;
++ }
++ [impact impactOccurred];
++ return;
++ }
++ }
++ }
+ AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
+ }
+ }
+diff --git a/src/love.cpp b/src/love.cpp
+index c8af8596..ae7a5e32 100644
+--- a/src/love.cpp
++++ b/src/love.cpp
+@@ -140,6 +140,10 @@ enum DoneAction
+ DONE_RESTART,
+ };
+
++extern "C" {
++ int luaopen_CCloader(lua_State *L);
++}
++
+ static DoneAction runlove(int argc, char **argv, int &retval)
+ {
+ // Oh, you just want the version? Okay!
+@@ -158,6 +162,9 @@ static DoneAction runlove(int argc, char **argv, int &retval)
+ lua_State *L = luaL_newstate();
+ luaL_openlibs(L);
+
++ // Init CCloader
++ luaopen_CCloader(L);
++
+ // LuaJIT-specific setup needs to be done as early as possible - before
+ // get_app_arguments because that loads external library code. This is also
+ // loaded inside require("love"). Note that it doesn't use the love table.
+diff --git a/src/modules/system/System.cpp b/src/modules/system/System.cpp
+index e1de16d5..e0f03557 100644
+--- a/src/modules/system/System.cpp
++++ b/src/modules/system/System.cpp
+@@ -174,7 +174,7 @@ void System::vibrate(double seconds) const
+ #ifdef LOVE_ANDROID
+ love::android::vibrate(seconds);
+ #elif defined(LOVE_IOS)
+- love::ios::vibrate();
++ love::ios::vibrate(seconds);
+ #else
+ LOVE_UNUSED(seconds);
+ #endif
diff --git a/.github/build/iOS/release/icon/icon_1024x1024.png b/.github/build/iOS/release/icon/icon_1024x1024.png
new file mode 100644
index 000000000..c80bf4202
Binary files /dev/null and b/.github/build/iOS/release/icon/icon_1024x1024.png differ
diff --git a/.github/build/iOS/release/icon/icon_20x20.png b/.github/build/iOS/release/icon/icon_20x20.png
new file mode 100644
index 000000000..93dac5191
Binary files /dev/null and b/.github/build/iOS/release/icon/icon_20x20.png differ
diff --git a/.github/build/iOS/release/icon/icon_20x20@2x.png b/.github/build/iOS/release/icon/icon_20x20@2x.png
new file mode 100644
index 000000000..887721240
Binary files /dev/null and b/.github/build/iOS/release/icon/icon_20x20@2x.png differ
diff --git a/.github/build/iOS/release/icon/icon_20x20@3x.png b/.github/build/iOS/release/icon/icon_20x20@3x.png
new file mode 100644
index 000000000..cace38818
Binary files /dev/null and b/.github/build/iOS/release/icon/icon_20x20@3x.png differ
diff --git a/.github/build/iOS/release/icon/icon_29x29.png b/.github/build/iOS/release/icon/icon_29x29.png
new file mode 100644
index 000000000..bab7dac11
Binary files /dev/null and b/.github/build/iOS/release/icon/icon_29x29.png differ
diff --git a/.github/build/iOS/release/icon/icon_29x29@2x.png b/.github/build/iOS/release/icon/icon_29x29@2x.png
new file mode 100644
index 000000000..bfb79f21a
Binary files /dev/null and b/.github/build/iOS/release/icon/icon_29x29@2x.png differ
diff --git a/.github/build/iOS/release/icon/icon_29x29@3x.png b/.github/build/iOS/release/icon/icon_29x29@3x.png
new file mode 100644
index 000000000..e1de7c286
Binary files /dev/null and b/.github/build/iOS/release/icon/icon_29x29@3x.png differ
diff --git a/.github/build/iOS/release/icon/icon_40x40.png b/.github/build/iOS/release/icon/icon_40x40.png
new file mode 100644
index 000000000..887721240
Binary files /dev/null and b/.github/build/iOS/release/icon/icon_40x40.png differ
diff --git a/.github/build/iOS/release/icon/icon_40x40@2x.png b/.github/build/iOS/release/icon/icon_40x40@2x.png
new file mode 100644
index 000000000..9f08f7614
Binary files /dev/null and b/.github/build/iOS/release/icon/icon_40x40@2x.png differ
diff --git a/.github/build/iOS/release/icon/icon_40x40@3x.png b/.github/build/iOS/release/icon/icon_40x40@3x.png
new file mode 100644
index 000000000..6ed8550ff
Binary files /dev/null and b/.github/build/iOS/release/icon/icon_40x40@3x.png differ
diff --git a/.github/build/iOS/release/icon/icon_60x60@2x.png b/.github/build/iOS/release/icon/icon_60x60@2x.png
new file mode 100644
index 000000000..6ed8550ff
Binary files /dev/null and b/.github/build/iOS/release/icon/icon_60x60@2x.png differ
diff --git a/.github/build/iOS/release/icon/icon_60x60@3x.png b/.github/build/iOS/release/icon/icon_60x60@3x.png
new file mode 100644
index 000000000..ec6b2bb4e
Binary files /dev/null and b/.github/build/iOS/release/icon/icon_60x60@3x.png differ
diff --git a/.github/build/iOS/release/icon/icon_76x76.png b/.github/build/iOS/release/icon/icon_76x76.png
new file mode 100644
index 000000000..ec239362d
Binary files /dev/null and b/.github/build/iOS/release/icon/icon_76x76.png differ
diff --git a/.github/build/iOS/release/icon/icon_76x76@2x.png b/.github/build/iOS/release/icon/icon_76x76@2x.png
new file mode 100644
index 000000000..1c0955c86
Binary files /dev/null and b/.github/build/iOS/release/icon/icon_76x76@2x.png differ
diff --git a/.github/build/iOS/release/icon/icon_83.5x83.5@2x.png b/.github/build/iOS/release/icon/icon_83.5x83.5@2x.png
new file mode 100644
index 000000000..d9968bd3a
Binary files /dev/null and b/.github/build/iOS/release/icon/icon_83.5x83.5@2x.png differ
diff --git a/.github/build/Linux/icon_snapshot.png b/.github/build/linux/dev/icon.png
similarity index 100%
rename from .github/build/Linux/icon_snapshot.png
rename to .github/build/linux/dev/icon.png
diff --git a/.github/build/Linux/icon.png b/.github/build/linux/release/icon.png
similarity index 100%
rename from .github/build/Linux/icon.png
rename to .github/build/linux/release/icon.png
diff --git a/.github/build/macOS/Techminodisk.icns b/.github/build/macOS/dev/dmg.icns
similarity index 100%
rename from .github/build/macOS/Techminodisk.icns
rename to .github/build/macOS/dev/dmg.icns
diff --git a/.github/build/macOS/backgroundImage.tiff b/.github/build/macOS/dev/dmg.png
similarity index 100%
rename from .github/build/macOS/backgroundImage.tiff
rename to .github/build/macOS/dev/dmg.png
diff --git a/.github/build/macOS/icon_snapshot.icns b/.github/build/macOS/dev/icon.icns
similarity index 100%
rename from .github/build/macOS/icon_snapshot.icns
rename to .github/build/macOS/dev/icon.icns
diff --git a/.github/build/macOS/info.plist.template b/.github/build/macOS/info.plist.template
deleted file mode 100644
index c4f251ef7..000000000
--- a/.github/build/macOS/info.plist.template
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-
-
- BuildMachineOSBuild
- 19B88
- CFBundleDevelopmentRegion
- English
- CFBundleExecutable
- love
- CFBundleIconFile
- iconfile
- CFBundleIdentifier
- @bundleId
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- Techmino
- CFBundlePackageType
- APPL
- CFBundleShortVersionString
- @versionName
- CFBundleSignature
- LoVe
- CFBundleSupportedPlatforms
-
- MacOSX
-
- DTCompiler
- com.apple.compilers.llvm.clang.1_0
- DTPlatformBuild
- 11C504
- DTPlatformVersion
- GM
- DTSDKBuild
- 19B90
- DTSDKName
- macosx10.15
- DTXcode
- 1130
- DTXcodeBuild
- 11C504
- LSApplicationCategoryType
- public.app-category.games
- LSMinimumSystemVersion
- 10.7
- NSHighResolutionCapable
-
- NSHumanReadableCopyright
- ©2020-@thisYear 26F Studio, GNU LGPLv3.0
- NSPrincipalClass
- NSApplication
- NSSupportsAutomaticGraphicsSwitching
-
-
-
diff --git a/.github/build/macOS/release/dmg.icns b/.github/build/macOS/release/dmg.icns
new file mode 100644
index 000000000..f1a560cbc
Binary files /dev/null and b/.github/build/macOS/release/dmg.icns differ
diff --git a/.github/build/macOS/release/dmg.png b/.github/build/macOS/release/dmg.png
new file mode 100644
index 000000000..e50fad1fc
Binary files /dev/null and b/.github/build/macOS/release/dmg.png differ
diff --git a/.github/build/macOS/icon.icns b/.github/build/macOS/release/icon.icns
similarity index 100%
rename from .github/build/macOS/icon.icns
rename to .github/build/macOS/release/icon.icns
diff --git a/.github/build/web/favicon.ico b/.github/build/web/favicon.ico
new file mode 100644
index 000000000..40793b9d8
Binary files /dev/null and b/.github/build/web/favicon.ico differ
diff --git a/.github/build/web/game.js b/.github/build/web/game.js
new file mode 100644
index 000000000..f0755e5f7
--- /dev/null
+++ b/.github/build/web/game.js
@@ -0,0 +1,288 @@
+
+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/index.html b/.github/build/web/index.html
new file mode 100644
index 000000000..8e28dc34e
--- /dev/null
+++ b/.github/build/web/index.html
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+ Techmino
+
+
+
+
+
+
+
+
Techmino
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.github/build/web/love.js b/.github/build/web/love.js
new file mode 100644
index 000000000..22e07ac9f
--- /dev/null
+++ b/.github/build/web/love.js
@@ -0,0 +1,22 @@
+
+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
new file mode 100644
index 000000000..ab96086b0
Binary files /dev/null and b/.github/build/web/love.wasm differ
diff --git a/.github/build/web/theme/bg.png b/.github/build/web/theme/bg.png
new file mode 100644
index 000000000..77ef798d9
Binary files /dev/null and b/.github/build/web/theme/bg.png differ
diff --git a/.github/build/web/theme/love.css b/.github/build/web/theme/love.css
new file mode 100644
index 000000000..96bc2c23b
--- /dev/null
+++ b/.github/build/web/theme/love.css
@@ -0,0 +1,49 @@
+* {
+ 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/build/windows/dev/.gitattributes b/.github/build/windows/dev/.gitattributes
new file mode 100644
index 000000000..20947f93f
--- /dev/null
+++ b/.github/build/windows/dev/.gitattributes
@@ -0,0 +1 @@
+*.rc text eol=crlf
diff --git a/.github/build/Windows/icon_snapshot.ico b/.github/build/windows/dev/icon.ico
similarity index 100%
rename from .github/build/Windows/icon_snapshot.ico
rename to .github/build/windows/dev/icon.ico
diff --git a/.github/build/windows/dev/template.rc b/.github/build/windows/dev/template.rc
new file mode 100644
index 000000000..f1774d581
--- /dev/null
+++ b/.github/build/windows/dev/template.rc
@@ -0,0 +1,26 @@
+1 VERSIONINFO
+FILEVERSION @FileVersion
+PRODUCTVERSION @FileVersion
+FILEOS 0x40004
+FILETYPE 0x1
+{
+ BLOCK "StringFileInfo"
+ {
+ BLOCK "040904B0"
+ {
+ VALUE "CompanyName", "26F Studio"
+ VALUE "FileDescription", "Techmino Development"
+ VALUE "FileVersion", "@Version"
+ VALUE "InternalName", "Techmino"
+ VALUE "LegalCopyright", "Copyright © 2019-2023 26F-Studio. Some Rights Reserved."
+ VALUE "OriginalFilename", "Techmino.exe"
+ VALUE "ProductName", "Techmino"
+ VALUE "ProductVersion", "@Version"
+ }
+ }
+
+ BLOCK "VarFileInfo"
+ {
+ VALUE "Translation", 0x0409 0x04E4
+ }
+}
diff --git a/.github/build/windows/release/.gitattributes b/.github/build/windows/release/.gitattributes
new file mode 100644
index 000000000..20947f93f
--- /dev/null
+++ b/.github/build/windows/release/.gitattributes
@@ -0,0 +1 @@
+*.rc text eol=crlf
diff --git a/.github/build/Windows/icon.ico b/.github/build/windows/release/icon.ico
similarity index 100%
rename from .github/build/Windows/icon.ico
rename to .github/build/windows/release/icon.ico
diff --git a/.github/build/Windows/Techmino.rc.template b/.github/build/windows/release/template.rc
similarity index 58%
rename from .github/build/Windows/Techmino.rc.template
rename to .github/build/windows/release/template.rc
index 30c8207da..1e94e1dd9 100644
--- a/.github/build/Windows/Techmino.rc.template
+++ b/.github/build/windows/release/template.rc
@@ -8,9 +8,12 @@ FILETYPE 0x1
{
BLOCK "040904B0"
{
- VALUE "FileDescription", "Techmino Alpha"
VALUE "CompanyName", "26F Studio"
- VALUE "LegalCopyright", "Copyright @ 26F Studio"
+ VALUE "FileDescription", "Techmino"
+ VALUE "FileVersion", "@Version"
+ VALUE "InternalName", "Techmino"
+ VALUE "LegalCopyright", "Copyright © 2019-2023 26F-Studio. Some Rights Reserved."
+ VALUE "OriginalFilename", "Techmino.exe"
VALUE "ProductName", "Techmino"
VALUE "ProductVersion", "@Version"
}
diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml
deleted file mode 100644
index dee4e5d07..000000000
--- a/.github/workflows/dev.yml
+++ /dev/null
@@ -1,203 +0,0 @@
-name: Techmino Develop CI
-
-on:
- push:
- branches: [ main, ci* ]
- pull_request:
- branches: [ main ]
-
-jobs:
- get-info:
- runs-on: ubuntu-20.04
- outputs:
- name: ${{ steps.actual-get-info.outputs.name }}
- apkCode: ${{ steps.actual-get-info.outputs.apkCode }}
- code: ${{ steps.actual-get-info.outputs.code }}
- commit: ${{ steps.actual-get-info.outputs.commit }}
- steps:
- - uses: actions/checkout@v2
- - name: Install lua
- run: |
- sudo apt-get install lua5.3 -y
- - name: Get Version
- id: actual-get-info
- run: |
- echo "::set-output name=name::$(lua .github/workflows/getVersion.lua -name)"
- echo "::set-output name=apkCode::$(lua .github/workflows/getVersion.lua -apkCode)"
- echo "::set-output name=code::$(lua .github/workflows/getVersion.lua -code)"
- echo "::set-output name=commit::$(git rev-parse --short ${{ GITHUB.SHA }})"
-
- automatic-test:
- runs-on: ubuntu-20.04
- steps:
- - uses: actions/checkout@v2
- - uses: ./.github/actions/automatic-test
-
- build-windows:
- runs-on: windows-latest
- needs: get-info
- steps:
- - uses: actions/checkout@v2
- - uses: ./.github/actions/update-version
- with:
- commit: ${{ needs.get-info.outputs.commit }}
- type: snapshot
- - uses: ./.github/actions/build-windows
- with:
- love-url: https://github.com/love2d/love/releases/download/11.3/love-11.3-win64.zip
- love-dir: love-11.3-win64
- arch: win64
- version: ${{ needs.get-info.outputs.name }}
- icon: .\.github\build\Windows\icon_snapshot.ico
- - name: Upload
- uses: actions/upload-artifact@v2
- with:
- name: Techmino_${{ needs.get-info.outputs.name }}_${{ GITHUB.RUN_NUMBER }}_${{ needs.get-info.outputs.commit }}_Windows
- path: love
-
- build-linux:
- runs-on: ubuntu-20.04
- needs: get-info
- steps:
- - uses: actions/checkout@v2
- - uses: ./.github/actions/update-version
- with:
- commit: ${{ needs.get-info.outputs.commit }}
- type: snapshot
- - uses: ./.github/actions/build-linux
- with:
- icon: .github/build/Linux/icon_snapshot.png
- - name: Upload
- uses: actions/upload-artifact@v2
- with:
- name: Techmino_${{ needs.get-info.outputs.name }}_${{ GITHUB.RUN_NUMBER }}_${{ needs.get-info.outputs.commit }}_Linux
- path: Techmino.AppImage
-
- build-android:
- runs-on: ubuntu-20.04
- needs: get-info
- steps:
- - uses: actions/checkout@v2
- - uses: ./.github/actions/update-version
- with:
- commit: ${{ needs.get-info.outputs.commit }}
- type: snapshot
- - uses: ./.github/actions/build-android
- with:
- type: Snapshot
- apkCode: ${{ needs.get-info.outputs.apkCode }}
- name: ${{ needs.get-info.outputs.name }}
- file-path: Techmino_Snapshot.apk
- SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
- KEY_STORE_PASSWORD: ${{ secrets.KEY_STORE_PASSWORD }}
- ALIAS: ${{ secrets.ALIAS }}
- KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
- - name: Upload
- uses: actions/upload-artifact@v2
- with:
- name: Techmino_${{ needs.get-info.outputs.name }}_${{ GITHUB.RUN_NUMBER }}_${{ needs.get-info.outputs.commit }}_Android
- path: Techmino_Snapshot.apk
-
- build-android-mini:
- runs-on: ubuntu-20.04
- needs: get-info
- steps:
- - uses: actions/checkout@v2
- - uses: ./.github/actions/update-version
- with:
- commit: ${{ needs.get-info.outputs.commit }}
- type: snapshot
- - name: remove media
- run: |
- rm -rf media/music media/effect media/vocal
- - uses: ./.github/actions/build-android
- with:
- type: Snapshot
- apkCode: ${{ needs.get-info.outputs.apkCode }}
- name: ${{ needs.get-info.outputs.name }}
- file-path: Techmino_Snapshot_Mini.apk
- SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
- KEY_STORE_PASSWORD: ${{ secrets.KEY_STORE_PASSWORD }}
- ALIAS: ${{ secrets.ALIAS }}
- KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
- - name: Upload
- uses: actions/upload-artifact@v2
- with:
- name: Techmino_${{ needs.get-info.outputs.name }}_${{ GITHUB.RUN_NUMBER }}_${{ needs.get-info.outputs.commit }}_Android_Mini
- path: Techmino_Snapshot_Mini.apk
-
- build-macOS:
- runs-on: macos-10.15
- needs: get-info
- steps:
- - uses: actions/checkout@v2
- - uses: ./.github/actions/update-version
- with:
- commit: ${{ needs.get-info.outputs.commit }}
- type: snapshot
- - uses: ./.github/actions/build-macos
- with:
- name: ${{ needs.get-info.outputs.name }}
- icon: .github/build/macOS/icon_snapshot.icns
- APPLE_API_ID: '${{ secrets.APPLE_API_ID }}'
- APPLE_API_ISSUER: '${{ secrets.APPLE_API_ISSUER }}'
- APPLE_API_KEY: '${{ secrets.APPLE_API_KEY }}'
- APPLE_APP_IDENTIFIER: '${{ secrets.APPLE_APP_IDENTIFIER }}'
- APPLE_KEYCHAIN_NAME: '${{ secrets.APPLE_KEYCHAIN_NAME }}'
- APPLE_KEYCHAIN_PWD: '${{ secrets.APPLE_KEYCHAIN_PWD }}'
- FASTLANE_MATCH_PWD: '${{ secrets.FASTLANE_MATCH_PWD }}'
- FASTLANE_MATCH_TOKEN: '${{ secrets.FASTLANE_MATCH_TOKEN }}'
- - name: Upload
- uses: actions/upload-artifact@v2
- with:
- name: Techmino_${{ needs.get-info.outputs.name }}_${{ GITHUB.RUN_NUMBER }}_${{ needs.get-info.outputs.commit }}_macOS
- path: Techmino.dmg
-
- build-iOS:
- runs-on: macos-latest
- if: (!startsWith( github.ref , 'refs/heads/ci-')) || startsWith( github.ref , 'refs/heads/ci-ios-')
- needs: get-info
- steps:
- - uses: actions/checkout@v2
- - uses: ./.github/actions/update-version
- with:
- commit: ${{ needs.get-info.outputs.commit }}
- type: snapshot
- - uses: ./.github/actions/build-ios
- with:
- name: ${{ needs.get-info.outputs.name }}
- type: 'dev'
- APPLE_API_ID: '${{ secrets.APPLE_API_ID }}'
- APPLE_API_ISSUER: '${{ secrets.APPLE_API_ISSUER }}'
- APPLE_API_KEY: '${{ secrets.APPLE_API_KEY }}'
- APPLE_APP_BUILD: '${{ needs.get-info.outputs.code }}.2.${{ github.run_number }}.${{ github.run_attempt }}'
- APPLE_APP_CHANGELOG: '${{ github.event.commits[0].message }}'
- APPLE_APP_ID: '${{ secrets.APPLE_APP_ID }}'
- APPLE_APP_IDENTIFIER: '${{ secrets.APPLE_APP_IDENTIFIER }}'
- APPLE_APP_PROFILE: '${{ secrets.APPLE_APP_PROFILE }}'
- APPLE_KEYCHAIN_NAME: '${{ secrets.APPLE_KEYCHAIN_NAME }}'
- APPLE_KEYCHAIN_PWD: '${{ secrets.APPLE_KEYCHAIN_PWD }}'
- FASTLANE_ACTION_ID: '${{ github.run_id }}'
- FASTLANE_DISCORD_WEBHOOK: '${{ secrets.FASTLANE_DISCORD_WEBHOOK }}'
- FASTLANE_MATCH_PWD: '${{ secrets.FASTLANE_MATCH_PWD }}'
- FASTLANE_MATCH_TOKEN: '${{ secrets.FASTLANE_MATCH_TOKEN }}'
- - name: Upload
- uses: actions/upload-artifact@v2
- with:
- name: Techmino_${{ needs.get-info.outputs.name }}_${{ GITHUB.RUN_NUMBER }}_${{ needs.get-info.outputs.commit }}_iOS
- path: Techmino.ipa
-
- build-love:
- runs-on: ubuntu-20.04
- needs: get-info
- steps:
- - uses: actions/checkout@v2
- - uses: ./.github/actions/update-version
- - uses: ./.github/actions/build-love
- with:
- file-path: Techmino.love
- - name: Upload
- uses: actions/upload-artifact@v2
- with:
- name: Techmino_${{ needs.get-info.outputs.name }}_${{ GITHUB.RUN_NUMBER }}_${{ needs.get-info.outputs.commit }}_Love
- path: Techmino.love
diff --git a/.github/workflows/getVersion.lua b/.github/workflows/getVersion.lua
deleted file mode 100644
index b50b09017..000000000
--- a/.github/workflows/getVersion.lua
+++ /dev/null
@@ -1,28 +0,0 @@
-local arg=arg[1]
-if arg=="-apkCode"then
- local code=require"version".apkCode
- print(code)
-elseif arg=="-code"then
- local str=require"version".code
- print(str)
-elseif arg=="-name"then
- local str=require"version".string
- print(str)
-elseif arg=="-release"then
- local str=require"version".string:gsub("V","",1)
- print(str)
-elseif arg=="-updateTitle"then
- local note=require"parts.updateLog"
- local p1=note:find("\n%d")+1
- local p2=note:find("\n",p1)-1
- note=note:sub(p1,p2)
- print(note)
-elseif arg=="-updateNote"then
- local note=require"parts.updateLog"
- local p1=note:find("\n",note:find("\n%d")+1)+1
- local p2=note:find("\n%d",p1+1)
- note=note:sub(p1,p2-2)
- :gsub(" ","- ")
- :gsub(" ","# ")
- print(note)
-end
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 000000000..99ab5c2ce
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,724 @@
+name: Techmino CI
+
+on:
+ push:
+ branches: [main, ci*]
+ tags: [pre*, v*]
+ pull_request:
+ branches: [main]
+
+env:
+ BUILD_TYPE: ${{ fromJSON('["dev", "release"]')[startsWith(github.ref, 'refs/tags/v')] }}
+ CORE_LOVE_PACKAGE_PATH: ./core.love
+ CORE_LOVE_ARTIFACT_NAME: core_love_package
+
+jobs:
+ get-info:
+ runs-on: ubuntu-latest
+ outputs:
+ app-name: ${{ steps.app-info.outputs.app-name }}
+ version-name: ${{ steps.app-info.outputs.version-name }}
+ version-string: ${{ steps.app-info.outputs.version-string }}
+ version-code: ${{ steps.app-info.outputs.version-code }}
+ update-title: ${{ steps.app-info.outputs.update-title }}
+ update-note: ${{ steps.app-info.outputs.update-note }}
+ commit-hash: ${{ steps.git-info.outputs.commit-hash }}
+ base-name: ${{ steps.assemble-base-name.outputs.base-name }}
+ steps:
+ - uses: actions/checkout@v3
+ - name: Install lua
+ run: |
+ sudo apt-get install lua5.3 -y
+ - name: Get app info
+ id: app-info
+ shell: lua {0}
+ run: |
+ local version = require "version"
+ os.execute('echo "app-name=Techmino" >> $GITHUB_OUTPUT')
+ os.execute('echo "version-name=' .. version.name .. '" >> $GITHUB_OUTPUT')
+ os.execute('echo "version-string=' .. version.string:gsub("%a", "") .. '" >> $GITHUB_OUTPUT')
+ os.execute('echo "version-code=' .. tostring(version.code) .. '" >> $GITHUB_OUTPUT')
+
+ local note = require 'parts.updateLog'
+ local p1 = note:find("\n%d") + 1
+ local p2 = note:find("\n", p1) - 1
+ os.execute('echo "update-title=' .. note:sub(p1, p2) .. '" >> $GITHUB_OUTPUT')
+ local p3 = note:find("\n", note:find("\n%d") + 1) + 1
+ local p4 = note:find("\n%d", p3 + 1)
+ updateNote = note:sub(p3, p4 - 2)
+ :gsub(" ", "- ")
+ :gsub(" ", "# ")
+ os.execute('echo "update-note<> $GITHUB_OUTPUT')
+ os.execute('echo "' .. updateNote .. '" >> $GITHUB_OUTPUT')
+ os.execute('echo "EOF" >> $GITHUB_OUTPUT')
+ - name: Get git info
+ id: git-info
+ shell: bash
+ run: |
+ COMMIT_HASH=$(git rev-parse --short ${{ GITHUB.SHA }})
+ echo "commit-hash=$COMMIT_HASH" >> $GITHUB_OUTPUT
+ - name: Assemble package base name
+ id: assemble-base-name
+ shell: bash
+ run: |
+ BASE_NAME=Techmino_${{ steps.app-info.outputs.version-string }}_${{ steps.git-info.outputs.commit-hash }}_#${{ GITHUB.RUN_NUMBER }}
+ echo "base-name=$BASE_NAME" >> $GITHUB_OUTPUT
+
+ build-core:
+ runs-on: ubuntu-latest
+ needs: get-info
+ 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('product-name=' + re.sub(r'[^A-Za-z0-9]+', '_', '${{ needs.get-info.outputs.app-name }}') + '\n')
+ - uses: ./.github/actions/update-version
+ if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
+ with:
+ commit: ${{ needs.get-info.outputs.commit-hash }}
+ type: snapshot
+ - name: Build core love package
+ uses: love-actions/love-actions-core@v1
+ with:
+ build-list: ./media/ ./parts/ ./Zframework/ ./conf.lua ./main.lua ./version.lua
+ package-path: ${{ env.CORE_LOVE_PACKAGE_PATH }}
+ - name: Upload core love package
+ uses: actions/upload-artifact@v3
+ 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
+ zip -u ${{ env.CORE_LOVE_PACKAGE_PATH }} media/image/icon.png
+ rm media/image/icon.png
+ - name: Rename love package
+ run: |
+ 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
+ with:
+ name: ${{ needs.get-info.outputs.base-name }}_Core_love
+ path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.love
+ - 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 }}.love ${{ env.RELEASE_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_Bare.love
+ - 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 }}_Bare.love
+ body: ${{ needs.get-info.outputs.update-note }}
+ name: ${{ needs.get-info.outputs.update-title }}
+ prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
+
+ auto-test:
+ runs-on: ubuntu-latest
+ needs: build-core
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ submodules: recursive
+ - name: Love actions for testing
+ uses: love-actions/love-actions-test@v1
+ with:
+ font-path: ./parts/fonts/proportional.otf
+ language-folder: ./parts/language
+
+ build-android:
+ runs-on: ubuntu-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:
+ 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')
+ f.write('product-name=' + re.sub(r'[^A-Za-z0-9]+', '-', '${{ needs.get-info.outputs.app-name }}') + '_Snapshot\n')
+ else:
+ 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
+ with:
+ name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
+ - name: Download ColdClear
+ uses: ./.github/actions/get-cc
+ with:
+ platform: Android
+ dir: ./libAndroid
+ - name: Build Android packages
+ id: build-packages
+ uses: love-actions/love-actions-android@main
+ with:
+ app-name: ${{ needs.get-info.outputs.app-name }}
+ bundle-id: ${{ steps.process-app-name.outputs.bundle-id }}
+ icon-specifier: "@mipmap/icon"
+ keystore-alias: ${{ secrets.ANDROID_KEYSTORE_ALIAS }}
+ keystore-base64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
+ 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/
+ 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
+ with:
+ name: ${{ needs.get-info.outputs.base-name }}_Android_release
+ path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}-release.apk
+ - 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 }}-release.apk ${{ env.RELEASE_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_Android.apk
+ - 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 }}_Android.apk
+ body: ${{ needs.get-info.outputs.update-note }}
+ name: ${{ needs.get-info.outputs.update-title }}
+ prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
+
+ build-ios:
+ 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: iOS
+ dir: ./ColdClear
+ - name: Build iOS packages
+ id: build-packages
+ uses: love-actions/love-actions-ios@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/iOS/${{ env.BUILD_TYPE }}/icon
+ love-patch: ./.github/build/iOS/love.patch
+ love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
+ libs-path: ./ColdClear/arm64/
+ product-name: ${{ steps.process-app-name.outputs.product-name }}
+ version-string: ${{ needs.get-info.outputs.version-string }}
+ output-folder: ${{ env.OUTPUT_FOLDER }}
+ apple-development-base64: ${{ secrets.APPLE_CERT_APPLE_DEVELOPMENT_BASE64 }}
+ apple-development-password: ${{ secrets.APPLE_CERT_APPLE_DEVELOPMENT_PWD }}
+ api-key: ${{ secrets.APPLE_API_KEY }}
+ api-key-id: ${{ secrets.APPLE_API_KEY_ID }}
+ api-issuer-id: ${{ secrets.APPLE_API_ISSUER_ID }}
+ team-id: ${{ secrets.APPLE_DEVELOPER_TEAM_ID }}
+ apple-id: ${{ secrets.APPLE_APPLE_ID }}
+ external-test: ${{ startsWith(github.ref, 'refs/tags/pre') }}
+ store-release: ${{ startsWith(github.ref, 'refs/tags/v') }}
+ - name: Upload logs artifact
+ uses: actions/upload-artifact@v3
+ with:
+ name: ${{ needs.get-info.outputs.base-name }}_iOS_logs
+ path: |
+ ${{ env.OUTPUT_FOLDER }}/DistributionSummary.plist
+ ${{ env.OUTPUT_FOLDER }}/ExportOptions.plist
+ ${{ env.OUTPUT_FOLDER }}/Packaging.log
+ - name: Upload ipa artifact
+ uses: actions/upload-artifact@v3
+ with:
+ name: ${{ needs.get-info.outputs.base-name }}_iOS_ipa
+ path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.ipa
+ - 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 }}.ipa ${{ env.RELEASE_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_iOS.ipa
+ - 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 }}_iOS.ipa
+ body: ${{ needs.get-info.outputs.update-note }}
+ name: ${{ needs.get-info.outputs.update-title }}
+ prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
+
+ build-linux:
+ runs-on: ubuntu-latest
+ needs: [get-info, build-core, auto-test]
+ 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
+
+ product_name = re.sub(r'[^A-Za-z0-9]+', '-', '${{ needs.get-info.outputs.app-name }}').strip('-').lower()
+ with open(os.getenv('GITHUB_OUTPUT'), 'a') as f:
+ 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
+ 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
+ zip -u ${{ env.CORE_LOVE_PACKAGE_PATH }} media/image/icon.png
+ rm media/image/icon.png
+ - name: Download ColdClear
+ uses: ./.github/actions/get-cc
+ with:
+ platform: Linux
+ dir: ./ColdClear
+ - name: Process ColdClear
+ shell: bash
+ run: |
+ cd ./ColdClear
+ 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
+ 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
+ love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
+ lib-path: ./ColdClear/lib
+ product-name: ${{ steps.process-app-name.outputs.product-name }}
+ output-folder: ${{ env.OUTPUT_FOLDER }}
+ - name: Upload AppImage artifact
+ uses: actions/upload-artifact@v3
+ 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
+ with:
+ name: ${{ needs.get-info.outputs.base-name }}_Linux_Debian
+ path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.deb
+ - 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 }}.AppImage ${{ env.RELEASE_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_Linux.AppImage
+ cp ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.deb ${{ env.RELEASE_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_Linux.deb
+ - 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 }}_Linux.AppImage
+ ${{ env.RELEASE_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_Linux.deb
+ body: ${{ needs.get-info.outputs.update-note }}
+ name: ${{ needs.get-info.outputs.update-title }}
+ prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
+
+ build-macos-appstore:
+ 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-appstore@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 }}
+ apple-development-base64: ${{ secrets.APPLE_CERT_APPLE_DEVELOPMENT_BASE64 }}
+ apple-development-password: ${{ secrets.APPLE_CERT_APPLE_DEVELOPMENT_PWD }}
+ api-key: ${{ secrets.APPLE_API_KEY }}
+ api-key-id: ${{ secrets.APPLE_API_KEY_ID }}
+ api-issuer-id: ${{ secrets.APPLE_API_ISSUER_ID }}
+ team-id: ${{ secrets.APPLE_DEVELOPER_TEAM_ID }}
+ apple-id: ${{ secrets.APPLE_APPLE_ID }}
+ external-test: ${{ startsWith(github.ref, 'refs/tags/pre') }}
+ store-release: ${{ startsWith(github.ref, 'refs/tags/v') }}
+ - name: Upload logs artifact
+ uses: actions/upload-artifact@v3
+ with:
+ name: ${{ needs.get-info.outputs.base-name }}_macOS_appstore_logs
+ path: |
+ ${{ env.OUTPUT_FOLDER }}/DistributionSummary.plist
+ ${{ env.OUTPUT_FOLDER }}/ExportOptions.plist
+ ${{ env.OUTPUT_FOLDER }}/Packaging.log
+ - name: Upload pkg artifact
+ uses: actions/upload-artifact@v3
+ with:
+ name: ${{ needs.get-info.outputs.base-name }}_macOS_appstore_pkg
+ path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.pkg
+ - 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_appstore.pkg
+ - 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_appstore.pkg
+ body: ${{ needs.get-info.outputs.update-note }}
+ 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:
+ runs-on: ubuntu-latest
+ needs: [get-info, build-core, auto-test]
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ submodules: recursive
+ - name: Download core love package
+ uses: actions/download-artifact@v3
+ with:
+ name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
+ - name: Move core love package
+ run: |
+ mv ${{ env.CORE_LOVE_PACKAGE_PATH }} ./.github/build/web/game.data
+ - name: Deploy to GitHub Pages
+ uses: crazy-max/ghaction-github-pages@v3
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ build_dir: ./.github/build/web/
+ 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/
+
+ build-windows:
+ runs-on: windows-latest
+ needs: [get-info, build-core, auto-test]
+ 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('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: Windows
+ dir: ./ColdClear
+ - 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:
+ data = file.read()
+ data = data\
+ .replace("@Version", version_string)\
+ .replace("@FileVersion", file_version)
+ file.seek(0)
+ file.truncate()
+ file.write(data)
+ - name: Build Windows packages
+ id: build-packages
+ uses: love-actions/love-actions-windows@v1
+ with:
+ icon-path: ./.github/build/windows/${{ env.BUILD_TYPE }}/icon.ico
+ rc-path: ./.github/build/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
+ 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
+ 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
+ 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
+ with:
+ name: ${{ needs.get-info.outputs.base-name }}_Windows_installer
+ path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_installer.exe
+ - 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 }}_x86.zip ${{ env.RELEASE_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_Windows_x86.zip
+ cp ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_x64.zip ${{ env.RELEASE_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_Windows_x64.zip
+ cp ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_installer.exe ${{ env.RELEASE_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_Windows_installer.exe
+ - 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 }}_Windows_x86.zip
+ ${{ env.RELEASE_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_Windows_x64.zip
+ ${{ env.RELEASE_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_Windows_installer.exe
+ body: ${{ needs.get-info.outputs.update-note }}
+ name: ${{ needs.get-info.outputs.update-title }}
+ prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
+
+ post-build:
+ runs-on: ubuntu-latest
+ if: ${{ always() }}
+ needs:
+ [
+ get-info,
+ auto-test,
+ build-core,
+ build-android,
+ build-ios,
+ build-linux,
+ build-macos-appstore,
+ build-macos-portable,
+ build-web,
+ 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
+ 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**iOS:** ${{ needs.build-ios.result }}\n**Linux:** ${{ needs.build-linux.result }}\n**macOS App Store:** ${{ needs.build-macos-appstore.result }}\n**macOS portable:** ${{ needs.build-macos-portable.result }}\n**Windows:** ${{ needs.build-windows.result }}"}
+ ]
+ }'
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
deleted file mode 100644
index 1fd139632..000000000
--- a/.github/workflows/release.yml
+++ /dev/null
@@ -1,189 +0,0 @@
-name: Techmino Release CI
-
-on:
- push:
- tags:
- - "v*"
-
-jobs:
- get-info:
- runs-on: ubuntu-20.04
- outputs:
- name: ${{ steps.actual-get-info.outputs.name }}
- apkCode: ${{ steps.actual-get-info.outputs.apkCode }}
- code: ${{ steps.actual-get-info.outputs.code }}
- release: ${{ steps.actual-get-info.outputs.release }}
- updateTitle: ${{ steps.actual-get-info.outputs.updateTitle }}
- updateNote: ${{ steps.actual-get-info.outputs.updateNote }}
- commit: ${{ steps.actual-get-info.outputs.commit }}
- steps:
- - uses: actions/checkout@v2
- - name: Install lua
- run: |
- sudo apt-get install lua5.3 -y
- - name: Get Version
- id: actual-get-info
- run: |
- UPDATE_NOTE=$(lua .github/workflows/getVersion.lua -updateNote)
- UPDATE_NOTE="${UPDATE_NOTE//'%'/'%25'}"
- UPDATE_NOTE="${UPDATE_NOTE//$'\n'/'%0A'}"
- UPDATE_NOTE="${UPDATE_NOTE//$'\r'/'%0D'}"
- echo "::set-output name=name::$(lua .github/workflows/getVersion.lua -name)"
- echo "::set-output name=apkCode::$(lua .github/workflows/getVersion.lua -apkCode)"
- echo "::set-output name=code::$(lua .github/workflows/getVersion.lua -code)"
- echo "::set-output name=release::$(lua .github/workflows/getVersion.lua -release)"
- echo "::set-output name=updateTitle::$(lua .github/workflows/getVersion.lua -updateTitle)"
- echo "::set-output name=updateNote::$UPDATE_NOTE"
- echo "::set-output name=commit::$(git rev-parse --short ${{ GITHUB.SHA }})"
-
- build-windows-x64:
- runs-on: windows-latest
- needs: get-info
- steps:
- - uses: actions/checkout@v2
- - uses: ./.github/actions/update-version
- - uses: ./.github/actions/build-windows
- with:
- love-url: https://github.com/love2d/love/releases/download/11.3/love-11.3-win64.zip
- love-dir: love-11.3-win64
- arch: win64
- version: ${{ needs.get-info.outputs.release }}
- icon: .\.github\build\Windows\icon.ico
- - name: Pack Techmino
- run: 7z a -tzip .\Techmino_a${{ needs.get-info.outputs.release }}_Win64.zip .\love
- - name: Release
- uses: softprops/action-gh-release@v1
- with:
- name: ${{ needs.get-info.outputs.updateTitle }}
- files: Techmino_a${{ needs.get-info.outputs.release }}_Win64.zip
-
- build-windows-x86:
- runs-on: windows-latest
- needs: get-info
- steps:
- - uses: actions/checkout@v2
- - uses: ./.github/actions/update-version
- - uses: ./.github/actions/build-windows
- with:
- love-url: https://github.com/love2d/love/releases/download/11.3/love-11.3-win32.zip
- love-dir: love-11.3-win32
- arch: win32
- version: ${{ needs.get-info.outputs.release }}
- icon: .\.github\build\Windows\icon.ico
- - name: Pack Techmino
- run: 7z a -tzip .\Techmino_a${{ needs.get-info.outputs.release }}_Win32.zip .\love
- - name: Release
- uses: softprops/action-gh-release@v1
- with:
- name: ${{ needs.get-info.outputs.updateTitle }}
- files: Techmino_a${{ needs.get-info.outputs.release }}_Win32.zip
-
- build-linux:
- runs-on: ubuntu-20.04
- needs: get-info
- steps:
- - uses: actions/checkout@v2
- - uses: ./.github/actions/update-version
- - uses: ./.github/actions/build-linux
- with:
- file-path: Techmino_a${{ needs.get-info.outputs.release }}_Linux.AppImage
- icon: .github/build/Linux/icon.png
- - name: Release
- uses: softprops/action-gh-release@v1
- with:
- name: ${{ needs.get-info.outputs.updateTitle }}
- files: Techmino_a${{ needs.get-info.outputs.release }}_Linux.AppImage
-
- build-android:
- runs-on: ubuntu-20.04
- needs: get-info
- steps:
- - uses: actions/checkout@v2
- - uses: ./.github/actions/update-version
- - uses: ./.github/actions/build-android
- with:
- type: Release
- apkCode: ${{ needs.get-info.outputs.apkCode }}
- name: ${{ needs.get-info.outputs.name }}
- file-path: Techmino_a${{ needs.get-info.outputs.release }}_Android.apk
- SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
- KEY_STORE_PASSWORD: ${{ secrets.KEY_STORE_PASSWORD }}
- ALIAS: ${{ secrets.ALIAS }}
- KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
- - name: Release
- uses: softprops/action-gh-release@v1
- with:
- name: ${{ needs.get-info.outputs.updateTitle }}
- files: Techmino_a${{ needs.get-info.outputs.release }}_Android.apk
-
- build-macOS:
- runs-on: macos-10.15
- needs: get-info
- steps:
- - uses: actions/checkout@v2
- - uses: ./.github/actions/update-version
- - uses: ./.github/actions/build-macos
- with:
- name: ${{ needs.get-info.outputs.name }}
- icon: .github/build/macOS/icon.icns
- APPLE_API_ID: "${{ secrets.APPLE_API_ID }}"
- APPLE_API_ISSUER: "${{ secrets.APPLE_API_ISSUER }}"
- APPLE_API_KEY: "${{ secrets.APPLE_API_KEY }}"
- APPLE_APP_IDENTIFIER: "${{ secrets.APPLE_APP_IDENTIFIER }}"
- APPLE_KEYCHAIN_NAME: "${{ secrets.APPLE_KEYCHAIN_NAME }}"
- APPLE_KEYCHAIN_PWD: "${{ secrets.APPLE_KEYCHAIN_PWD }}"
- FASTLANE_MATCH_PWD: "${{ secrets.FASTLANE_MATCH_PWD }}"
- FASTLANE_MATCH_TOKEN: "${{ secrets.FASTLANE_MATCH_TOKEN }}"
- - name: Pack Techmino
- run: |
- mv Techmino.dmg Techmino_a${{ needs.get-info.outputs.release }}_MacOS.dmg
- - name: Release
- uses: softprops/action-gh-release@v1
- with:
- name: ${{ needs.get-info.outputs.updateTitle }}
- files: Techmino_a${{ needs.get-info.outputs.release }}_MacOS.dmg
-
- build-iOS:
- runs-on: macos-latest
- needs: get-info
- steps:
- - uses: actions/checkout@v2
- - uses: ./.github/actions/update-version
- - uses: ./.github/actions/build-ios
- with:
- name: ${{ needs.get-info.outputs.name }}
- type: "release"
- APPLE_API_ID: "${{ secrets.APPLE_API_ID }}"
- APPLE_API_ISSUER: "${{ secrets.APPLE_API_ISSUER }}"
- APPLE_API_KEY: "${{ secrets.APPLE_API_KEY }}"
- APPLE_APP_BUILD: "${{ needs.get-info.outputs.code }}.0.${{ github.run_number }}.${{ github.run_attempt }}"
- APPLE_APP_CHANGELOG: "${{ needs.get-info.outputs.updateNote }}"
- APPLE_APP_ID: "${{ secrets.APPLE_APP_ID }}"
- APPLE_APP_IDENTIFIER: "${{ secrets.APPLE_APP_IDENTIFIER }}"
- APPLE_APP_PROFILE: "${{ secrets.APPLE_APP_PROFILE }}"
- APPLE_KEYCHAIN_NAME: "${{ secrets.APPLE_KEYCHAIN_NAME }}"
- APPLE_KEYCHAIN_PWD: "${{ secrets.APPLE_KEYCHAIN_PWD }}"
- FASTLANE_ACTION_ID: "${{ github.run_id }}"
- FASTLANE_DISCORD_WEBHOOK: "${{ secrets.FASTLANE_DISCORD_WEBHOOK }}"
- FASTLANE_MATCH_PWD: "${{ secrets.FASTLANE_MATCH_PWD }}"
- FASTLANE_MATCH_TOKEN: "${{ secrets.FASTLANE_MATCH_TOKEN }}"
- - name: Rename ipa
- shell: bash
- run: |
- mv Techmino.ipa Techmino_a${{ needs.get-info.outputs.release }}_iOS.ipa
- - name: Release
- uses: softprops/action-gh-release@v1
- with:
- name: ${{ needs.get-info.outputs.updateTitle }}
- files: Techmino_a${{ needs.get-info.outputs.release }}_iOS.ipa
-
- Add-Release-note:
- runs-on: ubuntu-20.04
- needs: get-info
- steps:
- - uses: actions/checkout@v2
- - name: Release
- uses: softprops/action-gh-release@v1
- with:
- name: ${{ needs.get-info.outputs.updateTitle }}
- body: ${{ needs.get-info.outputs.updateNote }}
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
deleted file mode 100644
index 399d18620..000000000
--- a/.github/workflows/test.yml
+++ /dev/null
@@ -1,154 +0,0 @@
-name: Techmino Test CI
-
-on:
- push:
- tags:
- - 'pre*'
-
-jobs:
- get-info:
- runs-on: ubuntu-20.04
- outputs:
- name: ${{ steps.actual-get-info.outputs.name }}
- apkCode: ${{ steps.actual-get-info.outputs.apkCode }}
- code: ${{ steps.actual-get-info.outputs.code }}
- release: ${{ steps.actual-get-info.outputs.release }}
- commit: ${{ steps.actual-get-info.outputs.commit }}
- steps:
- - uses: actions/checkout@v2
- - name: Install lua
- run: |
- sudo apt-get install lua5.3 -y
- - name: Get Version
- id: actual-get-info
- run: |
- echo "::set-output name=name::$(lua .github/workflows/getVersion.lua -name)"
- echo "::set-output name=apkCode::$(lua .github/workflows/getVersion.lua -apkCode)"
- echo "::set-output name=code::$(lua .github/workflows/getVersion.lua -code)"
- echo "::set-output name=release::$(lua .github/workflows/getVersion.lua -release)"
- echo "::set-output name=commit::$(git rev-parse --short ${{ GITHUB.SHA }})"
-
- build-windows:
- runs-on: windows-latest
- needs: get-info
- steps:
- - uses: actions/checkout@v2
- - uses: ./.github/actions/update-version
- with:
- commit: ${{ needs.get-info.outputs.commit }}
- type: snapshot
- - uses: ./.github/actions/build-windows
- with:
- love-url: https://github.com/love2d/love/releases/download/11.3/love-11.3-win64.zip
- love-dir: love-11.3-win64
- arch: win64
- version: ${{ needs.get-info.outputs.name }}
- icon: .\.github\build\Windows\icon_snapshot.ico
- - name: Upload
- uses: actions/upload-artifact@v2
- with:
- name: Techmino_pre${{ needs.get-info.outputs.release }}_${{ needs.get-info.outputs.commit }}_Windows
- path: love
-
- build-linux:
- runs-on: ubuntu-20.04
- needs: get-info
- steps:
- - uses: actions/checkout@v2
- - uses: ./.github/actions/update-version
- with:
- commit: ${{ needs.get-info.outputs.commit }}
- type: snapshot
- - uses: ./.github/actions/build-linux
- with:
- icon: .github/build/Linux/icon_snapshot.png
- - name: Upload
- uses: actions/upload-artifact@v2
- with:
- name: Techmino_pre${{ needs.get-info.outputs.release }}_${{ needs.get-info.outputs.commit }}_Linux
- path: Techmino.AppImage
-
- build-android:
- runs-on: ubuntu-20.04
- needs: get-info
- steps:
- - uses: actions/checkout@v2
- - uses: ./.github/actions/update-version
- with:
- commit: ${{ needs.get-info.outputs.commit }}
- type: snapshot
- - uses: ./.github/actions/build-android
- with:
- type: Snapshot
- apkCode: ${{ needs.get-info.outputs.apkCode }}
- name: ${{ needs.get-info.outputs.name }}
- file-path: Techmino_Snapshot.apk
- SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
- KEY_STORE_PASSWORD: ${{ secrets.KEY_STORE_PASSWORD }}
- ALIAS: ${{ secrets.ALIAS }}
- KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
- - name: Upload
- uses: actions/upload-artifact@v2
- with:
- name: Techmino_pre${{ needs.get-info.outputs.release }}_${{ needs.get-info.outputs.commit }}_Android
- path: Techmino_Snapshot.apk
-
- build-macOS:
- runs-on: macos-10.15
- needs: get-info
- steps:
- - uses: actions/checkout@v2
- - uses: ./.github/actions/update-version
- with:
- commit: ${{ needs.get-info.outputs.commit }}
- type: snapshot
- - uses: ./.github/actions/build-macos
- with:
- name: ${{ needs.get-info.outputs.name }}
- icon: .github/build/macOS/icon_snapshot.icns
- APPLE_API_ID: '${{ secrets.APPLE_API_ID }}'
- APPLE_API_ISSUER: '${{ secrets.APPLE_API_ISSUER }}'
- APPLE_API_KEY: '${{ secrets.APPLE_API_KEY }}'
- APPLE_APP_IDENTIFIER: '${{ secrets.APPLE_APP_IDENTIFIER }}'
- APPLE_KEYCHAIN_NAME: '${{ secrets.APPLE_KEYCHAIN_NAME }}'
- APPLE_KEYCHAIN_PWD: '${{ secrets.APPLE_KEYCHAIN_PWD }}'
- FASTLANE_MATCH_PWD: '${{ secrets.FASTLANE_MATCH_PWD }}'
- FASTLANE_MATCH_TOKEN: '${{ secrets.FASTLANE_MATCH_TOKEN }}'
- - name: Upload
- uses: actions/upload-artifact@v2
- with:
- name: Techmino_pre${{ needs.get-info.outputs.release }}_${{ needs.get-info.outputs.commit }}_MacOS
- path: Techmino.dmg
-
- build-iOS:
- runs-on: macos-latest
- needs: get-info
- steps:
- - uses: actions/checkout@v2
- - uses: ./.github/actions/update-version
- with:
- commit: ${{ needs.get-info.outputs.commit }}
- type: snapshot
- - uses: ./.github/actions/build-ios
- with:
- name: ${{ needs.get-info.outputs.name }}
- type: 'test'
- APPLE_API_ID: '${{ secrets.APPLE_API_ID }}'
- APPLE_API_ISSUER: '${{ secrets.APPLE_API_ISSUER }}'
- APPLE_API_KEY: '${{ secrets.APPLE_API_KEY }}'
- APPLE_APP_BUILD: '${{ needs.get-info.outputs.code }}.1.${{ github.run_number }}.${{ github.run_attempt }}'
- APPLE_APP_CHANGELOG: '${{ github.event.commits[0].message }}'
- APPLE_APP_ID: '${{ secrets.APPLE_APP_ID }}'
- APPLE_APP_IDENTIFIER: '${{ secrets.APPLE_APP_IDENTIFIER }}'
- APPLE_APP_PROFILE: '${{ secrets.APPLE_APP_PROFILE }}'
- APPLE_KEYCHAIN_NAME: '${{ secrets.APPLE_KEYCHAIN_NAME }}'
- APPLE_KEYCHAIN_PWD: '${{ secrets.APPLE_KEYCHAIN_PWD }}'
- FASTLANE_ACTION_ID: '${{ github.run_id }}'
- FASTLANE_DISCORD_WEBHOOK: '${{ secrets.FASTLANE_DISCORD_WEBHOOK }}'
- FASTLANE_MATCH_PWD: '${{ secrets.FASTLANE_MATCH_PWD }}'
- FASTLANE_MATCH_TOKEN: '${{ secrets.FASTLANE_MATCH_TOKEN }}'
- - name: Upload
- uses: actions/upload-artifact@v2
- with:
- name: Techmino_pre${{ needs.get-info.outputs.release }}_${{ needs.get-info.outputs.commit }}_iOS
- path: Techmino.ipa
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 000000000..9f049b305
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "Zframework"]
+ path = Zframework
+ url = https://github.com/26F-Studio/Zframework.git
diff --git a/Zframework b/Zframework
new file mode 160000
index 000000000..359539073
--- /dev/null
+++ b/Zframework
@@ -0,0 +1 @@
+Subproject commit 3595390738cf1374dc54fe1210e38b0560764657
diff --git a/Zframework/background.lua b/Zframework/background.lua
deleted file mode 100644
index 22f817868..000000000
--- a/Zframework/background.lua
+++ /dev/null
@@ -1,56 +0,0 @@
-local gc_clear=love.graphics.clear
-local BGs={
- none={draw=function()gc_clear(.08,.08,.084)end}
-}
-local BGlist={'none'}
-local BG={
- default='none',
- locked=false,
- cur='none',
- init=false,
- resize=false,
- update=NULL,
- draw=BGs.none.draw,
- event=false,
- discard=NULL,
-}
-
-function BG.lock()BG.locked=true end
-function BG.unlock()BG.locked=false end
-function BG.add(name,bg)
- BGs[name]=bg
- BGlist[#BGlist+1]=name
-end
-function BG.getList()
- return BGlist
-end
-function BG.remList(name)
- table.remove(BGlist,TABLE.find(BGlist,name))
-end
-function BG.send(...)
- if BG.event then
- BG.event(...)
- end
-end
-function BG.setDefault(bg)
- BG.default=bg
-end
-function BG.set(name)
- name=name or BG.default
- if not BGs[name]or BG.locked then return end
- if name~=BG.cur then
- BG.discard()
- BG.cur=name
- local bg=BGs[name]
-
- BG.init= bg.init or NULL
- BG.resize= bg.resize or NULL
- BG.update= bg.update or NULL
- BG.draw= bg.draw or NULL
- BG.event= bg.event or NULL
- BG.discard=bg.discard or NULL
- BG.init()
- end
- return true
-end
-return BG
diff --git a/Zframework/bgm.lua b/Zframework/bgm.lua
deleted file mode 100644
index 924f1a46b..000000000
--- a/Zframework/bgm.lua
+++ /dev/null
@@ -1,182 +0,0 @@
-local lastLoaded={}
-local maxLoadedCount=3
-local nameList={}
-local SourceObjList={}
-local volume=1
-
-local BGM={
- default=false,
- onChange=NULL,
- --nowPlay=[str:playing ID]
- --playing=[src:playing SRC]
- --lastPlayed=[str:lastPlayed ID]
-}
-
-local function _tryReleaseSources()
- local n=#lastLoaded
- while #lastLoaded>maxLoadedCount do
- local name=lastLoaded[n]
- if SourceObjList[name].source:isPlaying()then
- n=n-1
- if n<=0 then return end
- else
- SourceObjList[name].source=SourceObjList[name].source:release()and nil
- table.remove(lastLoaded,n)
- return
- end
- end
-end
-local function _addFile(name,path)
- if not SourceObjList[name]then
- table.insert(nameList,name)
- SourceObjList[name]={path=path,source=false}
- end
-end
-
-function BGM.getList()return nameList end
-function BGM.getCount()return #nameList end
-function BGM.load(name,path)
- if type(name)=='table'then
- for k,v in next,name do
- _addFile(k,v)
- end
- else
- _addFile(name,path)
- end
- table.sort(nameList)
- LOG(BGM.getCount().." BGM files added")
-end
-
-function BGM.setDefault(bgm)
- BGM.default=bgm
-end
-function BGM.setMaxSources(count)
- maxLoadedCount=count
- _tryReleaseSources()
-end
-function BGM.setChange(func)
- BGM.onChange=func
-end
-function BGM.setVol(v)
- assert(type(v)=='number'and v>=0 and v<=1,'Wrong volume')
- volume=v
- if BGM.playing then
- if volume>0 then
- BGM.playing:setVolume(volume)
- BGM.playing:play()
- elseif BGM.nowPlay then
- BGM.playing:pause()
- end
- end
-end
-
-local function task_fadeOut(src)
- while true do
- coroutine.yield()
- local v=src:getVolume()-volume/40
- src:setVolume(v>0 and v or 0)
- if v<=0 then
- src:stop()
- return true
- end
- end
-end
-local function task_fadeIn(src)
- while true do
- coroutine.yield()
- local v=volume
- v=math.min(v,src:getVolume()+v/40)
- src:setVolume(v)
- if v>=volume then
- return true
- end
- end
-end
-local function check_curFadeOut(task,code,src)
- return task.code==code and task.args[1]==src
-end
-local function _tryLoad(name)
- if SourceObjList[name]then
- if SourceObjList[name].source then
- return true
- elseif love.filesystem.getInfo(SourceObjList[name].path)then
- SourceObjList[name].source=love.audio.newSource(SourceObjList[name].path,'stream')
- SourceObjList[name].source:setVolume(0)
- table.insert(lastLoaded,1,name)
- _tryReleaseSources()
- return true
- else
- LOG("No BGM: "..SourceObjList[name],5)
- end
- elseif name then
- LOG("No BGM: "..name,5)
- end
-end
-function BGM.play(name,args)
- name=name or BGM.default
- args=args or""
- if not _tryLoad(name)or args:sArg('-preLoad')then return end
- if volume==0 then
- BGM.nowPlay=name
- BGM.playing=SourceObjList[name].source
- return true
- end
- if name and SourceObjList[name].source then
- if BGM.nowPlay~=name then
- if BGM.nowPlay then
- if not args:sArg('-sdout')then
- TASK.new(task_fadeOut,BGM.playing)
- else
- BGM.playing:pause()
- end
- end
- TASK.removeTask_iterate(check_curFadeOut,task_fadeOut,SourceObjList[name].source)
- TASK.removeTask_code(task_fadeIn)
-
- BGM.nowPlay=name
- BGM.playing=SourceObjList[name].source
- if not args:sArg('-sdin')then
- BGM.playing:setVolume(0)
- TASK.new(task_fadeIn,BGM.playing)
- else
- BGM.playing:setVolume(volume)
- BGM.playing:play()
- end
- SourceObjList[name].source:setLooping(not args:sArg('-noloop'))
- BGM.lastPlayed=BGM.nowPlay
- BGM.playing:play()
- BGM.onChange(name)
- end
- return true
- end
-end
-function BGM.seek(t)
- if BGM.playing then
- BGM.playing:seek(t)
- end
-end
-function BGM.isPlaying()
- return BGM.playing and BGM.playing:isPlaying()
-end
-function BGM.continue()
- if BGM.lastPlayed then
- BGM.nowPlay,BGM.playing=BGM.lastPlayed,SourceObjList[BGM.lastPlayed].source
- TASK.removeTask_iterate(check_curFadeOut,task_fadeOut,SourceObjList[BGM.nowPlay].source)
- TASK.removeTask_code(task_fadeIn)
- TASK.new(task_fadeIn,BGM.playing)
- BGM.playing:play()
- end
-end
-function BGM.stop(args)
- args=args or""
- TASK.removeTask_code(task_fadeIn)
- if not args:sArg('-s')then
- if BGM.nowPlay then
- TASK.new(task_fadeOut,BGM.playing)
- end
- elseif BGM.playing then
- BGM.playing:pause()
- end
- BGM.nowPlay,BGM.playing=nil
-end
-return BGM
diff --git a/Zframework/color.lua b/Zframework/color.lua
deleted file mode 100644
index 3b1ded1c3..000000000
--- a/Zframework/color.lua
+++ /dev/null
@@ -1,148 +0,0 @@
-local abs=math.abs
-local function hsv(h,s,v,a)--Color type, Color amount, Light
- if s<=0 then return v,v,v,a end
- h=h*6
- local c=v*s
- local x=abs((h-1)%2-1)*c
- if h<1 then return v,x+v-c,v-c,a
- elseif h<2 then return x+v-c,v,v-c,a
- elseif h<3 then return v-c,v,x+v-c,a
- elseif h<4 then return v-c,x+v-c,v,a
- elseif h<5 then return x+v-c,v-c,v,a
- else return v,v-c,x+v-c,a
- end
-end
-
-local COLOR={
- hsv=hsv,
-
- red= {hsv(0.00, 0.89, 0.91)},
- fire= {hsv(0.04, 0.93, 0.94)},
- orange= {hsv(0.09, 0.99, 0.96)},
- yellow= {hsv(0.15, 0.82, 0.90)},
- lime= {hsv(0.20, 0.89, 0.88)},
- jade= {hsv(0.25, 1.00, 0.82)},
- green= {hsv(0.33, 1.00, 0.81)},
- aqua= {hsv(0.47, 1.00, 0.76)},
- cyan= {hsv(0.53, 1.00, 0.88)},
- navy= {hsv(0.56, 1.00, 1.00)},
- sea= {hsv(0.61, 1.00, 1.00)},
- blue= {hsv(0.64, 1.00, 0.95)},
- violet= {hsv(0.74, 1.00, 0.91)},
- purple= {hsv(0.80, 1.00, 0.81)},
- magenta= {hsv(0.86, 1.00, 0.78)},
- wine= {hsv(0.92, 0.98, 0.91)},
-
- lRed= {hsv(0.00, 0.38, 0.93)},
- lFire= {hsv(0.04, 0.45, 0.91)},
- lOrange= {hsv(0.10, 0.53, 0.92)},
- lYellow= {hsv(0.14, 0.61, 0.95)},
- lLime= {hsv(0.20, 0.66, 0.92)},
- lJade= {hsv(0.26, 0.56, 0.90)},
- lGreen= {hsv(0.34, 0.49, 0.89)},
- lAqua= {hsv(0.47, 0.59, 0.86)},
- lCyan= {hsv(0.51, 0.77, 0.88)},
- lNavy= {hsv(0.54, 0.80, 0.95)},
- lSea= {hsv(0.57, 0.72, 0.97)},
- lBlue= {hsv(0.64, 0.44, 0.96)},
- lViolet= {hsv(0.72, 0.47, 0.95)},
- lPurple= {hsv(0.80, 0.62, 0.89)},
- lMagenta= {hsv(0.86, 0.61, 0.89)},
- lWine= {hsv(0.93, 0.57, 0.92)},
-
- dRed= {hsv(0.00, 0.80, 0.48)},
- dFire= {hsv(0.04, 0.80, 0.34)},
- dOrange= {hsv(0.07, 0.80, 0.39)},
- dYellow= {hsv(0.12, 0.80, 0.37)},
- dLime= {hsv(0.20, 0.80, 0.26)},
- dJade= {hsv(0.29, 0.80, 0.27)},
- dGreen= {hsv(0.33, 0.80, 0.26)},
- dAqua= {hsv(0.46, 0.80, 0.24)},
- dCyan= {hsv(0.50, 0.80, 0.30)},
- dNavy= {hsv(0.58, 0.80, 0.42)},
- dSea= {hsv(0.64, 0.80, 0.40)},
- dBlue= {hsv(0.67, 0.80, 0.34)},
- dViolet= {hsv(0.71, 0.80, 0.35)},
- dPurple= {hsv(0.76, 0.80, 0.32)},
- dMagenta= {hsv(0.87, 0.80, 0.28)},
- dWine= {hsv(0.92, 0.80, 0.28)},
-
- black= {hsv(0.04, 0.04, 0.14)},
- dGray= {hsv(0.02, 0.05, 0.44)},
- gray= {hsv(0.02, 0.05, 0.65)},
- lGray= {hsv(0.02, 0.06, 0.86)},
- white= {hsv(0.01, 0.02, 0.99)},
-
- xGray= {hsv(0.00, 0.00, 0.35,.8)},
- lxGray= {hsv(0.00, 0.00, 0.62,.8)},
- dxGray= {hsv(0.00, 0.00, 0.16,.8)},
-}
-for k,v in next,{
- R='red', F='fire', O='orange', Y='yellow', L='lime', J='jade', G='green', A='aqua', C='cyan', N='navy', S='sea', B='blue', V='violet', P='purple', M='magenta', W='wine',
- lR='lRed',lF='lFire',lO='lOrange',lY='lYellow',lL='lLime',lJ='lJade',lG='lGreen',lA='lAqua',lC='lCyan',lN='lNavy',lS='lSea',lB='lBlue',lV='lViolet',lP='lPurple',lM='lMagenta',lW='lWine',
- dR='dRed',dF='dFire',dO='dOrange',dY='dYellow',dL='dLime',dJ='dJade',dG='dGreen',dA='dAqua',dC='dCyan',dN='dNavy',dS='dSea',dB='dBlue',dV='dViolet',dP='dPurple',dM='dMagenta',dW='dWine',
- D='black',dH='dGray',H='gray',lH='lGray',Z='white',
- X='xGray',lX='lxGray',dX='dxGray',
- --Remain letter: EIKQTUX
-}do
- COLOR[k]=COLOR[v]
-end
-setmetatable(COLOR,{__index=function(_,k)
- error("No color: "..tostring(k))
-end})
-
-
-do--Random generators
- local rnd=math.random
- local list_norm={'red','fire','orange','yellow','lime','jade','green','aqua','cyan','navy','sea','blue','violet','purple','magenta','wine'}
- local len_list_norm=#list_norm
- function COLOR.random_norm()
- return COLOR[list_norm[rnd(len_list_norm)]]
- end
-
- local list_bright={'lRed','lFire','lOrange','lYellow','lLime','lJade','lGreen','lAqua','lCyan','lNavy','lSea','lBlue','lViolet','lPurple','lMagenta','lWine'}
- local len_list_bright=#list_bright
- function COLOR.random_bright()
- return COLOR[list_bright[rnd(len_list_bright)]]
- end
-
- local list_dark={'dRed','dFire','dOrange','dYellow','dLime','dJade','dGreen','dAqua','dCyan','dNavy','dSea','dBlue','dViolet','dPurple','dMagenta','dWine'}
- local len_list_dark=#list_dark
- function COLOR.random_dark()
- return COLOR[list_dark[rnd(len_list_dark)]]
- end
-end
-
-do--Rainbow generators
- local sin=math.sin
- function COLOR.rainbow(phase,a)
- return
- sin(phase)*.4+.6,
- sin(phase+2.0944)*.4+.6,
- sin(phase-2.0944)*.4+.6,
- a
- end
- function COLOR.rainbow_light(phase,a)
- return
- sin(phase)*.2+.7,
- sin(phase+2.0944)*.2+.7,
- sin(phase-2.0944)*.2+.7,
- a
- end
- function COLOR.rainbow_dark(phase,a)
- return
- sin(phase)*.2+.4,
- sin(phase+2.0944)*.2+.4,
- sin(phase-2.0944)*.2+.4,
- a
- end
- function COLOR.rainbow_gray(phase,a)
- return
- sin(phase)*.16+.5,
- sin(phase+2.0944)*.16+.5,
- sin(phase-2.0944)*.16+.5,
- a
- end
-end
-
-return COLOR
diff --git a/Zframework/file.lua b/Zframework/file.lua
deleted file mode 100644
index 83b847c56..000000000
--- a/Zframework/file.lua
+++ /dev/null
@@ -1,105 +0,0 @@
-local fs=love.filesystem
-local FILE={}
-function FILE.load(name,args)
- if not args then args=''end
- if fs.getInfo(name)then
- local F=fs.newFile(name)
- assert(F:open'r','open error')
- local s=F:read()F:close()
- local mode=
- STRING.sArg(args,'-luaon')and'luaon'or
- STRING.sArg(args,'-lua')and'lua'or
- STRING.sArg(args,'-json')and'json'or
- STRING.sArg(args,'-string')and'string'or
- s:sub(1,6)=='return{'and'luaon'or
- (s:sub(1,1)=='['and s:sub(-1)==']'or s:sub(1,1)=='{'and s:sub(-1)=='}')and'json'or
- 'string'
- if mode=='luaon'then
- local func,err_mes=loadstring(s)
- if func then
- setfenv(func,{})
- local res=func()
- return assert(res,'decode error')
- else
- error('decode error: '..err_mes)
- end
- elseif mode=='lua'then
- local func,err_mes=loadstring(s)
- if func then
- local res=func()
- return assert(res,'run error')
- else
- error('compile error: '..err_mes)
- end
- elseif mode=='json'then
- local res=JSON.decode(s)
- if res then
- return res
- end
- error('decode error')
- elseif mode=='string'then
- return s
- else
- error('unknown mode')
- end
- else
- error('no file')
- end
-end
-function FILE.save(data,name,args)
- if not args then args=''end
- if STRING.sArg(args,'-d')and fs.getInfo(name)then
- error('duplicate')
- end
-
- if type(data)=='table'then
- if STRING.sArg(args,'-luaon')then
- data=TABLE.dump(data)
- if not data then
- error('encode error')
- end
- else
- data=JSON.encode(data)
- if not data then
- error('encode error')
- end
- end
- else
- data=tostring(data)
- end
-
- local F=fs.newFile(name)
- assert(F:open('w'),'open error')
- F:write(data)F:flush()F:close()
-end
-function FILE.clear(path)
- if fs.getRealDirectory(path)==SAVEDIR and fs.getInfo(path).type=='directory'then
- for _,name in next,fs.getDirectoryItems(path)do
- name=path..'/'..name
- if fs.getRealDirectory(name)==SAVEDIR then
- local t=fs.getInfo(name).type
- if t=='file'then
- fs.remove(name)
- end
- end
- end
- end
-end
-function FILE.clear_s(path)
- if path==''or(fs.getRealDirectory(path)==SAVEDIR and fs.getInfo(path).type=='directory')then
- for _,name in next,fs.getDirectoryItems(path)do
- name=path..'/'..name
- if fs.getRealDirectory(name)==SAVEDIR then
- local t=fs.getInfo(name).type
- if t=='file'then
- fs.remove(name)
- elseif t=='directory'then
- FILE.clear_s(name)
- fs.remove(name)
- end
- end
- end
- fs.remove(path)
- end
-end
-return FILE
diff --git a/Zframework/font.lua b/Zframework/font.lua
deleted file mode 100644
index 78238bd6c..000000000
--- a/Zframework/font.lua
+++ /dev/null
@@ -1,60 +0,0 @@
-local gc=love.graphics
-local set=gc.setFont
-local fontFiles,fontCache={},{}
-local defaultFont,defaultFallBack
-local curFont=false--Current using font object
-
-local FONT={}
-function FONT.setDefault(name)defaultFont=name end
-function FONT.setFallback(name)defaultFallBack=name end
-function FONT.rawget(s)
- if not fontCache[s]then
- fontCache[s]=gc.setNewFont(s,'light',gc.getDPIScale()*SCR.k*2)
- end
- return fontCache[s]
-end
-function FONT.rawset(s)
- set(fontCache[s]or FONT.rawget(s))
-end
-function FONT.load(fonts)
- for name,path in next,fonts do
- assert(love.filesystem.getInfo(path),STRING.repD("Font file $1($2) not exist!",name,path))
- fontFiles[name]=love.filesystem.newFile(path)
- fontCache[name]={}
- end
- FONT.reset()
-end
-function FONT.get(size,name)
- if not name then name=defaultFont end
- local f=fontCache[name][size]
- if not f then
- f=gc.setNewFont(fontFiles[name],size,'light',gc.getDPIScale()*SCR.k*2)
- if defaultFallBack and name~=defaultFallBack then
- f:setFallbacks(FONT.get(size,defaultFallBack))
- end
- fontCache[name][size]=f
- end
- return f
-end
-function FONT.set(size,name)
- if not name then name=defaultFont end
-
- local f=fontCache[name][size]
- if f~=curFont then
- curFont=f or FONT.get(size,name)
- set(curFont)
- end
-end
-function FONT.reset()
- for name,cache in next,fontCache do
- if type(cache)=='table'then
- for size in next,cache do
- cache[size]=FONT.get(size,name)
- end
- else
- fontCache[name]=FONT.rawget(name)
- end
- end
-end
-
-return FONT
diff --git a/Zframework/gcExtend.lua b/Zframework/gcExtend.lua
deleted file mode 100644
index 57cea2b00..000000000
--- a/Zframework/gcExtend.lua
+++ /dev/null
@@ -1,164 +0,0 @@
-local gc=love.graphics
-local setColor,printf,draw=gc.setColor,gc.printf,gc.draw
-local GC={}
-function GC.mStr(obj,x,y)printf(obj,x-626,y,1252,'center')end--Printf a string with 'center'
-function GC.simpX(obj,x,y)draw(obj,x-obj:getWidth()*.5,y)end--Simply draw an obj with x=obj:getWidth()/2
-function GC.simpY(obj,x,y)draw(obj,x,y-obj:getHeight()*.5)end--Simply draw an obj with y=obj:getWidth()/2
-function GC.X(obj,x,y,a,k)draw(obj,x,y,a,k,nil,obj:getWidth()*.5,0)end--Draw an obj with x=obj:getWidth()/2
-function GC.Y(obj,x,y,a,k)draw(obj,x,y,a,k,nil,0,obj:getHeight()*.5)end--Draw an obj with y=obj:getWidth()/2
-function GC.draw(obj,x,y,a,k)draw(obj,x,y,a,k,nil,obj:getWidth()*.5,obj:getHeight()*.5)end--Draw an obj with both middle X & Y
-function GC.outDraw(obj,div,x,y,a,k)
- local w,h=obj:getWidth()*.5,obj:getHeight()*.5
- draw(obj,x-div,y-div,a,k,nil,w,h)
- draw(obj,x-div,y+div,a,k,nil,w,h)
- draw(obj,x+div,y-div,a,k,nil,w,h)
- draw(obj,x+div,y+div,a,k,nil,w,h)
-end
-function GC.shadedPrint(str,x,y,mode,d,clr1,clr2)
- local w=1280
- if mode=='center'then
- x=x-w*.5
- elseif mode=='right'then
- x=x-w
- end
- if not d then d=1 end
- setColor(clr1 or COLOR.D)
- printf(str,x-d,y-d,w,mode)
- printf(str,x-d,y+d,w,mode)
- printf(str,x+d,y-d,w,mode)
- printf(str,x+d,y+d,w,mode)
- setColor(clr2 or COLOR.Z)
- printf(str,x,y,w,mode)
-end
-function GC.regularPolygon(mode,x,y,R,segments,r,phase)
- local X,Y={},{}
- local ang=phase or 0
- local angStep=6.283185307179586/segments
- for i=1,segments do
- X[i]=x+R*math.cos(ang)
- Y[i]=y+R*math.sin(ang)
- ang=ang+angStep
- end
- X[segments+1]=x+R*math.cos(ang)
- Y[segments+1]=y+R*math.sin(ang)
- local halfAng=6.283185307179586/segments/2
- local erasedLen=r*math.tan(halfAng)
- if mode=='line'then
- erasedLen=erasedLen+1--Fix 1px cover
- for i=1,segments do
- --Line
- local x1,y1,x2,y2=X[i],Y[i],X[i+1],Y[i+1]
- local dir=math.atan2(y2-y1,x2-x1)
- gc.line(x1+erasedLen*math.cos(dir),y1+erasedLen*math.sin(dir),x2-erasedLen*math.cos(dir),y2-erasedLen*math.sin(dir))
-
- --Arc
- ang=ang+angStep
- local R2=R-r/math.cos(halfAng)
- local arcCX,arcCY=x+R2*math.cos(ang),y+R2*math.sin(ang)
- gc.arc('line','open',arcCX,arcCY,r,ang-halfAng,ang+halfAng)
- end
- elseif mode=='fill'then
- local L={}
- for i=1,segments do
- --Line
- local x1,y1,x2,y2=X[i],Y[i],X[i+1],Y[i+1]
- local dir=math.atan2(y2-y1,x2-x1)
- table.insert(L,x1+erasedLen*math.cos(dir))
- table.insert(L,y1+erasedLen*math.sin(dir))
- table.insert(L,x2-erasedLen*math.cos(dir))
- table.insert(L,y2-erasedLen*math.sin(dir))
-
- --Arc
- ang=ang+angStep
- local R2=R-r/math.cos(halfAng)
- local arcCX,arcCY=x+R2*math.cos(ang),y+R2*math.sin(ang)
- gc.arc('fill','open',arcCX,arcCY,r,ang-halfAng,ang+halfAng)
- end
- gc.polygon('fill',L)
- else
- error("Draw mode should be 'line' or 'fill'")
- end
-end
-do--function GC.DO(L)
- local cmds={
- origin="origin",
- move="translate",
- scale="scale",
- rotate="rotate",
- shear="shear",
- clear="clear",
-
- setCL="setColor",
- setCM="setColorMask",
- setLW="setLineWidth",
- setLS="setLineStyle",
- setLJ="setLineJoin",
-
- print="print",
- rawFT=function(...)FONT.rawset(...)end,
- setFT=function(...)FONT.set(...)end,
- mText=GC.mStr,
- mDraw=GC.draw,
- mDrawX=GC.X,
- mDrawY=GC.Y,
- mOutDraw=GC.outDraw,
-
- draw="draw",
- line="line",
- fRect=function(...)gc.rectangle('fill',...)end,
- dRect=function(...)gc.rectangle('line',...)end,
- fCirc=function(...)gc.circle('fill',...)end,
- dCirc=function(...)gc.circle('line',...)end,
- fElps=function(...)gc.ellipse('fill',...)end,
- dElps=function(...)gc.ellipse('line',...)end,
- fPoly=function(...)gc.polygon('fill',...)end,
- dPoly=function(...)gc.polygon('line',...)end,
-
- dPie=function(...)gc.arc('line',...)end,
- dArc=function(...)gc.arc('line','open',...)end,
- dBow=function(...)gc.arc('line','closed',...)end,
- fPie=function(...)gc.arc('fill',...)end,
- fArc=function(...)gc.arc('fill','open',...)end,
- fBow=function(...)gc.arc('fill','closed',...)end,
-
- fRPol=function(...)GC.regularPolygon('fill',...)end,
- dRPol=function(...)GC.regularPolygon('line',...)end,
- }
- local sizeLimit=gc.getSystemLimits().texturesize
- function GC.DO(L)
- gc.push()
- ::REPEAT_tryAgain::
- local success,canvas=pcall(gc.newCanvas,math.min(L[1],sizeLimit),math.min(L[2],sizeLimit))
- if not success then
- sizeLimit=math.floor(sizeLimit*.8)
- goto REPEAT_tryAgain
- end
- gc.setCanvas(canvas)
- gc.origin()
- gc.clear(1,1,1,0)
- gc.setColor(1,1,1)
- gc.setLineWidth(1)
- for i=3,#L do
- local cmd=L[i][1]
- if type(cmd)=='boolean'and cmd then
- table.remove(L[i],1)
- cmd=L[i][1]
- end
- if type(cmd)=='string'then
- local func=cmds[cmd]
- if type(func)=='string'then
- func=gc[func]
- end
- if func then
- func(unpack(L[i],2))
- else
- error("No gc command: "..cmd)
- end
- end
- end
- gc.setCanvas()
- gc.pop()
- return canvas
- end
-end
-return GC
diff --git a/Zframework/image.lua b/Zframework/image.lua
deleted file mode 100644
index 7f5412300..000000000
--- a/Zframework/image.lua
+++ /dev/null
@@ -1,25 +0,0 @@
-local IMG={}
-function IMG.init(list)
- IMG.init=nil
-
- setmetatable(IMG,{__index=function(self,name)
- if type(list[name])=='table'then
- self[name]={}
- for i=1,#list[name]do
- self[name][i]=love.graphics.newImage(list[name][i])
- end
- elseif type(list[name])=='string'then
- self[name]=love.graphics.newImage(list[name])
- else
- LOG("No IMG: "..name)
- self[name]=PAPER
- end
- return self[name]
- end})
-
- function IMG.loadAll()
- for k in next,list do local _=IMG[k]end
- IMG.loadAll=nil
- end
-end
-return IMG
diff --git a/Zframework/init.lua b/Zframework/init.lua
deleted file mode 100644
index 400a62631..000000000
--- a/Zframework/init.lua
+++ /dev/null
@@ -1,885 +0,0 @@
-NONE={}function NULL()end PAPER=love.graphics.newCanvas(1,1)
-EDITING=""
-LOADED=false
-
---Pure lua modules (basic)
-MATH= require'Zframework.mathExtend'
-COLOR= require'Zframework.color'
-TABLE= require'Zframework.tableExtend'
-STRING= require'Zframework.stringExtend'
-PROFILE= require'Zframework.profile'
-JSON= require'Zframework.json'
-TEST= require'Zframework.test'
-
-do--Add pcall & MES for JSON lib
- local encode,decode=JSON.encode,JSON.decode
- JSON.encode=function(val)
- local a,b=pcall(encode,val)
- if a then
- return b
- elseif MES then
- MES.traceback()
- end
- end
- JSON.decode=function(str)
- local a,b=pcall(decode,str)
- if a then
- return b
- elseif MES then
- MES.traceback()
- end
- end
-end
-
---Pure lua modules (complex)
-LOG= require'Zframework.log'
-REQUIRE= require'Zframework.require'
-TASK= require'Zframework.task'
-WS= require'Zframework.websocket'
-LANG= require'Zframework.languages'
-
---Love-based modules (basic)
-FILE= require'Zframework.file'
-WHEELMOV= require'Zframework.wheelScroll'
-SCR= require'Zframework.screen'
-SCN= require'Zframework.scene'
-LIGHT= require'Zframework.light'
-
---Love-based modules (complex)
-GC= require'Zframework.gcExtend'
-FONT= require'Zframework.font'
-TEXT= require'Zframework.text'
-SYSFX= require'Zframework.sysFX'
-MES= require'Zframework.message'
-BG= require'Zframework.background'
-WIDGET= require'Zframework.widget'
-VIB= require'Zframework.vibrate'
-SFX= require'Zframework.sfx'
-IMG= require'Zframework.image'
-BGM= require'Zframework.bgm'
-VOC= require'Zframework.voice'
-
-local ms,kb=love.mouse,love.keyboard
-local KBisDown=kb.isDown
-
-local gc=love.graphics
-local gc_push,gc_pop,gc_clear,gc_discard=gc.push,gc.pop,gc.clear,gc.discard
-local gc_replaceTransform,gc_present=gc.replaceTransform,gc.present
-local gc_setColor,gc_setLineWidth=gc.setColor,gc.setLineWidth
-local gc_draw,gc_line,gc_circle,gc_print=gc.draw,gc.line,gc.circle,gc.print
-
-local WIDGET,SCR,SCN=WIDGET,SCR,SCN
-local xOy=SCR.xOy
-local ITP=xOy.inverseTransformPoint
-
-local max,min=math.max,math.min
-
-local devMode
-local mx,my,mouseShow,cursorSpd=640,360,false,0
-local jsState={}--map, joystickID->axisStates: {axisName->axisVal}
-local errData={}--list, each error create {mes={errMes strings},scene=sceneNameStr}
-
-local function drawCursor(_,x,y)
- gc_setColor(1,1,1)
- gc_setLineWidth(2)
- gc_circle(ms.isDown(1)and'fill'or'line',x,y,6)
-end
-local showPowerInfo=true
-local showClickFX=true
-local discardCanvas=false
-local frameMul=100
-local sleepInterval=1/60
-local onQuit=NULL
-
-local batteryImg=GC.DO{31,20,
- {'fRect',1,0,26,2},
- {'fRect',1,18,26,2},
- {'fRect',0,1,2,18},
- {'fRect',26,1,2,18},
- {'fRect',29,3,2,14},
-}
-local infoCanvas=gc.newCanvas(108,27)
-local function updatePowerInfo()
- local state,pow=love.system.getPowerInfo()
- gc.setCanvas(infoCanvas)
- gc_push('transform')
- gc.origin()
- gc_clear(0,0,0,.25)
- if state~='unknown'then
- gc_setLineWidth(4)
- if state=='nobattery'then
- gc_setColor(1,1,1)
- gc_setLineWidth(2)
- gc_line(74,5,100,22)
- elseif pow then
- if state=='charging'then gc_setColor(0,1,0)
- elseif pow>50 then gc_setColor(1,1,1)
- elseif pow>26 then gc_setColor(1,1,0)
- elseif pow==26 then gc_setColor(.5,0,1)
- else gc_setColor(1,0,0)
- end
- gc.rectangle('fill',76,6,pow*.22,14)
- if pow<100 then
- FONT.set(15)
- gc.setColor(COLOR.D)
- gc_print(pow,77,1)
- gc_print(pow,77,3)
- gc_print(pow,79,1)
- gc_print(pow,79,3)
- gc_setColor(COLOR.Z)
- gc_print(pow,78,2)
- end
- end
- gc_draw(batteryImg,73,3)
- end
- FONT.set(25)
- gc_print(os.date("%H:%M"),3,-5)
- gc_pop()
- gc.setCanvas()
-end
--------------------------------------------------------------
-local lastX,lastY=0,0--Last click pos
-local function _updateMousePos(x,y,dx,dy)
- if SCN.swapping then return end
- dx,dy=dx/SCR.k,dy/SCR.k
- if SCN.mouseMove then SCN.mouseMove(x,y,dx,dy)end
- if ms.isDown(1)then
- WIDGET.drag(x,y,dx,dy)
- else
- WIDGET.cursorMove(x,y)
- end
-end
-local function _triggerMouseDown(x,y,k)
- if devMode==1 then
- print(("(%d,%d)<-%d,%d ~~(%d,%d)<-%d,%d"):format(
- x,y,
- x-lastX,y-lastY,
- math.floor(x/10)*10,math.floor(y/10)*10,
- math.floor((x-lastX)/10)*10,math.floor((y-lastY)/10)*10
- ))
- end
- if SCN.swapping then return end
- if SCN.mouseDown then SCN.mouseDown(x,y,k)end
- WIDGET.press(x,y,k)
- lastX,lastY=x,y
- if showClickFX then SYSFX.newTap(3,x,y)end
-end
-local function mouse_update(dt)
- if not KBisDown('lctrl','rctrl')and KBisDown('up','down','left','right')then
- local dx,dy=0,0
- if KBisDown('up')then dy=dy-cursorSpd end
- if KBisDown('down')then dy=dy+cursorSpd end
- if KBisDown('left')then dx=dx-cursorSpd end
- if KBisDown('right')then dx=dx+cursorSpd end
- mx=max(min(mx+dx,1280),0)
- my=max(min(my+dy,720),0)
- if my==0 or my==720 then
- WIDGET.sel=false
- WIDGET.drag(0,0,0,-dy)
- end
- _updateMousePos(mx,my,dx,dy)
- cursorSpd=min(cursorSpd+dt*26,12.6)
- else
- cursorSpd=6
- end
-end
-local function gp_update(js,dt)
- local sx,sy=js._jsObj:getGamepadAxis('leftx'),js._jsObj:getGamepadAxis('lefty')
- if math.abs(sx)>.1 or math.abs(sy)>.1 then
- local dx,dy=0,0
- if sy<-.1 then dy=dy+2*sy*cursorSpd end
- if sy>.1 then dy=dy+2*sy*cursorSpd end
- if sx<-.1 then dx=dx+2*sx*cursorSpd end
- if sx>.1 then dx=dx+2*sx*cursorSpd end
- mx=max(min(mx+dx,1280),0)
- my=max(min(my+dy,720),0)
- if my==0 or my==720 then
- WIDGET.sel=false
- WIDGET.drag(0,0,0,-dy)
- end
- _updateMousePos(mx,my,dx,dy)
- cursorSpd=min(cursorSpd+dt*26,12.6)
- else
- cursorSpd=6
- end
-end
-function love.mousepressed(x,y,k,touch)
- if touch then return end
- mouseShow=true
- mx,my=ITP(xOy,x,y)
- _triggerMouseDown(mx,my,k)
-end
-function love.mousemoved(x,y,dx,dy,touch)
- if touch then return end
- mouseShow=true
- mx,my=ITP(xOy,x,y)
- _updateMousePos(mx,my,dx,dy)
-end
-function love.mousereleased(x,y,k,touch)
- if touch or SCN.swapping then return end
- mx,my=ITP(xOy,x,y)
- if SCN.mouseUp then SCN.mouseUp(mx,my,k)end
- if WIDGET.sel then
- WIDGET.release(mx,my)
- else
- if lastX and SCN.mouseClick and(mx-lastX)^2+(my-lastY)^2<62 then
- SCN.mouseClick(mx,my,k)
- end
- end
-end
-function love.wheelmoved(x,y)
- if SCN.swapping then return end
- if SCN.wheelMoved then
- SCN.wheelMoved(x,y)
- else
- WIDGET.unFocus()
- WIDGET.drag(0,0,0,100*y)
- end
-end
-
-function love.touchpressed(id,x,y)
- mouseShow=false
- if SCN.swapping then return end
- if not SCN.mainTouchID then
- SCN.mainTouchID=id
- WIDGET.unFocus(true)
- love.touchmoved(id,x,y,0,0)
- end
- x,y=ITP(xOy,x,y)
- lastX,lastY=x,y
- WIDGET.cursorMove(x,y)
- if SCN.touchDown then SCN.touchDown(x,y,id)end
- if kb.hasTextInput()then kb.setTextInput(false)end
-end
-function love.touchmoved(id,x,y,dx,dy)
- if SCN.swapping then return end
- x,y=ITP(xOy,x,y)
- if SCN.touchMove then SCN.touchMove(x,y,dx/SCR.k,dy/SCR.k,id)end
- WIDGET.drag(x,y,dx/SCR.k,dy/SCR.k)
-end
-function love.touchreleased(id,x,y)
- if SCN.swapping then return end
- x,y=ITP(xOy,x,y)
- if id==SCN.mainTouchID then
- WIDGET.press(x,y,1)
- WIDGET.release(x,y)
- WIDGET.cursorMove(x,y)
- WIDGET.unFocus()
- SCN.mainTouchID=false
- end
- if SCN.touchUp then SCN.touchUp(x,y,id)end
- if(x-lastX)^2+(y-lastY)^2<62 then
- if SCN.touchClick then SCN.touchClick(x,y)end
- if showClickFX then SYSFX.newTap(3,x,y)end
- end
-end
-
-local fnKey={NULL,NULL,NULL,NULL,NULL,NULL,NULL}
-local function noDevkeyPressed(key)
- if key=='f1'then fnKey[1]()
- elseif key=='f2'then fnKey[2]()
- elseif key=='f3'then fnKey[3]()
- elseif key=='f4'then fnKey[4]()
- elseif key=='f5'then fnKey[5]()
- elseif key=='f6'then fnKey[6]()
- elseif key=='f7'then fnKey[7]()
- elseif key=='f8'then devMode=nil MES.new('info',"DEBUG OFF",.2)
- elseif key=='f9'then devMode=1 MES.new('info',"DEBUG 1")
- elseif key=='f10'then devMode=2 MES.new('info',"DEBUG 2")
- elseif key=='f11'then devMode=3 MES.new('info',"DEBUG 3")
- elseif key=='f12'then devMode=4 MES.new('info',"DEBUG 4")
- elseif devMode==2 then
- local W=WIDGET.sel
- if W then
- if key=='left'then W.x=W.x-10
- elseif key=='right'then W.x=W.x+10
- elseif key=='up'then W.y=W.y-10
- elseif key=='down'then W.y=W.y+10
- elseif key==','then W.w=W.w-10
- elseif key=='.'then W.w=W.w+10
- elseif key=='/'then W.h=W.h-10
- elseif key=='\''then W.h=W.h+10
- elseif key=='['then W.font=W.font-5
- elseif key==']'then W.font=W.font+5
- else return true
- end
- else
- return true
- end
- else
- return true
- end
-end
-function love.keypressed(key,_,isRep)
- mouseShow=false
- if devMode and not noDevkeyPressed(key)then
- return
- elseif key=='f8'then
- devMode=1
- MES.new('info',"DEBUG ON",.2)
- elseif key=='f11'then
- SETTING.fullscreen=not SETTING.fullscreen
- applySettings()
- saveSettings()
- elseif not SCN.swapping then
- if EDITING==""and(not SCN.keyDown or SCN.keyDown(key,isRep))then
- local W=WIDGET.sel
- if key=='escape'and not isRep then
- SCN.back()
- elseif key=='up'or key=='down'or key=='left'or key=='right'then
- mouseShow=true
- if KBisDown('lctrl','rctrl')then
- if W and W.arrowKey then W:arrowKey(key)end
- end
- elseif key=='space'or key=='return'then
- mouseShow=true
- if not isRep then
- if showClickFX then SYSFX.newTap(3,mx,my)end
- _triggerMouseDown(mx,my,1)
- end
- else
- if W and W.keypress then
- W:keypress(key)
- end
- end
- end
- end
-end
-function love.keyreleased(i)
- if SCN.swapping then return end
- if SCN.keyUp then SCN.keyUp(i)end
-end
-
-function love.textedited(texts)
- EDITING=texts
-end
-function love.textinput(texts)
- WIDGET.textinput(texts)
-end
-
---analog sticks: -1, 0, 1 for neg, neutral, pos
---triggers: 0 for released, 1 for pressed
-local jsAxisEventName={
- leftx={'leftstick_left','leftstick_right'},
- lefty={'leftstick_up','leftstick_down'},
- rightx={'rightstick_left','rightstick_right'},
- righty={'rightstick_up','rightstick_down'},
- triggerleft='triggerleft',
- triggerright='triggerright'
-}
-local gamePadKeys={'a','b','x','y','back','guide','start','leftstick','rightstick','leftshoulder','rightshoulder','dpup','dpdown','dpleft','dpright'}
-local dPadToKey={
- dpup='up',
- dpdown='down',
- dpleft='left',
- dpright='right',
- start='return',
- back='escape',
-}
-function love.joystickadded(JS)
- table.insert(jsState,{
- _id=JS:getID(),
- _jsObj=JS,
- leftx=0,lefty=0,
- rightx=0,righty=0,
- triggerleft=0,triggerright=0
- })
- MES.new('info',"Joystick added")
-end
-function love.joystickremoved(JS)
- for i=1,#jsState do
- if jsState[i]._jsObj==JS then
- for j=1,#gamePadKeys do
- if JS:isGamepadDown(gamePadKeys[j])then
- love.gamepadreleased(JS,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)
- 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
- local js=jsState[1]
- if axis=='leftx'or axis=='lefty'or axis=='rightx'or axis=='righty'then
- local newVal=--range: [0,1]
- val>.4 and 1 or
- val<-.4 and -1 or
- 0
- if newVal~=js[axis]then
- if js[axis]==-1 then
- love.gamepadreleased(JS,jsAxisEventName[axis][1])
- elseif js[axis]~=0 then
- love.gamepadreleased(JS,jsAxisEventName[axis][2])
- end
- if newVal==-1 then
- love.gamepadpressed(JS,jsAxisEventName[axis][1])
- elseif newVal==1 then
- love.gamepadpressed(JS,jsAxisEventName[axis][2])
- end
- js[axis]=newVal
- end
- elseif axis=='triggerleft'or axis=='triggerright'then
- 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])
- else
- love.gamepadreleased(JS,jsAxisEventName[axis])
- end
- js[axis]=newVal
- end
- end
- end
-end
-function love.gamepadpressed(_,key)
- mouseShow=false
- if not SCN.swapping then
- local cursorCtrl
- if SCN.gamepadDown then
- cursorCtrl=SCN.gamepadDown(key)
- elseif SCN.keyDown then
- cursorCtrl=SCN.keyDown(dPadToKey[key]or key)
- else
- cursorCtrl=true
- end
- if cursorCtrl then
- key=dPadToKey[key]or key
- mouseShow=true
- local W=WIDGET.sel
- if key=='back'then
- SCN.back()
- elseif key=='up'or key=='down'or key=='left'or key=='right'then
- mouseShow=true
- if W and W.arrowKey then W:arrowKey(key)end
- elseif key=='return'then
- mouseShow=true
- if showClickFX then SYSFX.newTap(3,mx,my)end
- _triggerMouseDown(mx,my,1)
- else
- if W and W.keypress then
- W:keypress(key)
- end
- end
- end
- end
-end
-function love.gamepadreleased(_,i)
- if SCN.swapping then return end
- if SCN.gamepadUp then SCN.gamepadUp(i)end
-end
-
-function love.filedropped(file)
- if SCN.fileDropped then SCN.fileDropped(file)end
-end
-function love.directorydropped(dir)
- if SCN.directoryDropped then SCN.directoryDropped(dir)end
-end
-local autoGCcount=0
-function love.lowmemory()
- collectgarbage()
- if autoGCcount<3 then
- autoGCcount=autoGCcount+1
- MES.new('check',"[auto GC] low MEM 设备内存过低")
- end
-end
-
-local onResize=NULL
-function love.resize(w,h)
- if SCR.w==w and SCR.h==h then return end
- SCR.resize(w,h)
- if BG.resize then BG.resize(w,h)end
- if SCN.resize then SCN.resize(w,h)end
- WIDGET.resize(w,h)
- FONT.reset()
- onResize(w,h)
-end
-
-local onFocus=NULL
-function love.focus(f)onFocus(f)end
-
-local yield=coroutine.yield
-local function secondLoopThread()
- local mainLoop=love.run()
- repeat yield()until mainLoop()
-end
-function love.errorhandler(msg)
- if type(msg)~='string'then
- msg="Unknown error"
- elseif msg:find("Invalid UTF-8")and text then
- msg=text.tryAnotherBuild
- end
-
- --Generate error message
- local err={"Error:"..msg}
- local c=2
- for l in debug.traceback("",2):gmatch("(.-)\n")do
- if c>2 then
- if not l:find("boot")then
- err[c]=l:gsub("^\t*","")
- c=c+1
- end
- else
- err[2]="Traceback"
- c=3
- end
- end
- print(table.concat(err,"\n",1,c-2))
-
- --Reset something
- love.audio.stop()
- gc.reset()
-
- if LOADED and #errData<3 then
- BG.set('none')
- local scn=SCN and SCN.cur or"NULL"
- table.insert(errData,{mes=err,scene=scn})
-
- --Write messages to log file
- love.filesystem.append('conf/error.log',
- os.date("%Y/%m/%d %A %H:%M:%S\n")..
- #errData.." crash(es) "..love.system.getOS().."-"..VERSION.string.." scene: "..scn.."\n"..
- table.concat(err,"\n",1,c-2).."\n\n"
- )
-
- --Get screencapture
- gc.captureScreenshot(function(_)errData[#errData].shot=gc.newImage(_)end)
- gc.present()
-
- --Create a new mainLoop thread to keep game alive
- local status,resume=coroutine.status,coroutine.resume
- local loopThread=coroutine.create(secondLoopThread)
- local res,threadErr
- repeat
- res,threadErr=resume(loopThread)
- until status(loopThread)=='dead'
- if not res then
- love.errorhandler(threadErr)
- return
- end
- else
- ms.setVisible(true)
-
- local errorMsg
- errorMsg=LOADED and
- "Too many errors or fatal error occured.\nPlease restart the game."or
- "An error has occurred during loading.\nError info has been created, and you can send it to the author."
- while true do
- love.event.pump()
- for E,a,b in love.event.poll()do
- if E=='quit'or a=='escape'then
- return true
- elseif E=='resize'then
- SCR.resize(a,b)
- end
- end
- gc_clear(.3,.5,.9)
- gc_push('transform')
- gc_replaceTransform(SCR.xOy)
- FONT.set(100)gc_print(":(",100,0,0,1.2)
- FONT.set(40)gc.printf(errorMsg,100,160,SCR.w0-100)
- FONT.set(20)
- gc_print(love.system.getOS().."-"..VERSION.string.." scene:"..(SCN and SCN.cur or"NULL"),100,660)
- gc.printf(err[1],100,360,1260-100)
- gc_print("TRACEBACK",100,450)
- for i=4,#err-2 do
- gc_print(err[i],100,400+20*i)
- end
- gc_pop()
- gc_present()
- love.timer.sleep(.26)
- end
- end
-end
-love.threaderror=nil
-
-love.draw,love.update=nil--remove default draw/update
-
-local devColor={
- COLOR.Z,
- COLOR.lM,
- COLOR.lG,
- COLOR.lB,
-}
-local WS=WS
-local WSnames={'app','user','play','stream','chat','manage'}
-local wsImg={}do
- local L={78,18,
- {'clear',1,1,1,0},
- {'setCL',1,1,1,.3},
- {'fRect',60,0,18,18},
- }
- for i=0,59 do
- table.insert(L,{'setCL',1,1,1,i*.005})
- table.insert(L,{'fRect',i,0,1,18})
- end
- wsImg.bottom=GC.DO(L)
- wsImg.dead=GC.DO{20,20,
- {'rawFT',20},
- {'setCL',1,.3,.3},
- {'mText',"X",11,-1},
- }
- wsImg.connecting=GC.DO{20,20,
- {'rawFT',20},
- {'setLW',3},
- {'mText',"C",11,-1},
- }
- wsImg.running=GC.DO{20,20,
- {'rawFT',20},
- {'setCL',.5,1,0},
- {'mText',"R",11,-1},
- }
-end
-
-local debugInfos={
- {"Cache",gcinfo},
-}
-function love.run()
- local love=love
-
- local BG=BG
- local TEXT_update,TEXT_draw=TEXT.update,TEXT.draw
- local MES_update,MES_draw=MES.update,MES.draw
- local WS_update=WS.update
- local TASK_update=TASK.update
- local SYSFX_update,SYSFX_draw=SYSFX.update,SYSFX.draw
- local WIDGET_update,WIDGET_draw=WIDGET.update,WIDGET.draw
- local STEP,WAIT=love.timer.step,love.timer.sleep
- local FPS,MINI=love.timer.getFPS,love.window.isMinimized
- local PUMP,POLL=love.event.pump,love.event.poll
-
- local timer,VERSION=love.timer.getTime,VERSION
-
- local frameTimeList={}
- local lastFrame=timer()
- local lastFreshPow=lastFrame
- local FCT=0--Framedraw counter, from 0~99
-
- love.resize(gc.getWidth(),gc.getHeight())
-
- --Scene Launch
- while #SCN.stack>0 do SCN.pop()end
- SCN.push('quit','slowFade')
- SCN.init(#errData==0 and'load'or'error')
-
- return function()
- local _
-
- local time=timer()
- local dt=time-lastFrame
- lastFrame=time
-
- --EVENT
- PUMP()
- for N,a,b,c,d,e in POLL()do
- if love[N]then
- love[N](a,b,c,d,e)
- elseif N=='quit'then
- onQuit()
- return a or true
- end
- end
-
- --UPDATE
- STEP()
- if mouseShow then mouse_update(dt)end
- if next(jsState)then gp_update(jsState[1],dt)end
- VOC.update()
- BG.update(dt)
- TEXT_update(dt)
- MES_update(dt)
- WS_update(dt)
- TASK_update(dt)
- SYSFX_update(dt)
- if SCN.update then SCN.update(dt)end
- if SCN.swapping then SCN.swapUpdate(dt)end
- WIDGET_update(dt)
-
- --DRAW
- if not MINI()then
- FCT=FCT+frameMul
- if FCT>=100 then
- FCT=FCT-100
-
- gc_replaceTransform(SCR.origin)
- gc_setColor(1,1,1)
- BG.draw()
- gc_replaceTransform(SCR.xOy)
- if SCN.draw then SCN.draw()end
- WIDGET_draw()
- SYSFX_draw()
- TEXT_draw()
-
- --Draw cursor
- if mouseShow then drawCursor(time,mx,my)end
- gc_replaceTransform(SCR.xOy_ul)
- MES_draw()
- gc_replaceTransform(SCR.origin)
- --Draw power info.
- if showPowerInfo then
- gc_setColor(1,1,1)
- gc_draw(infoCanvas,SCR.safeX,0,0,SCR.k)
- end
-
- --Draw scene swapping animation
- if SCN.swapping then
- gc_setColor(1,1,1)
- _=SCN.stat
- _.draw(_.time)
- end
- gc_replaceTransform(SCR.xOy_d)
- --Draw Version string
- gc_setColor(.9,.9,.9,.42)
- FONT.set(20)
- mStr(VERSION.string,0,-30)
- gc_replaceTransform(SCR.xOy_dl)
- local safeX=SCR.safeX/SCR.k
-
- --Draw FPS
- FONT.set(15)
- gc_setColor(1,1,1)
- gc_print(FPS(),safeX+5,-20)
-
- --Debug info.
- if devMode then
- --Debug infos at left-down
- gc_setColor(devColor[devMode])
-
- --Text infos
- for i=1,#debugInfos do
- gc_print(debugInfos[i][1],safeX+5,-20-20*i)
- gc_print(debugInfos[i][2](),safeX+62.6,-20-20*i)
- end
-
- --Update & draw frame time
- table.insert(frameTimeList,1,dt)table.remove(frameTimeList,126)
- gc_setColor(1,1,1,.3)
- for i=1,#frameTimeList do
- gc.rectangle('fill',150+2*i,-20,2,-frameTimeList[i]*4000)
- end
-
- --Cursor pos disp
- gc_replaceTransform(SCR.origin)
- local x,y=SCR.xOy:transformPoint(mx,my)
- gc_setLineWidth(1)
- gc_line(x,0,x,SCR.h)
- gc_line(0,y,SCR.w,y)
- local t=math.floor(mx+.5)..","..math.floor(my+.5)
- gc.setColor(COLOR.D)
- gc_print(t,x+1,y)
- gc_print(t,x+1,y-1)
- gc_print(t,x+2,y-1)
- gc_setColor(COLOR.Z)
- gc_print(t,x+2,y)
-
- gc_replaceTransform(SCR.xOy_dr)
- --Websocket status
- for i=1,6 do
- local status=WS.status(WSnames[i])
- gc_setColor(1,1,1)
- gc.draw(wsImg.bottom,-79,20*i-139)
- if status=='dead'then
- gc_draw(wsImg.dead,-20,20*i-140)
- elseif status=='connecting'then
- gc_setColor(1,1,1,.5+.3*math.sin(time*6.26))
- gc_draw(wsImg.connecting,-20,20*i-140)
- elseif status=='running'then
- gc_draw(wsImg.running,-20,20*i-140)
- end
- local t1,t2,t3=WS.getTimers(WSnames[i])
- gc_setColor(.9,.9,.9,t1)gc.rectangle('fill',-60,20*i-122,-16,-16)
- gc_setColor(.3,1,.3,t2)gc.rectangle('fill',-42,20*i-122,-16,-16)
- gc_setColor(1,.2,.2,t3)gc.rectangle('fill',-24,20*i-122,-16,-16)
- end
- end
- gc_present()
-
- --SPEED UPUPUP!
- if discardCanvas then gc_discard()end
- end
- end
-
- --Fresh power info.
- if time-lastFreshPow>2.6 then
- if showPowerInfo then
- updatePowerInfo()
- lastFreshPow=time
- end
- if gc.getWidth()~=SCR.w or gc.getHeight()~=SCR.h then
- love.resize(gc.getWidth(),gc.getHeight())
- end
- end
-
- --Slow devmode
- if devMode then
- if devMode==3 then
- WAIT(.1)
- elseif devMode==4 then
- WAIT(.5)
- end
- end
-
- _=timer()-lastFrame
- if _= math.huge then
- error("unexpected number value '" .. tostring(val) .. "'")
- end
- return string.format("%.14g", val)
-end
-
-local type_func_map = {
- ['nil'] = encode_nil,
- ['table'] = encode_table,
- ['string'] = encode_string,
- ['number'] = encode_number,
- ['boolean'] = tostring
-}
-
-_encode = function(val, stack)
- local t = type(val)
- local f = type_func_map[t]
- if f then return f(val, stack) end
- error("unexpected type '" .. t .. "'")
-end
-
-json.encode=_encode
-
--------------------------------------------------------------------------------
--- Decode
--------------------------------------------------------------------------------
-
-local parse
-
-local function create_set(...)
- local res = {}
- for i = 1, select("#", ...) do res[select(i, ...)] = true end
- return res
-end
-
-local space_chars = create_set(" ", "\t", "\r", "\n")
-local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",")
-local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")
-local literals = create_set("true", "false", "null")
-
-local literal_map = {["true"] = true, ["false"] = false, ["null"] = nil}
-
-local function next_char(str, idx, set, negate)
- for i = idx, #str do if set[str:sub(i, i)] ~= negate then return i end end
- return #str + 1
-end
-
-local function decode_error(str, idx, msg)
- local line_count = 1
- local col_count = 1
- for i = 1, idx - 1 do
- col_count = col_count + 1
- if str:sub(i, i) == "\n" then
- line_count = line_count + 1
- col_count = 1
- end
- end
- error(string.format("%s at line %d col %d", msg, line_count, col_count))
-end
-
-local function codepoint_to_utf8(n)
- -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa
- local f = bit.rshift
- if n <= 0x7f then
- return char(n)
- elseif n <= 0x7ff then
- return char(f(n, 6) + 192, n % 64 + 128)
- elseif n <= 0xffff then
- return char(f(n, 12) + 224, f(n % 4096, 6) + 128, n % 64 + 128)
- elseif n <= 0x10ffff then
- return char(f(n, 18) + 240, f(n % 262144, 12) + 128, f(n % 4096, 6) + 128, n % 64 + 128)
- end
- error(string.format("invalid unicode codepoint '%x'", n))
-end
-
-local function parse_unicode_escape(s)
- local n1 = tonumber(s:sub(1, 4), 16)
- local n2 = tonumber(s:sub(7, 10), 16)
- -- Surrogate pair?
- if n2 then
- return
- codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
- else
- return codepoint_to_utf8(n1)
- end
-end
-
-local function parse_string(str, i)
- local res = ""
- local j = i + 1
- local k = j
-
- while j <= #str do
- local x = str:byte(j)
-
- if x < 32 then
- decode_error(str, j, "control character in string")
-
- elseif x == 92 then -- `\`: Escape
- res = res .. str:sub(k, j - 1)
- j = j + 1
- local c = str:sub(j, j)
- if c == "u" then
- local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1) or
- str:match("^%x%x%x%x", j + 1) or
- decode_error(str, j - 1,
- "invalid unicode escape in string")
- res = res .. parse_unicode_escape(hex)
- j = j + #hex
- else
- if not escape_chars[c] then
- decode_error(str, j - 1,
- "invalid escape char '" .. c .. "' in string")
- end
- res = res .. escape_char_map_inv[c]
- end
- k = j + 1
-
- elseif x == 34 then -- `"`: End of string
- res = res .. str:sub(k, j - 1)
- return res, j + 1
- end
-
- j = j + 1
- end
-
- decode_error(str, i, "expected closing quote for string")
-end
-
-local function parse_number(str, i)
- local x = next_char(str, i, delim_chars)
- local s = str:sub(i, x - 1)
- local n = tonumber(s)
- if not n then decode_error(str, i, "invalid number '" .. s .. "'") end
- return n, x
-end
-
-local function parse_literal(str, i)
- local x = next_char(str, i, delim_chars)
- local word = str:sub(i, x - 1)
- if not literals[word] then
- decode_error(str, i, "invalid literal '" .. word .. "'")
- end
- return literal_map[word], x
-end
-
-local function parse_array(str, i)
- local res = {}
- local n = 1
- i = i + 1
- while 1 do
- local x
- i = next_char(str, i, space_chars, true)
- -- Empty / end of array?
- if str:sub(i, i) == "]" then
- i = i + 1
- break
- end
- -- Read token
- x, i = parse(str, i)
- res[n] = x
- n = n + 1
- -- Next token
- i = next_char(str, i, space_chars, true)
- local chr = str:sub(i, i)
- i = i + 1
- if chr == "]" then break end
- if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
- end
- return res, i
-end
-
-local function parse_object(str, i)
- local res = {}
- i = i + 1
- while 1 do
- local key, val
- i = next_char(str, i, space_chars, true)
- -- Empty / end of object?
- if str:sub(i, i) == "}" then
- i = i + 1
- break
- end
- -- Read key
- if str:sub(i, i) ~= '"' then
- decode_error(str, i, "expected string for key")
- end
- key, i = parse(str, i)
- -- Read ':' delimiter
- i = next_char(str, i, space_chars, true)
- if str:sub(i, i) ~= ":" then
- decode_error(str, i, "expected ':' after key")
- end
- i = next_char(str, i + 1, space_chars, true)
- -- Read value
- val, i = parse(str, i)
- -- Set
- res[key] = val
- -- Next token
- i = next_char(str, i, space_chars, true)
- local chr = str:sub(i, i)
- i = i + 1
- if chr == "}" then break end
- if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
- end
- return res, i
-end
-
-local char_func_map = {
- ['"'] = parse_string,
- ["0"] = parse_number,
- ["1"] = parse_number,
- ["2"] = parse_number,
- ["3"] = parse_number,
- ["4"] = parse_number,
- ["5"] = parse_number,
- ["6"] = parse_number,
- ["7"] = parse_number,
- ["8"] = parse_number,
- ["9"] = parse_number,
- ["-"] = parse_number,
- ["t"] = parse_literal,
- ["f"] = parse_literal,
- ["n"] = parse_literal,
- ["["] = parse_array,
- ["{"] = parse_object
-}
-
-function parse(str, idx)
- local chr = str:sub(idx, idx)
- local f = char_func_map[chr]
- if f then return f(str, idx) end
- decode_error(str, idx, "unexpected character '" .. chr .. "'")
-end
-
-function json.decode(str)
- if type(str) ~= 'string' then
- error("expected argument of type string, got " .. type(str))
- end
- local res, idx = parse(str, next_char(str, 1, space_chars, true))
- idx = next_char(str, idx, space_chars, true)
- if idx <= #str then decode_error(str, idx, "trailing garbage") end
- return res
-end
-return json
diff --git a/Zframework/languages.lua b/Zframework/languages.lua
deleted file mode 100644
index ad40ce35e..000000000
--- a/Zframework/languages.lua
+++ /dev/null
@@ -1,57 +0,0 @@
-local LANG={}
---ONLY FIRST CALL MAKE SENSE
---Create LANG.get() and LANG.addScene()
-function LANG.init(defaultLang,langList,publicText,pretreatFunc)
- local function _langFallback(T0,T)
- for k,v in next,T0 do
- if type(v)=='table'and not v.refuseCopy then--refuseCopy: just copy pointer, not contents
- if not T[k]then T[k]={}end
- if type(T[k])=='table'then
- _langFallback(v,T[k])
- end
- elseif not T[k]then
- T[k]=v
- end
- end
- end
-
- --Set public text
- if publicText then
- for _,L in next,langList do
- for key,list in next,publicText do L[key]=list end
- end
- end
-
- --Fallback to default language
- for name,L in next,langList do
- if name~=defaultLang then
- _langFallback(langList[L.fallback or defaultLang],L)
- end
- end
-
- --Custom pretreatment for each language
- if pretreatFunc then
- for _,L in next,langList do
- pretreatFunc(L)
- end
- end
-
- function LANG.get(l)
- if not langList[l]then
- LOG("Wrong language: "..tostring(l))
- l=defaultLang
- end
- return langList[l]
- end
-
- function LANG.addScene(name)
- for _,L in next,langList do
- if L.WidgetText and not L.WidgetText[name]then
- L.WidgetText[name]={}
- end
- end
- end
-
- function LANG.init()end
-end
-return LANG
diff --git a/Zframework/light/init.lua b/Zframework/light/init.lua
deleted file mode 100644
index 712139692..000000000
--- a/Zframework/light/init.lua
+++ /dev/null
@@ -1,86 +0,0 @@
---LIGHT MODULE (Optimized by MrZ, Original on github/LÖVE community/simple-love-lights)
---Heavily based on mattdesl's libGDX implementation:
---https://github.com/mattdesl/lwjgl-basics/wiki/2D-Pixel-Perfect-Shadows
-local gc=love.graphics
-local clear,gc_translate=gc.clear,gc.translate
-local gc_setCanvas,gc_setShader=gc.setCanvas,gc.setShader
-local gc_setColor,gc_draw=gc.setColor,gc.draw
-
-local shadowMapShader=gc.newShader('Zframework/light/shadowMap.glsl')--Shader for caculating the 1D shadow map.
-local lightRenderShader=gc.newShader('Zframework/light/lightRender.glsl')--Shader for rendering blurred lights and shadows.
-local Lights={}--Lightsource objects
-local function move(L,x,y)
- L.x,L.y=x,y
-end
-local function setPow(L,pow)
- L.size=pow
-end
-local function drawLight(L)
- local s=L.size
-
- --Initialization
- gc_setCanvas(L.blackCanvas)clear()
- gc_setCanvas(L.shadowCanvas)clear()
- gc_setCanvas(L.renderCanvas)clear()
- lightRenderShader:send('xresolution',s)
- shadowMapShader:send('yresolution',s)
-
- --Get up-left of light
- local X=L.x-s*.5
- local Y=L.y-s*.5
-
- --Render solid
- gc_translate(-X,-Y)
- L.blackCanvas:renderTo(L.blackFn)
- gc_translate(X,Y)
-
- --Render shade canvas by solid
- gc_setShader(shadowMapShader)
- gc_setCanvas(L.shadowCanvas)
- gc_draw(L.blackCanvas)
-
- --Render light canvas by shade
- gc_setShader(lightRenderShader)
- gc_setCanvas(L.renderCanvas)
- gc_draw(L.shadowCanvas,0,0,0,1,s)
-
- --Ready to final render
- gc_setShader()gc_setCanvas()gc.setBlendMode('add')
-
- --Render to screen
- gc_draw(L.renderCanvas,X,Y+s,0,1,-1)
-
- --Reset
- gc.setBlendMode('alpha')
-end
-
-local LIGHT={}
-function LIGHT.draw()
- gc_setColor(1,1,1)
- for i=1,#Lights do
- drawLight(Lights[i])
- end
-end
-function LIGHT.clear()
- for i=1,#Lights do
- Lights[i].blackCanvas:release()
- Lights[i].shadowCanvas:release()
- Lights[i].renderCanvas:release()
- Lights[i]=nil
- end
-end
-function LIGHT.add(x,y,radius,solidFunc)
- local id=#Lights+1
- Lights[id]={
- id=id,
- x=x,y=y,size=radius,
- blackCanvas=gc.newCanvas(radius,radius),--Solid canvas
- shadowCanvas=gc.newCanvas(radius,1),--1D vis-depth canvas
- renderCanvas=gc.newCanvas(radius,radius),--Light canvas
- blackFn=solidFunc,--Solid draw function
-
- move=move,
- setPow=setPow,
- }
-end
-return LIGHT
diff --git a/Zframework/light/lightRender.glsl b/Zframework/light/lightRender.glsl
deleted file mode 100644
index 7d3efe70d..000000000
--- a/Zframework/light/lightRender.glsl
+++ /dev/null
@@ -1,29 +0,0 @@
-#define PI 3.14159
-extern float xresolution;
-// Sample from 1D vis-depth map
-float samp(vec2 coord,float r,Image u_texture){
- return step(r,Texel(u_texture,coord).r);
-}
-vec4 effect(vec4 color,Image tex,vec2 tex_coords,vec2 screen_coords){
- // Cartesian to polar, y of 1D sample is always 0
- vec2 norm=tex_coords.st*2.-1.;
- vec2 tc=vec2((atan(norm.y,norm.x)+PI)/(2.*PI),0.);
- float r=length(norm);
-
- // Enlarge blur parameter by distance, light scattering simulation
- float blur=(1./xresolution)*smoothstep(0.3,1.,r);
-
- // Simple Gaussian blur
- float sum=// Brightness(0~1)
- samp(vec2(tc.x-3.*blur,tc.y),r,tex)*0.1
- +samp(vec2(tc.x-2.*blur,tc.y),r,tex)*0.13
- +samp(vec2(tc.x-1.*blur,tc.y),r,tex)*0.17
-
- +samp(tc,r,tex)*0.2// The center tex coord, which gives us hard shadows.
- +samp(vec2(tc.x+1.*blur,tc.y),r,tex)*0.17
- +samp(vec2(tc.x+2.*blur,tc.y),r,tex)*0.13
- +samp(vec2(tc.x+3.*blur,tc.y),r,tex)*0.1;
-
- // Multiply the distance to get a soft fading
- return vec4(vec3(1.),sum*smoothstep(1.,0.,r));
-}
diff --git a/Zframework/light/shadowMap.glsl b/Zframework/light/shadowMap.glsl
deleted file mode 100644
index 54809c799..000000000
--- a/Zframework/light/shadowMap.glsl
+++ /dev/null
@@ -1,20 +0,0 @@
-#define PI 3.14
-extern float yresolution;
-vec4 effect(vec4 color,Image tex,vec2 tex_coords,vec2 screen_coords){
- // Iterate through the occluder map's y-axis.
- for(float y=0.;y0.1
- )return vec4(vec3(y/yresolution),1.);// Collision check, alpha>0.1 means transparent
- }
- return vec4(1.);// Return max distance 1
-}
diff --git a/Zframework/log.lua b/Zframework/log.lua
deleted file mode 100644
index f1cec3cdb..000000000
--- a/Zframework/log.lua
+++ /dev/null
@@ -1,20 +0,0 @@
-local ins=table.insert
-
-local logs={os.date("Techmino logs %Y/%m/%d %A")}
-
-local function log(message)
- ins(logs,os.date("[%H:%M:%S] ")..message)
-end
-
-local LOG=setmetatable({logs=logs},{
- __call=function(_,message)
- print(message)
- log(message)
- end
-})
-
-function LOG.read()
- return table.concat(logs,"\n")
-end
-
-return LOG
diff --git a/Zframework/mathExtend.lua b/Zframework/mathExtend.lua
deleted file mode 100644
index 5f3db7c39..000000000
--- a/Zframework/mathExtend.lua
+++ /dev/null
@@ -1,37 +0,0 @@
-local MATH={}for k,v in next,math do MATH[k]=v end
-
-local rnd=math.random
-
-MATH.tau=2*math.pi
-
-function MATH.sign(a)
- return a>0 and 1 or a<0 and -1 or 0
-end
-
-function MATH.roll(chance)
- return rnd()<(chance or .5)
-end
-
-function MATH.coin(a,b)
- if rnd()<.5 then
- return a
- else
- return b
- end
-end
-
-function MATH.interval(v,low,high)
- if v<=low then
- return low
- elseif v>=high then
- return high
- else
- return v
- end
-end
-
-function MATH.expApproach(a,b,k)
- return b+(a-b)*2.718281828459045^-k
-end
-
-return MATH
\ No newline at end of file
diff --git a/Zframework/message.lua b/Zframework/message.lua
deleted file mode 100644
index c2bbafa03..000000000
--- a/Zframework/message.lua
+++ /dev/null
@@ -1,148 +0,0 @@
-local gc=love.graphics
-local gc_push,gc_pop=gc.push,gc.pop
-local gc_translate,gc_setColor,gc_draw=gc.translate,gc.setColor,gc.draw
-
-local ins,rem=table.insert,table.remove
-local max=math.max
-
-local mesList={}
-local mesIcon={
- check=GC.DO{40,40,
- {'setLW',10},
- {'setCL',0,0,0},
- {'line',4,19,15,30,36,9},
- {'setLW',6},
- {'setCL',.7,1,.6},
- {'line',5,20,15,30,35,10},
- },
- info=GC.DO{40,40,
- {'setCL',.2,.25,.85},
- {'fCirc',20,20,15},
- {'setCL',1,1,1},
- {'setLW',2},
- {'dCirc',20,20,15},
- {'fRect',18,11,4,4},
- {'fRect',18,17,4,12},
- },
- broadcast=GC.DO{40,40,
- {'setCL',1,1,1},
- {'fRect',2,4,36,26,3},
- {'fPoly',2,27,2,37,14,25},
- {'setCL',.5,.5,.5},
- {'fRect',6,11,4,4,1},{'fRect',14,11,19,4,1},
- {'fRect',6,19,4,4,1},{'fRect',14,19,19,4,1},
- },
- warn=GC.DO{40,40,
- {'setCL',.95,.83,.4},
- {'fPoly',20.5,1,0,38,40,38},
- {'setCL',0,0,0},
- {'dPoly',20.5,1,0,38,40,38},
- {'fRect',17,10,7,18,2},
- {'fRect',17,29,7,7,2},
- {'setCL',1,1,1},
- {'fRect',18,11,5,16,2},
- {'fRect',18,30,5,5,2},
- },
- error=GC.DO{40,40,
- {'setCL',.95,.3,.3},
- {'fCirc',20,20,19},
- {'setCL',0,0,0},
- {'dCirc',20,20,19},
- {'setLW',6},
- {'line',10.2,10.2,29.8,29.8},
- {'line',10.2,29.8,29.8,10.2},
- {'setLW',4},
- {'setCL',1,1,1},
- {'line',11,11,29,29},
- {'line',11,29,29,11},
- },
- music=GC.DO{40,40,
- {'setLW',2},
- {'dRect',1,3,38,34,3},
- {'setLW',4},
- {'line',21,26,21,10,28,10},
- {'fElps',17,26,6,5},
- },
-}
-
-local MES={}
-local backColors={
- check={.3,.6,.3,.7},
- broadcast={.3,.3,.6,.8},
- warn={.4,.4,.2,.9},
- error={.4,.2,.2,.9},
- music={.2,.4,.4,.9},
-}
-function MES.new(icon,str,time)
- local backColor={.5,.5,.5,.7}
- if type(icon)=='string'then
- backColor=backColors[icon]or backColor
- icon=mesIcon[icon]
- end
- local t=gc.newText(FONT.get(30),str)
- local w=math.max(t:getWidth()+(icon and 45 or 5),200)+15
- local h=math.max(t:getHeight(),46)+2
- local L={w,h,
- {'clear',backColor},
- {'setCL',.7,.7,.7},
- {'setLW',2},
- {'dRect',1,1,w-2,h-2},
- {'setCL',1,1,1},
- }
- if icon then
- ins(L,{'draw',icon,4,4,nil,40/icon:getWidth(),40/icon:getHeight()})
- end
- ins(L,{'mDrawY',t,icon and 50 or 10,h/2})
-
- ins(mesList,{
- startTime=.5,
- endTime=.5,
- time=time or 3,
- canvas=GC.DO(L),
- width=w,height=h,
- scale=h>400 and 1/math.min(h/400,2.6)or 1
- })
-end
-
-function MES.update(dt)
- for i=#mesList,1,-1 do
- local m=mesList[i]
- if m.startTime>0 then
- m.startTime=max(m.startTime-dt,0)
- elseif m.time>0 then
- m.time=max(m.time-dt,0)
- elseif m.endTime>0 then
- m.endTime=m.endTime-dt
- else
- rem(mesList,i)
- end
- end
-end
-
-function MES.draw()
- gc_push('transform')
- if #mesList>0 then
- gc_translate(SCR.safeX,30)
- for i=1,#mesList do
- local m=mesList[i]
- gc_setColor(1,1,1,2*(m.endTime-m.startTime))
- gc_draw(m.canvas,40-80*(m.endTime+m.startTime),0,nil,m.scale)
- gc_translate(0,m.height*m.scale+2)
- end
- end
- gc_pop()
-end
-
-function MES.traceback()
- local mes=
- debug.traceback('',1)
- :gsub(': in function',', in')
- :gsub(':',' ')
- :gsub('\t','')
- MES.new('error',mes:sub(
- mes:find("\n",2)+1,
- mes:find("\n%[C%], in 'xpcall'")
- ),5)
-end
-
-return MES
diff --git a/Zframework/profile.lua b/Zframework/profile.lua
deleted file mode 100644
index 65266f604..000000000
--- a/Zframework/profile.lua
+++ /dev/null
@@ -1,157 +0,0 @@
-local clock=os.clock
-
-local profile={}
-
-local _labeled={} -- function labels
-local _defined={} -- function definitions
-local _tcalled={} -- time of last call
-local _telapsed={}-- total execution time
-local _ncalls={} -- number of calls
-local _internal={}-- list of internal profiler functions
-
-local getInfo=debug.getinfo
-function profile.hooker(event,line,info)
- info=info or getInfo(2,'fnS')
- local f=info.func
- if _internal[f]then return end-- ignore the profiler itself
- if info.name then _labeled[f]=info.name end-- get the function name if available
- -- find the line definition
- if not _defined[f]then
- _defined[f]=info.short_src..":"..info.linedefined
- _ncalls[f]=0
- _telapsed[f]=0
- end
- if _tcalled[f]then
- local dt=clock()-_tcalled[f]
- _telapsed[f]=_telapsed[f]+dt
- _tcalled[f]=nil
- end
- if event=='tail call'then
- local prev=getInfo(3,'fnS')
- profile.hooker('return',line,prev)
- profile.hooker('call',line,info)
- elseif event=='call'then
- _tcalled[f]=clock()
- else
- _ncalls[f]=_ncalls[f]+1
- end
-end
-
---- Starts collecting data.
-function profile.start()
- if jit then
- jit.off()
- jit.flush()
- end
- debug.sethook(profile.hooker,'cr')
-end
-
---- Stops collecting data.
-function profile.stop()
- debug.sethook()
- for f in next,_tcalled do
- local dt=clock()-_tcalled[f]
- _telapsed[f]=_telapsed[f]+dt
- _tcalled[f]=nil
- end
- -- merge closures
- local lookup={}
- for f,d in next,_defined do
- local id=(_labeled[f]or"?")..d
- local f2=lookup[id]
- if f2 then
- _ncalls[f2]=_ncalls[f2]+(_ncalls[f]or 0)
- _telapsed[f2]=_telapsed[f2]+(_telapsed[f]or 0)
- _defined[f],_labeled[f]=nil,nil
- _ncalls[f],_telapsed[f]=nil,nil
- else
- lookup[id]=f
- end
- end
- collectgarbage()
-end
-
---- Resets all collected data.
-function profile.reset()
- for f in next,_ncalls do
- _ncalls[f]=0
- _telapsed[f]=0
- _tcalled[f]=nil
- end
- collectgarbage()
-end
-
-local function _comp(a,b)
- local dt=_telapsed[b]-_telapsed[a]
- return dt==0 and _ncalls[b]<_ncalls[a]or dt<0
-end
-
---- Iterates all functions that have been called since the profile was started.
-function profile.query(limit)
- local t={}
- for f,n in next,_ncalls do
- if n>0 then
- t[#t+1]=f
- end
- end
- table.sort(t,_comp)
-
- if limit then while #t>limit do table.remove(t)end end
-
- for i,f in ipairs(t)do
- local dt=0
- if _tcalled[f]then
- dt=clock()-_tcalled[f]
- end
- t[i]={i,_labeled[f]or"?",math.floor((_telapsed[f]+dt)*1e6)/1e6,_ncalls[f],_defined[f]}
- end
- return t
-end
-
-local cols={3,20,8,6,32}
-function profile.report(n)
- local out={}
- local report=profile.query(n)
- for i,row in ipairs(report)do
- for j=1,5 do
- local s=tostring(row[j])
- local l1,l2=#s,cols[j]
- if l1l2 then
- s=s:sub(l1-l2+1,l1)
- end
- row[j]=s
- end
- out[i]=table.concat(row," | ")
- end
-
- local row=" +-----+----------------------+----------+--------+----------------------------------+ \n"
- local col=" | # | Function | Time | Calls | Code | \n"
- local sz=row..col..row
- if #out>0 then
- sz=sz.." | "..table.concat(out," | \n | ").." | \n"
- end
- return "\n"..sz..row
-end
-
-local switch=false
-function profile.switch()
- switch=not switch
- if not switch then
- profile.stop()
- love.system.setClipboardText(profile.report())
- profile.reset()
- return false
- else
- profile.start()
- return true
- end
-end
-
--- store all internal profiler functions
-for _,v in next,profile do
- _internal[v]=type(v)=='function'
-end
-
-return profile
diff --git a/Zframework/require.lua b/Zframework/require.lua
deleted file mode 100644
index d1b1afae7..000000000
--- a/Zframework/require.lua
+++ /dev/null
@@ -1,33 +0,0 @@
-package.cpath=package.cpath..';'..SAVEDIR..'/lib/lib?.so;'..'?.dylib'
-local loaded={}
-return function(libName)
- local require=require
- if love.system.getOS()=='OS X'then
- require=package.loadlib(libName..'.dylib','luaopen_'..libName)
- libname=nil
- elseif love.system.getOS()=='Android'then
- if not loaded[libName]then
- local platform=(function()
- local p=io.popen('uname -m')
- local arch=p:read('*a'):lower()
- p:close()
- if arch:find('v8')or arch:find('64')then
- return'arm64-v8a'
- else
- return'armeabi-v7a'
- end
- end)()
- love.filesystem.write(
- 'lib/libCCloader.so',
- love.filesystem.read('data','libAndroid/'..platform..'/libCCloader.so')
- )
- loaded[libName]=true
- end
- end
- local success,res=pcall(require,libName)
- if success and res then
- return res
- else
- MES.new('error',"Cannot load "..libName..": "..res)
- end
-end
diff --git a/Zframework/scene.lua b/Zframework/scene.lua
deleted file mode 100644
index e990c71ba..000000000
--- a/Zframework/scene.lua
+++ /dev/null
@@ -1,210 +0,0 @@
-local gc=love.graphics
-local abs=math.abs
-
-local scenes={}
-
-local SCN={
- mainTouchID=nil, --First touching ID(userdata)
- cur='NULL', --Current scene name
- swapping=false, --If Swapping
- stat={
- tar=false, --Swapping target
- style=false, --Swapping style
- changeTime=false,--Loading point
- time=false, --Full swap time
- draw=false, --Swap draw func
- },
- stack={},--Scene stack
- prev=false,
- args={},--Arguments from previous scene
-
- scenes=scenes,
-
- --Events
- update=false,
- draw=false,
- mouseClick=false,
- touchClick=false,
- mouseDown=false,
- mouseMove=false,
- mouseUp=false,
- wheelMoved=false,
- touchDown=false,
- touchUp=false,
- touchMove=false,
- keyDown=false,
- keyUp=false,
- gamepadDown=false,
- gamepadUp=false,
- fileDropped=false,
- directoryDropped=false,
- resize=false,
- socketRead=false,
-}--Scene datas, returned
-
-function SCN.add(name,scene)
- scenes[name]=scene
- if scene.widgetList then
- setmetatable(scene.widgetList,WIDGET.indexMeta)
- end
-end
-
-function SCN.swapUpdate(dt)
- local S=SCN.stat
- S.time=S.time-dt
- if S.time=S.changeTime then
- --Scene swapped this frame
- SCN.prev=SCN.cur
- SCN.init(S.tar)
- SCN.mainTouchID=nil
- end
- if S.time<0 then
- SCN.swapping=false
- end
-end
-function SCN.init(s)
- love.keyboard.setTextInput(false)
-
- local S=scenes[s]
- SCN.cur=s
-
- WIDGET.setScrollHeight(S.widgetScrollHeight)
- WIDGET.setWidgetList(S.widgetList)
- SCN.sceneInit=S.sceneInit
- SCN.sceneBack=S.sceneBack
- SCN.mouseDown=S.mouseDown
- SCN.mouseMove=S.mouseMove
- SCN.mouseUp=S.mouseUp
- SCN.mouseClick=S.mouseClick
- SCN.wheelMoved=S.wheelMoved
- SCN.touchDown=S.touchDown
- SCN.touchUp=S.touchUp
- SCN.touchMove=S.touchMove
- SCN.touchClick=S.touchClick
- SCN.keyDown=S.keyDown
- SCN.keyUp=S.keyUp
- SCN.gamepadDown=S.gamepadDown
- SCN.gamepadUp=S.gamepadUp
- SCN.fileDropped=S.fileDropped
- SCN.directoryDropped=S.directoryDropped
- SCN.resize=S.resize
- SCN.socketRead=S.socketRead
- SCN.update=S.update
- SCN.draw=S.draw
- if S.sceneInit then
- S.sceneInit()
- end
-end
-function SCN.push(tar,style)
- if not SCN.swapping then
- local m=#SCN.stack
- SCN.stack[m+1]=tar or SCN.cur
- SCN.stack[m+2]=style or'fade'
- end
-end
-function SCN.pop()
- local s=SCN.stack
- s[#s],s[#s-1]=nil
-end
-
-local swap={
- none={
- duration=0,changeTime=0,
- draw=function()end
- },
- flash={
- duration=.16,changeTime=.08,
- draw=function()gc.clear(1,1,1)end
- },
- fade={
- duration=.5,changeTime=.25,
- draw=function(t)
- t=t>.25 and 2-t*4 or t*4
- gc.setColor(0,0,0,t)
- gc.rectangle('fill',0,0,SCR.w,SCR.h)
- end
- },
- fade_togame={
- duration=2,changeTime=.5,
- draw=function(t)
- t=t>.5 and(2-t)/1.5 or t*.5
- gc.setColor(0,0,0,t)
- gc.rectangle('fill',0,0,SCR.w,SCR.h)
- end
- },
- slowFade={
- duration=3,changeTime=1.5,
- draw=function(t)
- t=t>1.5 and (3-t)/1.5 or t/1.5
- gc.setColor(0,0,0,t)
- gc.rectangle('fill',0,0,SCR.w,SCR.h)
- end
- },
- swipeL={
- duration=.5,changeTime=.25,
- draw=function(t)
- t=t*2
- gc.setColor(.1,.1,.1,1-abs(t-.5))
- t=t*t*(3-2*t)*2-1
- gc.rectangle('fill',t*SCR.w,0,SCR.w,SCR.h)
- end
- },
- swipeR={
- duration=.5,changeTime=.25,
- draw=function(t)
- t=t*2
- gc.setColor(.1,.1,.1,1-abs(t-.5))
- t=t*t*(2*t-3)*2+1
- gc.rectangle('fill',t*SCR.w,0,SCR.w,SCR.h)
- end
- },
- swipeD={
- duration=.5,changeTime=.25,
- draw=function(t)
- t=t*2
- gc.setColor(.1,.1,.1,1-abs(t-.5))
- t=t*t*(2*t-3)*2+1
- gc.rectangle('fill',0,t*SCR.h,SCR.w,SCR.h)
- end
- },
-}--Scene swapping animations
-function SCN.swapTo(tar,style,...)--Parallel scene swapping, cannot back
- if scenes[tar]then
- if not SCN.swapping and tar~=SCN.cur then
- style=style or'fade'
- SCN.swapping=true
- SCN.args={...}
- local S=SCN.stat
- S.tar,S.style=tar,style
- S.time=swap[style].duration
- S.changeTime=swap[style].changeTime
- S.draw=swap[style].draw
- end
- else
- MES.new('warn',"No Scene: "..tar)
- end
-end
-function SCN.go(tar,style,...)--Normal scene swapping, can back
- if scenes[tar]then
- SCN.push()
- SCN.swapTo(tar,style,...)
- else
- MES.new('warn',"No Scene: "..tar)
- end
-end
-function SCN.back(...)
- if SCN.swapping then return end
-
- --Leave scene
- if SCN.sceneBack then
- SCN.sceneBack()
- end
-
- --Poll&Back to previous Scene
- local m=#SCN.stack
- if m>0 then
- SCN.swapTo(SCN.stack[m-1],SCN.stack[m],...)
- SCN.stack[m],SCN.stack[m-1]=nil
- end
-end
-return SCN
diff --git a/Zframework/screen.lua b/Zframework/screen.lua
deleted file mode 100644
index cf86cbd42..000000000
--- a/Zframework/screen.lua
+++ /dev/null
@@ -1,73 +0,0 @@
-local SCR={
- w0=1280,h0=720, --Default Screen Size
- x=0,y=0, --Up-left Coord on screen
- cx=0,cy=0, --Center Coord on screen (Center X/Y)
- ex=0,ey=0, --Down-right Coord on screen (End X/Y)
- w=0,h=0, --Fullscreen w/h for graphic functions
- W=0,H=0, --Fullscreen w/h for shader
- safeX=0,safeY=0,--Safe area
- safeW=0,safeH=0,--Safe area
- rad=0, --Radius
- k=1, --Scale size
- dpi=1, --DPI from gc.getDPIScale()
-
- --Screen transformation objects
- origin=love.math.newTransform(),
- xOy=love.math.newTransform(),
- xOy_m=love.math.newTransform(),
- xOy_ul=love.math.newTransform(),
- xOy_u=love.math.newTransform(),
- xOy_ur=love.math.newTransform(),
- xOy_l=love.math.newTransform(),
- xOy_r=love.math.newTransform(),
- xOy_dl=love.math.newTransform(),
- xOy_d=love.math.newTransform(),
- xOy_dr=love.math.newTransform(),
-}
-function SCR.setSize(w,h)
- SCR.w0,SCR.h0=w,h
-end
-function SCR.resize(w,h)
- SCR.w,SCR.h,SCR.dpi=w,h,love.graphics.getDPIScale()
- SCR.W,SCR.H=SCR.w*SCR.dpi,SCR.h*SCR.dpi
- SCR.r=h/w
- SCR.rad=(w^2+h^2)^.5
-
- SCR.x,SCR.y=0,0
- if SCR.r>=SCR.h0/SCR.w0 then
- SCR.k=w/SCR.w0
- SCR.y=(h-SCR.h0*SCR.k)/2
- else
- SCR.k=h/SCR.h0
- SCR.x=(w-SCR.w0*SCR.k)/2
- end
- SCR.cx,SCR.cy=SCR.w/2,SCR.h/2
- SCR.ex,SCR.ey=SCR.w-SCR.x,SCR.h-SCR.y
- SCR.safeX,SCR.safeY,SCR.safeW,SCR.safeH=love.window.getSafeArea()
-
- SCR.origin:setTransformation(0,0)
- SCR.xOy:setTransformation(SCR.x,SCR.y,0,SCR.k)
- SCR.xOy_m:setTransformation(w/2,h/2,0,SCR.k)
- SCR.xOy_ul:setTransformation(0,0,0,SCR.k)
- SCR.xOy_u:setTransformation(w/2,0,0,SCR.k)
- SCR.xOy_ur:setTransformation(w,0,0,SCR.k)
- SCR.xOy_l:setTransformation(0,h/2,0,SCR.k)
- SCR.xOy_r:setTransformation(w,h/2,0,SCR.k)
- SCR.xOy_dl:setTransformation(0,h,0,SCR.k)
- SCR.xOy_d:setTransformation(w/2,h,0,SCR.k)
- SCR.xOy_dr:setTransformation(w,h,0,SCR.k)
-end
-function SCR.info()
- return{
- ("w0,h0 : %d, %d"):format(SCR.w0,SCR.h0),
- ("x,y : %d, %d"):format(SCR.x,SCR.y),
- ("cx,cy : %d, %d"):format(SCR.cx,SCR.cy),
- ("ex,ey : %d, %d"):format(SCR.ex,SCR.ey),
- ("w,h : %d, %d"):format(SCR.w,SCR.h),
- ("W,H : %d, %d"):format(SCR.W,SCR.H),
- ("safeX,safeY : %d, %d"):format(SCR.safeX,SCR.safeY),
- ("safeW,safeH : %d, %d"):format(SCR.safeW,SCR.safeH),
- ("k,dpi,rad : %.2f, %d, %.2f"):format(SCR.k,SCR.dpi,SCR.rad),
- }
-end
-return SCR
diff --git a/Zframework/sfx.lua b/Zframework/sfx.lua
deleted file mode 100644
index 8f5c5c20f..000000000
--- a/Zframework/sfx.lua
+++ /dev/null
@@ -1,170 +0,0 @@
-local type,rem=type,table.remove
-local int,rnd=math.floor,math.random
-local interval=MATH.interval
-
-local sfxList={}
-local packSetting={}
-local Sources={}
-local volume=1
-local stereo=1
-
-local noteVal={
- C=1,c=1,
- D=3,d=3,
- E=5,e=5,
- F=6,f=6,
- G=8,g=8,
- A=10,a=10,
- B=12,b=12,
-}
-local noteName={'C','C#','D','D#','E','F','F#','G','G#','A','A#','B'}
-local function _getTuneHeight(tune)
- local octave=tonumber(tune:sub(-1,-1))
- if octave then
- local tuneHeight=noteVal[tune:sub(1,1)]
- if tuneHeight then
- tuneHeight=tuneHeight+(octave-1)*12
- local s=tune:sub(2,2)
- if s=='s'or s=='#'then
- tuneHeight=tuneHeight+1
- elseif s=='f'or s=='b'then
- tuneHeight=tuneHeight-1
- end
- return tuneHeight
- end
- end
-end
-
-local SFX={}
-
-function SFX.init(list)
- assert(type(list)=='table',"Initialize SFX lib with a list of filenames!")
- for i=1,#list do table.insert(sfxList,list[i])end
-end
-function SFX.load(path)
- local c=0
- local missing=0
- for i=1,#sfxList do
- local fullPath=path..sfxList[i]..'.ogg'
- if love.filesystem.getInfo(fullPath)then
- if Sources[sfxList[i]]then
- for j=1,#Sources[sfxList[i]]do
- Sources[sfxList[i]][j]:release()
- end
- end
- Sources[sfxList[i]]={love.audio.newSource(fullPath,'static')}
- c=c+1
- else
- LOG("No SFX: "..sfxList[i]..'.ogg',.1)
- missing=missing+1
- end
- end
- LOG(c.."/"..#sfxList.." SFX files loaded")
- LOG(missing.." SFX files missing")
- if missing>0 then
- MES.new('info',missing.." SFX files missing")
- end
- collectgarbage()
-end
-function SFX.loadSample(pack)
- assert(type(pack)=='table',"Usage: SFX.loadsample([table])")
- assert(pack.name,"No field: name")
- assert(pack.path,"No field: path")
- local num=1
- while love.filesystem.getInfo(pack.path..'/'..num..'.ogg')do
- Sources[pack.name..num]={love.audio.newSource(pack.path..'/'..num..'.ogg','static')}
- num=num+1
- end
- local base=(_getTuneHeight(pack.base)or 37)-1
- local top=base+num-1
- packSetting[pack.name]={base=base,top=top}
- LOG((num-1).." "..pack.name.." samples loaded")
-end
-
-function SFX.getCount()
- return #sfxList
-end
-function SFX.setVol(v)
- assert(type(v)=='number'and v>=0 and v<=1,'Wrong volume')
- volume=v
-end
-function SFX.setStereo(v)
- assert(type(v)=='number'and v>=0 and v<=1,'Wrong stereo')
- stereo=v
-end
-
-function SFX.getNoteName(note)
- if note<1 then
- return'---'
- else
- note=note-1
- local octave=int(note/12)+1
- return noteName[note%12+1]..octave
- end
-end
-function SFX.playSample(pack,...)--vol-1, sampSet1, vol-2, sampSet2
- if ... then
- local arg={...}
- local vol
- for i=1,#arg do
- local a=arg[i]
- if type(a)=='number'and a<=1 then
- vol=a
- else
- local base=packSetting[pack].base
- local top=packSetting[pack].top
- local tune=type(a)=='string'and _getTuneHeight(a)or a--Absolute tune in number
- local playTune=tune+rnd(-2,2)
- if playTune<=base then--Too low notes
- playTune=base+1
- elseif playTune>top then--Too high notes
- playTune=top
- end
- SFX.play(pack..playTune-base,vol,nil,tune-playTune)
- end
- end
- end
-end
-local function _play(name,vol,pos,pitch)
- if volume==0 or vol==0 then return end
- local S=Sources[name]--Source list
- if not S then return end
- local n=1
- while S[n]:isPlaying()do
- n=n+1
- if not S[n]then
- S[n]=S[1]:clone()
- S[n]:seek(0)
- break
- end
- end
- S=S[n]--AU_SRC
- if S:getChannelCount()==1 then
- if pos then
- pos=interval(pos,-1,1)*stereo
- S:setPosition(pos,1-pos^2,0)
- else
- S:setPosition(0,0,0)
- end
- end
- S:setVolume(vol^1.626)
- S:setPitch(pitch and 1.0594630943592953^pitch or 1)
- S:play()
-end
-SFX.fplay=_play--Play sounds without apply module's volume setting
-function SFX.play(name,vol,pos,pitch)
- _play(name,(vol or 1)*volume,pos,pitch)
-end
-function SFX.reset()
- for _,L in next,Sources do
- if type(L)=='table'then
- for i=#L,1,-1 do
- if not L[i]:isPlaying()then
- rem(L,i)
- end
- end
- end
- end
-end
-
-return SFX
diff --git a/Zframework/stringExtend.lua b/Zframework/stringExtend.lua
deleted file mode 100644
index ca2ccdbd8..000000000
--- a/Zframework/stringExtend.lua
+++ /dev/null
@@ -1,231 +0,0 @@
-local data=love.data
-local STRING={}
-local assert,tostring,tonumber=assert,tostring,tonumber
-local int,format=math.floor,string.format
-local find,sub,gsub,upper=string.find,string.sub,string.gsub,string.upper
-local char,byte=string.char,string.byte
-
---"Replace dollars", replace all $n with ...
-function STRING.repD(str,...)
- local l={...}
- for i=#l,1,-1 do
- str=gsub(str,'$'..i,l[i])
- end
- return str
-end
-
---"Scan arg", scan if str has the arg (format of str is like "-json -q", arg is like "-q")
-function STRING.sArg(str,switch)
- if find(str.." ",switch.." ")then
- return true
- end
-end
-
-do--function STRING.shiftChar(c)
- local shiftMap={
- ['1']='!',['2']='@',['3']='#',['4']='$',['5']='%',
- ['6']='^',['7']='&',['8']='*',['9']='(',['0']=')',
- ['`']='~',['-']='_',['=']='+',
- ['[']='{',[']']='}',['\\']='|',
- [';']=':',['\'']='"',
- [',']='<',['.']='>',['/']='?',
- }
- function STRING.shiftChar(c)
- return shiftMap[c]or upper(c)
- end
-end
-
-function STRING.trim(s)
- if not s:find("%S")then return""end
- s=s:sub((s:find("%S"))):reverse()
- return s:sub((s:find("%S"))):reverse()
-end
-
-function STRING.split(s,sep,regex)
- local L={}
- local p1,p2=1--start,target
- if regex then
- while p1<=#s do
- p2=find(s,sep,p1)or #s+1
- L[#L+1]=sub(s,p1,p2-1)
- p1=p2+#sep
- end
- else
- while p1<=#s do
- p2=find(s,sep,p1,true)or #s+1
- L[#L+1]=sub(s,p1,p2-1)
- p1=p2+#sep
- end
- end
- return L
-end
-
-function STRING.simpEmailCheck(e)
- e=STRING.split(e,"@")
- if #e~=2 then return false end
- if e[1]:sub(-1)=="."or e[2]:sub(-1)=="."then return false end
- local e1,e2=STRING.split(e[1],"."),STRING.split(e[2],".")
- if #e1*#e2==0 then return false end
- for _,v in next,e1 do if #v==0 then return false end end
- for _,v in next,e2 do if #v==0 then return false end end
- return true
-end
-
-function STRING.time_simp(t)
- return format("%02d:%02d",int(t/60),int(t%60))
-end
-
-function STRING.time(t)
- if t<60 then
- return format("%.3f″",t)
- elseif t<3600 then
- return format("%d′%05.2f″",int(t/60),int(t%60*100)/100)
- else
- return format("%d:%.2d′%05.2f″",int(t/3600),int(t/60%60),int(t%60*100)/100)
- end
-end
-
-function STRING.UTF8(n)--Simple utf8 coding
- assert(type(n)=='number',"Wrong type ("..type(n)..")")
- assert(n>=0 and n<2^31,"Out of range ("..n..")")
- if n<2^7 then return char(n)
- elseif n<2^11 then return char(192+int(n/2^06),128+n%2^6)
- elseif n<2^16 then return char(224+int(n/2^12),128+int(n/2^06)%2^6,128+n%2^6)
- elseif n<2^21 then return char(240+int(n/2^18),128+int(n/2^12)%2^6,128+int(n/2^06)%2^6,128+n%2^6)
- elseif n<2^26 then return char(248+int(n/2^24),128+int(n/2^18)%2^6,128+int(n/2^12)%2^6,128+int(n/2^06)%2^6,128+n%2^6)
- elseif n<2^31 then return char(252+int(n/2^30),128+int(n/2^24)%2^6,128+int(n/2^18)%2^6,128+int(n/2^12)%2^6,128+int(n/2^06)%2^6,128+n%2^6)
- end
-end
-
-do--function STRING.bigInt(t)
- local lg=math.log10
- local units={"","K","M","B","T","Qa","Qt","Sx","Sp","Oc","No"}
- local preUnits={"","U","D","T","Qa","Qt","Sx","Sp","O","N"}
- local secUnits={"Dc","Vg","Tg","Qd","Qi","Se","St","Og","Nn","Ce"}--Ce is next-level unit, but DcCe is not used so used here
- for _,preU in next,preUnits do for _,secU in next,secUnits do table.insert(units,preU..secU)end end
- function STRING.bigInt(t)
- if t<1000 then
- return tostring(t)
- elseif t~=1e999 then
- local e=int(lg(t)/3)
- return(t/10^(e*3))..units[e+1]
- else
- return"INF"
- end
- end
-end
-
-function STRING.hexColor(str)--[LOW PERFORMENCE]
- assert(type(str)=='string')
- if str:sub(1,1)=="#"then str=str:sub(2)end
- assert(#str<=8)
- local r=(tonumber(str:sub(1,2),16)or 0)/255
- local g=(tonumber(str:sub(3,4),16)or 0)/255
- local b=(tonumber(str:sub(5,6),16)or 0)/255
- local a=(tonumber(str:sub(7,8),16)or 255)/255
- return r,g,b,a
-end
-
-do--function STRING.urlEncode(s)
- local rshift=bit.rshift
- local b16={[0]='0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}
- function STRING.urlEncode(s)
- local out=""
- for i=1,#s do
- if s:sub(i,i):match("[a-zA-Z0-9]")then
- out=out..s:sub(i,i)
- else
- local b=s:byte(i)
- out=out.."%"..b16[rshift(b,4)]..b16[b%16]
- end
- end
- return out
- end
-end
-
-function STRING.vcsEncrypt(text,key)
- local keyLen=#key
- local result=""
- local buffer=""
- for i=0,#text-1 do
- buffer=buffer..char((byte(text,i+1)-32+byte(key,i%keyLen+1))%95+32)
- if #buffer==26 then
- result=result..buffer
- buffer=""
- end
- end
- return result..buffer
-end
-function STRING.vcsDecrypt(text,key)
- local keyLen=#key
- local result=""
- local buffer=""
- for i=0,#text-1 do
- buffer=buffer..char((byte(text,i+1)-32-byte(key,i%keyLen+1))%95+32)
- if #buffer==26 then
- result=result..buffer
- buffer=""
- end
- end
- return result..buffer
-end
-function STRING.digezt(text)--Not powerful hash, just protect the original text
- local out={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
- local seed=26
- for i=1,#text do
- local c=byte(text,i)
- seed=(seed+c)%26
- c=c+seed
- local pos=c*i%16
- local step=(c+i)%4+1
- local times=2+(c%6)
- for _=1,times do
- out[pos+1]=(out[pos+1]+c)%256
- pos=(pos+step)%16
- end
- end
- local result=""
- for i=1,16 do result=result..char(out[i])end
- return result
-end
-
-function STRING.readLine(str)
- local p=str:find("\n")
- if p then
- return str:sub(1,p-1),str:sub(p+1)
- else
- return str,""
- end
-end
-function STRING.readChars(str,n)
- return sub(str,1,n),sub(str,n+1)
-end
-
-function STRING.packBin(s)
- return data.encode('string','base64',data.compress('string','zlib',s))
-end
-function STRING.unpackBin(str)
- local res
- res,str=pcall(data.decode,'string','base64',str)
- if not res then return end
- res,str=pcall(data.decompress,'string','zlib',str)
- if res then return str end
-end
-function STRING.packText(s)
- return data.encode('string','base64',data.compress('string','gzip',s))
-end
-function STRING.unpackText(str)
- local res
- res,str=pcall(data.decode,'string','base64',str)
- if not res then return end
- res,str=pcall(data.decompress,'string','gzip',str)
- if res then return str end
-end
-function STRING.packTable(t)
- return STRING.packText(JSON.encode(t))
-end
-function STRING.unpackTable(t)
- return JSON.decode(STRING.unpackText(t))
-end
-
-return STRING
diff --git a/Zframework/sysFX.lua b/Zframework/sysFX.lua
deleted file mode 100644
index 07ddef2cb..000000000
--- a/Zframework/sysFX.lua
+++ /dev/null
@@ -1,205 +0,0 @@
-local gc=love.graphics
-local gc_setColor,gc_setLineWidth=gc.setColor,gc.setLineWidth
-local gc_draw,gc_line=gc.draw,gc.line
-local gc_rectangle,gc_circle=gc.rectangle,gc.circle
-
-local max,min=math.max,math.min
-local rnd=math.random
-local ins,rem=table.insert,table.remove
-
-local fx={}
-
-local function _normUpdate(S,dt)
- S.t=S.t+dt*S.rate
- return S.t>1
-end
-
-local FXupdate={}
-function FXupdate.badge(S,dt)
- S.t=S.t+dt
- if S.t<.2 then
- S.x,S.y=S.x1-14,S.y1-14
- elseif S.t<.8 then
- local t=((S.t-.2)*1.6667)
- t=(3-2*t)*t*t
- S.x,S.y=S.x1*(1-t)+S.x2*t-14,S.y1*(1-t)+S.y2*t-14
- else
- S.x,S.y=S.x2-14,S.y2-14
- end
- return S.t>=1
-end
-FXupdate.attack=_normUpdate
-FXupdate.tap=_normUpdate
-FXupdate.ripple=_normUpdate
-FXupdate.rectRipple=_normUpdate
-FXupdate.shade=_normUpdate
-function FXupdate.cell(S,dt)
- if S.vx then
- S.x=S.x+S.vx*S.rate
- S.y=S.y+S.vy*S.rate
- if S.ax then
- S.vx=S.vx+S.ax*S.rate
- S.vy=S.vy+S.ay*S.rate
- end
- end
- S.t=S.t+dt*S.rate
- return S.t>1
-end
-FXupdate.line=_normUpdate
-
-local FXdraw={}
-function FXdraw.badge(S)
- gc_setColor(1,1,1,S.t<.2 and S.t*.6 or S.t<.8 and 1 or(1-S.t)*.6)
- gc_draw(IMG.badgeIcon,S.x,S.y)
-end
-function FXdraw.attack(S)
- gc_setColor(S.r*2,S.g*2,S.b*2,S.a*min(4-S.t*4,1))
-
- gc_setLineWidth(S.wid)
- local t1,t2=max(5*S.t-4,0),min(S.t*4,1)
- gc_line(
- S.x1*(1-t1)+S.x2*t1,
- S.y1*(1-t1)+S.y2*t1,
- S.x1*(1-t2)+S.x2*t2,
- S.y1*(1-t2)+S.y2*t2
- )
-
- gc_setLineWidth(S.wid*.6)
- t1,t2=max(4*S.t-3,0),min(S.t*5,1)
- gc_line(
- S.x1*(1-t1)+S.x2*t1,
- S.y1*(1-t1)+S.y2*t1,
- S.x1*(1-t2)+S.x2*t2,
- S.y1*(1-t2)+S.y2*t2
- )
-end
-function FXdraw.tap(S)
- local t=S.t
- gc_setColor(1,1,1,(1-t)*.4)
- gc_circle('fill',S.x,S.y,30*(1-t)^.5)
-end
-function FXdraw.ripple(S)
- local t=S.t
- gc_setLineWidth(2)
- gc_setColor(1,1,1,1-t)
- gc_circle('line',S.x,S.y,t*(2-t)*S.r)
-end
-function FXdraw.rectRipple(S)
- gc_setLineWidth(6)
- gc_setColor(1,1,1,1-S.t)
- local r=(10*S.t)^1.2
- gc_rectangle('line',S.x-r,S.y-r,S.w+2*r,S.h+2*r)
-end
-function FXdraw.shade(S)
- gc_setColor(S.r,S.g,S.b,1-S.t)
- gc_rectangle('fill',S.x,S.y,S.w,S.h,2)
-end
-function FXdraw.cell(S)
- gc_setColor(1,1,1,1-S.t)
- gc_draw(S.image,S.x,S.y,nil,S.size,nil,S.cx,S.cy)
-end
-function FXdraw.line(S)
- gc_setColor(1,1,1,S.a*(1-S.t))
- gc_line(S.x1,S.y1,S.x2,S.y2)
-end
-
-local SYSFX={}
-function SYSFX.update(dt)
- for i=#fx,1,-1 do
- if fx[i]:update(dt)then
- rem(fx,i)
- end
- end
-end
-function SYSFX.draw()
- for i=1,#fx do
- fx[i]:draw()
- end
-end
-
-function SYSFX.newBadge(x1,y1,x2,y2)
- ins(fx,{
- update=FXupdate.badge,
- draw=FXdraw.badge,
- t=0,
- x=x1,y=y1,
- x1=x1,y1=y1,
- x2=x2,y2=y2,
- })
-end
-function SYSFX.newAttack(rate,x1,y1,x2,y2,wid,r,g,b,a)
- ins(fx,{
- update=FXupdate.attack,
- draw=FXdraw.attack,
- t=0,
- rate=rate,
- x1=x1,y1=y1,--Start pos
- x2=x2,y2=y2,--End pos
- wid=wid,--Line width
- r=r,g=g,b=b,a=a,
- })
-end
-function SYSFX.newTap(rate,x,y)
- local T=
- {
- update=FXupdate.tap,
- draw=FXdraw.tap,
- t=0,
- rate=rate,
- x=x,y=y,
- }
- ins(fx,T)
-end
-function SYSFX.newRipple(rate,x,y,r)
- ins(fx,{
- update=FXupdate.ripple,
- draw=FXdraw.ripple,
- t=0,
- rate=rate,
- x=x,y=y,r=r,
- })
-end
-function SYSFX.newRectRipple(rate,x,y,w,h)
- ins(fx,{
- update=FXupdate.rectRipple,
- draw=FXdraw.rectRipple,
- t=0,
- rate=rate,
- x=x,y=y,w=w,h=h,
- })
-end
-function SYSFX.newShade(rate,x,y,w,h,r,g,b)
- ins(fx,{
- update=FXupdate.shade,
- draw=FXdraw.shade,
- t=0,
- rate=rate,
- x=x,y=y,w=w,h=h,
- r=r or 1,g=g or 1,b=b or 1,
- })
-end
-function SYSFX.newCell(rate,image,size,x,y,vx,vy,ax,ay)
- ins(fx,{
- update=FXupdate.cell,
- draw=FXdraw.cell,
- t=0,
- rate=rate*(.9+rnd()*.2),
- image=image,size=size,
- cx=image:getWidth()*.5,cy=image:getHeight()*.5,
- x=x,y=y,
- vx=vx,vy=vy,
- ax=ax,ay=ay,
- })
-end
-function SYSFX.newLine(rate,x1,y1,x2,y2,r,g,b,a)
- ins(fx,{
- update=FXupdate.line,
- draw=FXdraw.line,
- t=0,
- rate=rate,
- x1=x1 or 0,y1=y1 or 0,
- x2=x2 or x1 or 1280,y2=y2 or y1 or 720,
- r=r or 1,g=g or 1,b=b or 1,a=a or 1,
- })
-end
-return SYSFX
diff --git a/Zframework/tableExtend.lua b/Zframework/tableExtend.lua
deleted file mode 100644
index 7b5c46c57..000000000
--- a/Zframework/tableExtend.lua
+++ /dev/null
@@ -1,255 +0,0 @@
-local find=string.find
-local rem=table.remove
-local next,type=next,type
-local TABLE={}
-
---Get a new filled table
-function TABLE.new(val,count)
- local L={}
- for i=1,count do
- L[i]=val
- end
- return L
-end
-
---Get a copy of [1~#] elements
-function TABLE.shift(org,depth)
- if not depth then depth=1e99 end
- local L={}
- for i=1,#org do
- if type(org[i])=='table'and depth>0 then
- L[i]=TABLE.shift(org[i],depth-1)
- else
- L[i]=org[i]
- end
- end
- return L
-end
-
---Get a full copy of a table, depth = how many layers will be recreate, default to inf
-function TABLE.copy(org,depth)
- if not depth then depth=1e99 end
- local L={}
- for k,v in next,org do
- if type(v)=='table'and depth>0 then
- L[k]=TABLE.copy(v,depth-1)
- else
- L[k]=v
- end
- end
- return L
-end
-
---For all things in new, push to old
-function TABLE.cover(new,old)
- for k,v in next,new do
- old[k]=v
- end
-end
-
---For all things in new, push to old
-function TABLE.coverR(new,old)
- for k,v in next,new do
- if type(v)=='table'and type(old[k])=='table'then
- TABLE.coverR(v,old[k])
- else
- old[k]=v
- end
- end
-end
-
-
---For all things in new if same type in old, push to old
-function TABLE.update(new,old)
- for k,v in next,new do
- if type(v)==type(old[k])then
- if type(v)=='table'then
- TABLE.update(v,old[k])
- else
- old[k]=v
- end
- end
- end
-end
-
---For all things in new if no val in old, push to old
-function TABLE.complete(new,old)
- for k,v in next,new do
- if type(v)=='table'then
- if old[k]==nil then old[k]={}end
- TABLE.complete(v,old[k])
- elseif old[k]==nil then
- old[k]=v
- end
- end
-end
-
---Remove [1~#] of table
-function TABLE.cut(G)
- for i=1,#G do
- G[i]=nil
- end
-end
-
---Clear table
-function TABLE.clear(G)
- for k in next,G do
- G[k]=nil
- end
-end
-
---Remove duplicated value of [1~#]
-function TABLE.trimDuplicate(org)
- local cache={}
- for i=1,#org,-1 do
- if cache[org[i]]then
- rem(org,i)
- else
- cache[org[i]]=true
- end
- end
-end
-
---Discard duplicated value
-function TABLE.remDuplicate(org)
- local cache={}
- for k,v in next,org do
- if cache[v]then
- org[k]=nil
- else
- cache[v]=true
- end
- end
-end
-
-
---Reverse [1~#]
-function TABLE.reverse(org)
- local l=#org
- for i=1,math.floor(l/2)do
- org[i],org[l+1-i]=org[l+1-i],org[i]
- end
-end
-
---------------------------
-
---Find value in [1~#]
-function TABLE.find(t,val)
- for i=1,#t do if t[i]==val then return i end end
-end
-
---Return next value of [1~#] (by value)
-function TABLE.next(t,val)
- for i=1,#t do if t[i]==val then return t[i%#t+1]end end
-end
-
---------------------------
-
---Find value in whole table
-function TABLE.search(t,val)
- for k,v in next,t do if v==val then return k end end
-end
-
---Re-index string value of a table
-function TABLE.reIndex(org)
- for k,v in next,org do
- if type(v)=='string'then
- org[k]=org[v]
- end
- end
-end
-
---------------------------
-
---Dump a simple lua table
-do--function TABLE.dump(L,t)
- local tabs={
- [0]="",
- "\t",
- "\t\t",
- "\t\t\t",
- "\t\t\t\t",
- "\t\t\t\t\t",
- }
- local function dump(L,t)
- local s
- if t then
- s="{\n"
- else
- s="return{\n"
- t=1
- if type(L)~='table'then
- return
- end
- end
- local count=1
- for k,v in next,L do
- local T=type(k)
- if T=='number'then
- if k==count then
- k=""
- count=count+1
- else
- k="["..k.."]="
- end
- elseif T=='string'then
- if find(k,"[^0-9a-zA-Z_]")then
- k="[\""..k.."\"]="
- else
- k=k.."="
- end
- elseif T=='boolean'then k="["..k.."]="
- else error("Error key type!")
- end
- T=type(v)
- if T=='number'then v=tostring(v)
- elseif T=='string'then v="\""..v.."\""
- elseif T=='table'then v=dump(v,t+1)
- elseif T=='boolean'then v=tostring(v)
- else error("Error data type!")
- end
- s=s..tabs[t]..k..v..",\n"
- end
- return s..tabs[t-1].."}"
- end
- TABLE.dump=dump
-end
-
---Dump a simple lua table (no whitespaces)
-do--function TABLE.dumpDeflate(L,t)
- local function dump(L)
- local s="return{"
- if type(L)~='table'then return end
- local count=1
- for k,v in next,L do
- local T=type(k)
- if T=='number'then
- if k==count then
- k=""
- count=count+1
- else
- k="["..k.."]="
- end
- elseif T=='string'then
- if find(k,"[^0-9a-zA-Z_]")then
- k="[\""..k.."\"]="
- else
- k=k.."="
- end
- elseif T=='boolean'then k="["..k.."]="
- else error("Error key type!")
- end
- T=type(v)
- if T=='number'then v=tostring(v)
- elseif T=='string'then v="\""..v.."\""
- elseif T=='table'then v=dump(v)
- elseif T=='boolean'then v=tostring(v)
- else error("Error data type!")
- end
- end
- return s.."}"
- end
- TABLE.dumpDeflate=dump
-end
-
-return TABLE
diff --git a/Zframework/task.lua b/Zframework/task.lua
deleted file mode 100644
index 6de252260..000000000
--- a/Zframework/task.lua
+++ /dev/null
@@ -1,56 +0,0 @@
-local rem=table.remove
-local assert,resume,status=assert,coroutine.resume,coroutine.status
-local tasks={}
-
-local TASK={}
-function TASK.getCount()
- return #tasks
-end
-local trigFrame=0
-function TASK.update(dt)
- trigFrame=trigFrame+dt*60
- while trigFrame>=1 do
- for i=#tasks,1,-1 do
- local T=tasks[i]
- if status(T.thread)=='dead'then
- rem(tasks,i)
- else
- assert(resume(T.thread))
- end
- end
- trigFrame=trigFrame-1
- end
-end
-function TASK.new(code,...)
- local thread=coroutine.create(code)
- assert(resume(thread,...))
- if status(thread)~='dead'then
- tasks[#tasks+1]={
- thread=thread,
- code=code,
- args={...},
- }
- end
-end
-function TASK.removeTask_code(code)
- for i=#tasks,1,-1 do
- if tasks[i].code==code then
- rem(tasks,i)
- end
- end
-end
-function TASK.removeTask_iterate(func,...)
- for i=#tasks,1,-1 do
- if func(tasks[i],...)then
- rem(tasks,i)
- end
- end
-end
-function TASK.clear()
- local i=#tasks
- while i>0 do
- tasks[i]=nil
- i=i-1
- end
-end
-return TASK
diff --git a/Zframework/test.lua b/Zframework/test.lua
deleted file mode 100644
index 46be780cb..000000000
--- a/Zframework/test.lua
+++ /dev/null
@@ -1,12 +0,0 @@
-local TEST={}
-
---Wait for the scene swapping animation to finish
-function TEST.yieldUntilNextScene()
- while SCN.swapping do YIELD()end
-end
-
-function TEST.yieldN(frames)
- for _=1,frames do YIELD()end
-end
-
-return TEST
diff --git a/Zframework/text.lua b/Zframework/text.lua
deleted file mode 100644
index ddc464e50..000000000
--- a/Zframework/text.lua
+++ /dev/null
@@ -1,153 +0,0 @@
-local gc=love.graphics
-local getColor,setColor=gc.getColor,gc.setColor
-
-local int,rnd=math.floor,math.random
-local ins,rem=table.insert,table.remove
-local draw=gc.draw
-
-local texts={}
-
-local textFX={}
-function textFX.appear(t)
- draw(
- t.text,t.x,t.y,
- nil,
- nil,nil,
- t.text:getWidth()*.5,t.text:getHeight()*.5
- )
-end
-function textFX.sudden(t)
- setColor(1,1,1,1-t.c)
- draw(
- t.text,t.x,t.y,
- nil,
- nil,nil,
- t.text:getWidth()*.5,t.text:getHeight()*.5
- )
-end
-function textFX.fly(t)
- draw(
- t.text,t.x+(t.c-.5)^3*300,t.y,
- nil,
- nil,nil,
- t.text:getWidth()*.5,t.text:getHeight()*.5
- )
-end
-function textFX.stretch(t)
- draw(
- t.text,t.x,t.y,
- nil,
- t.c<.3 and(.3-t.c)*1.6+1 or 1,1,
- t.text:getWidth()*.5,t.text:getHeight()*.5
- )
-end
-function textFX.drive(t)
- draw(
- t.text,t.x,t.y,
- nil,
- nil,nil,
- t.text:getWidth()*.5,t.text:getHeight()*.5,
- t.c<.3 and(.3-t.c)*2 or 0,0
- )
-end
-function textFX.spin(t)
- draw(
- t.text,t.x,t.y,
- t.c<.3 and(.3-t.c)^2*4 or t.c<.8 and 0 or(t.c-.8)^2*-4,
- nil,nil,
- t.text:getWidth()*.5,t.text:getHeight()*.5
- )
-end
-function textFX.flicker(t)
- local _,_,_,T=getColor()
- setColor(1,1,1,T*(rnd()+.5))
- draw(
- t.text,t.x,t.y,
- nil,
- nil,nil,
- t.text:getWidth()*.5,t.text:getHeight()*.5
- )
-end
-function textFX.zoomout(t)
- draw(
- t.text,t.x,t.y,
- nil,
- t.c^.5*.1+1,nil,
- t.text:getWidth()*.5,t.text:getHeight()*.5
- )
-end
-function textFX.beat(t)
- local k=t.c<.3 and 1.3-t.c^2/.3 or 1
- draw(
- t.text,t.x,t.y,
- nil,
- k,k,
- t.text:getWidth()*.5,t.text:getHeight()*.5
- )
-end
-function textFX.score(t)
- local _,_,_,T=getColor()
- setColor(1,1,1,T*.5)
- draw(
- t.text,t.x,t.y-0-t.c^.2*50,
- nil,
- nil,nil,
- t.text:getWidth()*.5,t.text:getHeight()*.5
- )
-end
-
-local TEXT={}
-function TEXT.clear()
- texts={}
-end
-function TEXT.show(text,x,y,font,style,spd,stop)
- ins(texts,{
- c=0, --Timer
- text=gc.newText(FONT.get(int(font/5)*5 or 40),text), --String
- x=x or 0, --X
- y=y or 0, --Y
- spd=(spd or 1), --Timing speed(1=last 1 sec)
- stop=stop, --Stop time(sustained text)
- draw=assert(textFX[style or'appear'],"no text type:"..style),--Draw method
- })
-end
-function TEXT.getText(text,x,y,font,style,spd,stop)--Another version of TEXT.show(), but only return text object, need manual management
- return{
- c=0,
- text=gc.newText(FONT.get(int(font/5)*5 or 40),text),
- x=x or 0,
- y=y or 0,
- spd=(spd or 1),
- stop=stop,
- draw=textFX[style or'appear']or error("unavailable type:"..style),
- }
-end
-function TEXT.update(dt,list)
- if not list then
- list=texts
- end
- for i=#list,1,-1 do
- local t=list[i]
- t.c=t.c+t.spd*dt
- if t.stop then
- if t.c>t.stop then
- t.c=t.stop
- end
- end
- if t.c>1 then
- rem(list,i)
- end
- end
-end
-function TEXT.draw(list)
- if not list then
- list=texts
- end
- for i=1,#list do
- local t=list[i]
- local p=t.c
- setColor(1,1,1,p<.2 and p*5 or p<.8 and 1 or 5-p*5)
- t:draw()
- end
-end
-return TEXT
diff --git a/Zframework/vibrate.lua b/Zframework/vibrate.lua
deleted file mode 100644
index 9443b01b2..000000000
--- a/Zframework/vibrate.lua
+++ /dev/null
@@ -1,12 +0,0 @@
-local level={0,0,.01,.016,.023,.03,.04,.05,.06,.07,.08,.09,.12,.15}
-local vib=love.system.vibrate
-return love.system.getOS()=='iOS'and
- function(t)
- t=level[t]
- if t then vib(t<=.03 and 1 or t<=.09 and 2 or 3)end
- end
-or
- function(t)
- t=level[t]
- if t then vib(t)end
- end
\ No newline at end of file
diff --git a/Zframework/voice.lua b/Zframework/voice.lua
deleted file mode 100644
index 4963bc3d0..000000000
--- a/Zframework/voice.lua
+++ /dev/null
@@ -1,132 +0,0 @@
-local rnd=math.random
-local volume=1
-local diversion=0
-local VOC={
- getCount=function()return 0 end,
- getQueueCount=function()return 0 end,
- load=function()error("Cannot load before init!")end,
- getFreeChannel=NULL,
- play=NULL,
- update=NULL,
-}
-function VOC.setDiversion(n)
- assert(type(n)=='number'and n>0 and n<12,'Wrong div')
- diversion=n
-end
-function VOC.setVol(v)
- assert(type(v)=='number'and v>=0 and v<=1,'Wrong volume')
- volume=v
-end
-function VOC.init(list)
- VOC.init=nil
- local rem=table.remove
- local voiceQueue={free=0}
- local bank={}--{vocName1={SRC1s},vocName2={SRC2s},...}
- local Source={}
-
- local count=#list function VOC.getCount()return count end
- local function _loadVoiceFile(path,N,vocName)
- local fullPath=path..vocName..'.ogg'
- if love.filesystem.getInfo(fullPath)then
- bank[vocName]={love.audio.newSource(fullPath,'stream')}
- table.insert(Source[N],vocName)
- return true
- end
- end
- --Load voice with string
- local function _getVoice(str)
- local L=bank[str]
- local n=1
- while L[n]:isPlaying()do
- n=n+1
- if not L[n]then
- L[n]=L[1]:clone()
- L[n]:seek(0)
- break
- end
- end
- return L[n]
- end
- function VOC.load(path)
- for i=1,count do
- Source[list[i]]={}
-
- local n=0
- repeat n=n+1 until not _loadVoiceFile(path,list[i],list[i]..'_'..n)
-
- if n==1 then
- if not _loadVoiceFile(path,list[i],list[i])then
- LOG("No VOC: "..list[i],.1)
- end
- end
- if not Source[list[i]][1]then
- Source[list[i]]=nil
- end
- end
-
- function VOC.getQueueCount()
- return #voiceQueue
- end
- function VOC.getFreeChannel()
- local l=#voiceQueue
- for i=1,l do
- if #voiceQueue[i]==0 then return i end
- end
- voiceQueue[l+1]={s=0}
- return l+1
- end
-
- function VOC.play(s,chn)
- if volume>0 then
- local _=Source[s]
- if not _ then return end
- if chn then
- local L=voiceQueue[chn]
- L[#L+1]=_[rnd(#_)]
- L.s=1
- --Add to queue[chn]
- else
- voiceQueue[VOC.getFreeChannel()]={s=1,_[rnd(#_)]}
- --Create new channel & play
- end
- end
- end
- function VOC.update()
- for i=#voiceQueue,1,-1 do
- local Q=voiceQueue[i]
- if Q.s==0 then--Free channel, auto delete when >3
- if i>3 then
- rem(voiceQueue,i)
- end
- elseif Q.s==1 then--Waiting load source
- Q[1]=_getVoice(Q[1])
- Q[1]:setVolume(volume)
- Q[1]:setPitch(1.0594630943592953^(diversion*(rnd()*2-1)))
- Q[1]:play()
- Q.s=Q[2]and 2 or 4
- elseif Q.s==2 then--Playing 1,ready 2
- if Q[1]:getDuration()-Q[1]:tell()<.08 then
- Q[2]=_getVoice(Q[2])
- Q[2]:setVolume(volume)
- Q[1]:setPitch(1.0594630943592953^(diversion*(rnd()*2-1)))
- Q[2]:play()
- Q.s=3
- end
- elseif Q.s==3 then--Playing 12 same time
- if not Q[1]:isPlaying()then
- for j=1,#Q do
- Q[j]=Q[j+1]
- end
- Q.s=Q[2]and 2 or 4
- end
- elseif Q.s==4 then--Playing last
- if not Q[1].isPlaying(Q[1])then
- Q[1]=nil
- Q.s=0
- end
- end
- end
- end
- end
-end
-return VOC
diff --git a/Zframework/websocket.lua b/Zframework/websocket.lua
deleted file mode 100644
index fca1e70c5..000000000
--- a/Zframework/websocket.lua
+++ /dev/null
@@ -1,191 +0,0 @@
-local host=
- -- '127.0.0.1'
- -- '192.168.114.102'
- 'game.techmino.org'
-local port='10026'
-local path='/tech/socket/v1'
-
--- lua + LÖVE threading websocket client
--- Original pure lua ver. by flaribbit and Particle_G
--- Threading version by MrZ
-
-local type=type
-local timer=love.timer.getTime
-local CHN=love.thread.newChannel()
-local CHN_getCount,CHN_push,CHN_pop=CHN.getCount,CHN.push,CHN.pop
-local TRD=love.thread.newThread("\n")
-local TRD_isRunning=TRD.isRunning
-
-local WS={}
-local wsList=setmetatable({},{
- __index=function(l,k)
- local ws={
- real=false,
- status='dead',
- lastPongTime=timer(),
- sendTimer=0,
- alertTimer=0,
- pongTimer=0,
- }
- l[k]=ws
- return ws
- end
-})
-
-function WS.switchHost(_1,_2,_3)
- for k in next,wsList do
- WS.close(k)
- end
- host=_1
- port=_2 or port
- path=_3 or path
-end
-
-function WS.connect(name,subPath,body,timeout)
- if wsList[name]and wsList[name].thread then
- wsList[name].thread:release()
- end
- local ws={
- real=true,
- thread=love.thread.newThread('Zframework/websocket_thread.lua'),
- triggerCHN=love.thread.newChannel(),
- sendCHN=love.thread.newChannel(),
- readCHN=love.thread.newChannel(),
- lastPingTime=0,
- lastPongTime=timer(),
- pingInterval=6,
- status='connecting',--'connecting', 'running', 'dead'
- sendTimer=0,
- alertTimer=0,
- pongTimer=0,
- }
- wsList[name]=ws
- ws.thread:start(ws.triggerCHN,ws.sendCHN,ws.readCHN)
- CHN_push(ws.sendCHN,host)
- CHN_push(ws.sendCHN,port)
- CHN_push(ws.sendCHN,path..subPath)
- CHN_push(ws.sendCHN,body or"")
- CHN_push(ws.sendCHN,timeout or 2.6)
-end
-
-function WS.status(name)
- local ws=wsList[name]
- return ws.status or'dead'
-end
-
-function WS.getTimers(name)
- local ws=wsList[name]
- return ws.pongTimer,ws.sendTimer,ws.alertTimer
-end
-
-function WS.setPingInterval(name,time)
- local ws=wsList[name]
- ws.pingInterval=math.max(time or 2.6,2.6)
-end
-
-function WS.alert(name)
- local ws=wsList[name]
- ws.alertTimer=2.6
-end
-
-local OPcode={
- continue=0,
- text=1,
- binary=2,
- close=8,
- ping=9,
- pong=10,
-}
-local OPname={
- [0]='continue',
- [1]='text',
- [2]='binary',
- [8]='close',
- [9]='ping',
- [10]='pong',
-}
-function WS.send(name,message,op)
- if type(message)=='string'then
- local ws=wsList[name]
- if ws.real and ws.status=='running'then
- CHN_push(ws.sendCHN,op and OPcode[op]or 2)--2=binary
- CHN_push(ws.sendCHN,message)
- ws.lastPingTime=timer()
- ws.sendTimer=1
- end
- else
- MES.new('error',"Attempt to send non-string value!")
- MES.traceback()
- end
-end
-
-function WS.read(name)
- local ws=wsList[name]
- if ws.real and ws.status~='connecting'and CHN_getCount(ws.readCHN)>=2 then
- local op,message=CHN_pop(ws.readCHN),CHN_pop(ws.readCHN)
- if op==8 then--8=close
- ws.status='dead'
- elseif op==9 then--9=ping
- WS.send(name,message or"",'pong')
- end
- ws.lastPongTime=timer()
- ws.pongTimer=1
- return message,OPname[op]or op
- end
-end
-
-function WS.close(name)
- local ws=wsList[name]
- if ws.real then
- CHN_push(ws.sendCHN,8)--close
- CHN_push(ws.sendCHN,"")
- ws.status='dead'
- end
-end
-
-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 CHN_getCount(ws.triggerCHN)==0 then
- CHN_push(ws.triggerCHN,0)
- end
- if ws.status=='connecting'then
- local mes=CHN_pop(ws.readCHN)
- if mes then
- if mes=='success'then
- ws.status='running'
- ws.lastPingTime=time
- ws.lastPongTime=time
- ws.pongTimer=1
- else
- ws.status='dead'
- MES.new('warn',text.wsFailed..": "..(mes=="timeout"and text.netTimeout or mes))
- end
- end
- elseif ws.status=='running'then
- if time-ws.lastPingTime>ws.pingInterval then
- WS.send(name,"",'pong')
- end
- if time-ws.lastPongTime>6+2*ws.pingInterval then
- WS.close(name)
- end
- end
- if ws.sendTimer>0 then ws.sendTimer=ws.sendTimer-dt end
- if ws.pongTimer>0 then ws.pongTimer=ws.pongTimer-dt end
- if ws.alertTimer>0 then ws.alertTimer=ws.alertTimer-dt end
- else
- ws.status='dead'
- local err=ws.thread:getError()
- if err then
- err=err:sub((err:find(":",(err:find(":")or 0)+1)or 0)+1,(err:find("\n")or 0)-1)
- MES.new('warn',text.wsClose..err)
- WS.alert(name)
- end
- end
- end
- end
-end
-
-return WS
diff --git a/Zframework/websocket_thread.lua b/Zframework/websocket_thread.lua
deleted file mode 100644
index db4dc5488..000000000
--- a/Zframework/websocket_thread.lua
+++ /dev/null
@@ -1,191 +0,0 @@
-local triggerCHN,sendCHN,readCHN=...
-
-local CHN_demand,CHN_getCount=triggerCHN.demand,triggerCHN.getCount
-local CHN_push,CHN_pop=triggerCHN.push,triggerCHN.pop
-
-local SOCK=require'socket'.tcp()
-local JSON=require'Zframework.json'
-
-do--Connect
- local host=CHN_demand(sendCHN)
- local port=CHN_demand(sendCHN)
- local path=CHN_demand(sendCHN)
- local body=CHN_demand(sendCHN)
- local timeout=CHN_demand(sendCHN)
-
- SOCK:settimeout(timeout)
- local res,err=SOCK:connect(host,port)
- assert(res,err)
-
- --WebSocket handshake
- if not body then body=''end
- SOCK:send(
- 'GET '..path..' HTTP/1.1\r\n'..
- 'Host: '..host..':'..port..'\r\n'..
- 'Connection: Upgrade\r\n'..
- 'Upgrade: websocket\r\n'..
- 'Content-Type: application/json\r\n'..
- 'Content-Length: '..#body..'\r\n'..
- 'Sec-WebSocket-Version: 13\r\n'..
- 'Sec-WebSocket-Key: osT3F7mvlojIvf3/8uIsJQ==\r\n\r\n'..--secKey
- body
- )
-
- --First line of HTTP
- res,err=SOCK:receive('*l')
- assert(res,err)
- local code,ctLen
- code=res:find(' ')
- code=res:sub(code+1,code+3)
-
- --Get body length from headers and remove headers
- repeat
- res,err=SOCK:receive('*l')
- assert(res,err)
- if not ctLen and res:find('length')then
- ctLen=tonumber(res:match('%d+'))
- end
- until res==''
-
- --Result
- if ctLen then
- if code=='101'then
- CHN_push(readCHN,'success')
- else
- res,err=SOCK:receive(ctLen)
- res=JSON.decode(assert(res,err))
- error((code or"XXX")..":"..(res and res.reason or"Server Error"))
- end
- end
- SOCK:settimeout(0)
-end
-
-local YIELD=coroutine.yield
-local byte,char=string.byte,string.char
-local band,bor,bxor=bit.band,bit.bor,bit.bxor
-local shl,shr=bit.lshift,bit.rshift
-
-local mask_key={1,14,5,14}
-local mask_str=char(unpack(mask_key))
-local function _send(op,message)
- --Message type
- SOCK:send(char(bor(op,0x80)))
-
- if message then
- --Length
- local length=#message
- if length>65535 then
- SOCK:send(char(bor(127,0x80),0,0,0,0,band(shr(length,24),0xff),band(shr(length,16),0xff),band(shr(length,8),0xff),band(length,0xff)))
- elseif length>125 then
- SOCK:send(char(bor(126,0x80),band(shr(length,8),0xff),band(length,0xff)))
- else
- SOCK:send(char(bor(length,0x80)))
- end
- local msgbyte={byte(message,1,length)}
- for i=1,length do
- msgbyte[i]=bxor(msgbyte[i],mask_key[(i-1)%4+1])
- end
- return SOCK:send(mask_str..char(unpack(msgbyte)))
- else
- SOCK:send('\128'..mask_str)
- return 0
- end
-end
-local sendThread=coroutine.wrap(function()
- while true do
- while CHN_getCount(sendCHN)>=2 do
- _send(CHN_pop(sendCHN),CHN_pop(sendCHN))
- end
- YIELD()
- end
-end)
-
-local function _receive(sock,len)
- local buffer=""
- while true do
- local r,e,p=sock:receive(len)
- if r then
- buffer=buffer..r
- len=len-#r
- elseif p then
- buffer=buffer..p
- len=len-#p
- elseif e then
- return nil,e
- end
- if len==0 then
- return buffer
- end
- YIELD()
- end
-end
-local readThread=coroutine.wrap(function()
- local res,err
- local op,fin
- local lBuffer=""--Long multi-pack buffer
- while true do
- --Byte 0-1
- res,err=_receive(SOCK,2)
- assert(res,err)
-
- op=band(byte(res,1),0x0f)
- fin=band(byte(res,1),0x80)==0x80
-
- --Calculating data length
- local length=band(byte(res,2),0x7f)
- if length==126 then
- res,err=_receive(SOCK,2)
- assert(res,err)
- length=shl(byte(res,1),8)+byte(res,2)
- elseif length==127 then
- local lenData
- lenData,err=_receive(SOCK,8)
- assert(res,err)
- local _,_,_,_,_5,_6,_7,_8=byte(lenData,1,8)
- length=shl(_5,24)+shl(_6,16)+shl(_7,8)+_8
- end
- res,err=_receive(SOCK,length)
- assert(res,err)
-
- --React
- if op==8 then--8=close
- CHN_push(readCHN,8)--close
- if type(res)=='string'then
- CHN_push(readCHN,res:sub(3))--[Warning] 2 bytes close code at start so :sub(3)
- else
- CHN_push(readCHN,"WS closed")
- end
- return
- elseif op==0 then--0=continue
- lBuffer=lBuffer..res
- if fin then
- CHN_push(readCHN,lBuffer)
- lBuffer=""
- end
- else
- CHN_push(readCHN,op)
- if fin then
- CHN_push(readCHN,res)
- lBuffer=""
- else
- lBuffer=res
- end
- end
- YIELD()
- end
-end)
-
-local success,err
-
-while true do--Running
- CHN_demand(triggerCHN)
- success,err=pcall(sendThread)
- if not success or err then break end
- success,err=pcall(readThread)
- if not success or err then break end
-end
-
-SOCK:close()
-CHN_push(readCHN,8)--close
-CHN_push(readCHN,err or"Disconnected")
-error()
diff --git a/Zframework/wheelScroll.lua b/Zframework/wheelScroll.lua
deleted file mode 100644
index 5e6024e8f..000000000
--- a/Zframework/wheelScroll.lua
+++ /dev/null
@@ -1,19 +0,0 @@
-local love=love
-local max,min=math.max,math.min
-local trigDist=0
-return function(y,key1,key2)
- if y>0 then
- trigDist=max(trigDist,0)+y^1.2
- elseif y<0 then
- if trigDist>0 then trigDist=0 end
- trigDist=min(trigDist,0)-(-y)^1.2
- end
- while trigDist>=1 do
- love.keypressed(key1 or'up')
- trigDist=trigDist-1
- end
- while trigDist<=-1 do
- love.keypressed(key2 or'down')
- trigDist=trigDist+1
- end
-end
diff --git a/Zframework/widget.lua b/Zframework/widget.lua
deleted file mode 100644
index a22b5d252..000000000
--- a/Zframework/widget.lua
+++ /dev/null
@@ -1,1499 +0,0 @@
-local gc=love.graphics
-local gc_origin=gc.origin
-local gc_translate,gc_replaceTransform=gc.translate,gc.replaceTransform
-local gc_stencil,gc_setStencilTest=gc.stencil,gc.setStencilTest
-local gc_push,gc_pop=gc.push,gc.pop
-local gc_setCanvas,gc_setBlendMode=gc.setCanvas,gc.setBlendMode
-local gc_setColor,gc_setLineWidth=gc.setColor,gc.setLineWidth
-local gc_draw,gc_line=gc.draw,gc.line
-local gc_rectangle=gc.rectangle
-local gc_print,gc_printf=gc.print,gc.printf
-
-local kb=love.keyboard
-local timer=love.timer.getTime
-
-local next=next
-local int,ceil=math.floor,math.ceil
-local max,min=math.max,math.min
-local sub,ins,rem=string.sub,table.insert,table.remove
-local xOy=SCR.xOy
-local FONT=FONT
-local mStr=GC.mStr
-local approach=MATH.expApproach
-
-local downArrowIcon=GC.DO{40,25,{'fPoly',0,0,20,25,40,0}}
-local upArrowIcon=GC.DO{40,25,{'fPoly',0,25,20,0,40,25}}
-local clearIcon=GC.DO{40,40,
- {'fRect',16,5,8,3},
- {'fRect',8,8,24,3},
- {'fRect',11,14,18,21},
-}
-local sureIcon=GC.DO{40,40,
- {'rawFT',35},
- {'mText',"?",20,0},
-}
-local smallerThen=GC.DO{20,20,
- {'setLW',5},
- {'line',18,2,1,10,18,18},
-}
-local largerThen=GC.DO{20,20,
- {'setLW',5},
- {'line',2,2,19,10,2,18},
-}
-
-local STW,STH--stencil-wid/hei
-local function _rectangleStencil()
- gc.rectangle('fill',1,1,STW-2,STH-2)
-end
-
-local onChange=NULL
-
-local WIDGET={}
-
-function WIDGET.setOnChange(func)onChange=assert(type(func)=='function'and func,"WIDGET.setOnChange(func): func must be a function")end
-
-local widgetMetatable={
- __tostring=function(self)
- return self:getInfo()
- end,
-}
-
-local text={
- type='text',
- mustHaveText=true,
- alpha=0,
-}
-
-function text:reset()end
-function text:update(dt)
- if self.hideF and self.hideF()then
- if self.alpha>0 then
- self.alpha=max(self.alpha-dt*7.5,0)
- end
- elseif self.alpha<1 then
- self.alpha=min(self.alpha+dt*7.5,1)
- end
-end
-function text:draw()
- if self.alpha>0 then
- local c=self.color
- gc_setColor(c[1],c[2],c[3],self.alpha)
- local w=self.obj:getWidth()
- local k=min(self.lim/self.obj:getWidth(),1)
- if self.align=='M'then
- gc_draw(self.obj,self.x,self.y,nil,k,1,w*.5,0)
- elseif self.align=='L'then
- gc_draw(self.obj,self.x,self.y,nil,k,1)
- elseif self.align=='R'then
- gc_draw(self.obj,self.x,self.y,nil,k,1,w,0)
- end
- end
-end
-function WIDGET.newText(D)--name,x,y[,lim][,fText][,color][,font=30][,fType][,align='M'][,hideF][,hide]
- local _={
- name= D.name or"_",
- x= D.x,
- y= D.y,
- lim= D.lim or 1e99,
-
- fText=D.fText,
- color=D.color and(COLOR[D.color]or D.color)or COLOR.Z,
- font= D.font or 30,
- fType=D.fType,
- align=D.align or'M',
- hideF=D.hideF,
- }
- for k,v in next,text do _[k]=v end
- if not _.hideF then _.alpha=1 end
- setmetatable(_,widgetMetatable)
- return _
-end
-
-local image={
- type='image',
-}
-function image:reset()
- if type(self.img)=='string'then
- self.img=IMG[self.img]
- end
-end
-function image:draw()
- gc_setColor(1,1,1,self.alpha)
- gc_draw(self.img,self.x,self.y,self.ang,self.k)
-end
-function WIDGET.newImage(D)--name[,img(name)],x,y[,ang][,k][,hideF][,hide]
- local _={
- name= D.name or"_",
- img= D.img or D.name or"_",
- alpha=D.alpha,
- x= D.x,
- y= D.y,
- ang= D.ang,
- k= D.k,
- hideF=D.hideF,
- hide= D.hide,
- }
- for k,v in next,image do _[k]=v end
- setmetatable(_,widgetMetatable)
- return _
-end
-
-local button={
- type='button',
- mustHaveText=true,
- ATV=0,--Activating time(0~8)
-}
-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)
- elseif obj then
- self.obj=obj
- end
-end
-function button:isAbove(x,y)
- local ATV=self.ATV
- return
- x>self.x-ATV and
- y>self.y and
- x0 then self.ATV=max(ATV-dt*30,0)end
- end
-end
-function button:draw()
- local x,y,w,h=self.x,self.y,self.w,self.h
- local ATV=self.ATV
- local c=self.color
- local r,g,b=c[1],c[2],c[3]
-
- --Button
- gc_setColor(.15+r*.7,.15+g*.7,.15+b*.7,.9)
- gc_rectangle('fill',x-ATV,y,w+2*ATV,h,4)
- gc_setLineWidth(2)
- gc_setColor(.3+r*.7,.3+g*.7,.3+b*.7)
- gc_rectangle('line',x-ATV,y,w+2*ATV,h,5)
- if ATV>0 then
- gc_setColor(.97,.97,.97,ATV*.125)
- gc_rectangle('line',x-ATV,y,w+2*ATV,h,3)
- end
-
- --Drawable
- local obj=self.obj
- 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
- local edge=self.edge
- gc_draw(obj,x+edge-1,y0-1-oy)
- gc_draw(obj,x+edge-1,y0+1-oy)
- gc_draw(obj,x+edge+1,y0-1-oy)
- gc_draw(obj,x+edge+1,y0+1-oy)
- gc_setColor(r*.55,g*.55,b*.55)
- gc_draw(obj,x+edge,y0-oy)
- elseif self.align=='R'then
- local x0=x+w-self.edge-ox*2
- gc_draw(obj,x0-1,y0-1-oy)
- gc_draw(obj,x0-1,y0+1-oy)
- gc_draw(obj,x0+1,y0-1-oy)
- gc_draw(obj,x0+1,y0+1-oy)
- gc_setColor(r*.55,g*.55,b*.55)
- gc_draw(obj,x0,y0-oy)
- end
-end
-function button:getInfo()
- return("x=%d,y=%d,w=%d,h=%d,font=%d"):format(self.x+self.w*.5,self.y+self.h*.5,self.w,self.h,self.font,self.fType)
-end
-function button:press(_,_,k)
- self.code(k)
- local ATV=self.ATV
- SYSFX.newRectRipple(
- 6,
- self.x-ATV,
- self.y-WIDGET.scrollPos,
- self.w+2*ATV,
- self.h
- )
- if self.sound then
- SFX.play(self.sound)
- end
-end
-function WIDGET.newButton(D)--name,x,y,w[,h][,fText][,color][,font=30][,fType][,sound][,align='M'][,edge=0][,code][,hideF][,hide]
- if not D.h then D.h=D.w end
- local _={
- name= D.name or"_",
-
- x= D.x-D.w*.5,
- y= D.y-D.h*.5,
- w= D.w,
- h= D.h,
-
- resCtr={
- D.x,D.y,
- D.x-D.w*.35,D.y-D.h*.35,
- D.x-D.w*.35,D.y+D.h*.35,
- D.x+D.w*.35,D.y-D.h*.35,
- D.x+D.w*.35,D.y+D.h*.35,
- },
-
- fText=D.fText,
- color=D.color and(COLOR[D.color]or D.color)or COLOR.Z,
- font= D.font or 30,
- fType=D.fType,
- align=D.align or'M',
- edge= D.edge or 0,
- code= D.code or NULL,
- hideF=D.hideF,
- hide= D.hide,
- }
- if D.sound==false then
- _.sound=false
- elseif type(D.sound)=='string'then
- _.sound=D.sound
- else
- _.sound='button'
- end
-
- for k,v in next,button do _[k]=v end
- setmetatable(_,widgetMetatable)
- return _
-end
-
-local key={
- type='key',
- mustHaveText=true,
- ATV=0,--Activating time(0~4)
-}
-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)
- elseif obj then
- self.obj=obj
- end
-end
-function key:isAbove(x,y)
- return
- x>self.x and
- y>self.y and
- x0 then self.ATV=max(ATV-dt*30,0)end
- end
-end
-function key:draw()
- local x,y,w,h=self.x,self.y,self.w,self.h
- local ATV=self.ATV
- local c=self.color
- local align=self.align
- local r,g,b=c[1],c[2],c[3]
-
- --Fill
- if self.fShade then
- gc_setColor(r,g,b,ATV*.25)
- if align=='M'then
- gc_draw(self.fShade,x+w*.5-self.fShade:getWidth()*.5,y+h*.5-self.fShade:getHeight()*.5)
- elseif align=='L'then
- gc_draw(self.fShade,x+self.edge,y+h*.5-self.fShade:getHeight()*.5)
- elseif align=='R'then
- gc_draw(self.fShade,x+w-self.edge-self.fShade:getWidth(),y+h*.5-self.fShade:getHeight()*.5)
- end
- else
- --Background
- gc_setColor(0,0,0,.3)
- gc_rectangle('fill',x,y,w,h,4)
-
- --Frame
- gc_setColor(.2+r*.8,.2+g*.8,.2+b*.8,.7)
- gc_setLineWidth(2)
- gc_rectangle('line',x,y,w,h,3)
-
- --Shade
- gc_setColor(1,1,1,ATV*.05)
- gc_rectangle('fill',x,y,w,h,3)
- end
-
- --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)
- elseif align=='R'then
- gc_draw(obj,x+w-self.edge-ox*2,y-oy+h*.5)
- end
-end
-function key:getInfo()
- return("x=%d,y=%d,w=%d,h=%d,font=%d"):format(self.x+self.w*.5,self.y+self.h*.5,self.w,self.h,self.font,self.fType)
-end
-function key:press(_,_,k)
- self.code(k)
- if self.sound then
- SFX.play(self.sound)
- end
-end
-function WIDGET.newKey(D)--name,x,y,w[,h][,fText][,fShade][,color][,font=30][,fType][,sound][,align='M'][,edge=0][,code][,hideF][,hide]
- if not D.h then D.h=D.w end
- local _={
- name= D.name or"_",
-
- x= D.x-D.w*.5,
- y= D.y-D.h*.5,
- w= D.w,
- h= D.h,
-
- resCtr={
- D.x,D.y,
- D.x-D.w*.35,D.y-D.h*.35,
- D.x-D.w*.35,D.y+D.h*.35,
- D.x+D.w*.35,D.y-D.h*.35,
- D.x+D.w*.35,D.y+D.h*.35,
- },
-
- fText= D.fText,
- fShade= D.fShade,
- color= D.color and(COLOR[D.color]or D.color)or COLOR.Z,
- font= D.font or 30,
- fType= D.fType,
- align= D.align or'M',
- edge= D.edge or 0,
- code= D.code or NULL,
- hideF= D.hideF,
- hide= D.hide,
- }
- if D.sound==false then
- _.sound=false
- elseif type(D.sound)=='string'then
- _.sound=D.sound
- else
- _.sound='key'
- end
- for k,v in next,key do _[k]=v end
- setmetatable(_,widgetMetatable)
- return _
-end
-
-local switch={
- type='switch',
- mustHaveText=true,
- ATV=0,--Activating time(0~8)
- CHK=0,--Check alpha(0~6)
-}
-function switch:reset()
- self.ATV=0
- self.CHK=0
-end
-function switch:isAbove(x,y)
- return x>self.x and xself.y-25 and y0 then self.ATV=max(ATV-dt*30,0)end
- end
- local chk=self.CHK
- if self:disp()then
- if chk<6 then self.CHK=min(chk+dt*60,6)end
- else
- if chk>0 then self.CHK=max(chk-dt*60,0)end
- end
-end
-function switch:draw()
- local x,y=self.x,self.y
- local ATV=self.ATV
-
- --Background
- gc_setColor(0,0,0,.3)
- gc_rectangle('fill',x,y-25,50,50,4)
-
- --Frame
- gc_setLineWidth(2)
- gc_setColor(1,1,1,.6+ATV*.1)
- gc_rectangle('line',x,y-25,50,50,3)
-
- --Checked
- if ATV>0 then
- gc_setColor(1,1,1,ATV*.06)
- gc_rectangle('fill',x,y-25,50,50,3)
- end
- if self.CHK>0 then
- gc_setColor(.9,1,.9,self.CHK/6)
- gc_setLineWidth(5)
- gc_line(x+5,y,x+18,y+13,x+45,y-14)
- end
-
- --Drawable
- local obj=self.obj
- gc_setColor(self.color)
- gc_draw(obj,x-12-ATV,y,nil,min(self.lim/obj:getWidth(),1),1,obj:getWidth(),obj:getHeight()*.5)
-end
-function switch:getInfo()
- return("x=%d,y=%d,font=%d"):format(self.x,self.y,self.font,self.fType)
-end
-function switch:press()
- self.code()
- if self.sound then
- SFX.play(self.disp()and'check'or'uncheck')
- end
-end
-function WIDGET.newSwitch(D)--name,x,y[,lim][,fText][,color][,font=30][,fType][,sound=true][,disp][,code][,hideF][,hide]
- local _={
- name= D.name or"_",
-
- x= D.x,
- y= D.y,
- lim= D.lim or 1e99,
-
- resCtr={
- D.x+25,D.y,
- },
-
- fText=D.fText,
- color=D.color and(COLOR[D.color]or D.color)or COLOR.Z,
- font= D.font or 30,
- fType=D.fType,
- sound=D.sound~=false,
- disp= D.disp,
- code= D.code or NULL,
- hideF=D.hideF,
- hide= D.hide,
- }
- for k,v in next,switch do _[k]=v end
- setmetatable(_,widgetMetatable)
- return _
-end
-
-local slider={
- type='slider',
- ATV=0,--Activating time(0~8)
- TAT=0,--Text activating time(0~180)
- pos=0,--Position shown
- lastTime=0,--Last value changing time
-}
-local sliderShowFunc={
- int=function(S)
- return S.disp()
- end,
- float=function(S)
- return int(S.disp()*100)*.01
- end,
- percent=function(S)
- return int(S.disp()*100).."%"
- end,
-}
-function slider:reset()
- self.ATV=0
- self.TAT=180
- self.pos=0
-end
-function slider:isAbove(x,y)
- return x>self.x-10 and xself.y-25 and y0 then
- self.TAT=max(self.TAT-dt*60,0)
- end
- if WIDGET.sel==self then
- if ATV<6 then self.ATV=min(ATV+dt*60,6)end
- self.TAT=180
- else
- if ATV>0 then self.ATV=max(ATV-dt*30,0)end
- end
- if not self.hide then
- self.pos=approach(self.pos,self.disp(),dt*26)
- end
-end
-function slider:draw()
- local x,y=self.x,self.y
- local ATV=self.ATV
- local x2=x+self.w
-
- gc_setColor(1,1,1,.5+ATV*.06)
-
- --Units
- if not self.smooth then
- gc_setLineWidth(2)
- for p=self.rangeL,self.rangeR,self.unit do
- local X=x+(x2-x)*(p-self.rangeL)/(self.rangeR-self.rangeL)
- gc_line(X,y+7,X,y-7)
- end
- end
-
- --Axis
- gc_setLineWidth(4)
- gc_line(x,y,x2,y)
-
- --Block
- local cx=x+(x2-x)*(self.pos-self.rangeL)/(self.rangeR-self.rangeL)
- local bx,by,bw,bh=cx-10-ATV*.5,y-16-ATV,20+ATV,32+2*ATV
- gc_setColor(.8,.8,.8)
- gc_rectangle('fill',bx,by,bw,bh,3)
-
- --Glow
- if ATV>0 then
- gc_setLineWidth(2)
- gc_setColor(.97,.97,.97,ATV*.16)
- gc_rectangle('line',bx+1,by+1,bw-2,bh-2,3)
- end
-
- --Float text
- if self.TAT>0 and self.show then
- FONT.set(25)
- gc_setColor(.97,.97,.97,self.TAT/180)
- mStr(self:show(),cx,by-30)
- end
-
- --Drawable
- local obj=self.obj
- if obj then
- gc_setColor(self.color)
- gc_draw(obj,x-12-ATV,y,nil,min(self.lim/obj:getWidth(),1),1,obj:getWidth(),obj:getHeight()*.5)
- end
-end
-function slider:getInfo()
- return("x=%d,y=%d,w=%d"):format(self.x,self.y,self.w)
-end
-function slider:press(x)
- self:drag(x)
-end
-function slider:drag(x)
- if not x then return end
- x=x-self.x
- local newPos=MATH.interval(x/self.w,0,1)
- local newVal
- if not self.unit then
- newVal=(1-newPos)*self.rangeL+newPos*self.rangeR
- else
- newVal=newPos*(self.rangeR-self.rangeL)
- newVal=self.rangeL+newVal-newVal%self.unit
- end
- if newVal~=self.disp()then
- self.code(newVal)
- end
- if self.change and timer()-self.lastTime>.5 then
- self.lastTime=timer()
- self.change()
- end
-end
-function slider:release(x)
- self:drag(x)
- self.lastTime=0
-end
-function slider:scroll(n)
- local p=self.disp()
- local u=self.unit or .01
- local P=MATH.interval(p+u*n,self.rangeL,self.rangeR)
- if p==P or not P then return end
- self.code(P)
- if self.change and timer()-self.lastTime>.18 then
- self.lastTime=timer()
- self.change()
- end
-end
-function slider:arrowKey(k)
- self:scroll((k=='left'or k=='up')and -1 or 1)
-end
-function WIDGET.newSlider(D)--name,x,y,w[,lim][,fText][,color][,axis][,smooth][,font=30][,fType][,change],disp[,show][,code],hide
- if not D.axis then
- D.axis={0,1,false}
- D.smooth=true
- elseif not D.axis[3]then
- D.smooth=true
- end
- local _={
- name= D.name or"_",
-
- x= D.x,
- y= D.y,
- w= D.w,
- lim= D.lim or 1e99,
-
- resCtr={
- D.x,D.y,
- D.x+D.w*.25,D.y,
- D.x+D.w*.5,D.y,
- D.x+D.w*.75,D.y,
- D.x+D.w,D.y,
- },
-
- fText= D.fText,
- color= D.color and(COLOR[D.color]or D.color)or COLOR.Z,
- rangeL=D.axis[1],
- rangeR=D.axis[2],
- unit= D.axis[3],
- smooth=D.smooth,
- font= D.font or 30,
- fType= D.fType,
- change=D.change,
- disp= D.disp,
- code= D.code or NULL,
- hideF= D.hideF,
- hide= D.hide,
- show= false,
- }
- if D.show then
- if type(D.show)=='function'then
- _.show=D.show
- else
- _.show=sliderShowFunc[D.show]
- end
- elseif D.show~=false then--Use default if nil
- if _.unit and _.unit%1==0 then
- _.show=sliderShowFunc.int
- else
- _.show=sliderShowFunc.percent
- end
- end
- for k,v in next,slider do _[k]=v end
- setmetatable(_,widgetMetatable)
- return _
-end
-
-local selector={
- type='selector',
- mustHaveText=true,
- ATV=8,--Activating time(0~4)
- select=false,--Selected item ID
- selText=false,--Selected item name
-}
-function selector:reset()
- self.ATV=0
- local V,L=self.disp(),self.list
- for i=1,#L do
- if L[i]==V then
- self.select=i
- self.selText=self.list[i]
- return
- end
- end
- self.select=0
- self.selText=""
- MES.new('error',"Selector "..self.name.." dead, disp= "..tostring(V))
-end
-function selector:isAbove(x,y)
- return
- x>self.x and
- xself.y and
- y0 then self.ATV=max(ATV-dt*30,0)end
- end
-end
-function selector:draw()
- local x,y=self.x,self.y
- local w=self.w
- local ATV=self.ATV
-
- --Background
- gc_setColor(0,0,0,.3)
- gc_rectangle('fill',x,y,w,60,4)
-
- --Frame
- gc_setColor(1,1,1,.6+ATV*.1)
- gc_setLineWidth(2)
- gc_rectangle('line',x,y,w,60,3)
-
- --Arrow
- gc_setColor(1,1,1,.2+ATV*.1)
- local t=(timer()%.5)^.5
- if self.select>1 then
- gc_draw(smallerThen,x+6,y+33)
- if ATV>0 then
- gc_setColor(1,1,1,ATV*.4*(.5-t))
- gc_draw(smallerThen,x+6-t*40,y+33)
- gc_setColor(1,1,1,.2+ATV*.1)
- end
- end
- if self.select<#self.list then
- gc_draw(largerThen,x+w-26,y+33)
- if ATV>0 then
- gc_setColor(1,1,1,ATV*.4*(.5-t))
- gc_draw(largerThen,x+w-26+t*40,y+33)
- end
- end
-
- --Drawable
- gc_setColor(self.color)
- gc_draw(self.obj,x+w*.5,y-4,nil,min((w-20)/self.obj:getWidth(),1),1,self.obj:getWidth()*.5,0)
- gc_setColor(1,1,1)
- FONT.set(30)
- mStr(self.selText,x+w*.5,y+22)
-end
-function selector:getInfo()
- return("x=%d,y=%d,w=%d"):format(self.x+self.w*.5,self.y+30,self.w)
-end
-function selector:press(x)
- if x then
- local s=self.select
- if x1 then
- s=s-1
- SYSFX.newShade(3,self.x,self.y-WIDGET.scrollPos,self.w*.5,60)
- end
- else
- if s<#self.list then
- s=s+1
- SYSFX.newShade(3,self.x+self.w*.5,self.y-WIDGET.scrollPos,self.w*.5,60)
- end
- end
- if self.select~=s then
- self.code(self.list[s])
- self.select=s
- self.selText=self.list[s]
- if self.sound then
- SFX.play('selector')
- end
- end
- end
-end
-function selector:scroll(n)
- local s=self.select
- if n==-1 then
- if s==1 then return end
- s=s-1
- SYSFX.newShade(3,self.x,self.y-WIDGET.scrollPos,self.w*.5,60)
- else
- if s==#self.list then return end
- s=s+1
- SYSFX.newShade(3,self.x+self.w*.5,self.y-WIDGET.scrollPos,self.w*.5,60)
- end
- self.code(self.list[s])
- self.select=s
- self.selText=self.list[s]
- if self.sound then
- SFX.play('selector')
- end
-end
-function selector:arrowKey(k)
- self:scroll((k=='left'or k=='up')and -1 or 1)
-end
-
-function WIDGET.newSelector(D)--name,x,y,w[,fText][,color][,sound=true],list,disp[,code],hide
- local _={
- name= D.name or"_",
-
- x= D.x-D.w*.5,
- y= D.y-30,
- w= D.w,
-
- resCtr={
- D.x,D.y,
- D.x+D.w*.25,D.y,
- D.x+D.w*.5,D.y,
- D.x+D.w*.75,D.y,
- D.x+D.w,D.y,
- },
-
- fText=D.fText,
- color=D.color and(COLOR[D.color]or D.color)or COLOR.Z,
- sound=D.sound~=false,
- font= 30,
- list= D.list,
- disp= D.disp,
- code= D.code or NULL,
- hideF=D.hideF,
- hide= D.hide,
- }
- for k,v in next,selector do _[k]=v end
- setmetatable(_,widgetMetatable)
- return _
-end
-
-local inputBox={
- type='inputBox',
- keepFocus=true,
- ATV=0,--Activating time(0~4)
- value="",--Text contained
-}
-function inputBox:reset()
- self.ATV=0
-end
-function inputBox:hasText()
- return #self.value>0
-end
-function inputBox:getText()
- return self.value
-end
-function inputBox:setText(str)
- if type(str)=='string'then
- self.value=str
- end
-end
-function inputBox:addText(str)
- if type(str)=='string'then
- self.value=self.value..str
- else
- MES.new('error',"inputBox "..self.name.." dead, addText("..type(str)..")")
- end
-end
-function inputBox:clear()
- self.value=""
-end
-function inputBox:isAbove(x,y)
- return
- x>self.x and
- y>self.y and
- x0 then self.ATV=max(ATV-dt*15,0)end
- end
-end
-function inputBox:draw()
- local x,y,w,h=self.x,self.y,self.w,self.h
- local ATV=self.ATV
-
- --Background
- gc_setColor(0,0,0,.4)
- gc_rectangle('fill',x,y,w,h,4)
-
- --Highlight
- gc_setColor(1,1,1,ATV*.08*(math.sin(TIME()*4.2)*.2+.8))
- gc_rectangle('fill',x,y,w,h,4)
-
- --Frame
- gc_setColor(1,1,1)
- gc_setLineWidth(3)
- gc_rectangle('line',x,y,w,h,3)
-
- --Drawable
- local f=self.font
- FONT.set(f,self.fType)
- if self.obj then
- gc_draw(self.obj,x-12-self.obj:getWidth(),y+h*.5-self.obj:getHeight()*.5)
- end
- if self.secret then
- y=y+h*.5-f*.2
- for i=1,#self.value do
- gc_rectangle("fill",x+f*.6*i,y,f*.4,f*.4)
- end
- else
- gc_printf(self.value,x+10,y,self.w)
- FONT.set(f-10)
- if WIDGET.sel==self then
- gc_print(EDITING,x+10,y+12-f*1.4)
- end
- end
-end
-function inputBox:getInfo()
- return("x=%d,y=%d,w=%d,h=%d"):format(self.x+self.w*.5,self.y+self.h*.5,self.w,self.h)
-end
-function inputBox:press()
- if MOBILE then
- local _,y1=xOy:transformPoint(0,self.y+self.h)
- kb.setTextInput(true,0,y1,1,1)
- end
-end
-function inputBox:keypress(k)
- local t=self.value
- if #t>0 and EDITING==""then
- if k=='backspace'then
- local p=#t
- while t:byte(p)>=128 and t:byte(p)<192 do
- p=p-1
- end
- t=sub(t,1,p-1)
- SFX.play('lock')
- elseif k=='delete'then
- t=""
- SFX.play('hold')
- end
- self.value=t
- end
-end
-function WIDGET.newInputBox(D)--name,x,y,w[,h][,font=30][,fType][,secret][,regex][,limit],hide
- local _={
- name= D.name or"_",
-
- x= D.x,
- y= D.y,
- w= D.w,
- h= D.h,
-
- resCtr={
- D.x+D.w*.2,D.y,
- D.x+D.w*.5,D.y,
- D.x+D.w*.8,D.y,
- },
-
- font= D.font or int(D.h/7-1)*5,
- fType= D.fType,
- secret=D.secret==true,
- regex= D.regex,
- limit= D.limit,
- hideF= D.hideF,
- hide= D.hide,
- }
- for k,v in next,inputBox do _[k]=v end
- setmetatable(_,widgetMetatable)
- return _
-end
-
-local textBox={
- type='textBox',
- scrollPos=0,--Scroll-down-distance
- sure=0,--Sure-timer for clear history
-}
-function textBox:reset()
- --haha nothing here, techmino is so fun!
-end
-function textBox:setTexts(t)
- self.texts=t
- self.scrollPos=0
-end
-function textBox:clear()
- self.texts={}
- self.scrollPos=0
- SFX.play('fall')
-end
-function textBox:isAbove(x,y)
- return
- x>self.x and
- y>self.y and
- x0 then
- self.sure=max(self.sure-dt,0)
- end
-end
-function textBox:push(t)
- ins(self.texts,t)
- if self.scrollPos==(#self.texts-1-self.capacity)*self.lineH then--minus 1 for the new message
- self.scrollPos=min(self.scrollPos+self.lineH,(#self.texts-self.capacity)*self.lineH)
- end
-end
-function textBox:press(x,y)
- if not(x and y)then return end
- self:drag(0,0,0,0)
- if not self.fix and x>self.x+self.w-40 and y0 then
- self:clear()
- self.sure=0
- else
- self.sure=1
- end
- end
-end
-function textBox:drag(_,_,_,dy)
- self.scrollPos=max(0,min(self.scrollPos-dy,(#self.texts-self.capacity)*self.lineH))
-end
-function textBox:scroll(dir)
- if type(dir)=='string'then
- if dir=="up"then
- dir=-1
- elseif dir=="down"then
- dir=1
- else
- return
- end
- end
- self:drag(nil,nil,nil,-dir*self.lineH)
-end
-function textBox:arrowKey(k)
- if k=='up'then
- self:scroll(-1)
- elseif k=='down'then
- self:scroll(-1)
- end
-end
-function textBox:draw()
- local x,y,w,h=self.x,self.y,self.w,self.h
- local texts=self.texts
- local scrollPos=self.scrollPos
- local cap=self.capacity
- local lineH=self.lineH
-
- --Background
- gc_setColor(0,0,0,.3)
- gc_rectangle('fill',x,y,w,h,4)
-
- --Frame
- gc_setLineWidth(2)
- gc_setColor(WIDGET.sel==self and COLOR.lN or COLOR.Z)
- gc_rectangle('line',x,y,w,h,3)
-
- --Texts
- FONT.set(self.font,self.fType)
- gc_push('transform')
- gc_translate(x,y)
-
- --Slider
- gc_setColor(1,1,1)
- if #texts>cap then
- local len=h*h/(#texts*lineH)
- gc_rectangle('fill',-15,(h-len)*scrollPos/((#texts-cap)*lineH),12,len,3)
- end
-
- --Clear button
- if not self.fix then
- gc_rectangle('line',w-40,0,40,40,3)
- gc_draw(self.sure==0 and clearIcon or sureIcon,w-40,0)
- end
-
- gc_setStencilTest('equal',1)
- STW,STH=w,h
- gc_stencil(_rectangleStencil)
- gc_translate(0,-(scrollPos%lineH))
- local pos=int(scrollPos/lineH)
- for i=pos+1,min(pos+cap+1,#texts)do
- gc_printf(texts[i],10,4,w-16)
- gc_translate(0,lineH)
- end
- gc_setStencilTest()
- gc_pop()
-end
-function textBox:getInfo()
- return("x=%d,y=%d,w=%d,h=%d"):format(self.x+self.w*.5,self.y+self.h*.5,self.w,self.h)
-end
-function WIDGET.newTextBox(D)--name,x,y,w,h[,font=30][,fType][,lineH][,fix],hide
- local _={
- name= D.name or"_",
-
- resCtr={
- D.x+D.w*.5,D.y+D.h*.5,
- D.x+D.w*.5,D.y,
- D.x-D.w*.5,D.y,
- D.x,D.y+D.h*.5,
- D.x,D.y-D.h*.5,
- D.x,D.y,
- D.x+D.w,D.y,
- D.x,D.y+D.h,
- D.x+D.w,D.y+D.h,
- },
-
- x= D.x,
- y= D.y,
- w= D.w,
- h= D.h,
-
- font= D.font or 30,
- fType=D.fType,
- fix= D.fix,
- texts={},
- hideF=D.hideF,
- hide= D.hide,
- }
- _.lineH=D.lineH or _.font*7/5
- _.capacity=ceil((D.h-10)/_.lineH)
-
- for k,v in next,textBox do _[k]=v end
- setmetatable(_,widgetMetatable)
- return _
-end
-
-local listBox={
- type='listBox',
- keepFocus=true,
- scrollPos=0,--Scroll-down-distance
- selected=0,--Hidden wheel move value
-}
-function listBox:reset()
- --haha nothing here too, techmino is really fun!
-end
-function listBox:clear()
- self.list={}
- self.scrollPos=0
-end
-function listBox:setList(t)
- self.list=t
- self.selected=1
- self.scrollPos=0
-end
-function listBox:getList()
- return self.list
-end
-function listBox:getLen()
- return #self.list
-end
-function listBox:getSel()
- return self.list[self.selected]
-end
-function listBox:isAbove(x,y)
- return
- x>self.x and
- y>self.y and
- x0 then
- rem(self.list)
- listBox:drag(0,0,0,0)
- end
-end
-function listBox:remove()
- if self.selected then
- rem(self.list,self.selected)
- if not self.list[self.selected]then
- self:arrowKey('up')
- end
- self:drag(0,0,0,0)
- end
-end
-function listBox:press(x,y)
- if not(x and y)then return end
- x,y=x-self.x,y-self.y
- if not(x and y and x>0 and y>0 and x<=self.w and y<=self.h)then return end
- self:drag(0,0,0,0)
- y=int((y+self.scrollPos)/self.lineH)+1
- if self.list[y]then
- if self.selected~=y then
- self.selected=y
- SFX.play('selector',.8,0,12)
- end
- end
-end
-function listBox:drag(_,_,_,dy)
- self.scrollPos=max(0,min(self.scrollPos-dy,(#self.list-self.capacity)*self.lineH))
-end
-function listBox:scroll(n)
- self:drag(nil,nil,nil,-n*self.lineH)
-end
-function listBox:arrowKey(dir)
- if dir=="up"then
- self.selected=max(self.selected-1,1)
- if self.selectedint(self.scrollPos/self.lineH)+self.capacity-1 then
- self:drag(nil,nil,nil,-self.lineH)
- end
- end
-end
-function listBox:select(i)
- self.selected=i
- if self.selectedint(self.scrollPos/self.lineH)+self.capacity-1 then
- self:drag(nil,nil,nil,-1e99)
- end
-end
-function listBox:draw()
- local x,y,w,h=self.x,self.y,self.w,self.h
- local list=self.list
- local scrollPos=self.scrollPos
- local cap=self.capacity
- local lineH=self.lineH
-
- gc_push('transform')
- gc_translate(x,y)
-
- --Background
- gc_setColor(0,0,0,.4)
- gc_rectangle('fill',0,0,w,h,4)
-
- --Frame
- gc_setColor(WIDGET.sel==self and COLOR.lN or COLOR.Z)
- gc_setLineWidth(2)
- gc_rectangle('line',0,0,w,h,3)
-
- --Slider
- if #list>cap then
- gc_setColor(1,1,1)
- local len=h*h/(#list*lineH)
- gc_rectangle('fill',-15,(h-len)*scrollPos/((#list-cap)*lineH),12,len,3)
- end
-
- --List
- gc_setStencilTest('equal',1)
- STW,STH=w,h
- gc_stencil(_rectangleStencil)
- local pos=int(scrollPos/lineH)
- gc_translate(0,-(scrollPos%lineH))
- for i=pos+1,min(pos+cap+1,#list)do
- self.drawF(list[i],i,i==self.selected)
- gc_translate(0,lineH)
- end
- gc_setStencilTest()
- gc_pop()
-end
-function listBox:getInfo()
- return("x=%d,y=%d,w=%d,h=%d"):format(self.x+self.w*.5,self.y+self.h*.5,self.w,self.h)
-end
-function WIDGET.newListBox(D)--name,x,y,w,h,lineH,drawF[,hideF][,hide]
- local _={
- name= D.name or"_",
-
- resCtr={
- D.x+D.w*.5,D.y+D.h*.5,
- D.x+D.w*.5,D.y,
- D.x-D.w*.5,D.y,
- D.x,D.y+D.h*.5,
- D.x,D.y-D.h*.5,
- D.x,D.y,
- D.x+D.w,D.y,
- D.x,D.y+D.h,
- D.x+D.w,D.y+D.h,
- },
-
- x= D.x,
- y= D.y,
- w= D.w,
- h= D.h,
-
- list= {},
- lineH= D.lineH,
- capacity=ceil(D.h/D.lineH),
- drawF= D.drawF,
- hideF= D.hideF,
- hide= D.hide,
- }
-
- for k,v in next,listBox do _[k]=v end
- setmetatable(_,widgetMetatable)
- return _
-end
-
-WIDGET.active={}--Table contains all active widgets
-WIDGET.scrollHeight=0--Max drag height, not actual container height!
-WIDGET.scrollPos=0--Current scroll position
-WIDGET.sel=false--Selected widget
-WIDGET.indexMeta={
- __index=function(L,k)
- for i=1,#L do
- if L[i].name==k then
- return L[i]
- end
- end
- end
-}
-function WIDGET.setWidgetList(list)
- WIDGET.unFocus(true)
- WIDGET.active=list or NONE
- WIDGET.cursorMove(SCR.xOy:inverseTransformPoint(love.mouse.getPosition()))
-
- --Reset all widgets
- if list then
- for i=1,#list do
- list[i]:reset()
- end
- onChange()
- end
-end
-function WIDGET.setScrollHeight(height)
- WIDGET.scrollHeight=height and height or 0
- WIDGET.scrollPos=0
-end
-function WIDGET.setLang(widgetText)
- for S,L in next,SCN.scenes do
- if L.widgetList then
- for _,W in next,L.widgetList do
- local t=W.fText or widgetText[S][W.name]
- if not t and W.mustHaveText then
- 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)
- end
- W.obj=t
- end
- end
- end
-end
-function WIDGET.getSelected()
- return WIDGET.sel
-end
-function WIDGET.isFocus(W)
- if W then
- return W and WIDGET.sel==W
- else
- return WIDGET.sel~=false
- end
-end
-function WIDGET.focus(W)
- if WIDGET.sel==W then return end
- if WIDGET.sel and WIDGET.sel.type=='inputBox'then
- kb.setTextInput(false)
- EDITING=""
- end
- WIDGET.sel=W
- if W and W.type=='inputBox'then
- local _,y1=xOy:transformPoint(0,W.y+W.h)
- kb.setTextInput(true,0,y1,1,1)
- end
-end
-function WIDGET.unFocus(force)
- local W=WIDGET.sel
- if W and(force or not W.keepFocus)then
- if W.type=='inputBox'then
- kb.setTextInput(false)
- EDITING=""
- end
- WIDGET.sel=false
- end
-end
-
-function WIDGET.cursorMove(x,y)
- for _,W in next,WIDGET.active do
- if not W.hide and W.resCtr and W:isAbove(x,y+WIDGET.scrollPos)then
- WIDGET.focus(W)
- return
- end
- end
- if WIDGET.sel and not WIDGET.sel.keepFocus then
- WIDGET.unFocus()
- end
-end
-function WIDGET.press(x,y,k)
- local W=WIDGET.sel
- if W then
- W:press(x,y and y+WIDGET.scrollPos,k)
- if W.hide then WIDGET.unFocus()end
- end
-end
-function WIDGET.drag(x,y,dx,dy)
- if WIDGET.sel then
- local W=WIDGET.sel
- if W.drag then
- W:drag(x,y+WIDGET.scrollPos,dx,dy)
- elseif not W:isAbove(x,y+WIDGET.scrollPos)then
- WIDGET.unFocus(true)
- end
- else
- WIDGET.scrollPos=max(min(WIDGET.scrollPos-dy,WIDGET.scrollHeight),0)
- end
-end
-function WIDGET.release(x,y)
- local W=WIDGET.sel
- if W and W.release then
- W:release(x,y+WIDGET.scrollPos)
- end
-end
-function WIDGET.textinput(texts)
- local W=WIDGET.sel
- if W and W.type=='inputBox'then
- if(not W.regex or texts:match(W.regex))and(not W.limit or #(WIDGET.sel.value..texts)<=W.limit)then
- WIDGET.sel.value=WIDGET.sel.value..texts
- SFX.play('touch')
- else
- SFX.play('drop_cancel')
- end
- end
-end
-
-function WIDGET.update(dt)
- for _,W in next,WIDGET.active do
- if W.hideF then
- W.hide=W.hideF()
- if W.hide and W==WIDGET.sel then
- WIDGET.unFocus(true)
- end
- end
- if W.update then W:update(dt)end
- end
-end
-local widgetCanvas
-local widgetCover do
- local L={1,360,{'fRect',0,30,1,300}}
- for i=0,30 do
- ins(L,{'setCL',1,1,1,i/30})
- ins(L,{'fRect',0,i,1,2})
- ins(L,{'fRect',0,360-i,1,2})
- end
- widgetCover=GC.DO(L)
-end
-local scr_w,scr_h
-function WIDGET.resize(w,h)
- scr_w,scr_h=w,h
- widgetCanvas=gc.newCanvas(w,h)
-end
-function WIDGET.draw()
- gc_setCanvas({stencil=true},widgetCanvas)
- gc_translate(0,-WIDGET.scrollPos)
- for _,W in next,WIDGET.active do
- if not W.hide then W:draw()end
- end
- gc_origin()
- gc_setColor(1,1,1)
- if WIDGET.scrollHeight>0 then
- if WIDGET.scrollPos>0 then
- gc_draw(upArrowIcon,scr_w*.5,10,0,SCR.k,nil,upArrowIcon:getWidth()*.5,0)
- end
- if WIDGET.scrollPos>'..k)print(debug.traceback():match("\n.-\n\t(.-): "))rawset(self,k,v)end})
+-- Var leak check
+-- setmetatable(_G,{__newindex=function(self,k,v) print('>>'..k..string.rep(" ",26-#k),debug.traceback():match("\n.-\n\t(.-): "))rawset(self,k,v) end})
---System Global Vars Declaration
+-- System Global Vars Declaration
local fs=love.filesystem
VERSION=require"version"
TIME=love.timer.getTime
-YIELD=coroutine.yield
-SYSTEM=love.system.getOS()if SYSTEM=='OS X'then SYSTEM='macOS'end
-FNNS=SYSTEM:find'\79\83'--What does FNSF stand for? IDK so don't ask me lol
-MOBILE=SYSTEM=='Android'or SYSTEM=='iOS'
-SAVEDIR=fs.getSaveDirectory()
---Global Vars & Settings
+-- Global Vars & Settings
SFXPACKS={'chiptune'}
-VOCPACKS={'miya',--[['mono',]]'xiaoya','miku'}
+VOCPACKS={'miya','mono','xiaoya','flore','miku','zundamon'}
FIRSTLAUNCH=false
DAILYLAUNCH=false
---System setting
+-- System setting
math.randomseed(os.time()*626)
love.setDeprecationOutput(false)
love.keyboard.setKeyRepeat(true)
love.keyboard.setTextInput(false)
-if MOBILE then
- local w,h,f=love.window.getMode()
- f.resizable=false
- love.window.setMode(w,h,f)
-end
local _LOADTIMELIST_={}
local _LOADTIME_=TIME()
---Load modules
+-- Load modules
Z=require'Zframework'
FONT.load{
- norm='parts/fonts/proportional.ttf',
- mono='parts/fonts/monospaced.ttf',
+ norm='parts/fonts/proportional.otf',
+ mono='parts/fonts/monospaced.otf',
}
FONT.setDefault('norm')
FONT.setFallback('norm')
-SCR.setSize(1280,720)--Initialize Screen size
+SCR.setSize(1280,720)-- Initialize Screen size
BGM.setMaxSources(5)
-BGM.setChange(function(name)MES.new('music',text.nowPlaying..name,5)end)
VOC.setDiversion(.62)
WIDGET.setOnChange(function()
- if SCN.cur~='custom_field'then
+ if SCN.cur~='net_game' and SCN.cur~='custom_field' then
local colorList=THEME.getThemeColor()
- if not colorList then return end
- local rnd=math.random
- for _,W in next,SCN.scenes[SCN.cur].widgetList do
- if W.color then
- W.color=colorList[rnd(#colorList)]
+ if colorList then
+ for _,W in next,SCN.scenes[SCN.cur].widgetList do
+ if W.color then
+ W.color=colorList[math.random(#colorList)]
+ end
end
end
end
end)
-table.insert(_LOADTIMELIST_,("Load Zframework: %.3fs"):format(TIME()-_LOADTIME_))
-
---Create shortcuts
+-- Create shortcuts
setFont=FONT.set
getFont=FONT.get
-mStr=GC.mStr
mText=GC.simpX
-mDraw=GC.draw
+mDraw=GC.mDraw
Snd=SFX.playSample
string.repD=STRING.repD
string.sArg=STRING.sArg
string.split=STRING.split
---Delete all naked files (from too old version)
+-- Delete all naked files (from ancient versions)
FILE.clear('')
---Create directories
-for _,v in next,{'conf','record','replay','cache','lib'}do
+-- Create directories
+for _,v in next,{'conf','record','replay','cache','lib'} do
local info=fs.getInfo(v)
if not info then
fs.createDirectory(v)
- elseif info.type~='directory'then
+ elseif info.type~='directory' then
fs.remove(v)
fs.createDirectory(v)
end
end
-CHAR=require'parts.char'
-require'parts.gameTables'
-require'parts.gameFuncs'
-
---Load shader files from SOURCE ONLY
+-- Load shader files from SOURCE ONLY
SHADER={}
-for _,v in next,fs.getDirectoryItems('parts/shaders')do
- if isSafeFile('parts/shaders/'..v)then
+for _,v in next,fs.getDirectoryItems('parts/shaders') do
+ if FILE.isSafe('parts/shaders/'..v) then
local name=v:sub(1,-6)
SHADER[name]=love.graphics.newShader('parts/shaders/'..name..'.glsl')
end
end
+-- Load modules
+CHAR=require'parts.char'
+require'parts.gameTables'
+require'parts.gameFuncs'
+
THEME= require'parts.theme'
LINE= require'parts.line'
DATA= require'parts.data'
@@ -125,7 +111,7 @@ USERS= require'parts.users'
NET= require'parts.net'
VK= require'parts.virtualKey'
BOT= require'parts.bot'
-RSlist= require'parts.RSlist'DSCP=RSlist.TRS.centerPos
+RSlist= require'parts.RSlist'; DSCP=RSlist.TRS.centerPos
PLY= require'parts.player'
NETPLY= require'parts.netPlayer'
MODES= require'parts.modes'
@@ -136,10 +122,29 @@ setmetatable(TEXTURE,{__index=function(self,k)
return self[k]
end})
-table.insert(_LOADTIMELIST_,("Load Parts: %.3fs"):format(TIME()-_LOADTIME_))
+-- Load mode files
+for i=1,#MODES do
+ local m=MODES[i]-- Mode template
+ if FILE.isSafe('parts/modes/'..m.name) then
+ TABLE.complete(require('parts.modes.'..m.name),MODES[i])
+ MODES[m.name],MODES[i]=MODES[i]
+ end
+end
+for _,v in next,fs.getDirectoryItems('parts/modes') do
+ if FILE.isSafe('parts/modes/'..v) and not MODES[v:sub(1,-5)] then
+ local M={name=v:sub(1,-5)}
+ local modeData=require('parts.modes.'..M.name)
+ if modeData.env then
+ TABLE.complete(modeData,M)
+ MODES[M.name]=M
+ end
+ end
+end
+
+table.insert(_LOADTIMELIST_,("Load Modules: %.3fs"):format(TIME()-_LOADTIME_))
---Init Zframework
-do--Z.setCursor
+-- Initialize Zframework
+do-- Z.setCursor
local normImg=GC.DO{16,16,
{'fCirc',8,8,4},
{'setCL',1,1,1,.7},
@@ -150,28 +155,26 @@ do--Z.setCursor
{'dCirc',8,8,7},
{'fCirc',8,8,3},
}
- local min,int,abs=math.min,math.floor,math.abs
- local gc_setColor,gc_draw=love.graphics.setColor,love.graphics.draw
- local ms=love.mouse
+ local _
Z.setCursor(function(time,x,y)
if not SETTING.sysCursor then
- local R=int((time+1)/2)%7+1
+ local R=math.floor((time+1)/2)%7+1
_=BLOCK_COLORS[SETTING.skin[R]]
- gc_setColor(_[1],_[2],_[3],min(abs(1-time%2),.3))
+ GC.setColor(_[1],_[2],_[3],math.min(math.abs(1-time%2),.3))
_=DSCP[R][0]
- gc_draw(TEXTURE.miniBlock[R],x,y,time%3.14159265359*4,16,16,_[2]+.5,#BLOCKS[R][0]-_[1]-.5)
- gc_setColor(1,1,1)
- gc_draw(ms.isDown(1)and holdImg or normImg,x,y,nil,nil,nil,8,8)
+ GC.draw(TEXTURE.miniBlock[R],x,y,time%math.pi*4,8,8,2*_[2]+1,2*(#BLOCKS[R][0]-_[1])-1)
+ GC.setColor(1,1,1)
+ GC.draw(love.mouse.isDown(1) and holdImg or normImg,x,y,nil,nil,nil,8,8)
end
end)
end
Z.setOnFnKeys({
- function()MES.new('check',PROFILE.switch()and"profile start!"or"profile report copied!")end,
- function()MES.new('info',("System:%s[%s]\nluaVer:%s\njitVer:%s\njitVerNum:%s"):format(SYSTEM,jit.arch,_VERSION,jit.version,jit.version_num))end,
- function()MES.new('error',"挂了")end,
+ function() MES.new('check',PROFILE.switch() and "profile start!" or "profile report copied!") end,
+ function() MES.new('info',("System:%s[%s]\nluaVer:%s\njitVer:%s\njitVerNum:%s"):format(SYSTEM,jit.arch,_VERSION,jit.version,jit.version_num)) end,
+ function() MES.new('error',"挂了") end,
function()
if GAME.playing and not GAME.net then
- for _=1,8 do
+ for _=1,1 do
if #PLY_ALIVE>1 then
local P=PLY_ALIVE[math.random(2,#PLY_ALIVE)]
P.lastRecv=PLAYERS[1]
@@ -180,20 +183,25 @@ Z.setOnFnKeys({
end
end
end,
- function()print(WIDGET.getSelected()or"no widget selected")end,
- function()for k,v in next,_G do print(k,v)end end,
- function()if love['_openConsole']then love['_openConsole']()end end,
+ function() print(BG.locked) end,
+ function() for k,v in next,_G do print(k,v) end end,
+ function() if love['_openConsole'] then love['_openConsole']() end end,
})
+Z.setOnGlobalKey('f11',function()
+ if not MOBILE then
+ SETTING.fullscreen=not SETTING.fullscreen
+ applySettings()
+ saveSettings()
+ end
+end)
+Z.setVersionText(VERSION.string)
Z.setDebugInfo{
{"Cache",gcinfo},
{"Tasks",TASK.getCount},
{"Voices",VOC.getQueueCount},
{"Audios",love.audio.getSourceCount},
}
-Z.setOnResize(function(w,_)
- SHADER.warning:send('w',w*SCR.dpi)
-end)
-do--Z.setOnFocus
+do-- Z.setOnFocus
local function task_autoSoundOff()
while true do
coroutine.yield()
@@ -221,52 +229,28 @@ do--Z.setOnFocus
TASK.new(task_autoSoundOn)
end
else
- if SCN.cur=='game'and SETTING.autoPause then
+ if SCN.cur=='game' and SETTING.autoPause then
pauseGame()
end
- if SETTING.autoMute then
+ if SETTING.autoMute and SCN.cur~='music' then
TASK.removeTask_code(task_autoSoundOn)
TASK.new(task_autoSoundOff)
end
end
end)
end
-Z.setOnQuit(destroyPlayers)
-
---Load settings and statistics
-TABLE.cover (loadFile('conf/user','-canSkip')or{},USER)
-TABLE.cover (loadFile('conf/unlock','-canSkip')or{},RANKS)
-TABLE.update(loadFile('conf/settings','-canSkip')or{},SETTING)
-TABLE.coverR(loadFile('conf/data','-canSkip')or{},STAT)
-TABLE.cover (loadFile('conf/key','-canSkip')or{},KEY_MAP)
-TABLE.cover (loadFile('conf/virtualkey','-json -canSkip')or{},VK_ORG)
-
---Initialize fields, sequence, missions, gameEnv for cutsom game
-local fieldData=loadFile('conf/customBoards','-string -canSkip')
-if fieldData then
- fieldData=STRING.split(fieldData,"!")
- for i=1,#fieldData do
- DATA.pasteBoard(fieldData[i],i)
- end
-else
- FIELD[1]=DATA.newBoard()
-end
-local sequenceData=loadFile('conf/customSequence','-string -canSkip')
-if sequenceData then
- DATA.pasteSequence(sequenceData)
-end
-local missionData=loadFile('conf/customMissions','-string -canSkip')
-if missionData then
- DATA.pasteMission(missionData)
-end
-local customData=loadFile('conf/customEnv','-canSkip')
-if customData and customData['version']==VERSION.code then
- TABLE.complete(customData,CUSTOMENV)
-end
-TABLE.complete(require"parts.customEnv0",CUSTOMENV)
-
+Z.setOnBeforeQuit(function()
+ NET.ws_close()
+ TASK.new(function()
+ TEST.yieldT(.26)
+ love.event.quit()
+ end)
+end)
+Z.setOnQuit(function()
+ destroyPlayers()
+end)
---Initialize image libs
+-- Initialize image libs
IMG.init{
lock='media/image/mess/lock.png',
dialCircle='media/image/mess/dialCircle.png',
@@ -274,7 +258,6 @@ IMG.init{
lifeIcon='media/image/mess/life.png',
badgeIcon='media/image/mess/badge.png',
ctrlSpeedLimit='media/image/mess/ctrlSpeedLimit.png',
- speedLimit='media/image/mess/speedLimit.png',--Not used, for future C2-mode
pay1='media/image/mess/pay1.png',
pay2='media/image/mess/pay2.png',
@@ -287,7 +270,18 @@ IMG.init{
monoCH='media/image/characters/mono.png',
xiaoyaCH='media/image/characters/xiaoya.png',
xiaoyaOmino='media/image/characters/xiaoya_Omino.png',
+ floreCH='media/image/characters/flore.png',
mikuCH='media/image/characters/miku.png',
+ zundamonCH='media/image/characters/zundamon.png',
+ z={
+ character='media/image/characters/z_character.png',
+ screen1='media/image/characters/z_screen1.png',
+ screen2='media/image/characters/z_screen2.png',
+ particle1='media/image/characters/z_particle1.png',
+ particle2='media/image/characters/z_particle2.png',
+ particle3='media/image/characters/z_particle3.png',
+ particle4='media/image/characters/z_particle4.png',
+ },
electric='media/image/characters/electric.png',
hbm='media/image/characters/hbm.png',
@@ -321,31 +315,35 @@ SKIN.load{
{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'},
}
---Initialize sound libs
+-- Initialize sound libs
SFX.init((function()--[Warning] Not loading files here, just get the list of sound needed
local L={}
- for _,v in next,fs.getDirectoryItems('media/effect/chiptune/')do
- if isSafeFile('media/effect/chiptune/'..v,"Dangerous file : %SAVE%/media/effect/chiptune/"..v)then
+ for _,v in next,fs.getDirectoryItems('media/effect/chiptune/') do
+ if FILE.isSafe('media/effect/chiptune/'..v) then
table.insert(L,v:sub(1,-5))
end
end
return L
end)())
-BGM.load((function()
+BGM.init((function()
local L={}
- for _,v in next,fs.getDirectoryItems('media/music')do
- if isSafeFile('media/music/'..v,"Dangerous file : %SAVE%/media/music/"..v)then
+ for _,v in next,fs.getDirectoryItems('media/music') do
+ if FILE.isSafe('media/music/'..v) then
L[v:sub(1,-5)]='media/music/'..v
end
end
@@ -353,7 +351,7 @@ BGM.load((function()
end)())
VOC.init{
'zspin','sspin','jspin','lspin','tspin','ospin','ispin','pspin','qspin','fspin','espin','uspin','vspin','wspin','xspin','rspin','yspin','nspin','hspin','cspin',
- 'single','double','triple','techrash','pentacrash','hexacrash',
+ 'single','double','triple','techrash','pentacrash','hexacrash','heptacrash','octacrash','nonacrash','decacrash','undecacrash','dodecacrash','tridecacrash','tetradecacrash','pentadecacrash','hexadecacrash','heptadecacrash','octadecacrash','nonadecacrash','ultracrash','impossicrash',
'mini','b2b','b3b',
'perfect_clear','half_clear',
'win','lose','bye',
@@ -361,235 +359,194 @@ VOC.init{
'welcome',
}
---Initialize language lib
-LANG.init('zh',
- {
- zh=require'parts.language.lang_zh',
- zh_trad=require'parts.language.lang_zh_trad',
- zh_full=require'parts.language.lang_zh_full',
- en=require'parts.language.lang_en',
- fr=require'parts.language.lang_fr',
- es=require'parts.language.lang_es',
- pt=require'parts.language.lang_pt',
- id=require'parts.language.lang_id',
- ja=require'parts.language.lang_ja',
- zh_grass=require'parts.language.lang_zh_grass',
- symbol=require'parts.language.lang_symbol',
- --1. Add language file to LANG folder;
- --2. Require it;
- --3. Add a button in parts/scenes/lang.lua;
- },
- {
- block=BLOCK_NAMES
- },
- (function()
- local tipMeta={__call=function(L)return L[math.random(#L)]end}
- return function(L)
- if type(rawget(L,'getTip'))=='table'then setmetatable(L.getTip,tipMeta)end
- setmetatable(L,{__index=function(self,k)
- local mes="No Text ("..SETTING.locale.."): "..k
- LOG(mes)
- MES.new('warn',mes)
- self[k]=CHAR.zChan.thinking
- return self[k]
- end})
- end
- end)()
-)
-
-table.insert(_LOADTIMELIST_,("Initialize Parts: %.3fs"):format(TIME()-_LOADTIME_))
+table.insert(_LOADTIMELIST_,("Initialize Modules: %.3fs"):format(TIME()-_LOADTIME_))
+
+-- Load settings and statistics
+if
+ not (
+ pcall(TABLE.cover, loadFile('conf/user', '-json -canSkip') or loadFile('conf/user', '-luaon -canSkip') or{},USER) and
+ pcall(TABLE.cover, loadFile('conf/unlock', '-json -canSkip') or loadFile('conf/unlock', '-luaon -canSkip') or{},RANKS) and
+ pcall(TABLE.update,loadFile('conf/settings', '-json -canSkip') or loadFile('conf/settings', '-luaon -canSkip') or{},SETTING) and
+ pcall(TABLE.coverR,loadFile('conf/data', '-json -canSkip') or loadFile('conf/data', '-luaon -canSkip') or{},STAT) and
+ pcall(TABLE.cover, loadFile('conf/key', '-json -canSkip') or loadFile('conf/key', '-luaon -canSkip') or{},KEY_MAP) and
+ pcall(TABLE.cover, loadFile('conf/virtualkey','-json -canSkip') or loadFile('conf/virtualkey','-luaon -canSkip') or{},VK_ORG)
+ )
+then
+ MES.new('error',"An error occured during loading, and some data was lost.")
+end
---Load background files from SOURCE ONLY
-for _,v in next,fs.getDirectoryItems('parts/backgrounds')do
- if isSafeFile('parts/backgrounds/'..v)and v:sub(-3)=='lua'then
- local name=v:sub(1,-5)
- BG.add(name,require('parts.backgrounds.'..name))
+-- Initialize fields, sequence, missions, gameEnv for cutsom game
+local fieldData=loadFile('conf/customBoards','-string -canSkip')
+if fieldData then
+ fieldData=STRING.split(fieldData,"!")
+ for i=1,#fieldData do
+ DATA.pasteBoard(fieldData[i],i)
end
+else
+ FIELD[1]=DATA.newBoard()
end
-BG.remList('none')BG.remList('gray')BG.remList('custom')
---Load scene files from SOURCE ONLY
-for _,v in next,fs.getDirectoryItems('parts/scenes')do
- if isSafeFile('parts/scenes/'..v)then
- local sceneName=v:sub(1,-5)
- SCN.add(sceneName,require('parts.scenes.'..sceneName))
- LANG.addScene(sceneName)
- end
+local sequenceData=loadFile('conf/customSequence','-string -canSkip')
+if sequenceData then
+ DATA.pasteSequence(sequenceData)
end
---Load mode files
-for i=1,#MODES do
- local m=MODES[i]--Mode template
- if isSafeFile('parts/modes/'..m.name)then
- TABLE.complete(require('parts.modes.'..m.name),MODES[i])
- MODES[m.name],MODES[i]=MODES[i]
- end
+local missionData=loadFile('conf/customMissions','-string -canSkip')
+if missionData then
+ DATA.pasteMission(missionData)
end
-for _,v in next,fs.getDirectoryItems('parts/modes')do
- if isSafeFile('parts/modes/'..v)and not MODES[v:sub(1,-5)]then
- local M={name=v:sub(1,-5)}
- local modeData=require('parts.modes.'..M.name)
- if modeData.env then
- TABLE.complete(modeData,M)
- MODES[M.name]=M
- end
- end
+local customData=loadFile('conf/customEnv','-canSkip')
+if customData and customData['version']==VERSION.code then
+ TABLE.complete(customData,CUSTOMENV)
end
+TABLE.complete(require"parts.customEnv0",CUSTOMENV)
-table.insert(_LOADTIMELIST_,("Load Files: %.3fs"):format(TIME()-_LOADTIME_))
-
---Update data
+-- Update data
do
- local needSave
-
- if not fs.getInfo('conf/data')then
- needSave=true
- end
- if type(STAT.version)~='number'then
+ if type(STAT.version)~='number' then
STAT.version=0
- needSave=true
- end
- if STAT.version<1500 then
- FILE.clear_s('')
- end
- if STAT.version<1505 then
- fs.remove('record/bigbang.rec')
- fs.remove('conf/replay')
- end
- if STAT.version==1506 then
- local temp1,temp2
- if fs.getInfo('record/master_l.rec')then
- temp1=fs.read('record/master_l.rec')
- end
- if fs.getInfo('record/master_u.rec')then
- temp2=fs.read('record/master_u.rec')
- end
- if temp1 then
- fs.write('record/master_u.rec',temp1)
- end
- if temp2 then
- fs.write('record/master_l.rec',temp2)
- end
- RANKS.master_l,RANKS.master_u=RANKS.master_u,RANKS.master_l
- if RANKS.tsd_u then
- RANKS.tsd_u=0
- end
- end
- if STAT.version==1601 then
- RANKS.round_e=nil
- RANKS.round_n=nil
- RANKS.round_h=nil
- RANKS.round_l=nil
- RANKS.round_u=nil
- fs.remove('record/round_e.rec')
- fs.remove('record/round_n.rec')
- fs.remove('record/round_h.rec')
- fs.remove('record/round_l.rec')
- fs.remove('record/round_u.rec')
end
if STAT.version<1700 and SETTING.dascut<5 then
SETTING.dascut=SETTING.dascut+1
- needSave=true
- end
- if SETTING.vocPack=='mono'then
- SETTING.vocPack='miya'
end
+
if RANKS.stack_e then
- RANKS.stack_e=nil
- RANKS.stack_h=nil
- RANKS.stack_u=nil
- fs.remove('record/stack_e.rec')
- fs.remove('record/stack_h.rec')
- fs.remove('record/stack_u.rec')
+ RANKS.stack_e=nil; fs.remove('record/stack_e.rec')
+ RANKS.stack_h=nil; fs.remove('record/stack_h.rec')
+ RANKS.stack_u=nil; fs.remove('record/stack_u.rec')
end
if RANKS.stack_20l then
- RANKS.stack_20l=nil
- RANKS.stack_40l=nil
- RANKS.stack_100l=nil
- fs.remove('record/stack_20l.rec')
- fs.remove('record/stack_40l.rec')
- fs.remove('record/stack_100l.rec')
+ RANKS.stack_20l=nil; fs.remove('record/stack_20l.rec')
+ RANKS.stack_40l=nil; fs.remove('record/stack_40l.rec')
+ RANKS.stack_100l=nil; fs.remove('record/stack_100l.rec')
end
if RANKS.rhythm_e then
- RANKS.rhythm_e=nil
- RANKS.rhythm_h=nil
- RANKS.rhythm_u=nil
- fs.remove('record/rhythm_e.rec')
- fs.remove('record/rhythm_h.rec')
- fs.remove('record/rhythm_u.rec')
- end
- if RANKS.bigbang then
- RANKS.clearRush,RANKS.bigbang=RANKS.bigbang
- fs.remove('record/bigbang.rec')
+ RANKS.rhythm_e=nil; fs.remove('record/rhythm_e.rec')
+ 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 STAT.version~=VERSION.code then
for k,v in next,MODE_UPDATE_MAP do
- if RANKS[k]then
+ if RANKS[k] then
RANKS[v]=RANKS[k]
RANKS[k]=nil
end
k='record/'..k
- if fs.getInfo(k..'.dat')then
+ if fs.getInfo(k..'.dat') then
fs.write('record/'..v..'.rec',fs.read(k..'.dat'))
fs.remove(k..'.dat')
end
- if fs.getInfo(k..'.rec')then
+ if fs.getInfo(k..'.rec') then
fs.write('record/'..v..'.rec',fs.read(k..'.rec'))
fs.remove(k..'.rec')
end
end
STAT.version=VERSION.code
- needSave=true
end
- SETTING.appLock,SETTING.dataSaving,SETTING.swap=nil
+ SETTING.appLock,SETTING.dataSaving,SETTING.swap,SETTING.autoLogin=nil
if not SETTING.VKSkin then SETTING.VKSkin=1 end
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 not TABLE.find({8,10,13,17,22,29,37,47,62,80,100},SETTING.frameMul)then SETTING.frameMul=100 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 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
+ if type(SETTING.bg)~='string' then SETTING.bg='on' end
if SETTING.skin[18]==10 then SETTING.skin[18]=4 end
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 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
- if RANKS.master_l then RANKS.master_n,RANKS.master_l=RANKS.master_l needSave=true end
- if RANKS.master_u then RANKS.master_h,RANKS.master_u=RANKS.master_u needSave=true end
+ if RANKS.master_l then RANKS.master_n,RANKS.master_l=RANKS.master_l end
+ if RANKS.master_u then RANKS.master_h,RANKS.master_u=RANKS.master_u end
for _,v in next,VK_ORG do v.color=nil end
for name,rank in next,RANKS do
- if type(name)=='number'or type(rank)~='number'then
+ if type(name)=='number' or type(rank)~='number' then
RANKS[name]=nil
- needSave=true
else
local M=MODES[name]
if M and M.unlock and rank>0 then
for _,unlockName in next,M.unlock do
- if not RANKS[unlockName]then
+ if not RANKS[unlockName] then
RANKS[unlockName]=0
- needSave=true
end
end
end
- if not(M and M.x)then
+ if not (M and M.x) then
RANKS[name]=nil
- needSave=true
end
end
end
- if not MODES[STAT.lastPlay]then
+ if not MODES[STAT.lastPlay] then
STAT.lastPlay='sprint_10l'
- needSave=true
end
+ fs.remove('conf/account')
- if needSave then
- saveStats()
- saveProgress()
- saveSettings()
- love.event.quit('restart')
+ saveStats()
+ saveProgress()
+ saveSettings()
+end
+
+-- Initialize language lib
+LANG.init('zh',
+ {
+ zh=require'parts.language.lang_zh',
+ zh_trad=require'parts.language.lang_zh_trad',
+ en=require'parts.language.lang_en',
+ fr=require'parts.language.lang_fr',
+ es=require'parts.language.lang_es',
+ pt=require'parts.language.lang_pt',
+ id=require'parts.language.lang_id',
+ ja=require'parts.language.lang_ja',
+ symbol=require'parts.language.lang_symbol',
+ zh_code=require'parts.language.lang_zh_code',
+ vi=require'parts.language.lang_vi',
+ -- 1. Add language file to LANG folder;
+ -- 2. Require it;
+ -- 3. Add a button in parts/scenes/lang.lua;
+ },
+ {
+ block=BLOCK_NAMES
+ },
+ (function()
+ local tipMeta={__call=function(L) return L[math.random(#L)] end}
+ return function(L)
+ if type(rawget(L,'getTip'))=='table' then setmetatable(L.getTip,tipMeta) end
+ setmetatable(L,{__index=function(self,k)
+ local mes="No Text ("..SETTING.locale.."): "..k
+ LOG(mes)
+ MES.new('warn',mes)
+ self[k]="["..k.."]"
+ return self[k]
+ end})
+ end
+ end)()
+)
+
+-- Load background files from SOURCE ONLY
+for _,v in next,fs.getDirectoryItems('parts/backgrounds') do
+ if FILE.isSafe('parts/backgrounds/'..v) and v:sub(-3)=='lua' then
+ local name=v:sub(1,-5)
+ BG.add(name,require('parts.backgrounds.'..name))
end
end
+BG.remList('none')BG.remList('gray')BG.remList('custom')
---First start
+-- Load scene files from SOURCE ONLY
+for _,v in next,fs.getDirectoryItems('parts/scenes') do
+ if FILE.isSafe('parts/scenes/'..v) then
+ local sceneName=v:sub(1,-5)
+ SCN.add(sceneName,require('parts.scenes.'..sceneName))
+ LANG.addScene(sceneName)
+ end
+end
+
+table.insert(_LOADTIMELIST_,("Load Files: %.3fs"):format(TIME()-_LOADTIME_))
+
+-- First start
FIRSTLAUNCH=STAT.run==0
if FIRSTLAUNCH and MOBILE then
SETTING.VKSwitch=true
@@ -597,21 +554,20 @@ if FIRSTLAUNCH and MOBILE then
SETTING.cleanCanvas=true
end
---Apply system setting
+-- Apply system setting
applySettings()
---Load replays
-for _,fileName in next,fs.getDirectoryItems('replay')do
- if fileName:sub(12,12):match("[a-zA-Z]")then
+-- Load replays
+for _,fileName in next,fs.getDirectoryItems('replay') do
+ if fileName:sub(12,12):match("[a-zA-Z]") then repeat
local date,mode,version,player,seed,setting,mod
- local fileData=fs.read('replay/'..fileName)
+ local success,fileData=true,fs.read('replay/'..fileName)
date, fileData=STRING.readLine(fileData)date=date:gsub("[a-zA-Z]","")
- mode, fileData=STRING.readLine(fileData)mode=MODE_UPDATE_MAP[mode]or mode
+ mode, fileData=STRING.readLine(fileData)mode=MODE_UPDATE_MAP[mode] or mode
version,fileData=STRING.readLine(fileData)
- player, fileData=STRING.readLine(fileData)if player=="Local Player"then player="Stacker"end
- local success
+ player, fileData=STRING.readLine(fileData) if player=="Local Player" then player="Stacker" end
success,fileData=pcall(love.data.decompress,'string','zlib',fileData)
- if not success then goto BREAK_cannotParse end
+ if not success then break end
seed, fileData=STRING.readLine(fileData)
setting,fileData=STRING.readLine(fileData)setting=JSON.decode(setting)
mod, fileData=STRING.readLine(fileData)mod=JSON.decode(mod)
@@ -620,7 +576,7 @@ for _,fileName in next,fs.getDirectoryItems('replay')do
not mod or
not mode or
#mode==0
- then goto BREAK_cannotParse end
+ then break end
fs.remove('replay/'..fileName)
local newName=fileName:sub(1,10)..fileName:sub(15)
@@ -639,21 +595,26 @@ for _,fileName in next,fs.getDirectoryItems('replay')do
)
)
fileName=newName
- end
- ::BREAK_cannotParse::
+ until true end
local rep=DATA.parseReplay('replay/'..fileName)
table.insert(REPLAY,rep)
end
-table.sort(REPLAY,function(a,b)return a.fileName>b.fileName end)
+table.sort(REPLAY,function(a,b) return a.fileName>b.fileName end)
-table.insert(_LOADTIMELIST_,("Initialize Data: %.3fs"):format(TIME()-_LOADTIME_))
+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")
+HTTP.setThreadCount(1)
-for i=1,#_LOADTIMELIST_ do LOG(_LOADTIMELIST_[i])end
+table.insert(_LOADTIMELIST_,("Load Resources: %.3fs"):format(TIME()-_LOADTIME_))
---Launch testing task if launch param received
-if TABLE.find(arg,'--test')then
+for i=1,#_LOADTIMELIST_ do LOG(_LOADTIMELIST_[i]) end
+
+-- Launch testing task if launch param received
+if TABLE.find(arg,'-- test') then
TASK.new(function()
- while not LOADED do YIELD()end
+ while not LOADED do coroutine.yield() end
LOG("\27[92m\27[1mAutomatic Test Started\27[0m")
BGM.setVol(0)SFX.setVol(0)
@@ -661,7 +622,7 @@ if TABLE.find(arg,'--test')then
TEST.yieldUntilNextScene()
for k,mode in next,MODES do
- if k~='netBattle'then
+ if k~='netBattle' then
LOG("Scanning mode: "..mode.name)
loadGame(mode.name,true)
TEST.yieldUntilNextScene()
@@ -675,8 +636,8 @@ if TABLE.find(arg,'--test')then
end)
TASK.new(function()
while true do
- YIELD()
- if Z.getErr(1)then break end
+ coroutine.yield()
+ if Z.getErr(1) then break end
end
LOG("\27[91m\27[1mAutomatic Test Failed :(\27[0m\nThe error message is:\n"..table.concat(Z.getErr(1).mes,"\n").."\27[91m\nAborting\27[0m")
TEST.yieldN(60)
diff --git a/media/effect/chiptune/achievement.ogg b/media/effect/chiptune/achievement.ogg
new file mode 100644
index 000000000..1c3b8beb0
Binary files /dev/null and b/media/effect/chiptune/achievement.ogg differ
diff --git a/media/effect/chiptune/back.ogg b/media/effect/chiptune/back.ogg
index 63894675f..916199278 100644
Binary files a/media/effect/chiptune/back.ogg and b/media/effect/chiptune/back.ogg differ
diff --git a/media/effect/chiptune/button.ogg b/media/effect/chiptune/button.ogg
index ee9d75f11..11139e2b9 100644
Binary files a/media/effect/chiptune/button.ogg and b/media/effect/chiptune/button.ogg differ
diff --git a/media/effect/chiptune/check.ogg b/media/effect/chiptune/check.ogg
index 8d51c0ec5..564dffcf9 100644
Binary files a/media/effect/chiptune/check.ogg and b/media/effect/chiptune/check.ogg differ
diff --git a/media/effect/chiptune/clear.ogg b/media/effect/chiptune/clear.ogg
deleted file mode 100644
index ce32bf7a6..000000000
Binary files a/media/effect/chiptune/clear.ogg and /dev/null differ
diff --git a/media/effect/chiptune/clear_1.ogg b/media/effect/chiptune/clear_1.ogg
index 174b36b90..027b30a8e 100644
Binary files a/media/effect/chiptune/clear_1.ogg and b/media/effect/chiptune/clear_1.ogg differ
diff --git a/media/effect/chiptune/clear_2.ogg b/media/effect/chiptune/clear_2.ogg
index f8f870968..4b445e044 100644
Binary files a/media/effect/chiptune/clear_2.ogg and b/media/effect/chiptune/clear_2.ogg differ
diff --git a/media/effect/chiptune/clear_3.ogg b/media/effect/chiptune/clear_3.ogg
index 91ee47faa..29446bca3 100644
Binary files a/media/effect/chiptune/clear_3.ogg and b/media/effect/chiptune/clear_3.ogg differ
diff --git a/media/effect/chiptune/clear_4.ogg b/media/effect/chiptune/clear_4.ogg
index 971e541c1..b9cb3d1b7 100644
Binary files a/media/effect/chiptune/clear_4.ogg and b/media/effect/chiptune/clear_4.ogg differ
diff --git a/media/effect/chiptune/clear_5.ogg b/media/effect/chiptune/clear_5.ogg
index b3e31f54d..64559c801 100644
Binary files a/media/effect/chiptune/clear_5.ogg and b/media/effect/chiptune/clear_5.ogg differ
diff --git a/media/effect/chiptune/clear_6.ogg b/media/effect/chiptune/clear_6.ogg
index 9d6a8fa09..1763238a2 100644
Binary files a/media/effect/chiptune/clear_6.ogg and b/media/effect/chiptune/clear_6.ogg differ
diff --git a/media/effect/chiptune/click.ogg b/media/effect/chiptune/click.ogg
index 38de65e68..37b26d2d6 100644
Binary files a/media/effect/chiptune/click.ogg and b/media/effect/chiptune/click.ogg differ
diff --git a/media/effect/chiptune/connect.ogg b/media/effect/chiptune/connect.ogg
index 3af92aea5..0cec7d69c 100644
Binary files a/media/effect/chiptune/connect.ogg and b/media/effect/chiptune/connect.ogg differ
diff --git a/media/effect/chiptune/connected.ogg b/media/effect/chiptune/connected.ogg
index 05daaf083..af5ac7345 100644
Binary files a/media/effect/chiptune/connected.ogg and b/media/effect/chiptune/connected.ogg differ
diff --git a/media/effect/chiptune/drop.ogg b/media/effect/chiptune/drop.ogg
index ad5fa3f5f..4a7da0bac 100644
Binary files a/media/effect/chiptune/drop.ogg and b/media/effect/chiptune/drop.ogg differ
diff --git a/media/effect/chiptune/drop_cancel.ogg b/media/effect/chiptune/drop_cancel.ogg
index 10d930948..f8b2de178 100644
Binary files a/media/effect/chiptune/drop_cancel.ogg and b/media/effect/chiptune/drop_cancel.ogg differ
diff --git a/media/effect/chiptune/emit.ogg b/media/effect/chiptune/emit.ogg
index 67f0788e9..82e42635f 100644
Binary files a/media/effect/chiptune/emit.ogg and b/media/effect/chiptune/emit.ogg differ
diff --git a/media/effect/chiptune/enter.ogg b/media/effect/chiptune/enter.ogg
index cb830c5a9..d410c713f 100644
Binary files a/media/effect/chiptune/enter.ogg and b/media/effect/chiptune/enter.ogg differ
diff --git a/media/effect/chiptune/error.ogg b/media/effect/chiptune/error.ogg
index f4fa1cdc6..f04ff295b 100644
Binary files a/media/effect/chiptune/error.ogg and b/media/effect/chiptune/error.ogg differ
diff --git a/media/effect/chiptune/fail.ogg b/media/effect/chiptune/fail.ogg
index f99b60160..7882c2094 100644
Binary files a/media/effect/chiptune/fail.ogg and b/media/effect/chiptune/fail.ogg differ
diff --git a/media/effect/chiptune/fall.ogg b/media/effect/chiptune/fall.ogg
index 290c88273..675257a41 100644
Binary files a/media/effect/chiptune/fall.ogg and b/media/effect/chiptune/fall.ogg differ
diff --git a/media/effect/chiptune/finesseError.ogg b/media/effect/chiptune/finesseError.ogg
index 302931564..4db7dea9c 100644
Binary files a/media/effect/chiptune/finesseError.ogg and b/media/effect/chiptune/finesseError.ogg differ
diff --git a/media/effect/chiptune/finesseError_long.ogg b/media/effect/chiptune/finesseError_long.ogg
index cb915c35a..d9c6c4d3d 100644
Binary files a/media/effect/chiptune/finesseError_long.ogg and b/media/effect/chiptune/finesseError_long.ogg differ
diff --git a/media/effect/chiptune/hold.ogg b/media/effect/chiptune/hold.ogg
index 831b2116c..0d526d185 100644
Binary files a/media/effect/chiptune/hold.ogg and b/media/effect/chiptune/hold.ogg differ
diff --git a/media/effect/chiptune/key.ogg b/media/effect/chiptune/key.ogg
index 58aa769a1..4f60e682d 100644
Binary files a/media/effect/chiptune/key.ogg and b/media/effect/chiptune/key.ogg differ
diff --git a/media/effect/chiptune/lock.ogg b/media/effect/chiptune/lock.ogg
index 9268e98eb..2e6f8e632 100644
Binary files a/media/effect/chiptune/lock.ogg and b/media/effect/chiptune/lock.ogg differ
diff --git a/media/effect/chiptune/prehold.ogg b/media/effect/chiptune/prehold.ogg
index 605d7ac03..73e5357c9 100644
Binary files a/media/effect/chiptune/prehold.ogg and b/media/effect/chiptune/prehold.ogg differ
diff --git a/media/effect/chiptune/prerotate.ogg b/media/effect/chiptune/prerotate.ogg
index 9dfe91bf7..53f5f25e4 100644
Binary files a/media/effect/chiptune/prerotate.ogg and b/media/effect/chiptune/prerotate.ogg differ
diff --git a/media/effect/chiptune/reach.ogg b/media/effect/chiptune/reach.ogg
index 9b57e9ad2..904d06dad 100644
Binary files a/media/effect/chiptune/reach.ogg and b/media/effect/chiptune/reach.ogg differ
diff --git a/media/effect/chiptune/ren_mega.ogg b/media/effect/chiptune/ren_mega.ogg
index 19691cef7..c7e91411c 100644
Binary files a/media/effect/chiptune/ren_mega.ogg and b/media/effect/chiptune/ren_mega.ogg differ
diff --git a/media/effect/chiptune/rotate.ogg b/media/effect/chiptune/rotate.ogg
index e9d4fa003..5460c038d 100644
Binary files a/media/effect/chiptune/rotate.ogg and b/media/effect/chiptune/rotate.ogg differ
diff --git a/media/effect/chiptune/rotatekick.ogg b/media/effect/chiptune/rotatekick.ogg
index acea4a683..842c7fb76 100644
Binary files a/media/effect/chiptune/rotatekick.ogg and b/media/effect/chiptune/rotatekick.ogg differ
diff --git a/media/effect/chiptune/selector.ogg b/media/effect/chiptune/selector.ogg
index f4e6a0d8c..fe75311a4 100644
Binary files a/media/effect/chiptune/selector.ogg and b/media/effect/chiptune/selector.ogg differ
diff --git a/media/effect/chiptune/spin_0.ogg b/media/effect/chiptune/spin_0.ogg
index 2530c75fc..09937b6e8 100644
Binary files a/media/effect/chiptune/spin_0.ogg and b/media/effect/chiptune/spin_0.ogg differ
diff --git a/media/effect/chiptune/spin_1.ogg b/media/effect/chiptune/spin_1.ogg
index 28388d5db..9b9b3b557 100644
Binary files a/media/effect/chiptune/spin_1.ogg and b/media/effect/chiptune/spin_1.ogg differ
diff --git a/media/effect/chiptune/spin_2.ogg b/media/effect/chiptune/spin_2.ogg
index 4e5e335b2..a8f019892 100644
Binary files a/media/effect/chiptune/spin_2.ogg and b/media/effect/chiptune/spin_2.ogg differ
diff --git a/media/effect/chiptune/spin_3.ogg b/media/effect/chiptune/spin_3.ogg
index 238924b4a..ecd9de42f 100644
Binary files a/media/effect/chiptune/spin_3.ogg and b/media/effect/chiptune/spin_3.ogg differ
diff --git a/media/effect/chiptune/swipe.ogg b/media/effect/chiptune/swipe.ogg
index b7f07127b..a297b340a 100644
Binary files a/media/effect/chiptune/swipe.ogg and b/media/effect/chiptune/swipe.ogg differ
diff --git a/media/effect/chiptune/touch.ogg b/media/effect/chiptune/touch.ogg
index d4841bc8c..67b46448f 100644
Binary files a/media/effect/chiptune/touch.ogg and b/media/effect/chiptune/touch.ogg differ
diff --git a/media/effect/chiptune/uncheck .ogg b/media/effect/chiptune/uncheck .ogg
index 740d0d88f..6665d8bb1 100644
Binary files a/media/effect/chiptune/uncheck .ogg and b/media/effect/chiptune/uncheck .ogg differ
diff --git a/media/effect/chiptune/uncheck.ogg b/media/effect/chiptune/uncheck.ogg
index 5a7a8dc04..c79af7867 100644
Binary files a/media/effect/chiptune/uncheck.ogg and b/media/effect/chiptune/uncheck.ogg differ
diff --git a/media/effect/chiptune/virtualKey.ogg b/media/effect/chiptune/virtualKey.ogg
index 1571ac50a..87d80bb53 100644
Binary files a/media/effect/chiptune/virtualKey.ogg and b/media/effect/chiptune/virtualKey.ogg differ
diff --git a/media/effect/chiptune/warn_1.ogg b/media/effect/chiptune/warn_1.ogg
index 9c8cdc640..a0bb0489c 100644
Binary files a/media/effect/chiptune/warn_1.ogg and b/media/effect/chiptune/warn_1.ogg differ
diff --git a/media/effect/chiptune/warn_2.ogg b/media/effect/chiptune/warn_2.ogg
index 8d0f21f3a..bb2f33dc5 100644
Binary files a/media/effect/chiptune/warn_2.ogg and b/media/effect/chiptune/warn_2.ogg differ
diff --git a/media/effect/chiptune/warn_beep.ogg b/media/effect/chiptune/warn_beep.ogg
index 8c6cc2858..8615f1047 100644
Binary files a/media/effect/chiptune/warn_beep.ogg and b/media/effect/chiptune/warn_beep.ogg differ
diff --git a/media/effect/chiptune/win.ogg b/media/effect/chiptune/win.ogg
index c3d56b468..66724db27 100644
Binary files a/media/effect/chiptune/win.ogg and b/media/effect/chiptune/win.ogg differ
diff --git a/media/image/characters/flore.png b/media/image/characters/flore.png
new file mode 100644
index 000000000..923c330f8
Binary files /dev/null and b/media/image/characters/flore.png differ
diff --git a/media/image/characters/miku.png b/media/image/characters/miku.png
index e1fa2c1f9..f1238afb9 100644
Binary files a/media/image/characters/miku.png and b/media/image/characters/miku.png differ
diff --git a/media/image/characters/mono.png b/media/image/characters/mono.png
index 72cd319dc..874cba48a 100644
Binary files a/media/image/characters/mono.png and b/media/image/characters/mono.png differ
diff --git a/media/image/characters/z_character.png b/media/image/characters/z_character.png
new file mode 100644
index 000000000..87320213f
Binary files /dev/null and b/media/image/characters/z_character.png differ
diff --git a/media/image/characters/z_particle1.png b/media/image/characters/z_particle1.png
new file mode 100644
index 000000000..58148fe7f
Binary files /dev/null and b/media/image/characters/z_particle1.png differ
diff --git a/media/image/characters/z_particle2.png b/media/image/characters/z_particle2.png
new file mode 100644
index 000000000..280b31be3
Binary files /dev/null and b/media/image/characters/z_particle2.png differ
diff --git a/media/image/characters/z_particle3.png b/media/image/characters/z_particle3.png
new file mode 100644
index 000000000..25de7e0e8
Binary files /dev/null and b/media/image/characters/z_particle3.png differ
diff --git a/media/image/characters/z_particle4.png b/media/image/characters/z_particle4.png
new file mode 100644
index 000000000..a1c07638b
Binary files /dev/null and b/media/image/characters/z_particle4.png differ
diff --git a/media/image/characters/z_screen1.png b/media/image/characters/z_screen1.png
new file mode 100644
index 000000000..4d5227ced
Binary files /dev/null and b/media/image/characters/z_screen1.png differ
diff --git a/media/image/characters/z_screen2.png b/media/image/characters/z_screen2.png
new file mode 100644
index 000000000..d6b77e5bb
Binary files /dev/null and b/media/image/characters/z_screen2.png differ
diff --git a/media/image/characters/zundamon.png b/media/image/characters/zundamon.png
new file mode 100644
index 000000000..1f4a06965
Binary files /dev/null and b/media/image/characters/zundamon.png differ
diff --git a/media/image/mess/speedLimit.png b/media/image/mess/speedLimit.png
deleted file mode 100644
index ceb602b54..000000000
Binary files a/media/image/mess/speedLimit.png and /dev/null differ
diff --git a/media/image/modeicon/big.png b/media/image/modeicon/big.png
new file mode 100644
index 000000000..3a6a234d0
Binary files /dev/null and b/media/image/modeicon/big.png differ
diff --git a/media/image/modeicon/dig_eff.png b/media/image/modeicon/dig_eff.png
new file mode 100644
index 000000000..00d72223a
Binary files /dev/null and b/media/image/modeicon/dig_eff.png differ
diff --git a/media/image/modeicon/secret_grade.png b/media/image/modeicon/secret_grade.png
new file mode 100644
index 000000000..bb3d7ec21
Binary files /dev/null and b/media/image/modeicon/secret_grade.png differ
diff --git a/media/image/modeicon/sprint_pento.png b/media/image/modeicon/sprint_pento.png
new file mode 100644
index 000000000..aea62da5a
Binary files /dev/null and b/media/image/modeicon/sprint_pento.png differ
diff --git a/media/image/modeicon/sprint_tri.png b/media/image/modeicon/sprint_tri.png
new file mode 100644
index 000000000..6203e946f
Binary files /dev/null and b/media/image/modeicon/sprint_tri.png differ
diff --git a/media/image/skin/guidetris_xmiao_lusisi.png b/media/image/skin/guidetris_xmiao_lusisi.png
new file mode 100644
index 000000000..72daacc45
Binary files /dev/null and b/media/image/skin/guidetris_xmiao_lusisi.png differ
diff --git a/media/image/skin/kanji_chno.png b/media/image/skin/kanji_chno.png
new file mode 100644
index 000000000..63d5c88db
Binary files /dev/null and b/media/image/skin/kanji_chno.png differ
diff --git a/media/image/skin/letters_chno.png b/media/image/skin/letters_chno.png
new file mode 100644
index 000000000..61847b649
Binary files /dev/null and b/media/image/skin/letters_chno.png differ
diff --git a/media/image/skin/minoes_scf.png b/media/image/skin/minoes_scf.png
index 769ce164a..5fe5a3b60 100644
Binary files a/media/image/skin/minoes_scf.png and b/media/image/skin/minoes_scf.png differ
diff --git a/media/image/skin/pastel_chno.png b/media/image/skin/pastel_chno.png
new file mode 100644
index 000000000..9b7cca1c3
Binary files /dev/null and b/media/image/skin/pastel_chno.png differ
diff --git a/media/image/virtualkey.png b/media/image/virtualkey.png
index eb6a6f69c..71e1cc6b6 100644
Binary files a/media/image/virtualkey.png and b/media/image/virtualkey.png differ
diff --git a/media/music/antispace.ogg b/media/music/antispace.ogg
new file mode 100644
index 000000000..f2b8d2384
Binary files /dev/null and b/media/music/antispace.ogg differ
diff --git a/media/music/empty.ogg b/media/music/empty.ogg
index 249cc8088..8b1cdc6ac 100644
Binary files a/media/music/empty.ogg and b/media/music/empty.ogg differ
diff --git a/media/music/way.ogg b/media/music/way.ogg
index d501b7cbc..b70240264 100644
Binary files a/media/music/way.ogg and b/media/music/way.ogg differ
diff --git a/media/vocal/flore/b2b_1.ogg b/media/vocal/flore/b2b_1.ogg
new file mode 100644
index 000000000..397710011
Binary files /dev/null and b/media/vocal/flore/b2b_1.ogg differ
diff --git a/media/vocal/flore/b2b_2.ogg b/media/vocal/flore/b2b_2.ogg
new file mode 100644
index 000000000..37e79559e
Binary files /dev/null and b/media/vocal/flore/b2b_2.ogg differ
diff --git a/media/vocal/flore/b2b_3.ogg b/media/vocal/flore/b2b_3.ogg
new file mode 100644
index 000000000..b8682b78f
Binary files /dev/null and b/media/vocal/flore/b2b_3.ogg differ
diff --git a/media/vocal/flore/b3b_1.ogg b/media/vocal/flore/b3b_1.ogg
new file mode 100644
index 000000000..cb2d7758c
Binary files /dev/null and b/media/vocal/flore/b3b_1.ogg differ
diff --git a/media/vocal/flore/b3b_2.ogg b/media/vocal/flore/b3b_2.ogg
new file mode 100644
index 000000000..24ef6a62b
Binary files /dev/null and b/media/vocal/flore/b3b_2.ogg differ
diff --git a/media/vocal/flore/b3b_3.ogg b/media/vocal/flore/b3b_3.ogg
new file mode 100644
index 000000000..24d80be76
Binary files /dev/null and b/media/vocal/flore/b3b_3.ogg differ
diff --git a/media/vocal/flore/bye_1.ogg b/media/vocal/flore/bye_1.ogg
new file mode 100644
index 000000000..17234bffd
Binary files /dev/null and b/media/vocal/flore/bye_1.ogg differ
diff --git a/media/vocal/flore/bye_2.ogg b/media/vocal/flore/bye_2.ogg
new file mode 100644
index 000000000..44608266a
Binary files /dev/null and b/media/vocal/flore/bye_2.ogg differ
diff --git a/media/vocal/flore/bye_3.ogg b/media/vocal/flore/bye_3.ogg
new file mode 100644
index 000000000..c55ad2ff2
Binary files /dev/null and b/media/vocal/flore/bye_3.ogg differ
diff --git a/media/vocal/flore/bye_4.ogg b/media/vocal/flore/bye_4.ogg
new file mode 100644
index 000000000..8bd4d2e3f
Binary files /dev/null and b/media/vocal/flore/bye_4.ogg differ
diff --git a/media/vocal/flore/bye_5.ogg b/media/vocal/flore/bye_5.ogg
new file mode 100644
index 000000000..f7dde5656
Binary files /dev/null and b/media/vocal/flore/bye_5.ogg differ
diff --git a/media/vocal/flore/bye_6.ogg b/media/vocal/flore/bye_6.ogg
new file mode 100644
index 000000000..96ce043fc
Binary files /dev/null and b/media/vocal/flore/bye_6.ogg differ
diff --git a/media/vocal/flore/cspin.ogg b/media/vocal/flore/cspin.ogg
new file mode 100644
index 000000000..a0618211f
Binary files /dev/null and b/media/vocal/flore/cspin.ogg differ
diff --git a/media/vocal/flore/decacrash_1.ogg b/media/vocal/flore/decacrash_1.ogg
new file mode 100644
index 000000000..a57b83324
Binary files /dev/null and b/media/vocal/flore/decacrash_1.ogg differ
diff --git a/media/vocal/flore/decacrash_2.ogg b/media/vocal/flore/decacrash_2.ogg
new file mode 100644
index 000000000..abb739252
Binary files /dev/null and b/media/vocal/flore/decacrash_2.ogg differ
diff --git a/media/vocal/flore/dodecacrash_1.ogg b/media/vocal/flore/dodecacrash_1.ogg
new file mode 100644
index 000000000..ba192c29e
Binary files /dev/null and b/media/vocal/flore/dodecacrash_1.ogg differ
diff --git a/media/vocal/flore/double_1.ogg b/media/vocal/flore/double_1.ogg
new file mode 100644
index 000000000..f7c33ffc8
Binary files /dev/null and b/media/vocal/flore/double_1.ogg differ
diff --git a/media/vocal/flore/double_2.ogg b/media/vocal/flore/double_2.ogg
new file mode 100644
index 000000000..9817a2beb
Binary files /dev/null and b/media/vocal/flore/double_2.ogg differ
diff --git a/media/vocal/flore/double_3.ogg b/media/vocal/flore/double_3.ogg
new file mode 100644
index 000000000..dbe251eb9
Binary files /dev/null and b/media/vocal/flore/double_3.ogg differ
diff --git a/media/vocal/flore/doubt_1.ogg b/media/vocal/flore/doubt_1.ogg
new file mode 100644
index 000000000..9453f8601
Binary files /dev/null and b/media/vocal/flore/doubt_1.ogg differ
diff --git a/media/vocal/flore/doubt_2.ogg b/media/vocal/flore/doubt_2.ogg
new file mode 100644
index 000000000..c615a5212
Binary files /dev/null and b/media/vocal/flore/doubt_2.ogg differ
diff --git a/media/vocal/flore/doubt_3.ogg b/media/vocal/flore/doubt_3.ogg
new file mode 100644
index 000000000..bb67115b3
Binary files /dev/null and b/media/vocal/flore/doubt_3.ogg differ
diff --git a/media/vocal/flore/espin.ogg b/media/vocal/flore/espin.ogg
new file mode 100644
index 000000000..34ea1fe6b
Binary files /dev/null and b/media/vocal/flore/espin.ogg differ
diff --git a/media/vocal/flore/fspin.ogg b/media/vocal/flore/fspin.ogg
new file mode 100644
index 000000000..e4647701e
Binary files /dev/null and b/media/vocal/flore/fspin.ogg differ
diff --git a/media/vocal/flore/half_clear_1.ogg b/media/vocal/flore/half_clear_1.ogg
new file mode 100644
index 000000000..7ba62f7bb
Binary files /dev/null and b/media/vocal/flore/half_clear_1.ogg differ
diff --git a/media/vocal/flore/half_clear_2.ogg b/media/vocal/flore/half_clear_2.ogg
new file mode 100644
index 000000000..00dbd0c5a
Binary files /dev/null and b/media/vocal/flore/half_clear_2.ogg differ
diff --git a/media/vocal/flore/happy_1.ogg b/media/vocal/flore/happy_1.ogg
new file mode 100644
index 000000000..925aa3f24
Binary files /dev/null and b/media/vocal/flore/happy_1.ogg differ
diff --git a/media/vocal/flore/happy_2.ogg b/media/vocal/flore/happy_2.ogg
new file mode 100644
index 000000000..aa283dacb
Binary files /dev/null and b/media/vocal/flore/happy_2.ogg differ
diff --git a/media/vocal/flore/happy_3.ogg b/media/vocal/flore/happy_3.ogg
new file mode 100644
index 000000000..bf653259f
Binary files /dev/null and b/media/vocal/flore/happy_3.ogg differ
diff --git a/media/vocal/flore/heptacrash_1.ogg b/media/vocal/flore/heptacrash_1.ogg
new file mode 100644
index 000000000..8895a1da2
Binary files /dev/null and b/media/vocal/flore/heptacrash_1.ogg differ
diff --git a/media/vocal/flore/heptacrash_2.ogg b/media/vocal/flore/heptacrash_2.ogg
new file mode 100644
index 000000000..e8dea3b0e
Binary files /dev/null and b/media/vocal/flore/heptacrash_2.ogg differ
diff --git a/media/vocal/flore/heptadecacrash_1.ogg b/media/vocal/flore/heptadecacrash_1.ogg
new file mode 100644
index 000000000..4e350a2ac
Binary files /dev/null and b/media/vocal/flore/heptadecacrash_1.ogg differ
diff --git a/media/vocal/flore/hexacrash_1.ogg b/media/vocal/flore/hexacrash_1.ogg
new file mode 100644
index 000000000..184074fcc
Binary files /dev/null and b/media/vocal/flore/hexacrash_1.ogg differ
diff --git a/media/vocal/flore/hexacrash_2.ogg b/media/vocal/flore/hexacrash_2.ogg
new file mode 100644
index 000000000..761057bfd
Binary files /dev/null and b/media/vocal/flore/hexacrash_2.ogg differ
diff --git a/media/vocal/flore/hexacrash_3.ogg b/media/vocal/flore/hexacrash_3.ogg
new file mode 100644
index 000000000..a5dfbb61d
Binary files /dev/null and b/media/vocal/flore/hexacrash_3.ogg differ
diff --git a/media/vocal/flore/hexadecacrash_1.ogg b/media/vocal/flore/hexadecacrash_1.ogg
new file mode 100644
index 000000000..34e1be53c
Binary files /dev/null and b/media/vocal/flore/hexadecacrash_1.ogg differ
diff --git a/media/vocal/flore/hspin.ogg b/media/vocal/flore/hspin.ogg
new file mode 100644
index 000000000..49d212da7
Binary files /dev/null and b/media/vocal/flore/hspin.ogg differ
diff --git a/media/vocal/flore/impossicrash_1.ogg b/media/vocal/flore/impossicrash_1.ogg
new file mode 100644
index 000000000..ae159a37a
Binary files /dev/null and b/media/vocal/flore/impossicrash_1.ogg differ
diff --git a/media/vocal/flore/ispin_1.ogg b/media/vocal/flore/ispin_1.ogg
new file mode 100644
index 000000000..003f7f532
Binary files /dev/null and b/media/vocal/flore/ispin_1.ogg differ
diff --git a/media/vocal/flore/ispin_2.ogg b/media/vocal/flore/ispin_2.ogg
new file mode 100644
index 000000000..fd0ca1b8c
Binary files /dev/null and b/media/vocal/flore/ispin_2.ogg differ
diff --git a/media/vocal/flore/jspin_1.ogg b/media/vocal/flore/jspin_1.ogg
new file mode 100644
index 000000000..1b37611ec
Binary files /dev/null and b/media/vocal/flore/jspin_1.ogg differ
diff --git a/media/vocal/flore/jspin_2.ogg b/media/vocal/flore/jspin_2.ogg
new file mode 100644
index 000000000..197c61c1e
Binary files /dev/null and b/media/vocal/flore/jspin_2.ogg differ
diff --git a/media/vocal/flore/lose_1.ogg b/media/vocal/flore/lose_1.ogg
new file mode 100644
index 000000000..0032572d6
Binary files /dev/null and b/media/vocal/flore/lose_1.ogg differ
diff --git a/media/vocal/flore/lose_2.ogg b/media/vocal/flore/lose_2.ogg
new file mode 100644
index 000000000..80d86e2bf
Binary files /dev/null and b/media/vocal/flore/lose_2.ogg differ
diff --git a/media/vocal/flore/lose_3.ogg b/media/vocal/flore/lose_3.ogg
new file mode 100644
index 000000000..1fa9164ef
Binary files /dev/null and b/media/vocal/flore/lose_3.ogg differ
diff --git a/media/vocal/flore/lose_4.ogg b/media/vocal/flore/lose_4.ogg
new file mode 100644
index 000000000..06b8f33af
Binary files /dev/null and b/media/vocal/flore/lose_4.ogg differ
diff --git a/media/vocal/flore/lose_5.ogg b/media/vocal/flore/lose_5.ogg
new file mode 100644
index 000000000..427ed6b65
Binary files /dev/null and b/media/vocal/flore/lose_5.ogg differ
diff --git a/media/vocal/flore/lose_6.ogg b/media/vocal/flore/lose_6.ogg
new file mode 100644
index 000000000..cb1340013
Binary files /dev/null and b/media/vocal/flore/lose_6.ogg differ
diff --git a/media/vocal/flore/lspin_1.ogg b/media/vocal/flore/lspin_1.ogg
new file mode 100644
index 000000000..fdb09d7d3
Binary files /dev/null and b/media/vocal/flore/lspin_1.ogg differ
diff --git a/media/vocal/flore/lspin_2.ogg b/media/vocal/flore/lspin_2.ogg
new file mode 100644
index 000000000..e949a8f63
Binary files /dev/null and b/media/vocal/flore/lspin_2.ogg differ
diff --git a/media/vocal/flore/mini_1.ogg b/media/vocal/flore/mini_1.ogg
new file mode 100644
index 000000000..00c0fae27
Binary files /dev/null and b/media/vocal/flore/mini_1.ogg differ
diff --git a/media/vocal/flore/mini_2.ogg b/media/vocal/flore/mini_2.ogg
new file mode 100644
index 000000000..e416a5661
Binary files /dev/null and b/media/vocal/flore/mini_2.ogg differ
diff --git a/media/vocal/flore/mini_3.ogg b/media/vocal/flore/mini_3.ogg
new file mode 100644
index 000000000..36d827d7f
Binary files /dev/null and b/media/vocal/flore/mini_3.ogg differ
diff --git a/media/vocal/flore/nonacrash_1.ogg b/media/vocal/flore/nonacrash_1.ogg
new file mode 100644
index 000000000..2f9e8a52a
Binary files /dev/null and b/media/vocal/flore/nonacrash_1.ogg differ
diff --git a/media/vocal/flore/nonacrash_2.ogg b/media/vocal/flore/nonacrash_2.ogg
new file mode 100644
index 000000000..6f2c159d3
Binary files /dev/null and b/media/vocal/flore/nonacrash_2.ogg differ
diff --git a/media/vocal/flore/nonadecacrash_1.ogg b/media/vocal/flore/nonadecacrash_1.ogg
new file mode 100644
index 000000000..5e2f5cc96
Binary files /dev/null and b/media/vocal/flore/nonadecacrash_1.ogg differ
diff --git a/media/vocal/flore/nspin.ogg b/media/vocal/flore/nspin.ogg
new file mode 100644
index 000000000..11b7f6fa5
Binary files /dev/null and b/media/vocal/flore/nspin.ogg differ
diff --git a/media/vocal/flore/octacrash_1.ogg b/media/vocal/flore/octacrash_1.ogg
new file mode 100644
index 000000000..a41ae17cc
Binary files /dev/null and b/media/vocal/flore/octacrash_1.ogg differ
diff --git a/media/vocal/flore/octacrash_2.ogg b/media/vocal/flore/octacrash_2.ogg
new file mode 100644
index 000000000..97d357c06
Binary files /dev/null and b/media/vocal/flore/octacrash_2.ogg differ
diff --git a/media/vocal/flore/octadecacrash_1.ogg b/media/vocal/flore/octadecacrash_1.ogg
new file mode 100644
index 000000000..da9273b5b
Binary files /dev/null and b/media/vocal/flore/octadecacrash_1.ogg differ
diff --git a/media/vocal/flore/ospin.ogg b/media/vocal/flore/ospin.ogg
new file mode 100644
index 000000000..437a1a892
Binary files /dev/null and b/media/vocal/flore/ospin.ogg differ
diff --git a/media/vocal/flore/ospin_1.ogg b/media/vocal/flore/ospin_1.ogg
new file mode 100644
index 000000000..042de6a22
Binary files /dev/null and b/media/vocal/flore/ospin_1.ogg differ
diff --git a/media/vocal/flore/pentacrash_1.ogg b/media/vocal/flore/pentacrash_1.ogg
new file mode 100644
index 000000000..45b96ce78
Binary files /dev/null and b/media/vocal/flore/pentacrash_1.ogg differ
diff --git a/media/vocal/flore/pentacrash_2.ogg b/media/vocal/flore/pentacrash_2.ogg
new file mode 100644
index 000000000..71c94804a
Binary files /dev/null and b/media/vocal/flore/pentacrash_2.ogg differ
diff --git a/media/vocal/flore/pentacrash_3.ogg b/media/vocal/flore/pentacrash_3.ogg
new file mode 100644
index 000000000..c16f7918c
Binary files /dev/null and b/media/vocal/flore/pentacrash_3.ogg differ
diff --git a/media/vocal/flore/pentadecacrash_1.ogg b/media/vocal/flore/pentadecacrash_1.ogg
new file mode 100644
index 000000000..187af33f4
Binary files /dev/null and b/media/vocal/flore/pentadecacrash_1.ogg differ
diff --git a/media/vocal/flore/perfect_clear_1.ogg b/media/vocal/flore/perfect_clear_1.ogg
new file mode 100644
index 000000000..769c66af1
Binary files /dev/null and b/media/vocal/flore/perfect_clear_1.ogg differ
diff --git a/media/vocal/flore/perfect_clear_2.ogg b/media/vocal/flore/perfect_clear_2.ogg
new file mode 100644
index 000000000..5aafb828b
Binary files /dev/null and b/media/vocal/flore/perfect_clear_2.ogg differ
diff --git a/media/vocal/flore/pspin.ogg b/media/vocal/flore/pspin.ogg
new file mode 100644
index 000000000..0995e5075
Binary files /dev/null and b/media/vocal/flore/pspin.ogg differ
diff --git a/media/vocal/flore/qspin.ogg b/media/vocal/flore/qspin.ogg
new file mode 100644
index 000000000..1a2b466b1
Binary files /dev/null and b/media/vocal/flore/qspin.ogg differ
diff --git a/media/vocal/flore/rspin.ogg b/media/vocal/flore/rspin.ogg
new file mode 100644
index 000000000..0d4c65c2e
Binary files /dev/null and b/media/vocal/flore/rspin.ogg differ
diff --git a/media/vocal/flore/single_1.ogg b/media/vocal/flore/single_1.ogg
new file mode 100644
index 000000000..392b5a89f
Binary files /dev/null and b/media/vocal/flore/single_1.ogg differ
diff --git a/media/vocal/flore/single_2.ogg b/media/vocal/flore/single_2.ogg
new file mode 100644
index 000000000..eb8554f0a
Binary files /dev/null and b/media/vocal/flore/single_2.ogg differ
diff --git a/media/vocal/flore/single_3.ogg b/media/vocal/flore/single_3.ogg
new file mode 100644
index 000000000..048f871fa
Binary files /dev/null and b/media/vocal/flore/single_3.ogg differ
diff --git a/media/vocal/flore/sspin_1.ogg b/media/vocal/flore/sspin_1.ogg
new file mode 100644
index 000000000..670e30474
Binary files /dev/null and b/media/vocal/flore/sspin_1.ogg differ
diff --git a/media/vocal/flore/sspin_2.ogg b/media/vocal/flore/sspin_2.ogg
new file mode 100644
index 000000000..61125ae6a
Binary files /dev/null and b/media/vocal/flore/sspin_2.ogg differ
diff --git a/media/vocal/flore/techrash_1.ogg b/media/vocal/flore/techrash_1.ogg
new file mode 100644
index 000000000..2cfe9e43f
Binary files /dev/null and b/media/vocal/flore/techrash_1.ogg differ
diff --git a/media/vocal/flore/techrash_2.ogg b/media/vocal/flore/techrash_2.ogg
new file mode 100644
index 000000000..c760b6d19
Binary files /dev/null and b/media/vocal/flore/techrash_2.ogg differ
diff --git a/media/vocal/flore/techrash_3.ogg b/media/vocal/flore/techrash_3.ogg
new file mode 100644
index 000000000..6c74f9381
Binary files /dev/null and b/media/vocal/flore/techrash_3.ogg differ
diff --git a/media/vocal/flore/test_1.ogg b/media/vocal/flore/test_1.ogg
new file mode 100644
index 000000000..37fb7073a
Binary files /dev/null and b/media/vocal/flore/test_1.ogg differ
diff --git a/media/vocal/flore/test_2.ogg b/media/vocal/flore/test_2.ogg
new file mode 100644
index 000000000..9d608c756
Binary files /dev/null and b/media/vocal/flore/test_2.ogg differ
diff --git a/media/vocal/flore/test_3.ogg b/media/vocal/flore/test_3.ogg
new file mode 100644
index 000000000..966a4b8bb
Binary files /dev/null and b/media/vocal/flore/test_3.ogg differ
diff --git a/media/vocal/flore/test_4.ogg b/media/vocal/flore/test_4.ogg
new file mode 100644
index 000000000..31d4f4206
Binary files /dev/null and b/media/vocal/flore/test_4.ogg differ
diff --git a/media/vocal/flore/tetradecacrash_1.ogg b/media/vocal/flore/tetradecacrash_1.ogg
new file mode 100644
index 000000000..23a0cf123
Binary files /dev/null and b/media/vocal/flore/tetradecacrash_1.ogg differ
diff --git a/media/vocal/flore/tridecacrash_1.ogg b/media/vocal/flore/tridecacrash_1.ogg
new file mode 100644
index 000000000..8dd702d5f
Binary files /dev/null and b/media/vocal/flore/tridecacrash_1.ogg differ
diff --git a/media/vocal/flore/triple_1.ogg b/media/vocal/flore/triple_1.ogg
new file mode 100644
index 000000000..d8c99d6fc
Binary files /dev/null and b/media/vocal/flore/triple_1.ogg differ
diff --git a/media/vocal/flore/triple_2.ogg b/media/vocal/flore/triple_2.ogg
new file mode 100644
index 000000000..45b349e1c
Binary files /dev/null and b/media/vocal/flore/triple_2.ogg differ
diff --git a/media/vocal/flore/triple_3.ogg b/media/vocal/flore/triple_3.ogg
new file mode 100644
index 000000000..42756d34f
Binary files /dev/null and b/media/vocal/flore/triple_3.ogg differ
diff --git a/media/vocal/flore/tspin_1.ogg b/media/vocal/flore/tspin_1.ogg
new file mode 100644
index 000000000..95f65ce47
Binary files /dev/null and b/media/vocal/flore/tspin_1.ogg differ
diff --git a/media/vocal/flore/tspin_2.ogg b/media/vocal/flore/tspin_2.ogg
new file mode 100644
index 000000000..d2a9919e3
Binary files /dev/null and b/media/vocal/flore/tspin_2.ogg differ
diff --git a/media/vocal/flore/ultracrash_1.ogg b/media/vocal/flore/ultracrash_1.ogg
new file mode 100644
index 000000000..172163432
Binary files /dev/null and b/media/vocal/flore/ultracrash_1.ogg differ
diff --git a/media/vocal/flore/undecacrash_1.ogg b/media/vocal/flore/undecacrash_1.ogg
new file mode 100644
index 000000000..9d7aab013
Binary files /dev/null and b/media/vocal/flore/undecacrash_1.ogg differ
diff --git a/media/vocal/flore/uspin.ogg b/media/vocal/flore/uspin.ogg
new file mode 100644
index 000000000..cea69dd96
Binary files /dev/null and b/media/vocal/flore/uspin.ogg differ
diff --git a/media/vocal/flore/vspin.ogg b/media/vocal/flore/vspin.ogg
new file mode 100644
index 000000000..f20235df1
Binary files /dev/null and b/media/vocal/flore/vspin.ogg differ
diff --git a/media/vocal/flore/welcome_1.ogg b/media/vocal/flore/welcome_1.ogg
new file mode 100644
index 000000000..28dd481a5
Binary files /dev/null and b/media/vocal/flore/welcome_1.ogg differ
diff --git a/media/vocal/flore/welcome_2.ogg b/media/vocal/flore/welcome_2.ogg
new file mode 100644
index 000000000..a1eec9b6e
Binary files /dev/null and b/media/vocal/flore/welcome_2.ogg differ
diff --git a/media/vocal/flore/welcome_3.ogg b/media/vocal/flore/welcome_3.ogg
new file mode 100644
index 000000000..9093d4787
Binary files /dev/null and b/media/vocal/flore/welcome_3.ogg differ
diff --git a/media/vocal/flore/welcome_4.ogg b/media/vocal/flore/welcome_4.ogg
new file mode 100644
index 000000000..4da82cd5b
Binary files /dev/null and b/media/vocal/flore/welcome_4.ogg differ
diff --git a/media/vocal/flore/welcome_5.ogg b/media/vocal/flore/welcome_5.ogg
new file mode 100644
index 000000000..795c3b034
Binary files /dev/null and b/media/vocal/flore/welcome_5.ogg differ
diff --git a/media/vocal/flore/welcome_6.ogg b/media/vocal/flore/welcome_6.ogg
new file mode 100644
index 000000000..90921af24
Binary files /dev/null and b/media/vocal/flore/welcome_6.ogg differ
diff --git a/media/vocal/flore/win_1.ogg b/media/vocal/flore/win_1.ogg
new file mode 100644
index 000000000..574f33a3f
Binary files /dev/null and b/media/vocal/flore/win_1.ogg differ
diff --git a/media/vocal/flore/win_2.ogg b/media/vocal/flore/win_2.ogg
new file mode 100644
index 000000000..aa2c8a0fd
Binary files /dev/null and b/media/vocal/flore/win_2.ogg differ
diff --git a/media/vocal/flore/win_3.ogg b/media/vocal/flore/win_3.ogg
new file mode 100644
index 000000000..336e321a3
Binary files /dev/null and b/media/vocal/flore/win_3.ogg differ
diff --git a/media/vocal/flore/win_4.ogg b/media/vocal/flore/win_4.ogg
new file mode 100644
index 000000000..5c4db48b1
Binary files /dev/null and b/media/vocal/flore/win_4.ogg differ
diff --git a/media/vocal/flore/win_5.ogg b/media/vocal/flore/win_5.ogg
new file mode 100644
index 000000000..c5be6be1a
Binary files /dev/null and b/media/vocal/flore/win_5.ogg differ
diff --git a/media/vocal/flore/win_6.ogg b/media/vocal/flore/win_6.ogg
new file mode 100644
index 000000000..d58806c45
Binary files /dev/null and b/media/vocal/flore/win_6.ogg differ
diff --git a/media/vocal/flore/wspin.ogg b/media/vocal/flore/wspin.ogg
new file mode 100644
index 000000000..ccf3a7505
Binary files /dev/null and b/media/vocal/flore/wspin.ogg differ
diff --git a/media/vocal/flore/xspin.ogg b/media/vocal/flore/xspin.ogg
new file mode 100644
index 000000000..c3ef14e8e
Binary files /dev/null and b/media/vocal/flore/xspin.ogg differ
diff --git a/media/vocal/flore/yspin.ogg b/media/vocal/flore/yspin.ogg
new file mode 100644
index 000000000..11e0c91f6
Binary files /dev/null and b/media/vocal/flore/yspin.ogg differ
diff --git a/media/vocal/flore/zspin_1.ogg b/media/vocal/flore/zspin_1.ogg
new file mode 100644
index 000000000..8c75a5414
Binary files /dev/null and b/media/vocal/flore/zspin_1.ogg differ
diff --git a/media/vocal/flore/zspin_2.ogg b/media/vocal/flore/zspin_2.ogg
new file mode 100644
index 000000000..90ed0f6d7
Binary files /dev/null and b/media/vocal/flore/zspin_2.ogg differ
diff --git a/media/vocal/miya/angry_1.ogg b/media/vocal/miya/angry_1.ogg
new file mode 100644
index 000000000..d07a20de0
Binary files /dev/null and b/media/vocal/miya/angry_1.ogg differ
diff --git a/media/vocal/miya/b2b_1.ogg b/media/vocal/miya/b2b_1.ogg
index 9825507a8..5e8219dc4 100644
Binary files a/media/vocal/miya/b2b_1.ogg and b/media/vocal/miya/b2b_1.ogg differ
diff --git a/media/vocal/miya/b2b_2.ogg b/media/vocal/miya/b2b_2.ogg
index fe4c83b87..982de8373 100644
Binary files a/media/vocal/miya/b2b_2.ogg and b/media/vocal/miya/b2b_2.ogg differ
diff --git a/media/vocal/miya/b2b_3.ogg b/media/vocal/miya/b2b_3.ogg
index dca284549..4f44531c9 100644
Binary files a/media/vocal/miya/b2b_3.ogg and b/media/vocal/miya/b2b_3.ogg differ
diff --git a/media/vocal/miya/b3b_1.ogg b/media/vocal/miya/b3b_1.ogg
index 533febbe8..323d40bbd 100644
Binary files a/media/vocal/miya/b3b_1.ogg and b/media/vocal/miya/b3b_1.ogg differ
diff --git a/media/vocal/miya/b3b_2.ogg b/media/vocal/miya/b3b_2.ogg
index 0dc6bcc6c..714979420 100644
Binary files a/media/vocal/miya/b3b_2.ogg and b/media/vocal/miya/b3b_2.ogg differ
diff --git a/media/vocal/miya/b3b_3.ogg b/media/vocal/miya/b3b_3.ogg
new file mode 100644
index 000000000..5d9aff5e9
Binary files /dev/null and b/media/vocal/miya/b3b_3.ogg differ
diff --git a/media/vocal/miya/bye_1.ogg b/media/vocal/miya/bye_1.ogg
index 13366f0c3..20d1d9353 100644
Binary files a/media/vocal/miya/bye_1.ogg and b/media/vocal/miya/bye_1.ogg differ
diff --git a/media/vocal/miya/bye_2.ogg b/media/vocal/miya/bye_2.ogg
index 045a26f85..5a77ac21c 100644
Binary files a/media/vocal/miya/bye_2.ogg and b/media/vocal/miya/bye_2.ogg differ
diff --git a/media/vocal/miya/bye_3.ogg b/media/vocal/miya/bye_3.ogg
new file mode 100644
index 000000000..f20572a47
Binary files /dev/null and b/media/vocal/miya/bye_3.ogg differ
diff --git a/media/vocal/miya/bye_4.ogg b/media/vocal/miya/bye_4.ogg
new file mode 100644
index 000000000..4445d7494
Binary files /dev/null and b/media/vocal/miya/bye_4.ogg differ
diff --git a/media/vocal/miya/bye_5.ogg b/media/vocal/miya/bye_5.ogg
new file mode 100644
index 000000000..419c8d60d
Binary files /dev/null and b/media/vocal/miya/bye_5.ogg differ
diff --git a/media/vocal/miya/clear_1.ogg b/media/vocal/miya/clear_1.ogg
deleted file mode 100644
index 3c3ad0758..000000000
Binary files a/media/vocal/miya/clear_1.ogg and /dev/null differ
diff --git a/media/vocal/miya/clear_2.ogg b/media/vocal/miya/clear_2.ogg
deleted file mode 100644
index 84cc57fa8..000000000
Binary files a/media/vocal/miya/clear_2.ogg and /dev/null differ
diff --git a/media/vocal/miya/double_1.ogg b/media/vocal/miya/double_1.ogg
index af2b2c634..e76f0f3df 100644
Binary files a/media/vocal/miya/double_1.ogg and b/media/vocal/miya/double_1.ogg differ
diff --git a/media/vocal/miya/double_2.ogg b/media/vocal/miya/double_2.ogg
index ca10bc118..627183de7 100644
Binary files a/media/vocal/miya/double_2.ogg and b/media/vocal/miya/double_2.ogg differ
diff --git a/media/vocal/miya/double_3.ogg b/media/vocal/miya/double_3.ogg
index 5e647be72..fb29529db 100644
Binary files a/media/vocal/miya/double_3.ogg and b/media/vocal/miya/double_3.ogg differ
diff --git a/media/vocal/miya/double_4.ogg b/media/vocal/miya/double_4.ogg
deleted file mode 100644
index 6e2b9b63a..000000000
Binary files a/media/vocal/miya/double_4.ogg and /dev/null differ
diff --git a/media/vocal/miya/double_5.ogg b/media/vocal/miya/double_5.ogg
deleted file mode 100644
index 950bb06d6..000000000
Binary files a/media/vocal/miya/double_5.ogg and /dev/null differ
diff --git a/media/vocal/miya/doubt_1.ogg b/media/vocal/miya/doubt_1.ogg
index e0d94c5f4..12af3f355 100644
Binary files a/media/vocal/miya/doubt_1.ogg and b/media/vocal/miya/doubt_1.ogg differ
diff --git a/media/vocal/miya/doubt_2.ogg b/media/vocal/miya/doubt_2.ogg
index cd7ee9bdc..230e51e85 100644
Binary files a/media/vocal/miya/doubt_2.ogg and b/media/vocal/miya/doubt_2.ogg differ
diff --git a/media/vocal/miya/doubt_3.ogg b/media/vocal/miya/doubt_3.ogg
new file mode 100644
index 000000000..6895441e0
Binary files /dev/null and b/media/vocal/miya/doubt_3.ogg differ
diff --git a/media/vocal/miya/doubt_4.ogg b/media/vocal/miya/doubt_4.ogg
new file mode 100644
index 000000000..e3b3d6c2b
Binary files /dev/null and b/media/vocal/miya/doubt_4.ogg differ
diff --git a/media/vocal/miya/espin_1.ogg b/media/vocal/miya/espin_1.ogg
new file mode 100644
index 000000000..ad3f5ba02
Binary files /dev/null and b/media/vocal/miya/espin_1.ogg differ
diff --git a/media/vocal/miya/fspin_1.ogg b/media/vocal/miya/fspin_1.ogg
new file mode 100644
index 000000000..34d813845
Binary files /dev/null and b/media/vocal/miya/fspin_1.ogg differ
diff --git a/media/vocal/miya/half_clear_1.ogg b/media/vocal/miya/half_clear_1.ogg
index 43bb3b7fe..5d5f9cd68 100644
Binary files a/media/vocal/miya/half_clear_1.ogg and b/media/vocal/miya/half_clear_1.ogg differ
diff --git a/media/vocal/miya/half_clear_2.ogg b/media/vocal/miya/half_clear_2.ogg
index ee1476e83..97262b0f8 100644
Binary files a/media/vocal/miya/half_clear_2.ogg and b/media/vocal/miya/half_clear_2.ogg differ
diff --git a/media/vocal/miya/happy_1.ogg b/media/vocal/miya/happy_1.ogg
index 8b10ba459..8975f100e 100644
Binary files a/media/vocal/miya/happy_1.ogg and b/media/vocal/miya/happy_1.ogg differ
diff --git a/media/vocal/miya/happy_2.ogg b/media/vocal/miya/happy_2.ogg
index 913ca1188..f16f84cb4 100644
Binary files a/media/vocal/miya/happy_2.ogg and b/media/vocal/miya/happy_2.ogg differ
diff --git a/media/vocal/miya/happy_3.ogg b/media/vocal/miya/happy_3.ogg
index f9f534965..6114b5ed5 100644
Binary files a/media/vocal/miya/happy_3.ogg and b/media/vocal/miya/happy_3.ogg differ
diff --git a/media/vocal/miya/happy_4.ogg b/media/vocal/miya/happy_4.ogg
index e1faf5055..38d4b96de 100644
Binary files a/media/vocal/miya/happy_4.ogg and b/media/vocal/miya/happy_4.ogg differ
diff --git a/media/vocal/miya/happy_5.ogg b/media/vocal/miya/happy_5.ogg
new file mode 100644
index 000000000..bdaebf74c
Binary files /dev/null and b/media/vocal/miya/happy_5.ogg differ
diff --git a/media/vocal/miya/happy_6.ogg b/media/vocal/miya/happy_6.ogg
new file mode 100644
index 000000000..b1c09ef0e
Binary files /dev/null and b/media/vocal/miya/happy_6.ogg differ
diff --git a/media/vocal/miya/happy_7.ogg b/media/vocal/miya/happy_7.ogg
new file mode 100644
index 000000000..63afff9c3
Binary files /dev/null and b/media/vocal/miya/happy_7.ogg differ
diff --git a/media/vocal/miya/hspin_1.ogg b/media/vocal/miya/hspin_1.ogg
new file mode 100644
index 000000000..3279d8946
Binary files /dev/null and b/media/vocal/miya/hspin_1.ogg differ
diff --git a/media/vocal/miya/ispin_1.ogg b/media/vocal/miya/ispin_1.ogg
index 25a5539f6..55e2ef080 100644
Binary files a/media/vocal/miya/ispin_1.ogg and b/media/vocal/miya/ispin_1.ogg differ
diff --git a/media/vocal/miya/ispin_2.ogg b/media/vocal/miya/ispin_2.ogg
index 661ea38be..a337b8aa2 100644
Binary files a/media/vocal/miya/ispin_2.ogg and b/media/vocal/miya/ispin_2.ogg differ
diff --git a/media/vocal/miya/ispin_3.ogg b/media/vocal/miya/ispin_3.ogg
deleted file mode 100644
index b0233fa7c..000000000
Binary files a/media/vocal/miya/ispin_3.ogg and /dev/null differ
diff --git a/media/vocal/miya/jspin_1.ogg b/media/vocal/miya/jspin_1.ogg
index efe109356..6d0c7a410 100644
Binary files a/media/vocal/miya/jspin_1.ogg and b/media/vocal/miya/jspin_1.ogg differ
diff --git a/media/vocal/miya/jspin_2.ogg b/media/vocal/miya/jspin_2.ogg
index 81abf3bc9..6b362600a 100644
Binary files a/media/vocal/miya/jspin_2.ogg and b/media/vocal/miya/jspin_2.ogg differ
diff --git a/media/vocal/miya/jspin_3.ogg b/media/vocal/miya/jspin_3.ogg
deleted file mode 100644
index cb9c44e87..000000000
Binary files a/media/vocal/miya/jspin_3.ogg and /dev/null differ
diff --git a/media/vocal/miya/jspin_4.ogg b/media/vocal/miya/jspin_4.ogg
deleted file mode 100644
index 3b6eb33c0..000000000
Binary files a/media/vocal/miya/jspin_4.ogg and /dev/null differ
diff --git a/media/vocal/miya/lose_1.ogg b/media/vocal/miya/lose_1.ogg
index 0d6c2e70c..baaa6d8a0 100644
Binary files a/media/vocal/miya/lose_1.ogg and b/media/vocal/miya/lose_1.ogg differ
diff --git a/media/vocal/miya/lose_2.ogg b/media/vocal/miya/lose_2.ogg
index 29ebd17b1..6b97a663d 100644
Binary files a/media/vocal/miya/lose_2.ogg and b/media/vocal/miya/lose_2.ogg differ
diff --git a/media/vocal/miya/lose_3.ogg b/media/vocal/miya/lose_3.ogg
index da48ed4bb..a590b5799 100644
Binary files a/media/vocal/miya/lose_3.ogg and b/media/vocal/miya/lose_3.ogg differ
diff --git a/media/vocal/miya/lose_4.ogg b/media/vocal/miya/lose_4.ogg
new file mode 100644
index 000000000..bb724ee72
Binary files /dev/null and b/media/vocal/miya/lose_4.ogg differ
diff --git a/media/vocal/miya/lose_5.ogg b/media/vocal/miya/lose_5.ogg
new file mode 100644
index 000000000..2f7394ee5
Binary files /dev/null and b/media/vocal/miya/lose_5.ogg differ
diff --git a/media/vocal/miya/lose_6.ogg b/media/vocal/miya/lose_6.ogg
new file mode 100644
index 000000000..cf5dacb81
Binary files /dev/null and b/media/vocal/miya/lose_6.ogg differ
diff --git a/media/vocal/miya/lspin_1.ogg b/media/vocal/miya/lspin_1.ogg
index ff0342f25..5af71baac 100644
Binary files a/media/vocal/miya/lspin_1.ogg and b/media/vocal/miya/lspin_1.ogg differ
diff --git a/media/vocal/miya/lspin_2.ogg b/media/vocal/miya/lspin_2.ogg
deleted file mode 100644
index 102abe279..000000000
Binary files a/media/vocal/miya/lspin_2.ogg and /dev/null differ
diff --git a/media/vocal/miya/mini_1.ogg b/media/vocal/miya/mini_1.ogg
index 8678bc2eb..f4586fbc6 100644
Binary files a/media/vocal/miya/mini_1.ogg and b/media/vocal/miya/mini_1.ogg differ
diff --git a/media/vocal/miya/mini_2.ogg b/media/vocal/miya/mini_2.ogg
index 4b1230a4e..4953c597b 100644
Binary files a/media/vocal/miya/mini_2.ogg and b/media/vocal/miya/mini_2.ogg differ
diff --git a/media/vocal/miya/mini_3.ogg b/media/vocal/miya/mini_3.ogg
index cf10f2291..bde5b757d 100644
Binary files a/media/vocal/miya/mini_3.ogg and b/media/vocal/miya/mini_3.ogg differ
diff --git a/media/vocal/miya/mini_4.ogg b/media/vocal/miya/mini_4.ogg
new file mode 100644
index 000000000..c68945bc5
Binary files /dev/null and b/media/vocal/miya/mini_4.ogg differ
diff --git a/media/vocal/miya/mini_5.ogg b/media/vocal/miya/mini_5.ogg
new file mode 100644
index 000000000..2d3037502
Binary files /dev/null and b/media/vocal/miya/mini_5.ogg differ
diff --git a/media/vocal/miya/nspin_1.ogg b/media/vocal/miya/nspin_1.ogg
new file mode 100644
index 000000000..cacb9d011
Binary files /dev/null and b/media/vocal/miya/nspin_1.ogg differ
diff --git a/media/vocal/miya/nya_1.ogg b/media/vocal/miya/nya_1.ogg
deleted file mode 100644
index c51b00c5e..000000000
Binary files a/media/vocal/miya/nya_1.ogg and /dev/null differ
diff --git a/media/vocal/miya/nya_2.ogg b/media/vocal/miya/nya_2.ogg
deleted file mode 100644
index e278ffffa..000000000
Binary files a/media/vocal/miya/nya_2.ogg and /dev/null differ
diff --git a/media/vocal/miya/nya_3.ogg b/media/vocal/miya/nya_3.ogg
deleted file mode 100644
index 0ed6aad7e..000000000
Binary files a/media/vocal/miya/nya_3.ogg and /dev/null differ
diff --git a/media/vocal/miya/nya_4.ogg b/media/vocal/miya/nya_4.ogg
deleted file mode 100644
index 9a7307c86..000000000
Binary files a/media/vocal/miya/nya_4.ogg and /dev/null differ
diff --git a/media/vocal/miya/nya_doubt_1.ogg b/media/vocal/miya/nya_doubt_1.ogg
deleted file mode 100644
index e0d94c5f4..000000000
Binary files a/media/vocal/miya/nya_doubt_1.ogg and /dev/null differ
diff --git a/media/vocal/miya/nya_doubt_2.ogg b/media/vocal/miya/nya_doubt_2.ogg
deleted file mode 100644
index cd7ee9bdc..000000000
Binary files a/media/vocal/miya/nya_doubt_2.ogg and /dev/null differ
diff --git a/media/vocal/miya/nya_happy_1.ogg b/media/vocal/miya/nya_happy_1.ogg
deleted file mode 100644
index 8b10ba459..000000000
Binary files a/media/vocal/miya/nya_happy_1.ogg and /dev/null differ
diff --git a/media/vocal/miya/nya_happy_2.ogg b/media/vocal/miya/nya_happy_2.ogg
deleted file mode 100644
index 913ca1188..000000000
Binary files a/media/vocal/miya/nya_happy_2.ogg and /dev/null differ
diff --git a/media/vocal/miya/nya_happy_3.ogg b/media/vocal/miya/nya_happy_3.ogg
deleted file mode 100644
index f9f534965..000000000
Binary files a/media/vocal/miya/nya_happy_3.ogg and /dev/null differ
diff --git a/media/vocal/miya/nya_happy_4.ogg b/media/vocal/miya/nya_happy_4.ogg
deleted file mode 100644
index e1faf5055..000000000
Binary files a/media/vocal/miya/nya_happy_4.ogg and /dev/null differ
diff --git a/media/vocal/miya/nya_sad_1.ogg b/media/vocal/miya/nya_sad_1.ogg
deleted file mode 100644
index 4270f18ca..000000000
Binary files a/media/vocal/miya/nya_sad_1.ogg and /dev/null differ
diff --git a/media/vocal/miya/ospin_1.ogg b/media/vocal/miya/ospin_1.ogg
index 1d0651ed3..26ad0e6ef 100644
Binary files a/media/vocal/miya/ospin_1.ogg and b/media/vocal/miya/ospin_1.ogg differ
diff --git a/media/vocal/miya/ospin_2.ogg b/media/vocal/miya/ospin_2.ogg
index a70f0e173..4fa006ab9 100644
Binary files a/media/vocal/miya/ospin_2.ogg and b/media/vocal/miya/ospin_2.ogg differ
diff --git a/media/vocal/miya/ospin_3.ogg b/media/vocal/miya/ospin_3.ogg
deleted file mode 100644
index b8523892b..000000000
Binary files a/media/vocal/miya/ospin_3.ogg and /dev/null differ
diff --git a/media/vocal/miya/perfect_clear_1.ogg b/media/vocal/miya/perfect_clear_1.ogg
index 3c3ad0758..aaf235f32 100644
Binary files a/media/vocal/miya/perfect_clear_1.ogg and b/media/vocal/miya/perfect_clear_1.ogg differ
diff --git a/media/vocal/miya/perfect_clear_2.ogg b/media/vocal/miya/perfect_clear_2.ogg
index 84cc57fa8..9efdadfaa 100644
Binary files a/media/vocal/miya/perfect_clear_2.ogg and b/media/vocal/miya/perfect_clear_2.ogg differ
diff --git a/media/vocal/miya/perfect_clear_3.ogg b/media/vocal/miya/perfect_clear_3.ogg
new file mode 100644
index 000000000..68b610f0a
Binary files /dev/null and b/media/vocal/miya/perfect_clear_3.ogg differ
diff --git a/media/vocal/miya/perfect_clear_4.ogg b/media/vocal/miya/perfect_clear_4.ogg
new file mode 100644
index 000000000..0a165b671
Binary files /dev/null and b/media/vocal/miya/perfect_clear_4.ogg differ
diff --git a/media/vocal/miya/perfect_clear_5.ogg b/media/vocal/miya/perfect_clear_5.ogg
new file mode 100644
index 000000000..91579e50f
Binary files /dev/null and b/media/vocal/miya/perfect_clear_5.ogg differ
diff --git a/media/vocal/miya/pspin_1.ogg b/media/vocal/miya/pspin_1.ogg
new file mode 100644
index 000000000..10bb18108
Binary files /dev/null and b/media/vocal/miya/pspin_1.ogg differ
diff --git a/media/vocal/miya/qspin_1.ogg b/media/vocal/miya/qspin_1.ogg
new file mode 100644
index 000000000..7acff5135
Binary files /dev/null and b/media/vocal/miya/qspin_1.ogg differ
diff --git a/media/vocal/miya/rspin_1.ogg b/media/vocal/miya/rspin_1.ogg
new file mode 100644
index 000000000..69cddb03a
Binary files /dev/null and b/media/vocal/miya/rspin_1.ogg differ
diff --git a/media/vocal/miya/sad_1.ogg b/media/vocal/miya/sad_1.ogg
new file mode 100644
index 000000000..9654ff7b1
Binary files /dev/null and b/media/vocal/miya/sad_1.ogg differ
diff --git a/media/vocal/miya/single_1.ogg b/media/vocal/miya/single_1.ogg
index 41ec27983..41f9411d0 100644
Binary files a/media/vocal/miya/single_1.ogg and b/media/vocal/miya/single_1.ogg differ
diff --git a/media/vocal/miya/single_2.ogg b/media/vocal/miya/single_2.ogg
index e74c71030..cf32a878f 100644
Binary files a/media/vocal/miya/single_2.ogg and b/media/vocal/miya/single_2.ogg differ
diff --git a/media/vocal/miya/single_3.ogg b/media/vocal/miya/single_3.ogg
deleted file mode 100644
index b90251aff..000000000
Binary files a/media/vocal/miya/single_3.ogg and /dev/null differ
diff --git a/media/vocal/miya/single_4.ogg b/media/vocal/miya/single_4.ogg
deleted file mode 100644
index d66efcf7e..000000000
Binary files a/media/vocal/miya/single_4.ogg and /dev/null differ
diff --git a/media/vocal/miya/single_5.ogg b/media/vocal/miya/single_5.ogg
deleted file mode 100644
index 43c718659..000000000
Binary files a/media/vocal/miya/single_5.ogg and /dev/null differ
diff --git a/media/vocal/miya/single_6.ogg b/media/vocal/miya/single_6.ogg
deleted file mode 100644
index edf427ad4..000000000
Binary files a/media/vocal/miya/single_6.ogg and /dev/null differ
diff --git a/media/vocal/miya/single_7.ogg b/media/vocal/miya/single_7.ogg
deleted file mode 100644
index f173c2dfc..000000000
Binary files a/media/vocal/miya/single_7.ogg and /dev/null differ
diff --git a/media/vocal/miya/sspin_1.ogg b/media/vocal/miya/sspin_1.ogg
index b620a7e0d..34347314c 100644
Binary files a/media/vocal/miya/sspin_1.ogg and b/media/vocal/miya/sspin_1.ogg differ
diff --git a/media/vocal/miya/sspin_2.ogg b/media/vocal/miya/sspin_2.ogg
index e32904b5f..565df4836 100644
Binary files a/media/vocal/miya/sspin_2.ogg and b/media/vocal/miya/sspin_2.ogg differ
diff --git a/media/vocal/miya/sspin_3.ogg b/media/vocal/miya/sspin_3.ogg
index e6cb63311..49baebd8b 100644
Binary files a/media/vocal/miya/sspin_3.ogg and b/media/vocal/miya/sspin_3.ogg differ
diff --git a/media/vocal/miya/sspin_4.ogg b/media/vocal/miya/sspin_4.ogg
index a1f184688..93ad383f3 100644
Binary files a/media/vocal/miya/sspin_4.ogg and b/media/vocal/miya/sspin_4.ogg differ
diff --git a/media/vocal/miya/sspin_5.ogg b/media/vocal/miya/sspin_5.ogg
deleted file mode 100644
index 2494d3bb5..000000000
Binary files a/media/vocal/miya/sspin_5.ogg and /dev/null differ
diff --git a/media/vocal/miya/sspin_6.ogg b/media/vocal/miya/sspin_6.ogg
deleted file mode 100644
index e2690ea5c..000000000
Binary files a/media/vocal/miya/sspin_6.ogg and /dev/null differ
diff --git a/media/vocal/miya/techrash_1.ogg b/media/vocal/miya/techrash_1.ogg
index 4c4b6f146..32347e031 100644
Binary files a/media/vocal/miya/techrash_1.ogg and b/media/vocal/miya/techrash_1.ogg differ
diff --git a/media/vocal/miya/techrash_2.ogg b/media/vocal/miya/techrash_2.ogg
index c56a01f1b..b45e0783b 100644
Binary files a/media/vocal/miya/techrash_2.ogg and b/media/vocal/miya/techrash_2.ogg differ
diff --git a/media/vocal/miya/techrash_3.ogg b/media/vocal/miya/techrash_3.ogg
deleted file mode 100644
index 49bc7ab0f..000000000
Binary files a/media/vocal/miya/techrash_3.ogg and /dev/null differ
diff --git a/media/vocal/miya/techrash_4.ogg b/media/vocal/miya/techrash_4.ogg
deleted file mode 100644
index c001c793f..000000000
Binary files a/media/vocal/miya/techrash_4.ogg and /dev/null differ
diff --git a/media/vocal/miya/test_1.ogg b/media/vocal/miya/test_1.ogg
index c51b00c5e..68724ef42 100644
Binary files a/media/vocal/miya/test_1.ogg and b/media/vocal/miya/test_1.ogg differ
diff --git a/media/vocal/miya/test_2.ogg b/media/vocal/miya/test_2.ogg
index e278ffffa..6484f0c9a 100644
Binary files a/media/vocal/miya/test_2.ogg and b/media/vocal/miya/test_2.ogg differ
diff --git a/media/vocal/miya/test_3.ogg b/media/vocal/miya/test_3.ogg
index 0ed6aad7e..f0d6d41a1 100644
Binary files a/media/vocal/miya/test_3.ogg and b/media/vocal/miya/test_3.ogg differ
diff --git a/media/vocal/miya/test_4.ogg b/media/vocal/miya/test_4.ogg
index 9a7307c86..e33d10c77 100644
Binary files a/media/vocal/miya/test_4.ogg and b/media/vocal/miya/test_4.ogg differ
diff --git a/media/vocal/miya/triple_1.ogg b/media/vocal/miya/triple_1.ogg
index 7d564188b..aaf713710 100644
Binary files a/media/vocal/miya/triple_1.ogg and b/media/vocal/miya/triple_1.ogg differ
diff --git a/media/vocal/miya/triple_2.ogg b/media/vocal/miya/triple_2.ogg
index 58518f144..7285cb6af 100644
Binary files a/media/vocal/miya/triple_2.ogg and b/media/vocal/miya/triple_2.ogg differ
diff --git a/media/vocal/miya/triple_3.ogg b/media/vocal/miya/triple_3.ogg
index eb9daf3b9..19a697966 100644
Binary files a/media/vocal/miya/triple_3.ogg and b/media/vocal/miya/triple_3.ogg differ
diff --git a/media/vocal/miya/triple_4.ogg b/media/vocal/miya/triple_4.ogg
index cea64b4ab..6d10a504f 100644
Binary files a/media/vocal/miya/triple_4.ogg and b/media/vocal/miya/triple_4.ogg differ
diff --git a/media/vocal/miya/triple_5.ogg b/media/vocal/miya/triple_5.ogg
deleted file mode 100644
index b19062fc0..000000000
Binary files a/media/vocal/miya/triple_5.ogg and /dev/null differ
diff --git a/media/vocal/miya/triple_6.ogg b/media/vocal/miya/triple_6.ogg
deleted file mode 100644
index 0221d8437..000000000
Binary files a/media/vocal/miya/triple_6.ogg and /dev/null differ
diff --git a/media/vocal/miya/triple_7.ogg b/media/vocal/miya/triple_7.ogg
deleted file mode 100644
index 4dedec5b9..000000000
Binary files a/media/vocal/miya/triple_7.ogg and /dev/null differ
diff --git a/media/vocal/miya/tspin_1.ogg b/media/vocal/miya/tspin_1.ogg
index 982712b17..c70038844 100644
Binary files a/media/vocal/miya/tspin_1.ogg and b/media/vocal/miya/tspin_1.ogg differ
diff --git a/media/vocal/miya/tspin_2.ogg b/media/vocal/miya/tspin_2.ogg
index f597536ad..87640b3a6 100644
Binary files a/media/vocal/miya/tspin_2.ogg and b/media/vocal/miya/tspin_2.ogg differ
diff --git a/media/vocal/miya/tspin_3.ogg b/media/vocal/miya/tspin_3.ogg
index d15c53480..6a1a8a422 100644
Binary files a/media/vocal/miya/tspin_3.ogg and b/media/vocal/miya/tspin_3.ogg differ
diff --git a/media/vocal/miya/tspin_4.ogg b/media/vocal/miya/tspin_4.ogg
deleted file mode 100644
index 3747c6eb8..000000000
Binary files a/media/vocal/miya/tspin_4.ogg and /dev/null differ
diff --git a/media/vocal/miya/tspin_5.ogg b/media/vocal/miya/tspin_5.ogg
deleted file mode 100644
index af2487ea0..000000000
Binary files a/media/vocal/miya/tspin_5.ogg and /dev/null differ
diff --git a/media/vocal/miya/tspin_6.ogg b/media/vocal/miya/tspin_6.ogg
deleted file mode 100644
index 0b569d33e..000000000
Binary files a/media/vocal/miya/tspin_6.ogg and /dev/null differ
diff --git a/media/vocal/miya/uspin_1.ogg b/media/vocal/miya/uspin_1.ogg
new file mode 100644
index 000000000..3ed149243
Binary files /dev/null and b/media/vocal/miya/uspin_1.ogg differ
diff --git a/media/vocal/miya/vspin_1.ogg b/media/vocal/miya/vspin_1.ogg
new file mode 100644
index 000000000..2b1c5f2bf
Binary files /dev/null and b/media/vocal/miya/vspin_1.ogg differ
diff --git a/media/vocal/miya/welcome.ogg b/media/vocal/miya/welcome.ogg
deleted file mode 100644
index 908560473..000000000
Binary files a/media/vocal/miya/welcome.ogg and /dev/null differ
diff --git a/media/vocal/miya/welcome_1.ogg b/media/vocal/miya/welcome_1.ogg
new file mode 100644
index 000000000..11e74486c
Binary files /dev/null and b/media/vocal/miya/welcome_1.ogg differ
diff --git a/media/vocal/miya/welcome_2.ogg b/media/vocal/miya/welcome_2.ogg
new file mode 100644
index 000000000..daf001cce
Binary files /dev/null and b/media/vocal/miya/welcome_2.ogg differ
diff --git a/media/vocal/miya/welcome_3.ogg b/media/vocal/miya/welcome_3.ogg
new file mode 100644
index 000000000..1b8b77499
Binary files /dev/null and b/media/vocal/miya/welcome_3.ogg differ
diff --git a/media/vocal/miya/welcome_4.ogg b/media/vocal/miya/welcome_4.ogg
new file mode 100644
index 000000000..33df5771e
Binary files /dev/null and b/media/vocal/miya/welcome_4.ogg differ
diff --git a/media/vocal/miya/welcome_5.ogg b/media/vocal/miya/welcome_5.ogg
new file mode 100644
index 000000000..5f85a97b2
Binary files /dev/null and b/media/vocal/miya/welcome_5.ogg differ
diff --git a/media/vocal/miya/welcome_6.ogg b/media/vocal/miya/welcome_6.ogg
new file mode 100644
index 000000000..46706bfb3
Binary files /dev/null and b/media/vocal/miya/welcome_6.ogg differ
diff --git a/media/vocal/miya/win_1.ogg b/media/vocal/miya/win_1.ogg
index 502d5d22b..0811560a3 100644
Binary files a/media/vocal/miya/win_1.ogg and b/media/vocal/miya/win_1.ogg differ
diff --git a/media/vocal/miya/win_2.ogg b/media/vocal/miya/win_2.ogg
index 543ca30ac..18d2912b6 100644
Binary files a/media/vocal/miya/win_2.ogg and b/media/vocal/miya/win_2.ogg differ
diff --git a/media/vocal/miya/win_3.ogg b/media/vocal/miya/win_3.ogg
index f50557127..86861684d 100644
Binary files a/media/vocal/miya/win_3.ogg and b/media/vocal/miya/win_3.ogg differ
diff --git a/media/vocal/miya/win_4.ogg b/media/vocal/miya/win_4.ogg
index 7528d3929..bb55c76b6 100644
Binary files a/media/vocal/miya/win_4.ogg and b/media/vocal/miya/win_4.ogg differ
diff --git a/media/vocal/miya/win_5.ogg b/media/vocal/miya/win_5.ogg
index c0e14db01..8210e03c1 100644
Binary files a/media/vocal/miya/win_5.ogg and b/media/vocal/miya/win_5.ogg differ
diff --git a/media/vocal/miya/win_6.ogg b/media/vocal/miya/win_6.ogg
index 99f681c41..1fe6416be 100644
Binary files a/media/vocal/miya/win_6.ogg and b/media/vocal/miya/win_6.ogg differ
diff --git a/media/vocal/miya/win_7.ogg b/media/vocal/miya/win_7.ogg
deleted file mode 100644
index fa5fa03be..000000000
Binary files a/media/vocal/miya/win_7.ogg and /dev/null differ
diff --git a/media/vocal/miya/win_8.ogg b/media/vocal/miya/win_8.ogg
deleted file mode 100644
index bcf18792d..000000000
Binary files a/media/vocal/miya/win_8.ogg and /dev/null differ
diff --git a/media/vocal/miya/wspin_1.ogg b/media/vocal/miya/wspin_1.ogg
new file mode 100644
index 000000000..3e2d490a5
Binary files /dev/null and b/media/vocal/miya/wspin_1.ogg differ
diff --git a/media/vocal/miya/xspin_1.ogg b/media/vocal/miya/xspin_1.ogg
new file mode 100644
index 000000000..823707d99
Binary files /dev/null and b/media/vocal/miya/xspin_1.ogg differ
diff --git a/media/vocal/miya/yspin_1.ogg b/media/vocal/miya/yspin_1.ogg
new file mode 100644
index 000000000..82af8c26d
Binary files /dev/null and b/media/vocal/miya/yspin_1.ogg differ
diff --git a/media/vocal/miya/zspin_1.ogg b/media/vocal/miya/zspin_1.ogg
index 8da82c520..7e9698975 100644
Binary files a/media/vocal/miya/zspin_1.ogg and b/media/vocal/miya/zspin_1.ogg differ
diff --git a/media/vocal/miya/zspin_2.ogg b/media/vocal/miya/zspin_2.ogg
index 776e51933..42736c160 100644
Binary files a/media/vocal/miya/zspin_2.ogg and b/media/vocal/miya/zspin_2.ogg differ
diff --git a/media/vocal/miya/zspin_3.ogg b/media/vocal/miya/zspin_3.ogg
index 91bd6caa8..c43fdad05 100644
Binary files a/media/vocal/miya/zspin_3.ogg and b/media/vocal/miya/zspin_3.ogg differ
diff --git a/media/vocal/mono/bye_1.ogg b/media/vocal/mono/bye_1.ogg
new file mode 100644
index 000000000..973a7fbdc
Binary files /dev/null and b/media/vocal/mono/bye_1.ogg differ
diff --git a/media/vocal/mono/bye_2.ogg b/media/vocal/mono/bye_2.ogg
new file mode 100644
index 000000000..65073d7c3
Binary files /dev/null and b/media/vocal/mono/bye_2.ogg differ
diff --git a/media/vocal/mono/bye_3.ogg b/media/vocal/mono/bye_3.ogg
new file mode 100644
index 000000000..70c9e3761
Binary files /dev/null and b/media/vocal/mono/bye_3.ogg differ
diff --git a/media/vocal/mono/bye_4.ogg b/media/vocal/mono/bye_4.ogg
new file mode 100644
index 000000000..24b94a561
Binary files /dev/null and b/media/vocal/mono/bye_4.ogg differ
diff --git a/media/vocal/mono/clear_1.ogg b/media/vocal/mono/clear_1.ogg
new file mode 100644
index 000000000..9d6714a3c
Binary files /dev/null and b/media/vocal/mono/clear_1.ogg differ
diff --git a/media/vocal/mono/clear_2.ogg b/media/vocal/mono/clear_2.ogg
new file mode 100644
index 000000000..1542fe6e7
Binary files /dev/null and b/media/vocal/mono/clear_2.ogg differ
diff --git a/media/vocal/mono/clear_3.ogg b/media/vocal/mono/clear_3.ogg
new file mode 100644
index 000000000..fc0bf401c
Binary files /dev/null and b/media/vocal/mono/clear_3.ogg differ
diff --git a/media/vocal/mono/clear_4.ogg b/media/vocal/mono/clear_4.ogg
new file mode 100644
index 000000000..e128d9fc4
Binary files /dev/null and b/media/vocal/mono/clear_4.ogg differ
diff --git a/media/vocal/mono/double.ogg b/media/vocal/mono/double.ogg
deleted file mode 100644
index 8617370df..000000000
Binary files a/media/vocal/mono/double.ogg and /dev/null differ
diff --git a/media/vocal/mono/double_1.ogg b/media/vocal/mono/double_1.ogg
new file mode 100644
index 000000000..8469bf0a0
Binary files /dev/null and b/media/vocal/mono/double_1.ogg differ
diff --git a/media/vocal/mono/double_2.ogg b/media/vocal/mono/double_2.ogg
new file mode 100644
index 000000000..77bbd7009
Binary files /dev/null and b/media/vocal/mono/double_2.ogg differ
diff --git a/media/vocal/mono/double_3.ogg b/media/vocal/mono/double_3.ogg
new file mode 100644
index 000000000..f13dc6535
Binary files /dev/null and b/media/vocal/mono/double_3.ogg differ
diff --git a/media/vocal/mono/double_4.ogg b/media/vocal/mono/double_4.ogg
new file mode 100644
index 000000000..e68d0d3af
Binary files /dev/null and b/media/vocal/mono/double_4.ogg differ
diff --git a/media/vocal/mono/doubt_1.ogg b/media/vocal/mono/doubt_1.ogg
new file mode 100644
index 000000000..7cf249862
Binary files /dev/null and b/media/vocal/mono/doubt_1.ogg differ
diff --git a/media/vocal/mono/doubt_2.ogg b/media/vocal/mono/doubt_2.ogg
new file mode 100644
index 000000000..626a63aea
Binary files /dev/null and b/media/vocal/mono/doubt_2.ogg differ
diff --git a/media/vocal/mono/doubt_3.ogg b/media/vocal/mono/doubt_3.ogg
new file mode 100644
index 000000000..63a37d62b
Binary files /dev/null and b/media/vocal/mono/doubt_3.ogg differ
diff --git a/media/vocal/mono/doubt_4.ogg b/media/vocal/mono/doubt_4.ogg
new file mode 100644
index 000000000..c48cfec60
Binary files /dev/null and b/media/vocal/mono/doubt_4.ogg differ
diff --git a/media/vocal/mono/half_clear_1.ogg b/media/vocal/mono/half_clear.ogg
similarity index 100%
rename from media/vocal/mono/half_clear_1.ogg
rename to media/vocal/mono/half_clear.ogg
diff --git a/media/vocal/mono/happy_1.ogg b/media/vocal/mono/happy_1.ogg
new file mode 100644
index 000000000..55013860b
Binary files /dev/null and b/media/vocal/mono/happy_1.ogg differ
diff --git a/media/vocal/mono/happy_2.ogg b/media/vocal/mono/happy_2.ogg
new file mode 100644
index 000000000..71445d813
Binary files /dev/null and b/media/vocal/mono/happy_2.ogg differ
diff --git a/media/vocal/mono/happy_3.ogg b/media/vocal/mono/happy_3.ogg
new file mode 100644
index 000000000..b98941221
Binary files /dev/null and b/media/vocal/mono/happy_3.ogg differ
diff --git a/media/vocal/mono/happy_4.ogg b/media/vocal/mono/happy_4.ogg
new file mode 100644
index 000000000..e076edbb7
Binary files /dev/null and b/media/vocal/mono/happy_4.ogg differ
diff --git a/media/vocal/mono/hexacrash_1.ogg b/media/vocal/mono/hexacrash_1.ogg
new file mode 100644
index 000000000..8bdf767cb
Binary files /dev/null and b/media/vocal/mono/hexacrash_1.ogg differ
diff --git a/media/vocal/mono/hexacrash_2.ogg b/media/vocal/mono/hexacrash_2.ogg
new file mode 100644
index 000000000..3183fc80e
Binary files /dev/null and b/media/vocal/mono/hexacrash_2.ogg differ
diff --git a/media/vocal/mono/hexacrash_3.ogg b/media/vocal/mono/hexacrash_3.ogg
new file mode 100644
index 000000000..702c2b205
Binary files /dev/null and b/media/vocal/mono/hexacrash_3.ogg differ
diff --git a/media/vocal/mono/hexacrash_4.ogg b/media/vocal/mono/hexacrash_4.ogg
new file mode 100644
index 000000000..c9b7d7945
Binary files /dev/null and b/media/vocal/mono/hexacrash_4.ogg differ
diff --git a/media/vocal/mono/ispin.ogg b/media/vocal/mono/ispin.ogg
new file mode 100644
index 000000000..07ef4f09b
Binary files /dev/null and b/media/vocal/mono/ispin.ogg differ
diff --git a/media/vocal/mono/ispin0.ogg b/media/vocal/mono/ispin0.ogg
new file mode 100644
index 000000000..5a9fcea46
Binary files /dev/null and b/media/vocal/mono/ispin0.ogg differ
diff --git a/media/vocal/mono/ispin_1.ogg b/media/vocal/mono/ispin_1.ogg
deleted file mode 100644
index b269f77c1..000000000
Binary files a/media/vocal/mono/ispin_1.ogg and /dev/null differ
diff --git a/media/vocal/mono/ispin_2.ogg b/media/vocal/mono/ispin_2.ogg
deleted file mode 100644
index 63e40ee35..000000000
Binary files a/media/vocal/mono/ispin_2.ogg and /dev/null differ
diff --git a/media/vocal/mono/ispin_3.ogg b/media/vocal/mono/ispin_3.ogg
deleted file mode 100644
index 310ed5791..000000000
Binary files a/media/vocal/mono/ispin_3.ogg and /dev/null differ
diff --git a/media/vocal/mono/ispin_4.ogg b/media/vocal/mono/ispin_4.ogg
deleted file mode 100644
index bf506a045..000000000
Binary files a/media/vocal/mono/ispin_4.ogg and /dev/null differ
diff --git a/media/vocal/mono/jspin.ogg b/media/vocal/mono/jspin.ogg
new file mode 100644
index 000000000..579eddd65
Binary files /dev/null and b/media/vocal/mono/jspin.ogg differ
diff --git a/media/vocal/mono/jspin0.ogg b/media/vocal/mono/jspin0.ogg
new file mode 100644
index 000000000..35d7dda15
Binary files /dev/null and b/media/vocal/mono/jspin0.ogg differ
diff --git a/media/vocal/mono/jspin_1.ogg b/media/vocal/mono/jspin_1.ogg
deleted file mode 100644
index 420eb5f34..000000000
Binary files a/media/vocal/mono/jspin_1.ogg and /dev/null differ
diff --git a/media/vocal/mono/jspin_2.ogg b/media/vocal/mono/jspin_2.ogg
deleted file mode 100644
index 68fb6f3dd..000000000
Binary files a/media/vocal/mono/jspin_2.ogg and /dev/null differ
diff --git a/media/vocal/mono/jspin_3.ogg b/media/vocal/mono/jspin_3.ogg
deleted file mode 100644
index 407052326..000000000
Binary files a/media/vocal/mono/jspin_3.ogg and /dev/null differ
diff --git a/media/vocal/mono/jspin_4.ogg b/media/vocal/mono/jspin_4.ogg
deleted file mode 100644
index 322556027..000000000
Binary files a/media/vocal/mono/jspin_4.ogg and /dev/null differ
diff --git a/media/vocal/mono/lose_1.ogg b/media/vocal/mono/lose_1.ogg
index 7cd53e1bb..9b645c3d4 100644
Binary files a/media/vocal/mono/lose_1.ogg and b/media/vocal/mono/lose_1.ogg differ
diff --git a/media/vocal/mono/lose_2.ogg b/media/vocal/mono/lose_2.ogg
index 58c0f5b38..94fe5124c 100644
Binary files a/media/vocal/mono/lose_2.ogg and b/media/vocal/mono/lose_2.ogg differ
diff --git a/media/vocal/mono/lose_3.ogg b/media/vocal/mono/lose_3.ogg
index fbab21e72..8ede047a3 100644
Binary files a/media/vocal/mono/lose_3.ogg and b/media/vocal/mono/lose_3.ogg differ
diff --git a/media/vocal/mono/lose_4.ogg b/media/vocal/mono/lose_4.ogg
new file mode 100644
index 000000000..2832ab42d
Binary files /dev/null and b/media/vocal/mono/lose_4.ogg differ
diff --git a/media/vocal/mono/lose_5.ogg b/media/vocal/mono/lose_5.ogg
new file mode 100644
index 000000000..1b3a2171b
Binary files /dev/null and b/media/vocal/mono/lose_5.ogg differ
diff --git a/media/vocal/mono/lose_6.ogg b/media/vocal/mono/lose_6.ogg
new file mode 100644
index 000000000..181497731
Binary files /dev/null and b/media/vocal/mono/lose_6.ogg differ
diff --git a/media/vocal/mono/lspin.ogg b/media/vocal/mono/lspin.ogg
new file mode 100644
index 000000000..83097cbc7
Binary files /dev/null and b/media/vocal/mono/lspin.ogg differ
diff --git a/media/vocal/mono/lspin0.ogg b/media/vocal/mono/lspin0.ogg
new file mode 100644
index 000000000..9ae4cc605
Binary files /dev/null and b/media/vocal/mono/lspin0.ogg differ
diff --git a/media/vocal/mono/lspin_1.ogg b/media/vocal/mono/lspin_1.ogg
deleted file mode 100644
index ccd114b18..000000000
Binary files a/media/vocal/mono/lspin_1.ogg and /dev/null differ
diff --git a/media/vocal/mono/lspin_2.ogg b/media/vocal/mono/lspin_2.ogg
deleted file mode 100644
index ac44b0045..000000000
Binary files a/media/vocal/mono/lspin_2.ogg and /dev/null differ
diff --git a/media/vocal/mono/lspin_3.ogg b/media/vocal/mono/lspin_3.ogg
deleted file mode 100644
index 72995edb7..000000000
Binary files a/media/vocal/mono/lspin_3.ogg and /dev/null differ
diff --git a/media/vocal/mono/mini_1.ogg b/media/vocal/mono/mini_1.ogg
deleted file mode 100644
index 4a5e4a2e2..000000000
Binary files a/media/vocal/mono/mini_1.ogg and /dev/null differ
diff --git a/media/vocal/mono/mini_2.ogg b/media/vocal/mono/mini_2.ogg
deleted file mode 100644
index 1245e8a2a..000000000
Binary files a/media/vocal/mono/mini_2.ogg and /dev/null differ
diff --git a/media/vocal/mono/mini_3.ogg b/media/vocal/mono/mini_3.ogg
deleted file mode 100644
index 18888005d..000000000
Binary files a/media/vocal/mono/mini_3.ogg and /dev/null differ
diff --git a/media/vocal/mono/ospin.ogg b/media/vocal/mono/ospin.ogg
new file mode 100644
index 000000000..20d0a9d24
Binary files /dev/null and b/media/vocal/mono/ospin.ogg differ
diff --git a/media/vocal/mono/ospin0.ogg b/media/vocal/mono/ospin0.ogg
new file mode 100644
index 000000000..c55725476
Binary files /dev/null and b/media/vocal/mono/ospin0.ogg differ
diff --git a/media/vocal/mono/ospin_1.ogg b/media/vocal/mono/ospin_1.ogg
deleted file mode 100644
index 3016ed39a..000000000
Binary files a/media/vocal/mono/ospin_1.ogg and /dev/null differ
diff --git a/media/vocal/mono/ospin_2.ogg b/media/vocal/mono/ospin_2.ogg
deleted file mode 100644
index 83695304a..000000000
Binary files a/media/vocal/mono/ospin_2.ogg and /dev/null differ
diff --git a/media/vocal/mono/ospin_3.ogg b/media/vocal/mono/ospin_3.ogg
deleted file mode 100644
index 185f43892..000000000
Binary files a/media/vocal/mono/ospin_3.ogg and /dev/null differ
diff --git a/media/vocal/mono/pentacrash_1.ogg b/media/vocal/mono/pentacrash_1.ogg
new file mode 100644
index 000000000..948aa8f5d
Binary files /dev/null and b/media/vocal/mono/pentacrash_1.ogg differ
diff --git a/media/vocal/mono/pentacrash_2.ogg b/media/vocal/mono/pentacrash_2.ogg
new file mode 100644
index 000000000..41db171f0
Binary files /dev/null and b/media/vocal/mono/pentacrash_2.ogg differ
diff --git a/media/vocal/mono/pentacrash_3.ogg b/media/vocal/mono/pentacrash_3.ogg
new file mode 100644
index 000000000..a41017d61
Binary files /dev/null and b/media/vocal/mono/pentacrash_3.ogg differ
diff --git a/media/vocal/mono/pentacrash_4.ogg b/media/vocal/mono/pentacrash_4.ogg
new file mode 100644
index 000000000..b79348f7e
Binary files /dev/null and b/media/vocal/mono/pentacrash_4.ogg differ
diff --git a/media/vocal/mono/perfect_clear.ogg b/media/vocal/mono/perfect_clear.ogg
deleted file mode 100644
index 9634a49f2..000000000
Binary files a/media/vocal/mono/perfect_clear.ogg and /dev/null differ
diff --git a/media/vocal/mono/perfect_clear_1.ogg b/media/vocal/mono/perfect_clear_1.ogg
new file mode 100644
index 000000000..7edf99d1b
Binary files /dev/null and b/media/vocal/mono/perfect_clear_1.ogg differ
diff --git a/media/vocal/mono/perfect_clear_2.ogg b/media/vocal/mono/perfect_clear_2.ogg
new file mode 100644
index 000000000..550726c97
Binary files /dev/null and b/media/vocal/mono/perfect_clear_2.ogg differ
diff --git a/media/vocal/mono/perfect_clear_3.ogg b/media/vocal/mono/perfect_clear_3.ogg
new file mode 100644
index 000000000..7ea10fcfc
Binary files /dev/null and b/media/vocal/mono/perfect_clear_3.ogg differ
diff --git a/media/vocal/mono/perfect_clear_4.ogg b/media/vocal/mono/perfect_clear_4.ogg
new file mode 100644
index 000000000..279d03801
Binary files /dev/null and b/media/vocal/mono/perfect_clear_4.ogg differ
diff --git a/media/vocal/mono/single_1.ogg b/media/vocal/mono/single_1.ogg
index 6591a2de1..83f3b062b 100644
Binary files a/media/vocal/mono/single_1.ogg and b/media/vocal/mono/single_1.ogg differ
diff --git a/media/vocal/mono/single_2.ogg b/media/vocal/mono/single_2.ogg
index 3e930847d..1c282225d 100644
Binary files a/media/vocal/mono/single_2.ogg and b/media/vocal/mono/single_2.ogg differ
diff --git a/media/vocal/mono/single_3.ogg b/media/vocal/mono/single_3.ogg
new file mode 100644
index 000000000..f5fafda9d
Binary files /dev/null and b/media/vocal/mono/single_3.ogg differ
diff --git a/media/vocal/mono/single_4.ogg b/media/vocal/mono/single_4.ogg
new file mode 100644
index 000000000..26a42b968
Binary files /dev/null and b/media/vocal/mono/single_4.ogg differ
diff --git a/media/vocal/mono/sspin.ogg b/media/vocal/mono/sspin.ogg
new file mode 100644
index 000000000..05569f799
Binary files /dev/null and b/media/vocal/mono/sspin.ogg differ
diff --git a/media/vocal/mono/sspin0.ogg b/media/vocal/mono/sspin0.ogg
new file mode 100644
index 000000000..c8ba8dc2e
Binary files /dev/null and b/media/vocal/mono/sspin0.ogg differ
diff --git a/media/vocal/mono/sspin_1.ogg b/media/vocal/mono/sspin_1.ogg
deleted file mode 100644
index 97ae12a9d..000000000
Binary files a/media/vocal/mono/sspin_1.ogg and /dev/null differ
diff --git a/media/vocal/mono/sspin_2.ogg b/media/vocal/mono/sspin_2.ogg
deleted file mode 100644
index 50b1f8bda..000000000
Binary files a/media/vocal/mono/sspin_2.ogg and /dev/null differ
diff --git a/media/vocal/mono/sspin_3.ogg b/media/vocal/mono/sspin_3.ogg
deleted file mode 100644
index e3c444236..000000000
Binary files a/media/vocal/mono/sspin_3.ogg and /dev/null differ
diff --git a/media/vocal/mono/techrash_1.ogg b/media/vocal/mono/techrash_1.ogg
index 77d1dbbde..181a350e4 100644
Binary files a/media/vocal/mono/techrash_1.ogg and b/media/vocal/mono/techrash_1.ogg differ
diff --git a/media/vocal/mono/techrash_2.ogg b/media/vocal/mono/techrash_2.ogg
index 4b9578377..06a44db02 100644
Binary files a/media/vocal/mono/techrash_2.ogg and b/media/vocal/mono/techrash_2.ogg differ
diff --git a/media/vocal/mono/techrash_3.ogg b/media/vocal/mono/techrash_3.ogg
new file mode 100644
index 000000000..11a699d4b
Binary files /dev/null and b/media/vocal/mono/techrash_3.ogg differ
diff --git a/media/vocal/mono/techrash_4.ogg b/media/vocal/mono/techrash_4.ogg
new file mode 100644
index 000000000..4491bb7d5
Binary files /dev/null and b/media/vocal/mono/techrash_4.ogg differ
diff --git a/media/vocal/mono/test_1.ogg b/media/vocal/mono/test_1.ogg
index ce261bdb8..78b66cb7e 100644
Binary files a/media/vocal/mono/test_1.ogg and b/media/vocal/mono/test_1.ogg differ
diff --git a/media/vocal/mono/test_2.ogg b/media/vocal/mono/test_2.ogg
index 4720a201f..3bc1f4f09 100644
Binary files a/media/vocal/mono/test_2.ogg and b/media/vocal/mono/test_2.ogg differ
diff --git a/media/vocal/mono/test_3.ogg b/media/vocal/mono/test_3.ogg
new file mode 100644
index 000000000..6cbbb6d11
Binary files /dev/null and b/media/vocal/mono/test_3.ogg differ
diff --git a/media/vocal/mono/test_4.ogg b/media/vocal/mono/test_4.ogg
new file mode 100644
index 000000000..71a95645a
Binary files /dev/null and b/media/vocal/mono/test_4.ogg differ
diff --git a/media/vocal/mono/triple.ogg b/media/vocal/mono/triple.ogg
deleted file mode 100644
index dade3b06e..000000000
Binary files a/media/vocal/mono/triple.ogg and /dev/null differ
diff --git a/media/vocal/mono/triple_1.ogg b/media/vocal/mono/triple_1.ogg
index 562475dc7..8eb3de1ca 100644
Binary files a/media/vocal/mono/triple_1.ogg and b/media/vocal/mono/triple_1.ogg differ
diff --git a/media/vocal/mono/triple_2.ogg b/media/vocal/mono/triple_2.ogg
new file mode 100644
index 000000000..11880edf7
Binary files /dev/null and b/media/vocal/mono/triple_2.ogg differ
diff --git a/media/vocal/mono/triple_3.ogg b/media/vocal/mono/triple_3.ogg
new file mode 100644
index 000000000..216786262
Binary files /dev/null and b/media/vocal/mono/triple_3.ogg differ
diff --git a/media/vocal/mono/triple_4.ogg b/media/vocal/mono/triple_4.ogg
new file mode 100644
index 000000000..d3af588bb
Binary files /dev/null and b/media/vocal/mono/triple_4.ogg differ
diff --git a/media/vocal/mono/tspin.ogg b/media/vocal/mono/tspin.ogg
new file mode 100644
index 000000000..8be45f917
Binary files /dev/null and b/media/vocal/mono/tspin.ogg differ
diff --git a/media/vocal/mono/tspin0.ogg b/media/vocal/mono/tspin0.ogg
new file mode 100644
index 000000000..dfc91b687
Binary files /dev/null and b/media/vocal/mono/tspin0.ogg differ
diff --git a/media/vocal/mono/tspin_1.ogg b/media/vocal/mono/tspin_1.ogg
deleted file mode 100644
index 1d2dc3abd..000000000
Binary files a/media/vocal/mono/tspin_1.ogg and /dev/null differ
diff --git a/media/vocal/mono/tspin_2.ogg b/media/vocal/mono/tspin_2.ogg
deleted file mode 100644
index a7fecadf8..000000000
Binary files a/media/vocal/mono/tspin_2.ogg and /dev/null differ
diff --git a/media/vocal/mono/tspin_3.ogg b/media/vocal/mono/tspin_3.ogg
deleted file mode 100644
index f0dad5a33..000000000
Binary files a/media/vocal/mono/tspin_3.ogg and /dev/null differ
diff --git a/media/vocal/mono/welcome_1.ogg b/media/vocal/mono/welcome_1.ogg
index d8f56e004..34008c076 100644
Binary files a/media/vocal/mono/welcome_1.ogg and b/media/vocal/mono/welcome_1.ogg differ
diff --git a/media/vocal/mono/welcome_2.ogg b/media/vocal/mono/welcome_2.ogg
index d7ba3b372..04b636e5a 100644
Binary files a/media/vocal/mono/welcome_2.ogg and b/media/vocal/mono/welcome_2.ogg differ
diff --git a/media/vocal/mono/welcome_3.ogg b/media/vocal/mono/welcome_3.ogg
index db690c620..97e1e500d 100644
Binary files a/media/vocal/mono/welcome_3.ogg and b/media/vocal/mono/welcome_3.ogg differ
diff --git a/media/vocal/mono/welcome_4.ogg b/media/vocal/mono/welcome_4.ogg
new file mode 100644
index 000000000..b6eeb8b0f
Binary files /dev/null and b/media/vocal/mono/welcome_4.ogg differ
diff --git a/media/vocal/mono/welcome_5.ogg b/media/vocal/mono/welcome_5.ogg
new file mode 100644
index 000000000..c88e9ae9a
Binary files /dev/null and b/media/vocal/mono/welcome_5.ogg differ
diff --git a/media/vocal/mono/win_1.ogg b/media/vocal/mono/win_1.ogg
index 1a733e9f2..dc4f023b0 100644
Binary files a/media/vocal/mono/win_1.ogg and b/media/vocal/mono/win_1.ogg differ
diff --git a/media/vocal/mono/win_2.ogg b/media/vocal/mono/win_2.ogg
index 94e80c8bf..bfab69057 100644
Binary files a/media/vocal/mono/win_2.ogg and b/media/vocal/mono/win_2.ogg differ
diff --git a/media/vocal/mono/win_3.ogg b/media/vocal/mono/win_3.ogg
index 04e8a1335..c159100a8 100644
Binary files a/media/vocal/mono/win_3.ogg and b/media/vocal/mono/win_3.ogg differ
diff --git a/media/vocal/mono/win_4.ogg b/media/vocal/mono/win_4.ogg
new file mode 100644
index 000000000..b49f3e755
Binary files /dev/null and b/media/vocal/mono/win_4.ogg differ
diff --git a/media/vocal/mono/win_5.ogg b/media/vocal/mono/win_5.ogg
new file mode 100644
index 000000000..dbfcb85ae
Binary files /dev/null and b/media/vocal/mono/win_5.ogg differ
diff --git a/media/vocal/mono/zspin.ogg b/media/vocal/mono/zspin.ogg
new file mode 100644
index 000000000..358de5c9e
Binary files /dev/null and b/media/vocal/mono/zspin.ogg differ
diff --git a/media/vocal/mono/zspin0.ogg b/media/vocal/mono/zspin0.ogg
new file mode 100644
index 000000000..46c2b96d7
Binary files /dev/null and b/media/vocal/mono/zspin0.ogg differ
diff --git a/media/vocal/mono/zspin_1.ogg b/media/vocal/mono/zspin_1.ogg
deleted file mode 100644
index 65508f39b..000000000
Binary files a/media/vocal/mono/zspin_1.ogg and /dev/null differ
diff --git a/media/vocal/mono/zspin_2.ogg b/media/vocal/mono/zspin_2.ogg
deleted file mode 100644
index a7b77163d..000000000
Binary files a/media/vocal/mono/zspin_2.ogg and /dev/null differ
diff --git a/media/vocal/mono/zspin_3.ogg b/media/vocal/mono/zspin_3.ogg
deleted file mode 100644
index 91c6157bb..000000000
Binary files a/media/vocal/mono/zspin_3.ogg and /dev/null differ
diff --git a/media/vocal/zundamon/air.ogg b/media/vocal/zundamon/air.ogg
new file mode 100644
index 000000000..b18c02649
Binary files /dev/null and b/media/vocal/zundamon/air.ogg differ
diff --git a/media/vocal/zundamon/b2b.ogg b/media/vocal/zundamon/b2b.ogg
new file mode 100644
index 000000000..608b25b2d
Binary files /dev/null and b/media/vocal/zundamon/b2b.ogg differ
diff --git a/media/vocal/zundamon/b3b.ogg b/media/vocal/zundamon/b3b.ogg
new file mode 100644
index 000000000..1b4f3c761
Binary files /dev/null and b/media/vocal/zundamon/b3b.ogg differ
diff --git a/media/vocal/zundamon/bye.ogg b/media/vocal/zundamon/bye.ogg
new file mode 100644
index 000000000..51b03349c
Binary files /dev/null and b/media/vocal/zundamon/bye.ogg differ
diff --git a/media/vocal/zundamon/color.ogg b/media/vocal/zundamon/color.ogg
new file mode 100644
index 000000000..983ff29f8
Binary files /dev/null and b/media/vocal/zundamon/color.ogg differ
diff --git a/media/vocal/zundamon/cspin.ogg b/media/vocal/zundamon/cspin.ogg
new file mode 100644
index 000000000..6e2dc58fa
Binary files /dev/null and b/media/vocal/zundamon/cspin.ogg differ
diff --git a/media/vocal/zundamon/cspin0.ogg b/media/vocal/zundamon/cspin0.ogg
new file mode 100644
index 000000000..e5c99caee
Binary files /dev/null and b/media/vocal/zundamon/cspin0.ogg differ
diff --git a/media/vocal/zundamon/decacrash.ogg b/media/vocal/zundamon/decacrash.ogg
new file mode 100644
index 000000000..902c1a7ef
Binary files /dev/null and b/media/vocal/zundamon/decacrash.ogg differ
diff --git a/media/vocal/zundamon/deep.ogg b/media/vocal/zundamon/deep.ogg
new file mode 100644
index 000000000..e447e63bc
Binary files /dev/null and b/media/vocal/zundamon/deep.ogg differ
diff --git a/media/vocal/zundamon/dodecacrash.ogg b/media/vocal/zundamon/dodecacrash.ogg
new file mode 100644
index 000000000..96664eede
Binary files /dev/null and b/media/vocal/zundamon/dodecacrash.ogg differ
diff --git a/media/vocal/zundamon/double.ogg b/media/vocal/zundamon/double.ogg
new file mode 100644
index 000000000..3cd5e9538
Binary files /dev/null and b/media/vocal/zundamon/double.ogg differ
diff --git a/media/vocal/zundamon/doubt.ogg b/media/vocal/zundamon/doubt.ogg
new file mode 100644
index 000000000..ce6664ed8
Binary files /dev/null and b/media/vocal/zundamon/doubt.ogg differ
diff --git a/media/vocal/zundamon/espin.ogg b/media/vocal/zundamon/espin.ogg
new file mode 100644
index 000000000..805d352ad
Binary files /dev/null and b/media/vocal/zundamon/espin.ogg differ
diff --git a/media/vocal/zundamon/espin0.ogg b/media/vocal/zundamon/espin0.ogg
new file mode 100644
index 000000000..14cceddc8
Binary files /dev/null and b/media/vocal/zundamon/espin0.ogg differ
diff --git a/media/vocal/zundamon/fspin.ogg b/media/vocal/zundamon/fspin.ogg
new file mode 100644
index 000000000..9cc49d3f4
Binary files /dev/null and b/media/vocal/zundamon/fspin.ogg differ
diff --git a/media/vocal/zundamon/fspin0.ogg b/media/vocal/zundamon/fspin0.ogg
new file mode 100644
index 000000000..891c4bca6
Binary files /dev/null and b/media/vocal/zundamon/fspin0.ogg differ
diff --git a/media/vocal/zundamon/half_clear_1.ogg b/media/vocal/zundamon/half_clear_1.ogg
new file mode 100644
index 000000000..39b15e2d2
Binary files /dev/null and b/media/vocal/zundamon/half_clear_1.ogg differ
diff --git a/media/vocal/zundamon/half_clear_2.ogg b/media/vocal/zundamon/half_clear_2.ogg
new file mode 100644
index 000000000..cd0a1932d
Binary files /dev/null and b/media/vocal/zundamon/half_clear_2.ogg differ
diff --git a/media/vocal/zundamon/happy.ogg b/media/vocal/zundamon/happy.ogg
new file mode 100644
index 000000000..5c472c13c
Binary files /dev/null and b/media/vocal/zundamon/happy.ogg differ
diff --git a/media/vocal/zundamon/heptacrash.ogg b/media/vocal/zundamon/heptacrash.ogg
new file mode 100644
index 000000000..75a059927
Binary files /dev/null and b/media/vocal/zundamon/heptacrash.ogg differ
diff --git a/media/vocal/zundamon/heptadecacrash.ogg b/media/vocal/zundamon/heptadecacrash.ogg
new file mode 100644
index 000000000..3a69ac96a
Binary files /dev/null and b/media/vocal/zundamon/heptadecacrash.ogg differ
diff --git a/media/vocal/zundamon/hexacrash.ogg b/media/vocal/zundamon/hexacrash.ogg
new file mode 100644
index 000000000..09d6bae8f
Binary files /dev/null and b/media/vocal/zundamon/hexacrash.ogg differ
diff --git a/media/vocal/zundamon/hexadecacrash.ogg b/media/vocal/zundamon/hexadecacrash.ogg
new file mode 100644
index 000000000..fcb30b0c5
Binary files /dev/null and b/media/vocal/zundamon/hexadecacrash.ogg differ
diff --git a/media/vocal/zundamon/hspin.ogg b/media/vocal/zundamon/hspin.ogg
new file mode 100644
index 000000000..2e8ba80e1
Binary files /dev/null and b/media/vocal/zundamon/hspin.ogg differ
diff --git a/media/vocal/zundamon/hspin0.ogg b/media/vocal/zundamon/hspin0.ogg
new file mode 100644
index 000000000..2bfbd5ba3
Binary files /dev/null and b/media/vocal/zundamon/hspin0.ogg differ
diff --git a/media/vocal/zundamon/impossicrash.ogg b/media/vocal/zundamon/impossicrash.ogg
new file mode 100644
index 000000000..6ad866ba1
Binary files /dev/null and b/media/vocal/zundamon/impossicrash.ogg differ
diff --git a/media/vocal/zundamon/ispin.ogg b/media/vocal/zundamon/ispin.ogg
new file mode 100644
index 000000000..41bba14e7
Binary files /dev/null and b/media/vocal/zundamon/ispin.ogg differ
diff --git a/media/vocal/zundamon/ispin0.ogg b/media/vocal/zundamon/ispin0.ogg
new file mode 100644
index 000000000..2d1c226d2
Binary files /dev/null and b/media/vocal/zundamon/ispin0.ogg differ
diff --git a/media/vocal/zundamon/jspin.ogg b/media/vocal/zundamon/jspin.ogg
new file mode 100644
index 000000000..02fad4414
Binary files /dev/null and b/media/vocal/zundamon/jspin.ogg differ
diff --git a/media/vocal/zundamon/jspin0.ogg b/media/vocal/zundamon/jspin0.ogg
new file mode 100644
index 000000000..31c238211
Binary files /dev/null and b/media/vocal/zundamon/jspin0.ogg differ
diff --git a/media/vocal/zundamon/lose_1.ogg b/media/vocal/zundamon/lose_1.ogg
new file mode 100644
index 000000000..e1a30e9e1
Binary files /dev/null and b/media/vocal/zundamon/lose_1.ogg differ
diff --git a/media/vocal/zundamon/lose_2.ogg b/media/vocal/zundamon/lose_2.ogg
new file mode 100644
index 000000000..a0b37f328
Binary files /dev/null and b/media/vocal/zundamon/lose_2.ogg differ
diff --git a/media/vocal/zundamon/lspin.ogg b/media/vocal/zundamon/lspin.ogg
new file mode 100644
index 000000000..3d25fe108
Binary files /dev/null and b/media/vocal/zundamon/lspin.ogg differ
diff --git a/media/vocal/zundamon/lspin0.ogg b/media/vocal/zundamon/lspin0.ogg
new file mode 100644
index 000000000..3c5caa617
Binary files /dev/null and b/media/vocal/zundamon/lspin0.ogg differ
diff --git a/media/vocal/zundamon/mini.ogg b/media/vocal/zundamon/mini.ogg
new file mode 100644
index 000000000..5218c0b71
Binary files /dev/null and b/media/vocal/zundamon/mini.ogg differ
diff --git a/media/vocal/zundamon/mis.ogg b/media/vocal/zundamon/mis.ogg
new file mode 100644
index 000000000..df2b82915
Binary files /dev/null and b/media/vocal/zundamon/mis.ogg differ
diff --git a/media/vocal/zundamon/nonacrash.ogg b/media/vocal/zundamon/nonacrash.ogg
new file mode 100644
index 000000000..90decaf84
Binary files /dev/null and b/media/vocal/zundamon/nonacrash.ogg differ
diff --git a/media/vocal/zundamon/nonadecacrash.ogg b/media/vocal/zundamon/nonadecacrash.ogg
new file mode 100644
index 000000000..a46c8aa69
Binary files /dev/null and b/media/vocal/zundamon/nonadecacrash.ogg differ
diff --git a/media/vocal/zundamon/nspin.ogg b/media/vocal/zundamon/nspin.ogg
new file mode 100644
index 000000000..8b6dc63e1
Binary files /dev/null and b/media/vocal/zundamon/nspin.ogg differ
diff --git a/media/vocal/zundamon/nspin0.ogg b/media/vocal/zundamon/nspin0.ogg
new file mode 100644
index 000000000..2f84118c3
Binary files /dev/null and b/media/vocal/zundamon/nspin0.ogg differ
diff --git a/media/vocal/zundamon/octacrash.ogg b/media/vocal/zundamon/octacrash.ogg
new file mode 100644
index 000000000..1b458d28f
Binary files /dev/null and b/media/vocal/zundamon/octacrash.ogg differ
diff --git a/media/vocal/zundamon/octadecacrash.ogg b/media/vocal/zundamon/octadecacrash.ogg
new file mode 100644
index 000000000..31aa8d461
Binary files /dev/null and b/media/vocal/zundamon/octadecacrash.ogg differ
diff --git a/media/vocal/zundamon/ospin.ogg b/media/vocal/zundamon/ospin.ogg
new file mode 100644
index 000000000..21354bf81
Binary files /dev/null and b/media/vocal/zundamon/ospin.ogg differ
diff --git a/media/vocal/zundamon/ospin0.ogg b/media/vocal/zundamon/ospin0.ogg
new file mode 100644
index 000000000..8166b62fb
Binary files /dev/null and b/media/vocal/zundamon/ospin0.ogg differ
diff --git a/media/vocal/zundamon/pentacrash.ogg b/media/vocal/zundamon/pentacrash.ogg
new file mode 100644
index 000000000..7aadf737e
Binary files /dev/null and b/media/vocal/zundamon/pentacrash.ogg differ
diff --git a/media/vocal/zundamon/pentadecacrash.ogg b/media/vocal/zundamon/pentadecacrash.ogg
new file mode 100644
index 000000000..3c1f0b791
Binary files /dev/null and b/media/vocal/zundamon/pentadecacrash.ogg differ
diff --git a/media/vocal/zundamon/perfect_clear_1.ogg b/media/vocal/zundamon/perfect_clear_1.ogg
new file mode 100644
index 000000000..e5bfd37dc
Binary files /dev/null and b/media/vocal/zundamon/perfect_clear_1.ogg differ
diff --git a/media/vocal/zundamon/perfect_clear_2.ogg b/media/vocal/zundamon/perfect_clear_2.ogg
new file mode 100644
index 000000000..f2ba74878
Binary files /dev/null and b/media/vocal/zundamon/perfect_clear_2.ogg differ
diff --git a/media/vocal/zundamon/pspin.ogg b/media/vocal/zundamon/pspin.ogg
new file mode 100644
index 000000000..8e376b55c
Binary files /dev/null and b/media/vocal/zundamon/pspin.ogg differ
diff --git a/media/vocal/zundamon/pspin0.ogg b/media/vocal/zundamon/pspin0.ogg
new file mode 100644
index 000000000..d7d604f1d
Binary files /dev/null and b/media/vocal/zundamon/pspin0.ogg differ
diff --git a/media/vocal/zundamon/qspin.ogg b/media/vocal/zundamon/qspin.ogg
new file mode 100644
index 000000000..ee668e195
Binary files /dev/null and b/media/vocal/zundamon/qspin.ogg differ
diff --git a/media/vocal/zundamon/qspin0.ogg b/media/vocal/zundamon/qspin0.ogg
new file mode 100644
index 000000000..092a2bb0d
Binary files /dev/null and b/media/vocal/zundamon/qspin0.ogg differ
diff --git a/media/vocal/zundamon/rspin.ogg b/media/vocal/zundamon/rspin.ogg
new file mode 100644
index 000000000..59692ec68
Binary files /dev/null and b/media/vocal/zundamon/rspin.ogg differ
diff --git a/media/vocal/zundamon/rspin0.ogg b/media/vocal/zundamon/rspin0.ogg
new file mode 100644
index 000000000..3ead7c168
Binary files /dev/null and b/media/vocal/zundamon/rspin0.ogg differ
diff --git a/media/vocal/zundamon/single.ogg b/media/vocal/zundamon/single.ogg
new file mode 100644
index 000000000..ca8823617
Binary files /dev/null and b/media/vocal/zundamon/single.ogg differ
diff --git a/media/vocal/zundamon/split.ogg b/media/vocal/zundamon/split.ogg
new file mode 100644
index 000000000..03a9aa954
Binary files /dev/null and b/media/vocal/zundamon/split.ogg differ
diff --git a/media/vocal/zundamon/sspin.ogg b/media/vocal/zundamon/sspin.ogg
new file mode 100644
index 000000000..020a63471
Binary files /dev/null and b/media/vocal/zundamon/sspin.ogg differ
diff --git a/media/vocal/zundamon/sspin0.ogg b/media/vocal/zundamon/sspin0.ogg
new file mode 100644
index 000000000..04507c6c4
Binary files /dev/null and b/media/vocal/zundamon/sspin0.ogg differ
diff --git a/media/vocal/zundamon/techrash.ogg b/media/vocal/zundamon/techrash.ogg
new file mode 100644
index 000000000..7610bded0
Binary files /dev/null and b/media/vocal/zundamon/techrash.ogg differ
diff --git a/media/vocal/zundamon/test.ogg b/media/vocal/zundamon/test.ogg
new file mode 100644
index 000000000..f1a028460
Binary files /dev/null and b/media/vocal/zundamon/test.ogg differ
diff --git a/media/vocal/zundamon/tetradecacrash.ogg b/media/vocal/zundamon/tetradecacrash.ogg
new file mode 100644
index 000000000..20fe2a690
Binary files /dev/null and b/media/vocal/zundamon/tetradecacrash.ogg differ
diff --git a/media/vocal/zundamon/tridecacrash.ogg b/media/vocal/zundamon/tridecacrash.ogg
new file mode 100644
index 000000000..779e35ec4
Binary files /dev/null and b/media/vocal/zundamon/tridecacrash.ogg differ
diff --git a/media/vocal/zundamon/triple.ogg b/media/vocal/zundamon/triple.ogg
new file mode 100644
index 000000000..97e0c0c8a
Binary files /dev/null and b/media/vocal/zundamon/triple.ogg differ
diff --git a/media/vocal/zundamon/tspin.ogg b/media/vocal/zundamon/tspin.ogg
new file mode 100644
index 000000000..c2fed4e45
Binary files /dev/null and b/media/vocal/zundamon/tspin.ogg differ
diff --git a/media/vocal/zundamon/tspin0.ogg b/media/vocal/zundamon/tspin0.ogg
new file mode 100644
index 000000000..7ffede935
Binary files /dev/null and b/media/vocal/zundamon/tspin0.ogg differ
diff --git a/media/vocal/zundamon/ultracrash.ogg b/media/vocal/zundamon/ultracrash.ogg
new file mode 100644
index 000000000..a4aaf7e58
Binary files /dev/null and b/media/vocal/zundamon/ultracrash.ogg differ
diff --git a/media/vocal/zundamon/undecacrash.ogg b/media/vocal/zundamon/undecacrash.ogg
new file mode 100644
index 000000000..d2bf95040
Binary files /dev/null and b/media/vocal/zundamon/undecacrash.ogg differ
diff --git a/media/vocal/zundamon/uspin.ogg b/media/vocal/zundamon/uspin.ogg
new file mode 100644
index 000000000..4e06a7c62
Binary files /dev/null and b/media/vocal/zundamon/uspin.ogg differ
diff --git a/media/vocal/zundamon/uspin0.ogg b/media/vocal/zundamon/uspin0.ogg
new file mode 100644
index 000000000..d9795ba87
Binary files /dev/null and b/media/vocal/zundamon/uspin0.ogg differ
diff --git a/media/vocal/zundamon/vspin.ogg b/media/vocal/zundamon/vspin.ogg
new file mode 100644
index 000000000..00de8914a
Binary files /dev/null and b/media/vocal/zundamon/vspin.ogg differ
diff --git a/media/vocal/zundamon/vspin0.ogg b/media/vocal/zundamon/vspin0.ogg
new file mode 100644
index 000000000..04f8be13a
Binary files /dev/null and b/media/vocal/zundamon/vspin0.ogg differ
diff --git a/media/vocal/zundamon/welcome_1.ogg b/media/vocal/zundamon/welcome_1.ogg
new file mode 100644
index 000000000..4dec925e3
Binary files /dev/null and b/media/vocal/zundamon/welcome_1.ogg differ
diff --git a/media/vocal/zundamon/welcome_2.ogg b/media/vocal/zundamon/welcome_2.ogg
new file mode 100644
index 000000000..06005923c
Binary files /dev/null and b/media/vocal/zundamon/welcome_2.ogg differ
diff --git a/media/vocal/zundamon/win_1.ogg b/media/vocal/zundamon/win_1.ogg
new file mode 100644
index 000000000..a675f27e5
Binary files /dev/null and b/media/vocal/zundamon/win_1.ogg differ
diff --git a/media/vocal/zundamon/win_2.ogg b/media/vocal/zundamon/win_2.ogg
new file mode 100644
index 000000000..4b7cb0f7d
Binary files /dev/null and b/media/vocal/zundamon/win_2.ogg differ
diff --git a/media/vocal/zundamon/wspin.ogg b/media/vocal/zundamon/wspin.ogg
new file mode 100644
index 000000000..8812ccd10
Binary files /dev/null and b/media/vocal/zundamon/wspin.ogg differ
diff --git a/media/vocal/zundamon/wspin0.ogg b/media/vocal/zundamon/wspin0.ogg
new file mode 100644
index 000000000..656c51ccc
Binary files /dev/null and b/media/vocal/zundamon/wspin0.ogg differ
diff --git a/media/vocal/zundamon/xspin.ogg b/media/vocal/zundamon/xspin.ogg
new file mode 100644
index 000000000..fdfc779d2
Binary files /dev/null and b/media/vocal/zundamon/xspin.ogg differ
diff --git a/media/vocal/zundamon/xspin0.ogg b/media/vocal/zundamon/xspin0.ogg
new file mode 100644
index 000000000..3314cb452
Binary files /dev/null and b/media/vocal/zundamon/xspin0.ogg differ
diff --git a/media/vocal/zundamon/yspin.ogg b/media/vocal/zundamon/yspin.ogg
new file mode 100644
index 000000000..da2e0ae54
Binary files /dev/null and b/media/vocal/zundamon/yspin.ogg differ
diff --git a/media/vocal/zundamon/yspin0.ogg b/media/vocal/zundamon/yspin0.ogg
new file mode 100644
index 000000000..4362b18e8
Binary files /dev/null and b/media/vocal/zundamon/yspin0.ogg differ
diff --git a/media/vocal/zundamon/zspin.ogg b/media/vocal/zundamon/zspin.ogg
new file mode 100644
index 000000000..5dc2ecbc7
Binary files /dev/null and b/media/vocal/zundamon/zspin.ogg differ
diff --git a/media/vocal/zundamon/zspin0.ogg b/media/vocal/zundamon/zspin0.ogg
new file mode 100644
index 000000000..543951dde
Binary files /dev/null and b/media/vocal/zundamon/zspin0.ogg differ
diff --git a/parts/RSlist.lua b/parts/RSlist.lua
index 661adcfa1..1da080033 100644
--- a/parts/RSlist.lua
+++ b/parts/RSlist.lua
@@ -1,43 +1,43 @@
-local defaultCenterTex=GC.DO{1,1}--No texture
-local defaultCenterPos={--For SRS-like RSs
- --Tetromino
- {[0]={0,1},{1,0},{1,1},{1,1}},--Z
- {[0]={0,1},{1,0},{1,1},{1,1}},--S
- {[0]={0,1},{1,0},{1,1},{1,1}},--J
- {[0]={0,1},{1,0},{1,1},{1,1}},--L
- {[0]={0,1},{1,0},{1,1},{1,1}},--T
- {[0]={.5,.5},{.5,.5},{.5,.5},{.5,.5}},--O
- {[0]={-.5,1.5},{1.5,-.5},{.5,1.5},{1.5,.5}},--I
+local defaultCenterTex=GC.DO{1,1}-- No texture
+local defaultCenterPos={-- For SRS-like RSs
+ -- Tetromino
+ {[0]={0,1},{1,0},{1,1},{1,1}},-- Z
+ {[0]={0,1},{1,0},{1,1},{1,1}},-- S
+ {[0]={0,1},{1,0},{1,1},{1,1}},-- J
+ {[0]={0,1},{1,0},{1,1},{1,1}},-- L
+ {[0]={0,1},{1,0},{1,1},{1,1}},-- T
+ {[0]={.5,.5},{.5,.5},{.5,.5},{.5,.5}},-- O
+ {[0]={-.5,1.5},{1.5,-.5},{.5,1.5},{1.5,.5}},-- I
- --Pentomino
- {[0]={1,1},{1,1},{1,1},{1,1}},--Z5
- {[0]={1,1},{1,1},{1,1},{1,1}},--S5
- {[0]={0,1},{1,0},{1,1},{1,1}},--P
- {[0]={0,1},{1,0},{1,1},{1,1}},--Q
- {[0]={1,1},{1,1},{1,1},{1,1}},--F
- {[0]={1,1},{1,1},{1,1},{1,1}},--E
- {[0]={1,1},{1,1},{1,1},{1,1}},--T5
- {[0]={0,1},{1,0},{1,1},{1,1}},--U
- {[0]={.5,1.5},{.5,.5},{1.5,.5},{1.5,1.5}},--V
- {[0]={1,1},{1,1},{1,1},{1,1}},--W
- {[0]={1,1},{1,1},{1,1},{1,1}},--X
- {[0]={.5,1.5},{1.5,.5},{.5,1.5},{1.5,.5}},--J5
- {[0]={.5,1.5},{1.5,.5},{.5,1.5},{1.5,.5}},--L5
- {[0]={.5,1.5},{1.5,.5},{.5,1.5},{1.5,.5}},--R
- {[0]={.5,1.5},{1.5,.5},{.5,1.5},{1.5,.5}},--Y
- {[0]={.5,1.5},{1.5,.5},{.5,1.5},{1.5,.5}},--N
- {[0]={.5,1.5},{1.5,.5},{.5,1.5},{1.5,.5}},--H
- {[0]={0,2},{2,0},{0,2},{2,0}},--I5
+ -- Pentomino
+ {[0]={1,1},{1,1},{1,1},{1,1}},-- Z5
+ {[0]={1,1},{1,1},{1,1},{1,1}},-- S5
+ {[0]={0,1},{1,0},{1,1},{1,1}},-- P
+ {[0]={0,1},{1,0},{1,1},{1,1}},-- Q
+ {[0]={1,1},{1,1},{1,1},{1,1}},-- F
+ {[0]={1,1},{1,1},{1,1},{1,1}},-- E
+ {[0]={1,1},{1,1},{1,1},{1,1}},-- T5
+ {[0]={0,1},{1,0},{1,1},{1,1}},-- U
+ {[0]={.5,1.5},{.5,.5},{1.5,.5},{1.5,1.5}},-- V
+ {[0]={1,1},{1,1},{1,1},{1,1}},-- W
+ {[0]={1,1},{1,1},{1,1},{1,1}},-- X
+ {[0]={.5,1.5},{1.5,.5},{.5,1.5},{1.5,.5}},-- J5
+ {[0]={.5,1.5},{1.5,.5},{.5,1.5},{1.5,.5}},-- L5
+ {[0]={.5,1.5},{1.5,.5},{.5,1.5},{1.5,.5}},-- R
+ {[0]={.5,1.5},{1.5,.5},{.5,1.5},{1.5,.5}},-- Y
+ {[0]={.5,1.5},{1.5,.5},{.5,1.5},{1.5,.5}},-- N
+ {[0]={.5,1.5},{1.5,.5},{.5,1.5},{1.5,.5}},-- H
+ {[0]={0,2},{2,0},{0,2},{2,0}},-- I5
- --Trimino
- {[0]={0,1},{1,0},{0,1},{1,0}},--I3
- {[0]={.5,.5},{.5,.5},{.5,.5},{.5,.5}},--C
+ -- Trimino
+ {[0]={0,1},{1,0},{0,1},{1,0}},-- I3
+ {[0]={.5,.5},{.5,.5},{.5,.5},{.5,.5}},-- C
- --Domino
- {[0]={-.5,.5},{.5,-.5},{.5,.5},{.5,.5}},--I2
+ -- Domino
+ {[0]={-.5,.5},{.5,-.5},{.5,.5},{.5,.5}},-- I2
- --Dot
- {[0]={0,0},{0,0},{0,0},{0,0}},--O1
+ -- Dot
+ {[0]={0,0},{0,0},{0,0},{0,0}},-- O1
}
local noKickSet,noKickSet_180 do
@@ -52,14 +52,14 @@ local function _strToVec(list)
return list
end
---Use this if the block is centrosymmetry, *PTR!!!
+-- Use this if the block is centrosymmetry, *PTR!!!
local function _centroSymSet(L)
L[23]=L[01]L[32]=L[10]
L[21]=L[03]L[12]=L[30]
L[20]=L[02]L[31]=L[13]
end
---Use this to copy a symmetry set
+-- Use this to copy a symmetry set
local function _flipList(O)
if not O then
return
@@ -72,7 +72,7 @@ local function _flipList(O)
end
local function _reflect(a)
- return{
+ return {
[03]=_flipList(a[01]),
[01]=_flipList(a[03]),
[30]=_flipList(a[10]),
@@ -91,21 +91,21 @@ end
local TRS
do
local OspinList={
- {111,5,2, 0,-1,0},{111,5,2,-1,-1,0},{111,5,0,-1, 0,0},--T
- {333,5,2,-1,-1,0},{333,5,2, 0,-1,0},{333,5,0, 0, 0,0},--T
- {313,1,2,-1, 0,0},{313,1,2, 0,-1,0},{313,1,2, 0, 0,0},--Z
- {131,2,2, 0, 0,0},{131,2,2,-1,-1,0},{131,2,2,-1, 0,0},--S
- {131,1,2,-1, 0,0},{131,1,2, 0,-1,0},{131,1,2, 0, 0,0},--Z(misOrder)
- {313,2,2, 0, 0,0},{313,2,2,-1,-1,0},{313,2,2,-1, 0,0},--S(misOrder)
- {331,3,2, 0,-1,1},--J(farDown)
- {113,4,2,-1,-1,1},--L(farDown)
- {113,3,2,-1,-1,0},{113,3,0, 0, 0,0},--J
- {331,4,2, 0,-1,0},{331,4,0,-1, 0,0},--L
- {222,7,0,-1, 1,1},{222,7,0,-2, 1,1},{222,7,0, 0, 1,1},--I(high)
- {222,7,2,-1, 0,2},{222,7,2,-2, 0,2},{222,7,2, 0, 0,2},--I(low)
- {121,6,0, 1,-1,2},{112,6,0, 2,-1,2},{122,6,0, 1,-2,2},--O
- {323,6,0,-1,-1,2},{332,6,0,-2,-1,2},{322,6,0,-1,-2,2},--O
- }--{keys, ID, dir, dx, dy, freeLevel (0=immovable, 1=U/D-immovable, 2=free)}
+ {111,5,2, 0,-1,0},{111,5,2,-1,-1,0},{111,5,0,-1, 0,0},-- T
+ {333,5,2,-1,-1,0},{333,5,2, 0,-1,0},{333,5,0, 0, 0,0},-- T
+ {313,1,2,-1, 0,0},{313,1,2, 0,-1,0},{313,1,2, 0, 0,0},-- Z
+ {131,2,2, 0, 0,0},{131,2,2,-1,-1,0},{131,2,2,-1, 0,0},-- S
+ {131,1,2,-1, 0,0},{131,1,2, 0,-1,0},{131,1,2, 0, 0,0},-- Z(misOrder)
+ {313,2,2, 0, 0,0},{313,2,2,-1,-1,0},{313,2,2,-1, 0,0},-- S(misOrder)
+ {331,3,2, 0,-1,0},-- J(farDown)
+ {113,4,2,-1,-1,0},-- L(farDown)
+ {113,3,2,-1,-1,0},{113,3,0, 0, 0,0},-- J
+ {331,4,2, 0,-1,0},{331,4,0,-1, 0,0},-- L
+ {222,7,0,-1, 1,1},{222,7,0,-2, 1,1},{222,7,0, 0, 1,1},-- I(high)
+ {222,7,2,-1, 0,2},{222,7,2,-2, 0,2},{222,7,2, 0, 0,2},-- I(low)
+ {121,6,0, 1,-1,2},{112,6,0, 2,-1,2},{122,6,0, 1,-2,2},-- O
+ {323,6,0,-1,-1,2},{332,6,0,-2,-1,2},{322,6,0,-1,-2,2},-- O
+ }-- {keys, ID, dir, dx, dy, freeLevel (0=immovable, 1=U/D-immovable, 2=free)}
local XspinList={
{{ 1,-1},{ 1, 0},{ 1, 1},{ 1,-2},{ 1, 2}},
{{ 0,-1},{ 0,-2},{ 0, 1},{ 0,-2},{ 0, 2}},
@@ -126,7 +126,7 @@ do
kickTable={
{
[01]={'+0+0','-1+0','-1+1','+0-2','-1+2','+0+1'},
- [10]={'+0+0','+1+0','+1-1','+0+2','+1-2','+1-2'},
+ [10]={'+0+0','+1+0','+1-1','+0+2','+1-2','+0-1'},
[03]={'+0+0','+1+0','+1+1','+0-2','+1-1','+1-2'},
[30]={'+0+0','-1+0','-1-1','+0+2','-1+2','+0-1'},
[12]={'+0+0','+1+0','+1-1','+0+2','+1+2','+1+1'},
@@ -137,8 +137,8 @@ do
[20]={'+0+0','-1+0','+1+0','+0+1','+0-1'},
[13]={'+0+0','+0-1','+0+1','+0-2'},
[31]={'+0+0','+0+1','+0-1','+0+2'},
- },--Z
- false,--S
+ },-- Z
+ false,-- S
{
[01]={'+0+0','-1+0','-1+1','+0-2','+1+1','+0+1','+0-1'},
[10]={'+0+0','+1+0','+1-1','+0+2','-1-1','+0-1','+0+1'},
@@ -152,22 +152,22 @@ do
[20]={'+0+0','+1+0','-1+0','+0+1','+0-1'},
[13]={'+0+0','+0-1','+0+1','+1+0'},
[31]={'+0+0','+0+1','+0-1','-1+0'},
- },--J
- false,--L
+ },-- J
+ false,-- L
{
[01]={'+0+0','-1+0','-1+1','+0-2','-1-2','+0+1'},
- [10]={'+0+0','+1+0','+1-1','+0+2','+1+2','+0-1'},
+ [10]={'+0+0','+1+0','+1-1','+0+2','+1+2','+0+1','+0-1'},
[03]={'+0+0','+1+0','+1+1','+0-2','+1-2','+0+1'},
- [30]={'+0+0','-1+0','-1-1','+0+2','-1+2','+0-1'},
+ [30]={'+0+0','-1+0','-1-1','+0+2','-1+2','+0+1','+0-1'},
[12]={'+0+0','+1+0','+1-1','+0-1','-1-1','+0+2','+1+2','+1+1'},
- [21]={'+0+0','-1+0','+0-2','-1-2','-1-1','+1+1'},
+ [21]={'+0+0','-1+0','+0-2','-1-2','-1-1','+0-1','+1+1'},
[32]={'+0+0','-1+0','-1-1','+0-1','+1-1','+0+2','-1+2','-1+1'},
- [23]={'+0+0','+1+0','+0-2','+1-2','+1-1','-1+1'},
+ [23]={'+0+0','+1+0','+0-2','+1-2','+1-1','+0-1','-1+1'},
[02]={'+0+0','-1+0','+1+0','+0+1'},
[20]={'+0+0','+1+0','-1+0','+0-1'},
[13]={'+0+0','+0-1','+0+1','+1+0','+0-2','+0+2'},
[31]={'+0+0','+0-1','+0+1','-1+0','+0-2','+0+2'},
- },--T
+ },-- T
function(P,d)
if P.gameEnv.easyFresh then
P:freshBlock('fresh')
@@ -175,7 +175,7 @@ do
if P.gameEnv.ospin then
local x,y=P.curX,P.curY
local C=P.cur
- if y==P.ghoY and((P:solid(x-1,y)or P:solid(x-1,y+1)))and(P:solid(x+2,y)or P:solid(x+2,y+1))then
+ if y==P.ghoY and ((P:solid(x-1,y) or P:solid(x-1,y+1))) and (P:solid(x+2,y) or P:solid(x+2,y+1)) then
if P.sound then
SFX.play('rotatekick',nil,P:getCenterX()*.15)
end
@@ -186,15 +186,15 @@ do
return end
for i=1,#OspinList do
local L=OspinList[i]
- if C.spinSeq==L[1]then
+ if C.spinSeq==L[1] then
local id,dir=L[2],L[3]
local bk=BLOCKS[id][dir]
x,y=P.curX+L[4],P.curY+L[5]
if
- not P:ifoverlap(bk,x,y)and(
- L[6]>0 or(P:ifoverlap(bk,x-1,y)and P:ifoverlap(bk,x+1,y))
- )and(
- L[6]==2 or(P:ifoverlap(bk,x,y-1)and P:ifoverlap(bk,x,y+1))
+ not P:ifoverlap(bk,x,y) and (
+ L[6]>0 or (P:ifoverlap(bk,x-1,y) and P:ifoverlap(bk,x+1,y))
+ ) and (
+ L[6]==2 or (P:ifoverlap(bk,x,y-1) and P:ifoverlap(bk,x,y+1))
)
then
C.id=id
@@ -220,7 +220,7 @@ do
SFX.play('rotate',nil,P:getCenterX()*.15)
end
end
- end,--O
+ end,-- O
{
[01]={'+0+0','+0+1','+1+0','-2+0','-2-1','+1+2'},
[10]={'+0+0','+2+0','-1+0','-1-2','+2+1','+0+1'},
@@ -234,14 +234,14 @@ do
[20]={'+0+0','+1+0','-1+0','+0+1','+0-1'},
[13]={'+0+0','+0-1','-1+0','+1+0','+0+1'},
[31]={'+0+0','+0-1','+1+0','-1+0','+0+1'},
- },--I
+ },-- I
{
[01]={'+0+0','+0+1','+1+1','-1+0','+0-3','+0+2','+0-2','+0+3','-1+2'},
[10]={'+0+0','+0-1','-1-1','+1+0','+0-3','+0+2','+0-2','+0+3','+1-2'},
[03]={'+0+0','+1+0','+0-3','+0-1','+0+1','+0-2','+0+2','+0+3','+1+2'},
[30]={'+0+0','-1+0','+0-1','+0+1','+0-2','+0-3','+0+2','+0+3','-1-2'},
- },--Z5
- false,--S5
+ },-- Z5
+ false,-- S5
{
[01]={'+0+0','-1+0','-1+1','+0-2','-1-2','-1-1','+0+1'},
[10]={'+0+0','+1+0','+1-1','+0+2','+1+2','+0-1','+1+1'},
@@ -255,8 +255,8 @@ do
[20]={'+0+0','+1+0','+0+1','+0-1'},
[13]={'+0+0','+1+0','+0+1','-1+0'},
[31]={'+0+0','-1+0','+0-1','+1+0'},
- },--P
- false,--Q
+ },-- P
+ false,-- Q
{
[01]={'+0+0','-1+0','+1+0','-1+1','+0-2','+0-3'},
[10]={'+0+0','+1+0','+1-1','-1+0','+0+2','+0+3'},
@@ -270,8 +270,8 @@ do
[20]={'+0+0','-1+0','+1+0','+1+1'},
[13]={'+0+0','+0-1','-1+1','+0+1'},
[31]={'+0+0','+0-1','+1-1','+0+1'},
- },--F
- false,--E
+ },-- F
+ false,-- E
{
[01]={'+0+0','+0-1','-1-1','+1+0','+1+1','+0-3','-1+0','+0+2','-1+2'},
[10]={'+0+0','+1+0','+0-1','-1-1','+0-2','-1+1','+0-3','+1-2','+0+1'},
@@ -285,7 +285,7 @@ do
[20]={'+0+0','+0-1','+0+1','+0-2'},
[13]={'+0+0','+1+0','-1+1','-2+0'},
[31]={'+0+0','-1+0','+1+1','+2+0'},
- },--T5
+ },-- T5
{
[01]={'+0+0','-1+0','-1+1','+0-2','-1-2'},
[10]={'+0+0','+1+0','+1-1','+0+2','+1+2'},
@@ -299,21 +299,21 @@ do
[20]={'+0+0','+0-1'},
[13]={'+0+0','+0-1','+0+1','+1+0'},
[31]={'+0+0','+0-1','+0+1','-1+0'},
- },--U
+ },-- U
{
[01]={'+0+0','+0+1','-1+0','+0-2','-1-2'},
[10]={'+0+0','+0+1','+1+0','+0-2','+1-2'},
[03]={'+0+0','+0-1','+0+1','+0+2'},
[30]={'+0+0','+0-1','+0+1','+0-2'},
[12]={'+0+0','+0-1','+0+1','+0+2'},
- [21]={'+0+0','+0-1','+0-2','+0-2'},
+ [21]={'+0+0','+0-1','+0+1','+0-2'},
[32]={'+0+0','+1+0','-1+0'},
[23]={'+0+0','-1+0','+1+0'},
[02]={'+0+0','-1+1','+1-1'},
[20]={'+0+0','+1-1','-1+1'},
[13]={'+0+0','+1+1','-1-1'},
[31]={'+0+0','-1-1','+1+1'},
- },--V
+ },-- V
{
[01]={'+0+0','+0-1','-1+0','+1+0','+1-1','+0+2'},
[10]={'+0+0','+0-1','-1-1','+0+1','+0-2','+1-2','+0+2'},
@@ -327,15 +327,15 @@ do
[20]={'+0+0','+0+1','+1+0'},
[13]={'+0+0','+0+1','-1+0'},
[31]={'+0+0','+0-1','+1+0'},
- },--W
+ },-- W
function(P,d)
- if P.type=='human'then
+ if P.type=='human' then
SFX.play('rotate',nil,P:getCenterX()*.15)
end
local kickData=XspinList[d]
for test=1,#kickData do
local x,y=P.curX+kickData[test][1],P.curY+kickData[test][2]
- if not P:ifoverlap(P.cur.bk,x,y)then
+ if not P:ifoverlap(P.cur.bk,x,y) then
P.curX,P.curY=x,y
P.spinLast=1
P:freshBlock('move')
@@ -344,7 +344,7 @@ do
end
end
P:freshBlock('fresh')
- end,--X
+ end,-- X
{
[01]={'+0+0','-1+0','-1+1','+0-3','-1+1','-1+2','+0+1'},
[10]={'+0+0','-1+0','+1-1','+0+3','+1-1','+1-2','+0+1'},
@@ -358,8 +358,8 @@ do
[20]={'+0+0','+0+1','+1+1','-1+1','+1+0','-2+1'},
[13]={'+0+0','-1+0','-1-1','+0+1','-1-2'},
[31]={'+0+0','+1+0','+1+1','+0-1','+1+2'},
- },--J5
- false,--L5
+ },-- J5
+ false,-- L5
{
[01]={'+0+0','-1+0','-1+1','+1+0','-1+2','-1-1','+0-3','+0+1'},
[10]={'+0+0','-1+0','+1+0','+1-1','+1-2','+1+1','+0+3','+0+1'},
@@ -373,8 +373,8 @@ do
[20]={'+0+0','+0+1','-1+1','+1+0','-2+1','+0-1'},
[13]={'+0+0','-1+0','-1-1','+0+1','-1-2'},
[31]={'+0+0','+1+0','+1+1','+0-1','+1+2'},
- },--R
- false,--Y
+ },-- R
+ false,-- Y
{
[01]={'+0+0','-1+0','-1+1','+0+1','+1+0','+1+1','-1+2','-2+0','+0-2'},
[10]={'+0+0','+1+0','-1+0','+0-1','-1-1','+1-1','+1-2','+2+0','+0+2'},
@@ -388,20 +388,20 @@ do
[20]={'+0+0','+1+0','+0-2','+0+1'},
[13]={'+0+0','-1+0','-1-1','+0+1','+1+2'},
[31]={'+0+0','+1+0','+1+1','+0-1','-1-2'},
- },--N
- false,--H
+ },-- N
+ false,-- H
{
[01]={'+0+0','+1-1','+1+0','+1+1','+0+1','-1+1','-1+0','-1-1','+0-1','+0-2','-2-1','-2-2','+2+0','+2-1','+2-2','+1+2','+2+2','-1+2','-2+2'},
[10]={'+0+0','-1+0','-1-1','+0-1','+1-1','-2-2','-2-1','-2+0','-1-2','+0-2','+1-2','+2-2','-1+1','-2+1','-2+2','+1+0','+2+0','+2-1','+0+1','+1-1','+2-2'},
- [03]={'+0+0','-1-1','-1+0','-1+1','-0+1','+1+1','+1+0','+1-1','-0-1','-0-2','+2-1','+2-2','-2+0','-2-1','-2-2','-1+2','-2+2','+1+2','+2+2'},
- [30]={'+0+0','+1+0','+1-1','-0-1','-1-1','+2-2','+2-1','+2+0','+1-2','-0-2','-1-2','-2-2','+1+1','+2+1','+2+2','-1+0','-2+0','-2-1','+0+1','-1-1','-2-2'},
- },--I5
+ [03]={'+0+0','-1-1','-1+0','-1+1','+0+1','+1+1','+1+0','+1-1','+0-1','+0-2','+2-1','+2-2','-2+0','-2-1','-2-2','-1+2','-2+2','+1+2','+2+2'},
+ [30]={'+0+0','+1+0','+1-1','+0-1','-1-1','+2-2','+2-1','+2+0','+1-2','+0-2','-1-2','-2-2','+1+1','+2+1','+2+2','-1+0','-2+0','-2-1','+0+1','-1-1','-2-2'},
+ },-- I5
{
[01]={'+0+0','-1+0','-1-1','+1+1','-1+1'},
[10]={'+0+0','-1+0','+1+0','-1-1','+1+1'},
[03]={'+0+0','+1+0','+1-1','-1+1','+1+1'},
[30]={'+0+0','+1+0','-1+0','+1-1','-1+1'},
- },--I3
+ },-- I3
{
[01]={'+0+0','-1+0','+1+0'},
[10]={'+0+0','+1+0','-1+0'},
@@ -415,7 +415,7 @@ do
[20]={'+0+0','+0+1','-1+1','+1+1'},
[13]={'+0+0','+0-1','-1-1','+1-1'},
[31]={'+0+0','+0+1','+1+1','-1+1'},
- },--C
+ },-- C
{
[01]={'+0+0','-1+0','+0+1'},
[10]={'+0+0','+1+0','+0+1'},
@@ -429,22 +429,22 @@ do
[20]={'+0+0','+0+1','+0-1'},
[13]={'+0+0','-1+0','+1+0'},
[31]={'+0+0','+1+0','-1+0'},
- },--I2
- nil,--O1
+ },-- I2
+ nil,-- O1
}
}
TRS.centerDisp[6]=false
TRS.centerDisp[18]=false
- TRS.kickTable[2]= _reflect(TRS.kickTable[1])--SZ
- TRS.kickTable[4]= _reflect(TRS.kickTable[3])--LJ
- TRS.kickTable[9]= _reflect(TRS.kickTable[8])--S5Z5
- TRS.kickTable[11]=_reflect(TRS.kickTable[10])--PQ
- TRS.kickTable[13]=_reflect(TRS.kickTable[12])--FE
- TRS.kickTable[20]=_reflect(TRS.kickTable[19])--L5J5
- TRS.kickTable[22]=_reflect(TRS.kickTable[21])--RY
- TRS.kickTable[24]=_reflect(TRS.kickTable[23])--NH
- _centroSymSet(TRS.kickTable[8])_centroSymSet(TRS.kickTable[9])--S5Z5
- _centroSymSet(TRS.kickTable[25])_centroSymSet(TRS.kickTable[26])--I5I3
+ TRS.kickTable[2]= _reflect(TRS.kickTable[1])-- SZ
+ TRS.kickTable[4]= _reflect(TRS.kickTable[3])-- LJ
+ TRS.kickTable[9]= _reflect(TRS.kickTable[8])-- S5Z5
+ TRS.kickTable[11]=_reflect(TRS.kickTable[10])-- PQ
+ TRS.kickTable[13]=_reflect(TRS.kickTable[12])-- FE
+ TRS.kickTable[20]=_reflect(TRS.kickTable[19])-- L5J5
+ TRS.kickTable[22]=_reflect(TRS.kickTable[21])-- RY
+ TRS.kickTable[24]=_reflect(TRS.kickTable[23])-- NH
+ _centroSymSet(TRS.kickTable[8])_centroSymSet(TRS.kickTable[9])-- S5Z5
+ _centroSymSet(TRS.kickTable[25])_centroSymSet(TRS.kickTable[26])-- I5I3
end
local SRS
@@ -469,12 +469,12 @@ do
[32]={'+0+0','-1+0','-1-1','+0+2','-1+2'},
[23]={'+0+0','+1+0','+1+1','+0-2','+1-2'},
[02]={'+0+0'},[20]={'+0+0'},[13]={'+0+0'},[31]={'+0+0'},
- },--Z
- false,--S
- false,--J
- false,--L
- false,--T
- noKickSet,--O
+ },-- Z
+ false,-- S
+ false,-- J
+ false,-- L
+ false,-- T
+ noKickSet,-- O
{
[01]={'+0+0','-2+0','+1+0','-2-1','+1+2'},
[10]={'+0+0','+2+0','-1+0','+2+1','-1-2'},
@@ -485,11 +485,11 @@ do
[30]={'+0+0','+1+0','-2+0','+1-2','-2+1'},
[03]={'+0+0','-1+0','+2+0','-1+2','+2-1'},
[02]={'+0+0'},[20]={'+0+0'},[13]={'+0+0'},[31]={'+0+0'},
- }--I
+ }-- I
}
}
- for i=2,5 do SRS.kickTable[i]=SRS.kickTable[1]end
- for i=8,29 do SRS.kickTable[i]=SRS.kickTable[1]end
+ for i=2,5 do SRS.kickTable[i]=SRS.kickTable[1] end
+ for i=8,29 do SRS.kickTable[i]=SRS.kickTable[1] end
end
local SRS_plus
@@ -519,30 +519,30 @@ do
[20]={'+0+0','+1+0','-1+0','+0-1','+0+1'},
[13]={'+0+0','+0-1','-1+0','+1+0','+0+1'},
[31]={'+0+0','+0-1','-1+0','+1+0','+0+1'},
- },--Z
- false,--S
- false,--J
- false,--L
- false,--T
- noKickSet,--O
+ },-- Z
+ false,-- S
+ false,-- J
+ false,-- L
+ false,-- T
+ noKickSet,-- O
{
- [01]={'+0+0','-2+0','+1+0','-2-1','+1+2'},
- [10]={'+0+0','+2+0','-1+0','+2+1','-1-2'},
+ [01]={'+0+0','+1+0','-2+0','+1+2','-2-1'},
+ [10]={'+0+0','-1+0','+2+0','-1-2','+2+1'},
+ [03]={'+0+0','-1+0','+2+0','-1+2','+2-1'},
+ [30]={'+0+0','+1+0','-2+0','+1-2','-2+1'},
[12]={'+0+0','-1+0','+2+0','-1+2','+2-1'},
[21]={'+0+0','+1+0','-2+0','+1-2','-2+1'},
- [23]={'+0+0','+2+0','-1+0','+2+1','-1-2'},
- [32]={'+0+0','-2+0','+1+0','-2-1','+1+2'},
- [30]={'+0+0','+1+0','-2+0','+1-2','-2+1'},
- [03]={'+0+0','-1+0','+2+0','-1+2','+2-1'},
+ [32]={'+0+0','+1+0','-2+0','+1+2','-2-1'},
+ [23]={'+0+0','-1+0','+2+0','-1-2','+2+1'},
[02]={'+0+0','-1+0','+1+0','+0-1','+0+1'},
[20]={'+0+0','+1+0','-1+0','+0+1','+0-1'},
[13]={'+0+0','+0-1','-1+0','+1+0','+0+1'},
[31]={'+0+0','+0-1','+1+0','-1+0','+0+1'},
- }--I
+ }-- I
}
}
- for i=2,5 do SRS_plus.kickTable[i]=SRS_plus.kickTable[1]end
- for i=8,29 do SRS_plus.kickTable[i]=SRS_plus.kickTable[1]end
+ for i=2,5 do SRS_plus.kickTable[i]=SRS_plus.kickTable[1] end
+ for i=8,29 do SRS_plus.kickTable[i]=SRS_plus.kickTable[1] end
end
local SRS_X
@@ -570,19 +570,19 @@ do
[20]={'+0+0','+1+0','-1+0','+0-1','+0+1'},
[13]={'+0+0','+0-1','-1+0','+1+0','+0+1'},
[31]={'+0+0','+0-1','-1+0','+1+0','+0+1'},
- },--Z
- false,--S
- false,--J
- false,--L
- false,--T
- noKickSet,--O
- false,--I
+ },-- Z
+ false,-- S
+ false,-- J
+ false,-- L
+ false,-- T
+ noKickSet,-- O
+ false,-- I
}
}
- for i=2,5 do SRS_X.kickTable[i]=SRS_X.kickTable[1]end
- for i=7,29 do SRS_X.kickTable[i]=TRS.kickTable[i]end
- SRS_X.kickTable[10]=SRS_X.kickTable[1]--P
- SRS_X.kickTable[11]=SRS_X.kickTable[1]--Q
+ for i=2,5 do SRS_X.kickTable[i]=SRS_X.kickTable[1] end
+ for i=7,29 do SRS_X.kickTable[i]=TRS.kickTable[i] end
+ SRS_X.kickTable[10]=SRS_X.kickTable[1]-- P
+ SRS_X.kickTable[11]=SRS_X.kickTable[1]-- Q
end
local BiRS
@@ -591,45 +591,45 @@ do
local L=_strToVec{'+0+0','+1+0','+1-1','+0-1','+1+1','-1-1','-1+0','+0+1','-1+1','+0+2','+1+2','-1+2','+2+0','-2+0'}
local F=_strToVec{'+0+0','+0-1','+0+1','+0+2'}
local list={
- {[02]=L,[20]=R,[13]=R,[31]=L},--Z
- {[02]=R,[20]=L,[13]=L,[31]=R},--S
- {[02]=L,[20]=R,[13]=L,[31]=R},--J
- {[02]=R,[20]=L,[13]=L,[31]=R},--L
- {[02]=F,[20]=F,[13]=L,[31]=R},--T
- {[02]=F,[20]=F,[13]=F,[31]=F},--O
- {[02]=F,[20]=F,[13]=R,[31]=L},--I
+ {[02]=L,[20]=R,[13]=R,[31]=L},-- Z
+ {[02]=R,[20]=L,[13]=L,[31]=R},-- S
+ {[02]=L,[20]=R,[13]=L,[31]=R},-- J
+ {[02]=R,[20]=L,[13]=L,[31]=R},-- L
+ {[02]=F,[20]=F,[13]=L,[31]=R},-- T
+ {[02]=F,[20]=F,[13]=F,[31]=F},-- O
+ {[02]=F,[20]=F,[13]=R,[31]=L},-- I
- {[02]=L,[20]=L,[13]=R,[31]=R},--Z5
- {[02]=R,[20]=R,[13]=L,[31]=L},--S5
- {[02]=L,[20]=R,[13]=L,[31]=R},--P
- {[02]=R,[20]=L,[13]=R,[31]=L},--Q
- {[02]=R,[20]=L,[13]=L,[31]=R},--F
- {[02]=L,[20]=R,[13]=R,[31]=L},--E
- {[02]=F,[20]=F,[13]=L,[31]=R},--T5
- {[02]=F,[20]=F,[13]=L,[31]=R},--U
- {[02]=R,[20]=L,[13]=L,[31]=R},--V
- {[02]=R,[20]=L,[13]=L,[31]=R},--W
- {[02]=F,[20]=F,[13]=F,[31]=F},--X
- {[02]=L,[20]=R,[13]=R,[31]=L},--J5
- {[02]=R,[20]=L,[13]=L,[31]=R},--L5
- {[02]=L,[20]=R,[13]=R,[31]=L},--R
- {[02]=R,[20]=L,[13]=L,[31]=R},--Y
- {[02]=L,[20]=R,[13]=R,[31]=L},--N
- {[02]=R,[20]=L,[13]=L,[31]=R},--H
- {[02]=F,[20]=F,[13]=F,[31]=F},--I5
+ {[02]=L,[20]=L,[13]=R,[31]=R},-- Z5
+ {[02]=R,[20]=R,[13]=L,[31]=L},-- S5
+ {[02]=L,[20]=R,[13]=L,[31]=R},-- P
+ {[02]=R,[20]=L,[13]=R,[31]=L},-- Q
+ {[02]=R,[20]=L,[13]=L,[31]=R},-- F
+ {[02]=L,[20]=R,[13]=R,[31]=L},-- E
+ {[02]=F,[20]=F,[13]=L,[31]=R},-- T5
+ {[02]=F,[20]=F,[13]=L,[31]=R},-- U
+ {[02]=R,[20]=L,[13]=L,[31]=R},-- V
+ {[02]=R,[20]=L,[13]=L,[31]=R},-- W
+ {[02]=F,[20]=F,[13]=F,[31]=F},-- X
+ {[02]=L,[20]=R,[13]=R,[31]=L},-- J5
+ {[02]=R,[20]=L,[13]=L,[31]=R},-- L5
+ {[02]=L,[20]=R,[13]=R,[31]=L},-- R
+ {[02]=R,[20]=L,[13]=L,[31]=R},-- Y
+ {[02]=L,[20]=R,[13]=R,[31]=L},-- N
+ {[02]=R,[20]=L,[13]=L,[31]=R},-- H
+ {[02]=F,[20]=F,[13]=F,[31]=F},-- I5
- {[02]=F,[20]=F,[13]=F,[31]=F},--I3
- {[02]=R,[20]=L,[13]=L,[31]=R},--C
- {[02]=F,[20]=F,[13]=R,[31]=L},--I2
- {[02]=F,[20]=F,[13]=F,[31]=F},--O1
+ {[02]=F,[20]=F,[13]=F,[31]=F},-- I3
+ {[02]=R,[20]=L,[13]=L,[31]=R},-- C
+ {[02]=F,[20]=F,[13]=R,[31]=L},-- I2
+ {[02]=F,[20]=F,[13]=F,[31]=F},-- O1
}
for i=1,29 do
local a,b=R,L
if i==6 or i==18 then
a,b=b,a
end
- list[i][01]=a;list[i][10]=b;list[i][03]=b;list[i][30]=a
- list[i][12]=a;list[i][21]=b;list[i][32]=b;list[i][23]=a
+ list[i][01]=a; list[i][10]=b; list[i][03]=b; list[i][30]=a
+ list[i][12]=a; list[i][21]=b; list[i][32]=b; list[i][23]=a
end
BiRS={
centerTex=GC.DO{10,10,
@@ -653,9 +653,9 @@ do
end
local dx,dy=0,0 do
local pressing=P.keyPressing
- if pressing[1]and P:ifoverlap(C.bk,P.curX-1,P.curY)then dx=dx-1 end
- if pressing[2]and P:ifoverlap(C.bk,P.curX+1,P.curY)then dx=dx+1 end
- if pressing[7]and P:ifoverlap(C.bk,P.curX,P.curY-1)then dy= -1 end
+ if pressing[1] and P:ifoverlap(C.bk,P.curX-1,P.curY) then dx=dx-1 end
+ if pressing[2] and P:ifoverlap(C.bk,P.curX+1,P.curY) then dx=dx+1 end
+ if pressing[7] and P:ifoverlap(C.bk,P.curX,P.curY-1) then dy= -1 end
end
while true do
for test=1,#kickList do
@@ -666,7 +666,7 @@ do
(P.freshTime>0 or fdy<=0)
then
local x,y=ix+fdx,iy+fdy
- if not P:ifoverlap(icb,x,y)then
+ if not P:ifoverlap(icb,x,y) then
if P.gameEnv.moveFX and P.gameEnv.block then
P:createMoveFX()
end
@@ -685,7 +685,7 @@ do
local sfx
if ifpre then
sfx='prerotate'
- elseif P:ifoverlap(icb,x,y+1)and P:ifoverlap(icb,x-1,y)and P:ifoverlap(icb,x+1,y)then
+ elseif P:ifoverlap(icb,x,y+1) and P:ifoverlap(icb,x-1,y) and P:ifoverlap(icb,x+1,y) then
sfx='rotatekick'
P:_rotateField(d)
else
@@ -700,7 +700,7 @@ do
end
end
- --Try release left/right, then softdrop, failed to rotate otherwise
+ -- Try release left/right, then softdrop, failed to rotate otherwise
if dx~=0 then
dx=0
elseif dy~=0 then
@@ -728,24 +728,24 @@ do
[02]=upOnly,[20]=upOnly,[13]=upOnly,[31]=upOnly,
}
local centerPos=TABLE.copy(defaultCenterPos)
- centerPos[1]={[0]={1,1},{1,0},{1,1},{1,0}}--Z
- centerPos[2]={[0]={1,1},{1,1},{1,1},{1,1}}--S
- centerPos[3]={[0]={1,1},{1,0},{1,1},{1,1}}--L
- centerPos[4]={[0]={1,1},{1,0},{1,1},{1,1}}--J
- centerPos[5]={[0]={1,1},{1,0},{1,1},{1,1}}--T
- centerPos[7]={[0]={0,2},{2,0},{0,2},{2,0}}--I
- centerPos[10]={[0]={1,1},{1,0},{1,1},{1,0}}--P
- centerPos[11]={[0]={1,1},{1,1},{1,1},{1,1}}--Q
- centerPos[15]={[0]={1,1},{1,0},{1,1},{1,1}}--U
- centerPos[16]={[0]={1,1},{1,1},{1,1},{1,1}}--V
- centerPos[19]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}--J5
- centerPos[20]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}--L5
- centerPos[21]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}--R
- centerPos[22]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}--Y
- centerPos[23]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}--N
- centerPos[24]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}--H
- centerPos[26]={[0]={0,1},{0,0},{0,1},{0,0}}--I3
- centerPos[28]={[0]={0,1},{0,0},{0,1},{0,0}}--I2
+ centerPos[1]={[0]={1,1},{1,0},{1,1},{1,0}}-- Z
+ centerPos[2]={[0]={1,1},{1,1},{1,1},{1,1}}-- S
+ centerPos[3]={[0]={1,1},{1,0},{1,1},{1,1}}-- L
+ centerPos[4]={[0]={1,1},{1,0},{1,1},{1,1}}-- J
+ centerPos[5]={[0]={1,1},{1,0},{1,1},{1,1}}-- T
+ centerPos[7]={[0]={0,2},{2,0},{0,2},{2,0}}-- I
+ centerPos[10]={[0]={1,1},{1,0},{1,1},{1,0}}-- P
+ centerPos[11]={[0]={1,1},{1,1},{1,1},{1,1}}-- Q
+ centerPos[15]={[0]={1,1},{1,0},{1,1},{1,1}}-- U
+ centerPos[16]={[0]={1,1},{1,1},{1,1},{1,1}}-- V
+ centerPos[19]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}-- J5
+ centerPos[20]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}-- L5
+ centerPos[21]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}-- R
+ centerPos[22]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}-- Y
+ centerPos[23]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}-- N
+ centerPos[24]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}-- H
+ centerPos[26]={[0]={0,1},{0,0},{0,1},{0,0}}-- I3
+ centerPos[28]={[0]={0,1},{0,0},{0,1},{0,0}}-- I2
ARS_Z={
centerTex=GC.DO{10,10,
@@ -765,24 +765,24 @@ end
local DRS_weak
do
local centerPos=TABLE.copy(defaultCenterPos)
- centerPos[1]={[0]={1,1},{1,0},{1,1},{1,1}}--Z
- centerPos[2]={[0]={1,1},{1,0},{1,1},{1,1}}--S
- centerPos[3]={[0]={1,1},{1,0},{1,1},{1,1}}--L
- centerPos[4]={[0]={1,1},{1,0},{1,1},{1,1}}--J
- centerPos[5]={[0]={1,1},{1,0},{1,1},{1,1}}--T
- centerPos[7]={[0]={.5,1.5},{1.5,-.5},{.5,1.5},{1.5,.5}}--I
- centerPos[10]={[0]={1,1},{1,0},{1,1},{1,0}}--P
- centerPos[11]={[0]={1,1},{1,1},{1,1},{1,1}}--Q
- centerPos[15]={[0]={1,1},{1,0},{1,1},{1,1}}--U
- centerPos[16]={[0]={1,1},{1,1},{1,1},{1,1}}--V
- centerPos[19]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}--J5
- centerPos[20]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}--L5
- centerPos[21]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}--R
- centerPos[22]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}--Y
- centerPos[23]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}--N
- centerPos[24]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}--H
- centerPos[26]={[0]={0,1},{0,0},{0,1},{0,0}}--I3
- centerPos[28]={[0]={0,1},{0,0},{0,1},{0,0}}--I2
+ centerPos[1]={[0]={1,1},{1,0},{1,1},{1,1}}-- Z
+ centerPos[2]={[0]={1,1},{1,0},{1,1},{1,1}}-- S
+ centerPos[3]={[0]={1,1},{1,0},{1,1},{1,1}}-- L
+ centerPos[4]={[0]={1,1},{1,0},{1,1},{1,1}}-- J
+ centerPos[5]={[0]={1,1},{1,0},{1,1},{1,1}}-- T
+ centerPos[7]={[0]={.5,1.5},{1.5,-.5},{.5,1.5},{1.5,.5}}-- I
+ centerPos[10]={[0]={1,1},{1,0},{1,1},{1,0}}-- P
+ centerPos[11]={[0]={1,1},{1,1},{1,1},{1,1}}-- Q
+ centerPos[15]={[0]={1,1},{1,0},{1,1},{1,1}}-- U
+ centerPos[16]={[0]={1,1},{1,1},{1,1},{1,1}}-- V
+ centerPos[19]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}-- J5
+ centerPos[20]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}-- L5
+ centerPos[21]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}-- R
+ centerPos[22]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}-- Y
+ centerPos[23]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}-- N
+ centerPos[24]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}-- H
+ centerPos[26]={[0]={0,1},{0,0},{0,1},{0,0}}-- I3
+ centerPos[28]={[0]={0,1},{0,0},{0,1},{0,0}}-- I2
local L={'+0+0','-1+0','+1+0','+0-1','-1-1','+1-1'}
local R={'+0+0','+1+0','-1+0','+0-1','+1-1','-1-1'}
@@ -802,24 +802,24 @@ do
},
centerPos=centerPos,
kickTable={
- Z,S,--Z,S
- Z,S,--J,L
- Z,--T
- noKickSet,--O
- Z,--I
+ Z,S,-- Z,S
+ Z,S,-- J,L
+ Z,-- T
+ noKickSet,-- O
+ Z,-- I
- Z,S,--Z5,S5
- Z,S,--P,Q
- Z,S,--F,E
- Z,Z,Z,Z,--T5,U,V,W
- noKickSet,--X
- Z,S,--J5,L5
- Z,S,--R,Y
- Z,S,--N,H
- Z,--I5
+ Z,S,-- Z5,S5
+ Z,S,-- P,Q
+ Z,S,-- F,E
+ Z,Z,Z,Z,-- T5,U,V,W
+ noKickSet,-- X
+ Z,S,-- J5,L5
+ Z,S,-- R,Y
+ Z,S,-- N,H
+ Z,-- I5
- Z,Z,--I3,C
- Z,Z,--I2,O1
+ Z,Z,-- I3,C
+ Z,Z,-- I2,O1
}
}
end
@@ -830,8 +830,19 @@ do
local R=_flipList(L)
local F={'+0+0'}
local centerPos=TABLE.copy(defaultCenterPos)
- centerPos[6]={[0]={0,0},{1,0},{1,1},{0,1}}
- centerPos[7]={[0]={0,1},{2,0},{0,2},{1,0}}
+ centerPos[6]={[0]={0,0},{1,0},{1,1},{0,1}}-- O
+ centerPos[7]={[0]={0,1},{2,0},{0,2},{1,0}}-- I
+ centerPos[14]={[0]={0,1},{1,0},{2,1},{1,2}}-- T5
+ centerPos[16]={[0]={1,1},{1,1},{1,1},{1,1}}-- V
+ centerPos[19]={[0]={0,1},{2,0},{1,2},{1,1}}-- J5
+ centerPos[20]={[0]={0,2},{1,0},{1,1},{2,1}}-- L5
+ centerPos[21]={[0]={0,2},{1,0},{1,1},{2,1}}-- R
+ centerPos[22]={[0]={0,1},{2,0},{1,2},{1,1}}-- Y
+ centerPos[23]={[0]={0,1},{2,0},{1,2},{1,1}}-- N
+ centerPos[24]={[0]={0,2},{1,0},{1,1},{2,1}}-- H
+ centerPos[27]={[0]={0,1},{0,0},{1,0},{1,1}}-- C
+ centerPos[28]={[0]={0,1},{0,0},{0,0},{1,0}}-- I2
+
ASC={
centerTex=GC.DO{10,10,
{'setLW',2},
@@ -857,7 +868,7 @@ do
local L={'+0+0','+1+0','+0-1','+1-1','+0-2','+1-2','+2+0','+2-1','+2-2','-1+0','-1-1','+0+1','+1+1','+2+1','-1-2','-2+0','+0+2','+1+2','+2+2','-2-1','-2-2'}
local R=_flipList(L)
local F={'+0+0','-1+0','+1+0','+0-1','-1-1','+1-1','+0-2','-1-2','+1-2','-2+0','+2+0','-2-1','+2-1','-2+1','+2+1','+0+2','-1+2','+1+2'}
- local centerPos=TABLE.copy(defaultCenterPos)
+ local centerPos=TABLE.copy(ASC.centerPos)
centerPos[6]={[0]={0,0},{1,0},{1,1},{0,1}}
centerPos[7]={[0]={0,1},{2,0},{0,2},{1,0}}
ASC_plus={
@@ -916,28 +927,62 @@ do
{'fRect',3,3,4,4},
},
kickTable={
- Z,S,--Z,S
- Z,S,--J,L
- Z,--T
- noKickSet,--O
- Z,--I
+ Z,S,-- Z,S
+ Z,S,-- J,L
+ Z,-- T
+ noKickSet,-- O
+ Z,-- I
- Z,S,--Z5,S5
- Z,S,--P,Q
- Z,S,--F,E
- Z,Z,Z,Z,--T5,U,V,W
- noKickSet,--X
- Z,S,--J5,L5
- Z,S,--R,Y
- Z,S,--N,H
- Z,--I5
+ Z,S,-- Z5,S5
+ Z,S,-- P,Q
+ Z,S,-- F,E
+ Z,Z,Z,Z,-- T5,U,V,W
+ noKickSet,-- X
+ Z,S,-- J5,L5
+ Z,S,-- R,Y
+ Z,S,-- N,H
+ Z,-- I5
- Z,Z,--I3,C
- Z,Z,--I2,O1
+ Z,Z,-- I3,C
+ Z,Z,-- I2,O1
}
}
end
+local N64
+do
+ local R={'+0+0','+0-1','+1+0','-1+0','+0+1'}
+ local L={'+0+0','+0-1','-1+0','+1+0','+0+1'}
+ N64={
+ centerTex=GC.DO{10,10,
+ {'setLW',2},
+ {'line',2,9,2,1,8,9,8,1},
+ },
+ kickTable=TABLE.new({
+ [01]=R,[10]=L,[12]=R,[21]=L,
+ [23]=R,[32]=L,[30]=R,[03]=L,
+ },29)
+ }
+end
+
+local N64_plus
+do
+ local R={'+0+0','+0-1','+1+0','-1+0','+0+1'}
+ local L={'+0+0','+0-1','-1+0','+1+0','+0+1'}
+ local F={'+0+0','+0-1','+0+1'}
+ N64_plus={
+ centerTex=GC.DO{10,10,
+ {'setLW',2},
+ {'line',4,9,2,9,2,1,8,9,8,1,6,1},
+ },
+ kickTable=TABLE.new({
+ [01]=R,[10]=L,[12]=R,[21]=L,
+ [23]=R,[32]=L,[30]=R,[03]=L,
+ [02]=F,[20]=F,[13]=F,[31]=F,
+ },29)
+ }
+end
+
local Classic do
local centerPos=TABLE.copy(defaultCenterPos)
centerPos[1]={[0]={1,1},{1,0},{1,1},{1,0}}
@@ -978,7 +1023,7 @@ local None={
{'setLW',2},
{'line',2,2,6,6},
},
- kickTable=TABLE.new(noKickSet_180,29)
+ kickTable=TABLE.new(noKickSet,29)
}
local None_plus={
@@ -987,7 +1032,7 @@ local None_plus={
{'line',1,1,7,7},
{'fRect',2,2,4,4},
},
- kickTable=TABLE.new(noKickSet,29)
+ kickTable=TABLE.new(noKickSet_180,29)
}
local RSlist={
@@ -1002,6 +1047,8 @@ local RSlist={
ASC_plus=ASC_plus,
C2=C2,
C2_sym=C2_sym,
+ N64=N64,
+ N64_plus=N64_plus,
Classic=Classic,
Classic_plus=Classic_plus,
None=None,
@@ -1009,15 +1056,15 @@ local RSlist={
}
for _,rs in next,RSlist do
- if not rs.centerDisp then rs.centerDisp=TABLE.new(true,29)end
+ if not rs.centerDisp then rs.centerDisp=TABLE.new(true,29) end
if not rs.centerPos then rs.centerPos=defaultCenterPos end
if not rs.centerTex then rs.centerTex=defaultCenterTex end
- --Make all string vec to the same table vec
+ -- Make all string vec to the same table vec
for _,set in next,rs.kickTable do
- if type(set)=='table'then
+ if type(set)=='table' then
for _,list in next,set do
- if type(list[1])=='string'then
+ if type(list[1])=='string' then
_strToVec(list)
end
end
diff --git a/parts/backgrounds/aura.lua b/parts/backgrounds/aura.lua
index 3927c8b29..eaea505a6 100644
--- a/parts/backgrounds/aura.lua
+++ b/parts/backgrounds/aura.lua
@@ -1,25 +1,19 @@
---Cool liquid background
-local gc=love.graphics
+-- Cool liquid background
local back={}
local shader=SHADER.aura
local t
function back.init()
t=math.random()*2600
- BG.resize(SCR.w,SCR.h)
-end
-function back.resize(_,h)
- shader:send('w',SCR.W)
- shader:send('h',h*SCR.dpi)
end
function back.update(dt)
- t=t+dt
+ t=(t+dt)%6200
end
function back.draw()
- gc.clear(.08,.08,.084)
- shader:send('t',t)
- gc.setShader(shader)
- gc.rectangle('fill',0,0,SCR.w,SCR.h)
- gc.setShader()
+ GC.clear(.08,.08,.084)
+ shader:send('phase',t)
+ GC.setShader(shader)
+ GC.rectangle('fill',0,0,SCR.w,SCR.h)
+ GC.setShader()
end
return back
diff --git a/parts/backgrounds/bg1.lua b/parts/backgrounds/bg1.lua
index a08ce3039..a5bb9f42c 100644
--- a/parts/backgrounds/bg1.lua
+++ b/parts/backgrounds/bg1.lua
@@ -1,24 +1,19 @@
---Horizonal red-blue gradient
-local gc=love.graphics
+-- Horizonal red-blue gradient
local back={}
local shader=SHADER.grad1
local t
function back.init()
t=math.random()*2600
- back.resize()
-end
-function back.resize()
- shader:send('w',SCR.W)
end
function back.update(dt)
- t=t+dt
+ t=(t+dt)%6200
end
function back.draw()
- gc.clear(.08,.08,.084)
- shader:send('t',t)
- gc.setShader(shader)
- gc.rectangle('fill',0,0,SCR.w,SCR.h)
- gc.setShader()
+ GC.clear(.08,.08,.084)
+ shader:send('phase',t)
+ GC.setShader(shader)
+ GC.rectangle('fill',0,0,SCR.w,SCR.h)
+ GC.setShader()
end
return back
diff --git a/parts/backgrounds/bg2.lua b/parts/backgrounds/bg2.lua
index 7a2952a12..b7af6541c 100644
--- a/parts/backgrounds/bg2.lua
+++ b/parts/backgrounds/bg2.lua
@@ -1,24 +1,19 @@
---Vertical red-green gradient
-local gc=love.graphics
+-- Vertical red-green gradient
local back={}
local shader=SHADER.grad2
local t
function back.init()
t=math.random()*2600
- BG.resize(nil,SCR.h)
-end
-function back.resize(_,h)
- shader:send('h',h*SCR.dpi)
end
function back.update(dt)
- t=t+dt
+ t=(t+dt)%6200
end
function back.draw()
- gc.clear(.08,.08,.084)
- shader:send('t',t)
- gc.setShader(shader)
- gc.rectangle('fill',0,0,SCR.w,SCR.h)
- gc.setShader()
+ GC.clear(.08,.08,.084)
+ shader:send('phase',t)
+ GC.setShader(shader)
+ GC.rectangle('fill',0,0,SCR.w,SCR.h)
+ GC.setShader()
end
return back
diff --git a/parts/backgrounds/blockfall.lua b/parts/backgrounds/blockfall.lua
index 4ecb0a74f..bce4c32b1 100644
--- a/parts/backgrounds/blockfall.lua
+++ b/parts/backgrounds/blockfall.lua
@@ -1,4 +1,4 @@
---Large falling tetrominoes
+-- Large falling tetrominoes
local gc=love.graphics
local gc_clear=gc.clear
local gc_setColor,gc_draw=gc.setColor,gc.draw
@@ -43,8 +43,8 @@ function back.draw()
local M=mino[i]
local b=M.block
for y=1,#b do
- for x=1,#b[1]do
- if b[y][x]then
+ for x=1,#b[1] do
+ if b[y][x] then
gc_draw(M.texture,M.x+(x-1)*30*M.k,M.y-y*30*M.k,nil,M.k)
end
end
diff --git a/parts/backgrounds/blockhole.lua b/parts/backgrounds/blockhole.lua
index 8f14f2ac2..f759b5182 100644
--- a/parts/backgrounds/blockhole.lua
+++ b/parts/backgrounds/blockhole.lua
@@ -1,4 +1,4 @@
---blockhole
+-- blockhole
local gc=love.graphics
local gc_clear,gc_replaceTransform=gc.clear,gc.replaceTransform
local gc_setColor,gc_setLineWidth=gc.setColor,gc.setLineWidth
@@ -44,14 +44,14 @@ function back.draw()
gc_clear(.1,.1,.1)
gc_replaceTransform(SCR.xOy_m)
- --Squares
+ -- Squares
gc_setColor(1,1,1,.2)
for i=1,#squares do
local S=squares[i]
gc_draw(S.texture,S.d*cos(S.ang),S.d*sin(S.ang),S.rotate,S.size*.026,nil,15,15)
end
- --blockhole
+ -- blockhole
gc_setColor(.07,.07,.07)
gc_circle('fill',0,0,157)
gc_setLineWidth(6)
diff --git a/parts/backgrounds/blockrain.lua b/parts/backgrounds/blockrain.lua
index c26abcb49..fc2eba5a8 100644
--- a/parts/backgrounds/blockrain.lua
+++ b/parts/backgrounds/blockrain.lua
@@ -1,4 +1,4 @@
---Block rain
+-- Block rain
local gc=love.graphics
local rnd=math.random
local ins,rem=table.insert,table.remove
@@ -20,7 +20,7 @@ function back.update()
color=BLOCK_COLORS[SETTING.skin[r]],
x=SCR.w*rnd(),
y=SCR.h*-.05,
- k=SCR.rad/100,
+ k=SCR.rad/200,
ang=rnd()*6.2832,
vy=.5+rnd()*.4,
vx=rnd()*.4-.2,
diff --git a/parts/backgrounds/blockspace.lua b/parts/backgrounds/blockspace.lua
index 092ff180e..ff5ce285c 100644
--- a/parts/backgrounds/blockspace.lua
+++ b/parts/backgrounds/blockspace.lua
@@ -1,4 +1,4 @@
---Space but tetrominoes
+-- Space but tetrominoes
local gc=love.graphics
local gc_clear,gc_translate=gc.clear,gc.translate
local gc_setColor,gc_draw=gc.setColor,gc.draw
@@ -47,7 +47,7 @@ function back.draw()
local M=mino[i]
local c=M.color
gc_setColor(c[1],c[2],c[3],.2)
- gc_draw(M.block,M.d*cos(M.ang),M.d*sin(M.ang),M.rotate,(18*M.d/SCR.rad)^1.6,nil,M.block:getWidth()/2,M.block:getHeight()/2)
+ gc_draw(M.block,M.d*cos(M.ang),M.d*sin(M.ang),M.rotate,(12*M.d/SCR.rad)^1.6,nil,M.block:getWidth()/2,M.block:getHeight()/2)
end
gc_translate(-SCR.cx,-SCR.cy)
end
diff --git a/parts/backgrounds/cubes.lua b/parts/backgrounds/cubes.lua
index 84442a1fb..bbf9724c9 100644
--- a/parts/backgrounds/cubes.lua
+++ b/parts/backgrounds/cubes.lua
@@ -1,4 +1,4 @@
---Flying cubes
+-- Flying cubes
local gc=love.graphics
local gc_clear=gc.clear
local gc_setColor,gc_setLineWidth=gc.setColor,gc.setLineWidth
diff --git a/parts/backgrounds/custom.lua b/parts/backgrounds/custom.lua
index 0d098cfae..06afbe503 100644
--- a/parts/backgrounds/custom.lua
+++ b/parts/backgrounds/custom.lua
@@ -1,4 +1,4 @@
---Secret custom background
+-- Custom background
local gc_clear,gc_setColor=love.graphics.clear,love.graphics.setColor
local back={}
diff --git a/parts/backgrounds/fan.lua b/parts/backgrounds/fan.lua
index aaa46fc32..2938fe1a5 100644
--- a/parts/backgrounds/fan.lua
+++ b/parts/backgrounds/fan.lua
@@ -1,4 +1,4 @@
---Yuyuko's fan
+-- Yuyuko's fan
local gc=love.graphics
local gc_clear,gc_origin,gc_replaceTransform=gc.clear,gc.origin,gc.replaceTransform
local gc_translate=gc.translate
@@ -61,7 +61,7 @@ function back.draw()
gc_setLineWidth(6)
gc_setColor(.8,.9,1,.3)
- for i=1,#SVG_TITLE_FAN do gc_polygon('line',SVG_TITLE_FAN[i])end
+ for i=1,#SVG_TITLE_FAN do gc_polygon('line',SVG_TITLE_FAN[i]) end
gc_setLineWidth(2)
gc_setColor(1,.5,.7,.3)
diff --git a/parts/backgrounds/firework.lua b/parts/backgrounds/firework.lua
index 33c5ae709..0ba9be889 100644
--- a/parts/backgrounds/firework.lua
+++ b/parts/backgrounds/firework.lua
@@ -1,4 +1,4 @@
---Firework
+-- Firework
local gc=love.graphics
local gc_clear=gc.clear
local gc_setColor,gc_setLineWidth=gc.setColor,gc.setLineWidth
@@ -37,7 +37,7 @@ function back.update(dt)
local x,y,color=F.x,F.y,F.color
if F.big then
SFX.play('fall',.5)
- for _=1,rnd(62,126)do
+ for _=1,rnd(62,126) do
ins(particle,{
x=x,y=y,
color=color,
@@ -48,7 +48,7 @@ function back.update(dt)
end
else
SFX.play('clear_1',.4)
- for _=1,rnd(16,26)do
+ for _=1,rnd(16,26) do
ins(particle,{
x=x,y=y,
color=color,
diff --git a/parts/backgrounds/fixColor.lua b/parts/backgrounds/fixColor.lua
new file mode 100644
index 000000000..7bc8b9aaa
--- /dev/null
+++ b/parts/backgrounds/fixColor.lua
@@ -0,0 +1,10 @@
+-- Customizable grey background
+local back={}
+local r,g,b=.26,.26,.26
+function back.draw()
+ GC.clear(r,g,b)
+end
+function back.event(_r,_g,_b)
+ r,g,b=_r,_g,_b
+end
+return back
diff --git a/parts/backgrounds/flink.lua b/parts/backgrounds/flink.lua
index 39b74e663..73112c254 100644
--- a/parts/backgrounds/flink.lua
+++ b/parts/backgrounds/flink.lua
@@ -1,5 +1,4 @@
---Flash after random time
-local gc=love.graphics
+-- Flash after random time
local back={}
local t
@@ -11,8 +10,8 @@ function back.update(dt)
end
function back.draw()
local t1=.13-t%3%1.9
- if t1<.2 then gc.clear(t1,t1,t1)
- else gc.clear(0,0,0)
+ if t1<.2 then GC.clear(t1,t1,t1)
+ else GC.clear(0,0,0)
end
end
return back
diff --git a/parts/backgrounds/galaxy.lua b/parts/backgrounds/galaxy.lua
new file mode 100644
index 000000000..bab729197
--- /dev/null
+++ b/parts/backgrounds/galaxy.lua
@@ -0,0 +1,41 @@
+--Space with stars
+local gc=love.graphics
+local circle,setColor,hsv=gc.circle,gc.setColor,COLOR.hsv
+local sin,cos=math.sin,math.cos
+local back={}
+
+local sDist,sRev={},{} -- star data in SoA [distance from center, revolution progress, color]
+
+function back.init()
+ if sDist[1] then return end
+ local max
+ for i=0,20 do
+ max=16*(i+1)
+ for j=1,max do
+ sDist[#sDist+1]=i+math.random()
+ sRev[#sRev+1]=MATH.tau*j/max+MATH.tau*math.random()/max
+ end
+ end
+end
+function back.update(dt)
+ for i=1,#sDist do
+ sRev[i]=(sRev[i]+dt/(sDist[i]+1))%MATH.tau
+ end
+end
+function back.draw()
+ gc.clear()
+ gc.translate(SCR.cx,SCR.cy)
+ gc.scale(SCR.k)
+ gc.rotate(1)
+ for i=1,#sDist do
+ local d,r=sDist[i],sRev[i]
+ if d<5 then
+ setColor(hsv(.088,(d-2)/7,1,.2))
+ else
+ setColor(hsv(.572,d/70+.1,(22-d)/12,.2))
+ end
+ circle('fill',8*d*cos(r),24*d*sin(r),5)
+ end
+end
+
+return back
diff --git a/parts/backgrounds/glow.lua b/parts/backgrounds/glow.lua
index 792a5a9b7..42e4a8ad5 100644
--- a/parts/backgrounds/glow.lua
+++ b/parts/backgrounds/glow.lua
@@ -1,5 +1,4 @@
---Light-dark
-local gc=love.graphics
+-- Light-dark
local sin=math.sin
local back={}
@@ -12,6 +11,6 @@ function back.update(dt)
end
function back.draw()
local t1=(sin(t*.5)+sin(t*.7)+sin(t*.9+1)+sin(t*1.5)+sin(t*2+10))*.08
- gc.clear(t1,t1,t1)
+ GC.clear(t1,t1,t1)
end
return back
diff --git a/parts/backgrounds/gray.lua b/parts/backgrounds/gray.lua
deleted file mode 100644
index c9ce3ffb2..000000000
--- a/parts/backgrounds/gray.lua
+++ /dev/null
@@ -1,11 +0,0 @@
---Customizable grey background
-local gc=love.graphics
-local back={}
-local brightness=.26
-function back.draw()
- gc.clear(brightness,brightness,brightness)
-end
-function back.event(b)
- brightness=b
-end
-return back
diff --git a/parts/backgrounds/lanterns.lua b/parts/backgrounds/lanterns.lua
index 63d606812..2a507f1d6 100644
--- a/parts/backgrounds/lanterns.lua
+++ b/parts/backgrounds/lanterns.lua
@@ -1,5 +1,4 @@
---A lantern background which is full of festive atmosphere. Lantern image by ScF
-local gc=love.graphics
+-- A lantern background which is full of festive atmosphere. Lantern image by ScF
local int,rnd=math.floor,math.random
local ins,rem=table.insert,table.remove
local mDraw=mDraw
@@ -37,8 +36,8 @@ function back.update(dt)
end
end
function back.draw()
- gc.clear(.08,.08,.084)
- gc.setColor(1,1,1,.2)
+ GC.clear(.08,.08,.084)
+ GC.setColor(1,1,1,.2)
local img=IMG.lanterns
for i=1,#lanterns do
local L=lanterns[i]
diff --git a/parts/backgrounds/league.lua b/parts/backgrounds/league.lua
index a940207ab..265082338 100644
--- a/parts/backgrounds/league.lua
+++ b/parts/backgrounds/league.lua
@@ -1,5 +1,4 @@
---Space with stars
-local gc=love.graphics
+-- Space with stars
local back={}
local upCover do
@@ -29,8 +28,8 @@ end
function back.update()
end
function back.draw()
- gc.clear(.08,.08,.084)
- gc.draw(upCover,0,0,0,W,H*.3/64)
- gc.draw(downCover,0,H*.7,0,W,H*.3/64)
+ GC.clear(.08,.08,.084)
+ GC.draw(upCover,0,0,0,W,H*.3/64)
+ GC.draw(downCover,0,H*.7,0,W,H*.3/64)
end
return back
diff --git a/parts/backgrounds/lightning.lua b/parts/backgrounds/lightning.lua
index 7bac2b457..0ae685844 100644
--- a/parts/backgrounds/lightning.lua
+++ b/parts/backgrounds/lightning.lua
@@ -1,5 +1,4 @@
---Lightning
-local gc=love.graphics
+-- Lightning
local back={}
local t
@@ -11,8 +10,8 @@ function back.update(dt)
end
function back.draw()
local t1=2.5-t%20%6%2.5
- if t1<.3 then gc.clear(t1,t1,t1)
- else gc.clear(0,0,0)
+ if t1<.3 then GC.clear(t1,t1,t1)
+ else GC.clear(0,0,0)
end
end
return back
diff --git a/parts/backgrounds/lightning2.lua b/parts/backgrounds/lightning2.lua
index 68aba3c97..1d8fd08b0 100644
--- a/parts/backgrounds/lightning2.lua
+++ b/parts/backgrounds/lightning2.lua
@@ -1,12 +1,10 @@
---Fast lightning + spining tetromino
-local gc=love.graphics
+-- Fast lightning + spining tetromino
local int,rnd=math.floor,math.random
local back={}
local t
local colorLib=BLOCK_COLORS
local blocks=BLOCKS
-local scs=RSlist.TRS.centerPos
function back.init()
t=rnd()*2600
end
@@ -16,11 +14,11 @@ end
function back.draw()
local R=7-int(t*.5%7)
local T=1.2-t%15%6%1.8
- if T<.26 then gc.clear(T,T,T)
- else gc.clear(0,0,0)
+ if T<.26 then GC.clear(T,T,T)
+ else GC.clear(0,0,0)
end
local _=colorLib[SETTING.skin[R]]
- gc.setColor(_[1],_[2],_[3],.12)
- gc.draw(TEXTURE.miniBlock[R],SCR.cx,SCR.cy,t%3.1416*6,400*SCR.k,nil,scs[R][0][2]+.5,#blocks[R][0]-scs[R][0][1]-.5)
+ GC.setColor(_[1],_[2],_[3],.12)
+ GC.draw(TEXTURE.miniBlock[R],SCR.cx,SCR.cy,t%3.1416*6,200*SCR.k,nil,2*DSCP[R][0][2]+1,2*(#blocks[R][0]-DSCP[R][0][1])-1)
end
return back
diff --git a/parts/backgrounds/matrix.lua b/parts/backgrounds/matrix.lua
index d487d801c..e1d413d47 100644
--- a/parts/backgrounds/matrix.lua
+++ b/parts/backgrounds/matrix.lua
@@ -1,4 +1,4 @@
---Black-White grid
+-- Black-White grid
local gc=love.graphics
local gc_clear,gc_scale=gc.clear,gc.scale
local gc_setColor=gc.setColor
@@ -9,7 +9,7 @@ local ceil=math.ceil
local back={}
local t
-local matrixT={}for i=1,50 do matrixT[i]={}for j=1,50 do matrixT[i][j]=love.math.noise(i,j)+2 end end
+local matrixT={} for i=1,50 do matrixT[i]={} for j=1,50 do matrixT[i][j]=love.math.noise(i,j)+2 end end
function back.init()
t=math.random()*2600
end
@@ -21,7 +21,7 @@ function back.draw()
local k=SCR.k
gc_scale(k)
local Y=ceil(SCR.h/80/k)
- for x=1,ceil(SCR.w/80/k)do
+ for x=1,ceil(SCR.w/80/k) do
for y=1,Y do
gc_setColor(1,1,1,sin(x+matrixT[x][y]*t)*.04+.04)
gc_rectangle('fill',80*x,80*y,-80,-80)
diff --git a/parts/backgrounds/quarks.lua b/parts/backgrounds/quarks.lua
new file mode 100644
index 000000000..2159d6779
--- /dev/null
+++ b/parts/backgrounds/quarks.lua
@@ -0,0 +1,145 @@
+local gc=love.graphics
+local hsv=COLOR.hsv
+local circle,push,pop,rot,translate,setColor=gc.circle,gc.push,gc.pop,gc.rotate,gc.translate,gc.setColor
+local rnd,sin,cos,log=math.random,math.sin,math.cos,math.log
+local back={}
+
+local qX,qY,qdX,qdY={},{},{},{} -- quark data in SoA [size, X, Y, dx, dy, color]
+
+local ptcclr={{1,0,0,.5},{0,1,0,.5},{0,0,1,.5}}
+local apcclr={{0,1,1,.5},{1,0,1,.5},{1,1,0,.5}}
+
+local blasts={} -- data about annihilation blasts from particles and antiparticles colliding
+local ptc={} -- particle-antiparticle data (antiparticle is a mirror of particle)
+local nextpair
+
+local W,H,size
+local quarkCount=400
+
+local function spawnQuarkRandom(i)
+ qX[i]=rnd(W)-10 -- X
+ qY[i]=rnd(H)-10 -- Y
+ local theta=rnd()*MATH.tau
+ qdX[i]=cos(theta)*300 -- dx
+ qdY[i]=sin(theta)*300 -- dy
+end
+local function spawnQuarkEdge(i)
+ local side=rnd(4)
+ if side==1 then -- Up edge of screen
+ qX[i]=rnd(SCR.x-10,SCR.ex+10)
+ qY[i]=SCR.y-10
+ elseif side==2 then -- Right edge of screen
+ qX[i]=SCR.ex+10
+ qY[i]=rnd(SCR.y-10,SCR.ey+10)
+ elseif side==3 then -- Down edge of screen
+ qX[i]=rnd(SCR.x-10,SCR.ex+10)
+ qY[i]=SCR.ey+10
+ elseif side==4 then -- Left edge of screen
+ qX[i]=SCR.x-10
+ qY[i]=rnd(SCR.y-10,SCR.ey+10)
+ end
+ local theta=rnd()*MATH.tau
+ qdX[i]=cos(theta)*300 -- dx
+ qdY[i]=sin(theta)*300 -- dy
+end
+local function spawnParticlePair()
+ ptc[#ptc+1]={
+ x=rnd(W)-10,
+ y=rnd(H)-10,
+ dist=0,
+ theta=rnd()*MATH.tau,
+ v=500,
+ c=rnd(3),
+ }
+end
+local function spawnBlast(_x,_y)
+ blasts[#blasts+1]={x=_x,y=_y,t=0}
+end
+
+function back.init()
+ qX,qY,qdX,qdY={},{},{},{}
+ blasts={}
+ ptc={}
+ nextpair=0
+ BG.resize(SCR.w,SCR.h)
+end
+function back.resize(w,h)
+ W,H=w+20,h+20
+ for i=1,quarkCount do spawnQuarkRandom(i) end
+ size=2.6*SCR.k
+end
+function back.update(dt)
+ -- Move far-away quarks
+ for i=1,quarkCount do
+ qX[i]=qX[i]+qdX[i]*dt
+ qY[i]=qY[i]+qdY[i]*dt
+ if qX[i]SCR.ex+26 or qY[i]SCR.ey+26 then
+ spawnQuarkEdge(i)
+ end
+ end
+
+ -- Particle pair attraction & destruction
+ for i=#ptc,1,-1 do
+ local p=ptc[i]
+ if p then
+ p.dist=p.dist+p.v*dt
+ p.v=p.v-p.dist^2*dt
+
+ -- Destroy colliding particle pairs
+ if p.dist<=10 and p.v<=0 then
+ spawnBlast(p.x,p.y)
+ table.remove(ptc,i)
+ end
+ end
+ end
+
+ -- Age blasts, delete old blasts
+ for i=#blasts,1,-1 do
+ if blasts[i] then
+ blasts[i].t=blasts[i].t+dt
+ if blasts[i].t>=1 then
+ table.remove(blasts,i)
+ end
+ end
+ end
+
+ -- Spawn particle pairs
+ nextpair=nextpair-dt
+ if nextpair<=0 then
+ spawnParticlePair()
+ nextpair=rnd()*4
+ end
+end
+function back.draw()
+ gc.clear(.08,.04,.01)
+ translate(-10,-10)
+
+ -- Draw quarks in R/G/B
+ setColor(1,0,0,.5) for i=1, math.floor(quarkCount/3) do circle('fill',qX[i],qY[i],size) end
+ setColor(0,1,0,.5) for i=math.floor(quarkCount/3)+1, math.floor(quarkCount*2/3) do circle('fill',qX[i],qY[i],size) end
+ setColor(0,0,1,.5) for i=math.floor(quarkCount*2/3)+1,quarkCount do circle('fill',qX[i],qY[i],size) end
+
+ for i=1,#ptc do
+ local p=ptc[i]
+ push()
+ translate(p.x,p.y)
+ rot(p.theta)
+
+ setColor(ptcclr[p.c])
+ circle('fill', p.dist,0,4*size)
+ setColor(apcclr[p.c])
+ circle('fill',-p.dist,0,4*size)
+ pop()
+ end
+ for i=1,#blasts do
+ local t=blasts[i].t
+ setColor(hsv(-80*t,1-1.7*log(5*t,10),1,1-t))
+ circle('fill',blasts[i].x,blasts[i].y,62*t^.3)
+ end
+end
+function back.discard()
+ qX,qY,qdX,qdY,qC=nil
+ ptc,blasts=nil
+ collectgarbage()
+end
+return back
diff --git a/parts/backgrounds/rainbow.lua b/parts/backgrounds/rainbow.lua
index b0a5d4fc6..ab82699f6 100644
--- a/parts/backgrounds/rainbow.lua
+++ b/parts/backgrounds/rainbow.lua
@@ -1,25 +1,19 @@
---Colorful RGB
-local gc=love.graphics
+-- Colorful RGB
local back={}
local shader=SHADER.rgb1
local t
function back.init()
t=math.random()*2600
- BG.resize(SCR.w,SCR.h)
-end
-function back.resize(_,h)
- shader:send('w',SCR.W)
- shader:send('h',h*SCR.dpi)
end
function back.update(dt)
- t=t+dt
+ t=(t+dt)%6200
end
function back.draw()
- gc.clear(.08,.08,.084)
- shader:send('t',t)
- gc.setShader(shader)
- gc.rectangle('fill',0,0,SCR.w,SCR.h)
- gc.setShader()
+ GC.clear(.08,.08,.084)
+ shader:send('phase',t)
+ GC.setShader(shader)
+ GC.rectangle('fill',0,0,SCR.w,SCR.h)
+ GC.setShader()
end
return back
diff --git a/parts/backgrounds/rainbow2.lua b/parts/backgrounds/rainbow2.lua
index ef8d56454..6fae525d1 100644
--- a/parts/backgrounds/rainbow2.lua
+++ b/parts/backgrounds/rainbow2.lua
@@ -1,25 +1,19 @@
---Blue RGB
-local gc=love.graphics
+-- Blue RGB
local back={}
local shader=SHADER.rgb2
local t
function back.init()
t=math.random()*2600
- BG.resize(SCR.w,SCR.h)
-end
-function back.resize(_,h)
- shader:send('w',SCR.W)
- shader:send('h',h*SCR.dpi)
end
function back.update(dt)
- t=t+dt
+ t=(t+dt)%6200
end
function back.draw()
- gc.clear(.08,.08,.084)
- shader:send('t',t)
- gc.setShader(shader)
- gc.rectangle('fill',0,0,SCR.w,SCR.h)
- gc.setShader()
+ GC.clear(.08,.08,.084)
+ shader:send('phase',t)
+ GC.setShader(shader)
+ GC.rectangle('fill',0,0,SCR.w,SCR.h)
+ GC.setShader()
end
return back
diff --git a/parts/backgrounds/rgb.lua b/parts/backgrounds/rgb.lua
index 1983464c0..2951e46c4 100644
--- a/parts/backgrounds/rgb.lua
+++ b/parts/backgrounds/rgb.lua
@@ -1,5 +1,4 @@
---Changing pure color
-local gc=love.graphics
+-- Changing pure color
local sin=math.sin
local back={}
@@ -11,7 +10,7 @@ function back.update(dt)
t=t+dt
end
function back.draw()
- gc.clear(
+ GC.clear(
sin(t*1.2)*.06+.08,
sin(t*1.5)*.06+.08,
sin(t*1.9)*.06+.08
diff --git a/parts/backgrounds/snow.lua b/parts/backgrounds/snow.lua
index d3a658037..d377a9262 100644
--- a/parts/backgrounds/snow.lua
+++ b/parts/backgrounds/snow.lua
@@ -1,4 +1,4 @@
---Snow
+-- Snow
local gc=love.graphics
local ellipse=gc.ellipse
local rnd=math.random
diff --git a/parts/backgrounds/space.lua b/parts/backgrounds/space.lua
index 48be71ad8..4d2f32fe8 100644
--- a/parts/backgrounds/space.lua
+++ b/parts/backgrounds/space.lua
@@ -1,4 +1,4 @@
---Space with stars
+-- Space with stars
local gc=love.graphics
local rectangle=gc.rectangle
local rnd=math.random
@@ -15,16 +15,16 @@ function back.resize(w,h)
local S=stars
for i=1,1260,5 do
local s=rnd(26,40)*.1
- S[i]=s*SCR.k --Size
- S[i+1]=rnd(W)-10 --X
- S[i+2]=rnd(H)-10 --Y
- S[i+3]=(rnd()-.5)*.01*s--Vx
- S[i+4]=(rnd()-.5)*.01*s--Vy
+ S[i]=s*SCR.k -- Size
+ S[i+1]=rnd(W)-10 -- X
+ S[i+2]=rnd(H)-10 -- Y
+ S[i+3]=(rnd()-.5)*.01*s-- Vx
+ S[i+4]=(rnd()-.5)*.01*s-- Vy
end
end
function back.update(dt)
local S=stars
- --Star moving
+ -- Star moving
for i=1,1260,5 do
S[i+1]=(S[i+1]+S[i+3]*dt*60)%W
S[i+2]=(S[i+2]+S[i+4]*dt*60)%H
@@ -32,7 +32,7 @@ function back.update(dt)
end
function back.draw()
gc.clear(.08,.08,.084)
- if not stars[1]then return end
+ if not stars[1] then return end
gc.translate(-10,-10)
gc.setColor(1,1,1,.6)
for i=1,1260,5 do
diff --git a/parts/backgrounds/tunnel.lua b/parts/backgrounds/tunnel.lua
index 103de65df..5391a25ae 100644
--- a/parts/backgrounds/tunnel.lua
+++ b/parts/backgrounds/tunnel.lua
@@ -1,5 +1,4 @@
---Cool Tunnel
-local gc=love.graphics
+-- Cool Tunnel
local rnd=math.random
local ins,rem=table.insert,table.remove
local back={}
@@ -29,12 +28,12 @@ function back.update(dt)
end
end
function back.draw()
- gc.clear(.08,.08,.084)
- gc.setColor(1,1,1,.1)
+ GC.clear(.08,.08,.084)
+ GC.setColor(1,1,1,.1)
for i=1,#ring do
local r=ring[i]^2/12
- gc.setLineWidth(30-15/(r+.5))
- gc.rectangle('line',W*.5-W*r/2,H*.5-H*r/2,W*r,H*r)
+ GC.setLineWidth(30-15/(r+.5))
+ GC.rectangle('line',W*.5-W*r/2,H*.5-H*r/2,W*r,H*r)
end
end
function back.discard()
diff --git a/parts/backgrounds/welcome.lua b/parts/backgrounds/welcome.lua
index 15c030fe9..09a95755c 100644
--- a/parts/backgrounds/welcome.lua
+++ b/parts/backgrounds/welcome.lua
@@ -1,5 +1,4 @@
---Welcome to Techmino
-local gc=love.graphics
+-- Welcome to Techmino
local sin=math.sin
local back={}
@@ -7,33 +6,33 @@ local t
local textObj
function back.init()
t=math.random()*2600
- textObj=gc.newText(getFont(80),"Welcome To Techmino")
+ textObj=GC.newText(getFont(80),"Welcome To Techmino")
end
function back.update(dt)
t=t+dt
end
function back.draw()
if -t%13.55<.1283 then
- gc.clear(.2+.1*sin(t),.2+.1*sin(1.26*t),.2+.1*sin(1.626*t))
+ GC.clear(.2+.1*sin(t),.2+.1*sin(1.26*t),.2+.1*sin(1.626*t))
else
- gc.clear(.08,.08,.084)
+ GC.clear(.08,.08,.084)
end
- gc.push('transform')
- gc.translate(SCR.cx,SCR.cy+20*sin(t*.02))
- gc.scale(SCR.k)
- gc.scale(1.26,1.36)
+ GC.push('transform')
+ GC.replaceTransform(SCR.xOy_m)
+ GC.translate(0,20*sin(t*.02))
+ GC.scale(1.26,1.36)
if -t%6.26<.1355 then
- gc.translate(60*sin(t*.26),100*sin(t*.626))
+ GC.translate(60*sin(t*.26),100*sin(t*.626))
end
if -t%12.6<.1626 then
- gc.rotate(t+5*sin(.26*t)+5*sin(.626*t))
+ GC.rotate(t+5*sin(.26*t)+5*sin(.626*t))
end
- gc.setColor(.4,.6,1,.3)
+ GC.setColor(.4,.6,1,.3)
mDraw(textObj,4*sin(t*.7942),4*sin(t*.7355))
- gc.setColor(.5,.7,1,.4)
+ GC.setColor(.5,.7,1,.4)
mDraw(textObj,2*sin(t*.77023),2*sin(t*.7026))
- gc.setColor(1,1,1,.5)
+ GC.setColor(1,1,1,.5)
mDraw(textObj,3*sin(t*.7283),3*sin(t*.7626))
- gc.pop()
+ GC.pop()
end
return back
diff --git a/parts/backgrounds/wing.lua b/parts/backgrounds/wing.lua
index b36ffa7f1..822812fb3 100644
--- a/parts/backgrounds/wing.lua
+++ b/parts/backgrounds/wing.lua
@@ -1,6 +1,4 @@
---Flandre's wing
-local gc=love.graphics
-local rnd=math.random
+-- Flandre's wing
local back={}
local crystal_img,crystals
local wingColor={
@@ -46,31 +44,31 @@ function back.update()
end
end
function back.draw()
- gc.clear(.06,.06,.06)
- gc.setColor(.12,.10,.08)
- gc.setLineJoin('bevel')
- gc.setLineWidth(14*SCR.k)
+ GC.clear(.06,.06,.06)
+ GC.setColor(.12,.10,.08)
+ GC.setLineJoin('bevel')
+ GC.setLineWidth(14*SCR.k)
local W,H=SCR.w,SCR.h
- gc.line(.018*W,.567*H,.101*W,.512*H,.202*W,.369*H,.260*W,.212*H)
- gc.line(.247*W,.257*H,.307*W,.383*H,.352*W,.436*H,.401*W,.309*H)
- gc.line(.982*W,.567*H,.899*W,.512*H,.798*W,.369*H,.740*W,.212*H)
- gc.line(.753*W,.257*H,.693*W,.383*H,.648*W,.436*H,.599*W,.309*H)
+ GC.line(.018*W,.567*H,.101*W,.512*H,.202*W,.369*H,.260*W,.212*H)
+ GC.line(.247*W,.257*H,.307*W,.383*H,.352*W,.436*H,.401*W,.309*H)
+ GC.line(.982*W,.567*H,.899*W,.512*H,.798*W,.369*H,.740*W,.212*H)
+ GC.line(.753*W,.257*H,.693*W,.383*H,.648*W,.436*H,.599*W,.309*H)
local k=SCR.k
for i=1,8 do
- gc.setColor(wingColor[i])
+ GC.setColor(wingColor[i])
local B=crystals[i]
- gc.draw(crystal_img,B.x,B.y,B.a,k,k,21,0)
+ GC.draw(crystal_img,B.x,B.y,B.a,k,k,21,0)
B=crystals[8+i]
- gc.draw(crystal_img,B.x,B.y,B.a,-k,k,21,0)
+ GC.draw(crystal_img,B.x,B.y,B.a,-k,k,21,0)
end
end
function back.event(level)
for i=1,8 do
local B=crystals[i]
- B.va=B.va+.001*level*(1+rnd())
+ B.va=B.va+.001*level*(1+math.random())
B=crystals[17-i]
- B.va=B.va-.001*level*(1+rnd())
+ B.va=B.va-.001*level*(1+math.random())
end
end
function back.discard()
diff --git a/parts/bot/bot_9s.lua b/parts/bot/bot_9s.lua
index b14b9b7d6..5f91e2cc4 100644
--- a/parts/bot/bot_9s.lua
+++ b/parts/bot/bot_9s.lua
@@ -38,8 +38,8 @@ local FCL={
local LclearScore={[0]=0,-200,-150,-100,200}
local HclearScore={[0]=0,100,140,200,500}
local function _ifoverlapAI(f,bk,x,y)
- for i=1,#bk do for j=1,#bk[1]do
- if f[y+i-1]and bk[i][j]and f[y+i-1][x+j-1]>0 then
+ for i=1,#bk do for j=1,#bk[1] do
+ if f[y+i-1] and bk[i][j] and f[y+i-1][x+j-1]>0 then
return true
end
end end
@@ -65,16 +65,21 @@ local function _getScore(field,cb,cy)
local hole=0
for i=cy+#cb-1,cy,-1 do
+ local full=true
for j=1,10 do
if field[i][j]==0 then
- goto CONTINUE_notFull
+ -- goto CONTINUE_notFull
+ full=false
+ break
end
end
- discardRow(rem(field,i))
- clear=clear+1
- ::CONTINUE_notFull::
+ if full then
+ -- ::CONTINUE_notFull::
+ discardRow(rem(field,i))
+ clear=clear+1
+ end
end
- if #field==0 then--PC
+ if #field==0 then-- PC
return 1e99
end
for x=1,10 do
@@ -116,10 +121,10 @@ local function _getScore(field,cb,cy)
-#field*30
-#cb*15
+(#field>10 and
- HclearScore[clear]--Clearing
- -hole*70--Hole
- -cy*50--Height
- -sdh--Sum of DeltaH
+ HclearScore[clear]-- Clearing
+ -hole*70-- Hole
+ -cy*50-- Height
+ -sdh-- Sum of DeltaH
or
LclearScore[clear]
-hole*100
@@ -139,10 +144,10 @@ local bot_9s={}
function bot_9s.thread(bot)
local P,data,keys=bot.P,bot.data,bot.keys
while true do
- --Thinking
+ -- Thinking
yield()
- local Tfield={}--Test field
- local best={x=1,dir=0,hold=false,score=-1e99}--Best method
+ local Tfield={}-- Test field
+ local best={x=1,dir=0,hold=false,score=-1e99}-- Best method
local field_org=P.field
for i=1,#field_org do
Tfield[i]=getRow(0)
@@ -152,33 +157,33 @@ function bot_9s.thread(bot)
end
for ifhold=0,data.hold and P.gameEnv.holdCount>0 and 1 or 0 do
- --Get block id
+ -- Get block id
local bn
if ifhold==0 then
bn=P.cur and P.cur.id
else
- bn=P.holdQueue[1]and P.holdQueue[1].id or P.nextQueue[1]and P.nextQueue[1].id
+ bn=P.holdQueue[1] and P.holdQueue[1].id or P.nextQueue[1] and P.nextQueue[1].id
end
if bn then
- for dir=0,dirCount[bn]do--Each dir
+ for dir=0,dirCount[bn] do-- Each dir
local cb=BLOCKS[bn][dir]
- for cx=1,11-#cb[1]do--Each pos
+ for cx=1,11-#cb[1] do-- Each pos
local cy=#Tfield+1
- --Move to bottom
- while cy>1 and not _ifoverlapAI(Tfield,cb,cx,cy-1)do
+ -- Move to bottom
+ while cy>1 and not _ifoverlapAI(Tfield,cb,cx,cy-1) do
cy=cy-1
end
- --Simulate lock
+ -- Simulate lock
for i=1,#cb do
local y=cy+i-1
- if not Tfield[y]then
+ if not Tfield[y] then
Tfield[y]=getRow(0)
end
local L=Tfield[y]
- for j=1,#cb[1]do
- if cb[i][j]then
+ for j=1,#cb[1] do
+ if cb[i][j] then
L[cx+j-1]=1
end
end
@@ -194,7 +199,7 @@ function bot_9s.thread(bot)
end
if not best.bn then return 1 end
- --Release cache
+ -- Release cache
while #Tfield>0 do
discardRow(rem(Tfield,1))
end
@@ -207,7 +212,7 @@ function bot_9s.thread(bot)
end
ins(keys,6)
- --Check if time to change target
+ -- Check if time to change target
yield()
if P.aiRND:random()<.00126 then
P:changeAtkMode(P.aiRND:random()<.85 and 1 or #P.atker>3 and 4 or P.aiRND:random()<.3 and 2 or 3)
diff --git a/parts/bot/bot_cc.lua b/parts/bot/bot_cc.lua
index ec2c615c0..bc4e4ede2 100644
--- a/parts/bot/bot_cc.lua
+++ b/parts/bot/bot_cc.lua
@@ -7,40 +7,58 @@ local pcall=pcall
local ins,rem=table.insert,table.remove
local yield=coroutine.yield
local bot_cc={}
-function bot_cc:checkDest()
+function bot_cc:checkDest(b2b,atk,exblock,yomi)
local dest=self.P.destFX
if not dest then return end
+ if not (dest.b2b==b2b and dest.attack==atk and dest.extra==exblock) then
+ -- print(('hope: %s %s %s'):format(dest.b2b,dest.attack,dest.extra))
+ -- print(('real: %s %s %s'):format(b2b,atk,exblock))
+ -- print(yomi)
+ self:lockWrongPlace()
+ self.P.destFX=nil
+ return
+ end
local CB=self.P.cur.bk
for k=1,#dest,2 do
local r=CB[dest[k+1]-self.P.curY+2]
- if not r or not r[dest[k]-self.P.curX+2]then
+ if not r or not r[dest[k]-self.P.curX+2] then
+ -- print('wrong place')
self:lockWrongPlace()
self.P.destFX=nil
return
end
end
+ local should_spawn = self.P:getNextSpawn() - 1
+ if dest.spawn ~= should_spawn then
+ assert(dest.spawn > should_spawn)
+ -- print('wrong spawn: should be '..dest.spawn..' but '..should_spawn)
+ -- print('-- should only happen when camera is going down')
+ self:lockWrongPlace()
+ self.P.destFX=nil
+ return
+ end
end
function bot_cc:revive()
TABLE.cut(self.P.holdQueue)
self.P:loadAI(self.data)
end
function bot_cc:pushNewNext(id)
- self.ccBot:addNext(rem(self.bufferedNexts,1))
ins(self.bufferedNexts,id)
+ self.ccBot:addNext(rem(self.bufferedNexts,1))
end
function bot_cc:thread()
local P,keys=self.P,self.keys
local ccBot=self.ccBot
while true do
- --Start thinking
+ -- Start thinking
yield()
ccBot:think()
- --Poll keys
- local success,result,dest,hold,move
+ -- Poll keys
+ local success,result,dest,hold,move,b2b,attack,extra,spawn
repeat
yield()
- success,result,dest,hold,move=pcall(ccBot.getMove,ccBot)
+ success,result,dest,hold,move,b2b,attack,extra,spawn=pcall(ccBot.getMove,ccBot)
until not success or result==0 or result==2
if not success then break end
if result==2 then
@@ -50,14 +68,20 @@ function bot_cc:thread()
dest[7],dest[8]=dest[2][1],dest[2][2]
dest[1],dest[2]=dest[3][1],dest[3][2]
dest[3],dest[4]=dest[4][1],dest[4][2]
+ dest.b2b = b2b
+ dest.attack = attack
+ dest.extra = extra
+ dest.spawn = spawn
P.destFX=dest
- if hold then--Hold
+ if hold then-- Hold
keys[1]=8
end
- while move[1]do
+ while move[1] do
local m=rem(move,1)
if m<4 then
ins(keys,m+1)
+ elseif m==5 then
+ ins(keys, 5)
elseif not self.data._20G then
ins(keys,13)
end
@@ -65,7 +89,7 @@ function bot_cc:thread()
ins(keys,6)
end
- --Check if time to change target
+ -- Check if time to change target
yield()
if P.aiRND:random()<.00126 then
P:changeAtkMode(P.aiRND:random()<.85 and 1 or #P.atker>3 and 4 or P.aiRND:random()<.3 and 2 or 3)
@@ -80,8 +104,16 @@ function bot_cc:updateField()
F[i],i=F0[y][x]>0,i+1
end end
while i<=400 do F[i],i=false,i+1 end
- if not pcall(self.ccBot.reset,self.ccBot,F,P.b2b>=100,P.combo)then
+ local y = P:getNextSpawn()-1
+ if not pcall(self.ccBot.reset,self.ccBot,F,P.b2b,P.combo,P.stat.pc,P.stat.row,y) then
print("CC is dead ("..P.id..")","error")
+ for y=#F0,1,-1 do
+ local s=""
+ for x=1,10 do
+ s=s..(F[(y-1)*10+x] and "[]" or "..")
+ end
+ print(s)
+ end
end
end
function bot_cc:switch20G()
diff --git a/parts/bot/init.lua b/parts/bot/init.lua
index 4df42abfa..aed19b239 100644
--- a/parts/bot/init.lua
+++ b/parts/bot/init.lua
@@ -14,9 +14,9 @@ function baseBot.update(bot)
local keys=bot.keys
if P.control and P.cur then
bot.delay=bot.delay-1
- if not keys[1]then
+ if not keys[1] then
if bot.runningThread then
- if not pcall(bot.runningThread)then
+ if not pcall(bot.runningThread) then
bot.runningThread=false
end
else
@@ -49,7 +49,7 @@ local botMeta={__index=_undefMethod}
local BOT={}
-local AISpeed={60,50,40,30,20,14,10,6,4,3}
+local AISpeed={60,50,42,34,27,21,16,12,9,6}
--[[
arg={
next: number of nexts
@@ -61,18 +61,18 @@ local AISpeed={60,50,40,30,20,14,10,6,4,3}
}
]]
function BOT.template(arg)
- if arg.type=='CC'then
- return{
+ if arg.type=='CC' then
+ return {
type='CC',
next=arg.next,
hold=arg.hold,
delay=AISpeed[arg.speedLV],
node=arg.node,
- bag=(arg.randomizer or'bag')=='bag',
+ bag=(arg.randomizer or 'bag')=='bag',
_20G=arg._20G,
}
- elseif arg.type=='9S'then
- return{
+ elseif arg.type=='9S' then
+ return {
type='9S',
delay=math.floor(AISpeed[arg.speedLV]),
hold=arg.hold,
@@ -82,8 +82,8 @@ end
function BOT.new(P,data)
local bot={P=P,data=data}
- if data.type=="CC"then
- P:setRS('SRS')
+ if data.type=="CC" then
+ P:setRS('TRS')
bot.keys={}
bot.bufferedNexts={}
bot.delay=data.delay
@@ -92,7 +92,7 @@ function BOT.new(P,data)
P:setHold(1)
end
- local cc=cc or REQUIRE"CCloader"
+ local cc=REQUIRE"CCloader"
if not cc then
data.type=false
return BOT.new(P,data)
@@ -107,8 +107,8 @@ function BOT.new(P,data)
local cc_lua=require"parts.bot.bot_cc"
setmetatable(bot,{__index=function(self,k)
return
- self.ccBot[k]and function(_,...)self.ccBot[k](self.ccBot,...)end or
- cc_lua[k]and function(_,...)cc_lua[k](self,...)end or
+ self.ccBot[k] and function(_,...)self.ccBot[k](self.ccBot,...) end or
+ cc_lua[k] and function(_,...)cc_lua[k](self,...) end or
assert(baseBot[k],"No CC action called "..k)
end})
@@ -127,7 +127,7 @@ function BOT.new(P,data)
end
bot.runningThread=coroutine.wrap(cc_lua.thread)
bot.runningThread(bot)
- else--if data.type=="9S"then--9s or else
+ else-- if data.type=="9S" then-- 9s or else
TABLE.cover(baseBot,bot)
TABLE.cover(require"parts.bot.bot_9s",bot)
P:setRS('TRS')
diff --git a/parts/char.lua b/parts/char.lua
index e6b57aef9..1f39bc6de 100644
--- a/parts/char.lua
+++ b/parts/char.lua
@@ -1,5 +1,5 @@
local L={
- zChan={--F0000~F003F
+ zChan={-- F0000~F003F
none= 0xF0000,
normal= 0xF0001,
full= 0xF0002,
@@ -24,7 +24,7 @@ local L={
thinking= 0xF0015,
spark= 0xF0016,
},
- mino={--F0040~F007F
+ mino={-- F0040~F007F
Z=0xF0040,
S=0xF0041,
J=0xF0042,
@@ -57,7 +57,7 @@ local L={
I2=0xF005B,
O1=0xF005C,
},
- icon={--F0080~F00FF
+ icon={-- F0080~F00FF
menu= 0xF0080,
music= 0xF0081,
language= 0xF0082,
@@ -130,8 +130,14 @@ local L={
bomb= 0xF00C5,
garbage= 0xF00C6,
copy= 0xF00C7,
+ tas= 0xF00C8,
+ pencil= 0xF00C9,
+ magGlass= 0xF00CA,
+ zoomIn= 0xF00CB,
+ zoomOut= 0xF00CC,
+ zoomDefault= 0xF00CD,
},
- key={--F0100~F017F
+ key={-- F0100~F017F
macCmd= 0xF0100,
macOpt= 0xF0101,
macCtrl= 0xF0102,
@@ -172,7 +178,7 @@ local L={
macPgdnAlt= 0xF0125,
iecPower= 0xF0126,
},
- controller={--F0100~F017F
+ controller={-- F0180~F01FF
xbox= 0xF0180,
lt= 0xF0181,
rt= 0xF0182,
@@ -186,12 +192,12 @@ local L={
joystickR= 0xF018A,
jsLU= 0xF018B,
jsLD= 0xF018C,
- jsLL= 0xF018D,
- jsLR= 0xF018E,
+ jsLR= 0xF018D,
+ jsLL= 0xF018E,
jsRU= 0xF018F,
jsRD= 0xF0190,
- jsRL= 0xF0191,
- jsRR= 0xF0192,
+ jsRR= 0xF0191,
+ jsRL= 0xF0192,
jsLPress= 0xF0193,
jsRPress= 0xF0194,
dpad= 0xF0195,
@@ -211,6 +217,94 @@ local L={
psMute= 0xF01A3,
psCreate= 0xF01A4,
psOption= 0xF01A5,
+ },
+ mahjong={-- F0200~F027F
+ m1= 0xF0200,
+ m2= 0xF0201,
+ m3= 0xF0202,
+ m4= 0xF0203,
+ m5= 0xF0204,
+ m6= 0xF0205,
+ m7= 0xF0206,
+ m8= 0xF0207,
+ m9= 0xF0208,
+ s1= 0xF0209,
+ s2= 0xF020A,
+ s3= 0xF020B,
+ s4= 0xF020C,
+ s5= 0xF020D,
+ s6= 0xF020E,
+ s7= 0xF020F,
+ s8= 0xF0210,
+ s9= 0xF0211,
+ p1= 0xF0212,
+ p2= 0xF0213,
+ p3= 0xF0214,
+ p4= 0xF0215,
+ p5= 0xF0216,
+ p6= 0xF0217,
+ p7= 0xF0218,
+ p8= 0xF0219,
+ p9= 0xF021A,
+ ton= 0xF021B,
+ nan= 0xF021C,
+ sha= 0xF021D,
+ pe= 0xF021E,
+ chun= 0xF021F,
+ hatsu= 0xF0220,
+ haku= 0xF0221,
+ hatsuAlt= 0xF0222,
+ hakuAlt= 0xF0223,
+ haru= 0xF0224,
+ natsu= 0xF0225,
+ aki= 0xF0226,
+ fuyu= 0xF0227,
+ ume= 0xF0228,
+ ran= 0xF0229,
+ kiku= 0xF022A,
+ take= 0xF022B,
+ m5Red= 0xF022C,
+ s5Red= 0xF022D,
+ p5Red= 0xF022E,
+ m1Base= 0xF022F,
+ m2Base= 0xF0230,
+ m3Base= 0xF0231,
+ m4Base= 0xF0232,
+ m5Base= 0xF0233,
+ m6Base= 0xF0234,
+ m7Base= 0xF0235,
+ m8Base= 0xF0236,
+ m9Base= 0xF0237,
+ mComb= 0xF0238,
+ s1Base= 0xF0239,
+ s1Comb= 0xF023A,
+ s5Base= 0xF023B,
+ s5Comb= 0xF023C,
+ s7Base= 0xF023D,
+ s7Comb= 0xF023E,
+ s9Base= 0xF023F,
+ s9Comb= 0xF0240,
+ p2Base= 0xF0241,
+ p2Comb= 0xF0242,
+ p3Base= 0xF0243,
+ p3Comb1= 0xF0244,
+ p3Comb2= 0xF0245,
+ p4Base= 0xF0246,
+ p4Comb= 0xF0247,
+ p5Base= 0xF0248,
+ p5Comb1= 0xF0249,
+ p5Comb2= 0xF024A,
+ p6Base= 0xF024B,
+ p6Comb= 0xF024C,
+ p7Base= 0xF024D,
+ p7Comb= 0xF024E,
+ p9Base= 0xF024F,
+ p9Comb1= 0xF0250,
+ p9Comb2= 0xF0251,
+ frameComb= 0xF0252,
+ s1j= 0xF0253,
+ s1jBase= 0xF0254,
+ s1jComb= 0xF0255,
}
}
diff --git a/parts/customEnv0.lua b/parts/customEnv0.lua
index 075304d0f..5b6629257 100644
--- a/parts/customEnv0.lua
+++ b/parts/customEnv0.lua
@@ -1,7 +1,7 @@
-return{
+return {
version=VERSION.code,
- --Basic
+ -- Basic
drop=1e99,
lock=1e99,
wait=0,
@@ -9,17 +9,17 @@ return{
hang=5,
hurry=1e99,
- --Control
+ -- Control
nextCount=6,
holdMode='hold',
holdCount=1,
infHold=true,
phyHold=false,
- --Visual
+ -- Visual
bone=false,
- --Rule
+ -- Rule
sequence='bag',
lockout=false,
fieldH=20,
@@ -40,7 +40,7 @@ return{
garbageSpeed=1,
missionKill=false,
- --Else
+ -- Else
bg='blockrain',
bgm='hang out',
diff --git a/parts/data.lua b/parts/data.lua
index 33c25864f..bd8ff4cef 100644
--- a/parts/data.lua
+++ b/parts/data.lua
@@ -5,8 +5,8 @@ local ins=table.insert
local BAG,FIELD,MISSION,CUSTOMENV,GAME=BAG,FIELD,MISSION,CUSTOMENV,GAME
local DATA={}
---Sep symbol: 33 (!)
---Safe char: 34~126
+-- Sep symbol: 33 (!)
+-- Safe char: 34~126
--[[
Count: 34~96
Block: 97~125
@@ -18,7 +18,7 @@ function DATA.copySequence()
local count=1
for i=1,#BAG+1 do
- if BAG[i+1]~=BAG[i]or count==64 then
+ if BAG[i+1]~=BAG[i] or count==64 then
str=str..char(96+BAG[i])
if count>1 then
str=str..char(32+count)
@@ -66,14 +66,14 @@ local fieldMeta={__index=function(self,h)
end
return self[h]
end}
-function DATA.newBoard(f)--Generate a new board
- return setmetatable(f and TABLE.shift(f)or{},fieldMeta)
+function DATA.newBoard(f)-- Generate a new board
+ return setmetatable(f and TABLE.shift(f) or{},fieldMeta)
end
-function DATA.copyBoard(page)--Copy the [page] board
+function DATA.copyBoard(page)-- Copy the [page] board
local F=FIELD[page or 1]
local str=""
- --Encode field
+ -- Encode field
for y=1,#F do
local S=""
local L=F[y]
@@ -91,25 +91,25 @@ function DATA.copyBoards()
end
return table.concat(out,"!")
end
-function DATA.pasteBoard(str,page)--Paste [str] data to [page] board
+function DATA.pasteBoard(str,page)-- Paste [str] data to [page] board
if not page then
page=1
end
- if not FIELD[page]then
+ if not FIELD[page] then
FIELD[page]=DATA.newBoard()
end
local F=FIELD[page]
- --Decode
+ -- Decode
str=STRING.unpackBin(str)
if not str then return end
- local fX,fY=1,1--*ptr for Field(r*10+(c-1))
+ local fX,fY=1,1-- *ptr for Field(r*10+(c-1))
local p=1
while true do
- local b=byte(str,p)--1byte
+ local b=byte(str,p)-- 1byte
- --Str end
+ -- Str end
if not b then
if fX~=1 then
return
@@ -118,16 +118,16 @@ function DATA.pasteBoard(str,page)--Paste [str] data to [page] board
end
end
- local id=b%32-1--Block id
- if id>26 then return end--Illegal blockid
- b=int(b/32)--Mode id
+ local id=b%32-1-- Block id
+ if id>26 then return end-- Illegal blockid
+ b=int(b/32)-- Mode id
F[fY][fX]=id
if fX<10 then
fX=fX+1
else
fY=fY+1
- if fY>20 then break end
+ if fY>60 then break end
fX=1
end
p=p+1
@@ -158,7 +158,7 @@ function DATA.copyMission()
local count=1
for i=1,#MISSION+1 do
- if MISSION[i+1]~=MISSION[i]or count==13 then
+ if MISSION[i+1]~=MISSION[i] or count==13 then
_=33+MISSION[i]
str=str..char(_)
if count>1 then
@@ -186,7 +186,7 @@ function DATA.pasteMission(str)
end
else
if b>=34 and b<=114 then
- if ENUM_MISSION[reg]then
+ if ENUM_MISSION[reg] then
ins(MISSION,reg)
reg=b-33
else
@@ -211,8 +211,8 @@ function DATA.copyQuestArgs()
local ENV=CUSTOMENV
local str=""..
ENV.holdCount..
- (ENV.ospin and"O"or"Z")..
- (ENV.missionKill and"M"or"Z")..
+ (ENV.ospin and "O" or "Z")..
+ (ENV.missionKill and "M" or "Z")..
ENV.sequence
return str
end
@@ -252,15 +252,15 @@ function DATA.dumpRecording(list,ptr)
local out=""
local buffer,buffer2=""
if not ptr then ptr=1 end
- local prevFrm=list[ptr-2]or 0
- while list[ptr]do
- --Flush buffer
+ local prevFrm=list[ptr-2] or 0
+ while list[ptr] do
+ -- Flush buffer
if #buffer>10 then
out=out..buffer
buffer=""
end
- --Encode time
+ -- Encode time
local t=list[ptr]-prevFrm
prevFrm=list[ptr]
if t>=128 then
@@ -275,7 +275,7 @@ function DATA.dumpRecording(list,ptr)
buffer=buffer..char(t)
end
- --Encode event
+ -- Encode event
t=list[ptr+1]
if t>=128 then
buffer2=char(t%128)
@@ -289,7 +289,7 @@ function DATA.dumpRecording(list,ptr)
buffer=buffer..char(t)
end
- --Step
+ -- Step
ptr=ptr+2
end
return out..buffer,ptr
@@ -298,10 +298,10 @@ function DATA.pumpRecording(str,L)
local len=#str
local p=1
- local curFrm=L[#L-1]or 0
+ local curFrm=L[#L-1] or 0
local code
while p<=len do
- --Read delta time
+ -- Read delta time
code=0
local b=byte(str,p)
while b>=128 do
@@ -324,7 +324,7 @@ function DATA.pumpRecording(str,L)
p=p+1
end
end
-do--function DATA.saveReplay()
+do-- function DATA.saveReplay()
local noRecList={"custom","solo","round","techmino"}
local function _getModList()
local res={}
@@ -336,17 +336,17 @@ do--function DATA.saveReplay()
return res
end
function DATA.saveReplay()
- --Filtering modes that cannot be saved
+ -- Filtering modes that cannot be saved
for _,v in next,noRecList do
- if GAME.curModeName:find(v)then
+ if GAME.curModeName:find(v) then
MES.new('error',"Cannot save recording of this mode now!")
return
end
end
- --Write file
+ -- Write file
local fileName=os.date("replay/%Y_%m_%d_%H%M%S.rep")
- if not love.filesystem.getInfo(fileName)then
+ if not love.filesystem.getInfo(fileName) then
love.filesystem.write(fileName,
love.data.compress('string','zlib',
JSON.encode{
@@ -371,29 +371,33 @@ do--function DATA.saveReplay()
end
function DATA.parseReplay(fileName,ifFull)
local fileData
- --Read file
+ -- Read file
fileData=love.filesystem.read(fileName)
return DATA.parseReplayData(fileName,fileData,ifFull)
end
function DATA.parseReplayData(fileName,fileData,ifFull)
- local success,metaData,rep
+ local success,metaData
+ local rep={-- unavailable replay object
+ fileName=fileName,
+ available=false,
+ }
- if not(fileData and #fileData>0)then goto BREAK_cannotParse end
+ if not (fileData and #fileData>0) then return rep end-- goto BREAK_cannotParse
- --Decompress file
+ -- Decompress file
success,fileData=pcall(love.data.decompress,'string','zlib',fileData)
- if not success then goto BREAK_cannotParse end
+ if not success then return rep end-- goto BREAK_cannotParse
- --Load metadata
+ -- Load metadata
metaData,fileData=STRING.readLine(fileData)
metaData=JSON.decode(metaData)
- if not metaData then goto BREAK_cannotParse end
+ if not metaData then return rep end-- goto BREAK_cannotParse
- --Convert ancient replays
- metaData.mode=MODE_UPDATE_MAP[metaData.mode]or metaData.mode
- if not MODES[metaData.mode]then goto BREAK_cannotParse end
+ -- Convert ancient replays
+ metaData.mode=MODE_UPDATE_MAP[metaData.mode] or metaData.mode
+ if not MODES[metaData.mode] then return rep end-- goto BREAK_cannotParse
- --Create replay object
+ -- Create replay object
rep={
fileName=fileName,
available=true,
@@ -409,13 +413,6 @@ function DATA.parseReplayData(fileName,fileData,ifFull)
tasUsed=metaData.tasUsed,
}
if ifFull then rep.data=fileData end
- do return rep end
-
- --Create unavailable replay object
- ::BREAK_cannotParse::
- return{
- fileName=fileName,
- available=false,
- }
+ return rep
end
return DATA
diff --git a/parts/eventsets/attacker_h.lua b/parts/eventsets/attacker_h.lua
index 06c88544a..fa2efa3fd 100644
--- a/parts/eventsets/attacker_h.lua
+++ b/parts/eventsets/attacker_h.lua
@@ -1,25 +1,25 @@
-return{
+return {
mesDisp=function(P)
setFont(55)
- mStr(P.modeData.wave,63,200)
- mStr("22",63,320)
+ GC.mStr(P.modeData.wave,63,200)
+ GC.mStr("22",63,320)
mText(TEXTOBJ.wave,63,260)
mText(TEXTOBJ.nextWave,63,380)
end,
task=function(P)
while true do
- YIELD()
+ coroutine.yield()
if P.control and P.atkBufferSum==0 then
local D=P.modeData
if D.wave==50 then
P:win('finish')
else
if D.wave<20 then
- local t=1500-30*D.wave--1500~900
+ local t=1500-30*D.wave-- 1500~900
table.insert(P.atkBuffer,{line=generateLine(P.holeRND:random(4,7)),amount=12,countdown=t,cd0=t,time=0,sent=false,lv=3})
table.insert(P.atkBuffer,{line=generateLine(P.holeRND:random(3,8)),amount=10,countdown=t,cd0=t,time=0,sent=false,lv=4})
else
- local t=900-10*(D.wave-20)--900~600
+ local t=900-10*(D.wave-20)-- 900~600
table.insert(P.atkBuffer,{line=generateLine(P.holeRND:random(10)),amount=14,countdown=t,cd0=t,time=0,sent=false,lv=4})
table.insert(P.atkBuffer,{line=generateLine(P.holeRND:random(4,7)),amount=8,countdown=t,cd0=t,time=0,sent=false,lv=5})
end
diff --git a/parts/eventsets/attacker_u.lua b/parts/eventsets/attacker_u.lua
index b59da766b..307ba42aa 100644
--- a/parts/eventsets/attacker_u.lua
+++ b/parts/eventsets/attacker_u.lua
@@ -1,21 +1,21 @@
-return{
+return {
mesDisp=function(P)
setFont(55)
- mStr(P.modeData.wave,63,200)
- mStr(20+4*math.min(math.floor(P.modeData.wave/10),2),63,320)
+ GC.mStr(P.modeData.wave,63,200)
+ GC.mStr(20+4*math.min(math.floor(P.modeData.wave/10),2),63,320)
mText(TEXTOBJ.wave,63,260)
mText(TEXTOBJ.nextWave,63,380)
end,
task=function(P)
while true do
- YIELD()
+ coroutine.yield()
if P.control and P.atkBufferSum<4 then
local D=P.modeData
if D.wave==50 then
P:win('finish')
else
local s
- local t=800-10*D.wave--800~700~600~500
+ local t=800-10*D.wave-- 800~700~600~500
if D.wave<10 then
table.insert(P.atkBuffer,{line=generateLine(P.holeRND:random(5,6)),amount=9,countdown=t,cd0=t,time=0,sent=false,lv=3})
table.insert(P.atkBuffer,{line=generateLine(P.holeRND:random(4,7)),amount=11,countdown=t,cd0=t+62,time=0,sent=false,lv=4})
diff --git a/parts/eventsets/backfire_0.lua b/parts/eventsets/backfire_0.lua
index 8c4a012cc..621df23d9 100644
--- a/parts/eventsets/backfire_0.lua
+++ b/parts/eventsets/backfire_0.lua
@@ -1,4 +1,4 @@
-return{
+return {
hook_drop=function(P)
if P.lastPiece.atk>0 then
P:receive(nil,P.lastPiece.atk,0,generateLine(P.holeRND:random(10)))
diff --git a/parts/eventsets/backfire_120.lua b/parts/eventsets/backfire_120.lua
index 4a284a48a..639cf3b70 100644
--- a/parts/eventsets/backfire_120.lua
+++ b/parts/eventsets/backfire_120.lua
@@ -1,4 +1,4 @@
-return{
+return {
hook_drop=function(P)
if P.lastPiece.atk>0 then
P:receive(nil,P.lastPiece.atk,120,generateLine(P.holeRND:random(10)))
diff --git a/parts/eventsets/backfire_30.lua b/parts/eventsets/backfire_30.lua
index bb949c4af..4ae0feb81 100644
--- a/parts/eventsets/backfire_30.lua
+++ b/parts/eventsets/backfire_30.lua
@@ -1,4 +1,4 @@
-return{
+return {
hook_drop=function(P)
if P.lastPiece.atk>0 then
P:receive(nil,P.lastPiece.atk,30,generateLine(P.holeRND:random(10)))
diff --git a/parts/eventsets/backfire_60.lua b/parts/eventsets/backfire_60.lua
index 22e7ff042..617fd6243 100644
--- a/parts/eventsets/backfire_60.lua
+++ b/parts/eventsets/backfire_60.lua
@@ -1,4 +1,4 @@
-return{
+return {
hook_drop=function(P)
if P.lastPiece.atk>0 then
P:receive(nil,P.lastPiece.atk,60,generateLine(P.holeRND:random(10)))
diff --git a/parts/eventsets/bigWallGen.lua b/parts/eventsets/bigWallGen.lua
index 072406732..a70051117 100644
--- a/parts/eventsets/bigWallGen.lua
+++ b/parts/eventsets/bigWallGen.lua
@@ -1,4 +1,4 @@
-return{
+return {
hook_drop=function(P)
if P.lastPiece.row>0 then
for _=1,#P.clearedRow do
diff --git a/parts/eventsets/blindMesDisp.lua b/parts/eventsets/blindMesDisp.lua
index 2dae20072..ecde9fc0c 100644
--- a/parts/eventsets/blindMesDisp.lua
+++ b/parts/eventsets/blindMesDisp.lua
@@ -1,13 +1,11 @@
-local gc=love.graphics
-
-return{
+return {
mesDisp=function(P)
mText(TEXTOBJ.techrash,63,420)
setFont(75)
- mStr(P.stat.clears[4],63,340)
+ GC.mStr(P.stat.clears[4],63,340)
PLY.draw.applyField(P)
- gc.setColor(1,1,1,.1)
- gc.draw(IMG.electric,0,106,0,2.6)
- PLY.draw.cancelField(P)
+ GC.setColor(1,1,1,.1)
+ GC.draw(IMG.electric,0,106,0,2.6)
+ PLY.draw.cancelField()
end,
}
diff --git a/parts/eventsets/c4wBase.lua b/parts/eventsets/c4wBase.lua
index 15fa311a3..3d88cab06 100644
--- a/parts/eventsets/c4wBase.lua
+++ b/parts/eventsets/c4wBase.lua
@@ -1,10 +1,10 @@
local rem=table.remove
-return{
+return {
mesDisp=function(P)
setFont(45)
- mStr(P.combo,63,310)
- mStr(P.modeData.maxCombo,63,400)
+ GC.mStr(P.combo,63,310)
+ GC.mStr(P.modeData.maxCombo,63,400)
mText(TEXTOBJ.combo,63,358)
mText(TEXTOBJ.maxcmb,63,450)
end,
diff --git a/parts/eventsets/c4wCheck_easy.lua b/parts/eventsets/c4wCheck_easy.lua
index 5f81dd243..2058cf8d2 100644
--- a/parts/eventsets/c4wCheck_easy.lua
+++ b/parts/eventsets/c4wCheck_easy.lua
@@ -1,4 +1,4 @@
-return{
+return {
hook_drop=function(P)
if P.lastPiece.row>0 then
for _=1,#P.clearedRow do
diff --git a/parts/eventsets/c4wCheck_hard.lua b/parts/eventsets/c4wCheck_hard.lua
index e2ecc4d88..ac31d3e8c 100644
--- a/parts/eventsets/c4wCheck_hard.lua
+++ b/parts/eventsets/c4wCheck_hard.lua
@@ -1,4 +1,4 @@
-return{
+return {
hook_drop=function(P)
if P.lastPiece.row==0 then
P:lose()
diff --git a/parts/eventsets/checkAttack_100.lua b/parts/eventsets/checkAttack_100.lua
index e112a2c7d..4c7c789a5 100644
--- a/parts/eventsets/checkAttack_100.lua
+++ b/parts/eventsets/checkAttack_100.lua
@@ -1,8 +1,8 @@
-return{
+return {
mesDisp=function(P)
setFont(45)
- mStr(("%.1f"):format(P.stat.atk),63,190)
- mStr(("%.2f"):format(P.stat.atk/P.stat.row),63,310)
+ GC.mStr(("%d"):format(P.stat.atk),63,190)
+ GC.mStr(("%.2f"):format(P.stat.atk/P.stat.row),63,310)
mText(TEXTOBJ.atk,63,243)
mText(TEXTOBJ.eff,63,363)
end,
diff --git a/parts/eventsets/checkClearBoard.lua b/parts/eventsets/checkClearBoard.lua
index ea51a2c98..a6016c77d 100644
--- a/parts/eventsets/checkClearBoard.lua
+++ b/parts/eventsets/checkClearBoard.lua
@@ -1,9 +1,9 @@
-return{
+return {
hook_drop=function(P)
if P.garbageBeneath==0 then
local D=P.modeData
D.finished=D.finished+1
- if FIELD[D.finished+1]then
+ if FIELD[D.finished+1] then
P.waiting=26
for i=#P.field,1,-1 do
P.field[i],P.visTime[i]=nil
diff --git a/parts/eventsets/checkLine_10.lua b/parts/eventsets/checkLine_10.lua
index 02edb80a0..06dc16757 100644
--- a/parts/eventsets/checkLine_10.lua
+++ b/parts/eventsets/checkLine_10.lua
@@ -1,9 +1,9 @@
-return{
+return {
mesDisp=function(P)
setFont(55)
local r=10-P.stat.row
if r<0 then r=0 end
- mStr(r,63,265)
+ GC.mStr(r,63,265)
PLY.draw.drawTargetLine(P,r)
end,
hook_drop=function(P)
diff --git a/parts/eventsets/checkLine_100.lua b/parts/eventsets/checkLine_100.lua
index 2c6bef5cc..61e4e63bf 100644
--- a/parts/eventsets/checkLine_100.lua
+++ b/parts/eventsets/checkLine_100.lua
@@ -1,9 +1,9 @@
-return{
+return {
mesDisp=function(P)
setFont(55)
local r=100-P.stat.row
if r<0 then r=0 end
- mStr(r,63,265)
+ GC.mStr(r,63,265)
PLY.draw.drawTargetLine(P,r)
end,
hook_drop=function(P)
diff --git a/parts/eventsets/checkLine_1000.lua b/parts/eventsets/checkLine_1000.lua
index c1321251b..8a515f783 100644
--- a/parts/eventsets/checkLine_1000.lua
+++ b/parts/eventsets/checkLine_1000.lua
@@ -1,9 +1,9 @@
-return{
+return {
mesDisp=function(P)
setFont(55)
local r=1000-P.stat.row
if r<0 then r=0 end
- mStr(r,63,265)
+ GC.mStr(r,63,265)
PLY.draw.drawTargetLine(P,r)
end,
hook_drop=function(P)
diff --git a/parts/eventsets/checkLine_20.lua b/parts/eventsets/checkLine_20.lua
index d901ec8d2..a135bc40b 100644
--- a/parts/eventsets/checkLine_20.lua
+++ b/parts/eventsets/checkLine_20.lua
@@ -1,9 +1,9 @@
-return{
+return {
mesDisp=function(P)
setFont(55)
local r=20-P.stat.row
if r<0 then r=0 end
- mStr(r,63,265)
+ GC.mStr(r,63,265)
PLY.draw.drawTargetLine(P,r)
end,
hook_drop=function(P)
diff --git a/parts/eventsets/checkLine_200.lua b/parts/eventsets/checkLine_200.lua
index e75128970..8edb41c57 100644
--- a/parts/eventsets/checkLine_200.lua
+++ b/parts/eventsets/checkLine_200.lua
@@ -1,9 +1,9 @@
-return{
+return {
mesDisp=function(P)
setFont(55)
local r=200-P.stat.row
if r<0 then r=0 end
- mStr(r,63,265)
+ GC.mStr(r,63,265)
PLY.draw.drawTargetLine(P,r)
end,
hook_drop=function(P)
diff --git a/parts/eventsets/checkLine_40.lua b/parts/eventsets/checkLine_40.lua
index bd8f2956a..a5a62e4bc 100644
--- a/parts/eventsets/checkLine_40.lua
+++ b/parts/eventsets/checkLine_40.lua
@@ -1,9 +1,9 @@
-return{
+return {
mesDisp=function(P)
setFont(55)
local r=40-P.stat.row
if r<0 then r=0 end
- mStr(r,63,265)
+ GC.mStr(r,63,265)
PLY.draw.drawTargetLine(P,r)
end,
hook_drop=function(P)
diff --git a/parts/eventsets/checkLine_400.lua b/parts/eventsets/checkLine_400.lua
index 3457f3c56..852c69b92 100644
--- a/parts/eventsets/checkLine_400.lua
+++ b/parts/eventsets/checkLine_400.lua
@@ -1,9 +1,9 @@
-return{
+return {
mesDisp=function(P)
setFont(55)
local r=400-P.stat.row
if r<0 then r=0 end
- mStr(r,63,265)
+ GC.mStr(r,63,265)
PLY.draw.drawTargetLine(P,r)
end,
hook_drop=function(P)
diff --git a/parts/eventsets/checkTurn_1.lua b/parts/eventsets/checkTurn_1.lua
index c0ca5c3f0..8f96769b6 100644
--- a/parts/eventsets/checkTurn_1.lua
+++ b/parts/eventsets/checkTurn_1.lua
@@ -1,4 +1,4 @@
-return{
+return {
hook_drop=function(P)
if #PLY_ALIVE>1 then
P.control=false
@@ -13,7 +13,7 @@ return{
end
end
for i=1,#PLY_ALIVE do
- if PLY_ALIVE[i].sid==(minMaxID==1e99 and minID or minMaxID)then
+ if PLY_ALIVE[i].sid==(minMaxID==1e99 and minID or minMaxID) then
PLY_ALIVE[i].control=true
return
end
diff --git a/parts/eventsets/checkTurn_7.lua b/parts/eventsets/checkTurn_7.lua
index bf0ce2d75..d44d326fd 100644
--- a/parts/eventsets/checkTurn_7.lua
+++ b/parts/eventsets/checkTurn_7.lua
@@ -1,4 +1,4 @@
-return{
+return {
hook_drop=function(P)
if P.stat.piece%7==0 and #PLY_ALIVE>1 then
P.control=false
@@ -13,7 +13,7 @@ return{
end
end
for i=1,#PLY_ALIVE do
- if PLY_ALIVE[i].sid==(minMaxID==1e99 and minID or minMaxID)then
+ if PLY_ALIVE[i].sid==(minMaxID==1e99 and minID or minMaxID) then
PLY_ALIVE[i].control=true
return
end
diff --git a/parts/eventsets/classic_e.lua b/parts/eventsets/classic_e.lua
index 483149bad..fc45ff67f 100644
--- a/parts/eventsets/classic_e.lua
+++ b/parts/eventsets/classic_e.lua
@@ -1,5 +1,29 @@
-local gc_setColor=love.graphics.setColor
-return{
+local function GetLevelStr(lvl)
+ local list={"01","02","03","04","05","06","07","08","09","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","00","0A","14","1E","28","32","3C","46","50","5A","64","6E","78","82","8C","96","A0","AA","B4","BE","C6","20","E6","20","06","21","26","21","46","21","66","21","86","21","A6","21","C6","21","E6","21","06","22","26","22","46","22","66","22","86","22","A6","22","C6","22","E6","22","06","23","26","23","85","A8","29","F0","4A","4A","4A","4A","8D","07","20","A5","A8","29","0F","8D","07","20","60","A6","49","E0","15","10","53","BD","D6","96","A8","8A","0A","AA","E8","BD","EA","96","8D","06","20","CA","A5","BE","C9","01","F0","1E","A5","B9","C9","05","F0","0C","BD","EA","96","38","E9","02","8D","06","20","4C","67","97","BD","EA","96","18","69","0C","8D","06","20","4C","67","97","BD","EA","96","18","69","06","8D","06","20","A2","0A","B1","B8","8D","07","20","C8","CA","D0","F7","E6","49","A5","49","C9","14","30","04","A9","20","85","49","60","A5","B1","29","03","D0","78","A9","00","85","AA","A6","AA","B5","4A","F0","5C","0A","A8","B9","EA","96","85","A8","A5","BE","C9","01","D0","0A","A5","A8","18","69","06","85","A8","4C","BD","97","A5","B9","C9","04","D0","0A","A5","A8","38","E9","02","85","A8","4C","BD","97","A5","A8"}
+ list[0]="00"
+ lvl=lvl%256
+ return list[lvl]
+end
+local function GetGravity(lvl)
+ lvl=lvl%256
+ return
+ lvl==0 and 48 or
+ lvl==1 and 43 or
+ lvl==2 and 38 or
+ lvl==3 and 33 or
+ lvl==4 and 28 or
+ lvl==5 and 23 or
+ lvl==6 and 18 or
+ lvl==7 and 13 or
+ lvl==8 and 8 or
+ lvl==9 and 6 or
+ lvl<13 and 5 or
+ lvl<16 and 4 or
+ lvl<19 and 3 or
+ lvl<29 and 2 or
+ 1
+end
+return {
das=16,arr=6,
sddas=6,sdarr=6,
irs=false,ims=false,
@@ -15,44 +39,38 @@ return{
keyCancel={5,6},
mesDisp=function(P)
setFont(75)
- local r=P.modeData.target/10
- mStr(r<10 and 9 or r<30 and r or("%02x"):format(r*10-300),63,210)
+ GC.mStr(GetLevelStr(P.modeData.lvl),63,210)
mText(TEXTOBJ.speedLV,63,290)
PLY.draw.drawProgress(P.stat.row,P.modeData.target)
if P.modeData.drought>7 then
if P.modeData.drought<=14 then
- gc_setColor(1,1,1,P.modeData.drought/7-1)
+ GC.setColor(1,1,1,P.modeData.drought/7-1)
else
local gb=P.modeData.drought<=21 and 2-P.modeData.drought/14 or .5
- gc_setColor(1,gb,gb)
+ GC.setColor(1,gb,gb)
end
setFont(50)
- mStr(P.modeData.drought,63,130)
+ GC.mStr(P.modeData.drought,63,130)
mDraw(MODES.drought_l.icon,63,200,nil,.5)
end
end,
task=function(P)
+ P.modeData.lvl=9
P.modeData.target=10
end,
hook_drop=function(P)
local D=P.modeData
D.drought=P.lastPiece.id==7 and 0 or D.drought+1
if P.stat.row>=D.target then
- if D.target==110 then
- P.gameEnv.drop,P.gameEnv.lock=5,5
- P.gameEnv.sddas,P.gameEnv.sdarr=5,5
- SFX.play('warn_2',.7)
- elseif D.target==140 then
- P.gameEnv.drop,P.gameEnv.lock=4,4
- P.gameEnv.sddas,P.gameEnv.sdarr=4,4
- SFX.play('warn_2',.7)
- elseif D.target==170 then
- P.gameEnv.drop,P.gameEnv.lock=3,3
- P.gameEnv.sddas,P.gameEnv.sdarr=3,3
+ if D.target>=100 then
+ D.lvl=D.lvl+1
+ end
+ local dropSpd=GetGravity(D.lvl)
+ if D.target==200 then P:win('finish') return
+ elseif dropSpd~=P.gameEnv.drop then
+ P.gameEnv.drop,P.gameEnv.lock=dropSpd,dropSpd
+ P.gameEnv.sddas,P.gameEnv.sdarr=dropSpd,dropSpd
SFX.play('warn_2',.7)
- elseif D.target==200 then
- P:win('finish')
- return
else
SFX.play('reach')
end
diff --git a/parts/eventsets/classic_h.lua b/parts/eventsets/classic_h.lua
index a4157e95a..be1ebb52f 100644
--- a/parts/eventsets/classic_h.lua
+++ b/parts/eventsets/classic_h.lua
@@ -1,5 +1,29 @@
-local gc_setColor=love.graphics.setColor
-return{
+local function GetLevelStr(lvl)
+ local list={"01","02","03","04","05","06","07","08","09","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","00","0A","14","1E","28","32","3C","46","50","5A","64","6E","78","82","8C","96","A0","AA","B4","BE","C6","20","E6","20","06","21","26","21","46","21","66","21","86","21","A6","21","C6","21","E6","21","06","22","26","22","46","22","66","22","86","22","A6","22","C6","22","E6","22","06","23","26","23","85","A8","29","F0","4A","4A","4A","4A","8D","07","20","A5","A8","29","0F","8D","07","20","60","A6","49","E0","15","10","53","BD","D6","96","A8","8A","0A","AA","E8","BD","EA","96","8D","06","20","CA","A5","BE","C9","01","F0","1E","A5","B9","C9","05","F0","0C","BD","EA","96","38","E9","02","8D","06","20","4C","67","97","BD","EA","96","18","69","0C","8D","06","20","4C","67","97","BD","EA","96","18","69","06","8D","06","20","A2","0A","B1","B8","8D","07","20","C8","CA","D0","F7","E6","49","A5","49","C9","14","30","04","A9","20","85","49","60","A5","B1","29","03","D0","78","A9","00","85","AA","A6","AA","B5","4A","F0","5C","0A","A8","B9","EA","96","85","A8","A5","BE","C9","01","D0","0A","A5","A8","18","69","06","85","A8","4C","BD","97","A5","B9","C9","04","D0","0A","A5","A8","38","E9","02","85","A8","4C","BD","97","A5","A8"}
+ list[0]="00"
+ lvl=lvl%256
+ return list[lvl]
+end
+local function GetGravity(lvl)
+ lvl=lvl%256
+ return
+ lvl==0 and 48 or
+ lvl==1 and 43 or
+ lvl==2 and 38 or
+ lvl==3 and 33 or
+ lvl==4 and 28 or
+ lvl==5 and 23 or
+ lvl==6 and 18 or
+ lvl==7 and 13 or
+ lvl==8 and 8 or
+ lvl==9 and 6 or
+ lvl<13 and 5 or
+ lvl<16 and 4 or
+ lvl<19 and 3 or
+ lvl<29 and 2 or
+ 1
+end
+return {
das=16,arr=6,
sddas=3,sdarr=3,
irs=false,ims=false,
@@ -15,36 +39,38 @@ return{
keyCancel={5,6},
mesDisp=function(P)
setFont(75)
- local r=P.modeData.target/10
- mStr(r<11 and 18 or r<22 and r+8 or("%02x"):format(r*10-220),63,210)
+ GC.mStr(GetLevelStr(P.modeData.lvl),63,210)
mText(TEXTOBJ.speedLV,63,290)
PLY.draw.drawProgress(P.stat.row,P.modeData.target)
if P.modeData.drought>7 then
if P.modeData.drought<=14 then
- gc_setColor(1,1,1,P.modeData.drought/7-1)
+ GC.setColor(1,1,1,P.modeData.drought/7-1)
else
local gb=P.modeData.drought<=21 and 2-P.modeData.drought/14 or .5
- gc_setColor(1,gb,gb)
+ GC.setColor(1,gb,gb)
end
setFont(50)
- mStr(P.modeData.drought,63,130)
+ GC.mStr(P.modeData.drought,63,130)
mDraw(MODES.drought_l.icon,63,200,nil,.5)
end
end,
task=function(P)
+ P.modeData.lvl=18
P.modeData.target=10
end,
hook_drop=function(P)
local D=P.modeData
D.drought=P.lastPiece.id==7 and 0 or D.drought+1
if P.stat.row>=D.target then
- if D.target==110 then
- P.gameEnv.drop,P.gameEnv.lock=2,2
- P.gameEnv.sddas,P.gameEnv.sdarr=2,2
+ if D.target>=100 then
+ D.lvl=D.lvl+1
+ end
+ local dropSpd=GetGravity(D.lvl)
+ if D.target==200 then P:win('finish') return
+ elseif dropSpd~=P.gameEnv.drop then
+ P.gameEnv.drop,P.gameEnv.lock=dropSpd,dropSpd
+ P.gameEnv.sddas,P.gameEnv.sdarr=dropSpd,dropSpd
SFX.play('warn_1')
- elseif D.target==200 then
- P:win('finish')
- return
else
SFX.play('reach')
end
diff --git a/parts/eventsets/classic_l.lua b/parts/eventsets/classic_l.lua
new file mode 100644
index 000000000..a2d2f1767
--- /dev/null
+++ b/parts/eventsets/classic_l.lua
@@ -0,0 +1,79 @@
+local function GetLevelStr(lvl)
+ local list={"01","02","03","04","05","06","07","08","09","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","00","0A","14","1E","28","32","3C","46","50","5A","64","6E","78","82","8C","96","A0","AA","B4","BE","C6","20","E6","20","06","21","26","21","46","21","66","21","86","21","A6","21","C6","21","E6","21","06","22","26","22","46","22","66","22","86","22","A6","22","C6","22","E6","22","06","23","26","23","85","A8","29","F0","4A","4A","4A","4A","8D","07","20","A5","A8","29","0F","8D","07","20","60","A6","49","E0","15","10","53","BD","D6","96","A8","8A","0A","AA","E8","BD","EA","96","8D","06","20","CA","A5","BE","C9","01","F0","1E","A5","B9","C9","05","F0","0C","BD","EA","96","38","E9","02","8D","06","20","4C","67","97","BD","EA","96","18","69","0C","8D","06","20","4C","67","97","BD","EA","96","18","69","06","8D","06","20","A2","0A","B1","B8","8D","07","20","C8","CA","D0","F7","E6","49","A5","49","C9","14","30","04","A9","20","85","49","60","A5","B1","29","03","D0","78","A9","00","85","AA","A6","AA","B5","4A","F0","5C","0A","A8","B9","EA","96","85","A8","A5","BE","C9","01","D0","0A","A5","A8","18","69","06","85","A8","4C","BD","97","A5","B9","C9","04","D0","0A","A5","A8","38","E9","02","85","A8","4C","BD","97","A5","A8"}
+ list[0]="00"
+ lvl=lvl%256
+ return list[lvl]
+end
+local function GetGravity(lvl)
+ lvl=lvl%256
+ return
+ lvl==0 and 48 or
+ lvl==1 and 43 or
+ lvl==2 and 38 or
+ lvl==3 and 33 or
+ lvl==4 and 28 or
+ lvl==5 and 23 or
+ lvl==6 and 18 or
+ lvl==7 and 13 or
+ lvl==8 and 8 or
+ lvl==9 and 6 or
+ lvl<13 and 5 or
+ lvl<16 and 4 or
+ lvl<19 and 3 or
+ lvl<29 and 2 or
+ 1
+end
+return {
+ das=16,arr=6,
+ sddas=2,sdarr=2,
+ irs=false,ims=false,
+ drop=2,lock=2,
+ wait=10,fall=25,
+ freshLimit=0,
+ fieldH=19,
+ nextCount=1,
+ holdCount=0,
+ RS='Classic',
+ sequence='rnd',
+ noTele=true,
+ keyCancel={5,6},
+ mesDisp=function(P)
+ setFont(75)
+ GC.mStr(GetLevelStr(P.modeData.lvl),63,210)
+ mText(TEXTOBJ.speedLV,63,290)
+ PLY.draw.drawProgress(P.stat.row,P.modeData.target)
+ if P.modeData.drought>7 then
+ if P.modeData.drought<=14 then
+ GC.setColor(1,1,1,P.modeData.drought/7-1)
+ else
+ local gb=P.modeData.drought<=21 and 2-P.modeData.drought/14 or .5
+ GC.setColor(1,gb,gb)
+ end
+ setFont(50)
+ GC.mStr(P.modeData.drought,63,130)
+ mDraw(MODES.drought_l.icon,63,200,nil,.5)
+ end
+ end,
+ task=function(P)
+ P.modeData.lvl=19
+ P.modeData.target=10
+ end,
+ hook_drop=function(P)
+ local D=P.modeData
+ D.drought=P.lastPiece.id==7 and 0 or D.drought+1
+ if P.stat.row>=D.target then
+ if D.target>=100 then
+ D.lvl=D.lvl+1
+ end
+ local dropSpd=GetGravity(D.lvl)
+ if dropSpd~=P.gameEnv.drop then
+ P.gameEnv.drop,P.gameEnv.lock=dropSpd,dropSpd
+ P.gameEnv.sddas,P.gameEnv.sdarr=dropSpd,dropSpd
+ SFX.play('warn_1')
+ else
+ SFX.play('reach')
+ end
+ D.target=D.target+10
+ end
+ end
+}
diff --git a/parts/eventsets/classic_u.lua b/parts/eventsets/classic_u.lua
index 31edc74f3..f6c9d14e8 100644
--- a/parts/eventsets/classic_u.lua
+++ b/parts/eventsets/classic_u.lua
@@ -1,5 +1,10 @@
-local gc_setColor=love.graphics.setColor
-return{
+local function GetLevelStr(lvl)
+ local list={"01","02","03","04","05","06","07","08","09","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","00","0A","14","1E","28","32","3C","46","50","5A","64","6E","78","82","8C","96","A0","AA","B4","BE","C6","20","E6","20","06","21","26","21","46","21","66","21","86","21","A6","21","C6","21","E6","21","06","22","26","22","46","22","66","22","86","22","A6","22","C6","22","E6","22","06","23","26","23","85","A8","29","F0","4A","4A","4A","4A","8D","07","20","A5","A8","29","0F","8D","07","20","60","A6","49","E0","15","10","53","BD","D6","96","A8","8A","0A","AA","E8","BD","EA","96","8D","06","20","CA","A5","BE","C9","01","F0","1E","A5","B9","C9","05","F0","0C","BD","EA","96","38","E9","02","8D","06","20","4C","67","97","BD","EA","96","18","69","0C","8D","06","20","4C","67","97","BD","EA","96","18","69","06","8D","06","20","A2","0A","B1","B8","8D","07","20","C8","CA","D0","F7","E6","49","A5","49","C9","14","30","04","A9","20","85","49","60","A5","B1","29","03","D0","78","A9","00","85","AA","A6","AA","B5","4A","F0","5C","0A","A8","B9","EA","96","85","A8","A5","BE","C9","01","D0","0A","A5","A8","18","69","06","85","A8","4C","BD","97","A5","B9","C9","04","D0","0A","A5","A8","38","E9","02","85","A8","4C","BD","97","A5","A8"}
+ list[0]="00"
+ lvl=lvl%256
+ return list[lvl]
+end
+return {
das=16,arr=6,
sddas=1,sdarr=1,
irs=false,ims=false,
@@ -15,35 +20,33 @@ return{
keyCancel={5,6},
mesDisp=function(P)
setFont(75)
- local r=P.modeData.target/10
- mStr(r==1 and 29 or("%02x"):format(r*10-20),63,210)
+ GC.mStr(GetLevelStr(P.modeData.lvl),63,210)
mText(TEXTOBJ.speedLV,63,290)
PLY.draw.drawProgress(P.stat.row,P.modeData.target)
if P.modeData.drought>7 then
if P.modeData.drought<=14 then
- gc_setColor(1,1,1,P.modeData.drought/7-1)
+ GC.setColor(1,1,1,P.modeData.drought/7-1)
else
local gb=P.modeData.drought<=21 and 2-P.modeData.drought/14 or .5
- gc_setColor(1,gb,gb)
+ GC.setColor(1,gb,gb)
end
setFont(50)
- mStr(P.modeData.drought,63,130)
+ GC.mStr(P.modeData.drought,63,130)
mDraw(MODES.drought_l.icon,63,200,nil,.5)
end
end,
task=function(P)
+ P.modeData.lvl=29
P.modeData.target=10
end,
hook_drop=function(P)
local D=P.modeData
D.drought=P.lastPiece.id==7 and 0 or D.drought+1
if P.stat.row>=D.target then
- if D.target==100 then
- P:win('finish')
- return
- end
- D.target=D.target+10
+ if D.target>=200 then P:win('finish') return end
SFX.play('reach')
+ D.lvl=D.lvl+1
+ D.target=D.target+10
end
end,
}
diff --git a/parts/eventsets/clearRush.lua b/parts/eventsets/clearRush.lua
deleted file mode 100644
index 21ce0dfba..000000000
--- a/parts/eventsets/clearRush.lua
+++ /dev/null
@@ -1,36 +0,0 @@
-local function task_newBoard(P,init)
- local targetLine
- local F,L={},{1}
- --TODO
- P:pushNextList(L)
-
- P.control=false
- if not init then for _=1,26 do YIELD()end end
- P.control=true
-
- P.gameEnv.heightLimit=targetLine or #F
- P:pushLineList(F)
-end
-local function _check(P)
- P.gameEnv.heightLimit=P.gameEnv.heightLimit-P.lastPiece.row
- if P.gameEnv.heightLimit==0 then
- P.modeData.stage=P.modeData.stage+1
- if P.modeData.stage>=100 then
- P:win('finish')
- else
- P:newTask(task_newBoard)
- end
- end
-end
-return{
- sequence='none',
- RS="TRS",
- pushSpeed=5,
- mesDisp=function(P)
- setFont(60)
- mStr(P.modeData.stage,63,280)
- mText(TEXTOBJ.wave,63,350)
- end,
- hook_drop=_check,
- task=function(P)task_newBoard(P,true)P.fieldBeneath=0 end,--Just run one time at first to start first level
-}
diff --git a/parts/eventsets/defender_l.lua b/parts/eventsets/defender_l.lua
index a27b537de..061f00e2b 100644
--- a/parts/eventsets/defender_l.lua
+++ b/parts/eventsets/defender_l.lua
@@ -1,46 +1,48 @@
-return{
+return {
drop=5,lock=60,
fall=6,
mesDisp=function(P)
setFont(55)
- mStr(P.modeData.wave,63,200)
- mStr(P.modeData.rpm,63,320)
+ GC.mStr(P.modeData.wave,63,200)
+ GC.mStr(P.modeData.rpm,63,320)
mText(TEXTOBJ.wave,63,260)
mText(TEXTOBJ.rpm,63,380)
end,
task=function(P)
while true do
- YIELD()
+ coroutine.yield()
if P.control then
local D=P.modeData
- D.counter=D.counter+1
- local t=
- D.wave<=60 and 240-2*D.wave or
- D.wave<=120 and 120-(D.wave-60)or
- D.wave<=180 and math.floor(60-(D.wave-120)*.5)or
- 30
- if D.counter>=t then
- D.counter=0
- for _=1,4 do
- table.insert(P.atkBuffer,{line=generateLine(P.holeRND:random(10)),amount=1,countdown=5*t,cd0=5*t,time=0,sent=false,lv=2})
+ D.timer=D.timer+1
+ if P.atkBufferSum<30 then
+ local t=
+ D.wave<=60 and 240-2*D.wave or
+ D.wave<=120 and 120-(D.wave-60) or
+ D.wave<=180 and math.floor(60-(D.wave-120)*.5) or
+ 30
+ if D.timer>=t then
+ D.timer=0
+ for _=1,4 do
+ table.insert(P.atkBuffer,{line=generateLine(P.holeRND:random(10)),amount=1,countdown=5*t,cd0=5*t,time=0,sent=false,lv=2})
+ end
+ P.atkBufferSum=P.atkBufferSum+4
+ P.stat.recv=P.stat.recv+4
+ D.wave=D.wave+1
+ D.rpm=math.floor(144e3/t)*.1
+ if D.wave==60 then
+ P:_showText(text.great,0,-140,100,'appear',.6)
+ P.gameEnv.pushSpeed=3
+ P.dropDelay,P.gameEnv.drop=4,4
+ elseif D.wave==120 then
+ P:_showText(text.awesome,0,-140,100,'appear',.6)
+ P.gameEnv.pushSpeed=4
+ P.dropDelay,P.gameEnv.drop=3,3
+ elseif D.wave==180 then
+ P:_showText(text.maxspeed,0,-140,100,'appear',.6)
+ P.dropDelay,P.gameEnv.drop=2,2
+ end
+ P:shakeField(3)
end
- P.atkBufferSum=P.atkBufferSum+4
- P.stat.recv=P.stat.recv+4
- D.wave=D.wave+1
- D.rpm=math.floor(144e3/t)*.1
- if D.wave==60 then
- P:_showText(text.great,0,-140,100,'appear',.6)
- P.gameEnv.pushSpeed=3
- P.dropDelay,P.gameEnv.drop=4,4
- elseif D.wave==120 then
- P:_showText(text.awesome,0,-140,100,'appear',.6)
- P.gameEnv.pushSpeed=4
- P.dropDelay,P.gameEnv.drop=3,3
- elseif D.wave==180 then
- P:_showText(text.maxspeed,0,-140,100,'appear',.6)
- P.dropDelay,P.gameEnv.drop=2,2
- end
- P:shakeField(3)
end
end
end
diff --git a/parts/eventsets/defender_n.lua b/parts/eventsets/defender_n.lua
index 7d89786e9..a4a984e08 100644
--- a/parts/eventsets/defender_n.lua
+++ b/parts/eventsets/defender_n.lua
@@ -1,46 +1,48 @@
-return{
+return {
drop=30,lock=60,
fall=10,
mesDisp=function(P)
setFont(55)
- mStr(P.modeData.wave,63,200)
- mStr(P.modeData.rpm,63,320)
+ GC.mStr(P.modeData.wave,63,200)
+ GC.mStr(P.modeData.rpm,63,320)
mText(TEXTOBJ.wave,63,260)
mText(TEXTOBJ.rpm,63,380)
end,
task=function(P)
while true do
- YIELD()
+ coroutine.yield()
if P.control then
local D=P.modeData
- D.counter=D.counter+1
- local t=
- D.wave<=60 and 360-D.wave*3 or
- D.wave<=120 and 180-(D.wave-60)*2 or
- D.wave<=180 and 120-(D.wave-120)or
- 60
- if D.counter>=t then
- D.counter=0
- for _=1,3 do
- table.insert(P.atkBuffer,{line=generateLine(P.holeRND:random(10)),amount=1,countdown=2*t,cd0=2*t,time=0,sent=false,lv=1})
+ D.timer=D.timer+1
+ if P.atkBufferSum<20 then
+ local t=
+ D.wave<=40 and 360-D.wave*4 or
+ D.wave<=80 and 200-(D.wave-40)*2 or
+ D.wave<=140 and 120-(D.wave-80) or
+ 60
+ if D.timer>=t then
+ D.timer=0
+ for _=1,3 do
+ table.insert(P.atkBuffer,{line=generateLine(P.holeRND:random(10)),amount=1,countdown=2*t,cd0=2*t,time=0,sent=false,lv=1})
+ end
+ P.atkBufferSum=P.atkBufferSum+3
+ P.stat.recv=P.stat.recv+3
+ D.wave=D.wave+1
+ D.rpm=math.floor(108e3/t)*.1
+ if D.wave==60 then
+ P:_showText(text.great,0,-140,100,'appear',.6)
+ P.gameEnv.pushSpeed=2
+ P.dropDelay,P.gameEnv.drop=20,20
+ elseif D.wave==120 then
+ P:_showText(text.awesome,0,-140,100,'appear',.6)
+ P.gameEnv.pushSpeed=3
+ P.dropDelay,P.gameEnv.drop=10,10
+ elseif D.wave==180 then
+ P.dropDelay,P.gameEnv.drop=5,5
+ P:_showText(text.maxspeed,0,-140,100,'appear',.6)
+ end
+ P:shakeField(3)
end
- P.atkBufferSum=P.atkBufferSum+3
- P.stat.recv=P.stat.recv+3
- D.wave=D.wave+1
- D.rpm=math.floor(108e3/t)*.1
- if D.wave==60 then
- P:_showText(text.great,0,-140,100,'appear',.6)
- P.gameEnv.pushSpeed=2
- P.dropDelay,P.gameEnv.drop=20,20
- elseif D.wave==120 then
- P:_showText(text.awesome,0,-140,100,'appear',.6)
- P.gameEnv.pushSpeed=3
- P.dropDelay,P.gameEnv.drop=10,10
- elseif D.wave==180 then
- P.dropDelay,P.gameEnv.drop=5,5
- P:_showText(text.maxspeed,0,-140,100,'appear',.6)
- end
- P:shakeField(3)
end
end
end
diff --git a/parts/eventsets/dig_100l.lua b/parts/eventsets/dig_100l.lua
index 5c2299ac4..9ec7f3b71 100644
--- a/parts/eventsets/dig_100l.lua
+++ b/parts/eventsets/dig_100l.lua
@@ -1,7 +1,7 @@
-return{
+return {
mesDisp=function(P)
setFont(55)
- mStr(100-P.stat.dig,63,265)
+ GC.mStr(100-P.stat.dig,63,265)
end,
hook_drop=function(P)
for _=1,math.min(10,100-P.stat.dig)-P.garbageBeneath do
diff --git a/parts/eventsets/dig_10l.lua b/parts/eventsets/dig_10l.lua
index eccb98545..c5aed4d88 100644
--- a/parts/eventsets/dig_10l.lua
+++ b/parts/eventsets/dig_10l.lua
@@ -1,7 +1,7 @@
-return{
+return {
mesDisp=function(P)
setFont(55)
- mStr(10-P.stat.dig,63,265)
+ GC.mStr(10-P.stat.dig,63,265)
end,
hook_drop=function(P)
if P.stat.dig==10 then
diff --git a/parts/eventsets/dig_400l.lua b/parts/eventsets/dig_400l.lua
index 1a56310df..23eb1cbc8 100644
--- a/parts/eventsets/dig_400l.lua
+++ b/parts/eventsets/dig_400l.lua
@@ -1,7 +1,7 @@
-return{
+return {
mesDisp=function(P)
setFont(55)
- mStr(400-P.stat.dig,63,265)
+ GC.mStr(400-P.stat.dig,63,265)
end,
hook_drop=function(P)
for _=1,math.min(10,400-P.stat.dig)-P.garbageBeneath do
diff --git a/parts/eventsets/dig_40l.lua b/parts/eventsets/dig_40l.lua
index 11c240408..8233b7575 100644
--- a/parts/eventsets/dig_40l.lua
+++ b/parts/eventsets/dig_40l.lua
@@ -1,7 +1,7 @@
-return{
+return {
mesDisp=function(P)
setFont(55)
- mStr(40-P.stat.dig,63,265)
+ GC.mStr(40-P.stat.dig,63,265)
end,
hook_drop=function(P)
for _=1,math.min(10,40-P.stat.dig)-P.garbageBeneath do
diff --git a/parts/eventsets/dig_h.lua b/parts/eventsets/dig_h.lua
index e040b141a..45cc0f674 100644
--- a/parts/eventsets/dig_h.lua
+++ b/parts/eventsets/dig_h.lua
@@ -1,16 +1,16 @@
-return{
+return {
mesDisp=function(P)
setFont(60)
- mStr(P.modeData.wave,63,310)
+ GC.mStr(P.modeData.wave,63,310)
mText(TEXTOBJ.wave,63,375)
end,
task=function(P)
while true do
- YIELD()
+ coroutine.yield()
if P.control then
local D=P.modeData
D.timer=D.timer+1
- if D.timer>=math.max(90,180-D.wave)then
+ if D.timer>=math.max(90,180-D.wave) then
P:garbageRise(21,1,P:getHolePos())
P.stat.recv=P.stat.recv+1
D.timer=0
diff --git a/parts/eventsets/dig_u.lua b/parts/eventsets/dig_u.lua
index 35bb49dbd..ac357a532 100644
--- a/parts/eventsets/dig_u.lua
+++ b/parts/eventsets/dig_u.lua
@@ -1,16 +1,16 @@
-return{
+return {
mesDisp=function(P)
setFont(60)
- mStr(P.modeData.wave,63,310)
+ GC.mStr(P.modeData.wave,63,310)
mText(TEXTOBJ.wave,63,375)
end,
task=function(P)
while true do
- YIELD()
+ coroutine.yield()
if P.control then
local D=P.modeData
D.timer=D.timer+1
- if D.timer>=math.max(30,80-.3*D.wave)then
+ if D.timer>=math.max(30,80-.3*D.wave) then
P:garbageRise(20+D.wave%5,1,P:getHolePos())
P.stat.recv=P.stat.recv+1
D.timer=0
diff --git a/parts/eventsets/marathon_bfmax.lua b/parts/eventsets/marathon_bfmax.lua
index 078c5b3fa..2873abbad 100644
--- a/parts/eventsets/marathon_bfmax.lua
+++ b/parts/eventsets/marathon_bfmax.lua
@@ -1,6 +1,6 @@
local dropSpeed={50,40,30,25,20,15,12,9,7,5,4,3,2,1,1,.5,.5,.25,.25}
-return{
+return {
drop=60,
wait=8,
fall=20,
@@ -14,11 +14,11 @@ return{
hook_drop=function(P)
local flag
local l=P.lastPiece
- if P.combo>1 then flag=true;P:showText("2x",0,-220,40,'flicker',.3)end
- if l.spin then flag=true;P:showText("spin",0,-180,40,'flicker',.3)end
- if l.row>1 then flag=true;P:showText("1+",0,-140,40,'flicker',.3)end
- if l.hpc then flag=true;P:showText("HPC",0,-100,40,'flicker',.3)end
- if l.pc then P:showText("PC",0,-90,100,'beat',.5)end
+ if P.combo>1 then flag=true;P:showText("2x",0,-220,40,'flicker',.3) end
+ if l.spin then flag=true;P:showText("spin",0,-180,40,'flicker',.3) end
+ if l.row>1 then flag=true;P:showText("1+",0,-140,40,'flicker',.3) end
+ if l.hpc then flag=true;P:showText("HPC",0,-100,40,'flicker',.3) end
+ if l.pc then P:showText("PC",0,-90,100,'beat',.5) end
if flag then
P:lose()
else
diff --git a/parts/eventsets/marathon_inf.lua b/parts/eventsets/marathon_inf.lua
index 80e8fa129..d9f88cfb1 100644
--- a/parts/eventsets/marathon_inf.lua
+++ b/parts/eventsets/marathon_inf.lua
@@ -2,7 +2,7 @@ local dropSpeed={
50,42,35,30,25,20,16,13,11,10,
9,8,7,6,5,5,4,4,3,3,
3,2,2,2,2,1,1,1,1,1,
- .5,.5,.5,.5,.25,.25,.25,.125,.125,--Total 39 numbers, switch to 20G when reach 400 lines
+ .5,.5,.5,.5,.25,.25,.25,.125,.125,-- Total 39 numbers, switch to 20G when reach 400 lines
}
local lockDelay={
57,54,51,48,46,44,42,40,38,36,
@@ -17,7 +17,7 @@ local lockDelay={
4,4,4,4,4,4,4,4,4,4,
3,3,3,3,3,3,3,3,3,3,
2,2,2,2,2,2,2,2,2,2,
- 1,1,1,1,1,1,1,1,1,--Finish at 1700
+ 1,1,1,1,1,1,1,1,1,-- Finish at 1700
}
return
diff --git a/parts/eventsets/master_ex.lua b/parts/eventsets/master_ex.lua
index c3845c1b3..16f024571 100644
--- a/parts/eventsets/master_ex.lua
+++ b/parts/eventsets/master_ex.lua
@@ -1,8 +1,16 @@
-local gc=love.graphics
local sectionName={"D","C","B","A","A+","S-","S","S+","S+","SS","SS","U","U","X","X+"}
local passPoint=16
-return{
+local function getRollGoal(P)
+ -- get amount of grades needed for X+
+ local rem=12.4-P.modeData.rankPoint/10
+ if rem<=0 then return 0 end
+ local goal=math.floor(rem)*4
+ rem=rem%1
+ return goal+(rem>0.3 and 4 or rem*10)
+end
+
+return {
drop=0,lock=15,
wait=15,fall=6,
noTele=true,
@@ -15,26 +23,27 @@ return{
mesDisp=function(P)
local h=(3600-P.stat.frame)/10
if h>0 then
- gc.setColor(1,1,1,.12)
- gc.rectangle('fill',0,475-h,125,h,4)
- gc.setColor(COLOR.Z)
+ GC.setColor(1,1,1,.12)
+ GC.rectangle('fill',0,475-h,125,h,4)
+ GC.setColor(COLOR.Z)
end
mText(TEXTOBJ.line,63,310)
mText(TEXTOBJ.techrash,63,420)
mText(TEXTOBJ.grade,63,180)
setFont(20)
- mStr(("%.1f"):format(P.modeData.rankPoint/10),63,208)
+ GC.mStr(("%.1f"):format(P.modeData.rankPoint/10),63,208)
setFont(55)
- mStr(P.modeData.rankName,63,125)
+ GC.mStr(P.modeData.rankName,63,125)
setFont(75)
- mStr(P.stat.row,63,230)
- mStr(P.stat.clears[4],63,340)
+ GC.mStr(P.stat.row,63,230)
+ GC.mStr(P.stat.clears[4],63,340)
+ PLY.draw.drawTargetLine(P,getRollGoal(P))
end,
hook_drop=function(P)
- if P.modeData.rankPoint<140-passPoint then--If Less then X
+ if P.modeData.rankPoint<140-passPoint then-- If Less then X
local R=#P.clearedRow
if R>0 then
- if R==4 then R=10 end--Techrash +10
+ if R==4 then R=10 end-- Techrash +10
P.modeData.rankPoint=math.min(P.modeData.rankPoint+R,140-passPoint)
P.modeData.rankName=sectionName[math.floor(P.modeData.rankPoint/10)+1]
end
@@ -44,7 +53,7 @@ return{
P.modeData.rankPoint=0
P.modeData.rankName=sectionName[1]
while true do
- YIELD()
+ coroutine.yield()
if P.stat.frame>=3600 then
P.modeData.rankPoint=math.min(P.modeData.rankPoint+passPoint,140)
P.modeData.rankName=sectionName[math.floor(P.modeData.rankPoint/10)+1]
diff --git a/parts/eventsets/master_final.lua b/parts/eventsets/master_final.lua
index b6ad08a79..b8fdbbd6f 100644
--- a/parts/eventsets/master_final.lua
+++ b/parts/eventsets/master_final.lua
@@ -1,4 +1,4 @@
-return{
+return {
drop=0,lock=12,
wait=10,fall=10,
noTele=true,
@@ -21,18 +21,18 @@ return{
if D.pt%100==99 then
SFX.play('warn_1')
- elseif D.pt>=D.target then--Level up!
- s=D.target/100--range from 1 to 9
+ elseif D.pt>=D.target then-- Level up!
+ s=D.target/100-- range from 1 to 9
local E=P.gameEnv
if s<4 then
P:stageComplete(s)
- --First 300
+ -- First 300
if s~=1 then E.lock=E.lock-1 end
if s~=2 then E.wait=E.wait-1 end
if s~=3 then E.fall=E.fall-1 end
D.target=D.target+100
elseif s<10 then
- if s==5 then BGM.play('distortion')end
+ if s==5 then BGM.play('distortion') end
P:stageComplete(s)
if s==4 or s==7 then E.das=E.das-1 end
if s%3==0 then E.lock=E.lock-1
diff --git a/parts/eventsets/master_g.lua b/parts/eventsets/master_g.lua
new file mode 100644
index 000000000..9b711325c
--- /dev/null
+++ b/parts/eventsets/master_g.lua
@@ -0,0 +1,344 @@
+local regretDelay=-1
+local int_grade=0
+local grade_points=0
+local int_grade_boosts={0,1,2,3,4,5,5,6,6,7,7,7,8,8,8,9,9,9,10,11,12,12,12,13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25,25,26}
+local coolList={false,false,false,false,false,false,false,false,false}
+local regretList={false,false,false,false,false,false,false,false,false,false}
+local gradeList={
+ "9","8","7","6","5","4","3","2","1",
+ "S1","S2","S3","S4","S5","S6","S7","S8","S9",
+ "m1","m2","m3","m4","m5","m6","m7","m8","m9",
+ "M","MK","MV","MO","MM-","MM","MM+","GM-","GM","GM+","TM-","TM","TM+"
+}
+local spd_lvl=0
+local cools=0
+local regrets=0
+local prevSectTime=0
+local isInRoll=false
+local rollGrades=0
+local cool_time={3120,3120,2940,2700,2700,2520,2520,2280,2280,0}
+local reg_time= {5400,4500,4500,4080,3600,3600,3000,3000,3000,3000}
+local prevDrop70=false -- determines if previous piece has level less than __70
+local nextSpeedUp=false -- determines if the next section speed should be boosted by 100
+local isInRollTrans=false
+local function getGrav(l)
+ return
+ l<30 and 64 or
+ l<35 and 43 or
+ l<40 and 32 or
+ l<50 and 26 or
+ l<60 and 21 or
+ l<70 and 16 or
+ l<80 and 8 or
+ l<90 and 6 or
+ l<120 and 4 or
+ l<160 and 3 or
+ l<200 and 2 or
+ l<220 and 64 or
+ l<230 and 8 or
+ l<233 and 4 or
+ l<236 and 3 or
+ l<243 and 2 or
+ l<300 and 1 or
+ l<360 and 0.5 or
+ l<450 and 0.25 or
+ 0
+end
+local function getLock(l)
+ return
+ l<900 and 30 or
+ l<1100 and 19 or
+ 15
+end
+local function getWait(l)
+ return
+ l<700 and 23 or
+ l<800 and 16 or
+ l<1000 and 12 or
+ l<1100 and 7 or
+ 6
+end
+local function getFall(l)
+ return
+ l<500 and 25 or
+ l<600 and 18 or
+ l<700 and 12 or
+ l<800 and 8 or
+ 4
+end
+local function getDas(l)
+ return
+ l<500 and 10 or
+ l<900 and 8 or
+ 6
+end
+local function getGrade()
+ if int_grade==nil then int_grade=0 end
+ if rollGrades==nil then rollGrades=0 end
+ return gradeList[math.max(math.min(math.floor(int_grade_boosts[math.min(int_grade+1,#int_grade_boosts)]+rollGrades+cools+1-regrets),#gradeList),1)]
+end
+local function addGrade(row, cmb, lvl) -- IGS = internal grade system
+ if row<1 then return end
+ local pts=0
+ local cmb_mult=1.0
+ local lvl_mult=math.floor(lvl/250)+1
+
+ if row==1 then
+ pts=int_grade<5 and 10 or int_grade<10 and 5 or 2
+ cmb_mult=1.0
+ elseif row==2 then
+ pts=int_grade<3 and 20 or int_grade<6 and 15 or int_grade<10 and 10 or 12
+ cmb_mult=cmb==1 and 1 or cmb<4 and 1.2 or cmb<8 and 1.4 or cmb<10 and 1.5 or 2.0
+ elseif row==3 then
+ pts=int_grade==0 and 40 or int_grade<4 and 30 or int_grade<7 and 20 or int_grade<10 and 15 or 13
+ cmb_mult=cmb==1 and 1 or cmb<10 and 1+(cmb+2)*0.1 or 2
+ else
+ pts=int_grade==0 and 50 or int_grade<5 and 40 or 30
+ cmb_mult=cmb==1 and 1 or cmb==2 and 1.5 or cmb<6 and (0.2*cmb)+1.2 or cmb<10 and (0.1*cmb)+1.7 or 3
+ end
+
+ grade_points=grade_points+(pts*cmb_mult*lvl_mult)
+ if grade_points>=100 then
+ grade_points=0
+ int_grade=int_grade+1
+ end
+end
+local function getRollGoal()
+ -- get amount of grades needed for TM+
+ local rem=#gradeList-(int_grade_boosts[math.min(int_grade+1,#int_grade_boosts)]+rollGrades+cools+1-regrets)
+ if rem<=0 then return 0 end
+ local goal=0
+ if cools>8 then
+ goal=math.floor(rem)*4
+ rem=rem%1
+ return goal+(rem>0.3 and 4 or rem*10)
+ else
+ goal=math.floor(rem/0.26)*4
+ rem=rem%0.26
+ return goal+(rem>0.12 and 4 or rem*25)
+ end
+end
+
+return {
+ drop=64,
+ lock=30,
+ wait=23,
+ fall=25,
+ keyCancel={10,11,12,14,15,16,17,18,19,20},
+ das=16,arr=1,
+ minsdarr=1,
+ ihs=true,irs=true,ims=false,
+ mesDisp=function(P)
+ GC.setColor(1,1,1,1)
+ setFont(45)
+ mText(TEXTOBJ.grade,63,180)
+ setFont(60)
+ GC.mStr(getGrade(),63,110) -- draw grade
+ for i=1,10 do -- draw cool/regret history
+ if not (coolList[i] or regretList[i]) then -- neither cool nor regret
+ GC.setColor(0.6,0.6,0.6,P.modeData.pt<(i-1)*100 and 0.25 or 0.6)
+ else
+ GC.setColor(regretList[i] and 1 or 0, coolList[i] and 1 or 0, 0, 1)
+ end
+ GC.circle('fill',-10,150+i*25,10)
+ GC.setColor(1,1,1,1)
+ end
+ if isInRoll then
+ setFont(20)
+ GC.mStr(("%.1f"):format(rollGrades),63,208) -- draw roll grades
+ GC.setLineWidth(2)
+ GC.setColor(.98,.98,.98,.8)
+ GC.rectangle('line',0,240,126,80,4)
+ GC.setColor(.98,.98,.98,.4)
+ GC.rectangle('fill',0+2,240+2,126-4,80-4,2) -- draw time box
+ setFont(45)
+ local t=(P.stat.frame-prevSectTime)/60
+ local T=("%.1f"):format(60-t)
+ GC.setColor(COLOR.dH)
+ GC.mStr(T,65,250) -- draw time
+ t=t/60
+ GC.setColor(1.7*t,2.3-2*t,.3)
+ GC.mStr(T,63,248)
+ PLY.draw.drawTargetLine(P,getRollGoal())
+ else
+ -- draw level counter
+ setFont(20)
+ GC.mStr(grade_points,63,208)
+ setFont(45)
+ if coolList[math.ceil(P.modeData.pt/100+0.01)] then
+ GC.setColor(0,1,0,1)
+ elseif P.stat.frame-prevSectTime > cool_time[math.ceil(P.modeData.pt/100+0.01)] then
+ GC.setColor(0.7,0.7,0.7,1)
+ end
+ if coolList[math.ceil(P.modeData.pt/100+0.01)] and regretList[math.ceil(P.modeData.pt/100+0.01)] then
+ GC.setColor(1,1,0,1)
+ elseif regretList[math.ceil(P.modeData.pt/100+0.01)] then
+ GC.setColor(1,0,0,1)
+ end
+ PLY.draw.drawProgress(P.modeData.pt,P.modeData.target)
+ end
+ end,
+ hook_drop=function(P)
+ local D=P.modeData
+
+ local c=#P.clearedRow
+
+ if cools>8 and isInRoll then
+ rollGrades=rollGrades+(c==4 and 1 or 0.1*c)
+ return
+ elseif isInRoll then
+ rollGrades=rollGrades+(c==4 and 0.26 or 0.04*c)
+ return
+ end
+
+ if c==0 and D.pt+1>=D.target then return end
+ local s=c<3 and c+1 or c==3 and 5 or 7
+ if P.combo>7 then s=s+2
+ elseif P.combo>3 then s=s+1
+ end
+
+ addGrade(c,P.combo,D.pt)
+
+ D.pt=D.pt+s
+ spd_lvl=spd_lvl+1
+
+ P.gameEnv.drop=getGrav(spd_lvl)
+
+ if (P.gameEnv.drop==0) then
+ P:set20G(true)
+ end
+
+ if D.pt%100>70 and not prevDrop70 then
+ if P.stat.frame-prevSectTime < cool_time[math.ceil(D.pt/100)] then
+ cools=cools+1
+ coolList[math.ceil(D.pt/100)]=true
+ P:_showText("COOL!",0,-120,80,'fly',.8)
+ nextSpeedUp=true
+ end
+ prevDrop70=true
+ end
+
+ if D.pt+1==D.target then
+ SFX.play('warn_1')
+ elseif D.pt>=D.target then-- Level up!
+ spd_lvl=nextSpeedUp and spd_lvl+100 or spd_lvl
+ nextSpeedUp=false
+ prevDrop70=false
+ s=D.target/100
+ local E=P.gameEnv
+ E.lock=getLock(spd_lvl)
+ E.wait=getWait(spd_lvl)
+ E.fall=getFall(spd_lvl)
+ E.das=getDas(spd_lvl)
+
+ if P.stat.frame-prevSectTime > reg_time[math.ceil(s)] then
+ regrets=regrets+1
+ regretDelay=60
+ end
+ prevSectTime=P.stat.frame
+ if s==2 then
+ BG.set('rainbow')
+ elseif s==4 then
+ BG.set('rainbow2')
+ elseif s==5 then
+ if P.stat.frame>420*60 then
+ D.pt=500
+ P:win('finish')
+ return
+ else
+ BG.set('glow')
+ BGM.play('secret7th remix')
+ end
+ elseif s==6 then
+ BG.set('lightning')
+ elseif s>9 then
+ if cools>8 then
+ if E.lockFX and E.lockFX>1 then E.lockFX=1 end
+ P:setInvisible(5)
+ else
+ P:setInvisible(300)
+ end
+ D.pt=999
+ P.waiting=240
+ BGM.stop()
+ isInRollTrans=true
+ return
+ end
+ D.target=D.target<900 and D.target+100 or 999
+ P:stageComplete(s)
+ SFX.play('reach')
+ end
+ end,
+ task=function(P)
+ regretDelay=-1
+ P.modeData.pt=0
+ P.modeData.target=100
+ int_grade=0
+ grade_points=0
+ rollGrades=0
+ spd_lvl=0
+ cools=0
+ regrets=0
+ prevSectTime=0
+ isInRoll=false
+ isInRollTrans=false
+ prevDrop70=false
+ nextSpeedUp=false
+ coolList={false,false,false,false,false,false,false,false,false}
+ regretList={false,false,false,false,false,false,false,false,false,false}
+ local decayRate={125,80,80,50,45,45,45,40,40,40,40,40,30,30,30,20,20,20,20,20,15,15,15,15,15,15,15,15,15,15,10,10,10,9,9,9,8,8,8,7,7,7,6}
+ local decayTimer=0
+ while true do
+ coroutine.yield()
+ P.modeData.grade=getGrade()
+ P.modeData.gradePts=math.max(math.min(math.floor(int_grade_boosts[math.min(int_grade+1,#int_grade_boosts)]+rollGrades+cools+1-regrets),#gradeList),1)
+ if P.stat.frame-prevSectTime > reg_time[math.ceil(P.modeData.pt/100+0.01)] and not (isInRoll or isInRollTrans) then
+ regretList[math.ceil(P.modeData.pt/100)]=true
+ end
+ if regretDelay>-1 then
+ regretDelay=regretDelay-1
+ if regretDelay==-1 then P:_showText("REGRET!!",0,-120,80,'beat',.8) end
+ end
+ if isInRollTrans then
+ if P.waiting>=220 then
+ -- Make field invisible
+ for y=1,#P.field do for x=1,10 do
+ P.visTime[y][x]=P.waiting-220
+ end end
+ elseif P.waiting==190 then
+ TABLE.cut(P.field)
+ TABLE.cut(P.visTime)
+ elseif P.waiting==180 then
+ playReadySFX(3,3)
+ P:_showText("3",0,-120,120,'fly',1)
+ elseif P.waiting==120 then
+ playReadySFX(2,1)
+ P:_showText("2",0,-120,120,'fly',1)
+ elseif P.waiting==60 then
+ playReadySFX(1,1)
+ P:_showText("1",0,-120,120,'fly',1)
+ elseif P.waiting==1 then
+ playReadySFX(0,1)
+ isInRollTrans=false
+ isInRoll=true
+ BGM.play('hope')
+ BG.set('blockspace')
+ prevSectTime=P.stat.frame
+ end
+ end
+ if P.waiting<=0 and grade_points>0 and not isInRoll then
+ decayTimer=decayTimer+1
+ if decayTimer>=decayRate[math.min(int_grade+1,#decayRate)] then
+ decayTimer=0
+ grade_points=grade_points-1
+ end
+ elseif isInRoll and P.stat.frame>=prevSectTime+3599 then
+ rollGrades=rollGrades+(cools>8 and 1.6 or 0.5)
+ P.modeData.grade=getGrade()
+ P.modeData.gradePts=math.min(math.floor(int_grade_boosts[math.min(int_grade+1,#int_grade_boosts)]+rollGrades+cools+1-regrets),#gradeList)
+ coroutine.yield()
+ P:win('finish')
+ end
+ end
+ end,
+}
diff --git a/parts/eventsets/master_h.lua b/parts/eventsets/master_h.lua
index 8934830a0..d141f8dc0 100644
--- a/parts/eventsets/master_h.lua
+++ b/parts/eventsets/master_h.lua
@@ -2,7 +2,7 @@ local death_lock={12,11,10,9,8, 8,8,7,7,6}
local death_wait={10,9, 8, 7,6, 7,6,6,5,5}
local death_fall={10,9, 8, 7,6, 7,6,5,5,5}
-return{
+return {
drop=0,
lock=death_lock[1],
wait=death_wait[1],
@@ -25,7 +25,7 @@ return{
if D.pt%100==99 then
SFX.play('warn_1')
- elseif D.pt>=D.target then--Level up!
+ elseif D.pt>=D.target then-- Level up!
s=D.target/100
local E=P.gameEnv
E.lock=death_lock[s]
diff --git a/parts/eventsets/master_instinct.lua b/parts/eventsets/master_instinct.lua
index d0588c2c5..053e786ce 100644
--- a/parts/eventsets/master_instinct.lua
+++ b/parts/eventsets/master_instinct.lua
@@ -5,7 +5,7 @@ local inv_hide={20,17,14,11, 8, 5, 3, 2, 1, 0}
local hidetimer=0
local held=false
-return{
+return {
drop=0,
lock=inv_lock[1],
wait=inv_wait[1],
@@ -20,7 +20,13 @@ return{
local D=P.modeData
local c=#P.clearedRow
- if c==0 and D.pt%100==99 then return end
+ if c==0 and D.pt%100==99 then
+ if D.pt<1000 then
+ hidetimer=0-inv_wait[(P.modeData.pt/100-(P.modeData.pt%100)/100)+1]
+ if c>0 then hidetimer=hidetimer-inv_fall[(P.modeData.pt/100-(P.modeData.pt%100)/100)+1] end
+ end
+ return
+ end
local s=c<3 and c+1 or c==3 and 5 or 7
if P.combo>7 then s=s+2
elseif P.combo>3 then s=s+1
@@ -29,12 +35,12 @@ return{
held=false
if D.pt<1000 then
hidetimer=0-inv_wait[(P.modeData.pt/100-(P.modeData.pt%100)/100)+1]
- if c>0 then hidetimer=hidetimer-inv_fall[(P.modeData.pt/100-(P.modeData.pt%100)/100)+1]end
+ if c>0 then hidetimer=hidetimer-inv_fall[(P.modeData.pt/100-(P.modeData.pt%100)/100)+1] end
end
if D.pt%100==99 then
SFX.play('warn_1')
- elseif D.pt>=D.target then--Level up!
+ elseif D.pt>=D.target then-- Level up!
s=D.target/100
local E=P.gameEnv
E.lock=inv_lock[s]
@@ -50,6 +56,8 @@ return{
elseif s==7 then
E.das=6
BGM.play('far')
+ elseif s==8 then
+ BG.set('none')
elseif s==10 then
D.pt=1000
P:win('finish')
@@ -64,13 +72,13 @@ return{
P.modeData.pt=0
P.modeData.target=100
while true do
- YIELD()
+ coroutine.yield()
if P.holdTime==0 and P.waiting<=0 and not held then
hidetimer=0
held=true
end
hidetimer=hidetimer+1
- if hidetimer>inv_hide[(P.modeData.pt/100-(P.modeData.pt%100)/100)+1]then
+ if hidetimer>inv_hide[(P.modeData.pt/100-(P.modeData.pt%100)/100)+1] then
P.gameEnv.block=false
else
P.gameEnv.block=true
diff --git a/parts/eventsets/master_n.lua b/parts/eventsets/master_n.lua
index ef573852c..3379f52c3 100644
--- a/parts/eventsets/master_n.lua
+++ b/parts/eventsets/master_n.lua
@@ -2,7 +2,7 @@ local rush_lock={20,18,16,15,14, 14,13,12,11,11}
local rush_wait={12,11,11,10,10, 10,10, 9, 9, 9}
local rush_fall={18,16,14,13,12, 12,11,11,10,10}
-return{
+return {
drop=0,
lock=rush_lock[1],
wait=rush_wait[1],
@@ -25,7 +25,7 @@ return{
if D.pt%100==99 then
SFX.play('warn_1')
- elseif D.pt>=D.target then--Level up!
+ elseif D.pt>=D.target then-- Level up!
s=D.target/100
local E=P.gameEnv
E.lock=rush_lock[s]
diff --git a/parts/eventsets/master_ph.lua b/parts/eventsets/master_ph.lua
index 917259290..0fc304f0a 100644
--- a/parts/eventsets/master_ph.lua
+++ b/parts/eventsets/master_ph.lua
@@ -18,9 +18,9 @@ return
if p>=P.modeData.target then
local ENV=P.gameEnv
local T=P.modeData.target
- --Stage 1: clear 3 techrash
- if T==12 then--Stage 2: swap color of S/Z & J/L
- P:stageComplete(2)
+ -- Stage 1: clear 3 techrash
+ if T==12 then-- Stage 2: swap color of S/Z & J/L
+ P:stageComplete(1)
P.waiting=30
P.curMission=false
@@ -34,9 +34,9 @@ return
P.modeData.target=26
SFX.play('reach')
- elseif T==26 then--Stage 3: dig to bottom
- P:stageComplete(3)
- if not P.holdQueue[1]then--1 up if ban hold
+ elseif T==26 then-- Stage 3: dig to bottom
+ P:stageComplete(2)
+ if not P.holdQueue[1] then-- 1 up if ban hold
P.life=P.life+1
end
P.waiting=45
@@ -44,7 +44,7 @@ return
ENV.skin[3],ENV.skin[4]=ENV.skin[4],ENV.skin[3]
for i=1,10 do
- if P.field[i]then
+ if P.field[i] then
for j=1,10 do
if P.field[i][j]>0 then
P.field[i][j]=17
@@ -79,9 +79,9 @@ return
P.modeData.target=42
SFX.play('reach')
- elseif T==42 then--Stage 4: survive in high speed
+ elseif T==42 then-- Stage 4: survive in high speed
if P.garbageBeneath==0 then
- P:stageComplete(4)
+ P:stageComplete(3)
P.waiting=30
ENV.lock=11
P:setNext(6)
@@ -93,8 +93,8 @@ return
else
p=41
end
- elseif T==62 then--Stage 5: survive without easy-fresh rule
- P:stageComplete(5)
+ elseif T==62 then-- Stage 5: survive without easy-fresh rule
+ P:stageComplete(4)
P.life=P.life+1
ENV.lock=13
ENV.wait=5
@@ -104,8 +104,8 @@ return
P.modeData.target=126
SFX.play('reach')
- elseif T==126 then--Stage 6: speed up
- P:stageComplete(6)
+ elseif T==126 then-- Stage 6: speed up
+ P:stageComplete(5)
P.life=P.life+1
ENV.lock=11
@@ -114,8 +114,8 @@ return
P.modeData.target=162
SFX.play('reach')
- elseif T==162 then--Stage 7: speed up+++
- P:stageComplete(7)
+ elseif T==162 then-- Stage 7: speed up+++
+ P:stageComplete(6)
P.life=P.life+1
ENV.lock=10
@@ -125,8 +125,8 @@ return
P.modeData.target=226
SFX.play('reach')
- elseif T==226 then--Stage 8: final invisible
- P:stageComplete(8)
+ elseif T==226 then-- Stage 8: final invisible
+ P:stageComplete(7)
P.life=P.life+1
ENV.bone=false
@@ -134,10 +134,10 @@ return
P.modeData.target=259
SFX.play('reach')
- elseif T==259 then--Stage 9: ending
- P:stageComplete(9)
+ elseif T==259 then-- Stage 9: ending
+ P:stageComplete(8)
P.life=P.life+1
- for i=1,7 do ENV.skin[i]=P.holeRND:random(16)end
+ for i=1,7 do ENV.skin[i]=P.holeRND:random(16) end
P:setInvisible(40)
ENV.lock=15
diff --git a/parts/eventsets/pc_inf.lua b/parts/eventsets/pc_inf.lua
index 78b8f07ae..e5bef0112 100644
--- a/parts/eventsets/pc_inf.lua
+++ b/parts/eventsets/pc_inf.lua
@@ -1,12 +1,12 @@
-return{
+return {
heightLimit=4,
mesDisp=function(P)
setFont(60)
- mStr(P.stat.pc,63,340)
+ GC.mStr(P.stat.pc,63,340)
mText(TEXTOBJ.pc,63,410)
end,
hook_drop=function(P)
- if P.lastPiece.pc and P.stat.row%4==0 then
+ if P.lastPiece.pc then
P.gameEnv.heightLimit=4
if P.stat.pc%5==0 then
P.gameEnv.drop=math.max(P.gameEnv.drop-1,1)
diff --git a/parts/eventsets/pctrain_l.lua b/parts/eventsets/pctrain_l.lua
index 2e83cf720..871999341 100644
--- a/parts/eventsets/pctrain_l.lua
+++ b/parts/eventsets/pctrain_l.lua
@@ -11,7 +11,7 @@ local function task_PC(P)
P:pushNextList(L,symmetry)
P.control=false
- if P.frameRun>180 then for _=1,26 do YIELD()end end
+ if P.frameRun>180 then for _=1,26 do coroutine.yield() end end
P.control=true
local base=PCbase[difficulty]
@@ -31,9 +31,9 @@ local function _check(P)
if P.stat.pc%4==0 and P.stat.pc>0 and P.stat.pc<=40 then
local s=P.stat.pc/4
- P.gameEnv.drop=pc_drop[s]or 10
- P.gameEnv.lock=pc_lock[s]or 25
- P.gameEnv.fall=pc_fall[s]or 4
+ P.gameEnv.drop=pc_drop[s] or 10
+ P.gameEnv.lock=pc_lock[s] or 25
+ P.gameEnv.fall=pc_fall[s] or 4
if s==10 then
P:_showText(text.maxspeed,0,-140,100,'appear',.6)
end
@@ -41,14 +41,14 @@ local function _check(P)
end
end
end
-return{
+return {
sequence='none',
RS="SRS",
mesDisp=function(P)
setFont(60)
- mStr(P.stat.pc,63,260)
+ GC.mStr(P.stat.pc,63,260)
mText(TEXTOBJ.pc,63,330)
end,
hook_drop=_check,
- task=_check,--Just run one time at first to start first level
+ task=_check,-- Just run one time at first to start first level
}
diff --git a/parts/eventsets/pctrain_n.lua b/parts/eventsets/pctrain_n.lua
index a925725ba..cfeac90e0 100644
--- a/parts/eventsets/pctrain_n.lua
+++ b/parts/eventsets/pctrain_n.lua
@@ -8,13 +8,13 @@ local PCtype={
1,2,3,
}
local function task_PC(P)
- local difficulty=PCtype[P.stat.pc+1]or 3
+ local difficulty=PCtype[P.stat.pc+1] or 3
local L=PClist[difficulty][P.holeRND:random(#PClist[difficulty])]
local symmetry=P.holeRND:random()>.5
P:pushNextList(L,symmetry)
P.control=false
- if P.frameRun>180 then for _=1,26 do YIELD()end end
+ if P.frameRun>180 then for _=1,26 do coroutine.yield() end end
P.control=true
local base=PCbase[difficulty]
@@ -34,14 +34,14 @@ local function _check(P)
end
end
end
-return{
+return {
sequence='none',
RS="SRS",
mesDisp=function(P)
setFont(60)
- mStr(P.stat.pc,63,260)
+ GC.mStr(P.stat.pc,63,260)
mText(TEXTOBJ.pc,63,330)
end,
hook_drop=_check,
- task=_check,--Just run one time at first to start first level
+ task=_check,-- Just run one time at first to start first level
}
diff --git a/parts/eventsets/royale.lua b/parts/eventsets/royale.lua
index fae53599c..71922b573 100644
--- a/parts/eventsets/royale.lua
+++ b/parts/eventsets/royale.lua
@@ -1,10 +1,4 @@
-local gc=love.graphics
-local gc_draw,gc_print,gc_setColor=gc.draw,gc.print,gc.setColor
-local setFont=setFont
-
-local PLAYERS,PLY_ALIVE=PLAYERS,PLY_ALIVE
-
-return{
+return {
layout='royale',
fkey1=function(P)
P:changeAtkMode(P.atkMode<3 and P.atkMode+2 or 5-P.atkMode)
@@ -12,20 +6,20 @@ return{
end,
mesDisp=function(P)
setFont(35)
- mStr(#PLY_ALIVE.."/"..#PLAYERS,63,175)
- mStr(P.modeData.ko,80,215)
- gc_draw(TEXTOBJ.ko,60-TEXTOBJ.ko:getWidth(),222)
+ GC.mStr(#PLY_ALIVE.."/"..#PLAYERS,63,175)
+ GC.mStr(P.modeData.ko,80,215)
+ GC.draw(TEXTOBJ.ko,60-TEXTOBJ.ko:getWidth(),222)
setFont(20)
- gc_setColor(1,.5,0,.6)
- gc_print(P.badge,103,227)
- gc_setColor(.97,.97,.97)
+ GC.setColor(1,.5,0,.6)
+ GC.print(P.badge,103,227)
+ GC.setColor(.97,.97,.97)
setFont(25)
- mStr(text.powerUp[P.strength],63,290)
- gc_setColor(1,1,1)
+ GC.mStr(text.powerUp[P.strength],63,290)
+ GC.setColor(1,1,1)
for i=1,P.strength do
- gc_draw(IMG.badgeIcon,16*i+6,260)
+ GC.draw(IMG.badgeIcon,16*i+6,260)
end
end,
}
diff --git a/parts/eventsets/secret_grade.lua b/parts/eventsets/secret_grade.lua
new file mode 100644
index 000000000..b93f44fcb
--- /dev/null
+++ b/parts/eventsets/secret_grade.lua
@@ -0,0 +1,92 @@
+local gc_setColor,gc_draw=love.graphics.setColor,love.graphics.draw
+local ply_applyField=PLY.draw.applyField
+local function getOpenHole(num)
+ return -math.abs(((num-1) % 18)-9)+10
+end
+local F={}
+
+-- local ranks={"10","9","8","7","6","5","4","3","2","1","S1","S2","S3","S4","S5","S6","S7","S8","S9","GM","GM+","TM","TM+","TM+₂","TM+₃", "TM+₄","TM+₅"}
+-- lines: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
+
+local function getSmallNum(num)
+ local smalldigit={[0]="₀","₁","₂","₃","₄","₅","₆","₇","₈","₉"}
+ local str=tostring(num)
+ local out=""
+ for i=1,#str do
+ out=out..smalldigit[tonumber(string.sub(str,i,i))]
+ end
+ return out
+end
+
+local function getRank(index)
+ if index<11 then -- rank 10 - 1
+ return tostring(11-index)
+ elseif index<20 then -- S1 - S9 ranks
+ return "S"..index-10
+ elseif index<24 then -- GM, GM+, TM, TM+ ranks
+ local r={"GM","GM+","TM","TM+"}
+ return r[index-19]
+ else
+ return "TM+"..getSmallNum(index-22)
+ end
+end
+
+local function generateGuide(num)
+ local l=#F
+ if l>num then
+ return
+ end
+ for i=l,num do
+ F[i] = {}
+ local h=getOpenHole(i)
+ for j=1,10 do
+ F[i][j]=h==j and -1 or 21
+ end
+ end
+end
+
+return {
+ fkey1=function(P) P.modeData.showGuide=not P.modeData.showGuide end,
+ mesDisp=function(P)
+ mText(TEXTOBJ.grade,63,190)
+ mText(TEXTOBJ.line,63,310)
+ setFont(55)
+ GC.mStr(getRank(P.modeData.rankPts),63,125)
+ GC.mStr(P.modeData.rankPts-1,63,245)
+ ply_applyField(P)
+ local mark=TEXTURE.puzzleMark
+ gc_setColor(1,1,1)
+ if P.modeData.showGuide then
+ for y=1,P.modeData.rankPts+1 do for x=1,10 do
+ local T=F[y][x]
+ if T~=0 then
+ gc_draw(mark[T],30*x-30,600-30*y)
+ end
+ end end
+ end
+ PLY.draw.cancelField()
+ end,
+ task=function(P)
+ P.modeData.rankPts=1
+ P.modeData.showGuide=true
+ generateGuide(10)
+ end,
+ hook_drop=function(P)
+ local D=P.modeData
+ D.rankPts=1
+ for i=1,#P.field do
+ local h=getOpenHole(i)
+ local flag
+ for j=1,10 do
+ if P.field[i][j]>0 and h==j then flag=true break end-- goto post_pts_calc
+ if P.field[i][j]==0 and h~=j then flag=true break end-- goto post_pts_calc
+ end
+ if flag then break end
+ if i==#P.field then break end-- goto post_pts_calc
+ if P.field[i+1][h]==0 then break end-- goto post_pts_calc
+ D.rankPts=D.rankPts+1
+ end
+ -- ::post_pts_calc::
+ generateGuide(D.rankPts+20)
+ end
+}
diff --git a/parts/eventsets/sprintEff_40.lua b/parts/eventsets/sprintEff_40.lua
index 09d76a226..412e8e6e2 100644
--- a/parts/eventsets/sprintEff_40.lua
+++ b/parts/eventsets/sprintEff_40.lua
@@ -1,15 +1,15 @@
-return{
+return {
mesDisp=function(P)
setFont(45)
- mStr(("%.1f"):format(P.stat.atk),63,270)
+ GC.mStr(("%d"):format(P.stat.atk),63,270)
mText(TEXTOBJ.atk,63,323)
- mStr(("%.2f"):format(P.stat.atk/P.stat.row),63,370)
+ GC.mStr(("%.2f"):format(P.stat.atk/P.stat.row),63,370)
mText(TEXTOBJ.eff,63,423)
setFont(55)
local r=40-P.stat.row
if r<0 then r=0 end
- mStr(r,63,170)
+ GC.mStr(r,63,170)
PLY.draw.drawTargetLine(P,r)
end,
hook_drop=function(P)
diff --git a/parts/eventsets/sprintMD.lua b/parts/eventsets/sprintMD.lua
index 0c18a7e1a..55793cebc 100644
--- a/parts/eventsets/sprintMD.lua
+++ b/parts/eventsets/sprintMD.lua
@@ -1,24 +1,24 @@
-return{
+return {
mesDisp=function(P)
setFont(55)
local r=40-P.stat.row
if r<0 then r=0 end
- mStr(r,63,265)
+ GC.mStr(r,63,265)
PLY.draw.drawTargetLine(P,r)
end,
task=function(P)
- YIELD()
+ coroutine.yield()
while true do
- for _=1,P.holeRND:random(40,200)do YIELD()end
+ for _=1,P.holeRND:random(40,200) do coroutine.yield() end
local r=P.holeRND:random(7)
if r==1 then
- if P.cur and not P:ifoverlap(P.cur.bk,P.curX-1,P.curY)then
+ if P.cur and not P:ifoverlap(P.cur.bk,P.curX-1,P.curY) then
P:createMoveFX('left')
P.curX=P.curX-1
P:freshBlock('move')
end
elseif r==2 then
- if P.cur and not P:ifoverlap(P.cur.bk,P.curX-1,P.curY)then
+ if P.cur and not P:ifoverlap(P.cur.bk,P.curX-1,P.curY) then
P:createMoveFX('left')
P.curX=P.curX-1
P:freshBlock('move')
diff --git a/parts/eventsets/sprintSym.lua b/parts/eventsets/sprintSym.lua
index 2457a189a..afe90dfc4 100644
--- a/parts/eventsets/sprintSym.lua
+++ b/parts/eventsets/sprintSym.lua
@@ -1,7 +1,7 @@
local oppo={
[1]=7,[7]=1,[11]=3,[3]=11,[14]=14,[4]=4,[9]=9,
}
-return{
+return {
skin={
1,7,11,3,14,4,9,
1,7,2,6,10,2,13,5,9,15,10,11,3,12,2,16,8,4,
@@ -11,7 +11,7 @@ return{
setFont(55)
local r=40-P.stat.row
if r<0 then r=0 end
- mStr(r,63,265)
+ GC.mStr(r,63,265)
PLY.draw.drawTargetLine(P,r)
end,
hook_drop=function(P)
@@ -19,7 +19,7 @@ return{
for y=1,#F do
local l=F[y]
for x=1,5 do
- if l[x]>0 and l[11-x]>0 and oppo[l[x]]~=l[11-x]then
+ if l[x]>0 and l[11-x]>0 and oppo[l[x]]~=l[11-x] then
P:lose()
return
end
diff --git a/parts/eventsets/stack_e.lua b/parts/eventsets/stack_e.lua
index a7ceed5e4..155a71db9 100644
--- a/parts/eventsets/stack_e.lua
+++ b/parts/eventsets/stack_e.lua
@@ -1,22 +1,32 @@
-return{
+return {
fieldH=20,
fillClear=false,
mesDisp=function(P)
setFont(60)
- mStr(P.stat.row,63,280)
+ GC.mStr(P.stat.row,63,280)
mText(TEXTOBJ.line,63,350)
PLY.draw.drawMarkLine(P,20,.3,1,1,TIME()%.42<.21 and .95 or .6)
end,
hook_die=function(P)
local cc=P:clearFilledLines(P.garbageBeneath+1,#P.field-P.garbageBeneath)
if cc>0 then
- local h=20-cc-P.garbageBeneath
- if h>0 then
- P:garbageRise(21,h,2e10-1)
+ local clearH=cc+P.garbageBeneath
+ if clearH<20 then
+ P:garbageRise(21,20-clearH,2e10-1)
if P.garbageBeneath>=20 then
P:lose()
end
+ elseif P.garbageBeneath>0 and clearH>20 then
+ local bonus=math.min(P.garbageBeneath,clearH-20)
+ if bonus>0 then
+ for _=1,bonus do
+ LINE.discard(table.remove(P.field,1))
+ LINE.discard(table.remove(P.visTime,1))
+ end
+ P.garbageBeneath=P.garbageBeneath-bonus
+ end
end
+ P:freshBlock('push')
end
end,
}
\ No newline at end of file
diff --git a/parts/eventsets/stack_u.lua b/parts/eventsets/stack_u.lua
index 7f08bd9df..c04a389f1 100644
--- a/parts/eventsets/stack_u.lua
+++ b/parts/eventsets/stack_u.lua
@@ -1,22 +1,32 @@
-return{
+return {
fieldH=21,
fillClear=false,
mesDisp=function(P)
setFont(60)
- mStr(P.stat.row,63,280)
+ GC.mStr(P.stat.row,63,280)
mText(TEXTOBJ.line,63,350)
PLY.draw.drawMarkLine(P,17,.3,1,1,TIME()%.42<.21 and .95 or .6)
end,
hook_die=function(P)
local cc=P:clearFilledLines(P.garbageBeneath+1,#P.field-P.garbageBeneath)
if cc>0 then
- local h=20-cc-P.garbageBeneath-3
- if h>0 then
- P:garbageRise(21,h,2e10-1)
- if P.garbageBeneath>=20 then
+ local clearH=cc+P.garbageBeneath
+ if clearH<17 then
+ P:garbageRise(21,17-clearH,2e10-1)
+ if P.garbageBeneath>=17 then
P:lose()
end
+ elseif P.garbageBeneath>0 and clearH>17 then
+ local bonus=math.min(P.garbageBeneath,clearH-17)
+ if bonus>0 then
+ for _=1,bonus do
+ LINE.discard(table.remove(P.field,1))
+ LINE.discard(table.remove(P.visTime,1))
+ end
+ P.garbageBeneath=P.garbageBeneath-bonus
+ end
end
+ P:freshBlock('push')
end
end,
}
\ No newline at end of file
diff --git a/parts/eventsets/survivor_e.lua b/parts/eventsets/survivor_e.lua
index 0abdad615..ec098e09e 100644
--- a/parts/eventsets/survivor_e.lua
+++ b/parts/eventsets/survivor_e.lua
@@ -1,16 +1,16 @@
-return{
+return {
mesDisp=function(P)
setFont(60)
- mStr(P.modeData.wave,63,310)
+ GC.mStr(P.modeData.wave,63,310)
mText(TEXTOBJ.wave,63,375)
end,
task=function(P)
while true do
- YIELD()
+ coroutine.yield()
if P.control then
local D=P.modeData
D.timer=D.timer+1
- if D.timer>=math.max(60,150-2*D.wave)and P.atkBufferSum<4 then
+ if D.timer>=math.max(60,150-2*D.wave) and P.atkBufferSum<4 then
if D.wave==100 then
P:win('finish')
else
diff --git a/parts/eventsets/survivor_h.lua b/parts/eventsets/survivor_h.lua
index fce75feff..9e078c2f1 100644
--- a/parts/eventsets/survivor_h.lua
+++ b/parts/eventsets/survivor_h.lua
@@ -1,16 +1,16 @@
-return{
+return {
mesDisp=function(P)
setFont(60)
- mStr(P.modeData.wave,63,310)
+ GC.mStr(P.modeData.wave,63,310)
mText(TEXTOBJ.wave,63,375)
end,
task=function(P)
while true do
- YIELD()
+ coroutine.yield()
if P.control then
local D=P.modeData
D.timer=D.timer+1
- if D.timer>=math.max(60,180-2*D.wave)and P.atkBufferSum<15 then
+ if D.timer>=math.max(60,180-2*D.wave) and P.atkBufferSum<15 then
if D.wave==90 then
P:win('finish')
else
diff --git a/parts/eventsets/survivor_l.lua b/parts/eventsets/survivor_l.lua
index ab0a951f5..e0999f933 100644
--- a/parts/eventsets/survivor_l.lua
+++ b/parts/eventsets/survivor_l.lua
@@ -1,16 +1,16 @@
-return{
+return {
mesDisp=function(P)
setFont(60)
- mStr(P.modeData.wave,63,310)
+ GC.mStr(P.modeData.wave,63,310)
mText(TEXTOBJ.wave,63,375)
end,
task=function(P)
while true do
- YIELD()
+ coroutine.yield()
if P.control then
local D=P.modeData
D.timer=D.timer+1
- if D.timer>=math.max(60,150-D.wave)and P.atkBufferSum<20 then
+ if D.timer>=math.max(60,150-D.wave) and P.atkBufferSum<20 then
if D.wave==110 then
P:win('finish')
else
@@ -18,7 +18,7 @@ return{
table.insert(P.atkBuffer,{line=generateLine(P.holeRND:random(10)),amount=4,countdown=t,cd0=t,time=0,sent=false,lv=3})
P.atkBufferSum=P.atkBufferSum+4
P.stat.recv=P.stat.recv+4
- if D.wave==60 then
+ if D.wave==90 then
P:_showText(text.maxspeed,0,-140,100,'appear',.6)
end
P:shakeField(3)
diff --git a/parts/eventsets/survivor_n.lua b/parts/eventsets/survivor_n.lua
index 80ac120fe..82393088e 100644
--- a/parts/eventsets/survivor_n.lua
+++ b/parts/eventsets/survivor_n.lua
@@ -1,24 +1,24 @@
-return{
+return {
mesDisp=function(P)
setFont(60)
- mStr(P.modeData.wave,63,310)
+ GC.mStr(P.modeData.wave,63,310)
mText(TEXTOBJ.wave,63,375)
end,
task=function(P)
while true do
- YIELD()
+ coroutine.yield()
if P.control then
local D=P.modeData
D.timer=D.timer+1
- if D.timer>=math.max(90,180-2*D.wave)and P.atkBufferSum<8 then
+ if D.timer>=math.max(90,180-2*D.wave) and P.atkBufferSum<8 then
if D.wave==80 then
P:win('finish')
else
local d=D.wave+1
table.insert(P.atkBuffer,
- d%4==0 and{line=generateLine(P.holeRND:random(10)),amount=1,countdown=60,cd0=60,time=0,sent=false,lv=1}or
- d%4==1 and{line=generateLine(P.holeRND:random(10)),amount=2,countdown=70,cd0=70,time=0,sent=false,lv=1}or
- d%4==2 and{line=generateLine(P.holeRND:random(10)),amount=3,countdown=80,cd0=80,time=0,sent=false,lv=2}or
+ d%4==0 and{line=generateLine(P.holeRND:random(10)),amount=1,countdown=60,cd0=60,time=0,sent=false,lv=1} or
+ d%4==1 and{line=generateLine(P.holeRND:random(10)),amount=2,countdown=70,cd0=70,time=0,sent=false,lv=1} or
+ d%4==2 and{line=generateLine(P.holeRND:random(10)),amount=3,countdown=80,cd0=80,time=0,sent=false,lv=2} or
d%4==3 and{line=generateLine(P.holeRND:random(10)),amount=4,countdown=90,cd0=90,time=0,sent=false,lv=3}
)
P.atkBufferSum=P.atkBufferSum+d%4+1
diff --git a/parts/eventsets/survivor_u.lua b/parts/eventsets/survivor_u.lua
index 161446189..0ab93cbff 100644
--- a/parts/eventsets/survivor_u.lua
+++ b/parts/eventsets/survivor_u.lua
@@ -1,16 +1,16 @@
-return{
+return {
mesDisp=function(P)
setFont(60)
- mStr(P.modeData.wave,63,310)
+ GC.mStr(P.modeData.wave,63,310)
mText(TEXTOBJ.wave,63,375)
end,
task=function(P)
while true do
- YIELD()
+ coroutine.yield()
if P.control then
local D=P.modeData
D.timer=D.timer+1
- if D.timer>=math.max(300,600-10*D.wave)and P.atkBufferSum<20 then
+ if D.timer>=math.max(300,600-10*D.wave) and P.atkBufferSum<20 then
if D.wave==35 then
P:win('finish')
else
diff --git a/parts/eventsets/techrash_n.lua b/parts/eventsets/techrash_n.lua
index f92000069..b78fdb0a5 100644
--- a/parts/eventsets/techrash_n.lua
+++ b/parts/eventsets/techrash_n.lua
@@ -1,7 +1,7 @@
-return{
+return {
mesDisp=function(P)
setFont(60)
- mStr(P.stat.clear[7][4],63,250)
+ GC.mStr(P.stat.clear[7][4],63,250)
mText(TEXTOBJ.techrash,63,315)
end,
hook_drop=function(P)
diff --git a/parts/eventsets/techrash_u.lua b/parts/eventsets/techrash_u.lua
index b32e99be6..70c3d28f7 100644
--- a/parts/eventsets/techrash_u.lua
+++ b/parts/eventsets/techrash_u.lua
@@ -1,23 +1,21 @@
-local gc=love.graphics
-
-return{
+return {
mesDisp=function(P)
setFont(60)
- mStr(P.modeData.techrash,63,250)
+ GC.mStr(P.modeData.techrash,63,250)
mText(TEXTOBJ.techrash,63,315)
PLY.draw.applyField(P)
local L=P.modeData.history
for i=1,#L do
- gc.setColor(1,.3,.3,.5-i*.04)
- gc.rectangle('fill',30*L[i]-30,0,30,600)
+ GC.setColor(1,.3,.3,.5-i*.04)
+ GC.rectangle('fill',30*L[i]-30,0,30,600)
end
- PLY.draw.cancelField(P)
+ PLY.draw.cancelField()
end,
hook_drop=function(P)
local C=P.lastPiece
if C.row>0 then
if C.row==4 then
- if TABLE.find(P.modeData.history,C.curX)then
+ if TABLE.find(P.modeData.history,C.curX) then
P:showText("STACK",0,-140,40,'flicker',.3)
P:lose()
else
diff --git a/parts/eventsets/tsd_e.lua b/parts/eventsets/tsd_e.lua
index cc6e450a9..b8583db4d 100644
--- a/parts/eventsets/tsd_e.lua
+++ b/parts/eventsets/tsd_e.lua
@@ -1,7 +1,7 @@
-return{
+return {
mesDisp=function(P)
setFont(60)
- mStr(P.modeData.tsd,63,250)
+ GC.mStr(P.modeData.tsd,63,250)
mText(TEXTOBJ.tsd,63,315)
end,
hook_drop=function(P)
diff --git a/parts/eventsets/tsd_h.lua b/parts/eventsets/tsd_h.lua
index d028b00fc..3f8c816d9 100644
--- a/parts/eventsets/tsd_h.lua
+++ b/parts/eventsets/tsd_h.lua
@@ -1,16 +1,14 @@
-local gc=love.graphics
-
-return{
+return {
mesDisp=function(P)
setFont(60)
- mStr(P.modeData.tsd,63,250)
+ GC.mStr(P.modeData.tsd,63,250)
mText(TEXTOBJ.tsd,63,315)
local L=P.modeData.history
- if L[1]and L[1]==L[2]and L[1]==L[3]then
+ if L[1] and L[1]==L[2] and L[1]==L[3] then
PLY.draw.applyField(P)
- gc.setColor(1,.3,.3,.2)
- gc.rectangle('fill',30*L[1]-30,0,30,600)
- PLY.draw.cancelField(P)
+ GC.setColor(1,.3,.3,.2)
+ GC.rectangle('fill',30*L[1]-30,0,30,600)
+ PLY.draw.cancelField()
end
end,
hook_drop=function(P)
@@ -18,7 +16,7 @@ return{
if C.row>0 then
if C.id==5 and C.row==2 and C.spin then
local L=P.modeData.history
- if L[1]==C.centX and L[1]==L[2]and L[1]==L[3]then
+ if L[1]==C.centX and L[1]==L[2] and L[1]==L[3] then
P:showText("STACK",0,-140,40,'flicker',.3)
P:lose()
else
diff --git a/parts/eventsets/tsd_u.lua b/parts/eventsets/tsd_u.lua
index 09f95d282..c2e6d9c67 100644
--- a/parts/eventsets/tsd_u.lua
+++ b/parts/eventsets/tsd_u.lua
@@ -1,23 +1,21 @@
-local gc=love.graphics
-
-return{
+return {
mesDisp=function(P)
setFont(60)
- mStr(P.modeData.tsd,63,250)
+ GC.mStr(P.modeData.tsd,63,250)
mText(TEXTOBJ.tsd,63,315)
PLY.draw.applyField(P)
local L=P.modeData.history
for i=1,#L do
- gc.setColor(1,.3,.3,.4-i*.05)
- gc.rectangle('fill',30*L[i]-30,0,30,600)
+ GC.setColor(1,.3,.3,.4-i*.05)
+ GC.rectangle('fill',30*L[i]-30,0,30,600)
end
- PLY.draw.cancelField(P)
+ PLY.draw.cancelField()
end,
hook_drop=function(P)
local C=P.lastPiece
if C.row>0 then
if C.id==5 and C.row==2 and C.spin then
- if TABLE.find(P.modeData.history,C.centX)then
+ if TABLE.find(P.modeData.history,C.centX) then
P:showText("STACK",0,-140,40,'flicker',.3)
P:lose()
else
diff --git a/parts/eventsets/ultra.lua b/parts/eventsets/ultra.lua
index 1f19b6a74..cd085dd12 100644
--- a/parts/eventsets/ultra.lua
+++ b/parts/eventsets/ultra.lua
@@ -1,29 +1,28 @@
-local gc=love.graphics
local warnTime={60,90,105,115,116,117,118,119,120}
for i=1,#warnTime do warnTime[i]=warnTime[i]*60 end
-return{
+return {
mesDisp=function(P)
- gc.setLineWidth(2)
- gc.setColor(.98,.98,.98,.8)
- gc.rectangle('line',0,260,126,80,4)
- gc.setColor(.98,.98,.98,.4)
- gc.rectangle('fill',0+2,260+2,126-4,80-4,2)
+ GC.setLineWidth(2)
+ GC.setColor(.98,.98,.98,.8)
+ GC.rectangle('line',0,260,126,80,4)
+ GC.setColor(.98,.98,.98,.4)
+ GC.rectangle('fill',0+2,260+2,126-4,80-4,2)
setFont(45)
local t=P.stat.frame/60
local T=("%.1f"):format(120-t)
- gc.setColor(COLOR.dH)
- mStr(T,65,270)
+ GC.setColor(COLOR.dH)
+ GC.mStr(T,65,270)
t=t/120
- gc.setColor(1.7*t,2.3-2*t,.3)
- mStr(T,63,268)
+ GC.setColor(1.7*t,2.3-2*t,.3)
+ GC.mStr(T,63,268)
end,
task=function(P)
- BGM.seek(0)
+ BGM.set('all','seek',0)
P.modeData.section=1
while true do
- YIELD()
- while P.stat.frame>=warnTime[P.modeData.section]do
+ coroutine.yield()
+ while P.stat.frame>=warnTime[P.modeData.section] do
if P.modeData.section<9 then
P.modeData.section=P.modeData.section+1
playReadySFX(3,.7+P.modeData.section*.03)
diff --git a/parts/fonts/monospaced.otf b/parts/fonts/monospaced.otf
new file mode 100644
index 000000000..6d562d164
Binary files /dev/null and b/parts/fonts/monospaced.otf differ
diff --git a/parts/fonts/monospaced.ttf b/parts/fonts/monospaced.ttf
deleted file mode 100644
index b915a953f..000000000
Binary files a/parts/fonts/monospaced.ttf and /dev/null differ
diff --git a/parts/fonts/proportional.otf b/parts/fonts/proportional.otf
new file mode 100644
index 000000000..20ab61810
Binary files /dev/null and b/parts/fonts/proportional.otf differ
diff --git a/parts/fonts/proportional.ttf b/parts/fonts/proportional.ttf
deleted file mode 100644
index ae127acca..000000000
Binary files a/parts/fonts/proportional.ttf and /dev/null differ
diff --git a/parts/gameFuncs.lua b/parts/gameFuncs.lua
index 2606af0d6..aefff5f60 100644
--- a/parts/gameFuncs.lua
+++ b/parts/gameFuncs.lua
@@ -1,9 +1,8 @@
-local gc=love.graphics
-local gc_push,gc_pop=gc.push,gc.pop
-local gc_origin,gc_replaceTransform=gc.origin,gc.replaceTransform
-local gc_setLineWidth,gc_setColor=gc.setLineWidth,gc.setColor
-local gc_setShader=gc.setShader
-local gc_draw,gc_rectangle,gc_line,gc_printf=gc.draw,gc.rectangle,gc.line,gc.printf
+local gc_push,gc_pop=GC.push,GC.pop
+local gc_origin,gc_replaceTransform=GC.origin,GC.replaceTransform
+local gc_setLineWidth,gc_setColor=GC.setLineWidth,GC.setColor
+local gc_setShader=GC.setShader
+local gc_draw,gc_rectangle,gc_printf=GC.draw,GC.rectangle,GC.printf
local ins,rem=table.insert,table.remove
local int,rnd=math.floor,math.random
@@ -11,12 +10,11 @@ local approach=MATH.expApproach
local SETTING,GAME,SCR=SETTING,GAME,SCR
local PLAYERS=PLAYERS
-local playSFX=SFX.play
---System
-do--function tryBack()
+-- System
+do-- function tryBack()
local sureTime=-1e99
function tryBack()
if TIME()-sureTime<1 then
@@ -28,7 +26,7 @@ do--function tryBack()
end
end
end
-do--function tryReset()
+do-- function tryReset()
local sureTime=-1e99
function tryReset()
if TIME()-sureTime<1 then
@@ -40,7 +38,7 @@ do--function tryReset()
end
end
end
-do--function tryDelete()
+do-- function tryDelete()
local sureTime=-1e99
function tryDelete()
if TIME()-sureTime<1 then
@@ -52,21 +50,21 @@ do--function tryDelete()
end
end
end
-do--function loadFile(name,args), function saveFile(data,name,args)
- local t=setmetatable({},{__index=function()return"'$1' loading failed: $2"end})
+do-- function loadFile(name,args), function saveFile(data,name,args)
+ local t=setmetatable({},{__index=function() return "'$1' loading failed: $2" end})
function loadFile(name,args)
local text=text or t
- if not args then args=''end
+ if not args then args='' end
local res,mes=pcall(FILE.load,name,args)
if res then
return mes
else
- if mes:find'open error'then
+ if mes:find'open error' then
MES.new('error',text.loadError_open:repD(name,""))
- elseif mes:find'unknown mode'then
+ elseif mes:find'unknown mode' then
MES.new('error',text.loadError_errorMode:repD(name,args))
- elseif mes:find'no file'then
- if not args:sArg'-canSkip'then
+ elseif mes:find'no file' then
+ if not args:sArg'-canSkip' then
MES.new('error',text.loadError_noFile:repD(name,""))
end
elseif mes then
@@ -83,24 +81,17 @@ do--function loadFile(name,args), function saveFile(data,name,args)
return true
else
MES.new('error',
- mes:find'duplicate'and
- text.saveError_duplicate:repD(name)or
- mes:find'encode error'and
- text.saveError_encode:repD(name)or
+ mes:find'duplicate' and
+ text.saveError_duplicate:repD(name) or
+ mes:find'encode error' and
+ text.saveError_encode:repD(name) or
mes and
- text.saveError_other:repD(name,mes)or
+ text.saveError_other:repD(name,mes) or
text.saveError_unknown:repD(name)
)
end
end
end
-function isSafeFile(file,mes)
- if love.filesystem.getRealDirectory(file)~=SAVEDIR then
- return true
- elseif mes then
- MES.new('warn',mes)
- end
-end
function saveStats()
return saveFile(STAT,'conf/data')
end
@@ -108,9 +99,15 @@ function saveProgress()
return saveFile(RANKS,'conf/unlock')
end
function saveSettings()
+ if WS.status('game')=='running' then
+ NET.player_updateConf()
+ end
return saveFile(SETTING,'conf/settings')
end
-do--function applySettings()
+function saveUser()
+ return saveFile(USER.__data,'conf/user')
+end
+do-- function applySettings()
local saturateValues={
normal={0,1},
soft={.2,.7},
@@ -119,87 +116,94 @@ do--function applySettings()
color={-.2,1.2},
}
function applySettings()
- --Apply fullscreen
+ -- Apply language
+ text=LANG.get(SETTING.locale)
+ WIDGET.setLang(text.WidgetText)
+ for k,v in next,TEXTOBJ do
+ if rawget(text,k) then
+ v:set(text[k])
+ end
+ end
+
+ -- Apply cursor
+ love.mouse.setVisible(SETTING.sysCursor)
+
+ -- Apply fullscreen
love.window.setFullscreen(SETTING.fullscreen)
- love.resize(gc.getWidth(),gc.getHeight())
+ love.resize(GC.getWidth(),GC.getHeight())
- --Apply Zframework setting
+ -- Apply Zframework setting
Z.setClickFX(SETTING.clickFX)
Z.setFrameMul(SETTING.frameMul)
Z.setPowerInfo(SETTING.powerInfo)
Z.setCleanCanvas(SETTING.cleanCanvas)
- --Apply VK shape
+ -- Apply VK shape
VK.setShape(SETTING.VKSkin)
- --Apply sound
+ -- Apply sound
love.audio.setVolume(SETTING.mainVol)
BGM.setVol(SETTING.bgm)
SFX.setVol(SETTING.sfx)
VOC.setVol(SETTING.voc)
- --Apply saturs
+ -- Apply saturs
local m
- m=saturateValues[SETTING.blockSatur]or saturateValues.normal
+ m=saturateValues[SETTING.blockSatur] or saturateValues.normal
SHADER.blockSatur:send('b',m[1])
SHADER.blockSatur:send('k',m[2])
- m=saturateValues[SETTING.fieldSatur]or saturateValues.normal
+ m=saturateValues[SETTING.fieldSatur] or saturateValues.normal
SHADER.fieldSatur:send('b',m[1])
SHADER.fieldSatur:send('k',m[2])
- --Apply language
- text=LANG.get(SETTING.locale)
- WIDGET.setLang(text.WidgetText)
- for k,v in next,TEXTOBJ do
- if rawget(text,k)then
- v:set(text[k])
- end
- end
-
- --Apply cursor
- love.mouse.setVisible(SETTING.sysCursor)
-
- --Apply BG
- if SETTING.bg=='on'then
+ -- Apply BG
+ if SETTING.bg=='on' then
BG.unlock()
BG.set()
- elseif SETTING.bg=='off'then
+ elseif SETTING.bg=='off' then
BG.unlock()
- BG.set('gray')
- BG.send(SETTING.bgAlpha)
+ BG.set('fixColor',SETTING.bgAlpha,SETTING.bgAlpha,SETTING.bgAlpha)
BG.lock()
- elseif SETTING.bg=='custom'then
- if love.filesystem.getInfo('conf/customBG')then
- local res,image=pcall(gc.newImage,love.filesystem.newFile('conf/customBG'))
+ elseif SETTING.bg=='custom' then
+ if love.filesystem.getInfo('conf/customBG') then
+ local res,image=pcall(GC.newImage,love.filesystem.newFile('conf/customBG'))
if res then
BG.unlock()
- BG.set('custom')
- gc.setDefaultFilter('linear','linear')
- BG.send(SETTING.bgAlpha,image)
- gc.setDefaultFilter('nearest','nearest')
+ GC.setDefaultFilter('linear','linear')
+ BG.set('custom',SETTING.bgAlpha,image)
+ GC.setDefaultFilter('nearest','nearest')
BG.lock()
else
MES.new('error',text.customBGloadFailed)
end
- else--Switch off when custom BG not found
+ else-- Switch off when custom BG not found
SETTING.bg='off'
BG.unlock()
- BG.set('gray')
- BG.send(SETTING.bgAlpha)
+ BG.set('fixColor',SETTING.bgAlpha,SETTING.bgAlpha,SETTING.bgAlpha)
BG.lock()
end
end
end
end
---Royale mode
-function randomTarget(P)--Return a random opponent for P
- if #PLY_ALIVE>1 then
- local R
- repeat
- R=PLY_ALIVE[rnd(#PLY_ALIVE)]
- until R~=P
- return R
+-- Royale mode
+function randomTarget(P)-- Return a random opponent for P
+ local l=TABLE.shift(PLY_ALIVE,0)
+ local count=0
+ for i=1,#l do
+ if P.group==0 and l[i]~=P or P.group~=l[i].group then
+ count=count+1
+ end
+ end
+ if count==0 then return end
+ count=rnd(count)
+ for i=1,#l do
+ if P.group==0 and l[i]~=P or P.group~=l[i].group then
+ count=count-1
+ if count==0 then
+ return l[i]
+ end
+ end
end
end
function freshMostDangerous()
@@ -246,7 +250,7 @@ end
function royaleLevelup()
GAME.stage=GAME.stage+1
local spd
- TEXT.show(text.royale_remain:gsub("$1",#PLY_ALIVE),640,200,40,'beat',.3)
+ TEXT.show(text.royale_remain:repD(#PLY_ALIVE),640,200,40,'beat',.3)
if GAME.stage==2 then
spd=30
elseif GAME.stage==3 then
@@ -276,7 +280,7 @@ function royaleLevelup()
for _,P in next,PLY_ALIVE do
P.gameEnv.drop=spd
end
- if GAME.curMode.name:find("_u")then
+ if GAME.curMode.name:find("_u") then
for i=1,#PLY_ALIVE do
local P=PLY_ALIVE[i]
P.gameEnv.drop=int(P.gameEnv.drop*.4)
@@ -288,29 +292,29 @@ function royaleLevelup()
end
end
---Sound shortcuts
+-- Sound shortcuts
function playClearSFX(cc)
if cc<=0 or cc%1~=0 then return end
if cc<=4 then
- playSFX('clear_'..cc)
+ SFX.play('clear_'..cc)
elseif cc<=6 then
- playSFX('clear_4')
+ SFX.play('clear_4')
elseif cc<=12 then
- playSFX('clear_4',.8)
+ SFX.play('clear_4',.8)
if cc<=9 then
Snd('bass','A3','E4')
else
Snd('bass','A3','E4','A4')
end
elseif cc<=16 then
- playSFX('clear_5',.7)
+ SFX.play('clear_5',.7)
if cc<=14 then
Snd('bass',.8,'A3','E4')Snd('lead','A4','E5')
else
Snd('bass',.8,'A3','G4')Snd('lead','B4','G5')
end
else
- playSFX('clear_6',.6)
+ SFX.play('clear_6',.6)
if cc==17 then Snd('bass',.8,'A3','A4')Snd('lead','E5','G5')
elseif cc==18 then Snd('bass',.7,'A4')Snd('lead',.8,'C4','G5')Snd('bell','D5')
elseif cc==19 then Snd('bass',.7,'A4')Snd('lead',.8,'A4','E5')Snd('bell','B5')
@@ -340,7 +344,7 @@ function playReadySFX(i,vol)
end
---Game
+-- Game
function getItem(itemName,amount)
STAT.item[itemName]=STAT.item[itemName]+(amount or 1)
end
@@ -358,7 +362,7 @@ function setField(P,page)
local F=FIELD[page]
local height=0
for y=#F,1,-1 do
- if notEmptyLine(F[y])then
+ if notEmptyLine(F[y]) then
height=y
break
end
@@ -385,16 +389,16 @@ function freshDate(args)
STAT.date=date
STAT.todayTime=0
getItem('zTicket',1)
- if not args:find'q'then
+ if not args:find'q' then
MES.new('info',text.newDay)
end
saveStats()
return true
end
end
-function legalGameTime()--Check if today's playtime is legal
+function legalGameTime()-- Check if today's playtime is legal
if
- SETTING.locale:find'zh'and
+ SETTING.locale:find'zh' and
RANKS.sprint_10l<4 and
(not RANKS.sprint_40l or RANKS.sprint_40l<3)
then
@@ -410,7 +414,7 @@ function legalGameTime()--Check if today's playtime is legal
end
return true
end
-do--function trySettingWarn()
+do-- function trySettingWarn()
local lastWarnTime=0
function trySettingWarn()
if TIME()-lastWarnTime>2.6 then
@@ -420,20 +424,20 @@ do--function trySettingWarn()
end
end
-function mergeStat(stat,delta)--Merge delta stat. to global stat.
+function mergeStat(stat,delta)-- Merge delta stat. to global stat.
for k,v in next,delta do
- if type(v)=='table'then
- if type(stat[k])=='table'then
+ if type(v)=='table' then
+ if type(stat[k])=='table' then
mergeStat(stat[k],v)
end
else
- if stat[k]then
+ if stat[k] then
stat[k]=stat[k]+v
end
end
end
end
-function scoreValid()--Check if any unranked mods are activated
+function scoreValid()-- Check if any unranked mods are activated
for _,M in next,GAME.mod do
if M.unranked then
return false
@@ -444,13 +448,13 @@ function scoreValid()--Check if any unranked mods are activated
end
return true
end
-function destroyPlayers()--Destroy all player objects, restore freerows and free CCs
+function destroyPlayers()-- Destroy all player objects, restore freerows and free CCs
for i=#PLAYERS,1,-1 do
local P=PLAYERS[i]
if P.canvas then
P.canvas:release()
end
- while P.field[1]do
+ while P.field[1] do
rem(P.field)
rem(P.visTime)
end
@@ -464,7 +468,7 @@ function pauseGame()
for i=1,#PLAYERS do
local l=PLAYERS[i].keyPressing
for j=1,#l do
- if l[j]then
+ if l[j] then
PLAYERS[i]:releaseKey(j)
end
end
@@ -473,31 +477,31 @@ function pauseGame()
for i=1,20 do
VK.release(i)
end
- if not(GAME.result or GAME.replaying)then
+ if not (GAME.result or GAME.replaying) then
GAME.pauseCount=GAME.pauseCount+1
end
SCN.swapTo('pause','none')
end
end
-function applyCustomGame()--Apply CUSTOMENV, BAG, MISSION
+function applyCustomGame()-- Apply CUSTOMENV, BAG, MISSION
for k,v in next,CUSTOMENV do
GAME.modeEnv[k]=v
end
- if BAG[1]then
+ if BAG[1] then
GAME.modeEnv.seqData=BAG
else
GAME.modeEnv.seqData=nil
end
- if MISSION[1]then
+ if MISSION[1] then
GAME.modeEnv.mission=MISSION
else
GAME.modeEnv.mission=nil
end
end
-function loadGame(mode,ifQuickPlay,ifNet)--Load a mode and go to game scene
+function loadGame(mode,ifQuickPlay,ifNet)-- Load a mode and go to game scene
freshDate()
- if legalGameTime()then
- if not MODES[mode]and love.filesystem.getRealDirectory('parts/modes/'..mode)~=SAVEDIR then
+ if legalGameTime() then
+ if not MODES[mode] and FILE.isSafe('parts/modes/'..mode) then
MODES[mode]=require('parts.modes.'..mode)
MODES[mode].name=mode
end
@@ -514,14 +518,14 @@ function loadGame(mode,ifQuickPlay,ifNet)--Load a mode and go to game scene
if ifNet then
SCN.go('net_game','swipeD')
else
- local modeText=text.modes[mode]or{"["..MODES[mode].name.."]",""}
+ local modeText=text.modes[mode] or{"["..MODES[mode].name.."]",""}
TEXTOBJ.modeName:set(modeText[1].." "..modeText[2])
- SCN.go('game',ifQuickPlay and'swipeD'or'fade_togame')
- playSFX('enter')
+ SCN.go('game',ifQuickPlay and 'swipeD' or 'fade_togame')
+ SFX.play('enter')
end
end
end
-function gameOver()--Save record
+function gameOver()-- Save record
if GAME.replaying then
local R=GAME.curMode.getRank
if R then
@@ -537,15 +541,15 @@ function gameOver()--Save record
local R=M.getRank
if R then
local P=PLAYERS[1]
- R=R(P)--New rank
+ R=R(P)-- New rank
if R then
if R>0 then
GAME.rank=R
end
- if not GAME.replaying and M.score and scoreValid()then
- if RANKS[M.name]then--Old rank exist
+ if not GAME.replaying and M.score and scoreValid() then
+ if RANKS[M.name] then-- Old rank exist
local needSave
- if R>RANKS[M.name]then
+ if R>RANKS[M.name] then
RANKS[M.name]=R
needSave=true
end
@@ -554,7 +558,7 @@ function gameOver()--Save record
for i=1,#M.unlock do
local m=M.unlock[i]
local n=MODES[m].name
- if not RANKS[n]then
+ if not RANKS[n] then
if MODES[m].x then
RANKS[n]=0
end
@@ -569,9 +573,9 @@ function gameOver()--Save record
end
local D=M.score(P)
local L=M.records
- local p=#L--Rank-1
+ local p=#L-- Rank-1
if p>0 then
- while M.comp(D,L[p])do--If higher rank
+ while M.comp(D,L[p]) do-- If higher rank
p=p-1
if p==0 then break end
end
@@ -579,15 +583,15 @@ function gameOver()--Save record
if p<10 then
if p==0 then
P:_showText(text.newRecord,0,-100,100,'beat',.5)
- if SETTING.autoSave and DATA.saveReplay()then
+ if SETTING.autoSave and DATA.saveReplay() then
GAME.saved=true
- playSFX('connected')
+ SFX.play('connected')
MES.new('check',text.saveDone)
end
end
D.date=os.date("%Y/%m/%d %H:%M")
ins(L,p+1,D)
- if L[11]then L[11]=nil end
+ if L[11] then L[11]=nil end
saveFile(L,('record/%s.rec'):format(M.name),'-luaon')
end
end
@@ -595,7 +599,7 @@ function gameOver()--Save record
end
end
function trySave()
- if not GAME.statSaved and PLAYERS[1]and PLAYERS[1].type=='human'and(PLAYERS[1].frameRun>300 or GAME.result)then
+ if not GAME.statSaved and PLAYERS[1] and PLAYERS[1].type=='human' and (PLAYERS[1].frameRun>300 or GAME.result) then
GAME.statSaved=true
STAT.game=STAT.game+1
mergeStat(STAT,PLAYERS[1].stat)
@@ -603,86 +607,314 @@ function trySave()
saveStats()
end
end
-do--function freshPlayerPosition(sudden)
- local posLists={
- --1~5
- {
- {340,75,1},
- {965,390,.5},
- {965,30,.5},
- {20,390,.5},
- {20,30,.5},
+do-- function freshPlayerPosition(sudden)
+ local posLists=setmetatable({
+ alive={
+ [1]={main={340,75,1}},
+ [3]={main={340,75,1},
+ {25,210,.5},
+ {955,210,.5},
+ },
+ [4]={main={340,75,1},
+ {25,210,.5},
+ {970,90,.45},{970,410,.45},
+ },
+ [5]={main={340,75,1},
+ {40,90,.45},{40,410,.45},
+ {970,90,.45},{970,410,.45},
+ },
+ [6]={main={340,75,1},
+ {40,90,.45},{40,410,.45},
+ {1010,80,.305},{1010,290,.305},{1010,500,.305},
+ },
+ [7]={main={340,75,1},
+ {100,80,.305},{100,290,.305},{100,500,.305},
+ {1010,80,.305},{1010,290,.305},{1010,500,.305},
+ },
+ [10]={main={340,75,1},
+ {100,80,.305},{100,290,.305},{100,500,.305},
+ {935,90,.275},{935,300,.275},{935,510,.275},
+ {1105,90,.275},{1105,300,.275},{1105,510,.275},
+ },
+ [13]={main={340,75,1},
+ {10,90,.275},{10,300,.275},{10,510,.275},
+ {180,90,.275},{180,300,.275},{180,510,.275},
+ {935,90,.275},{935,300,.275},{935,510,.275},
+ {1105,90,.275},{1105,300,.275},{1105,510,.275},
+ },
+ [14]={main={340,75,1},
+ {10,90,.275},{10,300,.275},{10,510,.275},
+ {180,90,.275},{180,300,.275},{180,510,.275},
+ {935,90,.275},{935,300,.275},{935,510,.275},
+ {1120,80,.225},{1120,240,.225},{1120,400,.225},{1120,560,.225},
+ },
+ [15]={main={340,75,1},
+ {10,90,.275},{10,300,.275},{10,510,.275},
+ {180,90,.275},{180,300,.275},{180,510,.275},
+ {960,80,.225},{960,240,.225},{960,400,.225},{960,560,.225},
+ {1120,80,.225},{1120,240,.225},{1120,400,.225},{1120,560,.225},
+ },
+ [16]={main={340,75,1},
+ {10,90,.275},{10,300,.275},{10,510,.275},
+ {190,80,.225},{190,240,.225},{190,400,.225},{190,560,.225},
+ {960,80,.225},{960,240,.225},{960,400,.225},{960,560,.225},
+ {1120,80,.225},{1120,240,.225},{1120,400,.225},{1120,560,.225},
+ },
+ [17]={main={340,75,1},
+ {30,80,.225},{30,240,.225},{30,400,.225},{30,560,.225},
+ {190,80,.225},{190,240,.225},{190,400,.225},{190,560,.225},
+ {960,80,.225},{960,240,.225},{960,400,.225},{960,560,.225},
+ {1120,80,.225},{1120,240,.225},{1120,400,.225},{1120,560,.225},
+ },
+ [24]={main={340,75,1},
+ {30,80,.225},{30,240,.225},{30,400,.225},{30,560,.225},
+ {190,80,.225},{190,240,.225},{190,400,.225},{190,560,.225},
+ {940,80,.175},{940,205,.175},{940,330,.175},{940,455,.175},{940,580,.175},
+ {1050,80,.175},{1050,205,.175},{1050,330,.175},{1050,455,.175},{1050,580,.175},
+ {1160,80,.175},{1160,205,.175},{1160,330,.175},{1160,455,.175},{1160,580,.175},
+ },
+ [31]={main={340,75,1},
+ {10,80,.175},{10,205,.175},{10,330,.175},{10,455,.175},{10,580,.175},
+ {120,80,.175},{120,205,.175},{120,330,.175},{120,455,.175},{120,580,.175},
+ {230,80,.175},{230,205,.175},{230,330,.175},{230,455,.175},{230,580,.175},
+ {940,80,.175},{940,205,.175},{940,330,.175},{940,455,.175},{940,580,.175},
+ {1050,80,.175},{1050,205,.175},{1050,330,.175},{1050,455,.175},{1050,580,.175},
+ {1160,80,.175},{1160,205,.175},{1160,330,.175},{1160,455,.175},{1160,580,.175},
+ },
+ [33]=(function()
+ local l={main={340,75,1}}
+ for y=-1.5,1.5 do for x=0,3 do
+ table.insert(l,{265-85*x,310+160*y,.125})
+ table.insert(l,{940+85*x,310+160*y,.125})
+ end end
+ return l
+ end)(),
+ [51]=(function()
+ local l={main={340,75,1}}
+ for y=-2,2 do for x=0,4 do
+ table.insert(l,{275-65*x,315+125*y,.1})
+ table.insert(l,{945+65*x,315+125*y,.1})
+ end end
+ return l
+ end)(),
+ [75]=(function()
+ local l={main={340,75,1}}
+ for y=-2,2 do for x=0,4 do
+ table.insert(l,{275-65*x,310+125*y,.1})
+ end end
+ for y=-3,3 do for x=0,6 do
+ table.insert(l,{940+47*x,340+92*y,.075})
+ end end
+ return l
+ end)(),
+ [99]=(function()
+ local l={main={340,75,1}}
+ for y=-3,3 do for x=0,6 do
+ table.insert(l,{290-47*x,340+92*y,.075})
+ table.insert(l,{940+47*x,340+92*y,.075})
+ end end
+ return l
+ end)(),
+ [MATH.inf]={main={340,75,1}},
},
- --6~17
- (function()
- local L={{340,75,1}}
- for i=1,4 do ins(L,{15,-160+180*i,.25})end
- for i=1,4 do ins(L,{180,-160+180*i,.25})end
- for i=1,4 do ins(L,{950,-160+180*i,.25})end
- for i=1,4 do ins(L,{1120,-160+180*i,.25})end
- return L
- end)(),
- --18~31
- (function()
- local L={{340,75,1}}
- for i=1,5 do ins(L,{10, -100+135*i,.18})end
- for i=1,5 do ins(L,{120, -100+135*i,.18})end
- for i=1,5 do ins(L,{230, -100+135*i,.18})end
- for i=1,5 do ins(L,{940, -100+135*i,.18})end
- for i=1,5 do ins(L,{1050,-100+135*i,.18})end
- for i=1,5 do ins(L,{1160,-100+135*i,.18})end
- return L
- end)(),
- --32~49
- (function()
- local L={{340,75,1}}
- for i=1,4 do for j=1,6 do ins(L,{78*i-54,115*j-98,.09})end end
- for i=9,12 do for j=1,6 do ins(L,{78*i+267,115*j-98,.09})end end
- return L
- end)(),
- --50~99
- (function()
- local L={{340,75,1}}
- for i=1,7 do for j=1,7 do ins(L,{46*i-36,97*j-72,.068})end end
- for i=15,21 do for j=1,7 do ins(L,{46*i+264,97*j-72,.068})end end
- return L
- end)(),
- }
- function freshPlayerPosition(sudden)--Set initial position for every player
+ dead={
+ [1]={{340,75,1}},
+ [2]={
+ {50,130,.925},{670,130,.925},
+ },
+ [3]={
+ {25,160,.675},{440,160,.675},{855,160,.675},
+ },
+ [4]={
+ {13,200,.525},{328,200,.525},{643,200,.525},{948,200,.525},
+ },
+ [5]={
+ {8,230,.425},{260,230,.425},{512,230,.425},{764,230,.425},{1016,230,.425},
+ },
+ [10]={
+ {8,110,.425},{260,110,.425},{512,110,.425},{764,110,.425},{1016,110,.425},
+ {8,410,.425},{260,410,.425},{512,410,.425},{764,410,.425},{1016,410,.425},
+ },
+ [12]={
+ {10,120,.35},{220,120,.35},{430,120,.35},{640,120,.35},{850,120,.35},{1060,120,.35},
+ {10,400,.35},{220,400,.35},{430,400,.35},{640,400,.35},{850,400,.35},{1060,400,.35},
+ },
+ [18]={
+ {10,90,.305},{220,90,.305},{430,90,.305},{640,90,.305},{850,90,.305},{1060,90,.305},
+ {10,300,.305},{220,300,.305},{430,300,.305},{640,300,.305},{850,300,.305},{1060,300,.305},
+ {10,510,.305},{220,510,.305},{430,510,.305},{640,510,.305},{850,510,.305},{1060,510,.305},
+ },
+ [21]={
+ {10,90,.295},{190,90,.295},{370,90,.295},{550,90,.295},{730,90,.295},{910,90,.295},{1090,90,.295},
+ {10,300,.295},{190,300,.295},{370,300,.295},{550,300,.295},{730,300,.295},{910,300,.295},{1090,300,.295},
+ {10,510,.295},{190,510,.295},{370,510,.295},{550,510,.295},{730,510,.295},{910,510,.295},{1090,510,.295},
+ },
+ [24]={
+ {20,100,.25},{175,100,.25},{330,100,.25},{485,100,.25},{640,100,.25},{795,100,.25},{950,100,.25},{1105,100,.25},
+ {20,300,.25},{175,300,.25},{330,300,.25},{485,300,.25},{640,300,.25},{795,300,.25},{950,300,.25},{1105,300,.25},
+ {20,500,.25},{175,500,.25},{330,500,.25},{485,500,.25},{640,500,.25},{795,500,.25},{950,500,.25},{1105,500,.25},
+ },
+ [27]={
+ {10,100,.225},{150,100,.225},{290,100,.225},{430,100,.225},{570,100,.225},{710,100,.225},{850,100,.225},{990,100,.225},{1130,100,.225},
+ {10,300,.225},{150,300,.225},{290,300,.225},{430,300,.225},{570,300,.225},{710,300,.225},{850,300,.225},{990,300,.225},{1130,300,.225},
+ {10,500,.225},{150,500,.225},{290,500,.225},{430,500,.225},{570,500,.225},{710,500,.225},{850,500,.225},{990,500,.225},{1130,500,.225},
+ },
+ [36]={
+ {10,90,.225},{150,90,.225},{290,90,.225},{430,90,.225},{570,90,.225},{710,90,.225},{850,90,.225},{990,90,.225},{1130,90,.225},
+ {10,245,.225},{150,245,.225},{290,245,.225},{430,245,.225},{570,245,.225},{710,245,.225},{850,245,.225},{990,245,.225},{1130,245,.225},
+ {10,400,.225},{150,400,.225},{290,400,.225},{430,400,.225},{570,400,.225},{710,400,.225},{850,400,.225},{990,400,.225},{1130,400,.225},
+ {10,555,.225},{150,555,.225},{290,555,.225},{430,555,.225},{570,555,.225},{710,555,.225},{850,555,.225},{990,555,.225},{1130,555,.225},
+ },
+ [39]=(function()
+ local l={}
+ for y=0,2 do for x=0,12 do
+ table.insert(l,{13+97*x,110+190*y,.15})
+ end end
+ return l
+ end)(),
+ [42]=(function()
+ local l={}
+ for y=0,2 do for x=0,13 do
+ table.insert(l,{15+90*x,120+190*y,.135})
+ end end
+ return l
+ end)(),
+ [45]=(function()
+ local l={}
+ for y=0,2 do for x=0,14 do
+ table.insert(l,{8+85*x,120+190*y,.125})
+ end end
+ return l
+ end)(),
+ [60]=(function()
+ local l={}
+ for y=0,3 do for x=0,14 do
+ table.insert(l,{8+85*x,85+155*y,.125})
+ end end
+ return l
+ end)(),
+ [64]=(function()
+ local l={}
+ for y=0,3 do for x=0,15 do
+ table.insert(l,{13+79*x,85+155*y,.115})
+ end end
+ return l
+ end)(),
+ [68]=(function()
+ local l={}
+ for y=0,3 do for x=0,16 do
+ table.insert(l,{6+75*x,85+155*y,.115})
+ end end
+ return l
+ end)(),
+ [72]=(function()
+ local l={}
+ for y=0,3 do for x=0,17 do
+ table.insert(l,{15+70*x,95+155*y,.1})
+ end end
+ return l
+ end)(),
+ [90]=(function()
+ local l={}
+ for y=0,4 do for x=0,17 do
+ table.insert(l,{15+70*x,82+127*y,.1})
+ end end
+ return l
+ end)(),
+ [95]=(function()
+ local l={}
+ for y=0,4 do for x=0,18 do
+ table.insert(l,{15+66*x,82+127*y,.1})
+ end end
+ return l
+ end)(),
+ [100]=(function()
+ local l={}
+ for y=0,4 do for x=0,19 do
+ table.insert(l,{12+63*x,82+127*y,.1})
+ end end
+ return l
+ end)(),
+ [MATH.inf]={},
+ },
+ }, {
+ __call=function(self,alive,count)
+ local lastTested=MATH.inf
+ for k in next,self[alive and 'alive' or 'dead'] do
+ if k=count then
+ lastTested=k
+ end
+ end
+ return self[alive and 'alive' or 'dead'][lastTested]
+ end,
+ })
+
+ function freshPlayerPosition(mode)-- Set initial position for every player, mode: 'normal'|'quick'|'update'
+ assert(mode=='normal' or mode=='quick' or mode=='update',"Wrong freshPlyPos mode")
local L=PLY_ALIVE
- if not sudden then
+ if mode~='update' then
for i=1,#L do
L[i]:setPosition(640,#L<=5 and 360 or -62,0)
end
end
- local posList
- if #L<=5 then posList=posLists[1]
- elseif #L<=17 then posList=posLists[2]
- elseif #L<=31 then posList=posLists[3]
- elseif #L<=49 then posList=posLists[4]
- elseif #L<=99 then posList=posLists[5]
- else error("TOO MANY PLAYERS!")
+ local alive=PLAYERS[1].alive
+
+ if mode=='update' then
+ if alive then
+ if #L<=31 then
+ for i=2,#L do
+ L[i].miniMode=false
+ L[i].draw=require"parts.player.draw".norm
+ end
+ end
+ else
+ if #L<=36 then
+ for i=1,#L do
+ L[i].miniMode=false
+ L[i].draw=require"parts.player.draw".norm
+ end
+ end
+ end
+ end
+
+ local posList=posLists(alive,#L)
+ local method=mode=='normal' and 'setPosition' or 'movePosition'
+
+ if alive then
+ for i=1,#L do
+ if i==1 then
+ if SETTING.portrait then-- WARNING: Brutly scaling up to 2x only for 1P, will cause many other visual issues.
+ L[i][method](L[i],36,-260,2)
+ else
+ L[i][method](L[i],unpack(posList['main']))
+ end
+ else
+ L[i][method](L[i],unpack(posList[i-1]))
+ end
+ end
+ else
+ for i=1,#L do
+ L[i][method](L[i],unpack(posList[i]))
+ end
end
- local method=sudden and'setPosition'or'movePosition'
- for i=1,#L do L[i][method](L[i],unpack(posList[i]))end
end
end
-do--function dumpBasicConfig()
+do-- function dumpBasicConfig()
local gameSetting={
- --Tuning
+ -- Tuning
'das','arr','dascut','dropcut','sddas','sdarr',
'ihs','irs','ims','RS',
- --System
+ -- System
'skin','face',
- --Graphic
+ -- Graphic
'ghostType','block','ghost','center','bagLine',
'dropFX','moveFX','shakeFX',
'text','highCam','nextPos',
- --Unnecessary graphic
+ -- Unnecessary graphic
-- 'grid','smooth',
-- 'lockFX','clearFX','splashFX','atkFX',
-- 'score',
@@ -695,11 +927,11 @@ do--function dumpBasicConfig()
return JSON.encode(S)
end
end
-do--function resetGameData(args)
+do-- function resetGameData(args)
local function task_showMods()
local time=0
while true do
- YIELD()
+ coroutine.yield()
time=time+1
if time%20==0 then
local M=GAME.mod[time/20]
@@ -712,14 +944,14 @@ do--function resetGameData(args)
end
end
local gameSetting={
- --Tuning
+ -- Tuning
'das','arr','dascut','dropcut','sddas','sdarr',
- 'ihs','irs','ims','RS','FTLock',
+ 'ihs','irs','ims','RS',
- --System
+ -- System
'skin','face',
- --Graphic
+ -- Graphic
'block','ghost','center','smooth','grid','bagLine',
'lockFX','dropFX','moveFX','clearFX','splashFX','shakeFX','atkFX',
'text','score','warn','highCam','nextPos',
@@ -727,7 +959,7 @@ do--function resetGameData(args)
local function _copyGameSetting()
local S={}
for _,key in next,gameSetting do
- if type(SETTING[key])=='table'then
+ if type(SETTING[key])=='table' then
S[key]=TABLE.shift(SETTING[key])
else
S[key]=SETTING[key]
@@ -736,20 +968,20 @@ do--function resetGameData(args)
return S
end
function resetGameData(args,seed)
- if not args then args=""end
+ if not args then args="" end
trySave()
GAME.result=false
GAME.rank=0
GAME.warnLVL0=0
GAME.warnLVL=0
- if args:find'r'then
+ if args:find'r' then
GAME.frameStart=0
GAME.recording=false
GAME.replaying=true
else
- GAME.frameStart=args:find'n'and 0 or 180-SETTING.reTime*60
- GAME.seed=seed or math.random(1046101471,2662622626)
+ 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
@@ -768,16 +1000,16 @@ do--function resetGameData(args)
else
PLY.newPlayer(1)
end
- freshPlayerPosition(args:find'q')
+ freshPlayerPosition((args:find'q') and 'quick' or 'normal')
VK.restore()
local bg=GAME.modeEnv.bg
- BG.set(type(bg)=='string'and bg or type(bg)=='table'and bg[math.random(#bg)])
+ BG.set(type(bg)=='string' and bg or type(bg)=='table' and bg[math.random(#bg)])
local bgm=GAME.modeEnv.bgm
- BGM.play(type(bgm)=='string'and bgm or type(bgm)=='table'and bgm[math.random(#bgm)])
+ BGM.play(type(bgm)=='string' and bgm or type(bgm)=='table' and bgm[math.random(#bgm)])
TEXT.clear()
- if GAME.modeEnv.eventSet=='royale'then
+ if GAME.modeEnv.eventSet=='royale' then
for i=1,#PLAYERS do
PLAYERS[i]:changeAtk(randomTarget(PLAYERS[i]))
end
@@ -796,14 +1028,13 @@ do--function resetGameData(args)
collectgarbage()
end
end
-do--function checkWarning()
+do-- function checkWarning(P,dt)
local max=math.max
- function checkWarning(dt)
- local P1=PLAYERS[1]
- if P1.alive then
- if P1.frameRun%26==0 then
- local F=P1.field
- local height=0--Max height of row 4~7
+ function checkWarning(P,dt)
+ if P.alive then
+ if P.frameRun%26==0 then
+ local F=P.field
+ local height=0-- Max height of row 4~7
for x=4,7 do
for y=#F,1,-1 do
if F[y][x]>0 then
@@ -814,7 +1045,7 @@ do--function checkWarning()
end
end
end
- GAME.warnLVL0=math.log(height-(P1.gameEnv.fieldH-5)+P1.atkBufferSum*.8)
+ GAME.warnLVL0=math.log(height-(P.gameEnv.fieldH-5)+P.atkBufferSum*.8)
end
local _=GAME.warnLVL
if _1.126 and P1.frameRun%30==0 then
+ if GAME.warnLVL>1.126 and P.frameRun%30==0 then
SFX.fplay('warn_beep',SETTING.sfx_warn)
end
elseif GAME.warnLVL>0 then
@@ -834,54 +1065,31 @@ end
---Game draw
-do--function drawSelfProfile()
- local lvColor={COLOR.J,COLOR.A,COLOR.C,COLOR.N,COLOR.S,COLOR.V,COLOR.P,COLOR.M,COLOR.W,COLOR.R,COLOR.O,COLOR.Y}
- local lvIcon=setmetatable({},{__index=function(self,lv)
- local c=lvColor[int((lv-1)/26)+1]or COLOR.Z
-
- local img=GC.DO{25,25,
- {"clear",0,0,0,0},
- {"setLW",2},
- {"setCL",c[1],c[2],c[3],.6},
- {"fRect",2,2,21,21,2},
- {"setCL",c},
- {"dRect",2,2,21,21,2},
- {"setCL",COLOR.Z},
- {"mText",(lv-1)%26+1,13,-1},
- }
- rawset(self,lv,img)
- return img
- end})
+-- Game draw
+do-- function drawSelfProfile()
local name
local textObj,scaleK,width,offY
function drawSelfProfile()
- local selfAvatar=USERS.getAvatar(USER.uid)
gc_push('transform')
gc_replaceTransform(SCR.xOy_ur)
- --Draw avatar
+ -- Draw avatar
gc_setLineWidth(2)
gc_setColor(COLOR.X)gc_rectangle('fill',0,0,-300,80)
gc_setColor(1,1,1)gc_rectangle('line',-300,0,300,80,5)
gc_rectangle('line',-73,7,66,66,2)
- gc_draw(selfAvatar,-72,8,nil,.5)
+ gc_draw(USERS.getAvatar(USER.uid),-72,8,nil,.5)
- --Draw username
- if name~=USERS.getUsername(USER.uid)then
+ -- Draw username
+ if name~=USERS.getUsername(USER.uid) then
name=USERS.getUsername(USER.uid)
- textObj=gc.newText(getFont(30),name)
+ textObj=GC.newText(getFont(30),name)
width=textObj:getWidth()
scaleK=210/math.max(width,210)
offY=textObj:getHeight()/2
end
gc_draw(textObj,-82,26,nil,scaleK,nil,width,offY)
- --Draw lv. & xp.
- gc_draw(lvIcon[USER.lv],-295,50)
- gc_line(-270,55,-80,55,-80,70,-270,70)
- gc_rectangle('fill',-210,55,150*USER.xp/USER.lv/USER.lv,15)
-
gc_pop()
end
end
@@ -890,7 +1098,7 @@ function drawOnlinePlayerCount()
gc_setColor(1,1,1)
gc_push('transform')
gc_replaceTransform(SCR.xOy_ur)
- gc_printf(("%s: %s/%s/%s"):format(text.onlinePlayerCount,NET.UserCount,NET.PlayCount,NET.StreamCount),-600,80,594,'right')
+ gc_printf(text.onlinePlayerCount:repD(NET.onlineCount),-600,80,594,'right')
gc_pop()
end
function drawWarning()
@@ -907,53 +1115,53 @@ end
---Widget function shortcuts
-function backScene()SCN.back()end
-do--function goScene(name,style)
+-- Widget function shortcuts
+function backScene() SCN.back() end
+do-- function goScene(name,style)
local cache={}
function goScene(name,style)
local hash=style and name..style or name
- if not cache[hash]then
- cache[hash]=function()SCN.go(name,style)end
+ if not cache[hash] then
+ cache[hash]=function() SCN.go(name,style) end
end
return cache[hash]
end
end
-do--function swapScene(name,style)
+do-- function swapScene(name,style)
local cache={}
function swapScene(name,style)
local hash=style and name..style or name
- if not cache[hash]then
- cache[hash]=function()SCN.swapTo(name,style)end
+ if not cache[hash] then
+ cache[hash]=function() SCN.swapTo(name,style) end
end
return cache[hash]
end
end
-do--function pressKey(k)
+do-- function pressKey(k)
local cache={}
function pressKey(k)
- if not cache[k]then
- cache[k]=function()love.keypressed(k)end
+ if not cache[k] then
+ cache[k]=function() love.keypressed(k) end
end
return cache[k]
end
end
-do--CUS/SETXXX(k)
+do-- CUS/SETXXX(k)
local CUSTOMENV=CUSTOMENV
local warnList={
'das','arr','dascut','dropcut','sddas','sdarr',
'ihs','irs','ims','RS',
- 'FTLock','frameMul','highCam',
+ 'frameMul','highCam',
'VKSwitch','VKIcon','VKTrack','VKDodge',
'simpMode',
}
- function CUSval(k)return function()return CUSTOMENV[k]end end
- function ROOMval(k)return function()return ROOMENV[k]end end
- function SETval(k)return function()return SETTING[k]end end
- function CUSrev(k)return function()CUSTOMENV[k]=not CUSTOMENV[k]end end
- function ROOMrev(k)return function()ROOMENV[k]=not ROOMENV[k]end end
- function SETrev(k)return function()if TABLE.find(warnList,k)then trySettingWarn()end SETTING[k]=not SETTING[k]end end
- function CUSsto(k)return function(i)CUSTOMENV[k]=i end end
- function ROOMsto(k)return function(i)ROOMENV[k]=i end end
- function SETsto(k)return function(i)if TABLE.find(warnList,k)then trySettingWarn()end SETTING[k]=i end end
+ function CUSval(k) return function() return CUSTOMENV[k] end end
+ function ROOMval(k) return function() return ROOMENV[k] end end
+ function SETval(k) return function() return SETTING[k] end end
+ function CUSrev(k) return function() CUSTOMENV[k]=not CUSTOMENV[k] end end
+ function ROOMrev(k) return function() ROOMENV[k]=not ROOMENV[k] end end
+ function SETrev(k) return function() if TABLE.find(warnList,k) then trySettingWarn() end SETTING[k]=not SETTING[k] end end
+ function CUSsto(k) return function(i) CUSTOMENV[k]=i end end
+ function ROOMsto(k) return function(i) ROOMENV[k]=i end end
+ function SETsto(k) return function(i) if TABLE.find(warnList,k) then trySettingWarn() end SETTING[k]=i end end
end
diff --git a/parts/gameTables.lua b/parts/gameTables.lua
index 97af692b9..d1eee3b2b 100644
--- a/parts/gameTables.lua
+++ b/parts/gameTables.lua
@@ -1,4 +1,4 @@
---Static data tables
+-- Static data tables
BLOCK_NAMES={
'Z','S','J','L','T','O','I',
'Z5','S5','P','Q','F','E',
@@ -6,13 +6,13 @@ BLOCK_NAMES={
'J5','L5','R','Y','N','H','I5',
'I3','C','I2','O1'
}
-BLOCK_CHARS={}for i=1,#BLOCK_NAMES do BLOCK_CHARS[i]=CHAR.mino[BLOCK_NAMES[i]]end
+BLOCK_CHARS={} for i=1,#BLOCK_NAMES do BLOCK_CHARS[i]=CHAR.mino[BLOCK_NAMES[i]] end
BLOCK_COLORS={
COLOR.R,COLOR.F,COLOR.O,COLOR.Y,COLOR.L,COLOR.J,COLOR.G,COLOR.A,
COLOR.C,COLOR.N,COLOR.S,COLOR.B,COLOR.V,COLOR.P,COLOR.M,COLOR.W,
COLOR.dH,COLOR.D,COLOR.lY,COLOR.H,COLOR.lH,COLOR.dV,COLOR.dR,COLOR.dG,
}
-RANK_CHARS={'B','A','S','U','X'}for i=1,#RANK_CHARS do RANK_CHARS[i]=CHAR.icon['rank'..RANK_CHARS[i]]end
+RANK_CHARS={'B','A','S','U','X'} for i=1,#RANK_CHARS do RANK_CHARS[i]=CHAR.icon['rank'..RANK_CHARS[i]] end
RANK_COLORS={
{.8,.86,.9},
{.6,.9,.7},
@@ -20,7 +20,17 @@ RANK_COLORS={
{1,.5,.4},
{.95,.5,.95},
}
-do--SVG_TITLE_FILL, SVG_TITLE_LINE
+GROUP_COLORS={
+ [0]=COLOR.Z,
+ [1]={STRING.hexColor'e57373'},
+ [2]={STRING.hexColor"4caf50"},
+ [3]={STRING.hexColor'5c6bc0'},
+ [4]={STRING.hexColor'ffe082'},
+ [5]={STRING.hexColor'ba68c8'},
+ [6]={STRING.hexColor'80deea'},
+}
+
+do-- SVG_TITLE_FILL, SVG_TITLE_LINE
SVG_TITLE_FILL={
{
0,0,
@@ -131,24 +141,24 @@ do--SVG_TITLE_FILL, SVG_TITLE_LINE
SVG_TITLE_LINE=TABLE.shift(SVG_TITLE_FILL)
SVG_TITLE_LINE[8],SVG_TITLE_LINE[9]={},{}
- for j=1,16 do SVG_TITLE_LINE[8][j]=SVG_TITLE_FILL[8][j]end
- for j=19,#SVG_TITLE_FILL[8]-2 do SVG_TITLE_LINE[9][j-18]=SVG_TITLE_FILL[8][j]end
+ for j=1,16 do SVG_TITLE_LINE[8][j]=SVG_TITLE_FILL[8][j] end
+ for j=19,#SVG_TITLE_FILL[8]-2 do SVG_TITLE_LINE[9][j-18]=SVG_TITLE_FILL[8][j] end
end
-do--SVG_TITLE_FAN
+do-- SVG_TITLE_FAN
SVG_TITLE_FAN={}
local sin,cos=math.sin,math.cos
for i=1,9 do
local L=TABLE.copy(SVG_TITLE_LINE[i])
SVG_TITLE_FAN[i]=L
for j=1,#L,2 do
- local x,y=L[j],L[j+1]--0) and Tennis (favorite sport of the creator of Tetris). Also, the Tetris games developed by Nintendo and SEGA were licensed by TTC. These two companies do not have the copyright of Tetris.",
+ -- _comment: original Lua file had this comment: "Thanks to Alexey Pajitnov!"
},
{"All Clear",
"pc perfectclear ac allclear",
"term",
- "Formerly known as Perfect Clear (PC). That is also still the term preferred by the communities and used in Techmino.\nClear all minoes on the field.",
+ "Also known as Perfect Clear (PC). That is also still the term preferred by the communities and used in Techmino.\nClear all minoes on the field.",
},
{"HPC",
- "hpc hc clear halfperfectclear",
+ "hc clear halfperfectclear",
"term",
- "*Techmino-exclusive*\nHalf Perfect Clear\nExtension of an All Clear. Should a line clear resemble an All Clear when ignoring lines below the clear, the clear is a Half Perfect Clear, and sends a small extra amount of attack.",
+ "*Techmino-Exclusive*\nHalf Perfect Clear\nAn extension to All Clear. Should a line clear resemble an All Clear when ignoring lines below the clear, the clear is a Half Perfect Clear and sends a minor extra attack.",
},
-
{"Spin",
"spin",
"term",
- "Use rotation to move a piece into a position otherwise unreachable. In some games, this manipulation sends extra attacks or awards extra score.",
+ "Use rotation to move a piece into a position otherwise unreachable. In some games, this manipulation sends extra attacks or awards additional scores. Different games may have different mechanisms on what counts as a spin.",
},
{"Mini",
"mini",
"term",
- "A modifier to Spins applied to Spin actions that the game considers easy (thus the name \"EZ T-Spin\" in an old game). Score and attack bonuses are reduced for Mini Spins than ordinary Spins.\nDifferent games have different rules for what counts as a Mini Spin, and many are not intuitive. You can just remember a few common shapes.",
+ "A modifier term to Spins applied to Spin actions that the game considers easy (thus the name “EZ T-Spin” in an old game). Score and attack bonuses are reduced for Mini Spins than ordinary Spins.\nDifferent games have different rules for what counts as a Mini Spin, and many are not intuitive. You can just remember a few common shapes.",
},
{"All-Spin",
"allspin",
"term",
- "A rule in which spins of all pieces are awarded extra attacks/scores, rather than just spins of the T piece (\"T-Spin only\").",
+ "A rule in which spins of all pieces are awarded extra attacks/scores, rather than just spins of the T piece (aka “T-Spin only”).",
},
{"T-Spin",
"tspin",
"term",
- "A spin performed using the T Tetromino.\nIn modern official games, T-Spins are detected using the 3-corner rule, i.e. if at least three of the four cells diagonal to the rotation center is occupied by minoes, it is considered as a T-Spin. Some games have extra rules to determine a T-Spin as a Mini T-Spin instead, which has reduced attacks/scores.",
+ "A spin performed using the T Tetromino.\nIn modern official games, T-Spins are detected using the 3-corner rule, i.e., if at least three of the four cells diagonal to the rotation center is occupied by minoes, it is considered as a T-Spin. Some games have additional rules to determine a T-Spin as a Mini T-Spin instead, which has reduced attacks/scores.",
},
{"TSS",
- "tss t1 tspinsingle",
+ "t1 tspinsingle",
"term",
- "T-Spin Single\nClear 1 line with a T-Spin.",
+ "T-Spin Single\nClear one line with a T-Spin.",
},
{"TSD",
- "tsd t2 tspindouble",
+ "t2 tspindouble",
"term",
- "T-Spin Double\nClear 2 lines with a T-Spin.",
+ "T-Spin Double\nClear two lines with a T-Spin.",
},
{"TST",
- "tst t3 tspintriple",
+ "t3 tspintriple",
"term",
- "T-Spin Triple\nClear 3 lines with a T-Spin.",
+ "T-Spin Triple\nClear three lines with a T-Spin.",
},
{"MTSS",
- "mtss minitspinsingle tsms tspinminisingle",
+ "minitspinsingle tsms tspinminisingle",
"term",
- "Mini T-Spin Single\nFormerly known as T-Spin Mini Single (TSMS).\nClear 1 line with a Mini T-Spin.\nDifferent games have different ways to determine whether a T-Spin is a Mini.",
+ "Mini T-Spin Single\nFormerly known as T-Spin Mini Single (TSMS).\nClear one line with a Mini T-Spin.\nDifferent games have different ways to determine whether a T-Spin is a Mini.",
},
{"MTSD",
- "mtsd minitspindouble tsmd tspinminidouble",
+ "minitspindouble tsmd tspinminidouble",
"term",
- "Mini T-Spin Double\nFormerly known as T-Spin Mini Double (TSMD).\nClear 2 lines with a Mini T-Spin.\nDifferent games have different ways to determine whether a T-Spin is a Mini.\nIn addition, different games have different behaviors when clearing a Mini T-Spin Double: some games credit this move correctly, and some games use a different displayed text because they never programmed this in.",
+ "Mini T-Spin Double\nFormerly known as T-Spin Mini Double (TSMD).\nClear two lines with a Mini T-Spin.MTSD only exists in a limited number of games and may have very different triggers.",
},
{"O-Spin",
"ospin",
"term",
- "In most cases, it's a meme.\nThe shape and position of the O Tetromino (a.k.a. the Square) does not change upon rotation, thus making it lack interesting spins/kicks that other Tetrominoes have, or be stuck in a place unable to get out.\nAs a joke, some people have made heavily edited videos or even programmed games where the O pieces can change shape and \"spin\" into different positions.\nTechmino also supports O-Spin in most modes.",
+ "Because the O block doesn’t change its shape after any rotations, there is no way to bring it out once it is stuck in a place. So, there was a meme about O-Spin in the Tetris community: Someone has made a fake video on how to perform an O-spin in Tetris 99 and Tetris Friend, and it went viral; XRS allows O blocks to “teleport” into a hole.\nIn TRS, you can rotate the O block in a specific way to teleport or transform O into another block to achieve an O-spin.",
},
{"Rotation Systems",
"wallkick rotationsystem",
"term",
- "Systems that determine how the pieces rotate.\n\nIn modern Tetris games, tetrominoes can rotate on a specfic rotation center (but this may be absent in some games). If the minoes overlap with the walls or the field, the system would attempt to perform some offsets (a process known as \"wall-kicking\"). Wall kicks allow minoes to move into in specific-shaped holes.",
+ "Systems that determine how the pieces rotate.\n\nIn modern Tetris games, tetrominoes can rotate on a specific rotation center (but this may be absent in some games). If the minoes overlap with the walls or the field, the system will attempt to perform some offsets (a process known as “wall-kicking”). Wall kicks allow minoes to move into specific-shaped holes.",
},
{"Orientation",
- "orientation direction 0r2l 02 20 rl lr",
+ "direction 0r2l 02 20 rl lr",
"term",
- "In SRS and SRS-like rotation systems, there are standard notations describing the orientations of the minoes:\n 0 for Original orientation; R for right, or 90° clockwise; L for left, or 90° counterclockwise; 2 for spin twice (180°). For example, 0→L means rotating counterclockwise from original orientation (0) to L; 0→R means rotating clockwise from original orientation (0) to R; 2→R means rotating counterclockwise from 2 (180°) to R.",
+ "In SRS and SRS-like rotation systems, there is a system of standard notations describing the orientations of the minoes:\n0 for Original orientation; R for right, or 90° clockwise; L for left, or 90° counterclockwise; 2 for spin twice (180°).\nFor example, 0→L means rotating counterclockwise from original orientation (0) to L; 0→R means rotating clockwise from original orientation (0) to R; 2→R means rotating counterclockwise from 2 (180°) to R.",
},
{"ARS",
- "ars arikrotationsystem atarirotationsystem",
+ "arikrotationsystem atarirotationsystem",
"term",
"It can refer to two things:\nArika Rotation System, which is used in Tetris: The Grand Master games.\nAtari Rotation System, which aligns pieces to the top-left when rotating.",
},
{"ASC",
"ascension",
"term",
- "Rotation system used in the Tetris clone Ascension. All pieces use the same two kick tables (one for CW, one for CCW), and the kick range is approximately ± 2 blocks on both axis.\n\nIn Techmino, ASC+ is a modified version of Ascension's rotation system, adding kicks for 180° spins.",
+ "Rotation system used in the Tetris clone Ascension. All pieces use the same two kick tables (one for CW, one for CCW), and the kick range is approximately ± 2 blocks on both axis.",
+ },
+ {"ASC+",
+ "ascension ascplus",
+ "term",
+ "The modified version of ASC in Techmino with support of wall kicks for 180° rotations.",
},
{"BRS",
- "brs bulletproofsoftware",
+ "bulletproofsoftware",
"term",
"BPS rotation system, the rotation system used in Tetris games by Bullet-Proof Software.",
},
{"BiRS",
- "birs biasrs biasrotationsystem",
+ "biasrs biasrotationsystem",
"term",
- "*Techmino exclusive*\n\nBias Rotation System, Techmino's original rotation system based on XRS and SRS.\nIt sets an offset to the rotation if you hold left/right/soft drop when you rotate.\nIf rotation fails when downwards offset is applied, it tries again without the downwards offset.\nThen it tries without left/right offset.\nIf it fails, then the rotation will not occur.\n\nCompared to XRS, BiRS only uses a single kick table, making it easier to memorize; also keeps the climb-over-terrain feature of SRS.\n\nThe final kick offset's euclidean distance can't be larger than √5; if there is a horizontal offset, the final kick offset can't be in the opposite direction.",
+ "*Techmino-Exclusive*\n\nBias Rotation System, Techmino’s original rotation system based on XRS and SRS.\nIt sets an offset to the rotation if you hold left/right/soft drop when you rotate.\nIf rotation fails when downwards offset is applied, it tries again without the downwards offset.\nThen it tries without left/right offset.\nIf it fails, then the rotation will not occur.\n\nCompared to XRS, BiRS only uses a single kick table, making it easier to memorize; also keeps the climb-over-terrain feature of SRS.\n\nThe final kick offset’s euclidean distance can’t be larger than √5; if there is a horizontal offset, the final kick offset can’t be in the opposite direction.",
},
{"C2RS",
- "c2rs",
+ "c2rs cultris2",
+ "term",
+ "Cultris II rotation system, a rotation system used in the Tetris clone Cultris II.\nAll rotations and all pieces share the same kick table (left, right, down, down-left, down-right, left 2, right 2), with left prioritizing over right.\n\nIn Techmino, C2sym is a modification to this rotation system that chooses whether to check left or right first depending on the piece and rotation.",
+ },
+ {"C2sym",
+ "cultris2",
"term",
- "Cultris II rotation system, a rotation system used in the Tetris clone Cultris II.\nAll rotations and all pieces share the same kick table (left, right, down, down-left, down-right, left 2, right 2), with left priortizing over right.\n\nIn Techmino, C2sym is a modification to this rotation system that chooses whether to check left or right first depending on the piece and rotation.",
+ "A modification of C2RS in Techmino. It changes the priorities of L/R based on the shapes of different blocks.",
},
{"DRS",
- "drs dtetrotationsystem",
+ "dtetrotationsystem",
"term",
"DTET Rotation System\nThe rotation system used in DTET.",
},
{"NRS",
- "nrs nintendorotationsystem",
+ "nintendorotationsystem",
"term",
- "Nintendo Rotation System\nThe rotation system used in the Tetris games on the NES and Game Boy.\nIt has two mirrored versions; the left-handed version is used on Game Boy, and the right-handed version on the NES.",
+ "Nintendo Rotation System\nThe rotation system used in the Tetris games on the NES and Game Boy.\nIt has two mirrored versions; the left-handed version is used on Game Boy and the right-handed version on the NES.",
},
{"SRS",
- "srs superrotationsystem",
+ "superrotationsystem",
+ "term",
+ "Super Rotation System, the most widely used rotation system by modern Tetris games and the foundation of many self-made rotation systems. There are four orientations for each tetromino, and they can rotate clockwise or counterclockwise (But without 180° rotations). Should a Tetromino overlap with the wall, floor, or other minoes on the field after rotation, a few offset positions will be checked, allowing pieces to kick off walls and floors. You can look up the details of the wall kick table on Tetris Wiki.",
+ },
+ {"SRS+",
+ "srsplus superrotationsystemplus",
"term",
- "Super Rotation System, the most widely used rotation system by modern Tetris games, and is the foundation of many self-made rotation systems. There are four orientations for each tetromino, and they can rotate clockwise or counterclockwise (But without 180° rotations). Should a Tetromino overlap with the wall, floor or other minoes on the field after rotation, a few offset positions will be checked, allowing pieces to kick off walls and floors. You can look up the details of the wall kick table on Tetris Wiki.",
+ "The extension to SRS with the support of 180° wall kicks.",
},
{"TRS",
- "trs techminorotationsystem",
+ "techminorotationsystem",
"term",
- "*Techmino-exclusive*\nTechmino Rotation System\nThe rotation system used in Techmino, based on SRS.\nIt includes fixes on common cases where S/Z are locked from rotating and some extra useful kicks. Each pentomino also has a kick table roughly based on SRS logic.",
+ "*Techmino-Exclusive*\nTechmino Rotation System\nThe rotation system used in Techmino, based on SRS.\nIt includes fixes on common cases where S/Z are locked from rotating and some extra useful kicks. Each pentomino also has a kick table roughly based on SRS logic. TRS supports O-spins.",
},
{"XRS",
"xrs",
"term",
- "X rotation system, a rotation system used in T-ex.\n\nIt introduced a feature to \"use another kick table if you hold a direction key\", making it possible for players to tell the game where they want the piece to go.",
+ "X rotation system, a rotation system used in T-ex.\n\nIt introduced a feature to “use another kick table if you hold a direction key,” making it possible for players to tell the game where they want the piece to go.",
},
-
{"Back to Back",
"b2b btb backtoback",
"term",
- "Clearing 2 or more technical line clears (Spins and Tetrises) in a row (without introducing ordinary line clears) gives extra attack power.\nUnlike combos, placing pieces that do not clear lines does not affect Back to Back.",
+ "Aka B2B. Clearing two or more technical line clears (Spins and Tetrises) in a row (without introducing ordinary line clears) gives extra attack power.\nUnlike combos, placing pieces that do not clear lines does not affect Back to Back.",
},
{"B2B2B",
- "b2b2b b3b",
+ "b3b",
"term",
- "*Techmino-exclusive*\nClearing many Back to Backs to fill the Back to Back gauge, and eventually you will be able to perform a Back to Back to Back, giving more bonus attack. A.k.a. B3B.",
+ "*Techmino-Exclusive*\nBack to back to back, aka B3B. Clearing many Back to Backs to fill the Back to Back gauge, you will eventually perform a Back to Back to Back, giving more bonus attacks.",
},
{"Fin, Neo, Iso",
"fin neo iso",
"term",
- "Special T-Spin techniques that exploit the T piece's kicks and T-Spin detections.\nThey might worth different values in different games (some games consider them Minis), and hardly have real value in combat due to their relatively complex setup.",
+ "Special T-Spin techniques that exploit the T piece’s kicks and T-Spin detections.\nThey might be worth different values in different games (some consider them as Minis) but hardly have real value in combat due to their relatively complex setup.",
},
{"Modern Tetris",
"modern",
"term",
- "The concept of a \"modern\" Tetris game or block-stacking game is a bit fuzzy. In general, a block-stacking game that somewhat resembles games that follow the Tetris Design Guideline is considered a modern game. Here are some rules of thumb, but they are not hard requirements:\n1. The visible part of the Matrix is 10w x 20h, often with additional hidden rows above this.\n2. Pieces spawn in the top-middle of the visible matrix. Each piece has a consistent spawn orientation and color.\n3. Has an appropriate randomizer like 7-Bag and His.\n4. Has an appropriate rotation system, with at least the ability to rotate both directions.\n5. Has an appropriate lockdown delay system.\n6. Has an appropriate top-out condition.\n7. Has a NEXT queue, with multiple next pieces displayed (usually 3 to 6), and with the presentation in the queue matching the spawn orientation of the piece.\n8. Has a HOLD queue.\n9. If there is spawn delay or line delay, usually has IRS and IHS.\n10. Has a DAS system for precise and swift sideways movements.",
+ "The concept of a “modern” Tetris game or block-stacking game is fuzzy. Generally speaking, a block-stacking game that resembles games that follow the Tetris Design Guideline is considered a modern game. Here are some rules of thumb, but they are not hard requirements:\n1. The visible part of the Matrix is 10 w × 20 h, often with additional hidden rows above this.\n2. Pieces spawn in the top-middle of the visible matrix. Each piece has a consistent spawn orientation and color.\n3. Has an appropriate randomizer like 7-Bag and His.\n4. Has a proper rotation system, with at least the ability to rotate both directions.\n5. Has an appropriate lockdown delay system.\n6. Has an appropriate top-out condition.\n7. Has a Next queue, with multiple next pieces displayed (usually 3–6), and with the presentation in the queue matching the spawn orientation of the piece.\n8. Has a Hold queue.\n9. If there is spawn delay or line delay, usually has IRS and IHS.\n10. Has a DAS system for precise and swift sideways movements.",
},
- {"Tetrominos' Shapes",
+ {"Tetrominos’ Shapes",
"shape structure form tetromino tetrimino",
"term",
- "In standard Tetris games, all the blocks used are tetrominoes, i.e. Blocks that are linked by four minoes side-by-side.\n\nThere are seven kinds of tetrominoes in total when allowing rotations and disallowing reflections. These tetrominoes are named by the letter in the alphabet that they resemble. They are Z, S, J, L, T, O, and I.",
+ "In standard Tetris games, all the blocks used are tetrominoes, i.e., Blocks that are linked by four minoes side-by-side.\n\nThere are seven kinds of tetrominoes in total when allowing rotations and disallowing reflections. These tetrominoes are named by the letter in the alphabet that they resemble. They are Z, S, J, L, T, O, and I. See the “Shape & Name” entry for more information.",
},
- {"Tetrominos' Colors",
+ {"Tetrominos’ Colors",
"colour hue tint tetromino tetrimino",
"term",
- "Many modern Tetris games use the same color scheme for the tetrominoes. The colors are:\nZ–red, S–green, J–blue, L–orange, T–purple, O–yellow, and I–cyan.\n\nTechmino also uses this \"standard\" coloring for the tetrominoes.",
+ "Many modern Tetris games use the same color scheme for the tetrominoes. The colors are:\nZ–red, S–green, J–blue, L–orange, T–purple, O–yellow, and I–cyan.\n\nTechmino also uses this “standard” coloring for the tetrominoes.",
},
{"IRS",
- "irs initialrotationsystem",
+ "initialrotationsystem",
"term",
"Initial Rotation System\nHolding a rotation key during spawn delay to spawn the piece pre-rotated. Sometimes prevents death.",
},
{"IHS",
- "ihs initialholdsystem",
+ "initialholdsystem",
"term",
- "Initial Hold System\nHolding the hold key during spawn delay to spawn the held piece (or Next piece in the Next queue if there is no held piece) instead of the current piece, and put the current piece in hold as if the player has performed the held before spawning. Sometimes prevents death.",
+ "Initial Hold System\nHolding the Hold key during spawn delay to spawn the held piece (or next piece in the Next queue if there is no held piece) instead of the current piece, and put the current piece in the Hold as if the player has performed the held before spawning. Sometimes prevents death.",
},
{"IMS",
- "ims initialmovesystem",
+ "initialmovesystem",
"term",
- "*Techmino-exclusive*\nInitial Movement System\nHolding a sideways movement key during spawn delay to spawn the piece one block off to the side. Sometimes prevents death.\nNote that DAS need to be full charged when new piece appear",
+ "*Techmino-Exclusive*\nInitial Movement System\nHolding a sideways movement key during spawn delay to spawn the piece one block off to the side. Sometimes prevents death.\nNote that DAS needs to be fully charged when a new piece appears.",
},
{"Next",
"nextpreview",
"term",
- "Displays the next few pieces to come. Using this to plan is often a good habit.",
+ "Displays the next few pieces to come. It is an essential skill to plan ahead where to place blocks in the Next queue to improve your Tetris skill.",
},
{"Hold",
"hold",
"term",
- "Save your current piece for later use, and take out a previously held piece (or next piece in the next queue, if no piece was held) to place instead. You can only perform this once per piece in most cases.\n\nTechmino Exclusive: Techmino has a \"In-place hold\" feature. When enabled, pieces that spawn from the Hold queue will spawn at where your currently-controlling piece is, instead of at the top of the matrix.",
+ "Save your current piece for later use, and take out a previously held piece (or next piece in the next queue, if no piece was held) to place instead. You can only perform this once per piece in most cases.\n\n*Techmino-Exclusive*: Techmino has an “In-place Hold” feature. When enabled, pieces that spawn from the Hold queue will spawn at where your currently-controlling piece is, instead of at the top of the matrix.",
},
{"Swap",
- "swap hold",
+ "hold",
"term",
- "Like *hold*, swap your current piece and the first piece of next queue. You can also only perform this once per piece in most cases.",
+ "Like *Hold*, swap your current piece and the first piece of the next queue. You can also only perform this once per piece in most cases.",
},
{"Deepdrop",
- "deepdrop shenjiang",
+ "shenjiang",
"term",
- "*Techmino exclusive*\n\nA special function that allows minoes to teleport through the wall to enter a hole. When the mino hits the bottom, pressing the soft drop button again will enable the deep drop. if there is a hole that fits the shape of the mino, it will teleport into this hole immediately/nThis mechanism is especially useful for AI because it allows AI to disregard the differences between different rotation systems.",
+ "*Techmino-Exclusive*\n\nA special function allows minoes to teleport through the wall to enter a hole. When the mino hits bottom, pressing the soft drop button again will enable the deep drop. Suppose there is a hole that fits the shape of the mino. In that case, it will teleport into this hole immediately.\nThis mechanism is especially useful for AIs because it allows AI to disregard the differences between different rotation systems.",
},
{"Misdrop",
"md misdrop",
@@ -602,97 +665,112 @@ return{
{"Mishold",
"mh mishold",
"term",
- "Accidentally pressed Hold key. This can lead to having to use an undesired piece or missing out a chance to a PC.",
+ "Accidentally pressed the Hold key. This can lead to using an undesired piece or missing out on a chance to a PC.",
},
{"sub",
"sub",
"term",
- "A sub-(number) time means the time is below a certain milestone. The unit of the time is often left out and inferred, for example, a \"sub-30\" time for a 40-line Sprint means below 30 seconds, and a \"sub-15\" time for a 1000-line Sprint means below 15 minutes.",
+ "A sub-[number] time means the time is below a certain milestone. The unit of the time is often left out and inferred; for example, a “sub-30” time for a 40-line Sprint means below 30 seconds, and a “sub-15” time for a 1000-line Sprint means below 15 minutes.",
+ },
+ {"Digging",
+ "downstacking ds",
+ "term",
+ "Clearing garbage lines entered from the bottom of the field. Aka downstacking.",
},
{"Donation",
- "donation donate",
+ "donate",
"term",
- "A method of \"plugging\" up the Tetris hole to send a T-Spin. After the T-Spin, the Tetris hole is opened up once again to allow the continuation of Tetris or downstacking.\n--Harddrop wiki",
+ "A method of “plugging” up the Tetris hole to send a T-Spin. After the T-Spin, the Tetris hole is opened up once again to allow the continuation of Tetris or downstacking.\n-- Harddrop wiki",
},
- {"\"Debt\"",
+ {"‘Debt’",
"qianzhai debt owe",
"term",
- "A terminology used in the Chinese Tetris community. A \"debt\" refers to a situation where one must first finish constructing a specific setup before he or she can perform one or more T-spins with real attacks. When constructing a setup where one or multiple debts are created, it is important to observe the opponent carefully to ensure your safety; otherwise, there is a high probability of topping out before the construction is finished.\n\nThis term is frequently used to describe setups such as TST tower. No real attacks can be made before the setup is constructed completely.",
+ "A terminology used in the Chinese Tetris community. A “debt” refers to a situation where one must first finish constructing a specific setup before they can perform one or more T-spins with real attacks. When constructing a setup where one or multiple debts are created, it is important to observe the opponent to ensure your safety; otherwise, there is a high probability of topping out before the construction is finished.\n\nThis term is frequently used to describe setups such as TST tower. No real attacks can be made before the setup is constructed completely.",
},
{"Attack & Defend",
"attacking defending",
"term",
- "Attacking: send garbage lines to your opponent by clearing lines.\nDefending: after your opponent send you lines, you offset this garbage by clearing lines.\nCounter attack: Send attack back at your opponent after offsetting incoming garbage, or taking the hit then attack back.\nIn most games, garbage offsetting is 1:1, i.e. one attack offsets one incoming garbage.",
+ "Attacking: send garbage lines to your opponent by clearing lines.\nDefending: You offset this garbage by clearing lines after your opponent sends you lines.\nCounter attack: Send attack back at your opponent after offsetting incoming garbage, or taking the hit, then attack back.\nIn most games, garbage offsetting is 1:1, i.e., one attack offsets one incoming garbage.",
},
{"Combo",
"ren combo",
"term",
- "Known in Japan as REN.\nConsecutive line clears make up combos. The second line clear in the combo is called 1 combo, and the third line clear is called 2 combo, and so on.\nUnlike Back to Back, placing a piece that does not clear a line will break the combo.",
+ "Known in Japan as REN.\nConsecutive line clears make up combos. The second line clear in the combo is called 1 Combo, and the third line clear is called 2 Combo, and so on.\nUnlike Back to Back, placing a piece that does not clear a line will break the combo.",
},
{"Spike",
"spike",
"term",
- "Send a lot of attacks in a short time.\n\nTechmino and Tetr.io has a spike counter, which shows how many attacks you send in a short time.\n\nNote that accumulated garbage due to network lag do not count as a spike.",
+ "Sending many attacks in a short time.\n\nBoth Techmino and TETR.IO have spike counters, which shows how many attacks you send in a short time.\n\nNote that accumulated garbage due to network lag do not count as a spike.",
},
{"Side well",
- "sidewell",
+ "ren combo sidewell",
+ "term",
+ "A stacking method where you leave a well of a certain width on the side.\nA Side 1-wide setup is the traditional Tetris setup (i.e., Side well Tetris).\nA Side 2-, 3-, or 4-wide setup is a combo setup. For new players, they can be effective ways to send attacks. However, opponents can easily send you garbage while building your stack, killing you or cutting your stack short. Because of this, advanced players might not opt to build tall stacks and instead keep a steady stream of T-Spins and Tetrises and attack when the opponent is unlikely to offset the garbage.",
+ },
+ {"Center well",
+ "ren combo centerwell",
"term",
- "A stacking method where you leave a well of a certain width on the side.\nA Side 1-wide setup is the traditional Tetris setup (i.e. Side well Tetris).\nA Side 2-, 3-, or 4-wide setup is a combo setup. For new players, they can be effective ways to send attacks. However, opponents can easily send you garbage while you are building your stack, killing you or cutting your stack short. Because of this, advanced players might not opt to build tall stacks, and rather keep a steady stream of T-Spins and Tetrises and attack when the opponent is unlikely to offset the garbage.",
+ "A stacking method where you leave a well of a certain width at the center.",
+ },
+ {"Partial well",
+ "ren combo partialwell",
+ "term",
+ "A stacking method where you leave a well of a certain width at not-center-or-side position.",
},
{"Side 1-wide",
"s1w side1wide sidewelltetris",
"term",
- "Also known as Side well Tetris.\nThe most traditional way to play. It is also easy to do in modern Tetris and can send a half-decent amount of attack. However this is hardly used in advanced matches due to the lower efficiency of Tetrises compared to T-Spins.",
+ "Also known as Side well Tetris.\nThe most traditional way to play. It is also easy to do in modern Tetris and can send a half-decent attacks. However, this is hardly used in advanced matches due to the lower efficiency of Tetrises compared to T-Spins.",
},
{"Side 2-wide",
"s2w side2wide",
"term",
- "The stacking method where you leave a 2-block-wide well on the side. A common combo setup.\nEasy to use. New players can give it a try and can produce some half-decent combos when combined with hold. Not often used in advanced games, because it takes more time to build the stack, leaving room for opponents to send garbage and cut your stack short. It is also not so good in terms of efficiency.",
+ "The stacking method where you leave a two-block-wide well on the side. A common combo setup.\nEasy to use. New players can give it a try and produce some half-decent combos when combined with Hold. Not often used in advanced games because it takes more time to build the stack, leaving room for opponents to send garbage and cut your stack short. It is also not so good in terms of efficiency.",
},
{"Side 3-wide",
"s3w side2wide",
"term",
- "The stacking method where you leave a 3-block-wide well on the side. A combo setup is less common than 2-wide.\nCan perform more combos than 2-wide, but also harder to do, easy to break the combo.",
+ "The stacking method where you leave a three-block-wide well on the side. A combo setup is less common than 2-wide.\nCan perform more combos than 2-wide, but also harder to do, easy to break the combo.",
},
{"Side 4-wide",
"s4w side4wide",
"term",
- "The stacking method where you leave a 4-block-wide well on the side. A combo setup.\nIf done well, can produce very impressive combos. Also, it takes less time to build up, so you might be able to start your combo before incoming garbage. However, there is still a risk of being killed by incoming garbage, and is thus less overpowered.",
+ "The stacking method where you leave a four-block-wide well on the side. A combo setup.\nIf done well, it can produce very impressive combos. Also, it takes less time to build up, so you might be able to start your combo before incoming garbage. However, there is still a risk of being killed by incoming garbage, and it is thus less overpowered.",
},
{"Center 1-wide",
"c1w center1wide centerwelltetris",
"term",
- "Also known as Center well Tetris\nThe stacking method where you leave a 1-block-wide well in the middle. Commonly used in combat because this allows Tetrises as well as T-Spins, and not too difficult.",
+ "Also known as Center well Tetris.\nThe stacking method where you leave a one-block-wide well in the middle. Commonly used in combat because this allows Tetrises and T-Spins and is not too difficult to make.",
},
{"Center 2-wide",
"c2w center2wide",
"term",
- "The combo setup where you leave a 2-block-wide well in the middle. Not very common though.",
+ "The combo setup where you leave a two-block-wide well in the middle. Not very common, though.",
},
{"Center 3-wide",
"c3w center3wide",
"term",
- "The combo setup where you leave a 3-block-wide well in the middle. Not very common though.",
+ "The combo setup where you leave a three-block-wide well in the middle. Not very common, though.",
},
{"Center 4-wide",
"c4w center4wide",
"term",
- "The stacking method where you leave a 4-block-wide well in the middle.\nThe infamous combo setup that not only makes a lot of combos but also abuses the death conditions and won't die even if you receive some garbage. This technique is often disliked by players due to how unbalanced it is.",
+ "The stacking method where you leave a four-block-wide well in the middle.\nThe infamous combo setup that not only makes many combos but also abuses the death conditions and won’t die even if you receive some garbage. Players often dislike this technique due to how unbalanced it is.",
},
{"Residual",
- "residual c4w s4w",
+ "c4w s4w",
"term",
- "Refers to how many blocks to leave in the well of a 4-wide combo setup. The most common are 3-residual and 6-residual.\n3-residual has fewer variations and is easier to learn, with a pretty good chance of success, and it's pretty useful in combat.\n6-residual has more variables and is harder, but can be more consistent if you do it well. It can also be used for special challenges like getting 100 combos in an infinite 4-wide challenge.",
+ "Refers to how many blocks to leave in the well of a four-wide combo setup. The most common are 3-residual and 6-residual.\n3-residual has fewer variations and is easier to learn, with a pretty good chance of success, and it’s pretty useful in combat.\n6-residual has more variables and is harder, but can be more consistent if you do it well. It can also be used for special challenges like getting 100 combos in an infinite 4-wide challenge.\nIn principle, use 6-Res first, then 5-Res and 3-Res, and then 4-Res.",
},
- {"6-3 Stacking",
- "63stacking",
+ {"6–3 Stacking",
+ "63stacking six-three sixthree",
"term",
- "A way of stacking where you have a 6-block-wide stack on the left, and a 3-block-wide stack on the right.\nFor a skilled player, this method of stacking might reduce the keypresses needed for stacking, and is a popular Sprint stacking method. The reason why it works has to do with the fact that pieces spawn with a bias to the left.",
+ "A way of stacking where you have a six-block-wide stack on the left and a three-block-wide stack on the right.\nFor a skilled player, this method of stacking might reduce the keypresses needed for stacking, and is a popular Sprint stacking method. The reason why it works has to do with the fact that pieces spawn with a bias to the left.",
},
{"Freestyle",
- "freestyle ziyou",
+ "ziyou",
"term",
- "This term is usually used in 20TSDs. Freestyle means finishing 20 TSDs without using static stacking modes. Freestyle 20TSDs is more difficult than static tsacking modes such as LST, and the performance can represent the T-spin skills a player has in battles.",
+ "This term is usually used in 20 TSDs. Freestyle means finishing 20 TSDs without using static stacking modes. Freestyle 20TSDs is more difficult than static stacking modes such as LST, and the performance can represent the T-spin skills a player has in battles.",
},
{"Topping out",
"die death topout toppingout",
@@ -700,162 +778,167 @@ return{
"Modern Tetris games have three different conditions in which the player tops out:\n1. Block out: when a piece spawned overlaps with the existing blocks in the field;\n2. Lock out: when a piece locks entirely above the skyline;\n3. Top out: when the stack exceeds 40 lines in height (often due to incoming garbage).\nTechmino does not check for locking out and topping out.",
},
{"Buffer zone",
- "buffer zone above super invisible disappear",
+ "above super invisible disappear",
"term",
- "Refers to 21st-40th lines above the visible field. Because the blocks in the field could go over the visible field (this usually happens when multiple garbage lines come in) so the buffer zone was created so those blocks could go back to the field when garbage lines are cleared. Also, the buffer zone is usually located at 21st-40th lines because this is sufficient for most cases. Refer to \"Vanish Zone\" to learn more.",
+ "Refers to 21st-40th lines above the visible field. Because the blocks in the field could go over the visible field (this usually happens when multiple garbage lines come in) so the buffer zone was created so those blocks could go back to the field when garbage lines are cleared. Also, the buffer zone is usually located at 21st-40th lines because this is sufficient for most cases. Refer to “Vanish Zone” to learn more.",
},
{"Vanish zone",
- "vanish zone disappear gone cut die",
+ "disappear gone cut die",
"term",
- "Refers to the area located above the 40th line. This is usually realised by combining c4w and multiple garbage lines. In many games, when any block reaches the vanish zone, the game is terminated immediately.\nHowever, this area can have different behaviours in different games. Some games are flawed because the game could crash when the blocks enter the vanish zone (e.g. Tetris Online). Wierd behaviours could also happen when the blocks enter the vanish zone (you can refer to this video, click on the globe icon to open the link).\n\nFurthermore, the vanish zone in Jstris is located above the 22nd line, and any blocks locked above the 21st line will disappear. ",
+ "Refers to the area located above the 40th line. This is usually realized by combining c4w and multiple garbage lines. When any block reaches the vanish zone in many games, the game is terminated immediately.\nHowever, this area can have different behaviors in different games. Some games are flawed because the game could crash when the blocks enter the vanish zone (e.g., Tetris Online). Wierd behaviors could also happen when the blocks enter the vanish zone (you can refer to this video, click on the globe icon to open the link).\n\nFurthermore, the vanish zone in Jstris is located above the 22nd line, and any blocks locked above the 21st line will disappear.",
"https://youtu.be/z4WtWISkrdU",
},
{"Falling speed",
"fallingspeed gravity",
"term",
- "Falling speed is often described in terms of \"G\", i.e. how many lines the blocks fall in one frame (usually assuming 60 fps).\nG is a relatively large unit. The speed of Lv 1 in a regular Marathon (one second per line) is 1/60 G, and 1G is about Lv 13 speed. The highest speed of modern Tetris is 20G because the field height is 20 lines. In fact, the real meaning of 20G is \"Infinite falling speed\", and even when the field height is more than 20 lines, 20G modes force all the blocks to fall down to the bottom instantly. You can learn more about 20G at the \"20G\" entry.",
+ "Falling speed is often described as “G,” i.e., how many lines the blocks fall in one frame (usually assuming 60 fps).\nG is a relatively large unit. The speed of Lv 1 in a regular Marathon (one second per line) is 1/60 G, and 1G is about Lv 13 speed. The highest speed of modern Tetris is 20G because the field height is 20 lines. The real meaning of 20G is “Infinite falling speed,” and even when the field height is more than 20 lines, 20G modes force all the blocks to fall to the bottom instantly. You can learn more about 20G at the “20G” entry\nIn Techmino, falling speed is described as the frames it takes for a block to fall one unit; for example, a speed of 60 refers to one unit per second (as the game runs in 60 fps as default).",
},
{"20G",
- "20g gravity instant",
+ "gravity instant",
"term",
- "The fastest falling speed of modern Tetris. In 20G modes, pieces appear instantly on the bottom of the field without the actual process of \"falling down\". This sometimes also limits a piece's sideways movements, as it is not always possible to make a piece climb over a bump or out of a well in 20G. You can learn more at the unit \"G\" at the \"falling speed\" entry. ",
+ "The fastest falling speed of modern Tetris. In 20G modes, pieces appear instantly on the bottom of the field without the actual process of falling. This sometimes also limits a piece’s sideways movements, as it is not always possible to make a piece climb over a bump or out of a well in 20G. You can learn more at the unit “G” at the “falling speed” entry.",
},
{"Lockdown Delay",
"lockdelay lockdowndelay lockdowntimer",
"term",
- "The delay between block touching the ground and locking down (i.e. can no longer be controlled, and the next piece spawns).\nModern Tetris games often have forgiving lockdown delay mechanics where you can reset this delay by moving or rotating (up to 15 times), and you can sometimes stall for time by doing this. Classic Tetris games often have a far less forgiving lockdown delay.",
+ "The delay between block touching the ground and locking down (i.e., can no longer be controlled, and the next piece spawns).\nModern Tetris games often have forgiving lockdown delay mechanics where you can reset this delay by moving or rotating (up to 15 times), and you can sometimes stall for time by doing this. Classic Tetris games often have a far less forgiving lockdown delay.",
},
{"ARE",
- "are spawn appearance delay",
+ "spawn appearance delay",
"term",
"Sometimes called the Entry Delay. ARE refers to the delay between the lockdown of one piece and the spawn of another piece.",
},
{"Line ARE",
- "line are appearance delay",
+ "appearance delay",
"term",
"The delay between the start of a line clear animation to the spawn of the next piece.",
},
{"Death ARE",
- "death are die delay",
+ "die delay dd",
"term",
- "(Techmino exclusive) When the spawn location of the next piece is blocked by an existing block in the field, a delay will be added in addition to the spawn ARE, and this delay is referred to as the death ARE. This mechanism can be used along with IHS and IRS to prevent death. \nOriginal idea by NOT_A_ROBOT",
+ "When an existing block blocks the spawn location of the next piece in the field, a delay will be added to the spawn ARE, referred to as the death ARE. This mechanism can be used along with IHS and IRS to prevent death. \nOriginal idea by NOT_A_ROBOT.",
},
{"Finesse",
"finesse",
"term",
- "A technique to move a piece into the desired position with the minimum number of key presses. This saves time and reduces chances to misdrop.\nYou can practice by playing with Jstris's \"restart on finesse error\", or with Techmino's finesse error sound effect.\n\nTechmino's finesse detection is not exactly \"theoretical minimum key presses\", but instead only checks for finesse against a pre-determined par keypress count *when the piece locks in a position that does not require soft dropping*. This means that Techmino will not judge a piece as having a finesse error when you soft drop and spin or tuck.\nTechmino also introduced additional checks, such as holding while the current piece and the held piece is the same, or holding after you have manipulated the current piece, count as a finesse fault.\nFinesse% in Techmino is defined to be 100% when par or below par, 50% when one keypress above par, 25% when two keypresses above par, and 0% when three or more keypresses above par.\nAlso note that in 20G finesse still runs as if there were no gravity, which can cause inaccurate results.",
+ "A technique to move a piece into the desired position with the minimum number of key presses. This saves time and reduces chances to misdrop.\nYou can practice by playing with Jstris’s “restart on finesse error” or with Techmino’s finesse error sound effect.\n\nTechmino’s finesse detection is not precisely “theoretical minimum key presses,” but instead only checks for finesse against a pre-determined par keypress count *when the piece locks in a position that does not require soft dropping*. This means that Techmino will not judge a piece as having a finesse error when you soft drop and spin or tuck.\nTechmino also introduced additional checks, such as holding while the current piece and the held piece is the same, or holding after you have manipulated the current piece, count as a finesse fault.\nFinesse% in Techmino is defined to be 100% when par or below par, 50% when one keypress above par, 25% when two keypresses above par, and 0% when three or more keypresses above par.\nAlso note that in 20G finesse still runs as if there were no gravity, which can cause inaccurate results.",
},
- {"\"doing research\"",
+ {"‘Doing Research’",
"scientificresearch",
"term",
- "\"Doing scientific research\" is a term sometimes used in the Chinese community, referring to researching/practicing techniques in a low-falling-speed, single-player environment.",
+ "“Doing scientific research” is a term sometimes used in the Chinese Tetris community, referring to researching/practicing techniques in a low-falling-speed, single-player environment.",
+ },
+ {"Keymapping",
+ "feel",
+ "term",
+ "Here're some general principles for configuring your controls.\n\n1. Avoid assigning one finger to multiple keys that you might want to press together - for example, you won't typically need to press the multiple rotation buttons together. Try assigning other buttons to one finger each.\n2. Unless you are confident with your pinky, probably avoid assigning it a button. Usually the pointer finger and middle finger are the most agile, but feel free to see how your own fingers perform.\n3. No need to copy someone else's key config. Every person is different; as long as you keep these ideas in mind, using a different key config should have minimal impact on your skills.",
},
{"Handling",
"feel handling",
"term",
- "Several main factors that affecting the handling:\n(1) Input delay is affected by device configuration or device condition. Restart/change device.\n(2) Program stability, program design (or implementation) is not good, cause lagging too much. Can be alleviated by lowering the effect setting.\n(3) Designed on purpose. Adapt it.\n(4) Improper parameter setting. Change the settings.\n(5) Improper play posture. It's not convenient to use force. Change your posture.\n(6) Not used to the operation after changing the key position or changing the device. Get used to it or change the settings.\n(7) Muscle fatigue, response and coordination ability decreased. Get some sleep or do some sports, and come back later (maybe a few days).",
+ "Several main factors that may affect handling:\n(1) Input delay, which could be affected by device configuration or condition. Restart the game or change your device can probably fix it.\n(2) Unstable programming or faulty designs. It could be alleviated by lowering the effect settings.\n(3) Designed on purpose. Adaptation might help.\n(4) Improper parameter setting. Change the settings.\n(5) Improper play posture. It’s not convenient to use force. Change your posture.\n(6) Not being used to the operation after changing the key position or changing the device. Getting used to it or changing the settings might help.\n(7) Muscle fatigue, response, and decreases in coordination abilities. Have some rest and come back later or in a few days.",
},
{"DAS (simple)",
"das arr delayedautoshift autorepeatrate",
"term",
- "Imagine you are typing, and you hold down a letter. Say you hold down \"O\".\nYou get a long string of O's.\nOn the timeline, it kinds of looks like O--------------O-O-O-O-O-O-O-O-O\nThe \"--------------\" is DAS, the \"-\" is ARR.",
+ "Imagine typing on a keyboard, where you press and hold the “O” key. \nYou get a long string of o’s.\nOn the timeline, it kinds of looks like o—————o-o-o-o-o-o-o-o-o…\nThe “—————” is DAS, the “-” is ARR.",
},
{"DAS & ARR",
"das arr delayedautoshift autorepeatrate",
"term",
- "DAS refers to Delayed Auto Shift, the way how blocks move to the side when you hold left or right. Also refers to the delay between the initial movement (when you press down the button) and the first automatic movement.\nARR refers to Auto-Repeat Rate, which is the delay between automatic movements.\nFor new players, the recommended values are: DAS 8-10f (133-167ms), ARR 1-2f (17-33ms).",
+ "DAS refers to Delayed Auto Shift, how blocks move to the side when you hold left or right. It also refers to the delay between the initial movement (when you press down the button) and the first automatic movement.\nARR refers to Auto-Repeat Rate, which is the delay between automatic movements. In some games, DAS and ARR are calculated using the unit f (frame). Multiply f by 16.7 (if you are running the game in 60 fps) to convert it to ms (millisecond).",
},
{"DAS tuning",
"das tuning",
"term",
- "For advanced players who want to play faster, the recommended values are DAS 4-6f (67-100ms), ARR 0f (0ms). (At 0ms ARR, pieces will instantly snap to the wall once you get past DAS.)\n\nThe ideal configuration strategy for advanced players is to minimize DAS while still being able to reliably control whether to tap or hold, and to set to ARR to 0 if possible, or as low as possible otherwise.",
+ "For advanced players who want to play faster, the recommended values are DAS 4–6 f (67–100 ms), ARR 0 f (0 ms). (At 0 ms ARR, pieces will instantly snap to the wall once you get past DAS.)\n\nThe ideal configuration strategy for advanced players is to minimize DAS while still being able to reliably control whether to tap or hold, and to set to ARR to 0 if possible, or as low as possible otherwise.",
},
{"DAS cut",
"dascut dcd",
"term",
- "Techmino exclusive: in Techmino, the DAS timer can be cleared or discharged for a short time when the player starts to control a new piece. This can reduce the case where a piece instantly starts moving if spawned with a direction button held.\n\nOther games may have a similar feature but may function differently.",
+ "*Techmino-Exclusive* In Techmino, the DAS timer can be cleared or discharged for a short time when the player starts to control a new piece. This can reduce the case where a piece instantly starts moving if spawned with a direction button held.\n\nOther games may have a similar feature but may function differently.",
},
{"Auto-lock cut",
"autolockcut mdcut",
"term",
- "Techmino exclusive: this feature is designed to prevent mis-harddropping from pressing hard drop key shortly after the previous piece is naturally locked down.\nHard drop key can be disabled for a few frames (depending on the settings) after a natural lockdown.\n\nOther games may have a similar feature but may function differently.",
+ "A feature designed to prevent mis-harddropping from pressing the hard drop key shortly after the last piece is naturally locked down.\nHard drop key can be disabled for a few frames (depending on the settings) after a natural lockdown.\n\nOther games may have a similar feature but may function differently.",
},
{"SDF",
- "sdf softdropfactor",
+ "softdropfactor",
+ "term",
+ "Soft Drop Factor\n\nA way to define soft drop speed as a multiple of natural falling speed. In guideline games, the soft drop is usually 20x the speed of natural falling, i.e., it has an SDF of 20. Techmino does not use SDF to define soft drop speed.",
+ },
+ {"Shape & Names",
+ "mino",
"term",
- "Soft Drop Factor\n\nA way to define soft drop speed as a multiple of natural falling speed. In guideline games, the soft drop is usually 20x the speed of natural falling, i.e. it has an SDF of 20. Techmino does not use SDF to define soft drop speed.",
+ "Here is a list of the all the blocks used by Techmino and their corresponding names:\nTetrominos:\nZ: "..CHAR.mino.Z..", S: "..CHAR.mino.S..", J: "..CHAR.mino.J..", L: "..CHAR.mino.L..", T: "..CHAR.mino.T..", O: "..CHAR.mino.O..", I: "..CHAR.mino.I..";\n\nPentominos:\nZ5: "..CHAR.mino.Z5..", S5: "..CHAR.mino.S5..", P: "..CHAR.mino.P..", Q: "..CHAR.mino.Q..", F: "..CHAR.mino.F..", E: "..CHAR.mino.E..", T5: "..CHAR.mino.T5..", U: "..CHAR.mino.U..", V: "..CHAR.mino.V..", W: "..CHAR.mino.W..", X: "..CHAR.mino.X..", J5: "..CHAR.mino.J5..", L5: "..CHAR.mino.L5..", R: "..CHAR.mino.R..", Y: "..CHAR.mino.Y..", N: "..CHAR.mino.N..", H: "..CHAR.mino.H..", I5: "..CHAR.mino.I5..";\n\nTriminos, Domino, and Mino:\nI3: "..CHAR.mino.I3..", C: "..CHAR.mino.C..", I2: "..CHAR.mino.I2..", O1: "..CHAR.mino.O1..".",
},
{"Bag7 generator",
"bag7bag randomgenerator",
"term",
- "Also known as \"7-Bag Generator\". Officially known as \"Random Generator\".\nThis is the algorithm used by modern, official Tetris games to generate pieces. Starting from the beginning of a game, every 7 pieces there are guaranteed to be one of each of the 7 Tetrominoes.",
+ "Also known as “7-Bag Generator.” Officially known as “Random Generator.”\nThis is the algorithm used by modern, official Tetris games to generate pieces. Starting from the beginning of a game, there is guaranteed to be one of the seven Tetrominoes for every seven pieces.\n\nAn example would be like: ZSJLTOI OTSLZIJ LTISZOJ.",
},
{"His generator",
"history hisgenerator",
"term",
- "A way to generate pieces, notably used in Tetris: The Grand Master games. Every time a random Tetromino is selected, but if this Tetromino is the same as one of the few previous pieces, then reroll until a different piece is rolled or until a reroll limit is reached.\nFor example, a \"his 4 roll 6\" (h4r6) generator rerolls when the piece is the same as one of the 4 previous pieces and rerolls up to 6 times.\nThere are other variations as well, such as \"his4 roll6 pool35\", which further reduces the randomness of the piece sequence.\n\nIn Techmino, the max. reroll count is half of the sequence length, rounded up.",
+ "A way to generate pieces, notably used in Tetris: The Grand Master games. Every time a random Tetromino is selected, but if this Tetromino is the same as one of the few previous pieces, then reroll until a different piece is rolled or until a reroll limit is reached.\nFor example, a “his 4 roll 6” (h4r6) generator rerolls when the piece is the same as one of the four previous pieces and rerolls up to 6 times.\nThere are other variations as well, such as “his4 roll6 pool35,” which further reduces the randomness of the piece sequence.\n\nIn Techmino, the maximum reroll count is half of the sequence length, rounded up.",
},
{"HisPool generator",
"hisPool history pool",
"term",
- "History Pool, a generator based on the His generator. It introduced a mechanism called \"Pool\". When generating a new piece, HisPool randomly selects a piece from the Pool and increase the probability of spawning of the least frequent piece.\n\nThis mechanism makes the sequence more stable and ensures that the drought won't last forever.",
+ "History Pool, a generator based on the His generator. It introduced a mechanism called “Pool.” When generating a new piece, HisPool randomly selects a piece from the Pool and increases the probability of spawning the least frequent piece.\n\nThis mechanism makes the sequence more stable and ensures that the drought won’t last forever.",
},
{"bagES generator",
"bages easy start",
"term",
- "*Techmino-exclusive*\nBag Easy-Start, an improved Bag generator. The first piece in the first bag won't be those hard-to-place pieces (S/Z/O/S5/Z5/F/E/W/X/N/H).",
+ "*Techmino-Exclusive*\nBag Easy-Start, an improved Bag generator. The first piece in the first bag won’t be those hard-to-place pieces (S/Z/O/S5/Z5/F/E/W/X/N/H).",
},
{"Reverb generator",
"reverb",
"term",
- "*Techmino-exclusive*\nA generator derived from Bag. Based on Bag generator, the Reverb generator repeats each piece several times. The probability of repetition decreases when a certain piece repeats too frequently and vice versa. ",
+ "*Techmino-Exclusive*\nA generator derived from Bag. The Reverb generator repeats each piece several times based on the Bag generator. The probability of repetition decreases when a certain piece repeats too frequently and vice versa.",
},
{"Hypertapping",
"hypertapping",
"term",
- "Vibrate your finger on the controller to achieve faster sideways movement speed than holding it.\nIt is most commonly used on classic Tetris where DAS is rather slow. In most cases, you do not need to hypertap in modern Tetris games, because their DAS is often fast enough.",
+ "Refers to the technique of vibrating your finger on the controller to achieve faster sideways movement speed than holding it.\nIt is most commonly used on classic Tetris where DAS is relatively slow. In most cases, you do not need to hypertap in modern Tetris games because their DAS is usually fast enough.",
},
{"Rolling",
"rolling",
"term",
- "Another method of fast-tapping in high-gravity (around 1G) modes (with slow DAS/ARR setting).\nWhen you perform rolling, you fix the position of one hand and the controller, and then tap the back of the controller with fingers on your other hand repeatedly. This method allows even faster moving speeds than hypertapping (see \"Hypertapping\" for more)and requires much less effort.\nThis method was first discovered by Cheez-fish and he has once achieved a tapping speed of more than 20 Hz.",
+ "Another method of fast-tapping in high-gravity (around 1G) modes (with slow DAS/ARR setting).\nWhen you perform rolling, you fix the position of one hand and the controller, and then tap the back of the controller with fingers on your other hand repeatedly. This method allows even faster speeds than hypertapping (see “Hypertapping” for more) and requires much less effort.\nThis method was first discovered by Cheez-fish, and he has once achieved a tapping speed of more than 20 Hz.",
},
{"Passthrough",
- "passthrough pingthrough",
+ "pingthrough",
"term",
- "",--TODO
+ "Refers to a situation where the attacks from both players were sent to the other player’s board without canceling out. Another term called “pingthrough” refers to a situation where a passthrough occurs due to Internet delays.",
},
{"Tetris OL attack",
"top tetrisonlineattack",
"term",
- "Single/Double/Triple/Tetris sends 0/1/2/4 attack(s).\nT-Spin Single/Double/Triple sends 2/4/6, half if Mini.\nCombo send 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5.\nBack to Back sends extra 1 (or 2 if T-Spin Triple).\nAll Clear sends extra 6. This extra 6 will be sent to opponents directly, and does not cancel your buffered incoming damage.",
+ "Single/Double/Triple/Tetris sends 0/1/2/4 attack(s).\nT-Spin Single/Double/Triple sends 2/4/6, half if Mini.\nCombo send 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5.\nBack to Back sends extra 1 (or 2 if T-Spin Triple).\nAll Clear sends extra 6 lines. This extra 6 lines will be sent to opponents directly, and does not cancel the buffered incoming damage.",
},
{"Techmino attack",
"techminoattack",
"term",
- "Regular line clears (clearing ≤3 lines):\n\tSends (lines cleared -0.5) attack\nSpecial line clears:\n\tSpin sends (lines cleared x2) attack,\n\t\t- B2B sends extra 1/1/2/4/8 (for Spin Single/Double/Triple/Techrash/Techrash+ respectively)\n\t\t- B2B2B sends (lines cleared x0.5), and +1 extra blocking\n\t\t- If it's a Mini, ×0.25\n\tNon-Spin Techrash/Techrash+ sends (lines cleared) attack,\n\t\t- B2B sends extra 1 attack,\n\t\t- B2B2B sends 50% more attack and +1 extra blocking.\n\nSpecial line clears will increase B2B gauge, making later special line clears have B2B or B2B2B bonus (see below)\nHalf Perfect Clear (a Perfect Clear \"with blocks left below\". If it's an I clearing 1 line, then the remaining blocks must not be player-placed): Attack +2, Extra Blocking +2\nPerfect Clear: half all damage above, then +8 to +20 attack (increases within a round by +2 per Perfect Clear) and +2 extra blocking. (note: if lines cleared in this round >4, then B2B gauge will be filled)\nCombos: All damage above will be given a (combo×25%) bonus, or (combo×15%) if the line clear is a Single, capped at 12 combo. +1 more attack for 3 Combo or more.\nAfter calculating all above, the damage value will be rounded down then sent",
+ "Check the user manual on the bottom right corner of the homepage for more information.",
},
{"C2 Generator",
"cultris2generator cultrisiigenerator c2generator",
"term",
- "All Tetrominoes have an initial weight of 0.\nEvery time, divide all weights by 2, add a random number between 0 and 1, pick the piece with the highest weight, and divide this piece's weight by 3.5.",
- },
- {"C2 wall kicks",
- "cultris2wallkicks cultrisiiwallkicks c2wallkicks cultris2kicks cultrisiikicks c2kicks",
- "term",
- "Left, right, down, bottom-left, bottom-right, left 2, right 2. (This applies to *any* rotation of *any* Tetromino.)",
+ "All Tetrominoes have an initial weight of 0.\nEvery time, divide all weights by 2, add a random number between 0 and 1, pick the piece with the highest weight, and divide this piece’s weight by 3.5.",
},
{"Stacking",
"stacking",
"term",
- "Often refers to stacking Tetrominoes without leaving holes.",
+ "Often refers to stacking Tetrominoes without leaving holes. An essential skill.",
},
- {"Rotation buttons (1)",
+ {"Rotation buttons (1/2)",
"doublerotation",
"term",
- "Using both clockwise and counter-clockwise rotation buttons allows reducing the number of key presses by replacing three rotation presses with one press of the opposite direction.\nFinesse assumes the use of both rotation buttons.",
+ "Using both clockwise and counter-clockwise rotation buttons reduces the number of key presses by replacing three rotation presses with one press of the opposite direction.\nFinesse assumes the use of both rotation buttons.",
},
- {"Rotation buttons (2)",
+ {"Rotation buttons (2/2)",
"triplerotation",
"term",
"Using all three rotation buttons (the third being 180° rotation), any piece only requires one rotation press to reach the desired direction.\nHowever, it is not exactly useful for not every game has this feature, and the speed increase from learning this technique is not as much as when you learn using both rotation buttons as opposed to one. You can skip this technique unless you want extreme speeds.",
@@ -868,132 +951,159 @@ return{
{"Bone block",
"bone tgm",
"term",
- "The block skin used by the earliest version of Tetris.\nIn the early times, computers were all using Command Line Interface instead of Graphical User Interface, so at that time a single mino in the game of Tetris is represented using two enclosing square brackets [ ]. It looks kinds of like bones so it is sometimes called the bone blocks.\nIn Techmino, bone blocks are defined as \"A single, fancy block skin that all of the blocks use.\". Different block skins may have different types of bone block styles.",
+ "The block skin used by the earliest version of Tetris.\nIn earlier times, computers all used the Command-Line Interfaces (like cmd on Windows, Terminal on Mac, or Console on Linux), so a single mino in the game Tetris is represented using two enclosing square brackets [ ]. It looks like bones, so it is sometimes called bone blocks.\nIn Techmino, bone blocks are defined as “a single, fancy block skin that all of the blocks use.” Different block skins may have different types of bone block styles.",
},
{"Semi-invisible",
"half invisible semi",
"term",
- "Refers to a rule where the tetrominoes will become invisible after a period of time.\nThis time interval is not definite and it is acceptable to describe it as \"disappear after a few seconds\".",
+ "Refers to a rule where the tetrominoes will become invisible after some time.\nThis time interval is not definite, and it is acceptable to describe it as “disappear after a few seconds.”",
},
{"Invisible",
"invisible",
"term",
- "Refers to a rule where blocks will disappear instantly when locked onto the field. \nN.B. It is also acceptable to refer to an invisible mode where a disappearing animation is shown. However, this makes the game a lot easier, so in this game, the invisible mode without such animations is referred to as \"Sudden Invisible\".",
+ "Refers to a rule where blocks will disappear instantly when locked onto the field. \nN.B. It is also acceptable to refer to an invisible mode where a disappearing animation is shown. However, this makes the game a lot easier, so in Techmino, the invisible mode without such animations is referred to as “Sudden Invisible.”",
},
{"MPH mode",
"mph",
"term",
- "Memoryless (i.e. random spawn), previewless (i.e. no next queue), holdless. A mode that requires quite some reaction speed.",
+ "Memoryless (random spawn), Previewless (no next queue), Holdless. A mode that requires quite some reaction speed.",
},
{"Input delay",
"input delay",
"term",
- "Any input device takes some time for the input to reach the game. This delay can range from a few milliseconds to a few dozen milliseconds.\nIf input delay is too long, the controls can feel uncomfortable.\nThis delay is often due to the performance of the hardware and software used, and often out of your control. Turn on performance mode (or turn off power saving mode) on your device, and turn on gaming mode on your monitor/TV (if you have one), may help reducing input delay.",
+ "Any input device takes some time for the input to reach the game. This delay can range from a few ms to a few dozen ms.\nIf input delay is too long, the controls can feel uncomfortable.\nThis delay is often due to the performance of the hardware and software used, which is often something out of your control. Turn on performance mode (or turn off power saving mode) on your device, and turn on gaming mode on your monitor/TV (if you have one), which may help reduce input delay.",
+ },
+ {"Secret Grade",
+ "larger than",
+ "term",
+ "An easter egg mode from the TGM series. During a “secret grade” gameplay, the player tries to make a “>” shape with one hole in each line using blocks. The ultimate goal is to finish the whole shape using 19 lines.\nFor more information, please visit Hard Drop Wiki. Click on the globe icon to open the link.",
+ "https://harddrop.com/wiki?search=Secret_Grade_Techniques",
},
{"Cold Clear",
"cc coldclear ai bot",
"term",
- "A Tetris bot. Originally built for Puyo Puyo Tetris, thus can be less powerful on Techmino.",
+ "A Tetris bot. \nDeveloped by MinusKelvin originally for Puyo Puyo tetris. The Cold Clear build in Techmino supports all-spin and TRS.",
},
{"ZZZbot",
- "zzzbot ai bot",
+ "ai bot zzztoj",
"term",
- "A Tetris bot. Built by the Chinese Tetris player 奏之章 (Zou Zhi Zhang) and has decent performance in many games",
+ "A Tetris bot. Built by the Chinese Tetris player 奏之章 (Zòu Zhī Zhāng, see entry below) and has decent performance in many games",
},
-
- --Setups
+ -- # Setups
{"Openers",
"setup openers",
"setup",
- "Openers are setups that can be build when a game begins. You can still make these setups mid-game, but will often require a different set of piece placements.\n\nGood setups often satisfy two to three of the following:\n- Can adapt to many piece orders,\n- Strong attack, minimal waste of the T piece,\n- require minimal soft dropping for more fast placement and using finesse,\n- has clear follow-up strategies with few branches.\n\nMost openers make use of the Random Generator (bag-7 generator) and exploit the fact that it gives one of every piece for every 7 pieces. This element of predictability makes it possible to have reliable setups.",
+ "Openers are setups that can be built when a game begins. You can still make these setups mid-game, but will often require a different set of piece placements.\n\nGood setups usually satisfy two to three of the following:\n- Can adapt to many piece orders,\n- Strong attack, minimal waste of the T piece,\n- Require minimal soft dropping for faster placement and using finesse,\n- Has clear follow-up strategies with few branches.\n\nMost openers make use of the Random Generator (bag-7 generator) and exploit the fact that it gives one of every piece for every seven pieces. This element of predictability makes it possible to have reliable setups.",
},
{"DT Cannon",
"dtcannon doubletriplecannon",
"setup",
- "Double-Triple Cannon."..HDwiki,
- HDsearch.."dt",
+ "Double-Triple Cannon.\nFor more information, please visit Hard Drop Wiki. Click on the globe icon to open the link.",
+ "https://harddrop.com/wiki?search=dt",
},
{"DTPC",
- "dtpc dtcannon doubletriplecannon",
+ "dtcannon doubletriplecannon",
"setup",
- "A follow-up of the DT Cannon that ends with an All Clear"..HDwiki,
- HDsearch.."dt",
+ "A follow-up of the DT Cannon that ends with an All Clear.\nFor more information, please visit Hard Drop Wiki. Click on the globe icon to open the link.",
+ "https://harddrop.com/wiki?search=dt",
},
{"BT Cannon",
"btcannon betacannon",
"setup",
- "β Cannon, Beta Cannon"..HDwiki,
- HDsearch.."bt_cannon",
+ "β Cannon, Beta Cannon.\nFor more information, please visit Hard Drop Wiki. Click on the globe icon to open the link.",
+ "https://harddrop.com/wiki?search=bt_cannon",
},
{"BTPC",
- "btpc btcannon betacannon",
+ "btcannon betacannon",
"setup",
- "A follow-up of the BT Cannon that ends with an All Clear."..HDwiki,
- HDsearch.."bt_cannon",
+ "A follow-up of the BT Cannon that ends with an All Clear.\nFor more information, please visit Hard Drop Wiki. Click on the globe icon to open the link.",
+ "https://harddrop.com/wiki?search=bt_cannon",
},
{"TKI 3 Perfect Clear",
"ddpc tki3perfectclear",
"setup",
- "A TSD opener that leads to a Double-Double-All Clear."..HDwiki,
- HDsearch.."TKI_3_Perfect_Clear",
+ "A TSD opener that leads to a Double-Double-All Clear.\nFor more information, please visit Hard Drop Wiki. Click on the globe icon to open the link.",
+ "https://harddrop.com/wiki?search=TKI_3_Perfect_Clear",
},
{"QT Cannon",
"qtcannon",
"setup",
- "We don't know much about this...",
+ "A DT Cannon-like setup with a higher probability of sending a DT Attack.\nFor more information, please visit Hard Drop Wiki. Click on the globe icon to open the link.",
+ "https://harddrop.com/wiki?search=QT_cannon",
},
{"Mini-Triple",
"mt minitriple",
"setup",
"A Mini T-Spin - T-Spin Triple structure.",
- HDsearch.."mt",
+ "https://harddrop.com/wiki?search=mt",
},
- {"Wolfmoon Cannon",
- "wolfmooncannon",
+ {"Trinity",
+ "trinity",
"setup",
- "We don't know much about this..."..HDwiki,
- HDsearch.."wolfmoon_cannon",
+ "A TSD + TSD + TSD or TSMS + TST+ TSD setup.",
+ "https://harddrop.com/wiki?search=trinity",
},
- {"ASC opener",
- "ascopener",
+ {"Wolfmoon Cannon",
+ "wolfmooncannon",
"setup",
- "We don't know much about this...",
+ "An opener.\nFor more information, please visit Hard Drop Wiki. Click on the globe icon to open the link.",
+ "https://harddrop.com/wiki?search=wolfmoon_cannon",
},
{"Sewer",
"sewer",
"setup",
- "An opener."..HDwiki,
- HDsearch.."sewer",
+ "An opener.\nFor more information, please visit Hard Drop Wiki. Click on the globe icon to open the link.",
+ "https://harddrop.com/wiki?search=sewer",
},
{"TKI",
- "tki",
+ "tki-3 tki3",
"setup",
- "Can refer to a TSD opener or a C Spin opener."..HDwiki,
- HDsearch.."tki",
+ "TKI-3. It can either refer to a TKI-3 starting with a TSD or a C-spin starting with a TST.\nFor more information, please visit Hard Drop Wiki. Click on the globe icon to open the link.",
+ "https://harddrop.com/wiki?search=tki_3_opening",
},
{"God Spin",
"godspin",
"setup",
- "a setup that is fancy on the eyes but awkward to use in action. Invented by Windkey."..HDwiki,
- HDsearch.."godspin",
+ "A setup that is fancy on the eyes [but awkward to use in action]. Invented by Windkey.\nFor more information, please visit Hard Drop Wiki. Click on the globe icon to open the link.",
+ "https://harddrop.com/wiki?search=godspin",
},
{"Albatross",
"albatross",
"setup",
- "A fancy, fast-paced opener with TSD-TST-TSD-All Clear, hardly wasting any T pieces.",
+ "A fancy, fast-paced opener with TSD–TST–TSD–All Clear, hardly wasting any T pieces.\nFor more information, please visit Hard Drop Wiki. Click on the globe icon to open the link.",
+ "https://harddrop.com/wiki?search=Albatross_Special",
},
- {"鹈鹕",
+ {"Pelican",
"",
"setup",
- "(\"Pelican\") An Albatross-ish opener to use when the piece orders do not support that.",
+ "An Albatross-ish opener to use when the piece orders do not support that.\nFor more information, please visit Hard Drop Wiki. Click on the globe icon to open the link.",
+ "https://harddrop.com/wiki?search=Pelican",
},
- {"7-piece Puzzle",
+ {"Perfect Clear Opener",
"7piecepuzzle",
"setup",
- "An All Clear opener with a high success rate. In Techmino's PC Practice modes, the setup that leaves an irregular opening is this setup.",
+ "An All Clear opener with a high success rate (~84.6% when you have an I in the Hold queue and ~61.2% if that’s not the case). In Techmino’s PC Practice modes, the setup that leaves an irregular opening is this setup.\nFor more information, please visit Hard Drop Wiki. Click on the globe icon to open the link.",
+ "https://harddrop.com/wiki?search=Perfect_Clear_Opener",
+ },
+ {"Grace System",
+ "liuqiaoban gracesystem 1stpc",
+ "setup",
+ "A PC opener with a success rate of ~88.57%. The 4×4 square in the PC challenge is this setup.",
+ "https://four.lol/perfect-clears/grace-system",
+ },
+ {"DPC",
+ "DPC",
+ "setup",
+ "An almost 100% TSD + PC setup with no blocks in the field and the last block of 7-bag in the next queue. More information on tetristemplate.info.",
+ "https://tetristemplate.info/dpc/",
+ },
+ {"Gamushiro Stacking",
+ "gamushiro",
+ "setup",
+ "(ガムシロ積み) A TD-Attack opener.\nFor more information, please visit Hard Drop Wiki. Click on the globe icon to open the link.",
+ "https://harddrop.com/wiki?search=Gamushiro_Stacking",
},
-
- --Pattern
+ -- # Pattern
{"Mid-game Setups",
"midgamesetups",
"pattern",
@@ -1002,363 +1112,146 @@ return{
{"C-spin",
"cspin",
"pattern",
- "Placing a J on top of an L (or vice versa) to form a C shape, filling the rest with appropriate shapes to perform a T-Spin Triple + T-Spin Double."..HDwiki,
- HDsearch.."c-spin",
+ "A T-Spin Triple + T-Spin Double attack, known as TKI in Japan.\nFor more information, please visit Hard Drop Wiki. Click on the globe icon to open the link.",
+ "https://harddrop.com/wiki?search=c-spin",
},
{"STSD",
"stsd",
"pattern",
- "Super T-Spin Double, a setup that allows two T-Spin Doubles.\nBut when the garbage is right under the STSD cave, it is impossible to perform two TSDs."..HDwiki,
- HDsearch.."stsd",
+ "Super T-Spin Double, a setup that allows two T-Spin Doubles.\nBut when the garbage is right under the STSD cave, it is impossible to perform two TSDs.\nFor more information, please visit Hard Drop Wiki. Click on the globe icon to open the link.",
+ "https://harddrop.com/wiki?search=stsd",
},
- {"STMB",
+ {"STMB Cave",
"stmb",
"pattern",
- "STMB cave, a donation setup by using S/Z to block off a 3-wide well and clear a T-Spin Double."..HDwiki,
- HDsearch.."stmb_cave",
+ "STMB cave, a donation setup by using S/Z to block off a 3-wide well and clear a T-Spin Double.\nFor more information, please visit Hard Drop Wiki. Click on the globe icon to open the link.",
+ "https://harddrop.com/wiki?search=stmb_cave",
+ },
+ {"Fractal",
+ "shuangrenjian fractal spider",
+ "pattern",
+ "A setup involving overlapping two TSD setups.\nFor more information, please visit Hard Drop Wiki. Click on the globe icon to open the link.",
+ "https://harddrop.com/wiki?search=Fractal",
},
{"LST stacking",
"lst",
"pattern",
- "An infinite T-Spin Double setup"..HDwiki,
- HDsearch.."st_stacking",
+ "An infinite T-Spin Double setup.",
+ "https://four.lol/stacking/lst",
},
{"Hamburger",
"hamburger",
"pattern",
- "A donation setup that still opens up for Tetrises."..HDwiki,
- HDsearch.."hamburger",
+ "A donation setup that opens up for Tetrises.\nFor more information, please visit Hard Drop Wiki. Click on the globe icon to open the link.",
+ "https://harddrop.com/wiki?search=hamburger",
},
{"Imperial Cross",
"imperialcross",
"pattern",
- "Covering a cross-shaped hole with an overhang to do two T-Spin Doubles."..HDwiki,
- HDsearch.."imperial_cross",
+ "Covering a cross-shaped hole with an overhang to do two T-Spin Doubles.\nFor more information, please visit Hard Drop Wiki. Click on the globe icon to open the link.",
+ "https://harddrop.com/wiki?search=imperial_cross",
},
- {"Amemiya Cannon",
- "amemiyacannon",
+ {"Kaidan",
+ "jieti kaidan stairs",
"pattern",
- "Donation T-Spin Double then Tetris, often a variation of a DT cannon",
+ "A setup that can donate a TSD on a stair-looking terrain.\nFor more information, please visit Hard Drop Wiki. Click on the globe icon to open the link.",
+ "https://harddrop.com/wiki?search=kaidan",
},
- {"千鸟格子",
- "",
+ {"Shachiku Train",
+ "shachikutrain shechu",
"pattern",
- "(\"Qianniao Grids\") A setup to donate a T-Spin Double over a small hole and can do another T-Spin Double after that.",
+ "A setup that can donate two TSDs on a TST setup.\nFor more information, please visit Hard Drop Wiki. Click on the globe icon to open the link.",
+ "https://harddrop.com/wiki?search=Shachiku_Train",
},
- {"6-piece puzzle",
- "liuqiaoban",
+ {"Cut Copy",
+ "qianniao cutcopy",
"pattern",
- "a setup that is often used to increase chances of a mid-game All Clear.",
+ "A setup to donate a T-Spin Double over a small hole and can do another T-Spin Double after that.",
},
{"King Crimson",
"kingcrimson",
"pattern",
- "Stacking TST(s) on top of a STSD.",
+ "Stacking TST(s) on top of a STSD.\nFor more information, please visit Hard Drop Wiki. Click on the globe icon to open the link.",
+ "https://harddrop.com/wiki?search=King_Crimson",
},
-
- --Savedata managing
+ {"Consecutive PCs (1/3)",
+ "pcloop",
+ "pattern",
+ "You can find detailed guides on “Tetris Hall” about 1st–4th and 7th PC. After you finish the 7th PC, exactly 70 blocks are used so you can go back to the 1st PC.",
+ "https://shiwehi.com/tetris/template/consecutivepc.php",
+ },
+ {"Consecutive PCs (2/3)",
+ "pcloop",
+ "pattern",
+ "four.lol has guides on 5th and 6th PC.",
+ "https://four.lol/perfect-clears/5th",
+ },
+ {"Consecutive PCs (2/3)",
+ "pcloop",
+ "pattern",
+ "A complete PC-loop tutorial written by NitenTeria.",
+ "https://docs.qq.com/sheet/DRmxvWmt3SWxwS2tV",
+ },
+ -- # Savedata managing
{"Console",
- "console cmd commamd minglinghang kongzhitai terminal",
+ "cmd commamd minglinghang kongzhitai terminal",
"command",
"Techmino has a console that enables debugging/advanced features.\nTo access the console, repeatedly tap (or click) the Techmino logo or press the C key on the keyboard on the main menu.\n\nCareless actions in the console may result in corrupting or losing saved data. Proceed at your own risk.",
},
{"Reset setting",
"reset setting",
"command",
- "Go to console and type \"rm conf/setting\" then press enter.\nRestart the game for the setting to take effect.\nPlay one game to get setting back",
+ "Go to console, type “rm conf/setting” and then press enter/return.\nRestart Techmino for this to take effect.\nTo revert this action, enter Settings then go back out.",
},
{"Reset statistics",
"reset statistic data",
"command",
- "Go to console and type \"rm conf/data\" then press enter.\nRestart the game for the setting to take effect.\nPlay one game to get data back",
+ "Go to console, type “rm conf/data” and then press enter/return.\nRestart Techmino for this to take effect.\nTo revert this action, play one game and reach a game over or win screen.",
},
{"Reset unlock",
"reset unlock",
"command",
- "Go to console and type \"rm conf/unlock\" then press enter.\nRestart the game for the setting to take effect.\nFresh a rank to get data back",
+ "Go to console, type “rm conf/unlock” and then press enter/return.\nRestart Techmino for this to take effect.\nTo revert this action, update any mode's status on the map.",
},
{"Reset records",
"reset record",
"command",
- "Go to console and type \"rm -s record\" then press enter.\nRestart the game for the setting to take effect.\nFresh a record list to get one list back",
+ "Go to console, type “rm -s record” and then press enter/return.\nRestart Techmino for this to take effect.\nYou can revert this action on an individual-mode basis; play one game and have its leaderboards updated to recover that mode's leaderboards.",
},
{"Reset key",
"reset virtualkey",
"command",
- "Go to console and type \"rm conf/[keyFile]\" then press enter.\nKeyboard: key, Virtualkey: virtualkey, Virtualkey save: vkSave1(2)\nRestart the game for the firsst two settings to take effect.\nEnter setting and go back to get one file back",
+ "Go to console, type “rm conf/[keyFile]” and then press enter/return.\nKeyboard: key, Virtualkey: virtualkey, Virtualkey save: vkSave1(2)\nRestart Techmino for the first two settings to take effect.\nEnter corresponding settings page and go back to get one file back.",
},
{"Delete replays",
"delete recording",
"command",
- "Go to console and type \"rm -s replay\" then press enter.\nTake effect immediately.",
+ "Go to console, type “rm -s replay“ and then press enter/return.\nTakes effect immediately.",
},
{"Delete cache",
"delete cache",
"command",
- "Go to console and type \"rm -s cache\" then press enter.\nTake effect immediately.",
+ "Go to console, type “rm -s cache” and then press enter/return.\nTakes effect immediately.",
},
-
- --English
+ -- # English
{"SFX",
- "sfx soundeffects",
+ "soundeffects",
"english",
- "Acronym for \"Sound Effects\".",
+ "Acronym for “Sound Effects.” Also abbrevated as “SE” in Japan.",
},
{"BGM",
- "bgm backgroundmusic",
+ "backgroundmusic",
"english",
- "Acronym for \"Background Music\".",
+ "Acronym for “Background Music.”",
},
{"TAS",
"tas",
"english",
- "Acronym for \"Tool-Assisted Speedrun(Superplay)\"\nPlay game with special tools without breaking the rules of the game (at the programming level).\nIt is generally used to get theoretical maximum scores or achieve interesting goals.\nA very simple TAS tool is built in this game",
+ "Acronym for “Tool-Assisted Speedrun (Superplay).”\nPlay a game with special tools without breaking the game’s rules (at the programming level).\nIt is generally used to get theoretical maximum scores or achieve interesting goals.\nA lightweight TAS tool is built into Techmino.",
},
{"AFK",
"afk",
"english",
- "Acronym for \"Away From Keyboard\", or in a broader sense, a period when you are not playing.\nTaking regular breaks help relief your muscle strain and help you to play better when you come back.",
- },
-
- --Famous
- {"Hebomai",
- "hebomai hbm",
- "name",
- "One of the top players.\nOnce Beat Wu Songhao (a Chinese player) on TV.",
- },
- {"Amemiya Taiyou",
- "amemiya taiyou",
- "name",
- "(あめみや たいよう)\n\nOne of the top players.\nWon champion on a game in Puyo Puyo Tetris's Swap mode.",
- },
- {"Ajanba",
- "ajanba ajb",
- "name",
- "One of the top players.\nWon champion of JsCup.",
- },
- {"Blink",
- "blink",
- "name",
- "One of the top players.\nRuns the Tetris community, Hard Drop.",
- },
- {"Doremy",
- "doremy 123",
- "name",
- "One of the top players.\nAmemiya once said he was the second-best player in the world.",
- },
- {"Firestorm",
- "firestorm fst",
- "name",
- "One of the top players.\nWon champion of JsCup.",
- },
- {"Furea",
- "furea fuleiya jk",
- "name",
- "(ふれあ)\n\nOne of the top players.\nWorld record holder of Puyo Puyo Tetris's Ultra mode.",
- },
- {"Iljain",
- "iljain yijianlian",
- "name",
- "One of the top players.\nAchieved Rank 1 in Cultris II.",
- },
- {"Jonas",
- "jonas",
- "name",
- "(1981-2021) One of the top players in Classic Tetris.\nFour-times-in-a-row champion of CTWC.",
- },
- {"Joseph",
- "joseph",
- "name",
- "One of the top players in Classic Tetris.\nTwice-in-a-row champion of CTWC. Also holds many world records of Tetris (NES, Nintendo).",
- },
- {"Kazu",
- "kazu mdking",
- "name",
- "One of the top players.\nFamous for how he can turn misdrops into donation setups.\nA.k.a. \"GAMEOVER\", \"GAMAOVER\", \"GAME_OVER_RETRY\"",
- },
- {"Microblizz",
- "microblizz",
- "name",
- "One of the top players.\nFormer world record holder for Sprint.",
- },
- {"Vince",
- "vincehd",
- "name",
- "One of the top players.\nLast world record holder for Sprint (no delay).",
- },
- {"Wumbo",
- "wumbotize squirtle",
- "name",
- "One of the top players.\nFamously fond of using Center 4-Wide setups, thus having a bad reputation. However, he is undeniably skilled in other techniques as well.",
- },
- {"Yakine",
- "yakine heshui",
- "name",
- "One of the top players.\nFamous for fancy T-Spins. When in combat but not in danger, he could often pull off some fancy donations very high on the field. Third place on the speed leaderboards of Jstris's 20TSD mode, and didn't use setups (the first and second place both used LST setup).",
- },
- {"Translator Note 3",
- "",
- "help",
- "Starting from here, all but one term are China-specific (the not-China term is Diao) and are less relevant for the global community.\n\"Virtual content creator\" refers to people who produce content online under a fictional persona, and appear as a motion-controlled animated character on screens. Basically \"Virtual YouTuber\" but not platform-specific."
- },
- {"TetroDictionary",
- "zictionary tetrodictionary littlez",
- "name",
- "(or Zictionary for short) The name of this dictionary!\nIt includes brief introductions on many common terms in Tetris.\nIt used to be a chatbot in our QQ group, which was used to answer new player's FAQs. The entries in the Tetrodictionary were also inherited from the database in the chatbot.\nThe contents in the TetroDictionary was adapted from a variety of sources such as Tetris Wiki and Hard Drop Wiki.",
- },
- {"MrZ",
- "mrz_26 t026 t626",
- "name",
- "Tetris Research community member, the author of Techmino.\nPersonal bests: Sprint 25.95 seconds, MPH Sprint 57 seconds, #8 on Jstris leaderboards, X rank on TETR.IO, cleared TGM3 (World rule, Shirase gold 1300).",
- "https://space.bilibili.com/225238922",
- },
-
- {"Circu1ation",
- "circu1ation",
- "name",
- "One of the top players. First one to achieve sub-20 40L Sprint in China, X rank on TETR.IO.",
- "https://space.bilibili.com/557547205",
- },
- {"Farter",
- "farteryhr",
- "name",
- "Tetris Research community member.\nPersonal bests: Sprint 26.193 seconds\nOne of the prestigious players in the Chinese Tetris community. Author of T-ex and Tetr.js Farter's Dig Mod.",
- "https://space.bilibili.com/132966",
- },
- {"Teatube",
- "teatube ttb chaguan chanaiye sifangchaye 022",
- "name",
- "Administrator of the Tetris Research community, Operator of the Tetris Online Study private server, chief editor of the Huiji wiki.\nPersonal bests: Sprint 33 seconds.",
- "https://space.bilibili.com/834903",
- },
- {"Sniraite",
- "sniraite",
- "name",
- "Tetris Research community member.\nPersonal bests: Sprint 23 seconds\nOne of the top players in China. Should be the fastest player in Mainland China.",
- "https://space.bilibili.com/561589",
- },
- {"xb",
- "xb",
- "name",
- "Tetris Research community member.\nMain organizer for competitions in the community.",
- },
- {"Flyz",
- "flyz fxg",
- "name",
- "Tetris Research community member.\nA technical player.",
- "https://space.bilibili.com/787096",
- },
- {"gggf",
- "xiaoqi kissne gggf",
- "name",
- "Tetris Research community member.\nPersonal bests: Sprint 22.677 seconds (25.483 seconds on mobile), MPH Sprint 56 seconds, X rank on Tetr.io\nOne of the top players of 20G in China, achieved almost every achievement in TGM3.\n\nAlso a Touhou fan: IN:EX NM 1B FS; MF:L NM ",
- "https://space.bilibili.com/287769888",
- },
- {"蕴空之灵",
- "ykzl yunkongzhiling niao bird",
- "name",
- "(Yùn Kōng Zhī Líng)Tetris Research community member.\nPersonal bests: Sprint 33 seconds.\nDecent efficiency. Can't eat spicy food. Often uses TKI 3, Albatross and PC opener.",
- "https://space.bilibili.com/9964553",
- },
- {"Mono",
- "mono dongxi",
- "name",
- "Tetris Research community member.\nWe seem to have lost some information about this individual, but you should still be able to find her in one of the voice packs in Techmino.",
- "https://space.bilibili.com/1048531896",
- },
- {"奏之章",
- "zzz zouzhizhang",
- "name",
- "(Zòu Zhī Zhāng) Tetris Research community member.\nAuthor of ZZZbot. An important figure in the developement of Tetris AI in China.",
- "https://space.bilibili.com/311039",
- },
- {"吴淞昊",
- "wusonghao modian",
- "name",
- "(Wú Sōnghào)\n\nTetris Research community member.\nOne of the top players of hidden Tetris in China. Was once on TV.",
- "https://space.bilibili.com/17583394",
- },
- {"他天一",
- "tty tatianyi hydrofierus",
- "name",
- "(Tā Tiān Yī)\n\nTetris Research community member.\nPersonal bests: Sprint 21.908 seconds, U rank on Tetr.io.\nOne of the top players of Tetris in China.",
- "https://space.bilibili.com/3895759",
- },
- {"Mars608",
- "mars608",
- "name",
- "Tetris Research community member.\nFormer regional first place on Puyo Puyo Tetris (Nintendo Switch, People's Republic of China region).",
- "https://space.bilibili.com/1471400",
- },
- {"Mifu",
- "mifu swl nanmaomao",
- "name",
- "Originally known as swl.\nPersonal bests: Sprint 28.445 seconds, Tetris Research community member.\nMiya's Tetris coach. Miya made an animated character art for him called Mifu, meaning \"Miya's Shifu\".",
- "https://space.bilibili.com/109356367",
- },
- {"ZXC",
- "zxc thtsod flag ctf",
- "name",
- "Also known as ThTsOd.\nTetris Research community member.\nA technical player.",
- "https://space.bilibili.com/4610502",
- },
- {"Tinko",
- "tinko",
- "name",
- "Tetris Research community member.\nA technical player.",
- "https://tinko.moe",
- },
- {"T0722",
- "0722",
- "name",
- "Tetris Research community member.\nMusic Composer.",
- "https://space.bilibili.com/30452985",
- },
- {"Diao",
- "diao",
- "name",
- "Tetris Research community member.\nOne of the top battle players. Won second place in JsCup, champion in TTT, champion in HDO XII.\nHas many former nicknames including nmdtql, diao, nanami.",
- "https://space.bilibili.com/471341780",
- },
- {"思竣",
- "sijun acm oi",
- "name",
- "(Sī Jùn)\n\nTetris Research community member.\nLots of mental computation power.",
- "https://space.bilibili.com/403250559",
- },
- {"Particle_G",
- "particleg pg",
- "name",
- "Tetris Research community member.\nSprint 59.4 seconds\nThe developer of Techmino backend",
- "https://space.bilibili.com/3306106",
- },
- {"琳雨空",
- "linyukong",
- "name",
- "(Lín Yǔ Kong)\n\nTetris Research community member.\nSprint 38.3 seconds, Highest Rank in pentomino mode and Blind-WTF (world No.1)",
- "https://space.bilibili.com/263909369",
- },
- {"子心Koishi",
- "koishi",
- "name",
- "(Zǐ Xīn Koishi)\n\nTetris Research community member, Virtual content creator.\nA top Tetris 99 players known for his strategies.",
- "https://space.bilibili.com/147529",
- },
- {"ditoly",
- "ditoly icrem kuimei jk",
- "name",
- "Tetris Research community member. The developer of Nanamino.",
- "https://space.bilibili.com/13014410",
- },
- {"蓝绿",
- "lanlv lanlyu gompyn imple lee blari'o blariho",
- "name",
- "(Lán Lǜ)\n\nTetris Research community member.\nParticipant of $1",--Techmino backend
- },
- {"喵田弥夜Miya",
- "miya miaotianmiye",
- "name",
- "(Miāo Tián Mí Yè Miya)\n\nTetris Research community member, Virtual content creator.\nPractically the mascot of the community. Voice actress of Techmino.",
- "https://space.bilibili.com/846180",
+ "Acronym for “Away From Keyboard,” or in a broader sense, a period when you are not playing.\nTaking regular breaks help relieve your muscle strain and allow you to play better when you come back.",
},
}
diff --git a/parts/language/dict_ja.lua b/parts/language/dict_ja.lua
new file mode 100644
index 000000000..136e5e1ef
--- /dev/null
+++ b/parts/language/dict_ja.lua
@@ -0,0 +1,1402 @@
+-- Automatically generated by a Python script, from a markdown source file.
+-- The script can be found here: https://github.com/user670/techmino-dictionary-converter/blob/master/tool.py
+return {
+ {"翻訳者からのメッセージ 1",
+ "",
+ "help",
+ "この日本語版TetroDictionary(通称:Zictionary)は、英語版を通して翻訳されています\nそのため中国語版の内容を正確に反映していない可能性があります\n\n翻訳者を知りたい、翻訳に協力したい場合は地球儀ボタンをクリックしてGithubのページにアクセスしましょう!",
+ "https://github.com/26F-Studio/Techmino/blob/main/parts/language/dict_ja.lua",
+ },
+ {"初心者へ",
+ "readme 初心者 下級者 コツ ガイド 上達",
+ "help",
+ "テトリス初心者の方へ\n\t2つの大事なこと:\n\t\t1.操作性のいいテトリスを選びましょう(TechminoやTETR.IO, Jstris, Tetr.js)\nガイドラインから大きく離れ、プログラミング教材に使われているような操作性の悪いものはプレイしないでください\n\t\t2.ネクストを見る、テトリスを安定して行う等の基本的な能力育成に時間を費やしましょう\nとりあえず今は、Tspinみたいな技は置いときましょう\nどうせ基礎に費やす時間は変わりません\n\t2つの技術:\n\t\t1.ミノの出現位置と操作方法を覚えて、好きな場所に移動できるようになりましょう\n\t\t2.次のミノの置く場所をあらかじめ決められるようになりましょう\n\n地球儀ボタンをクリックすると中国のテトリスプレイヤー、Tatianyiさんが書いた「Suggestion for new players to Tetris Online」という記事の英語版(翻訳者:User670)が見れます",
+ "https://github.com/user670/temp/blob/master/tips_to_those_new_to_top.md",
+ },
+ {"おすすめの練習法",
+ "readme 初心者 下級者 コツ ガイド 上達 練習",
+ "help",
+ "ここでは、おすすめの練習方法を紹介します\nもし煮詰まった場合は、リラックスして好きなモードを楽しみましょう!楽しむことが一番大事です!!\n\n以下は、達成してほしい目標のリストです\nA,B,Cとセットがあり、更にその中に複数の目標がありますがセット単位で複数の目標を同時にこなすのがおすすめです\n\nA.積み(1)\n\tA1.ミノを置く前に次のミノも考慮に入れてください\nもし次のミノが置きづらい場合には、今持ってるミノの置き場所を考え直してください\n\tA2.地形を平らにするよう意識するとどんなミノでも置きやすくなります(一部ではより具体的に横置きを意識するとも言われています)\n\tA3.ホールドが使える時は、今持っているミノ、ホールドにあるミノ、ネクストにあるミノの3つを意識するとより長い時間平らな地形を維持できます\n\nB.効率と速さ\n\tB1.ゴーストを見ながら置かないでください\nこのミノをここに置くにはこの操作をするというのを頭の中で処理してください\n\tB2.回転キーは左右両方使ってください\n一回の入力で済む操作は一回で処理しましょう\n\tB3.最適化を覚え始めてきたら速さはあまり気にしないでください\n最適化は癖付けるものなので一度身につければ、精度を保ったまま速くなれます\n\nC.積み(2)\n\tC1.スプリント(40Line)を完走する\n\tC2.ホールドなしでスプリント(40Line)を完走する \n\tC3.Techrashだけでスプリント(40Line)を完走する\n\tC4.ノーホールド、Techrashだけでスプリント(40Line)を完走する\n\nCは難易度を調整しやすいので、自身の能力に合わせて難易度を調整してください\n\nCが終わった場合は、A1の練習をしてください\nこれはテトリスの基本技術の一つでネクストの把握量が多ければどんなゲームモードでもすぐに上達できます",
+ },
+ {"Tspinを学ぼう",
+ "t tspin t-spin tスピン 上達法 初心者 下級者 ガイド tip おすすめ 練習 helps",
+ "help",
+ "Tspinはテトリスの中でも高等技術なのでTspinの地形を見ているだけでは、習得できません\nまた積みの技術やネクスト把握能力も必要になってきます\nもし本当にTspin技術を上達させたい場合は、積みの技術などの土台となる技術をしっかり習得しましょう\n\nおすすめの習得タイミング:スプリント(40Line)を60秒(条件によっては40~120秒)以内に完走、Techrashだけで完走、ホールドなしで大きく減速せずに完走\nこれらで十分にネクストを考慮した思考ができるようになってからTspinを学び始めることをおすすめします",
+ },
+ {"Techmino公式web",
+ "homepage web mainpage ホームページ ウェブ メインページ テクミノ テックミノ techmino",
+ "help",
+ "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",
+ },
+ {"HardDrop wiki",
+ "harddrop hd wiki ハードドロップ ハードロ ウィキ うぃき",
+ "help",
+ "テトリス最大コミュニティ、HardDropが運営している英語テトリスwikiです",
+ "https://harddrop.com/wiki/Tetris_Wiki",
+ },
+ {"Tetris wiki",
+ "tetris テトリス てとりす wiki ウィキ うぃき",
+ "help",
+ "Tetris wikiはテトリス関連の情報に焦点を当てたwikiです\nMyndziが2015年に開設しました\n公式テトリス及びファン製作の落ちものパズルゲームの記録、ゲームの仕様の解析、上達のためのガイドの作成など様々な記事が長年にわたり何千も投稿されています",
+ "https://tetris.wiki",
+ },
+ {"Tetris Wiki Fandom",
+ "tetris テトリス てとりす wiki ウィキ うぃき fandom ファンダム ふぁんだむ",
+ "help",
+ "英語のテトリスwikiです\n公式テトリスを重点的にまとめています",
+ "https://tetris.fandom.com/wiki/Tetris_Wiki",
+ },
+ {"Four.lol",
+ "four wiki lol fourlol フォー ウィキ うぃき テンプレ template",
+ "help",
+ "様々な開幕や連パフェが集められたテトリスwikiです",
+ "https://four.lol",
+ },
+ {"テトリス堂",
+ "tetris テトリス てとりす hall はる 日本語 japanese テンプレ template",
+ "help",
+ "日本語サイトです\n開幕のチュートリアル、パフェクイズなどのミニゲーム、連パフェの詳細な解説があります",
+ "https://shiwehi.com/tetris/",
+ },
+ {"テトリステンプレ集@テト譜",
+ "wiki ウィキ うぃき atwiki テンプレ template 日本語 japanese",
+ "help",
+ "非常に多くのテンプレを保有している日本語atwikiです",
+ "https://w.atwiki.jp/tetrismaps/",
+ },
+ {"テトリスブログ - PerfectClear",
+ "テンプレ template 日本語 japanese 開幕",
+ "help",
+ "数は多くないですが開幕テンプレのセットアップが詳細に解説されている日本語サイトです",
+ "https://tetristemplate.info/",
+ },
+ {"ほゐスライド",
+ "上達 練習 ほゐ スライド",
+ "help",
+ "日本のテトリスプレイヤー、whipemerald氏が作ったテトリスを上達させるためのスライド\nテトリスフレンズの時代に作られたものだが今の時代でも問題なく通じる",
+ "https://docs.google.com/presentation/d/1kYU2T6Kb-CVVshOa3BHGIhCoOWbbbKUekQqq-TsZgoY/mobilepresent?slide=id.p",
+ },
+ {"テト譜",
+ "fumen テト譜 譜面 研究 解析",
+ "help",
+ "Mihys氏が開発したテトリスの地形を描画や共有ができる偉大なサイト\n他のテトリスツールを使用する際にもよく使われる\nAdd-onからframe.jsを選択することでさらに拡張した機能が使えます",
+ "http://fumen.zui.jp",
+ },
+ {"Fumen for Mobile",
+ "fumenformobile fm fumen テト譜 譜面 モバイル mobile もばいる 研究 解析",
+ "help",
+ "Newjade氏によってテト譜をスマホ等でより直感的に使えるように開発されたテト譜サイトです\nフィールドの画像出力や範囲塗りなどの公式のテト譜にはない機能も多数あります",
+ "https://knewjade.github.io/fumen-for-mobile/",
+ },
+ {"テト譜ブラウザ",
+ "fm fumen テト譜 譜面 研究 解析",
+ "help",
+ "主にテト譜を管理するためのソフト\n大量にテト譜を管理する人は持っていて損はない",
+ "https://com.nicovideo.jp/community/co1370000",
+ },
+ {"solution-finder",
+ "fm fumen テト譜 譜面 研究 解析",
+ "help",
+ "Newjade氏によって開発されたパフェの確率やパターン、最大ren数など様々な解を見つけたり確率を計算できるツール\n日本ではテンプレ制作、それ以外ではパフェ関連に使われることが多い",
+ "https://solution-finder.readthedocs.io/ja/latest/",
+ },
+ {"path-filter",
+ "fm fumen テト譜 譜面 研究 解析 パフェ perfect all 最小",
+ "help",
+ "Newjade氏によって開発されたパフェ率を維持したまま最小パターンを求めるためのツール\nただし近似解を出力するので複数回もしくは、長時間使うことが前提である",
+ "https://github.com/knewjade/path-filter/releases",
+ },
+ -- # Webpages / Organizations
+ {"Github Repository",
+ "githubrepository sourcecode src ソース リポジトリ りぽじとり github",
+ "org",
+ "Techminoの公式Githubです\n星をお願いします!",
+ "https://github.com/26F-Studio/Techmino",
+ },
+ {"Discord コミュニティ",
+ "community コミュニティ コミュ こみゅにてぃ こみゅ discord ディスコード",
+ "org",
+ "Techminoコミュニティに参加して、他のプレイヤーと交流しよう!地球儀ボタンからTechminoのdiscordサーバーにアクセスできます",
+ "https://discord.gg/f9pUvkh",
+ },
+ {"テトリスオンラインポーランド",
+ "tetrisonline servers top toj toz poland japan zapan",
+ "org",
+ "地球儀ボタンをクリックするとTOPクライアントの情報にアクセスできますが2023年4月10日現在、2種類の日本サーバーはダウンしており、TOPサーバーのみ使えます",
+ "http://tetrisonline.pl/",
+ },
+ {"Tetris OL Servers",
+ "tetrisonline servers tos",
+ "org",
+ "地球儀ボタンをクリックするとTeatube氏作成の中国のTetris Online Studyの情報にアクセスできます",
+ "https://teatube.cn/tos/",
+ },
+FNNS and {"サポート1",
+ "support サポート 寄付 wechat vx weixin alipay zfb zhifubao",
+ "org",
+ "こちらの内容はプラットフォームの関係により非表示にされています\\n詳しくはTechminoのdiscordサーバーにて聞いてください",
+ -- id: support-1
+ -- platform-restriction: apple
+ } or {"サポート1",
+ "support サポート 寄付 wechat vx weixin alipay zfb zhifubao",
+ "org",
+ "WechatやAlipayを使ってTechminoに寄付してくださる場合は、ゲームメイン画面の「TECHMINO」のTを連打→コンソール画面で「support」と入力→QRコードを読み取って寄付してください",
+ -- id: support-1
+ -- platform-restriction: non-apple
+ },
+FNNS and {"サポート2",
+ "support サポート 寄付 afdian aidadian",
+ "org",
+ "こちらの内容はプラットフォームの関係により非表示にされています\\n詳しくはTechminoのdiscordサーバーにて聞いてください",
+ -- id: support-2
+ -- platform-restriction: apple
+ } or {"サポート2",
+ "support サポート 寄付 afdian aidadian",
+ "org",
+ "Aifadianを使ってTechminoに寄付してくださる場合は、地球儀ボタンからURLを開いてください\nAifadianの場合、寄付金額から6%の手数料がかかります",
+ "https://afdian.net/@MrZ_26",
+ -- id: support-2
+ -- platform-restriction: non-apple
+ },
+FNNS and {"サポート3",
+ "support サポート 寄付 patreon patreon",
+ "org",
+ "こちらの内容はプラットフォームの関係により非表示にされています\\n詳しくはTechminoのdiscordサーバーにて聞いてください",
+ -- id: support-3
+ -- platform-restriction: apple
+ } or {"サポート3",
+ "support サポート 寄付 patreon patreon",
+ "org",
+ "Patreonを使ってTechminoに寄付してくださる場合は、地球儀ボタンからURLを開いてください\nPatreonの場合、一定額以上の寄付に対して手数料がかかります",
+ "https://www.patreon.com/techmino",
+ -- id: support-3
+ -- platform-restriction: non-apple
+ },
+ -- # Games
+ {"テトリス トレーナー トレビアン",
+ "tetris trainer tres bien 上達 練習 テトリス トレーナー トレビアン",
+ "game",
+ "こな氏によって開発されたチュートリアルサイトです\nTspinや最適化、SRS等の対戦テトリスで使う技術を学べます\nノーホールド、Techrashだけでスプリント(40Line)を完走できたプレイヤーにおすすめです",
+ "http://taninkona.web.fc2.com/ttt/",
+ },
+ {"テトリス パフェチャレンジ",
+ "tetris perfect clear challenge パフェ 連パフェ 上達 練習",
+ "game",
+ "Chokotia氏によって開発された開幕パフェのチュートリアルサイトです\nテトリス トレーナー トレビアンをクリアし、SRSに慣れたプレイヤーにおすすめです",
+ "https://davdav1233.github.io/ttpc/",
+ },
+ {"ナゾテト",
+ "nazo なぞ ナゾ 謎 上達 練習",
+ "game",
+ "Tspinやオールスピン、簡単な問題から難しい問題まで様々な謎テトがあります\nテトリス トレーナー トレビアンをクリアしたプレイヤーにおすすめです",
+ "http://klyuchevskayanazoteto.web.fc2.com/",
+ },
+ {"TPO",
+ "nazo なぞ ナゾ 謎 上達 練習",
+ "game",
+ "Tetris puzzle O(テトリスパズルオー)はTCV100によって開発された中国の謎テトサイトです\nナゾテトのパズルをいくつか含んでいます",
+ "http://121.36.2.245:3000/tpo",
+ },
+ {"詰めテトリス",
+ "nazo なぞ ナゾ 謎 上達 練習",
+ "game",
+ "ナゾテトよりも実践向けの謎テトがまとめられたatwiki\nテトリスDS時代のものなのでパフェとren火力はなし、TSMはTSS扱い",
+ "https://w.atwiki.jp/tetrisds/pages/26.html",
+ },
+ {"twowide",
+ "nazo なぞ ナゾ 謎 上達 練習",
+ "game",
+ "多数の高難易度謎テト、豊富なモードがある謎テトサイトです\nオンラインランキングもあるので他のプレイヤーと競い合うことができます",
+ "https://twowi.de",
+ },
+ {"downstack-practice",
+ "nazo なぞ ナゾ 謎 上達 練習",
+ "game",
+ "downstackと書いてあるが掘以外にもTspinや途中パフェ等の謎テトを生成する謎テトサイトです\n中盤テンプレも練習でき、より実践に近い謎テトを解くことができます",
+ "https://himitsuconfidential.github.io/downstack-practice/",
+ },
+ {"途中メモ 1",
+ "note memo ノート メモ nb NB DM notice",
+ "game",
+ "次からは公式テトリスや落ちものパズルゲームの簡単な紹介です\n\nもちろんここにあるゲームがすべてではありません\nまたTechmino制作者がコメントをしていることがありますが、あくまで主観的な意見でありそのゲームの良し悪しを決めるものではないことに注意してください\n事実と意見を明確に区別するために意見は大括弧([,])で囲んでいます",
+ },
+ {"King of Stackers",
+ "kos kingofstackers こす コス キング スタッカーズ",
+ "game",
+ "ブラウザ | マルチプレイ | モバイル端末可\n略称はkos\nターン制の非公式テトリスです\n基本的なルール:\nプレイヤーは1ターンにつき7つずつミノを設置していきます\n相手から火力が送られてもLine消去をしている間はせり上がりません\nこのゲームはppsの概念がないためとても戦略的です\nまた試合設定で様々な攻撃ルールに設定できます(通常はExclusive+)",
+ "https://kingofstackers.com/",
+ },
+ {"Tetr.js",
+ "tetrjs tetr.js js",
+ "game",
+ "ブラウザ | シングルプレイ | モバイル端末可\nオリジナルは単純な1人用の非公式テトリスです[見た目もシンプルでアニメーションはほとんどありません]\nしかし有志により細かいチューニングや多くのモード、仮想キーボードの追加等が行われました\n地球儀ボタンのリンクはfarter氏によるDig Modへのリンクです",
+ "http://farter.cn/t",
+ },
+ {"Tetra Legends",
+ "tl tetralegends レジェンズ レジェンド てとら テトラ",
+ "game",
+ "ブラウザ | シングルプレイ | モバイル端末不可\n略称はTL\n多くの1人用モードと2つの隠しリズムゲームを持っている1人用の非公式テトリスです\n通常他のゲームでは隠されている部分まで可視化されています\nしかし複合的な理由により2020年12月に開発が中止されました",
+ "https://tetralegends.app",
+ },
+ {"Ascension",
+ "asc ASC ascension アズセシオン",
+ "game",
+ "ブラウザ | シングル/マルチプレイ\n略称はASC\n同じくASCと呼ばれる独自の回転法則があり、多くの一人用モードがあります\n1vs1モードは2022年11月26日現在、α版です\nTechminoのstackモードはASCからアイデアを得ています",
+ "https://asc.winternebs.com",
+ },
+ {"Jstris",
+ "js jstris じぇすとりす ジェストリス",
+ "game",
+ "ブラウザ | シングル/マルチプレイ | モバイル端末可\n略称はjs\n現在、主流の非公式テトリスの1つであり、様々なシングルモードと豊富な設定、自由に配置できる仮想キーボードを備えています\nまたjstris+を導入することでさらに拡張されたjstrisを楽しむことができます",
+ "https://jstris.jezevec10.com",
+ },
+ {"TETR.IO",
+ "io tetrio tetr.io てとりお テトリオ tetr てとらいお テトライオ",
+ "game",
+ "ブラウザ | シングル/マルチプレイ\n略称はテトリオ\n現在、主流の非公式テトリスの1つであり、レーティングシステムや多くのゲーム設定を変更できるカスタムゲーム、FFAなど様々な要素を備えています\nまた安定して動作しやすいデスクトップクライアント版が存在します\nそしてTETR.IO+を導入することでさらに拡張されたテトリオを楽しむことができます\n[safariじゃテトリオはできないようです]",
+ "https://tetr.io",
+ },
+ {"Nuketris",
+ "nuketris nuke ぬけ ヌケ ぬけとりす ヌケトリス",
+ "game",
+ "ブラウザ | シングル/マルチプレイ\n基本的な1人用モードやレーティングシステムを備えた非公式テトリスです\n独特なゲームルールをしており、Ospinもできます",
+ "https://nuketris.com",
+ },
+ {"Worldwide Combos",
+ "wwc worldwidecombos ワールド ワイド コンボ コンボズ",
+ "game",
+ "ブラウザ | シングル/マルチプレイ\n略称はWWC\n世界規模の1vs1やリプレイと戦えるモード、豊富なゲーム設定など様々な機能を備えた非公式テトリスです",
+ "https://worldwidecombos.com",
+ },
+ {"Tetris Friends",
+ "tf tetrisfriends notrisfoes テトリス てとふれ テトフレ のとりす ノトリス official 公式",
+ "game",
+ "ブラウザ | シングル/マルチプレイ\n略称はテトフレ\n今は亡き公式テトリス\n昔はとても人気があったが数年前にサービス終了した\n現在は「Notris Foes」という非公式プライベートサーバーが存在している",
+ "https://notrisfoes.com",
+ },
+ {"tetris.com",
+ "tetris テトリス online オンライン official 公式",
+ "game",
+ "ブラウザ | シングルプレイ\ntetris.comにある公式テトリス\nゲームモードはマラソンのみです\n公式テトリスでは珍しくマウス操作に対応しています",
+ "https://tetris.com/play-tetris/?utm_source=top_nav_link&utm_medium=webnav&utm_campaign=playNow_btm_tst&utm_content=text_play_now",
+ },
+ {"Tetris Gems",
+ "tetris テトリス online オンライン official 公式 gem ジェム",
+ "game",
+ "ブラウザ | シングルプレイ\ntetris.comにある公式テトリス\n横1列を揃えると揃えた部分が重力の影響を受ける特殊なブロックになり、連鎖的にLine消去が可能なゲームである\nさらに3種類の宝石ブロックが存在し、それぞれ特殊能力を持っています",
+ "https://tetris.com/play-tetrisgems",
+ },
+ {"Tetris Mind Bender",
+ "tetris テトリス online オンライン official 公式 gem ジェム",
+ "game",
+ "ブラウザ | シングルプレイ\ntetris.comにある公式テトリス\nルールはマラソンと同じですが「マインドベンダー」という特殊なブロックが出現します\nマインドベンダーを消すことで様々なイベントが起こります",
+ "https://tetris.com/play-tetrismindbender",
+ },
+ {"Techmino",
+ "techmino テクミノ テックミノ",
+ "game",
+ "クロスプラットフォーム | シングル/マルチプレイ\n日本語だとテクミノと呼ばれます\nMrZを筆頭にLÖVEを使って開発された落ちものパズルゲームです\n多くの一人用モード、多彩なカスタマイズ性を持ち、オンラインマルチプレイも徐々に開発されています",
+ },
+ {"Falling Lightblocks",
+ "fl fallinglightblocks ライト フォーリング",
+ "game",
+ "ブラウザ/iOS/Android | シングル/マルチプレイ\n縦でも横でも遊べるマルチプラットフォームの非公式テトリス\nDASやLine消去時間は固定されています\nまたモバイル端末では操作を一部カスタマイズ可能です\nFalling Lightblocks内にあるゲームのほとんどはファミコンのクラッシクテトリスがベースになっていますがモダンテトリスも存在します\nバトルシステムは半分ターン制、半分リアルタイム制になっており、相殺システムはありません",
+ "https://golfgl.de/lightblocks/",
+ },
+ {"HATETRIS",
+ "hatetris へいと ヘイト はてとりす ハテトリス",
+ "game",
+ "ブラウザ | シングルプレイ\n常に嫌なブロックが出現する一風変わった非公式テトリス\nLine消去数がそのままスコアになる\nテトリス全体で見ても非常に難しいことから人間によるスコア更新よりも機械を使った研究の方が盛んである",
+ "https://qntm.org/files/hatetris/hatetris.html",
+ },
+ {"Cambridge",
+ "cambridge ケンブリッジ",
+ "game",
+ "クロスプラットフォーム | シングルプレイ\nLÖVEを使って開発された非公式テトリスです\n簡単かつ高度にカスタマイズできる新しいゲームモードがあります\n元々はJoe Zeng氏が開発していましたが2020年10月8日のver.0.1.5からMilla氏が引継ぎました\n-Tetris wikiより",
+ },
+ {"Nanamino",
+ "nanamino ななみの なな ナナミノ ナナ",
+ "game",
+ "Windows/Android | シングルプレイ\n面白い回転システムを持っている開発中の非公式テトリスです",
+ },
+ {"TGM",
+ "tetrisgrandmaster tetristhegrandmaster gm グランド マスター",
+ "game",
+ "アーケード/PS/NS | シングル/ローカルマルチプレイ\nTetris The Grand Masterはアーケードテトリスです\nS13やGM等のモードはこのシリーズから始まりました\nTGM3はシリーズの中で最も有名なタイトルです\nNintendo SwitchやPlaystation 4に移植されてます",
+ },
+ {"DTET",
+ "dtet デテト でてと ディテト でぃてと",
+ "game",
+ "Windows | シングルプレイ\nTGMのクラッシクルールをベースに20Gや強力な回転システムを導入した非公式テトリスです\n現在、このゲームを見つけ出すのは難しく、見つからないDLLファイルを自分で補う必要があります",
+ },
+ {"Heboris",
+ "hb heboris へぼ ヘボリス へぼりす",
+ "game",
+ "Windows | シングルプレイ\nアーケードのような雰囲気の非公式テトリスです\n他のテトリスの様々なゲームモードをシミュレーションできます",
+ },
+ {"Texmaster",
+ "txm texmaster テクス マスター",
+ "game",
+ "Windows | シングルプレイ\nTGMの全モードを収録している非公式テトリスです\nただしインスタントソフトドロップやキックテーブルの仕様がワールドルールと少し異なります",
+ },
+ {"Tetris Effect",
+ "te tec tetriseffectconnected TE:C テック テトエフェ エフェクト コネクテッド",
+ "game",
+ "PS/Oculus Quest/Xbox/NS/Windows | シングル/マルチプレイ\n略称はテトエフェ(TEC)\n入力に反応するド派手なグラフィックとサウンドを備えた現在、主流の公式テトリスの1つ\n「Connected」の文字がない基本版では1人用モードしかない\nコネクテッドの方ではコネクテッドバトル、Zoneバトル、スコアアタック、クラッシクスコアアタックの計4つのモードで対戦が可能となっている(ただしフレンドマッチやローカルマッチではZoneなし等のルール設定が可能)",
+ },
+ {"Tetris 99",
+ "t99 tetris99 99",
+ "game",
+ "Nintendo Switch | シングル/マルチプレイ\n99人でバトルロイヤルを行う公式テトリス\n従来の対戦テトリスにはない戦略が多く存在する\nまたDLCをダウンロードすることでマラソンやcpuとの試合、キャラクタースキンなどが追加される",
+ },
+ {"ぷよぷよテトリス",
+ "ppt puyopuyotetris ぷよテト ぷよぷよ テトリス ぷて",
+ "game",
+ "PS/NS/Xbox/Windows | シングル/マルチプレイ\nぷよぷよとテトリスの2つが入ったゲーム\n異種対戦もでき、多くのゲームモードが存在する\n\n[steam版は操作性が悪く、オンライン対戦も酷い]",
+ },
+ {"Tetris online",
+ "top toj toz tetrisonline poland japan zapan テトオン",
+ "game",
+ "Windows | シングル/マルチプレイ\n今は亡き日本の公式テトリス\nDASとARRの値を設定できますがどちらも0にはできません\nプライベートサーバーで稼働していましたが2023年4月10日現在、2種類の日本サーバーはダウンしており、TOPサーバーのみ使えます",
+ },
+ {"Tetra Online",
+ "TO tetraonline tetraoffline offline テトラ てとら オンライン オフライン",
+ "game",
+ "Windows/macOS/Linux | シングル/マルチプレイ\nDr OceloとMineによって開発された非公式テトリスです\n操作性は意図的にAREが高い値に設定されているのでぷよテトなどに近い\nThe tetris companyがDMCA(デジタルミレニアム著作権法)を理由にsteamから削除されました\nしかしオフライン版は現在もGithubから入手可能です\n\nテトラオフライン",
+ "https://github.com/Juan-Cartes/Tetra-Offline/releases/tag/1.0",
+ },
+ {"Cultris II",
+ "c2 cultris2 cultrisii カルトリス",
+ "game",
+ "Windows/OS X | シングル/マルチプレイ\nクラッシクテトリスをベースにデザインされた非公式テトリス\n対戦モードはコンボ(ren)に重点を置いたものとなっており、コンボ地形を組み立てる速さ、コンボ消化速度、掘のスキルが試されるゲームとなっている\n\n[Mac版は長い間メンテナンスされてなく、macOS Catalineよりも新しいビルドのmac OSではこのゲームをプレイできません]",
+ },
+ {"Nullpomino",
+ "np nullpomino ぬるぽ ヌルポ ぬるぽみの ヌルポミノ ぬる",
+ "game",
+ "Windows/macOS/Linux | シングル/マルチプレイ\nカスタマイズ性の高い非公式テトリス\nゲーム内のほぼ全ての設定を変更できる\n\n[しかしUIが時代遅れでフルキーボードでの操作が必須になります\nNullpommino初心者は慣れるまで問題がある可能性があります\nまたmac OS Montereyではこのゲームは動作しません]",
+ },
+ {"Misamino",
+ "misamino ミサミノ みさみの みさかみの ミサカミノ",
+ "game",
+ "Windows | シングルプレイ\nローカルでMisaminoというbotと対戦できる非公式テトリス\nAPIを学ぶことで自分でbotを作ることもできる",
+ },
+ {"four-tris",
+ "four 練習 上達 解析 研究",
+ "game",
+ "Windows | シングルプレイ\n主に試合を解析するためのソフト\n盤面の取り込みは画像解析によって行う(かなり精度が高い)\n n回目のパフェやren、チーズの練習もできる",
+ "https://github.com/fiorescarlatto/four-tris/releases",
+ },
+ {"Touhoumino",
+ "touhoumino 東方 touhou とうほう トウホウ",
+ "game",
+ "Windows | シングルプレイ\nNullpominoを改造し、東方projectの要素を追加した非公式テトリス\nマラソンではスペルカードが存在し、制限時間内に必要なスコアに到達しないといけない\n\n[自分の腕に自信がある人におすすめ\nそうじゃないとどうやって死んだのかすらわからない]",
+ },
+ {"Tetris Blitz",
+ "blitz ea mobile phone ブリッツ イーエー スマホ スマートフォン モバイル",
+ "game",
+ "iOS/Android | シングルプレイ\nEAによって開発されたスマートフォン用の公式テトリス\nゲーム開始時に多くのミノが落ちて来たり、Line消去を連続で行うことで「Frenzy」モードに入ることができたり、トップアウトが存在しなかったりと様々な特殊な仕様がある\n\nこのゲームは2020年4月に配信を終了しています",
+ },
+ {"Tetris (EA)",
+ "tetris ea galaxy universe cosmos mobile phone テトリス イーエー スマホ スマートフォン モバイル ギャラクシー 銀河 宇宙 ユニバーサル コスモス",
+ "game",
+ "iOS/Android | シングル/マルチプレイ(?)\nEAが開発したもう1つのスマートフォン用公式テトリス\nスワイプとワンタッチの2つの操作方法がある\nまたマラソンの他にギャラクシーモードというものが存在する\nこのモードのクリア条件は指定されたミノを使い切る前にギャラクシーミノを消去することです\n\nこのゲームは2020年4月に配信を終了しています",
+ },
+ {"Tetris (N3TWORK)",
+ "tetris n3twork mobile phone テトリス スマホ スマートフォン モバイル",
+ "game",
+ "iOS/Android |シングルプレイ\nN3TWORKが開発したスマートフォン用の公式テトリス\n3分のウルトラ、マラソン、100人(cpu)のバトルロイヤルモードがある\n\n[UIは素晴らしいが操作性が良くない]",
+ },
+ {"Tetris Beat",
+ "n3twork rhythm リズム ビート beat スマホ スマートフォン モバイル mobile phone",
+ "game",
+ "iOS | シングルプレイ\nN3TWORKがAppleアーケードで配信しているスマートフォン用の公式テトリス\nマラソンの他にビートモードがあるがBGMのリズムに合わせてミノを置いて行くだけである\n\n[エフェクトが重いし操作性もイマイチ]",
+ },
+ {"Tetris Journey",
+ "tetrisjourney mobile phone huanyouji スマホ スマートフォン モバイル ジャーニー",
+ "game",
+ "iOS/Android | シングルプレイ\nTencentによって開発され、中国限定で配信されたスマートフォン用の公式テトリス\nレベルモードや対戦モード、いくつかの1人用モードがある\n対戦モードでは2分間の時間制限があり、対戦者がトップアウトしない場合、より多く火力を送った方が勝者となる\n仮想キーボードの配置や大きさを調整できる",
+ },
+ {"JJ Tetris",
+ "jjtetris じぇーじぇー ジェージェー じぇじぇ ジェジェ",
+ "game",
+ "Android | マルチプレイ\n正式名称:JJ块\nJJ棋牌のカジュアルゲーム\n縦画面、低入力遅延と操作性が高い\nDASやARR、20Gソフトドロップなども制限はありますが設定可能です\nホールドやB2Bシステム、相殺システムはありません\n他にもそれぞれの攻撃の火力の上限が4、コンボが強いという特徴がありますが、それ以外はモダンテトリスに似ています",
+ },
+ {"Huopin Tetris",
+ "huopin qq ほうぴん",
+ "game",
+ "Windows |マルチプレイ\n正式名称:火拼俄罗斯\nTencent Game Centerが開発した公式テトリス\n幅12の盤面、DASやARRはキーボードのタイピングと同じ、ネクストは1つ、ホールドはない\n3line消し(火力:2)とテトリス(火力:3)でしか攻撃を送れない\n下穴が市松模様のようになっているので掘ることはほぼ不可能",
+ },
+ -- # Terms
+ {"途中メモ 2",
+ "note memo ノート メモ nb NB DM notice",
+ "term",
+ "ここからは用語解説になります\n\nこれらの用語は全てのコミュニティで通じるとは限らず、また全ての用語が常に同じ意味になるとは限らないことに注意してください\nここでは主にTechmino内で使うことを想定しています",
+ },
+ {"LPM",
+ "linesperminute speed 速さ 早さ はやさ lpm l'pm",
+ "term",
+ "Lines per minute\n\tプレイヤーの速さを計る指標です\nゲームによってLPMの計算方法が異なります\n例えばテトリスオンラインの場合、PPSという値からLPMを計算しています(1PPS=24LPM)\nこの時、下穴消去が無視されているので文字通りのLPMとは異なります\nTechmino内ではこのLPMを「L'PM」と表記しています",
+ },
+ {"PPS",
+ "piecespersecond speed 速さ 早さ はやさ pps",
+ "term",
+ "Pieces per second\n\tプレイヤーの速さを計る指標です",
+ },
+ {"BPM",
+ "blocksperminute piecesperminute speed 速さ 早さ はやさ bpm ppm",
+ "term",
+ "Blocks per minute\n\tプレイヤーの速さを計る指標です\n音楽用語との混同を避けるためにPPMと呼ばれることもあります",
+ },
+ {"KPM",
+ "keysperminute keypressesperminute 速さ 早さ はやさ 入力 kpm",
+ "term",
+ "Keypresses per minute\n\tプレイヤーの入力の速さを計る指標です",
+ },
+ {"KPP",
+ "keysperpiece keypressesperpiece 速さ 早さ はやさ 効率 入力",
+ "term",
+ "Keypresses per piece\n\tミノ操作の効率を計る指標です\n最適化を習得することでこの値を下げることができます",
+ },
+ {"APM",
+ "attackperminute 火力 攻撃",
+ "term",
+ "Attack per minute\n\tプレイヤーが出した火力を計る指標です",
+ },
+ {"SPM",
+ "linessentperminute 火力 攻撃",
+ "term",
+ "[lines] Sent per minute\n\tプレイヤーの攻撃力を計る指標です\nここでは相殺に使用した火力はカウントされず、相手の火力ゲージに送った火力だけがカウントされます",
+ },
+ {"DPM",
+ "digperminute defendperminute 防御 火力 相殺 サバイバル 生存 掘り",
+ "term",
+ "Dig(またはDefend) per minute\n\tプレイヤーの掘り、若しくは防御力(相殺火力+掘ったLine数)を計る指標です",
+ },
+ {"RPM",
+ "receive jieshou 受け 外し 相殺外し",
+ "term",
+ "[lines] Receive per Minute\n\tプレイヤーが受けた攻撃量を計る指標です",
+ },
+ {"ADPM",
+ "attackdigperminute vs",
+ "term",
+ "(Attack + Dig) per minute\n\tその試合で対戦者間のスキルを比較するための指標です\nTETR.IOのVSスコアはこれと違い、100(Attack+Dig)/sで計算しています",
+ },
+ {"APL",
+ "attackperline efficiency 効率 火力 攻撃",
+ "term",
+ "Attack per line (cleared)\n\tよく「効率」という言葉で置き換えられます\n1Line単位の火力を算出している値であり、ここではTSSがテトリスやTSDよりも効率が良いとされる",
+ },
+ {"Single",
+ "single 1 シングル",
+ "term",
+ "1回で1Line消すこと",
+ },
+ {"Double",
+ "double 2 ダブル",
+ "term",
+ "1回で2Line消すこと",
+ },
+ {"Triple",
+ "triple 3 トリプル",
+ "term",
+ "1回で3Line消すこと",
+ },
+ {"Techrash",
+ "techrash tetris 4 quad クアッド",
+ "term",
+ "*Techmino用語*\n1回で4Line消すこと",
+ },
+ {"Tetris",
+ "tetris 4 quad クアッド",
+ "term",
+ "ゲームの名称(商標)\nまた公式テトリスにおいて1回に4Line消すことを指す言葉\n\nTetra(ギリシャ語で「4」を意味する)とTennis(テトリスの制作者が好きなスポーツ)を組み合わせた造語\n\nまた任天堂とセガが開発したテトリスはThe Tetris Companyのライセンス登録を受けていますが、この2社がテトリスそのものの著作権を保有しているわけではありません\n\n-- Alexey Pajitnovに感謝を!",
+ },
+ {"All Clear",
+ "pc perfectclear ac allclear パフェ オール パーフェクト",
+ "term",
+ "Perfect Clear(PC、パフェ)とも言われる\n盤面内にある全てのミノを消去すること\n明らかにあるのに見逃した場合、「今パ」と言われることがある(逆にこれに言い返すフレーズも存在する)",
+ },
+ {"HPC",
+ "hc clear halfperfectclear ハーフ セミ",
+ "term",
+ "Techmino用語\nHalf Perfect Clearの略\n下穴以外のミノを全て消去するとHPCとなり、軽い火力強化が行われる\n\n俗に言う実質パフェ",
+ },
+ {"Spin(回転入れ)",
+ "spin 回転 スピン",
+ "term",
+ "任意のミノを回転システムを使うことにより入れること\nこれを使うことにより通常では置けない場所にでも置くことが可能になります\nまたこの操作により火力やスコアに補正がかかることがあります\nゲームによって回転システムが異なる場合がある",
+ },
+ {"Mini",
+ "mini ミニ みに",
+ "term",
+ "ゲーム側が簡単すぎると判断したspinに適用されるシステムです\nそのために昔のゲームでは「EZ T-spin」とも呼ばれていました\nminiの付いたspinは火力やスコアボーナスが通常のspinよりも少なくなるように設定されています\n\n基本は細かい仕様を覚えずにminiになる地形だけ覚えておけば大丈夫です",
+ },
+ {"All-Spin",
+ "allspin オール 全",
+ "term",
+ "全てのミノのspinに火力、スコア補正がかかるルールのこと(通常ルールはTspinのみ)\nまた稀にルールではなくAll-spinという回転法則を指すこともある",
+ },
+ {"T-Spin",
+ "tspin ティ ts ふんどし",
+ "term",
+ "Tミノを回転入れ(spin)すること\n\n最近の公式テトリスでは3コーナールールを採用している\nこれは回転入れをした時にTミノの回転軸を中心として斜め4マスの内3マス以上が埋まっていた場合にTspinとして判断するというものである\nゲームによっては一部のTspinをmini扱いしている",
+ },
+ {"TSS",
+ "t1 tspinsingle ティ シングル",
+ "term",
+ "T-Spin Single\nTspinで1Line消去すること",
+ },
+ {"TSD",
+ "t2 tspindouble ティ ダブル",
+ "term",
+ "T-Spin Double\nTspinで2Line消去すること",
+ },
+ {"TST",
+ "t3 tspintriple ティ トリプル",
+ "term",
+ "T-Spin Triple\nTspinで3Line消去すること",
+ },
+ {"MTSS",
+ "minitspinsingle tsms tspinminisingle tsm mini 1 シングル",
+ "term",
+ "Mini T-spin Single\n通称:T-spin Mini Single(TSMS)\nTSSだがmini判定のもののこと\n\nゲームによってどのTSSがminiなのか判定が異なっていたり、そもそもなかったりする",
+ },
+ {"MTSD",
+ "minitspindouble tsmd tspinminidouble tsm mini 2 ダブル",
+ "term",
+ "Mini T-Spin Double\n通称:T-spin Mini Double(TSMD)\nTSDだがmini判定のもののこと\nMTSDは一部のゲームにしか存在せず、発生する地形も異なる場合がある\n\nさらに一部のテトリスではMTSDを想定しておらず最悪の場合、フリーズや強制終了する",
+ },
+ {"O-Spin",
+ "ospin o オー 2",
+ "term",
+ "Oミノはどんなに回転させても形が変化しないため回転入れが不可能でした(一部では毎秒500~600回転させることでOミノが熱膨張したり溶けたり変形したりするという噂があります)\nそのためテトリスコミュニティ内でミームのように扱われ、フェイクビデオ等も作成されました\n\nXRSという回転法則ではOミノを特定の地形で回転させると穴にテレポートするように設計し、それをOspinとしています\nまたTRSでは同様にすることでテレポートさせるだけでなく、他のミノの形に変形することによってOspinを実現しています",
+ },
+ {"Rotation Systems(回転システム、回転法則)",
+ "wallkick rotationsystem 回転 壁 法則",
+ "term",
+ "ミノがどのように回転するかを決定しているシステムのこと\nモダンテトリスの場合、ミノは特定の回転軸を中心に回転している(もちろんそれがないゲームもある)\nそして回転させたときに壁や既にマスが埋まっている場所にミノが重なると通常「壁蹴り」という処理が行われ、あらかじめ決められた位置にズレ、再び壁蹴りが必要かの判定が行われる\nこれを繰り返しミノは設置可能な穴に移動する\nまたこの時、spin判定が出る場合がある",
+ },
+ {"方向表記",
+ "direction 0r2l 02 20 rl lr 表記 ミッション",
+ "term",
+ "SRS系統の回転システムではミノの向きを記述する表記法がある\n「0」や「正の向き」の場合は出現した時と同じ向き、「R」や「右」、「1」という場合は90°右回転(CW)した向き、「L」や「左」、「2」や「逆の向き」の場合は180°回転させた向き、「3」の場合は90°左回転(CCW)した向きを表す\n\n例えば0->Lは左回転1回、2->右は逆の向きの状態から左回転1回となる(これは回転方向ではなくミノの向きを表す表記法なので右回転ではない)\nカスタムモードにあるミッションはこの表記を使っている\n\n「->」や数字使った表記は日本であまり使われない",
+ },
+ {"ARS",
+ "arikrotationsystem atarirotationsystem あたり アタリ ありか アリカ",
+ "term",
+ "これは以下の2つの意味があります\n\nTGMにて採用されているArika Rotation Systemのこと\n\n回転した時にミノを左上に揃えるように回転方向するAtari Rotation Systemのこと",
+ },
+ {"ASC",
+ "ascension アスセンション アズセンション",
+ "term",
+ "テトリスクローン「Ascension」にて使用されている回転法則\n全てのミノに同じ2つのキックテーブルが使用されている\nキック範囲は右回転、左回転両方で±2マスとなっています",
+ },
+ {"ASC+",
+ "ascension ascplus アスセンション アズセンション",
+ "term",
+ "ASCをTechminoのために修正したもの\n180°回転の壁蹴りをサポートしています",
+ },
+ {"BRS",
+ "bulletproofsoftware バレット",
+ "term",
+ "BPS rotation system\nBullet-Proof Software社のテトリスで使用されている回転法則",
+ },
+ {"BiRS",
+ "biasrs biasrotationsystem",
+ "term",
+ "*Techmino用語*\nBias Rotation System\nXRSとSRSを基に作られたTechmino独自の回転法則\n回転時に右や左、ソフトドロップを入力しているとその方向にミノがズレるように回転に補正がかけられます\n下方向に補正がかかっているときに回転に失敗(既存のマスと重なる)と下方向への補正をかけずに再試行します\nそしてそれにも失敗した場合は右、または左の補正をかけずに再試行します\nそれにも失敗した場合には回転されません\n\nBiRSはXRSに比べてキックテーブルが1つのため覚えやすく、さらにSRSの特徴である地形に沿った壁超え等も備えています\n\n追加事項:最後の回転補正を試行する時のルールとして移動するユークリッド距離が√5を超えてはいけない、また右または左に補正がかかっている場合には最後の回転補正はもう一方の方向には行かないという2つのルールがBiRSにあります",
+ },
+ {"C2RS",
+ "c2rs cultris 2 カルトリス",
+ "term",
+ "Cultris II rotation system\nCultris IIで使われている回転法則\n全ての回転、全てのミノのキックテーブルが同じ(ズレ方:左、右、下、左下、右下、左に2、右に2)\nまた左右は左が優先される\n\nTechminoではこの回転法則を改良したC2symという回転法則があり、そちらは左右の優先順位をミノと回転によって決定している",
+ },
+ {"C2sym",
+ "cultris2 カルトリス c2rs",
+ "term",
+ "C2RSを改良した回転法則\nミノと回転によって左右の優先順位を変えています",
+ },
+ {"DRS",
+ "dtetrotationsystem dtet デテト でてと ディテト でぃてと",
+ "term",
+ "DTET Rotation System\nDTETで使われている回転法則",
+ },
+ {"NRS",
+ "nintendorotationsystem 任天堂 ニンテンドー",
+ "term",
+ "Nintendo Rotation System\nファミコンやゲームボーイ時代のテトリスに使用された回転法則\nゲームボーイ用の左手用とファミコン用の右手用の2種類があります",
+ },
+ {"SRS",
+ "superrotationsystem 回転",
+ "term",
+ "Super Rotation System\n最もポピュラーな回転法則であり、多くの自作回転法則の基礎にもなっている\nそれぞれのミノには上下左右4方向あり、右回転、左回転の2つの方向に回転できる(この回転法則では180°は存在しない)\nそして回転した時にミノが既に埋められているマスや壁、床に重なった場合、位置ズレが発生し床や壁を蹴ることができます(通称:壁蹴り)\nキックテーブルの詳細はTetris wikiやHardDropにて調べられます",
+ },
+ {"SRS+",
+ "srsplus superrotationsystemplus tetr",
+ "term",
+ "SRSを180°に対応させ、さらに一部の回転に対称性を持たせた回転法則です",
+ },
+ {"TRS",
+ "techminorotationsystem techmino",
+ "term",
+ "*Techmino用語*\nTechmino Rotation System\nSRSを基にした回転法則\nSとZが回転しない場合を修正し、いくつかの便利なキックテーブルがあります\n\nTRSはOspinをサポートしています",
+ },
+ {"XRS",
+ "xrs",
+ "term",
+ "X rotation system\nTetris.grのT-EXで使われている回転法則\n方向を入力していると別のキックテーブルを使えるという機能を備えておりプレイヤーがミノのズレる先を操作できるようになっている",
+ },
+ {"Back to Back",
+ "b2b btb backtoback バック",
+ "term",
+ "略称はBtB(B2B)\n他のLine消去を挟まずにspinやテトリスをすること\n火力やスコアに補正がかる\nコンボとは違い、Line消去に関わらないミノを置いてもBtBには影響がない",
+ },
+ {"B2B2B",
+ "b3b b2b btb backtoback バック",
+ "term",
+ "*Techmino用語*\nBack to Back to Back、略称はB3B\nBtBを続けて維持し、BtBゲージを満タンにすることでB3Bになり、火力やスコアに更に強力な補正がかかる",
+ },
+ {"Fin, Neo, Iso",
+ "fin neo iso 特殊 フィン ネオ アイエスオー ふぃん ねお あいえすおー",
+ "term",
+ "Tspinのキックテーブルと成立条件を利用した特殊なTspinです\nゲームによってはminiになったりと価値が異なりますが実戦では限られた場面でしか使われません",
+ },
+ {"モダンテトリス",
+ "modern モダン 現代",
+ "term",
+ "“モダン“テトリスや落ちものパズルゲームのコンセプトは曖昧です\n一般的にテトリスガイドラインに準じて作られたテトリス(公式テトリス)に似ている落ちものパズルゲームはモダン(現代的)ゲームと言われます\nこれに共通するルールを以下に挙げますがこれは厳密な定義ではありません\n\n1.可視部分の盤面は横10×縦20、さらにこの上に見えない盤面があることが多い\n2.ミノは盤面可視部分の中央上部に生成され、それぞれ一貫した方向と色を持っています\n3.7-BagやHisのような適当な生成機構がある\n4.適当な回転システムを持ち、最低でも左右、両回転が可能\n5.適当な設置システムがある\n6.適当なトップアウト条件がある\n7.複数個(通常3~6個)のネクストが表示されており、ネクストに表示されているミノが出現時にの方向と一致している\n8.ホールドがある\n9.ミノの出現時間やLine消去時間がある場合、通常IRSやIHSがある\n10.正確かつ素早い横移動のためのDASシステムがある",
+ },
+ {"テトロミノの形",
+ "shape structure form tetromino tetrimino ミノ テトロミノ テトリミノ ブロック ピース 形",
+ "term",
+ "通常のテトリスの場合、使用するミノは全てテトロミノ、つまり4つの正方形が最低でも1辺それぞれ共有するように並べたブロックです\n回転して合同になることは許し、反転で合同になることは許さなかった場合、全部で7種類のテトロミノができます\nこれらのテトロミノはアルファベットに似ていることからそれぞれZ,S,J,L,T,O,Iと名前が付けられている\n詳しくは「形と名前」の項目を参照",
+ },
+ {"テトロミノの色",
+ "colour hue tint tetromino tetrimino ミノ テトロミノ テトリミノ ブロック ピース 色",
+ "term",
+ "最近のモダンテトリスではそれぞれのテトロミノに同じ配色をしています\n\nZ-赤、S-緑、J-青、L-オレンジ、T-紫、O-黄色、I-水色\n\nTechminoも例にもれずこの配色を使っています",
+ },
+ {"IRS",
+ "initialrotationsystem 先行 操作",
+ "term",
+ "Initial Rotation System\nミノ出現前に回転を入力し続けることでミノが回転した状態で出現するシステム\nミノの重なりによる死亡判定を回避することが可能",
+ },
+ {"IHS",
+ "initialholdsystem 先行 操作",
+ "term",
+ "Initial Hold System\nミノ出現前にホールドを入力し続けることでホールドを行った後のミノが出現するシステム\nミノの重なりによる死亡判定を回避することが可能",
+ },
+ {"IMS",
+ "initialmovesystem 先行 操作",
+ "term",
+ "*Techmino用語*\nInitial Movement System\nミノ出現前に横移動を入力し続けることでミノが1つ横にズレた状態で出現するシステム\nミノの重なりによる死亡判定を回避することが可能\n\n補足:横移動を入力し始めてからミノ出現までの時間がDAS時間よりも長くなければいけません",
+ },
+ {"Next(ネクスト)",
+ "nextpreview next ネク ネクスト ねく ねくすと 次 上達 練習",
+ "term",
+ "次に来るミノをいくつか表示している部分のこと\nネクストを処理することによって前もってミノの置く場所を決めることができ、テトリスを上手くなるには必須技術です",
+ },
+ {"Hold(ホールド)",
+ "hold ホールド 一時 保留",
+ "term",
+ "その時点で操作しているミノがホールド部分に移動し、代わりに元々ホールド部分にあったミノを取り出します(もしホールド部分にミノがなかった場合、ネクストのミノが操作ミノになります)\nこの操作は通常繰り返すことはできず、一度ホールド部分に移動したミノは再びホールドすることはできません\n\n*Techmino用語*\nTechminoには「その場ホールド」という機能があります\nこの機能を有効にしていた場合、ホールドから取り出されるミノは従来の出現位置ではなく、その時ミノがある位置に出現します",
+ },
+ {"Swap",
+ "hold ホールド 一時 保留 スワップ",
+ "term",
+ "ホールドと似た機能ですが、swapはネクストとミノを入れ替えます\nつまりこの操作をした場合、swapしたミノは次の操作ミノになります\n\nこの操作は通常繰り返すことはできず、一度swapしたミノは再びswapすることはできません",
+ },
+ {"Deepdrop(ディープドロップ)",
+ "shenjiang ディープ deep",
+ "term",
+ "*Techmino用語*\nこの機能を有効にした場合、床を貫通して回転入れのようにテレポートします\nミノと同じ形の穴があり、その穴が埋まっている時に下までソフトドロップし、もう一度ソフトドロップを入力することで埋まっている穴にテレポートします\nこの機能はAIが回転法則の違いを無視できるようになるため特にAIに有効な機能です",
+ },
+ {"Misdrop(置きミス)",
+ "md misdrop ミス 置き",
+ "term",
+ "意図しない場所にミノを置いてしまうこと\n\n日本では、テトリスするためのIミノが縦のまま1つ横にズレることを「あるぎミス」と言ったりする",
+ },
+ {"Mishold(ホールドミス)",
+ "mh mishold ホールド ミス",
+ "term",
+ "意図しないタイミングでホールドしてしまうこと\n置きミスにつながったりパフェを逃す原因になります",
+ },
+ {"sub(切り)",
+ "sub 切り タイム 秒 分",
+ "term",
+ "sub<時間>(<時間>切り)はスプリント(40Line)などのタイムが<時間>未満であることを意味する\nsubの場合は時間の単位が省かれることが多い\n例えば、スプリント(40Line)の場合はsub30(30秒切り)、1000Lineの場合はsub15(15分切り)と表す",
+ },
+ {"Digging(掘り)",
+ "downstacking ds 掘り 堀り dig ダウン",
+ "term",
+ "盤面の下にある下穴などを消していくこと\n「堀り」ではなく、「掘り」",
+ },
+ {"Downstack",
+ "downstacking down ds 掘り dig ダウン upstack up ud 積み stack",
+ "term",
+ "大きく見た時に地形を下げる積み方のこと\n掘りはこれの1種である\n対義語としてUpstackがある\n\n1巡毎に2Line消去をする場合、盤面内は1巡につき8つブロックが増えていく\nつまり毎巡TSDをすると火力が送れる上にリソースが溜まっていくのである。",
+ },
+ {"削り",
+ "削り 整地",
+ "term",
+ "主に整地を目的として1~3Line消去をすること\n無駄な削りもあるが必要な削りも世の中には存在する",
+ },
+ {"Donation(ドネイト)",
+ "donate ドネイト 空中",
+ "term",
+ "穴を一旦塞いでTspinの地形を作ること\n特にTspinの後に塞いだ穴が空く形状となるもの",
+ },
+ {"‘Debt’",
+ "qianzhai debt owe",
+ "term",
+ "中国のテトリスコミュニティで使われる用語(欠债と呼ばれている)\n\n特定の地形を完成させないとまともな攻撃(Tspinやテトリス)ができない状況や地形を表す用語\n端的に言えばTSTタワーやキングクリムゾンのような大型テンプレを組み終わるまでの隙のことを指す\n大型テンプレを実践でする場合には凝視等で安全なことを確認してから行わないと不利な状況になります",
+ },
+ {"謎テト",
+ "クイズ quiz 謎 上達 練習",
+ "term",
+ "特定の状況とお題が与えられ、それを満たすような答えを探す詰将棋みたいなもの\n謎テトがまとめられたサイトもある",
+ },
+ {"てとぼ",
+ "募集 上達 練習 tetobo",
+ "term",
+ "テトリス募集の略\nTwitterやDiscord上で対戦相手を募る時に使う言葉\nTwitterではてとぼをRTしてくれるbotが存在する",
+ },
+ {"テト譜コード",
+ "開発 テト譜 譜面 コード",
+ "term",
+ "テト譜URLの「v115@~」以降の部分のこと\nこれにはテト譜地形やコメント等の情報が収められている\n「v115@」の部分は「m115@」だったり「v095@」だったりする\n詳しくはnewjade氏が作成した「テト譜v115のデータ構造」というスライド参照",
+ "https://docs.google.com/presentation/d/1P5xt0vPGuxSb9hbRW6hvQFYKFoIccfNTJkWTdjtyigc/edit#slide=id.p",
+ },
+ {"地力",
+ "実力 上達",
+ "term",
+ "あらゆる場面に対応できる総合的な能力のこと\n要はテトリスの実力\n\n実際には速さや見える手、凝視等の根本的な能力の総称として使われることが多い",
+ },
+ {"パリティ",
+ "開発 テト譜 譜面 研究 練習",
+ "term",
+ "地形を特定の法則に従って2色以上で塗り分けた時の性質のこと\n今までは主に市松パリティや縦パリティでパフェが取れる条件を絞り込みだけだったが、最近では研究が進みアップスタック時に安定して火力が出せる地形を維持する条件などが解明されている",
+ },
+ {"Attack & Defend",
+ "attacking defending 攻撃 防御 攻防 アタック ディフェンス 火力 相殺",
+ "term",
+ "attack:相手の火力ゲージに到達した攻撃のこと\ndefend:相手から送られてきた火力に自分の火力を当てること(日本では「相殺」と呼ばれる)\nカウンター:相手からの火力を受ける(相殺外し)、または相手の火力を相殺してから相手に攻撃を送り返すこと\nほとんどのゲームでは1:1で相殺が計算されます\nつまり相手が火力4で攻撃してきた時に自分がテトリス等で火力4を出した場合、4-4=0 で完全相殺となります",
+ },
+ {"Combo(コンボ)",
+ "ren combo れん レン こんぼ コンボ 連",
+ "term",
+ "日本では「ren」とも言う\n連続してLien消去を行うこと\n1回目のLine消去を0ren目、2回目を1ren目、3回目を2ren目としてカウントアップしていく\nもちろんLine消去せずにミノを置いたらren数はリセットになる",
+ },
+ {"Spike(スパイク)",
+ "spike スパイク すぱいく まとめ",
+ "term",
+ "短時間で高火力を出すこと\nただしネットのラグによって大量の火力が行き来することを「ラグスパイク」と呼ぶことがあるが厳密にはスパイクではない\nTechminoとTETR.IOにはスパイクカウンターがあり、これによって短時間でどれだけ高火力を出したかがわかる",
+ },
+ {"端開け(端空け)",
+ "sidewell 端 開け 空け ren combo レン れん コンボ",
+ "term",
+ "端を任意の幅開ける積み方\nつまり端開け1列はテトリス積みになります\n端開け2~4列はren地形になります\n\n端開けは幅を広げる程、短時間で積み上げられますがその分相手からの攻撃が簡単に刺さります\nそのため上級者が端ren等をする場合は相手に隙があるかを確認してから組み始めます",
+ },
+ {"中開け(中空け)",
+ "centerwell 中 開け 空け ren combo レン れん コンボ",
+ "term",
+ "真ん中を任意の幅開ける積み方\n基本的に左右から5,6列目を中心に開けることを指す\nミノを左右に移動させる回数が端開けに比べ多くなるため積み込む速さは遅くなるがそれ以上に選択肢が増えるので好まれる",
+ },
+ {"Partial well",
+ "partialwell 開け 空け ren combo レン れん コンボ",
+ "term",
+ "日本では使われない用語\n中でも端でもない左右から2,3,4列目を中心に任意の幅開ける積み方\n定義的には63積みやヤンキーrenなどがこれにあたる",
+ },
+ {"Side 1-wide(端開け1列、端空け1列)",
+ "s1w side1wide sidewelltetris 端 1 空け 開け テトリス",
+ "term",
+ "つまり端を開けてテトリス積みをすること\n最も伝統的な積み方\n最も簡単に積め、簡単に火力を送れる\nただし攻撃の幅が狭い(テトリスかドネイトTspinぐらい)ので上に行くほどあまり好まれない",
+ },
+ {"Side 2-wide(端開け2列、端空け2列)",
+ "s2w side2wide 端 2 空け 開け ren combo レン れん コンボ 初心者 下級者",
+ "term",
+ "端に2列幅を持たせるrenの積み方\n積みやすくrenによって簡単に火力が出せるので初心者におすすめ\n上に行くほどren数を稼ぎづらいことからあまり使われない",
+ },
+ {"Side 3-wide(端開け3列、端空け3列)",
+ "s3w side3wide 端 3 空け 開け ren combo レン れん コンボ",
+ "term",
+ "端に3列幅を持たせるrenの積み方\n2列開けよりもren数を稼ぎやすいが、2列開けよりもrenが途切れやすい",
+ },
+ {"Side 4-wide(端開け4列、端空け4列)",
+ "s4w side4wide 端 4 空け 開け ren combo レン れん コンボ",
+ "term",
+ "端に4列幅を持たせるrenの積み方\nren地形を作る時によく使われる\n積む幅が狭いので速く積み上げることができ、上手くいった場合にはren数を大きく稼ぐことができる\nただしrenを繋げるのは少し難しく、また地形が高くなるのが早いので油断していると簡単に刺さる",
+ },
+ {"Center 1-wide(中開け1列、中空け1列)",
+ "c1w center1wide centerwelltetris 中 1 空け 開け テトリス",
+ "term",
+ "つまり真ん中を開けてテトリス積みをすること\n攻撃の幅が広く、また簡単に攻撃を組み立てることができるため対戦で好まれる",
+ },
+ {"Center 2-wide(中開け2列、中空け2列)",
+ "c2w center2wide 中 2 空け 開け ren combo レン れん コンボ",
+ "term",
+ "真ん中に2列の幅を持たせるrenの積み方\nTミノが遠い時にTspinを作るとなりやすいが意図的に使われることは少ない",
+ },
+ {"Center 3-wide(中開け3列、中空け3列)",
+ "c3w center3wide 中 3 空け 開け ren combo レン れん コンボ",
+ "term",
+ "真ん中に3列の幅を持たせるrenの積み方\nSTSDやSTMB-ケイブ、TSTタワー等テンプレを組みやすい幅ではあるが精々10段ぐらいしか積まれない",
+ },
+ {"Center 4-wide(中開け4列、中空け4列)",
+ "c4w center4wide 中 4 空け 開け ren combo レン れん コンボ",
+ "term",
+ "真ん中に4列の幅を持たせるrenの積み方\nren数を稼ぎやすく、相手から20段以上の攻撃を受けないと出現ミノの位置にブロックが重ならないのでrenを狙う場合によく使われる\nrenの調整が強いゲームだと嫌われやすい",
+ },
+ {"ヤンキーren",
+ "partial ヤンキー 空け 開け ren combo レン れん コンボ",
+ "term",
+ "真ん中でも端でもない左右一方から2,3列目を中心に2~3列の幅を持たせるrenの積み方\n積み込み難易度の高さや最適化のしづらさからあまり使われることはない",
+ },
+ {"Residual(種)",
+ "res 種 residual c4w s4w 端 中 ren combo れん レン こんぼ コンボ",
+ "term",
+ "端開けや中開けをした時に幅を持たせた部分にあるブロックの数のこと\n特に4列renの時に使われる\nよく使われる種数は種3、または種6だが種3n(n:1以上の整数)なら理論上多くのren数を稼げる\nまた3nじゃなくても種2などは1ミノLine消去せずに置くことで種6になったりする\n\n種3の特徴:消し方の種類が少ないので簡単に習得でき、積みに使うブロック数が多くなるので速く積み上げられるが種6等よりも繋げられないパターンが多い\n種6の特徴:消し方の種類が多いので難しいですが安定してrenがつなげやすく、途中でTSSを加えられるためゲームによっては非常に強力な攻撃になります",
+ },
+ {"6–3 Stacking(63積み)",
+ "63stacking six-three sixthree 6 3 積み 初心者 下級者 40 スプリント",
+ "term",
+ "左側に幅6、右側に幅3で積む積み方\n最適化をある程度習得していれば横2入力が少なくなるのでKPPが少なくなり、積みに使うIミノの割合を下げることができるのでより効率よくテトリスを撃つことができます\n特にスプリント(40Line)で使われる積み方です\nしかし端開け(90積み、09積み)と比べ積める幅が狭いので少し練習が必要になります",
+ },
+ {"Freestyle(フリースタイル)",
+ "ziyou フリー",
+ "term",
+ "主に20TSDで使われる用語\nLST等のループできるテンプレを使わずに20TSDを完走することを指します\nLST等のテンプレを使わない分難易度は高いがプレイヤーのTspinスキルを見せることができます",
+ },
+ {"Topping out(トップアウト)",
+ "die death topout toppingout トップ 死 刺",
+ "term",
+ "モダンテトリスの死亡判定は3つあり、どれか1つを満たすとゲームオーバーとなる\n\n1.ブロックアウト:出現したミノが盤面上にあるブロックと重なる\n2:ロックアウト:致死Lineよりも上にブロックを置く\n3.トップアウト:せり上がりなどにより地形の高さが40を超える\n\nTechminoの場合はブロックアウトの判定しか行っておらず、ロックアウトとトップアウトはない",
+ },
+ {"Buffer zone",
+ "above super invisible disappear 猶予 盤面 上部",
+ "term",
+ "通常、盤面は縦20段だが実際には21段目以上が存在し、21段目から40段前後までをBuffer Zoneという(日本ではあまり使われない)\n通常は40段までで十分なのだがゲームによっては足りない場合がある\n詳しくは「Vanish zone」参照",
+ },
+ {"Vanish zone",
+ "disappear gone cut die 猶予 盤面 上部 死 バグ 無限",
+ "term",
+ "Buffer zoneよりも上の領域を指す\n通常はVanish zoneに到達できないが開発者の設計ミスによって到達できるゲームがいくつかある\nそしてこの領域に侵入すると一般的には強制終了になるがゲームによっては異なる振る舞いをする\n例えばぷよぷよテトリスではBuffer zoneが43段必要だが十分に確保されていないためLine消去時に最上段のブロックをコピーし続けるバグがあります(具体的な活用方法は地球儀ボタンのリンクをご覧ください)\nまたJstrisのVanish zoneは22段以上の領域となっており、21段よりも上のブロックは消滅します",
+ "https://youtu.be/z4WtWISkrdU",
+ },
+ {"Falling speed(落下速度)",
+ "fallingspeed gravity 落下 重力 20 g",
+ "term",
+ "1フレーム(通常は60fps)に何段自由落下するかを計る指標\n単位は「G」\nGは通常時には大きすぎる単位であり、例えばマラソンのLv.1は1/60Gの落下速度で1GはLv.13相当になります\nモダンテトリスの最高落下速度は20Gでこれは盤面の高さが20段なことから来ています\nしかし実際には20Gと表記されていても無限なことが多く、盤面の高さが21段以上でも出現した瞬間にミノが一番下に落ちるようになっている\n詳しくは「20G」の項目参照\nTechminoでの落下速度は1ブロック落ちるのに必要なフレーム数で表現されます\n例えば落下速度60の場合、1秒間に1マス下に落ちます(ゲームがデフォルト60fpsで動作しているため)",
+ },
+ {"20G",
+ "gravity instant 瞬間 落下 重力 20 g",
+ "term",
+ "モダンテトリスの最高落下速度\n20Gモードでは実際に20Gで動いているわけでなく、ミノが一番下に出現するようになっている\nこれによってミノが段差や壁を登れないことがある\n単位「G」は「Falling speed(落下速度)」の項目参照",
+ },
+ {"Lockdown Delay(設置時間)",
+ "lockdelay lockdowndelay lockdowntimer 設置 ロック 接着 ディレイ 遅延 時間",
+ "term",
+ "ミノが地面に接してから完全に設置するまでの時間のこと\nモダンテトリスでは設置時間が比較的緩く、さらに移動や回転によって設置時間をリセットできることが多い\nほとんどのゲームでは最大15回まで設置時間をリセットできるようになっているが、この回数も操作ミノがあった最低高度を更新することでリセットすることができる\nこれを使うことで時間稼ぎができる\nクラッシクテトリスでは設置時間が厳しいことが多々あります",
+ },
+ {"ARE(出現時間)",
+ "spawn appearance delay are 出現 スポーン 遅延 ディレイ 時間",
+ "term",
+ "ミノが設置してから次の操作ミノが出現するまでの時間のこと",
+ },
+ {"Line ARE(Line消去時間)",
+ "appearance delay line ライン are 消去 遅延 ディレイ 時間",
+ "term",
+ "Lineを消去するのにかかる時間",
+ },
+ {"Death ARE(死後硬直時間)",
+ "die delay dd 死 硬直 are 出現 スポーン 残機 復活 遅延 ディレイ 時間",
+ "term",
+ "残機制などが有効になっている時に死亡してから復活するまでの時間\nTechminoの場合はブロックアウトで死亡した時、次のミノの出現時間に死後硬直時間が加算されます\nまたIHSやIRSなどを使うことによってブロックアウトを回避できる場合があります\n\nこのシステムはNOT_A_ROBOT氏によるアイデアです",
+ },
+ {"Finesse(最適化)",
+ "finesse 最適化 効率 操作 初心者 下級者 上達 練習",
+ "term",
+ "ミスなく最低限の操作で目的の場所にミノを移動させる技術\n速さが上がり、ミスも減ります\nJstrisの「restart on finesse error」やTechminoの最適化失敗音を有効にすることで練習できます\n厳密にはTechminoの最適化判定は「理論上の最小入力数」ではなく、「ソフトドロップを必要としない位置の時、一定回数以下の入力かどうか」で判定しています\nそのためソフトドロップが必要なspinなどの時は最適化の判定を行っていません\nまたホールドと操作ミノが同じ時にホールドをしたり、ホールドする前のミノを無駄に動かしても最適化が失敗しているとは判定されません\nまたTechminoの最適化率は一定回数以下の場合100%、一定回数より入力が1多い場合50%、入力が2多い場合25%、入力が3以上多い場合0%とされています\nまた0Gと20Gで最適化の算出方法を変えていないため落下速度が速い時は不正確なことに注意してください",
+ },
+ {"‘Doing Research’",
+ "scientificresearch 研究 上達 練習 科研",
+ "term",
+ "「科研」という中国のテトリスコミュニティで使われる言葉\n落下速度の低い1人用モードで技術やテンプレを研究・練習することを言います(日本でもこの練習はありますがその行為のみを指す単語は存在しません)",
+ },
+ {"Keymapping(キー配置)",
+ "feel キー key 操作",
+ "term",
+ "ここではキーボードでのキーコンフィグについて言及します\nキーコンフィグの原則\n1.同時に押される可能性がある複数のキーを1本の指に割り当てないでください\n基本的には回転3種類(右、左、180°)と左右移動(右、左)はそれぞれ同時に押されることはありません\n2.既に他のゲームで小指を鍛えていない限り小指を使わないキー配置にしてください\n基本的には人差し指と中指を中心に組み立てるといいでしょう\n3.人によって最適なキー配置は違うので使っている人を理由に変える必要はないです\n\n最低限の原則を守っていればキー配置による優劣は非常に薄いと考えられます",
+ },
+ {"Handling(ハンドリング)",
+ "feel handling チューニング das arr ハンドリング 操作",
+ "term",
+ "操作に悪影響を与える主な要因を以下に挙げます\n1.デバイスの設定や状態による遅延\nゲームを再起動したりデバイスを変えたりすることで改善されます\n2.ゲームが重い\n機器の性能不足やプログラムコードが不安定、設計の不具合が原因です\nエフェクト設定などを軽くすることで緩和される場合があります\n3.意図的に操作性を悪くされている\n適応するしかありません\n4.DASやARR等のチューニング設定が合っていない\n適当な値に変更しましょう\n5.姿勢が悪い\n腰痛めますよ?\n6.姿勢やキー配置、チューニングを変えて慣れていない\n慣れるの諦めるか根気強く頑張りましょう\n7.疲労\n早急に休んでください",
+ },
+ {"DAS (横溜め)(簡易な説明)",
+ "das arr delayedautoshift autorepeatrate ダス だす ため 溜め 横",
+ "term",
+ "キーボードの「O」を長押しすると長いOの文字列ができます\nこのときOがどのように出現したかというと「O->(長い溜め時間)->O->(僅かな溜め時間)->O->(僅かな溜め時間)->...」のようになります\nこの長い溜め時間のことをDAS(delay auto shift、別名:横溜め)、僅かな溜め時間のことをARR(auto repeat rate)と呼びます",
+ },
+ {"DAS & ARR",
+ "das arr delayedautoshift autorepeatrate ダス だす ため 溜め 横",
+ "term",
+ "Delay Auto Shiftの略、日本だと「横溜め」とも言われる\n左右入力をした時に横に移動する仕組みのこと\nまた長時間左右入力した時に最初の横に1つズレる移動から次の移動までの時間のこと\n\nARRはAuto Repeat Rateの略\n左右入力を長時間すると連続して横に動き始めるがその時の移動周期のこと\nゲームによってはDASやARRをフレームで計算しています\n60fpsで動作するゲームの場合、f(フレーム)×16.7でms(ミリ秒)に換算できます",
+ },
+ {"DAS tuning(DASチューニング)",
+ "das tuning チューニング 操作",
+ "term",
+ "より速くプレイしたい人はDASを4~6f(67~100ms)、ARRを0f(0ms)にすることをおすすめします(ARR:0というのはDASより長く入力を続けた瞬間、端にミノが移動する設定です)\n理想の操作方法としては単時間入力と長時間入力を確実にコントロールできるようにし、ARRを0にDASやそれ以外の設定は可能な限り低くすることです",
+ },
+ {"DAS cut(DASカット)",
+ "dascut dcd カット",
+ "term",
+ "*Techmino用語*通常、ミノが出現する前にDAS時間以上入力をしているとミノが出現した瞬間に動き出します\nDASカットはこのような現象を減らすためにDAS時間以上入力していても出現時にDASカット分減算する機能です\n他のゲームにも似たようなものがありますが恐らく異なるでしょう",
+ },
+ {"Auto-lock cut(自動設置カット)",
+ "autolockcut mdcut 自動 カット",
+ "term",
+ "ミノが自由落下により設置された時にハードドロップを入力してしまうことで暴発するという事故を防ぐ機能です\n自由落下によって設置した場合、自動設置カット時間の間ハードドロップが無効化されます\n他のゲームにも似たようなものがありますが恐らく異なるでしょう",
+ },
+ {"SDF",
+ "softdropfactor ソフトドロップ",
+ "term",
+ "Soft Drop Factor\n\nソフトドロップの速さを自由落下の速さの倍数で表現する方法\nガイドラインテトリスではSDF20、つまりソフトドロップの速さは自由落下の速さの20倍と定められている\nなおTechminoではSDFを使用してません",
+ },
+ {"形と名前",
+ "mino ミノ みの",
+ "term",
+ "Techminoで使われる全ブロックとその名前のリストです:\nTetrominos:\nZ: "..CHAR.mino.Z..", S: "..CHAR.mino.S..", J: "..CHAR.mino.J..", L: "..CHAR.mino.L..", T: "..CHAR.mino.T..", O: "..CHAR.mino.O..", I: "..CHAR.mino.I..";\n\nPentominos:\nZ5: "..CHAR.mino.Z5..", S5: "..CHAR.mino.S5..", P: "..CHAR.mino.P..", Q: "..CHAR.mino.Q..", F: "..CHAR.mino.F..", E: "..CHAR.mino.E..", T5: "..CHAR.mino.T5..", U: "..CHAR.mino.U..", V: "..CHAR.mino.V..", W: "..CHAR.mino.W..", X: "..CHAR.mino.X..", J5: "..CHAR.mino.J5..", L5: "..CHAR.mino.L5..", R: "..CHAR.mino.R..", Y: "..CHAR.mino.Y..", N: "..CHAR.mino.N..", H: "..CHAR.mino.H..", I5: "..CHAR.mino.I5..";\n\nTriminos, Domino, and Mino:\nI3: "..CHAR.mino.I3..", C: "..CHAR.mino.C..", I2: "..CHAR.mino.I2..", O1: "..CHAR.mino.O1..".",
+ },
+ {"7種1巡",
+ "bag 7bag randomgenerator 7 種 1 巡 生成 出現 法 則",
+ "term",
+ "別名:7-bag、正式名称:Random Generator\n公式テトリスがミノを生成するのに使うアルゴリズムのこと\nテトリスには通常7種類のミノがあるが全種類が同じ数出現することが保証されている\n例:ZSJLOIT OJSIZLT TOILSZJ...",
+ },
+ {"His generator",
+ "history hisgenerator tgm 生成 出現 法 則",
+ "term",
+ "History generator\nTGMに使われるミノを生成するときの法則\n毎回ランダムに7種類の中から選択されるが、もし選択されたものが数個前と同じな場合はまたランダムに7種類の中から選択され最終的に別のミノが選択されるか再選択回数が限界に達して同じミノが選択される\n例えば「his 4 roll 6」と設定されているジェネレータの場合、選択したミノが前に使った4つのミノの中にある場合、最大6回まで違うミノが出るまで再選択する\n他に「his 4 roll 6 pool 35」のようにさらにランダム性を減らしたものもある\nTechminoではrollの値はネクストの長さの半分、小数点以下切り上げになっています",
+ },
+ {"HisPool generator",
+ "hisPool history pool tgm 生成 出現 法 則",
+ "term",
+ "History Pool generator\nHis generatorを基に「Pool」という機能を導入した生成法則\nミノを選択する場合にPoolという袋の中から選択されている\nPoolの中にあるミノは選択された回数に基づいて選択される確率が変動しており、出現頻度が低いものほど確率が高くなっている\nこの仕組みによってランダム性が大きく減らされ、同じようなミノばかり来るということはなくなった",
+ },
+ {"bagES generator",
+ "bages easy start 生成 出現 法 則",
+ "term",
+ "*Techmino用語*\nBag Easy-Start\n7種1巡を更に改良した生成法則\n最初に置きづらいミノ(S/Z/O/S5/Z5/F/E/W/X/N/H)が選択されません",
+ },
+ {"Reverb generator",
+ "reverb 生成 出現 法 則",
+ "term",
+ "*Techmino用語*\n7種1巡から派生した生成法則\n7種1巡を基にしてそれぞれのミノが数回連続して出ようとします\n特定のミノが頻繫に連続して出ようとすると連続して出る確率が下がり、逆にあまり連続して出ないミノは連続して出るように確率が上げられます",
+ },
+ {"Hypertapping(ハイパータッピング)",
+ "hypertapping ハイパー コントローラー 操作",
+ "term",
+ "指をコントローラー上で振動させることでARRよりも速い周期で横移動させる技術\nDASが遅いクラッシクテトリスでよく使われる\nモダンテトリスのほとんどはDASが十分に短いためこの技術は不要です",
+ },
+ {"Rolling(ローリング)",
+ "rolling ローリング ピアノ コントローラー 操作",
+ "term",
+ "DASやARRが遅いクラッシクテトリスの高重力(1G以上)下で安定してプレイするための操作方法\n片方の手とコントローラーを固定し、もう片方の手でコントローラーの背面を叩くこと高速入力を実現している\nこの操作方法はハイパータッピングよりも速く、さらに少ない力で行うことができます\nこの操作方法はCheez-fishが最初に発見し、理論上1fに1回操作できると言われています",
+ },
+ {"Passthrough(貫通)",
+ "pingthrough ピンスルー 貫通 すり抜け",
+ "term",
+ "双方の火力が互いに相殺されず相手の火力ゲージに火力が到達すること\nまたインターネットのラグにより貫通が発生することを「pingthrough」と言う",
+ },
+ {"Tetris OL attack",
+ "top tetrisonlineattack テトオン toj toz オンライン テトリス 火力 攻撃 計算",
+ "term",
+ "テトリスオンラインの火力計算\nSingle,double,triple,tetrisの火力はそれぞれ0,1,2,4となっており、TSS,TSD,TSTの場合は2,4,6となる\nまたTspin mini判定になると火力が半分になります\nrenの火力は1ren目から+0,+1,+1,+2,+2,+3,+3,+4,+4,+5,+5,+5...と上限5まで上昇し、元の火力に加算されます\nBtBの火力は+1、ただしTSTの場合は+2で元の火力に加算されます\nパーフェクトクリアの火力は+6で元の火力に加算されます\nただしパーフェクトクリア分の火力は相殺が当たらず、直接相手に送られます",
+ },
+ {"Techmino attack",
+ "techminoattack Techmino てくみの テクミノ てっくみの テックミノ 火力 攻撃 計算",
+ "term",
+ "少し複雑なためメイン画面の右下にある「?」を参照",
+ },
+ {"C2 Generator",
+ "cultris2generator cultrisiigenerator c2generator カルトリス 生成 出現 法 則",
+ "term",
+ "Cultris IIで使われる生成法則\nミノに重みを付けて計算しています\n初期は全ミノの重みは0に設定されています\nそしてミノを選択する時、全てのミノそれぞれに次のような処理を施します:\n現在の重みを半分にし、そこに0~1の間で生成された乱数を加算する((重み/2)+(0~1の乱数))\n\nそして算出された値を新たな重みとし、最も重みが大きいミノを選択します\nまた選択されたミノの重みは3.5で割られ、それを新たな重みとします\nつまり選択されたミノの新しい重みは((元の重み/2)+(0~1の乱数))/3.5、選択されなかったミノの新しい重みは(元の重み/2)+(0~1の乱数)となります",
+ },
+ {"Stacking(積み)",
+ "stacking 積み つみ 置く",
+ "term",
+ "ミノを置いて行くこと\n必須技術の1つ",
+ },
+ {"Rotation buttons(左右回転)",
+ "doublerotation 回転 左 右 2",
+ "term",
+ "左右回転両方を使うことで3回転操作がなくなり、入力数が減少します\n最適化は左右回転のみを使うことを前提に設計されています",
+ },
+ {"Rotation buttons (左右180°回転)",
+ "triplerotation 回転 左 右 180 3",
+ "term",
+ "左右,180°回転の全てを使えばどんな回転方向でも1回の入力で済みます\nしかし全てのゲームに180°回転があるわけでなく、この技術を習得しても左右回転を習得した時ほどの上達はないでしょう\n最適化という点では速さを極端に求めない限り必要ありません(ただし180°の回転入れは覚える必要があります)",
+ },
+ {"ザンギ",
+ "操作 ザンギ ざんぎ zangi",
+ "term",
+ "左右移動->ソニックドロップ->もう一方の左右移動と行われる操作のこと\n例えば左ザンギの場合、左端へ一瞬で移動->ソニックドロップ->右へ壁に衝突するまで移動 となる",
+ },
+ {"Drought(ドラウト)",
+ "drought ドラウト 干ばつ 連続",
+ "term",
+ "欲しいミノが全く来ない状況のこと\nクラッシクテトリスでよく起こることで地形やプレイが乱れる原因になります\nモダンテトリスではランダムではなく、ある程度生成されるミノが制御されているのでほとんど起こらず、最大でも13ミノ引けば欲しいミノが1つは出現します",
+ },
+ {"Bone block(骨ブロック)",
+ "bone tgm 骨 ボーン ブロック スキン",
+ "term",
+ "初期のテトリスで使われているミノスキン\n昔のコンピュータはコマンドラインインターフェイス(WindowsのcmdやMacのterminalなど)を主に使っていたのでテトリスのミノは「[]」の集合で表現されていました\nこれが骨のように見えるので骨ブロックと呼ばれています\n\nTechminoでは骨ブロックを「全てのミノが使用できるミノスキン」と定義されています\nミノスキンが異なる場合、骨ブロックのスタイルも異なる可能性があります",
+ },
+ {"Semi-invisible(セミインビジブル)",
+ "half invisible semi セミ 半 インビジブル 透明",
+ "term",
+ "時間が経過すると設置されたミノが透明になるルール\nこの透明になるまでの時間は明確ではないので「数秒後に消える」と表現しても問題ない",
+ },
+ {"Invisible(インビジブル)",
+ "invisible 透明 インビジブル",
+ "term",
+ "瞬時に設置したミノが透明になるルール\n消えるアニメーションがあるインビジブルルールのことを指すことがあるが、Techminoではそのようなルールは簡単になりすぎると判断し、アニメーションなしのインビジブルルールを「Sudden Invisible」と読んでいます",
+ },
+ {"MPH mode",
+ "mph",
+ "term",
+ "生成法則なし(ランダム生成)、ネクストなし、ホールドなし\nかなりの反応速度が要求される",
+ },
+ {"Input delay(入力遅延)",
+ "input delay 入力 遅延 硬直 ディレイ 時間",
+ "term",
+ "どんなデバイスでも入力してからゲームに反映されるまでに遅延があります(通常、数ms~数十ms)\n入力遅延が大きすぎると操作に違和感を覚えます\nこの遅延は使用するハードウェアやソフトウェアの性能が主な原因であり、機器のパフォーマンスモードを有効(または省電力モードを無効)にしたり、モニターのゲーミングモードを有効にすると軽減されるかもしれません",
+ },
+ {"Secret Grade(裏GM)",
+ "larger than 裏 gm ジグザグ",
+ "term",
+ "TGMシリーズに登場するイースターエッグモード\n19段使って「>」の形に穴を作ることでクリアとなる\n詳しい情報は、地球儀ボタンをクリックしてHarddrop wikiにあります!",
+ "https://harddrop.com/wiki?search=Secret_Grade_Techniques",
+ },
+ {"Cold Clear",
+ "cc coldclear ai bot コールド",
+ "term",
+ "テトリスのbot\n元々はMinus Kelvin氏がぷよぷよテトリス用に開発したbotだがTechminoではAllspinとTRSに対応できるよう改良されている",
+ },
+ {"ZZZbot",
+ "ai bot zzztoj misamino",
+ "term",
+ "テトリスのbot\n中国のテトリスプレイヤー、奏之章 (Zòu Zhī Zhāng)氏が開発し、多くのゲームで動作する",
+ },
+ {"Zetris",
+ "ai bot zetris misamino",
+ "term",
+ "テトリスのbot\nmat氏がぷよぷよテトリス用に開発したbot\nmisaminoを元に開発された\n凝視はしてないが受けた後に一定段以下になる攻撃は外すような仕様になっている",
+ },
+ {"ほいこ",
+ "ai bot hoiko howyiko ほゐこ",
+ "term",
+ "テトリスのbot\nうかん氏がぷよぷよテトリス用に開発したbot\n相手から送られる火力を見ており、直列になる確率と待ち時間から相殺外しを判断している",
+ },
+ {"wataame",
+ "ai bot わたあめ watame",
+ "term",
+ "テトリスのbot\n雨安氏がぷよぷよテトリス用に開発したbot\n多様なモードを搭載している",
+ },
+ -- # Setups
+ {"Openers(開幕テンプレ)",
+ "setup openers 開幕 テンプレ",
+ "setup",
+ "ゲーム開始時に組むテンプレのこと\n中盤でも作れるものがあるが完全に同じになるとは限らない\n強い開幕テンプレは基本以下の点を満たしている\n1.強い攻撃を持ち、積みに使っているTの割合が低い\n2.必要なソフトドロップが少ない\n3.多くのミノ順で組める\n4.中盤へ移行しやすく、分岐が少ない\nほとんどの開幕テンプレは通常7種1巡を利用して作られているために安定して組める",
+ },
+ {"DT Cannon(DT砲)",
+ "dtcannon doubletriplecannon dt 砲",
+ "setup",
+ "Double-Triple 砲\n詳しい情報は、地球儀ボタンをクリックしてHarddrop wikiにあります!",
+ "https://harddrop.com/wiki?search=dt",
+ },
+ {"DTパフェ",
+ "dtcannon doubletriplecannon パフェ パーフェクト dt 砲",
+ "setup",
+ "DT砲の後にパフェを取る派生のこと\n詳しい情報は、地球儀ボタンをクリックしてHarddrop wikiにあります!",
+ "https://harddrop.com/wiki?search=double_triple_cannon_opener",
+ },
+ {"BT砲",
+ "btcannon betacannon 砲",
+ "setup",
+ "β砲, Beta砲\n詳しい情報は、地球儀ボタンをクリックしてHarddrop wikiにあります!",
+ "https://harddrop.com/wiki?search=bt_cannon",
+ },
+ {"BTパフェ",
+ "btcannon betacannon ループ 5 パフェ",
+ "setup",
+ "BT砲の後にパフェを取る派生のこと\n詳しい情報は、地球儀ボタンをクリックしてHarddrop wikiにあります!",
+ "https://harddrop.com/wiki?search=bt_cannon",
+ },
+ {"TKI 3 Perfect Clear(DDパフェ)",
+ "ddpc tki3perfectclear d パフェ tsd tki",
+ "setup",
+ "開幕TSDからもう一度TSDを撃ち、パフェを取るテンプレ\n詳しい情報は、地球儀ボタンをクリックしてHarddrop wikiにあります!",
+ "https://harddrop.com/wiki?search=TKI_3_Perfect_Clear",
+ },
+ {"MKO積み",
+ "mko むこうみず",
+ "setup",
+ "派生を含めれば大体のことはできる開幕テンプレ\nHarddropのwikiを載せるがmko全体の内、1割も情報が書かれていない\n使い方がかなり重要な開幕テンプレなので使う場合は積極的に情報収集することをおすすめする",
+ "https://harddrop.com/wiki?search=MKO_Stacking",
+ },
+ {"QT砲",
+ "qtcannon 砲",
+ "setup",
+ "DT砲より安定してTSDとTSTを撃てるように作られた開幕テンプレ\nただし下穴が端にあると二巡目が組めない\nTD派生がしやすい",
+ "https://tetrisopener.wicurio.com/index.php?QT%E7%A0%B2",
+ },
+ {"Mini-Triple(MT)",
+ "mt minitriple ミニ トリプル ts",
+ "setup",
+ "TSMからTSTを撃つ形",
+ "https://knewjade.github.io/fumen-for-mobile/#?d=v115@tgB8IeA8DeD8AeH8BeH8BeG8CeE8JeAgWJAteEfEXU?b9ARAAAAvhG1bfdmfdrf1vBAAAdrBAAAtgB8IeA8DeD8AeG?8CeG8BeAAAeF8AeB8AeD8JeAAPJAteEfEXUb9ASAAAAvhF1?bfdmf1qfNqBAAAdrB",
+ },
+ {"Trinity(トリニティ)",
+ "trinity トリニティ tsd",
+ "setup",
+ "TSD3回かTSM->TST->TSDを撃つテンプレ",
+ "https://harddrop.com/wiki?search=trinity",
+ },
+ {"Wolfmoon Cannon",
+ "wolfmooncannon 砲",
+ "setup",
+ "形が特殊な開幕テンプレ\n詳しい情報は、地球儀ボタンをクリックしてHarddrop wikiにあります!",
+ "https://harddrop.com/wiki?search=wolfmoon_cannon",
+ },
+ {"Sewer(TZT砲)",
+ "sewer",
+ "setup",
+ "形が特殊な開幕テンプレ\n詳しい情報は、地球儀ボタンをクリックしてHarddrop wikiにあります!",
+ "https://harddrop.com/wiki?search=sewer",
+ },
+ {"TKI",
+ "tki-3 tki3 tsd c td",
+ "setup",
+ "開幕TSD、またはTDの形をしたTKIという開幕テンプレを指す(日本では後者の方が多い)\nここでは後者のリンクを置いておく\n詳しい情報は、地球儀ボタンをクリックしてHarddrop wikiにあります!",
+ "https://harddrop.com/wiki?search=C-Spin",
+ },
+ {"God Spin",
+ "godspin 神 ゴッド",
+ "setup",
+ "派手な開幕テンプレ[しかし実際に使うのは難しい]\nWindkey氏考案\n詳しい情報は、地球儀ボタンをクリックしてHarddrop wikiにあります!",
+ "https://harddrop.com/wiki?search=godspin",
+ },
+ {"AlbatrossSP(アルバトロスSP)",
+ "albatross アルバトロス アルバ sp",
+ "setup",
+ "TSD->TST->TSD->パフェを撃つ開幕テンプレ\nほとんどのTミノをTspinに使う、派手で素早いテンプレです\n詳しい情報は、地球儀ボタンをクリックしてHarddrop wikiにあります!",
+ "https://harddrop.com/wiki?search=Albatross_Special",
+ },
+ {"Pelican(無名砲)",
+ "うーみん ウーミン 無名 むめい",
+ "setup",
+ "日本では無名砲(3文字で「うーみん」と読む)と呼ばれる\nアルバトロスSPに似た流れを持つ開幕テンプレ\n詳しい情報は、地球儀ボタンをクリックしてHarddrop wikiにあります!",
+ "https://harddrop.com/wiki?search=Pelican",
+ },
+ {"Perfect Clear Opener(パフェ積み)",
+ "7piecepuzzle パフェ 積み",
+ "setup",
+ "7ミノ置いた後、パフェを取れる確率が最も高い形\n通常はパフェ率61.2%だがIミノを置かず残り4ミノからパフェを見抜くことで84.6%までパフェ率が上昇する\nTechminoのパフェトレーニングでジグザグの形が出たらこのテンプレの形です\n詳しい情報は、地球儀ボタンをクリックしてHarddrop wikiにあります!",
+ "https://harddrop.com/wiki?search=Perfect_Clear_Opener",
+ },
+ {"Grace System(グレースシステム)",
+ "liuqiaoban gracesystem 1stpc グレース パフェ",
+ "setup",
+ "6ミノ置いた後、パフェが取れる確率が最も高い形\nパフェ率88.57%\nパフェチャレンジの4×4の形が出たらこのテンプレの形です",
+ "https://four.lol/perfect-clears/grace-system",
+ },
+ {"DPC",
+ "DPC 3 1",
+ "setup",
+ "2連パフェや8段パフェ(TD系テンプレのパフェ、SDパフェ等)を取った後に余った1ミノとその後の2巡を使ってDパフェ、もしくはDDパフェを取るテンプレ\nまたは開幕TSDのパフェ派生のこと\n\n前者でDパフェを取る場合、ほぼ100%パフェが取れる",
+ "https://tetristemplate.info/dpc/",
+ },
+ {"Gamushiro Stacking(ガムシロ積み)",
+ "gamushiro ガムシロ td",
+ "setup",
+ "TDパフェ系統のテンプレで最初に作られた開幕TDテンプレ\n詳しい情報は、地球儀ボタンをクリックしてHarddrop wikiにあります!",
+ "https://harddrop.com/wiki?search=Gamushiro_Stacking",
+ },
+ -- # Pattern
+ {"Mid-game Setups(中盤テンプレ)",
+ "midgamesetups 中盤",
+ "pattern",
+ "中盤で使われるテンプレのこと\n中には開幕テンプレとして使用されるものがある",
+ },
+ {"TD",
+ "cspin tki td",
+ "pattern",
+ "TST->TSDと撃てる形\n詳しい情報は、地球儀ボタンをクリックしてHarddrop wikiにあります!",
+ "https://harddrop.com/wiki?search=Triple Double_Attack_Setups",
+ },
+ {"STSD",
+ "stsd",
+ "pattern",
+ "Super T-Spin Double\n2回TSDを撃てる形\nしかし盤面の底に作った場合、相手からの下穴により1/10の確率で最初のTSDが撃てなくなる\nこの確率は100%と言う人もいる\n詳しい情報は、地球儀ボタンをクリックしてHarddrop wikiにあります!",
+ "https://harddrop.com/wiki?search=stsd",
+ },
+ {"STMB Cave(STMBケイブ)",
+ "stmb ケイブ ドネイト",
+ "pattern",
+ "幅3がある時にS(Z)を壁に引っ掛けてTSDドネイトを作るテンプレ\nSTMBはテトリスDS時代のプレイヤーの名前\n詳しい情報は、地球儀ボタンをクリックしてHarddrop wikiにあります!",
+ "https://harddrop.com/wiki?search=stmb_cave",
+ },
+ {"Fractal(ダブルダガー)",
+ "shuangrenjian fractal spider ダブル 2 ダガー フラクタル ダブダ",
+ "pattern",
+ "TSDの上にTSDが乗った形\nS(Z)が引っ掛かってTSDが2つできてる場合はSTMBケイブとなり、引っ掛けておらず1つの屋根で2回TSDを撃てる場合はダブルダガーとなる\n詳しい情報は、地球儀ボタンをクリックしてHarddrop wikiにあります!",
+ "https://harddrop.com/wiki?search=Fractal",
+ },
+ {"LST stacking(LST積み)",
+ "lst 積み",
+ "pattern",
+ "半永久的にTSDとテトリスをし続ける積み方",
+ "https://four.lol/stacking/lst",
+ },
+ {"Hamburger(ハンバーガー)",
+ "hamburger ハンバーグ ハンバーガー",
+ "pattern",
+ "S(Z)でTSSをするドネイトテンプレ\n半永久的にTSSとテトリスができる\n当初はSを使った場合をハンバーガー、Zを使った場合をハンバーグと言っていたが廃れた\n詳しい情報は、地球儀ボタンをクリックしてHarddrop wikiにあります!",
+ "https://harddrop.com/wiki?search=hamburger",
+ },
+ {"Imperial Cross(インペリアルクロス)",
+ "imperialcross インペリ",
+ "pattern",
+ "十字上の穴に屋根を付けて2回TSDをする形\n詳しい情報は、地球儀ボタンをクリックしてHarddrop wikiにあります!",
+ "https://harddrop.com/wiki?search=imperial_cross",
+ },
+ {"Kaidan(階段ドネイト)",
+ "jieti kaidan stairs 階段",
+ "pattern",
+ "段々になっている地形にS(Z)を置くことでTSD地形を作るドネイトテンプレ\n詳しい情報は、地球儀ボタンをクリックしてHarddrop wikiにあります!",
+ "https://harddrop.com/wiki?search=kaidan",
+ },
+ {"Shachiku Train(社畜トレイン)",
+ "shachikutrain shechu 社畜 トレイン",
+ "pattern",
+ "2回TSDを撃つテンプレ\nテンプレ名は制作者が満員電車で思い付いたことに由来する\n詳しい情報は、地球儀ボタンをクリックしてHarddrop wikiにあります!",
+ "https://harddrop.com/wiki?search=Shachiku_Train",
+ },
+ {"Cut Copy",
+ "qianniao cutcopy 千鳥 カット",
+ "pattern",
+ "Tspin地形がある時にさらにTspinできるような地形を作ること\n千鳥格子はこの技術を使った中盤テンプレ\n詳しい情報は、地球儀ボタンをクリックしてHarddrop wikiにあります!",
+ "https://harddrop.com/wiki?search=Cut_copy",
+ },
+ {"King Crimson(キングクリムゾン)",
+ "kingcrimson キンクリ キング jojo ジョジョ",
+ "pattern",
+ "STSDの上にTSTを足したテンプレ\n詳しい情報は、地球儀ボタンをクリックしてHarddrop wikiにあります!",
+ "https://harddrop.com/wiki?search=King_Crimson",
+ },
+ {"連パフェ(1/3)",
+ "pcloop パフェ ループ 連",
+ "pattern",
+ "テトリス堂にて1~5回目と7回目のパフェについて詳しく知れます\n7回目のパフェがキレイに終わると丁度70ミノ、つまり10巡終わったことになりゲーム開始時と同じ状態になります",
+ "https://shiwehi.com/tetris/template/consecutivepc.php",
+ },
+ {"連パフェ(2/3)",
+ "pcloop パフェ ループ 連",
+ "pattern",
+ "four.lolに1~7回目のパフェについて詳しく知れます",
+ "https://four.lol/perfect-clears/5th",
+ },
+ {"連パフェ(3/3)",
+ "pcloop パフェ ループ 連",
+ "pattern",
+ "ナイテン(NitenTeria)によって作成された連パフェについての情報がまとめられているドキュメント\nただし情報量の多さ等から自分である程度吟味する必要がある",
+ "https://docs.qq.com/sheet/DRmxvWmt3SWxwS2tV",
+ },
+ -- # Savedata managing
+ {"Console(コンソール)",
+ "cmd commamd minglinghang kongzhitai terminal コンソール ターミナル コンソール console",
+ "command",
+ "Techminoにはデバッグや高度な機能を実行するためのコンソールがあります\nコンソールにはメイン画面のTechminoのロゴを連打するかメイン画面で「C」を連打することで移動できます\nコンソールの使用は自己責任です",
+ },
+ {"Reset setting",
+ "reset setting リセット 設定",
+ "command",
+ "コンソールに「rm conf/setting」と入力し、Enterもしくはreturnを押す\nそしてTechminoを再起動すると有効になります\n設定をリセットします",
+ },
+ {"Reset statistics",
+ "reset statistic data リセット 統計 データ",
+ "command",
+ "コンソールに「rm conf/data」と入力し、Enterもしくはreturnを押す\nそしてTechminoを再起動すると有効になります\n統計をリセットします",
+ },
+ {"Reset unlock",
+ "reset unlock リセット 未開封",
+ "command",
+ "コンソールに「rm conf/unlock」と入力し、Enterもしくはreturnを押す\nそしてTechminoを再起動すると有効になります\n1人用モードのランクをリセットします",
+ },
+ {"Reset records",
+ "reset record リセット レコード 記録",
+ "command",
+ "コンソールに「rm -s record」と入力し、Enterもしくはreturnを押す\nそしてTechminoを再起動すると有効になります\n記録をリセットします",
+ },
+ {"Reset key",
+ "reset virtualkey リセット キー 仮想",
+ "command",
+ "コンソールに「rm conf/[keyFile]」(キーボード:key、仮想キーボード:virtualkey、仮想キーボード設定を保存:vkSave1(2))と入力し、Enterもしくはreturnを押す\nそしてキーボードと仮想キーボードの場合は再起動すると有効になります\n仮想キーボード設定保存の場合はEnterもしくはreturnを押した時に1つのファイルを出力します",
+ },
+ {"Delete replays",
+ "delete recording 削除 消去 リセット デリート リプレイ",
+ "command",
+ "コンソールに「rm -s replay」と入力し、Enterもしくはreturnを押すと即座に実行されます\nリプレイデータを消去します",
+ },
+ {"Delete cache",
+ "delete cache 消去 削除 リセット デリート キャッシュ",
+ "command",
+ "コンソールに「rm -s cache」と入力し、Enterもしくはreturnを押すと即座に実行されます\nキャッシュを消去します",
+ },
+ -- # English
+ {"SFX",
+ "soundeffects 効果音",
+ "english",
+ "日本語で「効果音」や「SE」と言われるもの",
+ },
+ {"BGM",
+ "backgroundmusic 音楽",
+ "english",
+ "ゲーム中に流れている音楽のこと",
+ },
+ {"TAS",
+ "tas",
+ "english",
+ "「Tool-Assisted Speedrun (Superplay)」の略\nゲームのルールを破ることなく特殊なツールを用いてプレイすること\n途中セーブやゲーム内時間の進みを弄る等して最高得点を出したりユニークな目標を達成している\n簡単なTASはTechminoに内蔵されている",
+ },
+ {"AFK",
+ "afk",
+ "english",
+ "Away From Keyboardの略\n画面前から離れる時だけじゃなく、休憩するときにも使われる\n適度に休憩することで身体と頭が休み、より質の高いプレイができる",
+ },
+ {"BRB",
+ "brb",
+ "english",
+ "Be right backの略\n一旦離れるけどすぐに戻るときに使われる\n人によっては試合中にbrbというが結局セットが終わるまで戻らない人もいる",
+ },
+ {"sweep",
+ "sweep ストレート",
+ "english",
+ "日本語で言うストレートのこと\n例えば、7先の試合で1本も取られずに勝利した場合、相手をsweepしたと言う",
+ },
+ {"Timing",
+ "timing shiji fanji タイミング",
+ "term",
+ "主に攻撃をするタイミングのこと\n攻撃をするタイミングを考えることで相手からの攻撃を相殺したり、逆に相殺を外して自分の攻撃を相手に送れたりできます\n要は相殺管理の1つです",
+ },
+}
diff --git a/parts/language/dict_vi.lua b/parts/language/dict_vi.lua
new file mode 100644
index 000000000..2bef8a92e
--- /dev/null
+++ b/parts/language/dict_vi.lua
@@ -0,0 +1,1914 @@
+local tetromino = " tetromino tetramino tetrimino"
+
+return {
+ {
+ "=[NHÓM 01]=",
+ "nhom01 giới thiệu bản dịch",
+ "name",
+ [[
+NHÓM 01: VỀ ZICTIONARY & BẢN DỊCH
+
+Zictionary là một từ điển về game xếp gạch cực kì hữu ích. Bạn có thể sử dụng để tra những từ hay thuật ngữ mà bạn không hiểu.
+Bạn có thể xem phần Mục lục bằng cách gõ trên thanh tìm kiếm "mucluc" hay "nhom2"; hoặc cũng có thể xem Nhóm 2
+
+Bản dịch này là bản dịch tiếng Việt của Squishy từ bản dịch tiếng Anh của User670 và C₂₉H₂₅N₃O₅
+Bản dịch có thể không thể hiện 100% nội dung của Zictionary tiếng Trung (bản gốc)
+
+Đây là bản phát hành đầu, có thể sẽ có một số chỗ bị sai sót hoặc đọc bị cấn miệng. Nếu bạn muốn đóng góp, có thể vào trang dự án Techmino ở trên GitHub để đóng góp bản dịch.
+Có câu hỏi? Liên hệ mình qua server Techmino trên Discord. Mình hiện tại đang chờ feedback để hoàn chỉnh bản dịch cho tốt hơn.
+ ]],
+ "https://github.com/26F-Studio/Techmino/blob/main/parts/language/dict_vi.lua",
+ },
+ {
+ "Mục lục",
+ "nhom01 index mucluc",
+ "help",
+ [[
+01. Về Zictionary & Bản dịch game & Mục lục ← bạn đang xem mục này
+02. Dự án Techmino: Trang web chính thức, Dự án trên GitHub, Discord
+03. Ủng hộ cho tác giả của Techmino
+04. Các yếu tố chính làm nên game Tetris hiện đại:
+ * Next, Hold, Swap, Topping out, Vùng đệm, Vùng biến mất
+ 04A. Gạch: Hình dạng, màu, hướng và tên của gạch
+ 04B. Hệ thống xoay gạch: ARS, ASC, ASC+, BRS, BiRS, C2RS, C2sym, NRS, SRS, SRS+, TRS, XRS
+ 04C. Hệ thống điều khiển: IRS, IHS, IMS
+ 04D. Cách kiểu xáo gạch: Túi 7 gạch, His, EZ-Start, Reverb, C2; và một vấn đề Drought & Flood của một vài kiểu xáo.
+ 04E. Thông số
+ 04E1. Thông số của game: Tốc độ rơi, 20G, Lockdown Delay, Spawn & Clear delay, ARE, Line ARE, Death ARE
+ 04E2. Thông số điều khiển: DAS & ARR, DAS cut, Hiệu chỉnh DAS, Auto-lock cut, SDF
+ 04F. Điều khiển
+ 04F1. Tốc độ: LPM, PPS, BPM, KPM, KPP
+ 04F2. Kỹ thuật: Hypertapping, Rolling, Finesse
+ 04F3. Độ trễ đầu vào
+ 04G. Khả năng tấn công
+ * APM, SPM, DPM, RPM, ADPM, APL
+ * Tấn công & Phòng thủ
+ * Combo, Spike, Debt, Passthrough
+ 04H. Hành động bất cẩn (Mis-): Misdrop, Mishold
+ 04I. Spin: (Mini)/(All-)/(T-)/(O-) spin; Fin, Neo, Iso
+ 04J: Kỹ thuật xóa hàng:
+ * Single, Double, Triple, Techrash, Tetris
+ * TSS, TSD, TST, MTSS, MSTSD
+ * Perfect Clear, Half Perfect Clear
+ 04K. Các thuật ngữ khác: sub, 'Doing Research', Bone block
+
+05. Các game xếp gạch
+ (Danh sách rất dài, gõ trên thanh tìm kiếm "nhom05" để xem danh sách đầy đủ)
+
+06. Một vài cơ chế và chế độ của một số game: Tàng hình một phần/hoàn toàn, Chế độ MPH, Secert Grade, Deepdrop
+07. Bot: Cold Clear, ZZZbot
+08. Mẹo và lời khuyên hữu ích:
+ * Đề xuất luyện tập, Học làm T-spin, Hiệu chỉnh DAS
+ * Bố cục phím, Khả năng xử lý gạch, Các nút xoay
+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
+ 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
+10. Cộng đồng: Tetris Online Servers, Tetris Việt Nam
+11. Xếp lên và đào xuống
+ 11A. Stacking (Xếp lên):
+ * Side/Center/Partial well
+ * Side/Center 1/2/3/4-wide
+ * Residual
+ * 6-3 Stacking
+ 11B. Digging (Đào xuống)
+12. Setup (Opener, Mid-game setup, Donation, Pattern)
+ 12A. Freestyle
+ 12B. Opener: DT Cannon, DTPC, BT Cannon, BTPC, TKI 3 Perfect Clear, QT Cannon, Mini-Triple, Trinity, Wolfmoon Cannon, Sewer, TKI, God Spin, Albatross, Pelican, Perrfect Clear Opener, Grace System, DPC, Gamushiro Stacking
+ 12C. Mid-game: C-spin, STSD, Fractal, LST stacking, Imperial Cross, King Crimson, Fin, Neo, Iso, PC liên tiếp (1+2+3)
+ 12D. Donation: Hamburger, STMB Cave, Kaidan, Shachiku Train, Cut Copy
+13. Cách tính lượng sát thơng gây ra: Tetris Online/Notris Foes, Techmino
+14. Console và chuyện quản lý dữ liệu game
+ — Console, đặt lại thiết lập, tình trạng mở khóa, bố cục phím
+ — Xóa toàn bộ thành tích, kỷ lục, bản phát lại, bộ nhớ đệm
+15. Các thuật ngữ không liên quan gì tới Tetris (tiếng Anh): SFX, BGM, TAS, AFK
+ ]]
+ },
+ {"=[NHÓM 02]=",
+ "nhom02",
+ "name",
+ "NHÓM 02: DỰ ÁN TECHMINO",
+ },
+ {"Website chính thức",
+ "nhom02 websites; trang chủ",
+ "org",
+ "Trang web chính thức của Techmino!\nBạn có thể lấy bản ổn định mới nhất của Techmino cũng như tạo tài khoản, thay avatar ngay tại đó\nNhấn vào nút “Mở link” để mở website đó trong trình duyệt",
+ "http://studio26f.org",
+ },
+ {"Dự án trên GitHub",
+ "nhom02; mã nguồn mở; dự án; github; repository; kho lưu trữ",
+ "org",
+ "Kho lưu trữ chính thức của Techmino trên GitHub. Chúng tôi đánh giá cao nếu bạn tặng cho chúng tôi một ngôi sao! (bạn có thể tặng sao miễn phí).",
+ "https://github.com/26F-Studio/Techmino",
+ },
+ {"Discord",
+ "nhom02 máy chủ server",
+ "org",
+ [[
+Cùng gặp gỡ và nói chuyện với tác giả của Techmino ở trong Discord
+Cũng như cùng thử nghiệm với sản phẩm và tính năng mới. Hay đơn giản là ngồi tám chuyện cho vui :)
+
+[Sea: bạn cũng có thể vào server và hỏi mình về vấn đề dịch thuật nếu bạn có thắc mắc/đề xuất]
+ ]],
+ "https://discord.gg/f9pUvkh"
+ },
+ not FNNS and {"=[NHÓM 03]=",
+ "nhom03",
+ "name",
+ "NHÓM 03: ỦNG HỘ CHO TÁC GIẢ CỦA TECHMINO",
+ } or {"=[NHÓM 03]=",
+ "nhom03",
+ "name",
+ "Nội dung của nhóm này đã bị ẩn đi do yêu cầu của nền tảng. Nhưng bạn vẫn có thể hỏi về nội dung này trong server Discord của chúng tôi."
+ },
+ not FNNS and {"Ủng hộ 1",
+ "nhom03; ủng hộ 1; wechat alipay",
+ "org",
+ "Để ủng hộ cho Techmino thông qua WeChat Pay hoặc Alipay, gõ “support” ở trong console và quét mã QR.",
+ } or {"*ĐÃ ẨN*", "", "org", ""},
+ not FNNS and {"Ủng hộ 2",
+ "nhom03; ủng hộ 2; afdian aidadian",
+ "org",
+ "Để ủng hộ cho Techmino qua Aifadian, hãy nhấn vào nút “Mở link” để mở trang ủng hộ. Lưu ý là Aifadian sẽ trừ bạn 6% phí giao dịch.",
+ "https://afdian.net/@MrZ_26",
+ } or {"*ĐÃ ẨN*", "", "org", ""},
+ not FNNS and {"Ủng hộ 3",
+ "nhom03; ủng hộ 3; patreon",
+ "org",
+ "Để ủng hộ cho Techmino qua Patreon, hãy nhấn vào nút “Mở link” để mở trang ủng hộ. Lưu ý là Patreon có thể tính phí dịch vụ cho bạn đối với các giao dịch trên một số tiền nhất định.",
+ "https://www.patreon.com/techmino",
+ } or {"*ĐÃ ẨN*", "", "org", ""},
+ {"=[NHÓM 04]=",
+ "nhom04",
+ "name",
+ [[
+NHÓM 04: CÁC YẾU TỐ TẠO NÊN TETRIS HIỆN ĐẠI
+
+Khái niệm về trò chơi Tetris hay trò chơi xếp gạch “hiện đại” khá là mờ nhạt.
+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 Tetris).
+
+Dưới đây là các yếu tố chính để làm nên Tetris, tuy nhiên chúng không bắt buộc phải xuất hiện trong mọi game
+ 1. Phần có thể nhìn được của bảng có kích thước 10 × 20 (rộng × dài), cùng với 2 — 3 hàng ẩn ở bên nhau.
+ 2. Gạch sẽ được sinh ra ở giữa trên cùng của ma trận có thể nhìn thấy (thường là ở hàng 21-22). Mỗi mảnh đều có màu sắc và hướng quay mặc định riêng.
+ 3. Có một bộ xáo gạch như 7-bag hay His.
+ 4. Có hẳn một hệ thống xoay, và cho phép xoay theo ít nhất 2 hướng.
+ 5. Có một hệ thống trì hoãn khóa gạch thích hợp.
+ 6. Có điều kiện kiểm tra gạch có đè lên gạch khác hay không.
+ 7. Có hiện NEXT, với nhiều gạch sắp rơi xuất hiện trong đó (thường là từ 3-6), những gạch này được hiện với hướng mà chúng sẽ đứng khi chúng được sinh ra.
+ 8. Cho phép giữ gạch (Hold).
+ 9. Nếu có spawn delay hoặc clear delay, thì game thường sẽ có hệ thống IRS và IHS.
+ 10. Có hệ thống DAS cho các chuyển động ngang chính xác và nhanh chóng.
+ ]],
+ },
+ {"Next (Kế/Tiếp)",
+ "nhom04 preview",
+ "term",
+ "Hiện một vài gạch tiếp theo sẽ xuất hiện. Có một kỹ năng cần thiết đó là lên kế hoạch trước nơi đặt các gạch từ hàng đợi NEXT.",
+ },
+ {"Hold (Giữ)",
+ "nhom04 hold",
+ "term",
+ "Lưu gạch để sử dụng sau, và lấy gạch tiếp theo từ NEXT\nNếu có gạch đang giữ, tráo đổi giữa gạch đang rơi và gạch trong HOLD\n\n*Chỉ có trên Techmino*: Techmino có một tính năng gọi là “In-place Hold” (“Giữ ngay tại chỗ”). Khi được bật thì gạch được lấy ra từ Hold sẽ xuất hiện ngay tại vị trí gạch đang rơi, thay vì xuất hiện ngay ở trên cùng bảng",
+ },
+ {"Swap",
+ "nhom04 hold",
+ "term",
+ "Tương tự như *Hold*, nhưng sẽ lấy gạch tiếp theo từ Next; gạch đang rơi hiện tại sẽ đứng cuối hàng. Bạn chỉ có thể đổi gạch một lần trong đa số trương hợp.",
+ },
+ {"Topping out",
+ "nhom04 topout toppingout game over",
+ "term",
+ [[
+Một tựa game xếp gạch hiện đại thường có 3 điều kiện để “game over”:
+1. Block out: Gạch mới được sinh ra chồng chéo với một gạch đã đặt;
+2. Lock out: Có gạch nằm trên vùng skyline (đường chân trời);
+3. Top out: Độ cao của bảng vượt quá độ cao cho phép (độ cao cho phép thường là 40 ô).
+Techmino không kiểm tra điều kiện Lock out và Top out.
+ ]],
+ },
+ {"Vùng đệm",
+ "nhom04 invisible buffer zone",
+ "term",
+ "Tên tiếng Anh: “Buffer Zone”. Chỉ những hàng từ hàng thứ 21-40, vùng này là vùng ở trên vùng nhìn thấy của bảng. Bởi vì gạch có thể cao hơn vùng nhìn thấy (thường xảy ra nếu có quá nhiều rác tới cùng một lúc) cho nên vùng đệm được tạo ra để cho phép những gạch ở trên cao có thể quay lại (sau) khi người chơi xóa hàng rác. Ngoài ra, vùng đệm thường nằm ở độ cao từ 21-40 vì chúng có thể áp dụng cho hầu hết các trường hợp. Tuy nhiên vẫn có những trường hợp ngoại lệ, hãy tham khảo “Vanish Zone” để biết thêm thông tin chi tiết",
+ },
+ {"Vùng biến mất",
+ "nhom04 gone vanish zone",
+ "term",
+ "Tên tiếng Anh: “Vanish Zone”. Chỉ những hàng từ hàng thứ 40 và cao hơn. Chỉ có thể phát hiện ra bằng cách sử dụng C4W và một đống hàng rác. Bình thường, nếu có gạch nào đụng vào vùng biến mất thì game sẽ crash ngay.\nTuy nhiên, có một số game có những phản ứng khác nhau. Một số game sẽ bị lỗi và sập khi có gạch đi vào vùng biến mất (ví dụ như Tetris Online). Riêng ở một số game thì game sẽ có hành động lạ (bạn có thể tham khảo video này, hãy nhấn vào nút “Mở link” để mở video).\n\nThông tin thêm: Jstris không có vùng đệm, chỉ có vùng biến mất được đặt từ hàng thứ 22.",
+ "https://youtu.be/z4WtWISkrdU",
+ },
+ {">A|Gạch",
+ "nhom04a",
+ "name",
+ "Bạn có biết? Có 29 gạch có thể chơi được trong game này!\n1 Mino | 1 Domino | 2 Trimino | 7 Tetromino | 18 Pentomino",
+ },
+ {"H.dạng của Tetro.",
+ "nhom04a hình dạng của tetro. hình dạng của tetromino"..tetromino,
+ "term",
+ "Trong những game xếp gạch chuẩn, tất cả toàn bộ gạch đều là Tetromino. Tức là, những gạch này được liên kết bởi 4 ô, bám dính vào mặt chứ không bám vào góc.\n\nCó 7 loại Tetromino, (nếu ta cho phép xoay nhưng không được lật ngang hay dọc). 7 Tetromino này được đặt tên theo hình dạng của chúng. Đó là Z, S, J, L, T, O, và I. Hãy xem mục “Gạch & tên tương ứng” để có thêm thông tin.",
+ },
+ {"Màu của Tetromino",
+ "nhom04a màu"..tetromino,
+ "term",
+ "Nhiều game xếp gạch hiện đại, từ chính thức tới fan làm, đã và đang sử dụng cùng một bảng màu duy nhất cho Tetromino. Những màu này bao gồm:\nZ — Đỏ, S — Lục, J — Lam, L — Cam, T — Tím, O — Vàng, và I — Lục lam.\n\nTechmino cũng sử dụng bảng màu này để tô màu cho Tetromino.",
+ },
+ {"Gạch & tên tg. ứng",
+ "nhom04a mino gạch & tên tương ứng gạch và tên tương ứng"..tetromino,
+ "term",
+ "Đây là danh sách gạch mà Techmino sử dụng cùng với tên tương ứng của chúng:\nTetromino:\nZ: "..CHAR.mino.Z..", S: "..CHAR.mino.S..", J: "..CHAR.mino.J..", L: "..CHAR.mino.L..", T: "..CHAR.mino.T..", O: "..CHAR.mino.O..", I: "..CHAR.mino.I..";\n\nPentomino:\nZ5: "..CHAR.mino.Z5..", S5: "..CHAR.mino.S5..", P: "..CHAR.mino.P..", Q: "..CHAR.mino.Q..", F: "..CHAR.mino.F..", E: "..CHAR.mino.E..", T5: "..CHAR.mino.T5..", U: "..CHAR.mino.U..", V: "..CHAR.mino.V..", W: "..CHAR.mino.W..", X: "..CHAR.mino.X..", J5: "..CHAR.mino.J5..", L5: "..CHAR.mino.L5..", R: "..CHAR.mino.R..", Y: "..CHAR.mino.Y..", N: "..CHAR.mino.N..", H: "..CHAR.mino.H..", I5: "..CHAR.mino.I5..";\n\nTrimino, Domino, and Mino:\nI3: "..CHAR.mino.I3..", C: "..CHAR.mino.C..", I2: "..CHAR.mino.I2..", O1: "..CHAR.mino.O1..".",
+ },
+ {"Hướng gạch",
+ "nhom04a 0r2l 02 20 rl lr"..tetromino,
+ "term",
+ [[
+Trong hệ thống xoay SRS và các biến thể của SRS, có một hệ thống tiêu chuẩn sử dụng số và chữ cái để mô tả hướng của các gạch:
+ 0: Hướng mặc định của hệ thống xoay
+ R: Xoay phải, góc 90° theo chiều kim đồng hồ
+ L: Xoay trái, góc 90° theo ngược chiều kim đồng hồ
+ 2: Xoay 2 lần, góc 180° theo bất kì chiều nào.
+
+Ví dụ:
+ 0→L nghĩa là xoay gạch ngược chiều kim đồng hồ, từ hướng ban đầu (0) sang hướng bên trái (L)
+ 0→R nghĩa là xoay gạch theo chiều kim đồng hồ, từ hướng ban đầu (0) sang hướng bên phải (R)
+ 2→R nghĩa là xoay gạch ngược chiều kim đồng hồ, từ hướng 180° (2) sang hướng bên phải (R).
+ ]],
+ },
+ {">B|Hệ thống xoay",
+ "nhom04b",
+ "name",
+ [[
+Một hệ thống để xác định cách gạch xoay.
+
+Ở các trò xếp gạch hiện đại, mỗi gạch có thể xoay dựa trên một tâm xoay cố định (có thể không xuất hiện trong một vài game). Nếu gạch sau khi xoay đè lên gạch khác/ra ngoài bảng, hệ thống sẽ thử đẩy gạch sang các vị trí xung quanh (một quá trình được gọi là “wall-kicking” (đá tường)).
+
+Đá tường cho phép gạch có thể đến những lỗ có hình dạng nào đó mà bình thường không thể tiếp cận được. Các vị trí mà gạch hệ thống xoay có thể thử được chứa trong một bảng gọi là “wall-kick table” (bảng (các vị trí) đá tường)
+ ]]
+ },
+ {"ARS",
+ "nhom04b arikrotationsystem atarirotationsystem",
+ "term",
+ "Có thể chỉ 1 trong 2 hệ thống sau:\nArika Rotation System (Hệ thống xoay Arika): hệ thống xoay được dùng trong series game Tetris: The Grand Master.\nAtari Rotation System (Hệ thống xoay Atari), hệ thống xoay luôn căn chỉnh các gạch ở trên cùng bên trái khi xoay.",
+ },
+ {"ASC",
+ "nhom04b ascension",
+ "term",
+ "Hệ thống xoay được dùng trong Ascension — một bản clone của Tetris. Tất cả các gạch đều sử dụng chung một bảng đá tường (một dành cho xoay phải, một dành cho xoay trái), và vùng đá nằm trong khoảng cách ± 2 ô ở cả hai trục.",
+ },
+ {"ASC+",
+ "nhom04b ascension ascplus",
+ "term",
+ "Một phiên bản chỉnh sửa của ASC trong Techmino, hỗ trợ đá tường cho trường hợp xoay 180°.",
+ },
+ {"BRS",
+ "nhom04b bulletproofsoftware",
+ "term",
+ "BPS rotation system | Hệ thống xoay BPS\nĐược dùng trong các game Tetris được viết bởi Bullet-Proof Software.",
+ },
+ {"BiRS",
+ "nhom04b biasrs biasrotationsystem",
+ "term",
+ [[
+Bias Rotation System | Hệ thống xoay Bias.
+*Chỉ có trên Techmino*
+
+Một hệ thống xoay dựa trên SRS và XRS
+Có khả năng điều chỉnh độ lệch khi xoay tùy thuộc phím di chuyển nào đang giữ khi nhấn phím xoay
+
+Quá trình thử của hệ thống này diễn ra như sau:
+1. Thử dịch chuyển gạch sang trái/phải/xuống tùy thuộc vào phím đang giữ + độ lệch xuống phía dưới
+2. Nếu thất bại, làm lại Bước 1; nhưng bỏ đi độ lệch xuống dưới
+Nếu cả 2 bước trên thất bại thì việc xoay gạch coi như hỏng!
+
+So với XRS, BiRS dễ nhớ hơn vì chỉ dùng một bảng đá tường; nhưng vẫn giữ được khả năng vượt địa hình của SRS.
+
+Khoảng cách euclide (ơclit) của độ lệch cú đá được chọn phải bé hơn √5
+Nếu có độ lệch theo chiều ngang, hướng của cú đá đó phải là hướng đã chọn.
+ ]],
+ },
+ {"C2RS",
+ "nhom04b c2rs cultris2",
+ "term",
+ "Cultris II rotation system | Hệ thống xoay Cultris II\n\nMột hệ thống xoay ở trong Cultris II — một bản clone của Tetris.\nToàn bộ gạch và cả hướng xoay đều sử dụng chung một bảng đá tường (trái, phải, xuống, xuống + trái, xuống + phải, trái 2, phải 2), với ưu tiên về phía bên trái so với bên phải.\n\nTrong Techmino có một bản chỉnh sửa của hệ thống này, đó là C2sym. C2sym sẽ ưu tiên hướng theo hình dạng của gạch",
+ },
+ {"C2sym",
+ "nhom04b cultris2",
+ "term",
+ "Một bản mod của C2RS. Hệ thống sẽ ưu tiên hướng Trái/Phải tùy vào hình dạng của các viên gạch khác nhau.",
+ },
+ {"DRS",
+ "nhom04b dtetrotationsystem",
+ "term",
+ "DTET Rotation System | Hệ thống xoay DTET\nHệ thống xoay trong DTET.",
+ },
+ {"NRS",
+ "nhom04b nintendorotationsystem",
+ "term",
+ "Nintendo Rotation System | Hệ thống xoay Nintendo\n\nHệ thống được sử dụng trong hai game Tetris, một dành cho máy NES, một dành cho máy Game Boy.\nHệ thống xoay này cũng có hai phiên bản ngược chiều nhau: trên Game Boy thì gạch sẽ căn về bên trái; trên NES thì gạch sẽ căn về bên phải.",
+ },
+ {"SRS",
+ "nhom04b superrotationsystem",
+ "term",
+ "Super Rotation System | Hệ thống xoay Siêu cấp\n\nHệ thống xoay được sử dụng rất nhiều trong các game xếp gạch 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. Có 4 hướng cho Tetromino và có thể xoay phải và xoay trái (nhưng không thể xoay 180°). Nếu Tetromino đụ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 đủ bảng đá tuờng trên Tetris.wiki",
+ },
+ {"SRS+",
+ "nhom04b srsplus superrotationsystemplus",
+ "term",
+ "Một biến thể của SRS, hỗ trợ bảng đá tường khi xoay 180°.",
+ },
+ {"TRS",
+ "nhom04b techminorotationsystem",
+ "term",
+ "Techmino Rotation System | Hệ thống xoay Techmino\n*Chỉ có trên Techmino*\n\nMột hệ thống xoay dựa trên SRS.\nHệ thống này khắc phục được hiện tượng gạch S/Z bị kẹt trong một số trường hợp; cũng như bổ sung thêm những vị trí đá hữu dụng.\n\nHơn nữa, TRS có một bảng đá tường dành cho Pentomino dựa trên logic của SRS.\n\nHệ thống cũng hỗ trợ O-Spin (cho phép gạch có thể đá và có thể 'biến hình').",
+ },
+ {"XRS",
+ "nhom04b xrs",
+ "term",
+ "X rotation system | Hệ thống xoay X, một hệ thống xoay trong T-ex.\n\nHệ thống giới thiệu một tính năng với tác dụng “dùng một bảng đá tường khác khi giữ một phím mũi tên,” cho phép người chơi có thể nói game hướng mà gạch nên di chuyển theo ý muốn của họ.",
+ },
+ {">C|Hệ thg đ.khiển",
+ "nhom04c",
+ "name",
+ "NHÓM 5C: HỆ THỐNG ĐIỀU KHIỂN"
+ },
+ {"IRS",
+ "nhom04c initialrotationsystem",
+ "term",
+ "Initial Rotation System\nGiữ phím xoay trong khoảng thời gian spawn delay để gạch xoay sẵn lúc xuất hiện. Đôi khi có thể giúp bạn thoát chết.",
+ },
+ {"IHS",
+ "nhom04c initialholdsystem",
+ "term",
+ "Initial Hold System\nGiữ phím Hold trong khoảng thời gian spawn delay để kích hoạt HOLD ngay lập tức thay vì để gạch spawn bình thường. Đôi khi có thể giúp bạn thoát chết.",
+ },
+ {"IMS",
+ "nhom04c initialmovesystem",
+ "term",
+ "Initial Movement System\n*Chỉ có trên Techmino*\n\nGiữ một phím di chuyển trong khoảng thời gian spawn delay để gạch xuất hiện ở một bên bảng thay vì ở giữa. Đôi khi có thể giúp bạn thoát chết.\nLưu ý: DAS buộc phải được “sạc” đầy trước khi gạch xuất hiện.",
+ },
+ {">D|Các kiểu xáo",
+ "nhom04d",
+ "name",
+ ""
+ },
+ {"Kiểu xáo Túi 7",
+ "nhom04d bag7 randomgenerator túi 7 gạch; kiểu xáo túi 7 gạch",
+ "term",
+ [[
+Tên gọi chính thức là “Random Generator” (Trình xáo gạch ngẫu nhiên)
+Ngoài ra nó còn có tên là “7-Bag Generator”.
+Tên tiếng Việt: “Kiểu xáo Túi 7 gạch”.
+
+Đây là kiểu xáo hay được sử dụng bởi các trò chơi xếp gạch hiện đại. Từ khi bắt đầu game, bạn luôn được đảm bảo rằng bạn sẽ có đủ 7 Tetromino mỗi 7 viên gạch bạn đã thả rơi.
+Một vài ví dụ: ZSJLTOI, OTSLZIJ, LTISZOJ.
+ ]],
+ },
+ {"Kiểu xáo His",
+ "nhom04d historygenerator hisgenerator",
+ "term",
+ [[
+Tên đầy đủ là History — Roll. (Tên tiếng Việt: “Nhớ — Lặp”)
+
+Một kiểu xáo gạch được sử dụng nhiều trong series game Tetris: The Grand Master. Mỗi lần một Tetromino sẽ được chọn ngẫu nhiên: Nếu nó là một trong những gạch đã bốc ra trước đó, thì bốc lại thêm lần nữa cho tới khi bốc được gạch không phải là những viên gạch kia, hoặc là hết lượt bốc lại. Ví dụ: “his4 roll6” (h4r6) (nhớ 4 lặp 6) sẽ nhớ 4 gạch đã bốc cuối cùng, và chỉ được bốc lại tối đa 6 lần nếu cần thiết.
+Kiểu xáo His cũng có một vài biến thể khác. Xem chi tiết tại mục “Kiểu xáo HisPool”.
+
+Trong Techmino, số lần bốc lại ngẫu nhiên sẽ là một nửa độ dài chuỗi gạch.
+ ]],
+ },
+ {"K.xáo HisPool [1/2]",
+ "nhom04d hispool historypoolgenerator kiểu xáo hispool",
+ "term",
+ [[
+Tên đầy đủ là History (- Roll) — Pool. (Tên tiếng Việt là Nhớ — Lặp — Rổ)
+
+Một kiểu xáo dựa trên kiểu xáo His. Nó giới thiệu một cơ chế mới: “Pool” (Rổ). Mỗi lần bốc gạch, HisPool sẽ chọn ngẫu nhiên một viên gạch trong cái Rổ và tăng khả năng xuất hiện của gạch ít xuất hiện nhất. (Bạn có thể tra mục tiếp theo để tìm hiểu về cơ chế Pool nếu bạn tò mò)
+
+Cơ chế này giúp chuỗi gạch ổn định hơn và tránh tình trạng drought xảy ra quá lâu
+Kiểu xáo thường gặp nhất là kiểu xáo “his4 roll6 pool35” (nhớ 4 lặp 6 rổ 35)
+ ]],
+ },
+ {"K.xáo HisPool [2/2]",
+ "nhom04d hispool historypoolgenerator kiểu xáo hispool",
+ "term",
+ [[
+[Sea: Phần này không có trong Zictionary ngôn ngữ khác!]
+Cách hoạt động của kiểu xáo “Nhớ — Lặp — Rổ” diễn ra tuần tự như sau:
+
+Đầu tiên, lấy một viên gạch ngẫu nhiên trong cái Rổ. Nếu gạch đó là một trong những gạch đã bốc ra trước đó thì bốc lại cho tới khi gạch đó không còn là một trong những viên gạch kia, hoặc là hết lượt bốc lại.
+Gạch được bốc trúng sẽ được lấy ra khỏi Rổ. Với các gạch khác, mỗi viên gạch sẽ bị cộng 1 lần vào số lần không xuất hiện của chúng.
+
+Vấn đề là, chiếc Rổ lúc này chỉ còn 34 gạch, nhưng yêu cầu đặt ra là chiếc Rổ phải có 35 gạch. Bây giờ phải kiếm thêm gạch từ đâu ra?
+
+Câu trả lời là: lấy gạch có *số lần không xuất hiện nhiều nhất* (hiểu nôm na là gạch ít xuất hiện nhất) (“The droughtest piece”) để thêm ngược lại Rổ. Và lẽ tất nhiên game có theo dõi các viên gạch đã không xuất hiện bao nhiêu lần để biết gạch nào cần lấy chứ :)
+
+Sau khi gạch đó đã thêm vào Rổ, số lần không xuất hiện của nó sẽ bị đặt lại về 0
+Cuối cùng là thêm gạch vào chuỗi NEXT và quay về bước đầu tiên.
+ ]],
+ },
+ {"Kiểu xáo EZ-Start",
+ "nhom04d bages easy start khởi đầu suôn sẻ; kiểu xáo ez-start' kiểu xáo ezstart",
+ "term",
+ "*Chỉ có trên Techmino*\n\nKiểu xáo Túi “Khởi đầu suôn sẻ” (Bag Easy-Start generator), một kiểu xáo được cải tiến từ kiểu xáo Túi. Gạch đầu tiên của mỗi túi sẽ không bao giờ là gạch khó đặt (S/Z/O/S5/Z5/F/E/W/X/N/H).",
+ },
+ {"Kiểu xáo Reverb",
+ "nhom04d kiểu xáo reverb",
+ "term",
+ "*Chỉ có trên Techmino*\n\nMột cách xáo gạch có nguồn gốc từ cách xáo Túi. Kiểu xáo Reverb sẽ lặp ngẫu nhiên một vài gạch từ kiểu xáo Túi. Khả năng lặp lại gạch giảm nếu gạch bị lặp quá nhiều và ngược lại",
+ },
+ {"Kiểu xáo C2",
+ "nhom04d cultris2generator cultrisiigenerator c2generator",
+ "term",
+ "Ban đầu toàn bộ Tetromino sẽ có trọng số (“weight”) là 0.\nSau mỗi lần xáo gạch, toàn bộ trọng số của các gạch sẽ bị chia hết cho 2, và được cộng một số thực ngẫu nhiên từ 0 tới 1. Gạch có trọng số cao nhất sẽ được bốc, và sau đó trọng số của nó sẽ bị chia cho 3.5.",
+ },
+ {">F|Thông số",
+ "nhom04e",
+ "name",
+ ""
+ },
+ {">E1|Thg số game",
+ "nhom04e1",
+ "name",
+ "NHÓM 5F1: THÔNG SỐ GAME"
+ },
+ {"Tốc độ rơi",
+ "nhom04e1 trọng lực falling speed gravity",
+ "term",
+ [[
+Đơn vị của tốc độ rơi là “G” — một đơn vị có số khá lớn, có nghĩa là gạch rơi xuống bao nhiêu ô/khung hình.
+Tốc độ của Level 1 trong chế độ Marathon thường là 1/60G (1 ô/giây = 1 ô/60 khung hình), ở Level 13 là gần/bằng 1G (từ 50-60 ô/giây).
+Tốc độ cao nhất trong các game Tetris hiện đại là 20G. Ý nghĩa thật sự của 20G là “Tốc độ rơi vô tận”. Bạn có thể tìm hiểu về 20G ở mục “20G”
+Trong Techmino, tốc độ rơi được mô tả là số khung hình cần thiết để gạch rơi xuống một đơn vị; ví dụ, 60 để chỉ gạch rơi mỗi ô một giây (nếu game mặc định chạy ở 60FPS).
+ ]],
+ },
+ {"20G",
+ "nhom04e1 trọng lực; ngay lập tức; gravity instantly",
+ "term",
+ "Tốc độ nhanh nhất trong các game xếp gạch hiện đại. Trong các chế độ xài tốc độ 20G, các viên gạch sẽ xuất hiện ngay lập tức ở đáy bảng thay vì rơi từ từ, bất chấp độ cao bảng là 20 hàng hoặc hơn. Việc này đôi khi sẽ làm bạn không thể di chuyển được theo phương ngang như ý; vì gạch không thể leo qua chỗ lồi lõm hoặc ra khỏi hố sâu.\nBạn có thể tìm hiểu thêm về đơn vị “G” trong mục “Tốc độ rơi”.",
+ },
+ {"Lockdown Delay",
+ "nhom04e1 lockdelay lockdowndelay lockdowntimer; thời gian chờ khóa gạch",
+ "term",
+ "Thời gian chờ khóa gạch\n\nĐây là khoảng thời gian sau khi gạch chạm đất và trước khi gạch bị khóa (lockdown) (và bạn sẽ phải điều khiển gạch tiếp theo).\n\nCác game Tetris hiện đại 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 đa số các game); bạn có thể sử dụng để kéo dài thời gian chờ. Tetris cổ điển vẫn có khoảng thời gian này nhưng cực kì ngắn.",
+ },
+ {"Spawn&Clear Delay",
+ "nhom04e1 spawndelay cleardelay; thời gian chờ gạch sinh ra; thời gian chờ xóa hàng",
+ "term",
+ [[
+Spawn Delay (Thời gian chờ gạch sinh ra): Khoảng thời gian từ lúc gạch bị khóa cho tới khi gạch mới được sinh ra.
+
+Line Clear Delay (Thời gian chờ xóa hàng): Thời gian để hiệu ứng xóa hàng thực hiện xong.
+ ]]
+ },
+ {"ARE",
+ "nhom04e1 spawn appearance delay",
+ "term",
+ "Tên đầy đủ: Apperance Delay (đôi khi được gọi là Entry Delay) (Thời gian trì hoãn sự xuất hiện của gạch mới). ARE chỉ khoảng thời gian sau khi gạch bị khóa và trước khi gạch mới sinh ra.",
+ },
+ {"Line ARE",
+ "nhom04e1 appearance delay",
+ "term",
+ "Khoảng thời gian khi hiệu ứng xóa hàng bắt đầu chạy cho tới khi gạch mới sinh ra.",
+ },
+ {"Death ARE",
+ "nhom04e1 die delay",
+ "term",
+ "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, spawn ARE sẽ được cộng với một khoảng thời gian nữa để tạo thành Death ARE. Cơ chế này có thể được sử dụng cùng với IHS và IRS để cho phép bạn có thể thoát chết.\nÝ tưởng về cơ chế này là của NOT_A_ROBOT.",
+ },
+ {">E2|Thg số đ.khiển",
+ "nhom04e2",
+ "name",
+ "NHÓM 5F2: THÔNG SỐ ĐIỀU KHIỂN"
+ },
+ {"DAS (đơn giản)",
+ "nhom04e2 das delayedautoshift",
+ "term",
+ "Tưởng tượng bạn đang gõ chữ, và bạn nhấn giữ phím “O”. \nVà bạn sẽ nhận được một chuỗi toàn là o.\nỞ trên thanh thời gian thì nó trông như thế này: o—————o-o-o-o-o-o-o-o-o…\n“—————” là DAS, còn “-” là ARR.",
+ },
+ {"DAS & ARR",
+ "nhom04e2 das arr delayedautoshift autorepeatrate",
+ "term",
+ "DAS viết tắt của từ Delayed Auto Shift, chỉ cách viên gạch di chuyển khi bạn giữ phím di chuyển sang trái hoặc phải. Thuật ngữ này còn ám chỉ khoảng thời gian từ lúc bạn nhấn phím cho tới khi gạch có thể tự động di chuyển liên tục. DAS chỉ được tính một lần và sẽ bị đặt lại khi bạn nhả phím\n\nARR viết tắt của từ Auto-Repeat Rate, nó là khoảng thời gian nghỉ sau khi gạch di chuyển được 1 ô trong quá trình di chuyển liên tục (sau khi đã qua DAS).\n\nTrong một vài game, DAS và ARR được tính bằng f (frame, khung hình). Nhân f với 16.7 (nếu bạn đang chạy game ở 60 FPS) để đổi sang ms (mili giây).",
+ },
+ {"Hiệu chỉnh DAS",
+ "nhom04e2 das tuning",
+ "term",
+ "Với những người chơi nâng cao mà muốn chơi nhanh hơn, có thể điều chỉnh DAS thành 4-6 f (67-100 ms) và ARR 0 f (0 ms); đây là hai giá trị khuyên dùng. (Ở ARR 0ms, các viên gạch sẽ ngay lập tức dính vào tường khi bạn vượt qua DAS.)\n\nĐây là cấu hình lý tưởng cho người nâng cao, với chiến lược là cắt giảm DAS trong khi vẫn có thể kiểm soát được gạch một cách tin cậy mặc dù ARR bằng 0 nếu có thể hoặc càng thấp càng tốt.",
+ },
+ {"DAS cut",
+ "nhom04e2 dascut dcd",
+ "term",
+ "*Chỉ có trên Techmino*\n\nTrong Techmino, bạn có thể hủy hoặc rút một khoảng thời gian từ bộ đếm ngược của DAS. Có thể giảm được tình trạng gạch di chuyển ngay lập tức khi vừa mới xuất hiện nếu có phím di chuyển nào đang được giữ.\n\nNhững game khác có thể có tính năng này nhưng cách hoạt động có thể đôi chút khác biệt.",
+ },
+ {"Auto-lock cut",
+ "nhom04e2 autolockcut",
+ "term",
+ "Một tính năng được thiết kế để ngăn chặn việc mis-harddrop do việc vô tình nhấn phím “Thả mạnh” vào trúng vài giây mili giây sau khi gạch trước đó đã được đặt một cách tự nhiên\nPhím “Thả mạnh” sẽ tạm thời bị vô hiệu trong vòng vài khung hình (tùy vào từng game/cài đặt của người chơi) ngay sau khi có gạch bị khóa một cách tự nhiên.\n\nNhững game khác có thể có tính năng này nhưng cách hoạt động có thể đôi chút khác biệt.",
+ },
+ {"SDF",
+ "nhom04e2 softdropfactor",
+ "term",
+ "Soft Drop Factor (Hệ số tốc độ rơi nhẹ)\n\nMột cách để xác định tốc độ gạch rơi khi nhấn phím “Thả nhẹ”. Ở những game chính thức: Tốc độ rơi nhẹ = Tốc độ rơi × 20 → SDF của những game này là 20. Techmino không dùng SDF để xác định tốc độ rơi nhẹ, mà dùng SDARR (thông số này có cách hoạt động giống với ARR, nhưng điểm khác là chỉ dùng cho “Thả nhẹ”).",
+ },
+ {">F|Điều khiển",
+ "nhom04f",
+ "name",
+ "",
+ },
+ {">F1|Tốc độ đ.khiển",
+ "nhom04f1",
+ "name",
+ "NHÓM 5G1: TỐC ĐỘ ĐIỀU KHIỂN",
+ },
+ {"LPM",
+ "nhom04f1 linesperminute; số hàng mỗi phút; tốc độ",
+ "term",
+ [[
+Lines per minute | Số hàng mỗi phút
+Phản ánh tốc độ chơi.
+Mỗi game có cách tính LPM khác nhau. Ví dụ như, Tetris Online tính LPM dựa trên PPS (nhìn mục ở bên dưới), trong đó 1 PPS = 24 LPM; do đó số hàng rác sẽ không được tính vào LPM và làm cho LPM khác với nghĩa đen của nó. Trong Techmino, giá trị LPM theo cách tính đó gọi là "L'PM"
+ ]],
+ },
+ {"PPS",
+ "nhom04f1 piecespersecond số gạch mỗi giây; tốc độ",
+ "term",
+ "Pieces per second | Số gạch mỗi giây\n\tPhản ánh tốc độ chơi.",
+ },
+ {"BPM",
+ "nhom04f1 blocksperminute piecesperminute số gạch mỗi phút; tốc độ",
+ "term",
+ "Blocks per minute | Số gạch mỗi phút\n\tPhản ánh tốc độ chơi.\n\tNgoài ra chúng được gọi là PPM (để tránh nhầm lẫn với một thuật ngữ trong âm nhạc) (P là viết tắt của từ Pieces).",
+ },
+ {"KPM",
+ "nhom04f1 keysperminute keypressesperminute số lần nhấn mỗi phút; số phím mỗi phút",
+ "term",
+ "Keypresses per minute | Số lần nhấn mỗi phút\n\tPhản ánh tốc độ người chơi nhấn phím hoặc nút.",
+ },
+ {"KPP",
+ "nhom04f1 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\n\tPhản ánh mức độ hiệu quả việc điều khiển gạch. Giảm con số này bằng cách học Finesse",
+ },
+ {">F2|K.th. đ.khiển",
+ "nhom04f2",
+ "name",
+ "NHÓM 5G2: KỸ THUẬT ĐIỀU KHIỂN",
+ },
+ {"Finesse",
+ "nhom04f2 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 số lần nhấn phím ít nhất. Giúp tiết kiệm thời gian và giảm khả năng misdrop.
+Bạn có thể luyện tập bằng cách dùng tính năng “Chơi lại nếu mắc lỗi” hoặc là để ý tới hiệu ứng âm thanh báo lỗi di chuyển của Techmino.
+
+Techmino phát hiện lỗi di chuyển không dựa vào “số lần nhấn phím tối thiểu để di chuyển theo lý thuyết”.
+Thay vào đó, chỉ kiểm tra lỗi di chuyển dựa trên số lần nhấn phím tương đương đã được quy định *trước khi gạch được đặt tại một vị trí mà không cần dùng Thả nhẹ* ——→ Techmino sẽ không tính lỗi di chuyển nếu bạn phải “nhét” gạch đó để lấp lỗ/thực hiện spin
+Techmino còn kiểm tra thêm một số điều kiện nữa, như nếu bạn giữ gạch mà cả gạch hiện tại giống với gạch đang giữ, hoặc là giữ gạch khi bạn đã di chuyển gạch hiện tại, cũng đều tính là lỗi di chuyển.
+
+Finesse% trong Techmino được tính như sau: 100% nếu số phím bằng hoặc ít hơn par¹, 50%/25%/0% nếu quá par 1/2/3+ phím
+LƯU Ý: trong 20G nếu vẫn kiểm tra lỗi di chuyển, kết quả có thể không chính xác.
+
+(1) Par: thuật ngữ trò đánh golf, thường được sử dụng để chỉ số lượt gậy dự kiến cần để có thể đưa bóng vào lỗ (hole) hoặc một vòng đánh golf (round of golf).
+ ]],
+ },
+ {"Hypertapping",
+ "nhom04f2 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 để nhấn liên tục làm tốc độ di chuyển nhanh hơn\nKỹ năng này được dùng nhiều trong xếp gạch cổ điển (Classic Tetris). Nhưng bạn không cần dùng vì DAS ngắn hơn nhiều so với trước đây.",
+ },
+ {"Rolling",
+ "nhom04f2",
+ "term",
+ [[
+Một phương pháp khác để di chuyển nhanh ở chế độ trọng lực cao (khoảng 1G) (với cài đặt DAS/ARR chậm).
+Để thực hiện thao tác rolling:
+ * Cố định ngón tay của bạn trên phím bạn muốn nhấn ở một bên tay
+ * Sau đó dùng các ngón tay ở bên kia gõ mạnh liên tục ở mặt sau của tay cầm.
+
+Phương pháp này nhanh hơn nhiều so với việc nhấn liên tục (xem mục “Hypertapping” để biết thêm thông tin) và yêu cầu ít công sức hơn.
+Phương pháp này lần đầu tiên được tìm thấy bởi Cheez-fish — người đã đạt tốc độ nhấn lên tới 20 Hz.
+ ]],
+ },
+ {">F3|Độ trễ input",
+ "nhom04f3 input delay",
+ "name",
+ "Độ trễ đầu vào\n\nBất kỳ thiết bị đầu vào cũng cần một khoảng thời gian để tín hiệu có thể tới game, không cao thì thấp, từ mấy ms đến cả trăm ms.\n\nNếu độ trễ đầu vào quá cao, thì việc điều khiển sẽ không thoải mái.\n\nĐộ trễ này thường do phần cứng và phần mềm, thứ mà bạn khó mà kiểm soát được.\nBật chế độ Hiệu suất cao (Performance mode) hoặc tắt chế độ tiết kiệm năng lượng (Energy saving), đồng thời bật chế độ Gaming trên màn hình máy tính/TV, có thể giúp giảm độ trễ.",
+ },
+ {">G|Mis-action",
+ "nhom04g",
+ "name",
+ "NHÓM 5G: HÀNH ĐỘNG BẤT CẨN (MIS-)"
+ },
+ {"Misdrop",
+ "nhom04g md misdrop",
+ "term",
+ "Vô tình thả rơi/đặt gạch vào nơi không mong muốn.",
+ },
+ {"Mishold",
+ "nhom04g mh mishold",
+ "term",
+ "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, và có thể làm bạn mất luôn cơ hội để làm PC.",
+ },
+ {">H|K.năng t.công",
+ "nhom04h",
+ "name",
+ "NHÓM 5H: KHẢ NĂNG TẤN CÔNG"
+ },
+ {"APM",
+ "nhom04h attackperminute; số hàng tấn công mỗi phút; số hàng tấn công trong một phút",
+ "term",
+ "Attack per minute | Số hàng tấn công mỗi phút\n\tPhản ánh sức mạnh tấn công của người chơi",
+ },
+ {"SPM",
+ "nhom04h linessentperminute; số hàng gửi mỗi phút; số hàng gửi trong một phút",
+ "term",
+ "[lines] Sent per minute | Số hàng gửi mỗi phút \n\tPhản ánh sức mạnh tấn công *thực tế* của người chơi (không tính các hàng dùng để chặn rác tới).",
+ },
+ {"DPM",
+ "nhom04h digperminute defendperminute số hàng đào xuống mỗi phút; số hàng đào xuống trong một phút",
+ "term",
+ "Dig/Defend per minute | Số hàng đào xuống mỗi phút\n\tĐôi khi có thể phản ánh mức độ sống sót của người chơi khi nhận được rác",
+ },
+ {"RPM",
+ "nhom04h receive; receiveperminute; số hàng rác phải nhận mỗi phút; số rác phải nhận mỗi phút; số hàng rác phải nhận trong một phút; số rác phải nhận trong mỗi phút",
+ "term",
+ "[lines] Receive per Minute | Số (hàng) rác phải nhận mỗi phút\n\tPhản ánh áp lực hiện có của người chơi",
+ },
+ {"ADPM",
+ "nhom04h attackdigperminute vs; số hàng tấn công và đào xuống mỗi phút; số hàng tấn công và đào xuống mỗi phút",
+ "term",
+ "Attack & Dig per minute | Số hàng tấn công & đào xuống mỗi phút\n\tDùng để so sánh sự khác nhau về kỹ năng của hai người chơi trong một trận đấu; chính xác hơn một chút so với APM\n\tVS Score (điểm VS) trong TETR.IO chính là ADPM mỗi 100 giây",
+ },
+ {"APL",
+ "nhom04h attackperline efficiency; số hàng tấn công; số hàng đã xóa; độ hiệu quả",
+ "term",
+ "Attack per line (cleared) | Số hàng tấn công / Số hàng đã xóa\n\tCòn được biết với tên “efficiency” (độ hiệu quả). Phản ánh độ hiệu quả khi tấn công sau mỗi lần xóa hàng. Ví dụ Tetris và T-spin có độ hiệu quả cao hơn so với Xóa 2 hàng và Xóa 3 hàng.",
+ },
+ {"Tấn công & Phg thủ",
+ "nhom04h attacking defending phòng thủ; tấn công & phòng thủ; tấn công và phòng thủ",
+ "term",
+ [[
+Tấn công: Gửi hàng rác tới đối thủ bằng cách xóa hàng.
+Phòng thủ: Loại hàng rác ra khỏi hàng chờ bằng cách xóa hàng sau khi đối thủ gửi hàng rác.
+Phản công: Gửi hàng rác lại sau khi nhận đòn tấn công, hoặc trong khi/sau khi tấn công.
+
+Trong hầu hết các game, tỷ lệ phản công rác thường là 1:1 — một lần tấn công đánh phản lại một lần nhận rác.
+ ]],
+ },
+ {"Combo",
+ "nhom04h ren combo",
+ "term",
+ "Trong tiếng Nhật gọi là REN.\nXóa hàng liên tiếp để tạo ra combo. Từ lần xóa hàng thứ 2 thì tính là 1 Combo, và từ lần xóa hàng thứ 3 thì tính là 2 Combo, và cứ như thế.\nKhông như Back to Back, đặt một viên gạch = phá combo.",
+ },
+ {"Spike",
+ "nhom04h spike",
+ "term",
+ "Làm nhiều đợt tấn công liên tiếp trong một khoảng thời gian ngắn.\n\nKể cả Techmino và TETR.IO đều có bộ đếm spike, sẽ hiện bao nhiêu hàng rác bạn đã gửi cho đối thủ trong lúc spike.\n\nLưu ý: hàng rác mà bị tích lũy do mạng lag thì không được tính là spike.",
+ },
+ {"‘Debt’",
+ "nhom04h debt owe",
+ "term",
+ "Một thuật ngữ hay được sử dụng trong cộng đồng Tetris Trung Quốc. “Debt” đề cập đến tình huống mà trước mắt một người chơi phải hoàn thành việc thực hiện một setup cụ thể trước khi học có thể thực hiện một/nhiều T-spin để có thể thực sự tấn công. Cho nên, khi đang làm một hoặc nhiều debt liên tiếp, người chơi buộc phải để ý tới đối thủ để đảm bảo an toàn; nếu không, khả năng người chơi sẽ bị đá bay trước khi xây dựng xong là khá cao\n\nThuật ngữ này hay được sử dụng để diễn tả một số setup như TST tower.\nHãy nhớ bạn thực sự KHÔNG THỂ thực hiện tấn công nếu như đang làm debt.",
+ },
+ {"Passthrough",
+ "nhom04h pingthrough",
+ "term",
+ "Đề cập đến một tình huống mà trong đó cả hai người chơi đều gửi tấn công, nhưng thay vì chúng hủy bỏ lẫn nhau thì nó lại gửi thẳng vào bảng của đối phương. Một thuật ngữ khác là “pingthrough” đề cập tình huống passthrough xảy ra do ping cao.",
+ },
+ {">I|Spin",
+ "nhom04i",
+ "name",
+ "Xoay 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. Game khác nhau sẽ có cách kiểm tra Spin khác nhau."
+ },
+ {"Mini",
+ "nhom04i",
+ "term",
+ "Một thuật ngữ bổ sung khác chỉ những Spin mà game nghĩ là có thể thực hiện dễ dàng (bởi vì trong một game cũ nó được gọi là “Ez T-spin”). Lượng điểm bổ sung và hàng rác đều ít hơn so với.\nCác game khác nhau có các quy tắc khác nhau để kiểm tra chúng có phải là Mini-Spin hay không. Nhưng bạn chỉ cần nhớ mấy cái bố cục làm Mini-spin là được.",
+ },
+ {"All-spin",
+ "nhom04i allspin",
+ "term",
+ "Một quy luật mà trong đó, làm Spin bằng gạch gì đều cũng được thưởng thêm điểm và gửi thêm hàng rác; trái ngược với“T-spin Only” (Chỉ làm T-spin).",
+ },
+ {"T-spin",
+ "nhom04i tspin",
+ "term",
+ [[
+Spin được thực hiện bởi Tetromino T.
+Trong các game chính thức, T-spins chủ yếu được phát hiện bởi “quy luật 3 góc”. Tứ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. Một vài game cũng sẽ có thêm vài quy tắc để phân biệt spin đó là T-spin hoặc là Mini T-spin.
+ ]],
+ },
+ {"O-Spin",
+ "nhom04i ospin",
+ "term",
+ "“O-spin is a lie!” (O-spin là một lời nói dối). Một quả meme được nhiều người biết tới.\nNguồn gốc meme này bắt nguồn từ việc gạch O “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.\n\nTrong khi đó:\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”",
+ },
+ {">J|K.th. xóa hàng",
+ "nhom04j",
+ "name",
+ "NHÓM 5J: KỸ THUẬT XÓA HÀNG"
+ },
+ {"Single",
+ "nhom04j 1",
+ "term",
+ "Xóa 1 hàng cùng một lúc.",
+ },
+ {"Double",
+ "nhom04j 2",
+ "term",
+ "Xóa 2 hàng cùng một lúc.",
+ },
+ {"Triple",
+ "nhom04j 3",
+ "term",
+ "Xóa 3 hàng cùng một lúc.",
+ },
+ {"Techrash",
+ "nhom04j tetris 4",
+ "term",
+ "*Chỉ có trên Techmino*\n\nXóa 4 hàng cùng một lúc.",
+ },
+ {"Tetris",
+ "nhom04j 4",
+ "term",
+ "Đây chính là tên của một tựa game (và cũng là tên thương hiệu của nó). Đây cũng là thuật ngữ chỉ việc xóa 4 hàng cùng lúc trong các game chính thức.\nĐược ghép từ 2 từ: Tetra (<τέτταρες>, có nghĩa là số 4 trong tiếng Hy Lạp) and Tennis (quần vợt, môn thể thao yêu thích nhất của người đã sáng tạo ra Tetris). Nhắc nhẹ: những game xếp gạch được phát triển bởi Nintendo và SEGA đều được cấp phép bởi TTC. Hai công ty này không (hề) sở hữu bản quyền của Tetris",
+ -- _comment: original Lua file had this comment: "Thanks to Alexey Pajitnov!"
+ },
+ {"TSS",
+ "nhom04j t1 tspinsingle T-spin Đơn",
+ "term",
+ "T-spin Single | T-spin Đơn\nXóa một hàng bằng T-spin",
+ },
+ {"TSD",
+ "nhom04j t2 tspindouble T-spin Đôi",
+ "term",
+ "T-spin Double | T-spin Đôi\nXóa hai hàng bằng T-spin.",
+ },
+ {"TST",
+ "nhom04j t3 tspintriple T-spin Tam",
+ "term",
+ "T-spin Triple | T-spin Tam\nXóa ba hàng bằng T-spin.",
+ },
+ {"MTSS",
+ "nhom04j minitspinsingle tsms tspinminisingle Mini T-spin Đơn",
+ "term",
+ "Mini T-spin Single | Mini T-spin Đơn\nTrước đây từng biết tới với cái tên “T-spin Mini Single” (TSMS) (T-spin Mini Đơn).\nXóa một hàng bằng Mini T-spin.\nMỗi game sẽ có cách khác nhau để xác định xem T-spin đó có phải là Mini hay không.",
+ },
+ {"MTSD",
+ "nhom04j minitspindouble tsmd tspinminidouble Mini T-spin Đôi",
+ "term",
+ "Mini T-spin Double | Mini T-spin Đôi\nTrước đây từng biết tới với với cái tên “T-spin Mini Double” (TSMD) (T-spin Mini Đôi).\nXóa hai hàng bằng Mini T-spin. MTSD chỉ xuất hiện trong một vài game hạn chế và có các cách kích khác nhau.",
+ },
+ {"Back to Back",
+ "nhom04j 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 'kỹ thuật' (như Tetris hay Spin) liên tiếp (nhưng không xóa theo kiểu 'bình thường'; gửi thêm hàng rác khi tấn công\nKhông như combo, Back To Back sẽ không bị mất khi đặt gạch.",
+ },
+ {"B2B2B",
+ "nhom04j b3b backtobacktoback",
+ "term",
+ "*Chỉ có trên Techmino*\n\nBack to back to back, hay còn gọi là B3B (hoặc B2B2B). Thực hiện nhiều Back to Back liên tiếp để lấp đầy thanh B3B; cuối cùng khi bạn đã lấp B3B vượt một mức nhất định, bạn có thể tấn công mạnh hơn khi làm được B2B, nhờ sức mạnh từ B3B",
+ },
+ {"All Clear",
+ "nhom04j 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: từ này còn một tên khác nữa giờ ít dùng đó là “Bravo”]",
+ },
+ {"HPC",
+ "nhom04j hc halfperfectclear",
+ "term",
+ "*Chỉ có trên Techmino*\nHalf Perfect Clear\n\nMột biến thể của All Clear. Nếu hàng đó bị xóa mà rõ ràng giống với Perfect Clear khi bỏ qua những hàng bên dưới, thì được tính là Half Perfect Clear và sẽ gửi thêm một lượng hàng rác nhỏ",
+ },
+ {">K|T.ngữ khác",
+ "nhom04k",
+ "name",
+ "NHÓM 5L: CÁC THUẬT NGỮ KHÁC"
+ },
+ {"sub",
+ "nhom04k sub",
+ "term",
+ "Sub-[số] có nghĩa là khoảng thời gian ở dưới một mốc nhất định. Đơn vị thời gian thường được bỏ qua và có thể tự suy ra. Ví dụ: “sub-30” có nghĩa là hoàn thành chế độ 40 hàng dưới 30 giây, “sub-15” có nghĩa là hoàn thành chế độ 1000 hàng dưới 15 phút.",
+ },
+ {"‘Doing Research’",
+ "nhom04k scientificresearch",
+ "term",
+ "“Doing scientific research” (“Nghiên cứu khoa học”) là một thuật ngữ đôi khi được dùng ở cộng đồng Tetris Trung Quốc, chỉ việc nghiên cứu/luyện tập kỹ thuật nào đó trong môi trường chơi đơn và tốc độ rơi thấp..",
+ },
+ {"Bone block",
+ "nhom04k bone tgm",
+ "term",
+ [[
+Đây là skin được dùng trong những phiên bản đời đầu của Tetris
+Trước đây, tất cả máy tính đều sử dụng Giao diện Dòng lệnh (Command-Line Interfaces) (nó na ná như cmd trên Windows, Terminal trên Mac, hay Console trên Linux), cho nên mỗi ô gạch đều được hiển thị dưới dạng 2 ngoặc vuông (như thế này: [ ]). Nó nhìn giống như xương, nên đôi khi được gọi là skin bone block (gạch xương).
+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 trong bản tiếng Việt, từ “gạch []” để chỉ bone block.
+ ]],
+ },
+ {"=[NHÓM 05]=",
+ "nhom05",
+ "name",
+ [[
+NHÓM 05: CÁC GAME XẾP GẠCH
+
+Nội dung sau đây là những giới thiệu ngắn gọn về một số game xếp gạch chính thức và do fan làm có mức độ phổ biến cao. MrZ — tác giả của Techmino đã để lại một vài lời nhận xét.
+
+Squishy cũng có một số lời nhận xét và thông tin bổ sung, lời này được đánh dấu bắt đầu bằng "Sea"
+
+Hãy nhớ là không phải game nào được nói đến đều có lời nhận xét, chúng chỉ là những ý kiến chủ quan. Đọc chỉ để tham khảo, những nhận xét này không có tính chuyên môn.
+ ]]
+ },
+ {"King of Stackers",
+ "nhom05 kos kingofstackers",
+ "game",
+ [[
+Chơi trên trình duyệt | Chơi trực tuyến | Hỗ trợ màn hình cảm ứng
+
+Gọi tắt là KoS. Một game xếp gạch chơi trên trình duyệt theo lượt. Về cơ bản: người chơi thay phiên nhau đặt các gạch trong bảng của họ theo chu kỳ 7 gạch. Hàng rác chỉ có thể vào bảng khi một gạch được đặt mà không xóa một hàng nào. Trò chơi mang tính chiến lược cao và có các tùy chọn khác nhau cho cơ chế tấn công.
+ ]],
+ "https://kingofstackers.com/games.php",
+ },
+ {"Tetr.js",
+ "nhom05 tetrjs tetr.js",
+ "game",
+ [[
+Chơi trên trình duyệt | Chơi đơn | Hỗ trợ màn hình cảm ứng
+
+Một game xếp gạch chơi trên trình duyệt với nhiều điều chỉnh và chế độ chuyên nghiệp.
+Liên kết của mục này sẽ đưa bạn tới bản của Farter (bản này là một bản đã mod, đã thêm một vài chế độ khác)
+Bạn cũng có thể tìm một phiên bản khác có tên là "Tetr.js Enhanced" — bản mod này do Dr Ocelot làm (đã bị gỡ xuống và thay thế bằng Tetra Legends, nhưng cũng bị dừng phát triển hoàn toàn từ T12/2020)
+
+[MrZ: Giao diện đơn giản với hầu như không có bất kỳ hiệu ứng (animation) nào. Chỉ có một số tổ hợp phím ảo khả dụng cho thiết bị di động.]
+ ]],
+ "http://farter.cn/t",
+ },
+ {"Tetra Legends",
+ "nhom05 tl tetralegends",
+ "game",
+ [[
+Chơi trên trình duyệt | Chơi đơn
+
+Gọi tắt là TL. Một tựa game chứa nhiều chế độ chơi đơn + 2 chế độ nhịp điệu. Nó cũng hình dung các cơ chế thường ẩn trong các trò chơi Tetris khác. Quá trình phát triển đã dừng lại hoàn toàn từ T12/2020.
+ ]],
+ "https://tetralegends.app",
+ },
+ {"Ascension",
+ "nhom05 asc",
+ "game",
+ [[
+Chơi trên trình duyệt | Chơi đơn/Chơi trực tuyến
+
+Gọi tắt là ASC. Game sử dụng hệ thống xoay có tên là ASC và có nhiều chế độ chơi đơn. Chế độ 1 đấu 1 hiện vẫn còn trong giai đoạn Alpha (tính tới 16/T4/2022).
+Chế độ Stack của Techmino cũng bắt nguồn từ game này.
+ ]],
+ "https://asc.winternebs.com",
+ },
+ {"Jstris",
+ "nhom05 js",
+ "game",
+ [[
+Chơi trên trình duyệt | Chơi đơn/Chơi trực tuyến | Hỗ trợ cảm ứng
+
+Gọi tắt là JS. Nó có một số chế độ chơi đơn với thông số có thể điều chỉnh được. Có thể điều chỉnh phím ảo trên màn hình, nhưng trò chơi này không có hiệu ứng động nào cả.
+ ]],
+ "https://jstris.jezevec10.com",
+ },
+ {"TETR.IO",
+ "nhom05 io tetrio",
+ "game",
+ [[
+Chơi trên trình duyệt/Chơi trên client chính thức | Chơi đơn/Chơi trực tuyến
+
+Gọi tắt là tetrio hoặc IO. Trò chơi này có một hệ thống xếp rank cũng như có chế độ tự do với nhiều thông số có thể tùy chỉnh. Trò chơi này cũng có một client dành cho máy tính, giúp cải thiện tốc độ, giảm độ trễ và gỡ bỏ quảng cáo
+
+[MrZ: Có vẻ như Safari không thể mở game này.]
+ ]],
+ "https://tetr.io",
+ },
+ {"Nuketris",
+ "nhom05",
+ "game",
+ [[
+Chơi trên trình duyệt | Chơi đơn/Chơi trực tuyến
+
+Một trò xếp gạch có chế độ 1 đấu 1 có xếp rank + các chế độ chơi đơn thông thường
+ ]],
+ "https://nuketris.com",
+ },
+ {"Worldwide Combos",
+ "nhom05 wwc worldwidecombos",
+ "game",
+ [[
+Chơi trên trình duyệt | Chơi đơn/Chơi trực tuyến
+
+Gọi tắt là WWC. Có chế độ 1 đấu 1 toàn cầu: chơi với người thật hoặc chơi với replay; có vài quy tắc khác nhau, với các trận đấu gửi rác bằng bom."
+ ]],
+ "https://worldwidecombos.com",
+ },
+ {"Tetris Friends",
+ "nhom05 tetris friends tf tetrisfriends notrisfoes",
+ "game",
+ [[
+Chơi trên trình duyệt/Chơi trên client chính thức | Chơi đơn/Chơi trực tuyến
+
+Gọi tắt là TF. Một trò chơi Tetris được viết dựa trên một plugin đã bị khai tử từ năm 2021. Từng rất phổ biến trong quá khứ, nhưng tất cả trò chơi đã đóng cửa từ mấy năm trước. Hiện giờ vẫn còn một máy chủ riêng tên là “Notris Foes”. Nhấn vào nút “Mở link” để mở ở trong trình duyệt
+ ]],
+ "https://notrisfoes.com",
+ },
+ {"tetris.com [1/2]",
+ "nhom05 tetris online official",
+ "game",
+ [[
+Chơi trên trình duyệt | Chơi đơn | Hỗ trợ màn hình cảm ứng
+
+Game Tetris chính thức tetris.com, mà chỉ có một chế độ (Marathon). Bù lại, có hỗ trợ hệ thống điều khiển thông minh bằng chuột
+ ]],
+ },
+ {"tetris.com [2/2]",
+ "nhom05 tetris online official",
+ "game",
+ [[
+[Mục này được viết bởi Squishy, không xuất hiện ở ngôn ngữ khác
+Có thể áp dụng cho "Tetris Gems" và "Tetris Mind Bender"]
+
+Hiện tại game đã Hỗ trợ màn hình cảm ứng
+(Trong Zictionary tiếng Anh không có ghi "Hỗ trợ màn hình cảm ứng".)
+
+Hiện có ba cách điều khiển: "vuốt" (swipe), "thông minh" (smart), "bàn phím". Bạn có thể thử nghiệm với cả ba chế độ điều khiển để tìm xem chế độ nào tối ưu với mình nhất
+
+Để điều khiển bằng bàn phím thì bạn chỉ cần kết nối với bàn phím là được (miễn là điện thoại có thể nhận bàn phím thì game cũng sẽ nhận thôi)
+Để đổi giữa "vuốt" và "thông minh" thì hãy mở Options của game.
+ ]]
+ },
+ {"Tetris Gems",
+ "nhom05 tetris online official gem",
+ "game",
+ [[
+Chơi trên trình duyệt | Chơi đơn | Hỗ trợ màn hình cảm ứng
+
+Một game xếp gạch khác từ tetris.com. Có cơ chế trọng lực và mỗi ván chỉ kéo dài trong 1 phút. Có 3 loại gem (ngọc) khác nhau với khả năng riêng biệt.
+ ]],
+ },
+ {"Tetris Mind Bender",
+ "nhom05 tetris online official gem",
+ "game",
+ [[
+Chơi trên trình duyệt | Chơi đơn | Hỗ trợ màn hình cảm ứng
+
+Một game xếp gạch khác từ tetris.com . Một chế độ Marathon vô tận với một mino đặc biệt gọi là "Mind Bender" sẽ đưa cho bạn ngẫu nhiên một hiệu ứng nào đó (có thể là tốt hoặc xấu).
+ ]],
+ },
+ {"Techmino",
+ "nhom05",
+ "game",
+ [[
+Đa nền tảng | Chơi đơn/Chơi trực tuyến
+
+Gọi tắt là Tech. Một tựa game xếp gạch được phát triển bởi MrZ. Sử dụng engine LÖVE (love2d). Có rất nhiều chế độ chơi đơn, cũng như có nhiều thông số có thể tùy chỉnh được. Tuy nhiên, chế độ nhiều người chơi hiện tại vẫn đang còn phát triển
+ ]],
+ },
+ {"Falling Lightblocks",
+ "nhom05 fl fallinglightblocks",
+ "game",
+ [[
+Chơi trên trình duyệt/iOS/Android | Chơi đơn/Chơi trực tuyến
+
+Một game xếp gạch đa nền tảng có thể chơi ở chế độ dọc hoặc ngang. Game này có DAS và ARE khi xóa hàng cố định; và có thể điều chỉnh cơ chế điều khiển trên điện thoại. Hầu hết các chế độ trong game đều được thiết kế dựa trên NES Tetris, nhưng cũng có vài chế độ hiện đại. Chế độ Battle theo kiểu nửa "theo lượt", nửa "theo thời gian thực", rác cũng không vào hàng chờ hay có thể hủy được.
+ ]],
+ "https://golfgl.de/lightblocks/",
+ },
+ {"Cambridge",
+ "nhom05",
+ "game",
+ [[
+Đa nền tảng | Chơi đơn
+
+Một game xếp gạch được phát triển bằng LÖVE và được dảnh riêng để tạo ra một nền tảng mạnh mẽ, dễ dàng tùy chỉnh để tạo ra các chế độ mới. Ban đầu được phát triển bởi Joe Zeng, Milla đã tiếp quản quá trình phát triển từ 08/T10/2020, kể từ V0.1.5.
+
+— Tetris Wiki
+ ]],
+ },
+ {"Nanamino",
+ "nhom05",
+ "game",
+ [[
+Windows/Android | Chơi đơn
+
+Một trò chơi do fan làm đang được phát triển với hệ thống xoay đặc trưng cực kỳ thú vị,
+ ]],
+ },
+ {"TGM",
+ "nhom05 tetrisgrandmaster tetristhegrandmaster",
+ "game",
+ [[
+Chỉ có trên máy thùng | Chơi đơn/Chơi qua mạng cục bộ
+
+Tetris The Grand Master, một series Tetris dành cho máy thùng, nổi tiếng với độ khó cực cao — được xem là series game khó nhất (tại thời điểm ra mắt). Những thứ như S13 hay GM cũng từ chính series này. TGM3 được coi là tựa game nổi tiếng nhất của series này.
+ ]],
+ },
+ {"DTET",
+ "nhom05",
+ "game",
+ [[
+Windows | Chơi đơn
+
+Một game xếp gạch dựa trên quy tắc Cổ điển của TGM + 20G với hệ thống xoay gạch mạnh mẽ. Cơ chế điều khiển tốt nhưng không có tùy chỉnh nào ngoài việc có thể gán lại phím. Game này bây giờ hơi khó tìm và bạn có thể phải cài tệp DLL cần thiết bằng tay. Tuy nhiên cũng may là có một bài hướng dẫn cách cài DTET, bạn có thể nhấn nút “Mở link” để mở bài viết.
+
+CẢNH BÁO: cẩn thận khi tải file DLL về!
+Vì chỉ có bạn chịu trách nhiệm nếu trong trường hợp xảy ra thiệt hại
+ ]],
+ "https://t-sp.in/dtet"
+ },
+ {"Heboris",
+ "nhom05 hb",
+ "game",
+ [[
+Windows | Chơi đơn
+
+Một game với phong cách chơi Arcade, có khả năng mô phỏng nhiều chế độ của các trò chơi Tetris khác.
+ ]],
+ },
+ {"Texmaster",
+ "nhom05 txm",
+ "game",
+ [[
+Windows | Chơi đơn
+
+Một game bao gồm tất cả chế độ trong TGM để có thể sử dụng để thực hành TGM. Lưu ý rằng quy tắc Rule trong Texmaster hơi khác một chút so với TGM
+ ]],
+ },
+ {"Tetris Effect",
+ "nhom05 tec tetriseffectconnected",
+ "game",
+ [[
+PS/Oculus Quest/Xbox/NS/Windows | Chơi đơn/Chơi trực tuyến
+
+Gọi tắt là TE(C). Một game xếp gạch chính thức với đồ họa và nhạc nền lạ mắt chuyển động theo sự điều khiển của bạn. Phiên bản cơ bản (Tetris Effect, không có chữ "Connected") chỉ có các chế độ chơi đơn. Phiên bản mở rộng, Tetris Effected Connected có 4 chế độ chơi trực tuyến đó là: Connected (VS), Zone Battle, Score Attack, và Classic Score Attack.
+ ]],
+ },
+ {"Tetris 99",
+ "nhom05 t99 tetris99",
+ "game",
+ [[
+Nintendo Switch | Chơi đơn/Chơi trực tuyến
+
+Một trò chơi nổi tiếng với chế độ Battle Royale 99 người và có nhiều chiến lược thú vị mà không có trong các game chiến đấu truyền thống. Nó cũng có các chế độ chơi đơn hạn chế như Marathon hay các trận đấu bot có sẵn dưới dạng DLC
+ ]],
+ },
+ {"Puyo Puyo Tetris",
+ "nhom05 ppt puyopuyotetris",
+ "game",
+ [[
+PS/NS/Xbox/Windows | Chơi đơn/Chơi trực tuyến
+
+Đây là một tựa game ghép từ hai trò chơi giải đố: Tetris và Puyo Puyo, và bạn có thể chơi đối đầu trong cả hai game này. Có nhiều chế độ chơi đơn và chơi trực tuyến.
+
+[MrZ: Bản PC (Steam) có cơ chế điều khiển và trải nghiệm trực tuyến khá là tệ.]
+ ]],
+ },
+ {"Tetris Online",
+ "nhom05 top tetrisonline",
+ "game",
+ [[
+Windows | Chơi đơn/Chơi trực tuyến
+
+Một game xếp gạch của Nhật Bản đã bị khai tử từ lâu. Có chế độ chơi đơn và chơi trực tuyến. Có thể điều chỉnh DAS và ARR nhưng không thể đặt thành 0. Độ trễ đầu vào nhỏ. Tuy server chính ở Nhật đã bị đóng cửa còn lâu nhưng vẫn còn tồn tại server riêng. Game rất phù hợp cho những người mới bắt đầu.
+ ]],
+ },
+ {"Tetra Online",
+ "nhom05 TO tetraonline",
+ "game",
+ [[
+Windows/macOS/Linux | Chơi đơn/Chơi trực tuyến
+
+Gọi tắt là TO. Một tựa game xếp gạch được phát triển bởi Dr Ocelot và Mine. Các loại độ trễ như AREs được cố tình đẩy ở giá trị cao, và những ai đã từng quen chơi xếp gạch mà có độ trễ thấp/không có độ trễ sẽ khó làm quen với game này
+Game đã bị gỡ ra khỏi Steam vào ngày 9/T12/2020 do TTC gửi thông báo DMCA
+Dù sao thì, vẫn còn một bản build có thể tải từ GitHub.
+ ]],
+ "https://github.com/Juan-Cartes/Tetra-Offline/releases/tag/1.0",
+ },
+ {"Cultris II",
+ "nhom05 c2 cultris2 cultrisii",
+ "game",
+ [[
+Windows/OS X | Chơi đơn/Chơi trực tuyến
+
+Gọi tắt là C2. Được thiết kế dựa trên Tetris cổ điển, Cultris II cho phép bạn có thể điều chỉnh DAS và ARR. Chế độ chiến đấu tập trung vào các combo dựa trên thời gian, thử thách người chơi về mặt tốc độ, n-wide setup và kỹ năng đào xuống của người chơi
+
+[MrZ: Phiên bản dành cho Mac đã không được bảo trì trong thời gian dài. Nếu bạn đang dùng macOS Catalina hoặc macOS mới hơn thì không thể chạy game này.]
+ ]],
+ },
+ {"Nullpomino",
+ "nhom05 np",
+ "game",
+ [[
+Windows/macOS/Linux | Chơi đơn/Chơi trực tuyến
+
+Gọi tắt là NP. Một game xếp gạch chuyên nghiệp có khả năng tùy biến cao. Gần như mọi thông số trong game đều có thể điều chỉnh được.
+
+[MrZ: Giao diện của game mang phong cách retro. Ngoài ra, game chỉ có thể điều khiển thông qua bàn phím, nên một vài người chơi mới sẽ gặp khó khi làm quen. Ngoài ra, có vẻ như macOS Monterey không thể chạy được game này.]
+ ]],
+ },
+ {"Misamino",
+ "nhom05",
+ "game",
+ [[
+Windows | Chơi đơn
+
+Chỉ có chế độ chơi 1 đấu 1 với bot, chủ yếu là chơi theo lượt. Bạn có thể viết bot cho game này (nhưng bạn cần phải học API của game này).
+
+Misamino cũng là tên của bot trong game này.
+ ]],
+ },
+ {"Touhoumino",
+ "nhom05",
+ "game",
+ [[
+Windows | Chơi đơn
+
+Một game Tetris do fan làm. Game này là một bản chỉnh sửa của Nullpomino
+
+[MrZ: Được đề xuất cho những người chơi có ít nhất một nửa kỹ năng, nếu không, bạn thậm chí không biết mình đã chết như thế nào]
+ ]],
+ },
+ {"Tetris Blitz",
+ "nhom05 blitz ea mobile phone",
+ "game",
+ [[
+iOS/Android | Chơi đơn
+
+Một game xếp gạch được làm bởi Electronic Arts (EA). Có cơ chế trọng lực, và mỗi ván game chỉ kéo dài trong vòng 2 phút. Sẽ có một vài gạch sẽ rơi xuống (làm đệm) mỗi khi bắt đầu mỗi ván, và bạn có thể kích hoạt chế độ “Frenzy” bằng cách liên tục xóa hàng. Có rất nhiều loại power-up khác nhau, thậm chí có cả Finisher giúp cho màn chơi kết thúc của bạn thêm đẹp mắt và tăng mạnh số điểm của bạn lên. Game không có cơ chế top-out. Khi mà gạch vừa tới đè lên gạch đang có thì tự động một vài hàng trên cùng sẽ tự động xóa
+
+Game đã bị khai tử từ T04/2020
+ ]],
+ },
+ {"Tetris (EA)",
+ "nhom05 tetris ea galaxy universe cosmos mobile phone",
+ "game",
+ [[
+iOS/Android | Chơi đơn/Chơi trực tuyến?
+
+Một tựa game xếp gạch được phát triển bởi EA. Có hai cách điều khiển: Swipe (Vuốt) và One-Touch (Một chạm). Game này có chế độ Galaxy ngoài chế độ Marathon (với cơ chế trọng lực), và mục tiêu của chế độ này là xóa hết tất cả các gạch của Galaxy trước khi hết chuỗi gạch
+
+Ra mắt lần đầu năm 2011, bị khai tử từ T04/2020
+
+[Sea: game đang nhắc ở đây là bản năm 2011 (phát hành khoảng 2011 — 2012)]
+ ]],
+ },
+ {"Tetris (N3TWORK)",
+ "nhom05 tetris n3twork mobile phone",
+ "game",
+ [[
+iOS/Android | Chơi đơn
+
+Một tựa game xếp gạch, trước đây được phát triển bởi N3TWORK; hiện đã nhượng lại bản quyền cho PlayStudio từ cuối tháng 11 năm 2021. Có chế độ Chơi nhanh 3 phút, Marathon, chế độ Royale 100 người chơi và chế độ Phiêu lưu (nơi mà bạn sẽ phải hoàn thành toàn bộ mục tiêu trước khi hết lượt).
+
+Ghi chú: từ T11-T12/2022 và sau này, tất cả các tài khoản mới tạo chỉ có thể chơi chế độ Marathon và chế độ Phiêu lưu.
+
+[MrZ: UI thì tuyệt nhưng cơ chế điều khiển thì tệ]
+ ]],
+ },
+ {"Tetris Beat",
+ "nhom05 n3twork rhythm",
+ "game",
+ [[
+iOS | Chơi đơn
+
+Một game xếp gạch tới từ nhà N3TWORK nhưng chỉ dành cho Apple Arcade. Nó có một chế độ gọi là “Beat” ngoài chế độ Marathon, nhưng bạn chỉ có thể thả gạch theo nhịp của bài thôi.
+
+[Hiệu ứng của game rất là nặng và cơ chế điều khiển không tốt]
+ ]],
+ },
+ {"Tetris Journey",
+ "nhom05 tetrisjourney mobile phone huanyouji",
+ "game",
+ [[
+iOS/Android | Chơi đơn [Sea: Mục này đã viết lại. Có tham khảo từ Tetris.wiki]
+
+Một game xếp gạch chính thức đã bị khai tử từng được phát triển bởi Tencent dành cho Trung Quốc.
+
+Có 5 chế độ chơi đơn: Marathon, 40 hàng, Ultra (2 phút), Road to Master (chứa nhiều bài học về các kỹ thuật khác nhau), Adventure (chế độ câu chuyện với minigame).
+
+Có 3 chế độ chơi trực tuyến: League Battle (chế độ đối đầu có xếp rank), Melee 101 (giống với Tetris 99 nhưng có 101 người/phòng), Relax Battle (chế độ đối đầu nhưng không xếp rank)
+Mỗi trận trong chế độ chơi trực tuyến dài 2 phút, nếu không ai bị top out thì ai gửi nhiều hàng nhất sẽ giành chiến thắng
+
+Có thể điều chỉnh vị trí và kích thước phím ảo, nhưng không thể điều chỉnh DAS và ARR.
+ ]],
+ },
+ {"JJ Tetris",
+ "nhom05 jjtetris",
+ "game",
+ [[
+Android | Chơi trực tuyến
+
+(JJ块)
+
+Một game bình thưởng trên JJ Card Games (JJ棋牌). Chơi ở màn hình dọc, độ trễ đầu vào thấp, điều khiển mượt. DAS/ARR có thể điều chỉnh được, nhưng hạn chế về tùy biến bố cục phím ảo. Không Hold cũng như B2B, không bộ đệm rác hay hủy rác được. Mỗi tấn công gửi tối đa 4 hàng, còn combo thì "ao chình". Phần còn lại thì tương tự như Tetris hiện đại.
+ ]],
+ },
+ {"Huopin Tetris",
+ "nhom05 huopin qq",
+ "game",
+ [[
+Windows | Chơi trực tuyến
+
+(火拼俄罗斯)
+
+Một game xếp gạch ở trên Tencent Game Center, bảng rộng 12 ô, DAS và ARR giống với DAS và ARR hay dùng trong các app gõ văn bản, 1 Next, không Hold. Chỉ có thể gửi rác bằng Tetris (gửi 3 hàng rác) và xóa 3 hàng (gửi 2 hàng rác). Hàng rác có cấu trúc xen kẽ và gần như không thể đào xuống
+ ]],
+ },
+ {"=[NHÓM 06]=",
+ "nhom06"
+ .."Tàng hình một phần; Tàng hình hoàn toàn; Chế độ MPH; Secret Grade; Deepdrop (Rơi sâu)",
+ "name",
+ [[
+NHÓM 06: MỘT VÀI CƠ CHẾ VÀ CHẾ ĐỘ CỦA MỘT SỐ GAME
+ ]]
+ },
+ {"Tàng hình một phần",
+ "nhom06 half invisible semi",
+ "term",
+ "Tên tiếng Anh: Semi-invisible\nChỉ một quy tắc trong đó gạch sẽ tàng hình sau một khoảng thời gian từ lúc nó được đặt xuống.\nKhoảng thời gian đó thường không được định sẵn, nên có thể chấp nhận mô tả nó là “biến mất sau một vài giây”.",
+ },
+ {"Tàng hình hoàn toàn",
+ "nhom06 invisible",
+ "term",
+ "Tên tiếng Anh: Invisible\nChỉ một quy tắc trong đó gạch sẽ tàng hình ngay tức thì sau khi đặt xuống\nNếu mode tàng hình hoàn toàn mà có hiệu ứng biến mất thì vẫn được chấp nhận. Tuy nhiên, nó làm game dễ hơn đôi chút\n\nỞ Techmino, chế độ tàng hình hoàn toàn mà không có hiệu ứng biến mất được gọi là “Sudden Invisible.”",
+ },
+ {"Chế độ MPH",
+ "nhom06 mph",
+ "term",
+ "Sự kết hợp của ba quy tắc: “Không nhớ gì” (chuỗi gạch tạo ra hoàn toàn ngẫu nhiên), “Không biết trước gạch nào sẽ tới” (không hiện NEXT), và “Không giữ được”. Một chế độ đòi hỏi tốc độ phản ứng.",
+ },
+ {"Secret Grade",
+ "nhom06 larger than",
+ "term",
+ "Một chế độ dạng easter egg trong series TGM. Ở lối chơi “secret grade”, người chơi sẽ làm một đường dích dắc (zigzag) (trông giống như “>” hay “<”) bằng cách tạo ra 1 ô trống duy nhất cho từng hàng. Mục tiêu cuối cùng là hoàn thành đường dích dắc bằng 19 hàng (hoặc hơn).\nĐể biết thêm thông tin, vui lòng tra wiki Hard Drop. Hãy nhấn vào nút “Mở link” để biết thêm thông tin.",
+ "https://harddrop.com/wiki?search=Secret_Grade_Techniques",
+ },
+ {"Deepdrop (Rơi sâu)",
+ "nhom06",
+ "term",
+ "*Chỉ có trên Techmino*\n\nMột chức năng cho phép cho phép gạch có thể teleport xuyên đất để xuống phía dưới. Khi gạch đụng vào đáy hoặc một gạch khác, nhấn phím Thả nhẹ để kích hoạt Deepdrop. Nếu có một cái lỗ phù hợp với hình dạng của gạch ở dưới vị trí gạch đang rơi, gạch sẽ được teleport vào lỗ đó.\nCơ chế này đặc biệt hữu ích cho AI vì nó cho phép AI bỏ qua sự khác biệt giữa các hệ thống xoay khác nhau.",
+ },
+ {"=[NHÓM 07]=",
+ "nhom07",
+ "name",
+ "NHÓM 07: BOT"
+ },
+ {"Cold Clear",
+ "nhom07 cc coldclear ai bot",
+ "term",
+ "Một bot chơi Tetris. Được viết bởi MinusKelvin, ban đầu dành cho Puyo Puyo Tetris.\nBản Cold Clear ở trong Techmino có hỗ trợ All-spin và hệ thống TRS.",
+ },
+ {"ZZZbot",
+ "nhom07 ai bot zzztoj",
+ "term",
+ "Một bot chơi xếp gạch. Được viết bởi một người chơi Tetris Trung Quốc có tên là 奏之章 (Zòu Zhī Zhāng, xem mục bên dưới) và hoạt động khá tốt trong nhiều game (sau khi điều chỉnh thông số). Bạn cũng có thể sử dụng bot này trên TETR.IO",
+ },
+ {"=[NHÓM 08]=",
+ "nhom08",
+ "name",
+ "NHÓM 08: MẸO & LỜI KHUYÊN HỮU ÍCH"
+ },
+ {"Đề xuất l.tập [1/2]",
+ "nhom08 readme noob new guides recommendations suggestions helps; đề xuất luyện tập; người mới chơi; hướng dẫn; lời khuyên; gợi ý",
+ "help",
+[[
+Lời khuyên khi tập chơi (Trang 1/2):
+Chúng tôi có các đề xuất để cải thiện kỹ năng Tetris của bạn (danh sách nằm ở mục tiếp theo).
+Nếu gặp khó khăn trong lúc luyện tập, hãy thư giãn…
+và dành thời gian chơi các chế độ mà bạn yêu thích. Chơi vui vẻ!
+
+Mặc dù các đề xuất này được xếp thành nhóm, hãy làm cả ba nhóm cùng lúc thay vì làm từng cái một.
+
+Mẹo: Bạn có thể điều chỉnh độ khó nhóm C tùy vào khả năng của bạn
+(kiểu như "đừng làm bạn chơi quá chậm")
+
+Sau khi xong nhóm C, hãy luyện tập tiếp nhóm A, đây là kỹ năng RẤT quan trọng trong bất kỳ game xếp gạch nào. Bạn sẽ có thể dần làm chủ bất kỳ chế độ nào trong khi bạn chỉ cần nhìn lướt qua NEXT.
+]],
+ },
+ {"Đề xuất l.tập [2/2]",
+ "nhom08 readme noob new guides recommendations suggestions helps; đề xuất luyện tập; người mới chơi; hướng dẫn; lời khuyên; gợi ý",
+ "help",
+[[
+Lời khuyên khi tập chơi (Trang 2/2):
+Danh sách các đề xuất mà bạn cần làm theo khi tập chơi:
+
+A. Stacking (Xếp gạch)
+ A1. Suy nghĩ kỹ trước khi đặt gạch. Chưa vừa ý? Suy nghĩ thêm lần nữa.
+ A2. Xếp gạch càng phẳng càng tốt để bạn có thể ra quyết định đặt gạch dễ dàng hơn.
+ A3. Lên kế hoạch trước cách xếp, hãy tận dụng tối đa NEXT và HOLD để giữ được thế đẹp.
+
+B. Efficiency & Speed (Hiệu quả & Tốc độ)
+ B1. Trước mỗi lần đặt gạch, hãy suy nghĩ xem bạn sẽ đặt gạch ở đâu? Bấm những phím nào để gạch tới chỗ đó và đứng đúng tư thế? Thay vì dựa dẫm vào bóng gạch quá nhiều
+ B2. Nên sử dụng 2 (hoặc 3, tùy game) phím xoay thay vì nhấn 1 phím xoay liên tục trong thời gian dài.
+ B3. Đừng lo lắng về tốc độ khi bạn mới tập chơi Finesse, đây là chuyện bình thường. Hơn nữa bạn có thể tập chơi nhanh hơn một khi bạn đã quen tay — việc này không khó đâu!
+
+C. Practice (Luyện tập)
+ C1. Hoàn thành chế độ "40 hàng".
+ C2. Hoàn thành chế độ "40 hàng" mà không dùng HOLD.
+ C3. Hoàn thành chế độ "40 hàng" mà chỉ được làm Techrash.
+ C4. Hoàn thành chế độ "40 hàng" mà chỉ được làm Techrash và không được dùng HOLD.
+]]
+ },
+ {"Học làm T-spin",
+ "nhom08 tspin; học; hướng dẫn; mẹo; lời khuyên; đề xuất",
+ "help",
+ [[
+Xin lưu ý rằng T-spin là một kỹ năng khá khó, vì vậy bạn không thể thành thạo nó nếu chỉ đơn thuần nhìn vào địa hình nơi T-spin được thực hiện. Tất nhiên, bạn phải có kỹ năng xếp gạch tốt và có thể nhìn lướt NEXT.
+Nếu bạn thực sự muốn làm T-spin, hãy đảm bảo bạn thành thạo những kỹ năng cơ bản trước khi học và làm.
+
+Lời khuyên của chúng tôi: chỉ nên bắt đầu học làm T-spin khi bạn có thể xóa 40 hàng với ≤ 60s/40-120s (tùy điều kiện), 40 hàng chỉ dùng Tetris, 40 hàng chỉ dùng Tetris + không Hold. Tất cả mà không làm bạn bị tụt tốc độ quá nhiều (phát triển khả năng để xem NEXT và suy nghĩ đủ kỹ trước khi thả rơi gạch.)
+ ]],
+ },
+ {"Hiệu chỉnh DAS",
+ "nhom08 das tuning",
+ "help",
+ "Với những người chơi nâng cao mà muốn chơi nhanh hơn, có thể điều chỉnh DAS thành 4-6 f (67-100 ms) và ARR 0 f (0 ms); đây là hai giá trị khuyên dùng. (Ở ARR 0ms, các viên gạch sẽ ngay lập tức bay vào tường khi bạn vượt qua DAS.)\n\nĐây là cấu hình lý tưởng cho người nâng cao, với chiến lược là cắt giảm DAS trong khi vẫn có thể kiểm soát được gạch một cách tin cậy mặc dù ARR bằng 0 nếu có thể hoặc càng thấp càng tốt.",
+ },
+ {"Bố cục phím",
+ "nhom08 feel",
+ "help",
+ [[
+Dưới đây là vài lời khuyên hữu ích khi bạn đang chỉnh sửa bố cục phím
+
+1. Một ngón tay chỉ nên thực hiện một chức năng khác nhau. Ví dụ như: 1 ngón cho sang trái, 1 ngón cho sang phải, 1 ngón cho phím xoay phải, 1 ngón cho rơi mạnh
+
+2. Trừ khi bạn tự tin với ngót út của mình, thì không nên để ngón tay này làm bất kì việc hết! Ngoài ra, nên xài ngón trỏ và ngón giữa vì hai ngón này là nhanh nhẹn nhất, nhưng bạn cũng có thể thoải mái tìm hiểu xem các ngón tay của mình nhanh chậm thế nào, mạnh yếu ra sao.
+
+3. Không nhất thiết phải sao chép bố cục phím của người khác, vì không ai giống ai. Thay vào đó hãy chỉnh theo cách của bạn, miễn là bạn chơi thoải mái là được.
+ ]],
+ },
+ {"Khả năng xử lý gạch",
+ "nhom08 feel handling",
+ "help",
+ [[
+Những yếu tố ảnh hưởng tới việc xử lý gạch của bạn:
+
+(1) Độ trễ đầu vào, có thể là do cấu hình, thông số hoặc tình trạng của thiết bị. Khởi động lại trò chơi, bảo dưỡng, sửa chữa hoặc thay đổi thiết bị của bạn có thể khắc phục vấn đề này.
+(2) Trò chơi không ổn định/thiết kế quá sơ sài và nhiều lỗi. Có thể giảm tình trạng này bằng cách chỉnh sửa cài đặt hiệu ứng để ở mức thấp.
+(3) Cái gì cũng có mục đích của nó, ngay cả thiết kế cũng vậy. Việc làm quen với chúng có thể giúp bạn.
+(4) Cài đặt thông số xử lý gạch không phù hợp (ví dụ: DAS, ARR, SDARR,…). Thay đổi cài đặt.
+(5) Tư thế chơi ko hợp lý, có thể gây ra bất tiện trong những lúc quan trọng. Nên tìm tư thế chơi phù hợp sao cho thuận tiện khi chơi.
+(6) Thao tác không quen sau khi đổi vị trí phím hay đổi sang thiết bị mới. Tập làm quen với chúng hoặc thay đổi cài đặt có thể hữu ích.
+(7) Mỏi cơ, chuột rút,… làm cho việc phản ứng và phối hợp tay khó khăn hơn. Hãy nghỉ ngơi và trở lại sau một hoặc vài ngày.
+ ]],
+ },
+ {"Các nút xoay",
+ "nhom08 doublerotation hai phím xoay",
+ "help",
+ "Dùng cả nút xoay phải và xoay trái giảm số lầm nút cần nhấn bằng cách thay thế việc nhấn 3 lần nút xoay một bên bằng việc nhấn 1 lần phím xoay bên kia.\nLỗi di chuyển cũng có tính đến việc có sử dụng cả hai nút xoay hay ko.\n\n----------------\n\nSử dụng cả ba nút xoay (nút thứ ba là xoay 180°), tất cả các gạch muốn xoay thì chỉ cần duy nhất nhấn một nút một lần. Tuy nhiên, việc này không phải lúc nào cũng hữu dụng vì không phải game nào đều hỗ trợ cả 3 nút xoay.\nHơn nữa, sự cải thiện về tốc độ khi so sánh dùng 3 nút so với dùng 2 nút không nhiều nếu so sánh chúng với dùng 2 phím so với dùng 1 phím. Bạn có thể bỏ qua kỹ thuật này trừ khi bạn muốn đạt tốc độ cực cao.",
+ },
+ {"=[NHÓM 09]=",
+ "nhom09",
+ "name",
+ "NHÓM 09: WIKI; CÁC TRANG WEB BÀY SETUP, CUNG CẤP CÂU ĐỐ & CHIA SẺ SETUP"
+ },
+ {">A|Wiki",
+ "nhom09a",
+ "name",
+ ""
+ },
+ {"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 Cộng đồng Nghiên cứu Tetris Trung Quốc và các nhóm phụ của nó. 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",
+ },
+ {"Wiki Hard Drop",
+ "nhom09a harddrop hd wiki",
+ "help",
+ "Một wiki về Tetris được host bởi cộng đồng Hard Drop.",
+ "https://harddrop.com/wiki/Tetris_Wiki",
+ },
+ {"Tetris.wiki",
+ "nhom09a tetris wiki",
+ "help",
+ "Tetris.wiki là 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 cách chơi.",
+ "https://tetris.wiki",
+ },
+ {"Tetris Wiki Fandom",
+ "nhom09a tetris wiki fandom",
+ "help",
+ "Cũng là một wiki về Tetris nhưng nó ở trên Fandom",
+ "https://tetris.fandom.com/wiki/Tetris_Wiki",
+ },
+ {">B|Câu đố",
+ "nhom09b",
+ "name",
+ "NHÓM 09B: CÁC TRANG WEB CUNG CẤP CÂU ĐỐ"
+ },
+ {"TTT",
+ "nhom09b tetris trainer tres bien",
+ "game",
+ [[
+Tetris Trainer Très-Bien (viết bởi こな “kona”). Một website chứa các hướng dẫn thực hành các kỹ thuật nâng cao trong Tetris hiện đại (lưu ý: website này chỉ hỗ trợ bàn phím vật lý, không hỗ trợ bàn phím ảo).
+Đề xuất cho những người chơi có thể hoàn thành chế độ 40L chỉ làm Tetris + không dùng Hold
+Website này đề cập tới T-spin, finesse, SRS và một số setup để chơi Battle
+Liên kết sẽ dẫn bạn tới phiên bản tiếng Anh, được dịch bởi User670 (Bản gốc là bản tiếng Nhật).
+ ]],
+ "https://user670.github.io/tetris-trainer-tres-bien/",
+ },
+ {"TTPC",
+ "nhom09b tetris perfect clear challenge",
+ "game",
+ [[
+Tetris Perfect Clear Challenge (viết bởi chokotia). Một website hướng dẫn bạn cách làm Perfect Clear khi sử dụng hệ thống xoay SRS và Bag-7 (chỉ hỗ trợ bàn phím). Đề xuất sử dụng nếu bạn đã hoàn thành TTT và đã làm quen với SRS
+
+Liên kết sẽ dẫn bạn tới phiên bản tiếng Anh, bản gốc là tiếng Nhật
+ ]],
+ "https://teatube.cn/ttpc/ttpc/",
+ },
+ {"NAZO",
+ "nhom09b",
+ "game",
+ [[
+(ナゾ)
+
+Một website chứa các loại câu đố SRS từ dễ đến cực kỳ khó, bao gồm T-spin và All spin. Đề xuất cho những người đã hoàn thành TTT.
+
+Liên kết sẽ dẫn bạn tới bản tiếng Trung Giản thể, nguyên bản bằng tiếng Nhật.
+ ]],
+ "https://teatube.cn/nazo/",
+ },
+ {"TPO",
+ "nhom09b nazo",
+ "game",
+ "Tetris Puzzle O. Một trang web bằng tiếng Nhật được viết bởi TCV100 (có lấy một vài câu đố từ NAZO sang).",
+ "http://121.36.2.245:3000/tpo",
+ },
+ {"4-wide Trainer",
+ "nhom09b nazo",
+ "game",
+ "Một công cụ được viết bởi DDRKirby(ISQ) để học & làm quen 4-wide.",
+ "https://ddrkirby.com/games/4-wide-trainer/4-wide-trainer.html",
+ },
+ {">C|Setup",
+ "nhom09c",
+ "name",
+ "NHÓM 09C: CÁC TRANG WEB BÀY SETUP"
+ },
+ {"Four.lol",
+ "nhom09c four wiki",
+ "help",
+ "Một website chứa các setup để làm opener",
+ "https://four.lol",
+ },
+ {"‘Tetris Hall’",
+ "nhom09c tetris hall",
+ "help",
+ "(テトリス堂)\n\nMột trang web tiếng Nhật, chứa nhiều setup, hướng dẫn cũng như có các minigame. Nó cũng có mô tả chi tiết về PC liên tiếp",
+ "https://shiwehi.com/tetris/",
+ },
+ {"‘Tetris Template Collections’",
+ "nhom09c tetris template collections",
+ "help",
+ "(テトリステンプレ集@テト譜)\n\nMột trang web tiếng Nhật với các setup và các danh mục chi tiết. Hầu hết các setup đều có ảnh minh họa, vì vậy việc chia sẻ với người khác sẽ dễ dàng hơn.",
+ "https://w.atwiki.jp/tetrismaps/",
+ },
+ {"tetristemplate.info",
+ "nhom09c",
+ "help",
+ "(テトリスブログ — PerfectClear)\n\nMột trang web ở Nhật Bản chứa một số setup. Tuy số lượng không bằng các trang web khác nhưng bù lại các setup đều được giải thích rất chi tiết",
+ "https://tetristemplate.info/",
+ },
+ {">D|Chia sẻ setup",
+ "nhom09d",
+ "name",
+ "NHÓM 09D: CÁC TRANG WEB CHIA SẺ SETUP"
+ },
+ {"Fumen",
+ "nhom09d",
+ "help",
+ "Đây là một công cụ chỉnh sửa bảng dành cho Tetris bằng tiếng Nhật. Thường được sử dụng để chia sẻ setup, PC solution (hướng đi để làm PC), v.v. Liên kết của mục này sẽ dẫn bạn tới bản tiếng Anh.",
+ "http://fumen.zui.jp/#english.js",
+ },
+ {"Fumen bản Đ.thoại",
+ "nhom09d fumenformobile fm",
+ "help",
+ "Fumen for Mobile (Fumen bản dành cho Điện thoại)\n\nCũng là Fumen nhưng hỗ trợ cho màn hình cảm ứng",
+ "https://knewjade.github.io/fumen-for-mobile/",
+ },
+ {"=[NHÓM 10]=",
+ "nhom10",
+ "name",
+ "NHÓM 10: CỘNG ĐỒNG"
+ },
+ {"Tetris OL Servers",
+ "nhom10 tetrisonline servers tos",
+ "org",
+ "Hãy lên Google tra “Tetris Online Poland” để tìm server ở Ba Lan.\nCòn nếu tìm server Tetris Online Study được đặt tại Trung Quốc (cung cấp bởi Teatube) thì nhấn vào nút “Mở link”",
+ "https://teatube.cn/tos/",
+ },
+ {
+ "Tetris Việt Nam", -- I will edit it later
+ "nhom10 community vietnam tetris việt nam",
+ "org",
+ [[
+Một trong những cộng đồng xếp gạch tại Việt Nam. Đây là nơi chia sẻ kinh nghiệm và thông tin: bao gồm cả game, các giải đấu và các sự kiên liên quan đến xếp gạch.
+
+Nhấn nút “Mở link” để vào server Discord, còn nếu muốn vào nhóm Facebook thì hãy vào Facebook và tìm nhóm "Tetris Việt Nam"
+ ]],
+ "https://discord.gg/jX7BX9g",
+ },
+ {"=[NHÓM 11]=",
+ "nhom11",
+ "name",
+ "NHÓM 11: XẾP LÊN VÀ ĐÀO XUỐNG"
+ },
+ {"A|Stacking",
+ "nhom11a",
+ "name",
+ "NHÓM 11A: STACKING (XẾP LÊN)\n\nDùng để chỉ việc xếp các gạch mà không để lại một cái lỗ.",
+ },
+ {"Side well",
+ "nhom11a ren combo sidewell",
+ "term",
+ "Một phương pháp xếp gạch mà bạn sẽ để lại một cái lỗ có một chiều rộng nhất định ở một bên bảng .\nSetup Side 1-wide là setup truyền thống để làm Tetris (ví dụ như, Side well Tetris).\nCác loại setup như Side 2-, 3-, hay 4-wide; là những setup được dùng để làm combo. Đối với những người chơi mới, đây là cách hiệu quả nhất để tấn công. NHƯNG, đối thủ có thể dễ dàng tấn công lại bạn, một là chết còn không thì stack của bạn sẽ bị cắt ngắn do bạn phải phản công lại. vì lẽ đó, những người chơi giỏi thường sẽ không xây quá cao, thay vào đó họ sẽ giữ một lượng T-spins và Tetris nhất định để có thể tấn công đối thủ khi đối thủ không có khả năng dọn rác tới.",
+ },
+ {"Center well",
+ "nhom11a ren combo centerwell",
+ "term",
+ "Một phương pháp xếp gạch mà bạn sẽ để lại một cái giếng có chiều rộng nhất định ở giữa bảng.",
+ },
+ {"Partial well",
+ "nhom11a ren combo partialwell",
+ "term",
+ "Một phương pháp xếp gạch mà bạn sẽ để lại một cái giếng có chiều rộng nhất định nhưng không ở giữa hay một bên bảng.",
+ },
+ {"Side 1-wide",
+ "nhom11a s1w side1wide sidewelltetris",
+ "term",
+ "Hay còn gọi là Side well Tetris.\nĐây là cách chơi xếp gạch kinh điển nhất, và để làm được thì bạn sẽ phải xây một cái lỗ (duy nhất) sâu rộng 1 ô ở một mặt bên của bảng. Dễ thực hiện trong Tetris hiện đại và có thể làm tấn công… nửa vời. Nhưng setup này hiếm khi được sử dụng trong những trận đấu hạng cao do hiệu quả của Tetris thấp hơn so với T-spin.",
+ },
+ {"Side 2-wide",
+ "nhom11a s2w side2wide",
+ "term",
+ "Tương tự như Side 1-wide nhưng lỗ rộng 2 ô. Một setup để làm combo phổ biến.\nDễ sử dụng. Những người mới chơi có thể thử và tạo ra tấn công nửa vời khi kết hợp với Hold. Nhưng setup này hiếm khi được sử dụng trong những trận đấu hạng cao, bởi vì tốn thời gian để xây, nhường thời gian cho đối thủ tấn công và có thể làm stack của bạn bị cắt ngắn. Và nó cũng không tốt lắm về mặt hiệu quả (efficiency).",
+ },
+ {"Side 3-wide",
+ "nhom11a s3w side3wide",
+ "term",
+ "Tương tự như Side 1-wide hay Side 2-wide nhưng lỗ rộng 3 ô. Ít phổ biến hơn so với Side 2-wide.\nTuy có thể làm nhiều combo hơn với setup này, nhưng lại khó xây, và dễ làm hỏng combo.",
+ },
+ {"Side 4-wide",
+ "nhom11a s4w side4wide",
+ "term",
+ "Tương tự như Side 1-, 2- hay 3-wide nhưng lỗ rộng 4 ô.\nNếu làm tốt thì nó có thể tạo ra những combo rất ấn tượng. Hơn nữa, setup này mất ít thời gian hơn để xây dựng, vì vậy có thể tranh thủ làm combo trước khi rác đến. Tuy nhiên, bạn vẫn có thể bị bay màu nếu có quá nhiều rác, do đó trong một số trường hợp, nó khó mà có thể áp đảo lại lượng rác tới.",
+ },
+ {"Center 1-wide",
+ "nhom11a c1w center1wide centerwelltetris",
+ "term",
+ "Hay còn gọi là Center well Tetris.\nMột phương pháp xếp gạch mà bạn sẽ để lại một cái hô sâu rộng 1 ô ở giữa bảng. Chủ yếu dùng trong combat bởi vì cho phép làm Tetris và T-spin trong khi nó không quá khó để làm.",
+ },
+ {"Center 2-wide",
+ "nhom11a c2w center2wide",
+ "term",
+ "Tương tự như Center 1-wide, nhưng lỗ rộng 2 ô. Tuy nhiên nó không được phổ biến lắm.",
+ },
+ {"Center 3-wide",
+ "nhom11a c3w center3wide",
+ "term",
+ "Tương tự như Center 1- hay 2-wide, nhưng lỗ rộng 3 ô. Tuy nhiên nó cũng không được phổ biến lắm.",
+ },
+ {"Center 4-wide",
+ "nhom11a c4w center4wide",
+ "term",
+ "Tượng tự như Center 1-, 2- hay 3-wide, nhưng rộng 4 ô.\nĐây là một setup combo không được phổ biến lắm, nhưng cho phép bạn gửi nhiều combo trong khi đánh bật luôn cả điều kiện game over nếu bạn nhận một vài hàng rác. Nhiều người chơi thường ghét kỹ thuật này, bởi vì chúng phá đi sự cân bằng trong game.",
+ },
+ {"Residual",
+ "nhom11a c4w s4w",
+ "term",
+ "Đề cập đến có bao nhiêu gạch được đặt trong cái lỗ khi sử dụng setup combo 4-wide.\nPhổ biến nhất là 3-residual và 6-residual.\n\n3-residual có ít biến thể và dễ học dễ nhớ hơn, và có khả năng thành công cao, rất hữu dựng trong combat.\n6-residual lại có nhiều biến thể hơn và khó học khó xài hơn, nhưng chúng thường ổn định nếu dùng tốt. Residual cũng có thể được sử dụng trong những thử thách đặc biệt như lấy 100 combo trong một thử thánh 4-wide vô tận.\n\nVề nguyên tắc, hãy dùng 6-Res trước, sau đó 5-Res rồi 3-Res, và cuối cùng là 4-Res.",
+ },
+ {"6 — 3 Stacking",
+ "nhom11a 63stacking six-three sixthree",
+ "term",
+ "Một phương pháp để xếp gạch, bạn sẽ phải tạo ra một bức tường cao có chiều rộng rộng 6 ô ở bên trái và một bức tường cao nữa có chiều rộng 3 ô ở bên phải.\nĐối với một người chơi có kỹ năng, phương pháp cho phép người chơi giảm số phím cần nhấn, và đây là một phương pháp phổ biến để chơi Sprint (như 10 hàng, 20 hàng, 40 hàng,…). Phương pháp này hoạt động được nhờ việc gạch xuất hiện hay bị căn lệch về bên trái.",
+ },
+ {">B|Digging",
+ "nhom11b",
+ "name",
+ "Digging (Đào xuống))\n\nDọn hàng rác để tiếp xúc đáy bảng. Hay còn gọi là downstacking.",
+ },
+ {"=[NHÓM 12]=",
+ "nhom12",
+ "name",
+ "NHÓM 12: Setup (Opener, Mid-game setup, Donation, Pattern)"
+ },
+ {">A|FreeStyle",
+ "nhom12a",
+ "name",
+ "Thuật ngữ hay được sử dụng trong thử thách 20TSD. Freestyle nghĩa là hoàn thành thử thách 20TSD mà không sử dụng phương pháp xếp gạch cố định nào. Làm 20TSD với Freestyle khó hơn nhiều so với việc sử dụng phương pháp nào đó như LST, và màn chạy có thể đại diện cho các kỹ năng T-spin có được trong các trận đấu.",
+ },
+ {">B|Opener",
+ "nhom12b",
+ "name",
+ [[
+Opener thường là các setup thường dùng ở đầu trận. Bạn vẫn có thể làm những setup này giữa trận, nhưng thường sẽ yêu cầu một tập hợp các vị trí gạch khác nhau.
+
+Setup này thường phải đạt cả ba yêu cầu sau:
+- Có thể thích ứng với các vị trí gạch khác nhau,
+- Tấn công mạnh, ít lãng phí gạch T,
+- Ít yêu cầu phải Thả nhẹ để có thể đặt gạch nhanh hơn và yêu cầu sử dụng finesse.
+- Có chiến lược rõ ràng và ít nhánh/biến thể.
+
+Đa số opener sẽ tận dụng Kiểu xáo Túi 7 gạch và khai thác một điều thực tế là kiểu xáo gạch này luôn cung cấp một cho mỗi loại gạch sau mỗi 7 gạch khác nhau. Yếu tố này giúp có thể có các setup tin cậy hơn.
+ ]],
+ },
+ {"DT Cannon",
+ "nhom12b dtcannon doubletriplecannon",
+ "setup",
+ "Double-Triple Cannon (Súng thần công T-spin Đôi-Tam).\nĐể có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên wiki Hard Drop",
+ "https://harddrop.com/wiki?search=dt",
+ },
+ {"DTPC",
+ "nhom12b dtcannon doubletriplecannon",
+ "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 “Mở link” để mở bài ở trên wiki Hard Drop",
+ "https://harddrop.com/wiki?search=dt",
+ },
+ {"BT Cannon",
+ "nhom12b btcannon betacannon",
+ "setup",
+ "β Cannon, Beta Cannon.\nĐể có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên wiki Hard Drop",
+ "https://harddrop.com/wiki?search=bt_cannon",
+ },
+ {"BTPC",
+ "nhom12b 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 “Mở link” để mở bài ở trên wiki Hard Drop",
+ "https://harddrop.com/wiki?search=bt_cannon",
+ },
+ {"TKI 3 Perfect Clear",
+ "nhom12b ddpc tki3perfectclear",
+ "setup",
+ "Một opener làm TSD dẫn đến Double-Double-All Clear.\nĐể có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên wiki Hard Drop",
+ "https://harddrop.com/wiki?search=TKI_3_Perfect_Clear",
+ },
+ {"QT Cannon",
+ "nhom12b qtcannon",
+ "setup",
+ "Một setup gần giống với DT Cannon và khả năng gửi DT Attack¹ cao.\nĐể có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên wiki Hard Drop\n\n¹: DT Attack = T-spin Double + T-spin Triple",
+ "https://harddrop.com/wiki?search=QT_cannon",
+ },
+ {"Mini-Triple",
+ "nhom12b mt minitriple",
+ "setup",
+ "Một setup làm Mini T-spin và T-spin Triple.\nĐể có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên wiki Hard Drop",
+ "https://harddrop.com/wiki?search=mt",
+ },
+ {"Trinity",
+ "nhom12b",
+ "setup",
+ "Một setup làm TSD + TSD + TSD hoặc TSMS + TST + TSD. Để có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên wiki Hard Drop",
+ "https://harddrop.com/wiki?search=trinity",
+ },
+ {"Wolfmoon Cannon",
+ "nhom12b wolfmooncannon",
+ "setup",
+ "Một opener.\nĐể có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên wiki Hard Drop",
+ "https://harddrop.com/wiki?search=wolfmoon_cannon",
+ },
+ {"Sewer",
+ "nhom12b",
+ "setup",
+ "Một opener.\nĐể có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên wiki Hard Drop",
+ "https://harddrop.com/wiki?search=sewer",
+ },
+ {"TKI",
+ "nhom12b tki-3 tki3",
+ "setup",
+ "TKI-3. Có thể chỉ TKI-3 bắt đầu bằng một TSD hoặc C-spin bắt đầu bằng một TST.\nĐể có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên wiki Hard Drop",
+ "https://harddrop.com/wiki?search=tki_3_opening",
+ },
+ {"God Spin",
+ "nhom12b godspin",
+ "setup",
+ "Một setup nhìn đẹp mắt [nhưng khó sử dụng trên thực tế]. Được phát minh bởi Windkey.\nĐể có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên wiki Hard Drop",
+ "https://harddrop.com/wiki?search=godspin",
+ },
+ {"Albatross",
+ "nhom12b",
+ "setup",
+ "Một opener nhìn đẹp mắt, nhịp độ nhanh với TSD — TST — TSD — All Clear, khó mà lãng phí được gạch T.\nĐể có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên wiki Hard Drop",
+ "https://harddrop.com/wiki?search=Albatross_Special",
+ },
+ {"Pelican",
+ "nhom12b",
+ "setup",
+ "Một opener kiểu Alabatross được sử dụng trong trường hợp trật tự gạch tới không ủng hộ opener Alabatross gốc.\nĐể có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên wiki Hard Drop",
+ "https://harddrop.com/wiki?search=Pelican",
+ },
+ {"Perfect Clear Opener",
+ "nhom12b 7piecepuzzle",
+ "setup",
+ "Một Opener làm All Clear có khả năng thành công cao (~84.6% nếu bạn đang giữ I trong ô Hold và ~61.2% nếu không giữ). Trong chế độ PC Training (Luyện tập PC), setup này được sử dụng để tạo ra setup chưa hoàn chỉnh, không tạo ra lỗ.\nĐể có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên wiki Hard Drop",
+ "https://harddrop.com/wiki?search=Perfect_Clear_Opener",
+ },
+ {"Grace System",
+ "nhom12b gracesystem 1stpc",
+ "setup",
+ "Một opener làm PC có khả năng thành công ~88.57%. Lỗ hình vuông 4x4 trong chế độ PC Training cũng dựa trên setup này.\nĐể có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên Four.lol",
+ "https://four.lol/perfect-clears/grace-system",
+ },
+ {"DPC",
+ "nhom12b",
+ "setup",
+ "Một setup làm TSD + PC gần như 100% không có gạch nào trong bảng và gạch cuối cùng trong Túi 7 gạch trong hàng đợi NEXT.\nĐể có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên tetristemplate.info.",
+ "https://tetristemplate.info/dpc/",
+ },
+ {"Gamushiro Stacking",
+ "nhom12b",
+ "setup",
+ "(ガムシロ積み) Một opener làm TD Attack (TD Attack = T-spin Triple + T-spin Double).\nĐể có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên wiki Hard Drop",
+ "https://harddrop.com/wiki?search=Gamushiro_Stacking",
+ },
+ {">C|Mid-game",
+ "nhom12c",
+ "name",
+ "NHÓM 12C: MID-GAME SETUP\n\nChỉ những setup cho phép gửi nhiều rác giữa trận. Một số có thể dùng làm opener, nhưng hầu như chúng không cần thiết.",
+ },
+ {"C-spin",
+ "nhom12c cspin",
+ "pattern",
+ "Một setup gửi tấn công bằng T-spin Triple + T-spin Double, known as TKI in Japan.\nĐể có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên wiki Hard Drop",
+ "https://harddrop.com/wiki?search=c-spin",
+ },
+ {"STSD",
+ "nhom12c",
+ "pattern",
+ "Super T-spin Double, một setup cho phép làm T-spin Double.\nNhưng nếu có rác ngay dưới setup này thì không tài nào làm T-spin Double được\nĐể có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên wiki Hard Drop",
+ "https://harddrop.com/wiki?search=stsd",
+ },
+ {"Fractal",
+ "nhom12c fractal spider",
+ "pattern",
+ "Một setup dùng để làm T-spin.\nĐể có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên wiki Hard Drop",
+ "https://harddrop.com/wiki?search=Fractal",
+ },
+ {"LST stacking",
+ "nhom12c",
+ "pattern",
+ "Một setup dùng để làm T-spin với số lượng vô tận.",
+ "https://four.lol/stacking/lst",
+ },
+ {"Imperial Cross",
+ "nhom12c imperialcross",
+ "pattern",
+ "Che lỗ hình chữ thập bằng phần nhô ra để thực hiện hai lần T-spin Double\nĐể có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên wiki Hard Drop",
+ "https://harddrop.com/wiki?search=imperial_cross",
+ },
+ {"King Crimson",
+ "nhom12c kingcrimson",
+ "pattern",
+ "Xếp chồng để làm (các) TSD trên STSD.\nĐể có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên wiki Hard Drop",
+ "https://harddrop.com/wiki?search=King_Crimson",
+ },
+ {"PC liên tiếp (1/3)",
+ "nhom12c pcloop",
+ "pattern",
+ "Bạn có thể tìm hướng dẫn đầy đủ trên “Tetris Hall” từ PC đầu → PC thứ 4 và thứ 7. Sau khi hoàn thành PC thứ 7, bạn đã dùng chính xác 70 gạch và bạn có thể quay lại và làm PC đầu.",
+ "https://shiwehi.com/tetris/template/consecutivepc.php",
+ },
+ {"PC liên tiếp (2/3)",
+ "nhom12c pcloop",
+ "pattern",
+ "four.lol có hướng dẫn cho PC thứ 5 và thứ 6.",
+ "https://four.lol/perfect-clears/5th",
+ },
+ {"PC liên tiếp (3/3)",
+ "nhom12c pcloop",
+ "pattern",
+ "Một hướng dẫn làm vòng lặp PC hoàn chỉnh được viết bởi NitenTeria.",
+ "https://docs.qq.com/sheet/DRmxvWmt3SWxwS2tV",
+ },
+ {">D|Donation",
+ "nhom12d",
+ "name",
+ "NHÓM 12D: DONATION\n\nChỉ những setup cho phép gửi nhiều rác giữa trận. Một số có thể dùng làm opener, nhưng hầu như chúng không cần thiết.",
+ },
+ {"STMB Cave",
+ "nhom12d stmb",
+ "pattern",
+ "STMB cave, một setup dạng donation bằng cách sử dụng S/Z để bịt tường rộng 3 ô và làm T-spin Double.\nĐể có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên wiki Hard Drop",
+ "https://harddrop.com/wiki?search=stmb_cave",
+ },
+ {"Hamburger",
+ "nhom12d",
+ "pattern",
+ "Một setup dạng donation setup dùng để tạo cơ hội làm Tetris.\nĐể có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên wiki Hard Drop",
+ "https://harddrop.com/wiki?search=hamburger",
+ },
+ {"Kaidan",
+ "nhom12d kaidan stairs",
+ "pattern",
+ "Một setup dạng donation có thể làm TSD trên địa hình cầu thang.\nĐể có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên wiki Hard Drop",
+ "https://harddrop.com/wiki?search=kaidan",
+ },
+ {"Shachiku Train",
+ "nhom12d shachikutrain shechu",
+ "pattern",
+ "Một setup dạng donation cho phép làm thêm hai TSD từ setup TST.\nĐể có thêm thông tin, bạn có thể nhấn nút “Mở link” để mở bài ở trên wiki Hard Drop",
+ "https://harddrop.com/wiki?search=Shachiku_Train",
+ },
+ {"Cut Copy",
+ "nhom12d cutcopy",
+ "pattern",
+ "Một setup dạng donation để làm T-spin Double trên một cái lỗ nhỏ và có thể làm thêm một TSD nữa sau đó.",
+ },
+ {"=[NHÓM 13]=",
+ "nhom13",
+ "name",
+ "NHÓM 13: CÁCH TÍNH TẤN CÔNG"
+ },
+ {"Tetris OL attack",
+ "nhom13 top tetrisonlineattack",
+ "term",
+ [[
+Cách tính tấn công trong Tetris Online
+
+Đơn/Đôi/Tam/Tetris gửi 0/1/2/4 hàng rác.
+T-spin Đơn/Đôi/Tam gửi 2/4/6 hàng rác, cắt một nửa nếu là Mini.
+Combo gửi thêm 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5 hàng rác.
+Back to Back gửi thêm 1 (hoặc 2 nếu T-spin Triple).
+All Clear gửi thêm 6 hàng rác. Nhưng 6 hàng rác này sẽ gửi thẳng vào bảng đối thủ, chứ không hủy rác tới.
+ ]],
+ },
+ {"Techmino attack",
+ "nhom13 techminoattack",
+ "term",
+ "Cách tính tấn công trong Techmino\n\nĐể biết công thức tính, hãy xem “hướng dẫn sử dụng” bằng cách nhấn nút "..CHAR.icon.help.." ở màn hình chính của game.\n\nNhấn nút “Mở link” sẽ dẫn bạn tới một bảng tấn công đã được tính sẵn và bạn chỉ cần cộng dồn lại các giá trị bạn muốn để biết kết quả.",
+ "https://media.discordapp.net/attachments/743861514057941204/1093386431096950815/Untitled.jpg"
+ },
+ {"=[NHÓM 14]=",
+ "nhom14",
+ "name",
+ "NHÓM 14: CONSOLE VÀ CHUYỆN QUẢN LÝ DỮ LIỆU GAME"
+ },
+ {"Console",
+ "nhom14 cmd commamd terminal console",
+ "command",
+ "Techmino có một console cho phép kích hoạt tính năng gỡ lỗi và bật các tính năng nâng cao.\nĐể truy cập, hãy chạm vào logo Techmino/nhấn phím C 4 lần, tại màn hình chính.\n\nHành động bất cẩn trong console có thể dẫn đến HƯ HỎNG/ MẤT TOÀN BỘ dữ liệu đã lưu KHÔNG THỂ PHỤC HỒI.\n\nCÓ RỦI RO KHI TIẾN HÀNH\nKHÔNG AI CHỊU TRÁCH NHIỆM MỌI MẤT MÁT CÓ THỂ XẢY RA TRỪ CHÍNH BẠN!",
+ },
+ {"Đặt lại thiết lập",
+ "nhom14 reset setting",
+ "command",
+ "Vào console, gõ “rm conf/setting” sau đó nhấn Enter/Return.\nKhởi động lại Techmino để thay đổi có hiệu lực.\nĐể hoàn tác/hủy bỏ thay đổi đã thực hiện, hãy vào Cài đặt rồi trở ra.",
+ },
+ {"Xóa t.bộ thành tích",
+ "nhom14 reset statistic data",
+ "command",
+ "Xóa toàn bộ thành tích\n\nVào console, gõ “rm conf/data” sau đó nhấn Enter/Return.\nKhởi động lại Techmino để thay đổi có hiệu lực.\nĐể hoàn tác/hủy bỏ thay đổi đã thực hiện, chơi một chế độ bất kỳ sau đó nhận màn hình Thắng/Thua",
+ },
+ {"Đặt lại t.trg mở khóa",
+ "nhom14 reset unlock",
+ "command",
+ "Đặt lại tình trạng mở khóa của (hầu hết) các chế độ trong game\n\nVào console, gõ “rm conf/unlock” sau đó nhấn Enter/Return.\nKhởi động lại Techmino để thay đổi có hiệu lực.\nĐể hoàn tác/hủy bỏ thay đổi đã thực hiện, cập nhật lại tình trạng của một chế độ bất kỳ.",
+ },
+ {"Xóa t.bộ kỷ lục",
+ "nhom14 reset record",
+ "command",
+ "Xóa toàn bộ kỷ lục\n\nVào console, gõ “rm -s record” sau đó nhấn Enter/Return.\nKhởi động lại Techmino để thay đổi có hiệu lực.\nBạn có thể hoàn nguyên hành động này trên cơ sở từng chế độ; chơi một chế độ và cập nhật bảng xếp hạng để khôi phục bảng xếp hạng của chế độ đó.",
+ },
+ {"Đặt lại bố cục phím",
+ "nhom14 reset virtualkey",
+ "command",
+ "Vào console, gõ “rm conf/[File_bố_cục_phím]” sau đó nhấn Enter/Return.\nThay [File_bố_cục_phím] với file cần xóa:\n\tFile bố cục bàn phím trên máy tính: key;\n\tFile bố cục nút trên màn hình: virtualkey;\n\tBản lưu bố cục nút trên màn hình: vkSave1, vkSave2\n\nKhởi động lại Techmino để hai thay đổi đầu tiên có hiệu lực.\nVào một trang chỉnh sửa bố cục phím/nút sau đó trở ra để lấy lại file tương ứng.",
+ },
+ {"Xóa t.bộ bản phát lại",
+ "nhom14 delete recording",
+ "command",
+ "Xóa toàn bộ bản phát lại\n\nVào console, gõ “rm -s replay“ sau đó nhấn Enter/Return.\nHiệu lực tức thì, KHÔNG THỂ HOÀN TÁC",
+ },
+ {"Xóa bộ nhớ đệm",
+ "nhom14 delete cache",
+ "command",
+ "Vào console, gõ “rm -s cache” sau đó nhấn Enter/Return.\nHiệu lực tức thì, KHÔNG THỂ HOÀN TÁC",
+ },
+ {"=[NHÓM 16]=",
+ "nhom15 sfx soundeffects; bgm backgroundmusic; tas; afk",
+ "name",
+ "NHÓM 16: CÁC THUẬT NGỮ KHÔNG LIÊN QUAN TỚI TETRIS (TIẾNG ANH)"
+ },
+ {"SFX",
+ "nhom15 soundeffects",
+ "english",
+ "Từ viết tắt của “Sound Effects” (Hiệu ứng âm thanh). Ở Nhật Bản, từ này được viết tắt là “SE”.",
+ },
+ {"BGM",
+ "nhom15 backgroundmusic",
+ "english",
+ "Từ viết tắt của “Background Music (Nhạc nền).”",
+ },
+ {"TAS",
+ "nhom15",
+ "english",
+ "Từ viết tắt của “Tool-Assisted Speedrun (Superplay)” (Công cụ hỗ trợ Speedrun)\nChơi một game nào đó mà không cần công cụ đặc biệt để phá vỡ quy tắc của game (ở cấp độ chương trình/phần mềm).\nNó thường được sử dụng để đạt điểm tối đa theo lý thuyết/đạt được những mục tiêu thú vị\nMột công cụ TAS như vậy cũng có sẵn, nhưng là bản nhỏ gọn, được đi kèm với Techmino.",
+ },
+ {"AFK",
+ "nhom15",
+ "english",
+ "Từ viết tắt của “Away From Keyboard” nghĩa là hiện đang nghỉ ngơi/làm việc khác VÀ không đụng game.\nNghỉ giải lao thường xuyên giúp bạn giảm căng cơ và giúp bạn chơi tốt hơn khi quay trở lại.",
+ },
+}
diff --git a/parts/language/dict_zh.lua b/parts/language/dict_zh.lua
index 7628ffe58..f7c57b108 100644
--- a/parts/language/dict_zh.lua
+++ b/parts/language/dict_zh.lua
@@ -1,121 +1,177 @@
-local HDsearch="https://harddrop.com/wiki?search="
-local HDwiki="\t更多内容见Hard Drop Wiki。"
-return{
+-- Automatically generated by a Python script, from a markdown source file.
+-- The script can be found here: https://github.com/user670/techmino-dictionary-converter/blob/master/tool.py
+return {
{"新人须知",
"读我 必读 萌新 xinren new noob readme",
"help",
- "致想深入玩下去的新人:\n\n\t两大根本原则:\n\t\t1. 选手感好的版本(Tech/Tetr.io/Jstris/TOP/Tetr.js),别用编程练习渣版本\n\t\t2. 踏实打好基础(预判next稳定消四等),别总想着炫酷T旋,对未来发展没好处。\n\t两大主要技巧:\n\t\t1. 熟悉初始位置以及到各个位置的初始操作;\n\t\t2. 提前计算好下一块能放哪。\n\n推荐阅读专栏《给TOP新人的几点建议》\n\n[点击右下角地球按钮打开链接]",
+ "致想深入玩下去的新人:\n\n\t两大根本原则:\n\t\t1. 选手感好的版本(Tech/Tetr.io/Jstris/TOP/Tetr.js),别用编程练习渣版本\n\t\t2. 踏实打好基础(预判next稳定消四等),别总想着炫酷T旋,对未来实力提升没好处。\n\t两大主要技巧:\n\t\t1. 熟悉初始位置以及到各个位置的初始操作;\n\t\t2. 提前计算好下一块能放哪。\n\n推荐阅读专栏《给TOP新人的几点建议》\n\n[点击右下角地球按钮打开链接]",
"https://bilibili.com/read/cv2352939",
},
+ {"新人学习/练习路线",
+ "读我 必读 萌新 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能力可以让你快速上手任何变种玩法。",
+ },
{"关于T-spin学习",
- "T旋 T转 tspin",
+ "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。",
+ "首先指出:要能熟练做出各种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",
"help",
- "Techmino的官网!\n可以在上面下载游戏本体,或者修改头像以及个人信息。\n\n游戏作者的一些话:强烈不建议在任何公开场合提及甚至宣传本游戏,更不要随便就对外公布我们的官网链接!请务必只在私下里向有基础或真的很有兴趣入坑认真玩的玩家推荐,不然很容易拉低社群质量破坏交流氛围,非常难处理,甚至有可能影响游戏的未来发展。为了保证游戏未来会变得越来越好玩,千万慎重考虑您对游戏的推广方式!感谢您对Techmino的支持!!感谢配合!!!",
- "http://home.techmino.org",
+ "Techmino的官网!\n可以在上面下载游戏本体,或者修改头像以及个人信息。\n\n游戏作者的一些话:强烈不建议在任何公开场合提及甚至宣传Techmino,更不要随便对外发送我们的官网链接!请务必只在私下里向有基础或真的很有兴趣入坑认真玩的玩家推荐,不然很容易拉低社群质量破坏交流氛围,比较难处理,甚至有可能影响游戏的未来发展。为了保证游戏能够变得越来越好玩,千万慎重考虑您对游戏的推广方式!感谢您对Techmino的大力支持!!",
+ "http://studio26f.org",
},
{"灰机Wiki",
- "灰机wiki huiji wiki",
+ "huiji",
"help",
"俄罗斯方块中文维基,由一群来自俄罗斯方块研究群及下属群的方块同好建立的关于俄罗斯方块的中文百科全书。\n\n目前其大部分页面翻译和参考来自Hard Drop Wiki和Tetris Wiki",
"https://tetris.huijiwiki.com",
},
{"HardDrop Wiki",
- "harddrop hard drop hd wiki",
+ "hd",
"help",
"(英文)位于Hard Drop全球俄罗斯方块社区的Wiki百科",
"https://harddrop.com/wiki/Tetris_Wiki",
},
{"Tetris Wiki",
- "tetris wiki",
+ "",
"help",
"(英文)一个专注于创建俄罗斯方块相关内容的Wiki百科,由Myndzi在 2015创办。年复一年,上千玩家贡献了一系列的官块和自制块的说明,游戏的隐藏机制,和提升游戏体验的教程",
"https://tetris.wiki",
},
{"Tetris Wiki Fandom",
- "tetris wiki fandom",
+ "",
"help",
"(英文)一个俄罗斯方块维基",
"https://tetris.fandom.com/wiki/Tetris_Wiki",
},
{"Four.lol",
- "four wiki",
+ "",
"help",
- "(英文,很可能打不开)一个开局定式收集网站,界面很简洁,包含超详细连续PC路线分析(新人勿学,要背的东西超乎你的想象)。",
+ "(英文,很可能打不开)一个开局定式收集网站",
"https://four.lol",
},
-
- --相关网页/组织
+ {"テトリス堂",
+ "",
+ "help",
+ "(日文)包含很多定式、教程和小游戏。内涵2nd、3rd、4th、7th PC的详细说明",
+ "https://shiwehi.com/tetris/",
+ },
+ {"テトリステンプレ集",
+ "",
+ "help",
+ "(日文)テトリステンプレ集@テト譜,包含非常多定式,有很详细的分类。大部分定式带有图片,可以很方便的分享给别人。",
+ "https://w.atwiki.jp/tetrismaps/",
+ },
+ {"tetristemplate.info",
+ "",
+ "help",
+ "(日文)テトリスブログ - PerfectClear,一个收集了定式的网站,量很少但是内容很精细。",
+ "https://tetristemplate.info/",
+ },
+ {"Fumen",
+ "fumen",
+ "help",
+ "(日文)一个方块版面编辑器,可以用于分享定式,PC解法等,用处很多。设置里可以启用英文版。",
+ "http://fumen.zui.jp",
+ },
+ {"Fumen for Mobile",
+ "fumenformobile fm",
+ "help",
+ "(英文)一个方块版面编辑器,添加了对触屏的控制,可以用于分享定式,PC解法等,用处很多。",
+ "https://knewjade.github.io/fumen-for-mobile/",
+ },
+ -- # 相关网页/组织
{"GitHub仓库",
- "源代码 源码 github git sourcecode yuandaima",
+ "源代码 源码 github git sourcecode yuandaima src",
"org",
"Techmino的GitHub仓库地址,欢迎Star",
"https://github.com/26F-Studio/Techmino",
},
- {"研究群",
- "研究群 yanjiu study research",
+ {"Discord服务器",
+ "不和谐 discord",
"org",
- "俄罗斯方块·[研究]群QQ号112897780,“中国俄罗斯方块总群”",
+ "点击下面的按钮加入Techmino的Discord服务器,和大家一起交流!",
+ "https://discord.gg/f9pUvkh",
},
- {"Mew据点",
- "mew tieba forum",
+ {"研究群",
+ "yanjiu study research",
"org",
- "研究群下属的Mew据点(类似贴吧或者Discord的服务器),2021年下半年建立,可以在同一个大社区的各个频道实时聊天,也可以发帖以主题交流,同时还有一个叫图书馆的功能方便各种方块资料整理(还在建设中,目前没多少内容,2021/11/02)",
- "https://mew.fun/n/tetris",
+ "俄罗斯方块·[研究]群QQ号764916351,“中国俄罗斯方块总群”",
},
{"茶服",
- "茶服 tos tea study chafu",
+ "tos tea study chafu",
"org",
"TO-S的添加方法、说明等关于茶服的一切",
- "http://teatube.ltd/tos",
+ "https://teatube.cn/tos/",
},
- {"赞助1",
- "赞助 support weixin vx zhifubao zfb zanzhu daqian",
+FNNS and {"赞助1",
+ "support weixin vx zhifubao zfb zanzhu daqian",
+ "org",
+ "vx/zfb-控制台-support",
+ -- id: support-1
+ -- platform-restriction: apple
+ } or {"赞助1",
+ "support weixin vx zhifubao zfb zanzhu daqian",
"org",
"vx/zfb-控制台-support",
+ -- id: support-1
+ -- platform-restriction: non-apple
},
{"赞助2",
- "赞助 support aifadian afdian zanzhu daqian",
+ "support aifadian afdian zanzhu daqian",
"org",
"Afdian",
- FNNS and"https://b23.tv/BV1uT4y1P7CX"or"https://afdian.net/@MrZ_26",
+ "https://afdian.net/@MrZ_26",
+ -- - id: support-2
+ -- platform-restriction: non-apple
},
- {"赞助3",
- "赞助 support zanzhu daqian",
+FNNS and {"赞助3",
+ "support zanzhu daqian",
"org",
- "P\97\116\114\101\111\110",
- FNNS and"https://b23.tv/BV1uT4y1P7CX"or"https://www.p\97\116\114\101\111\110.com/techmino",
+ "Patreon",
+ -- id: support-3
+ -- platform-restriction: apple
+ } or {"赞助3",
+ "support zanzhu daqian",
+ "org",
+ "Patreon",
+ "https://www.patreon.com/techmino",
+ -- id: support-3
+ -- platform-restriction: non-apple
},
-
- --游戏(题库)
+ -- # 游戏(题库)
{"TTT",
- "教程 ttt trainer tres bien",
+ "教程 trainer tres bien",
"game",
- "Tetris Trainer Très-Bien。现代方块特殊操作手把手教程(推荐使用电脑,移动设备需要外接键盘)\n\t推荐能无Hold纯消四完成40L挑战的人学习\n\t内含T-spin、极简、SRS、部分对战定式介绍等教程\n注:提供的链接是翻译后挂在茶服的版本",
- "http://teatube.ltd/ttt",
+ "全称Tetris Trainer Très-Bien (by こな)。现代方块特殊操作手把手教程(只能键盘操作)\n\t推荐能纯消四完成40L挑战的人学习\n\t内含T-spin、极简、SRS、部分对战定式介绍等教程\n注:提供的链接是翻译后挂在茶服的版本",
+ "https://teatube.cn/ttt/index.html",
},
{"TTPC",
- "pc教程 ttpc",
+ "pc教程",
"game",
- "SRS+Bag7方块游戏开局PC教程(推荐使用电脑,移动设备需要外接键盘)\n\t推荐完成了TTT的人学习(必须先学会SRS)\n\t(不包括六巧板等其它PC定式)\n\n注:提供的链接是翻译后挂在茶服的版本。",
- "http://teatube.ltd/ttpc",
+ "全称TETRIS Perfect Clear Challenge (by chokotia)。SRS+Bag7方块游戏Perfect Clear Opener教程(只能键盘操作)。推荐完成了TTT的人学习(必须先学会SRS)\n\n注:提供的链接是翻译后挂在茶服的版本。",
+ "https://teatube.cn/ttpc/",
},
{"NAZO",
+ "题库",
+ "game",
+ "各类SRS试题\n\t推荐能通过TTT的玩家尝试。\n\t内含各种T-spin/All spin题目,简单到极难题目都有。\n\n注:提供的链接是翻译后挂在茶服的版本。",
+ "https://teatube.cn/nazo/",
+ },
+ {"TPO",
"题库 nazo",
"game",
- "各类SRS试题(手机触屏玩不了)\n\t推荐能通过TTT的玩家尝试。\n\t内含各种T-spin/All spin题目,简单到极难题目都有。\n\n注:提供的链接是翻译后挂在茶服的版本。",
- "http://teatube.ltd/nazo",
+ "全称Tetris Puzzle O。由TCV100制作的题库网站,内含nazo的部分题库。",
+ "http://121.36.2.245:3000/tpo",
},
-
- --游戏(网页)
+ -- # 游戏(网页)
{"注[1]",
"备注 notice",
"game",
- "以下内容是为部分官方和较高人气同人方块游戏的简介。\n其中可能包含一些只代表个人观点的主观评价,写在方括号里面,请不要根据这些评论直接认定游戏的好坏。",
+ "以下内容是为部分官方和较高人气同人方块游戏的简介。\n其中可能包含一些只代表个人观点的主观评价写在方括号里仅供参考,顺便也请不要因为某个方面有欠缺就直接认为 “这个游戏不好”。",
},
{"King of Stackers",
"回合制 网页 手机 kos kingofstackers",
@@ -136,110 +192,107 @@ return{
"https://tetralegends.app",
},
{"Ascension",
- "网页 asc ascension",
+ "网页",
"game",
- "网页游戏 | 单机/多人 | [服务器在国外可能卡]\n简称ASC,使用自己的ASC旋转系统,有不少单机模式(本游戏的堆积模式就来自ASC),对战模式目前处在测试阶段(2021/12/15)",
+ "网页游戏 | 单机/多人 | [服务器在国外可能卡]\n简称ASC,使用自己的ASC旋转系统,有不少单机模式(Techmino的堆积模式就来自ASC),对战模式目前处在测试阶段(2022/04/16)",
"https://asc.winternebs.com",
},
{"Jstris",
- "网页 手机 js jstris",
+ "网页 手机",
"game",
- "网页游戏 | 单机/多人 | 支持移动端 | [服务器在国外可能卡]\n简称JS,有常用的科研向单机模式和自定义各种参数的功能,允许拖放固定尺寸的正方形虚拟按键,但没有任何动画效果。",
+ "网页游戏 | 单机/多人 | 支持移动端 | [服务器在国外可能卡]\n简称JS,有常用的科研向单机模式和自定义各种参数的功能,允许拖放固定尺寸的正方形虚拟按键,没有任何动画效果",
"https://jstris.jezevec10.com",
},
{"TETR.IO",
- "网页 io tetrio tetr.io",
+ "网页 io tetrio",
"game",
"网页游戏 | 单机/多人 | [服务器在国外可能卡]\n简称IO,有排位系统和功能全面的自定义模式,单机模式只有三个。有电脑客户端下载(优化性能,无广告)。\n[Safari浏览器似乎打不开]",
"https://tetr.io",
},
{"Nuketris",
- "网页 nuketris he",
+ "网页 核 he",
"game",
"网页游戏 | 单机/多人 | [服务器在国外可能卡]\n有几个基础单机模式和1V1排位。",
- "https://nuketris.herokuapp.com/",
+ "https://nuketris.com/",
},
{"Worldwide Combos",
- "网页 wwc worldwidecombo",
+ "网页 wwc",
"game",
"网页游戏 | 单机/多人 | [服务器在国外可能卡]\n简称WWC,全世界匹配制1V1。特色:有录像战,匹配的对手可以不是真人;几种不同风格的大规则;炸弹垃圾行对战。",
"https://worldwidecombos.com",
},
{"Tetris Friends",
- "网页 tf tetrisfriends",
+ "网页 tf",
"game",
"网页游戏 | 单机/多人\n简称TF,已经关服了的网页版方块。以前人比较多,后来官服倒闭了热度下去了,不过现在有人架了私服还可以体验到。",
"https://notrisfoes.com",
},
- {"Tetris.com",
- "网页 手机 tetris online",
+ {"tetris.com",
+ "网页 手机",
"game",
"网页游戏 | 单机 | 支持移动端\ntetris.com官网上的俄罗斯方块,只有马拉松一种模式,特色是支持基于鼠标指针位置的智能控制。",
},
{"Tetris Gems",
- "网页 宝石 tetris online gems",
+ "网页 宝石",
"game",
"网页游戏 | 单机\ntetris.com官网上的俄罗斯方块,限时1分钟挖掘,有重力机制。\n有三种消除后可以获得不同功能的宝石方块。",
},
{"Tetris Mind Bender",
- "网页 技能 tetris online mindbender",
+ "网页 技能",
"game",
"网页游戏 | 单机\ntetris.com官网上的俄罗斯方块,在马拉松基础上添加了技能,场地上会随机冒出技能方块,消除后会得到各种各样或好或坏的技能。",
},
-
- --游戏(跨平台)
+ -- # 游戏(跨平台)
{"Techmino",
- "铁壳米诺 方块研究所 techmino tieke",
+ "铁壳米诺 方块研究所 tieke",
"game",
"跨平台 | 单机/多人\n简称Tech,使用LÖVE引擎开发的一款方块游戏,单机模式和各种设置都很齐全,联机正在逐渐开发中。",
},
{"Falling Lightblocks",
- "手机 fl fallinglightblocks",
+ "手机 fl",
"game",
- "网页游戏/iOS/Android | 单机/多人\n一个全平台块,横竖屏,有延迟并且不可调。手机支持自定义键位,主要玩法基于NES块设计,也有现代模式。对战为半即时半回合制,无攻击缓冲不可抵消。"
+ "网页游戏/iOS/Android | 单机/多人\n一个全平台块,横竖屏,有延迟并且不可调。手机支持自定义键位,主要玩法基于NES块设计,也有现代模式。对战为半即时半回合制,无攻击缓冲不可抵消。",
},
{"Cambridge",
- "剑桥 cambridge",
+ "剑桥",
"game",
"跨平台 | 单机\n使用LÖVE引擎开发的一款方块游戏,致力于创建一个轻松高度自定义新模式的方块平台。最初由Joe Zeng开发,于2020/10/08的0.1.5版开始Milla接管了开发。 — Tetris Wiki.",
},
{"Nanamino",
- "nanamino",
+ "",
"game",
"Windows/Android | 单机\n块圈玩家自制方块,正在开发中,有一个原创旋转系统。",
},
-
- --游戏(街机/类街机)
+ -- # 游戏(街机/类街机)
{"TGM",
- "俄罗斯方块大师 tgm3 tetrisgrandmaster",
+ "俄罗斯方块大师 tetrisgrandmaster",
"game",
"Windows | 单机/本地双人\n全称Tetris The Grand Master,一个街机方块系列(有修改过的版本可以在大多数Windows电脑运行),S13/GM等称号都出自该作。\n\n其中TGM3目前玩得最普遍,部分模式说明:\n\nMaster:大师模式,有段位评价,拿到更高段位点的要求:非消一的连击和消四,字幕战中消除和通关,每100的前70小于【标准时间,上一个0~70秒数+2】中小的一个,每100总用时不能超过限定值(不然取消上一个方法的加分并反扣点数);到500若没有进标准时间会强制结束游戏(称为铁门);字幕战有两个难度,半隐和全隐,后者必须拿到几乎全部的段位点才能进,消除奖励的段位点也更多。\n\nShirase:死亡模式,类似于techmino中的20G-极限,开局就是高速20G,500和1000有铁门,500开始底下开始涨垃圾行,1000开始出现骨块,1300通关进入大方块字幕战;段位结算:每通100加1段从S1到S13,如果通关了字幕战就会有金色的S13\n\n更多内容详见链接",
- "http://teatube.ltd/TGMGUIDE/",
+ "https://teatube.cn/TGMGUIDE/",
},
{"DTET",
- "dtet",
+ "",
"game",
"Windows | 单机\n单机方块游戏,基于经典规则加入了20G和一个强大的旋转系统,但是除了键位其他参数都不可自定义。有点难找到,而且找到后可能还要自己补齐缺的DLL文件。",
},
{"Heboris",
- "hb heboris",
+ "hb",
"game",
"Windows | 单机\n一个仿街机方块游戏,可以模拟多个方块游戏的部分模式。",
},
{"Texmaster",
- "txm texmaster",
+ "txm",
"game",
"Windows | 单机\n简称Tex,包含TGM的所有模式,可以用来练习TGM,但World规则不完全一样(如软降到底无锁延,踢墙表有细节不同等)。",
},
-
- --游戏(其他)
+ -- # 游戏(其他)
{"Tetris Effect",
"效应 tec tetriseffectconnected xiaoyinglianjie",
"game",
"PS/Oculus Quest/Xbox/NS/Windows | 单机/多人\n简称TE(C),特效方块游戏。不带Connected的基础版本只有单机模式。\n拓展版本Tetris Effect: Connected增加了联网对战,包含Boss战、Zone对战、经典块对战和分数对战四个模式。",
},
{"Tetris 99",
- "吃鸡 t99 tetris99",
+ "吃鸡 t99",
"game",
"NS | 单机/多人\n简称T99,主玩99人混战的吃鸡模式,战术比重比较大,胜率不只由玩家在平时1V1时的水平决定。\n也有一些常用单机模式如马拉松等。",
},
@@ -249,38 +302,38 @@ return{
"PS/NS/Xbox/Windows | 单机/多人\n简称PPT,将方块和 Puyo Puyo 两个下落消除游戏放到一个游戏里,二者可以对战,联机单机模式都很多。另有一拓展版本Puyo Puyo Tetris 2。\n[Steam PC版相对NS版手感和网络等都不太好]",
},
{"Tetris Online",
- "top tetris online study",
+ "top study",
"game",
- "Windows | 单机/多人\n简称TO,主要用来6人内对战/单挑/刷每日40L榜/挖掘模式/打机器人。支持自定义DAS/ARR但都不能到0。\n现在还开着的服务器有:\nTO-P(波兰服,服务器在波兰,可能会卡顿)\nTO-S(研究服,研究群群友自己开的服,很稳定,需要进群注册)\nTO-X(千雪服,VUP星月千雪于20年9月开的服,还处于实验阶段)",
+ "Windows | 单机/多人\n简称TO,主要用来6人内对战/单挑/刷每日40L榜/挖掘模式/打机器人。支持自定义DAS/ARR但都不能到0。\n现在还开着的服务器有:\nTO-P(波兰服,服务器在波兰,可能会卡顿)\nTO-S(研究服,研究群群友自己开的服,很稳定,需要进群注册)",
},
{"Tetra Online",
- "to tetraonline",
+ "to",
"game",
"Windows/macOS/Linux | 单机/多人\n简称TO,由Dr Ocelot和Mine两人开发\n故意设计为延迟较多,平时玩无延迟方块的玩家可能会不习惯。\n2020年12月9日收到来自TTC的DMCA警告信于是被迫停止开发,在一段时间后关服并下架Steam。\n现在在GitHub上面还可以下到Windows的Offline Build。\n[UI部分模仿了PPT,音乐不错,攻击特效好看。]",
"https://github.com/Juan-Cartes/Tetra-Offline/releases/tag/1.0",
},
{"Cultris II",
- "文艺方块 c2 cultris2 cultrisii",
+ "文艺方块 c2 cultris2",
"game",
"Windows/OS X | 单机/多人\n简称C2,设计基于经典规则出发,支持自定义DAS/ARR,对战的主要玩法是基于时间的连击,考验玩家速度/Wide打法/挖掘。\n[游戏作者太久没有更新Mac版导致macOS Catalina以后的系统无法运行]",
},
{"Nullpomino",
- "np nullpomino",
+ "np",
"game",
"Windows/macOS/Linux | 单机/多人\n简称NP,整个游戏自定义程度极高,几乎任何参数都可以自己设置,是一个专业级方块。\n[不过UI风格比较老,需要全键盘操作,刚开始可能不习惯。macOS Monterey貌似无法运行。]",
},
{"Misamino",
- "回合制 misamino",
+ "回合制",
"game",
"Windows | 单机\n块圈玩家自制方块,单机1v1,主玩回合制模式,可以自定义AI(自己写的话需要了解接口)。",
},
{"Touhoumino",
- "东方 车万 偷猴 touhoumino chewan dongfang th",
+ "东方 车万 偷猴 chewan dongfang th",
"game",
- "Windows | 单机\n块圈玩家自制方块,一个Nullpomino的自带资源包的改版,将东方Project元素与俄罗斯方块结合。马拉松模式结合了东方Project里的”符卡”机制,需要在一定时间内达成目标分数才能击破。\n[难度较大,适合有方块基础并且各项能力都较强的玩家游玩(不然都不知道自己怎么死的)。]",
+ "Windows | 单机\n块圈玩家自制方块,一个Nullpomino的自带资源包的改版,将东方Project元素与俄罗斯方块结合。马拉松模式结合了东方Project里的 “符卡” 机制,需要在一定时间内达成目标分数才能击破。\n[难度较大,适合有方块基础并且各项能力都较强的玩家游玩(不然都不知道自己怎么死的)。]",
},
{"Tetris Blitz",
- "闪电战 tetris blitz ea",
+ "闪电战 ea",
"game",
"iOS/Android | 单机/多人\n简称闪电战,EA代理的一款移动端方块,有重力连锁机制,限时2分钟,游戏开始会掉下一堆小方块;持续消行会进入Frenzy模式(场地下方会不断冒出垃圾行,帮助玩家制造大连锁,如果多次落块没有消行会强制结束Frenzy)。有非常多的道具。\n当新出现的方块与场地现有方块重叠时,场地最上方的几行会被自动清除,游戏不结束。已于2020年4月下架。",
},
@@ -290,9 +343,9 @@ return{
"iOS/Android | 单机/多人?\nEA代理的一款宇宙主题的移动端方块。有滑动操控和单点触控两种操作模式;除经典的马拉松外还有一个星系模式(地图挖掘),有重力连锁机制,目标是在限定块数内消除所有地图块。\n已于2020年4月下架。",
},
{"Tetris Beat",
- "节奏 tetris beat n3twork",
+ "节奏 n3twork",
"game",
- "iOS | 单机\nN3TWORK代理的一款移动端方块。除了马拉松以外游戏还有一个“Beat”模式,但只需根据BGM的节奏落块就可以得到额外分数。\n[特效比较瞎眼,不支持自定义键位,而且默认的按钮也很小导致控制也不是很舒服]",
+ "iOS | 单机\nN3TWORK代理的一款移动端方块。除了马拉松以外游戏还有一个 “Beat” 模式,但只需根据BGM的节奏落块就可以得到额外分数。\n[特效比较瞎眼,不支持自定义键位,而且默认的按钮也很小导致控制也不是很舒服]",
},
{"Tetris (N3TWORK)",
"Tetris n3twork",
@@ -300,158 +353,155 @@ return{
"iOS/Android | 单机/多人\nN3TWORK代理的一款移动端方块,有马拉松、3分钟限时打分和Royale(最多100人对战)模式。\n[UI设计比较不错,但不支持自定义键位,而且默认的按钮也很小导致控制也不是很舒服]",
},
{"俄罗斯方块环游记",
- "环游记 tetris journey huanyouji",
+ "tetris journey huanyouji",
"game",
- "iOS/Android | 单机/多人\n简称环游记,国内第一款正版授权手游方块。有闯关模式、对战模式和几个单机模式。闯关模式有各种各样有趣规则大多数有重力连锁,对战规则同现代方块,可以自定义虚拟按键的大小和位置,但是不能自定义DAS/ARR。",
+ "iOS/Android | 单机/多人\n简称环游记,国内第一款正版授权手游方块。有闯关模式、对战模式和几个单机模式。闯关模式有各种各样有趣规则大多数有重力连锁,对战规则同现代方块,可以自定义虚拟按键的大小和位置,但是不能自定义DAS/ARR。已于2023年2月15日停服。",
},
{"JJ块",
- "手机 jj gougou",
+ "手机 gougou",
"game",
- "Android | 单机/多人\nJJ棋牌平台下一个休闲游戏,Android端百度“JJ比赛”官网下载平台后可以找到(找不到的原因是iOS系统或者没在官网下载或者被限制不可直接访问游戏)。竖屏,输入延迟很小,可自定义DAS/ARR/20G软降,简单自定义键位,无Hold,没有B2B,无攻击缓冲不可抵消,每次攻击上限为4,连击较强,其他同现代方块。",
+ "Android | 单机/多人\nJJ棋牌平台下一个休闲游戏,Android端百度 “JJ比赛” 官网下载平台后可以找到(找不到的原因是iOS系统或者没在官网下载或者被限制不可直接访问游戏)。竖屏,输入延迟很小,可自定义DAS/ARR/20G软降,简单自定义键位,无Hold,没有B2B,无攻击缓冲不可抵消,每次攻击上限为4,连击较强,其他同现代方块。",
},
{"火拼俄罗斯",
- "火拼俄罗斯 huopin qq",
+ "huopin qq",
"game",
"Windows | 多人\n腾讯游戏大厅的方块,场地12列,打字的 DAS 和 ARR,1 Next无 Hold,攻击途径只有消4打3、 消3打2,垃圾行为国际象棋棋盘式,几乎不可能挖掘。",
},
-
- --术语(缩写)
+ -- # 术语(缩写)
{"LPM",
- "lpm sudu",
+ "速度 sudu",
"term",
- "Line Per Minute\n行每分,体现玩家下块速度。\n\n注:不同游戏中显示的LPM算法可能不一样,例如TO中的LPM是用PPS换算的,每1PPS=24LPM,忽略掉了垃圾行的影响,不再是字面意思,本游戏中使用L'PM代表这种换算后的LPM。",
+ "Line Per Minute\n行每分,体现玩家下块速度。\n\n注:不同游戏中显示的LPM算法可能不一样,例如TO中的LPM是用PPS换算的,每1PPS=24LPM,忽略掉了垃圾行的影响,不再是字面意思,Techmino中使用L’PM代表这种换算后的LPM。",
},
{"PPS",
- "pps sudu",
+ "速度 sudu",
"term",
"Piece Per Second\n块每秒,体现玩家下块速度。",
},
{"BPM",
- "bpm sudu",
+ "速度 sudu",
"term",
"Block Per Minute\n块每分,体现玩家下块速度\n又称PPM(Piece Per Minute)",
},
{"KPM",
- "kpm sudu",
+ "速度 sudu",
"term",
"Key Per Minute\n按键每分,体现玩家按键速度。",
},
{"KPP",
- "kpp anjian",
+ "按键 anjian",
"term",
"Key Per Piece\n按键每块,体现玩家操作是否繁琐。\n学会极简提升操作效率以减少此数字。",
},
{"APM",
- "apm attack gongji",
+ "攻击 attack gongji",
"term",
"Attack Per Minute\n攻击每分,即玩家每分钟能打出的垃圾行数。\n一定程度体现玩家攻击力。",
},
{"SPM",
- "spm send gongji",
+ "发送 送出 发出 send gongji",
"term",
- "Send Per Minute\n送出每分,即玩家每分钟实际打出去给对手的垃圾行数。\n一定程度体现玩家给对手实际造成的攻击力。",
+ "[lines] Sent per minute\n送出每分,即玩家每分钟实际打出去给对手的垃圾行数。\n一定程度体现玩家给对手实际造成的攻击力。",
},
{"DPM",
- "dpm dig defend",
+ "挖掘 防御 防守 dig defend",
"term",
"Dig/Defend Per Minute\n挖掘每分,即玩家每分钟向下挖掘的垃圾行数。\n某些时候可以体现玩家生存能力。\n\n或:防御(抵消+挖掘)每分。",
},
{"RPM",
- "rpm receive jieshou",
+ "接收 接受 receive jieshou",
"term",
"Receive Per Minute\n接收每分,即玩家每分钟收到来自对手的垃圾行数。\n一定程度体现玩家被对手施加的压力。",
},
{"ADPM",
- "adpm attack defend vs",
+ "攻击 防御 防守 attack defend vs",
"term",
- "Atk+Dig Per Minute\n攻击+挖掘每分,用于在同一局游戏内对比玩家间水平差距,比APM更准确一些。在TETR.IO中叫VS的数据就是ADPM(调整过比例,具体是Atk + Dig per 100s)",
+ "Atk & Dig Per Minute\n攻击+挖掘每分,用于在同一局游戏内对比玩家间水平差距,比APM更准确一些。在TETR.IO中叫 “VS” 的数据就是ADPM(调整过比例,具体是Atk & Dig per 100s)",
},
{"APL",
- "apl xiaolv",
+ "效率 xiaolv xiaolyu",
"term",
- "Attack Per Line\n攻击每行,也叫效率,体现玩家攻击的行利用率。",
+ "Attack Per Line\n攻击每行,也叫效率,体现玩家攻击的行利用率。例如消四和T旋的效率就比消二和消三高。",
},
-
- --术语(消除名)
+ -- # 术语(消除名)
{"Single",
- "1 single xiaoyi",
+ "1 xiaoyi",
"term",
"一次消除一行。",
},
{"Double",
- "2 double xiaoer",
+ "2 xiaoer",
"term",
"一次消除两行。",
},
{"Triple",
- "3 triple xiaosan",
+ "3 xiaosan",
"term",
"一次消除三行。",
},
{"Techrash",
- "4 tetris techrash xiaosi",
+ "4 tetris xiaosi",
"term",
- "一次消除四行(Techmino限定名称)。",
+ "一次消除四行(Techmino限定)。",
},
{"Tetris",
- "4 tetris xiaosi",
+ "4 xiaosi",
"term",
- "商标,Tetris游戏名,同时也是别的方块游戏里消四行的名字。\n含义是Tetra(古希腊语 四)+Tennis(游戏原作者喜欢的运动)。\n现在版权在TTC(The Tetris Company) 手上, 任天堂和世嘉开发游戏是 TTC 授权的, 它们自己并没有Tetris的版权。",
+ "商标,Tetris游戏名,同时也是别的方块游戏里消四行的名字。\n含义是Tetra(古希腊语, 四 <τέτταρες>)+ Tennis(网球 游戏原作者喜欢的运动)。\n现在版权在TTC(The Tetris Company)手上,任天堂和世嘉开发游戏是 TTC 授权的, 它们自己并没有Tetris的版权。",
},
{"PC",
- "全消 全清 pc perfectclear ac allclear quanxiao quanqing",
+ "全消 全清 perfectclear ac allclear quanxiao quanqing",
"term",
"Perfect Clear(也叫All Clear,全消,或全清)。\n消除场地上所有的方块。",
},
{"HPC",
- "hpc hc clear banqing banquanqing banquanxiao",
+ "hc clear banqing banquanqing banquanxiao",
"term",
- "Half-PC\nPC(全消)的外延,“下方有剩余方块”的全消(特别地,如果只消1行则必须不剩余玩家放置的方块),能打出一些攻击和防御(Techmino限定)。",
+ "Half-PC\nPC(全消)的外延,“下方有剩余方块” 的全消(特别地,如果只消1行则必须不剩余玩家放置的方块),能打出一些攻击和防御(Techmino限定)。",
},
-
- --术语(旋转相关)
+ -- # 术语(旋转相关)
{"Spin",
- "转 spin xuanzhuan zuandong",
+ "转 xuanzhuan zuandong",
"term",
"(部分游戏中)使用旋转将方块卡进不能直接移动进入的位置,具体判定规则不同游戏不一样,可能会有攻击加成。",
},
{"Mini",
- "迷你 mini",
+ "迷你",
"term",
"Spin附加Mini后攻击会弱化,用于平衡不同难易度的T-spin攻击,判定在不同游戏都不一样,而且大多数很不好理解,建议只记住常见形状即可。",
},
{"All Spin",
"allspin",
"term",
- "一种规则,指所有方块的Spin都有攻击力,而不止是T-spin才有攻击(即T-spin Only)。",
+ "一种规则,指所有方块的Spin都有攻击力,而不止是T-spin才有攻击(即T-Spin Only)。",
},
- {"T-spin",
+ {"T-Spin",
"T转 T旋 旋转 tspin txuan",
"term",
"在官方规则中,当T方块在锁定前的最后一个操作是旋转,并且锁定后旋转中心对应的四个斜角位置有三个不是空气,那么这就是一个T-spin。\nPS:如果满足一些额外条件会被打上mini标签减少攻击力。",
},
{"TSS",
- "tss t1 tspin",
+ "t1 tspin",
"term",
- "T-Spin Single\n指T方块Spin消1行。简称T1。",
+ "T-Spin Single\n指使用T方块Spin并一次消除1行。简称T1。",
},
{"TSD",
- "tsd t2 tspin",
+ "t2 tspin",
"term",
- "T-spin Double\n指T方块Spin消2行。简称T2。",
+ "T-spin Double\n指使用T方块Spin并一次消除2行。简称T2。",
},
{"TST",
- "tst t3 tspin",
+ "t3 tspin",
"term",
- "T-spin Triple\n指T方块Spin消3行。简称T3。",
+ "T-spin Triple\n指使用T方块Spin并一次消除3行。简称T3。",
},
{"MTSS",
- "mtss mini tspin",
+ "mini tspin minitspinsingle tsms tspinminisingle",
"term",
- "Mini T-spin Single\n指T方块Mini Spin消1行(不同游戏判定不一样)。\n部分游戏中可能叫做“T-Spin Mini”。",
+ "Mini T-spin Single\n指T方块Mini Spin消1行(不同游戏判定不一样)。\n部分游戏中可能叫做 “T-Spin Mini”。",
},
{"MTSD",
- "mtsd mini tspin",
+ "mini tspin minitspindouble tsmd tspinminidouble",
"term",
"Mini T-spin Double\n指T方块Mini Spin消2行(仅部分游戏内存在且判定不一样)。",
},
@@ -460,18 +510,18 @@ return{
"term",
"由于O方块旋转后形状不变,只能左右移动,所以经常被卡住,于是方块圈就有了O-spin的梗:\n有人做过T99/TF中的O变形的特效视频且广为流传;\nT-ex设计的旋转系统可以用spin使O传送进坑;\nTech设计的变形系统中可以旋转O来变形/传送进入一些特定形状的洞。",
},
- {"旋转系统(踢墙)",
+ {"旋转系统 (踢墙)",
"旋转系统 踢墙 xuanzhuanxitong wallkick tiqiang",
"term",
- "现代方块游戏中,方块可以绕着旋转中心(在本游戏中可见)旋转(部分游戏没有固定中心),如果旋转后和场地或墙壁有重合,会根据<从哪个方向转到哪个方向>进行一些偏移测试(这个偏移称为踢墙),不会卡住转不动,同时也可以让方块钻进入一些特定形状的洞。",
+ "现代方块游戏中,方块可以绕着旋转中心(Techmino中可见)旋转(部分游戏没有固定中心),如果旋转后和场地或墙壁有重合,会根据<从哪个方向转到哪个方向>进行一些偏移测试(这个偏移称为踢墙),不会卡住转不动,同时也可以让方块钻进入一些特定形状的洞。不同的旋转系统偏移位置顺序都不一样,具体数据去各大Wiki上查,一堆数字这里就不放了",
},
{"方块朝向",
"旋转 朝向 xuanzhuan chaoxiang orientation direction 0r2l 02 20 rl lr",
"term",
- "在SRS或者类SRS的旋转系统中需要说明方块朝向的时候,“朝下”“竖着”等词描述太模糊。\nSRS中每种方块的初始状态固定,所以我们使用0(原位)、R(右,即顺时针转一次)、2(转两下,即180°)、L(左,即逆时针转一次)四个字符表示方块的四种状态,从原位(0)开始顺时针转一圈四个状态是0R2L。\n最早见于SRS踢墙表的行首,0→L表示原位逆时针转一次到L状态,0→R表示原位顺时针转一次到R状态,2→R代表从180°状态逆时针转一次到R状态。",
+ "在SRS或者类SRS的旋转系统中需要说明方块朝向的时候,“朝下” “竖着” 等词描述太模糊。\nSRS中每种方块的初始状态固定,所以我们使用0(原位)、R(右,即顺时针转一次)、2(转两下,即180°)、L(左,即逆时针转一次)四个字符表示方块的四种状态,从原位(0)开始顺时针转一圈四个状态是0R2L。\n最早见于SRS踢墙表的行首,0→L表示原位逆时针转一次到L状态,0→R表示原位顺时针转一次到R状态,2→R代表从180°状态逆时针转一次到R状态。",
},
{"ARS",
- "旋转系统 ars rotate",
+ "旋转系统 rotate",
"term",
"Arika Rotation System,TGM系列使用的旋转系统(3代中的C模式)\n或者\nAtari Rotation System,一个左上对齐旋转系统。",
},
@@ -483,68 +533,67 @@ return{
{"ASC+ RS",
"旋转系统 asc+rs ascplusrs rotate",
"term",
- "Techmino中对ASC的修改版本,添加了180°转的踢墙表。",
+ "Techmino中ASC的修改版本,添加了180°转的踢墙表。",
},
{"BRS",
- "旋转系统 brs rotate",
+ "旋转系统 rotate",
"term",
"BPS Rotation System\nBPS块使用的旋转系统。",
},
{"BiRS",
- "旋转系统 birs rotate",
+ "旋转系统 rotate",
"term",
"Bias Rotation System\nTechmino原创旋转系统,基于XRS和SRS设计。\n当左/右/下(软降)被按下并且那个方向顶住了墙,按旋转后会先设定一个偏移(三个键朝各自方向加1格),在偏移的基础上试踢墙表里的位移(全都失败了会先取消向下的偏移再把踢墙重新试一遍,再都不行就取消左右,再不行就失败)。\nBiRS相比XRS只使用一个踢墙表更容易记忆,并且保留了SRS翻越地形的功能。\n\n细节补充:在测试踢墙时要满足两个条件,最终位移欧氏距离不能超过√5,并且存在水平偏移时最终水平位移必须和它不反向。",
},
{"C2RS",
- "旋转系统 c2rs rotate",
+ "旋转系统 rotate",
"term",
"Cultris II Rotation System\nCultris II原创的旋转系统,所有旋转共用一个表,顺序是:\n左1→右1→下1→左下→右下→左2→右2\n注意,左优先于右。",
},
{"C2sym",
- "旋转系统 c2sym rotate",
+ "旋转系统 rotate",
"term",
- "Techmino中对C2RS的修改版本,根据不同的方块形状和状态,各自选择优先测试左还是右。",
+ "Techmino中C2RS的修改版本,根据不同的方块形状和状态,各自选择优先测试左还是右。",
},
{"DRS",
- "旋转系统 drs rotate",
+ "旋转系统 rotate",
"term",
"DTET Rotation System.",
},
{"NRS",
- "旋转系统 nrs rotate",
+ "旋转系统 rotate",
"term",
- "Nintendo Rotation System.",
+ "Nintendo Rotation System,NES和GB块使用的旋转系统。NRS有两个互为镜像的版本,左旋版用于GB,右旋版用于NES。",
},
{"SRS",
- "超级旋转系统 srs rotate",
+ "超级旋转系统 rotate",
"term",
"Super Rotation System\n现代方块最常用的旋转系统,也是不少自制旋转系统的设计模板。\n对于SRS,每个方块有四个方向,可以朝两边转(180°不算,最开始没有这个设计),所以总共8种,对应8个偏移表,具体数据去Wiki上查,这里就不放了。",
"https://tetris.wiki/Super_Rotation_System",
},
{"SRS+",
- "超级旋转系统 srs+ srsplus rotate",
+ "超级旋转系统 srsplus rotate",
"term",
"SRS的拓展版,添加了180°转的踢墙表。",
},
{"TRS",
- "旋转系统 trs rotate",
+ "旋转系统 rotate",
"term",
"Techmino Rotation System\nTechmino原创旋转系统,基于SRS设计,修补了一些常见SZ卡死的地形,增加了不少实用踢墙。\n每个五连块也基本按照SRS的Spin逻辑单独设计了踢墙表。\n更有神奇O-spin等你探索!",
},
{"XRS",
- "旋转系统 xrs rotate",
+ "旋转系统 rotate",
"term",
- "X Rotation System\nT-ex原创旋转系统,引入了“按住方向键换一套踢墙表”的设定(在对应的方向需要顶住墙),让“想去哪”能被游戏捕获从而转到玩家希望到达的位置。\n\n其他旋转系统无论踢墙表怎么设计,块处在某个位置时旋转后最终只能按固定顺序测试,这导致不同的踢墙是竞争的,若存在两个可能想去的位置就只能二选一,XRS解决了这个问题。",
+ "X Rotation System\nT-ex原创旋转系统,引入了 “按住方向键换一套踢墙表” 的设定(在对应的方向需要顶住墙),让 “想去哪” 能被游戏捕获从而转到玩家希望到达的位置。\n\n其他旋转系统无论踢墙表怎么设计,块处在某个位置时旋转后最终只能按固定顺序测试,这导致不同的踢墙是竞争的,若存在两个可能想去的位置就只能二选一,XRS解决了这个问题。",
},
-
- --术语(其他)
+ -- # 术语(其他)
{"B2B",
- "大满贯 b2b btb backtoback",
+ "大满贯 btb backtoback",
"term",
"Back to Back\n连续打出两次特殊消行(Spin或消四),中间不夹杂普通消行,可以提供额外的攻击(在Techmino中B2B为满贯,大满贯是B3B)。连续PC/HPC在Techmino中也算B2B/B3B。",
},
{"B2B2B",
- "大满贯 b2b2b b3b backtoback backtobacktoback",
+ "大满贯 b3b backtobacktoback",
"term",
"Back to Back to Back\nB2B的加强版,缩写B3B,大量B2B后连续B2B会变成B2B2B,提供更强的攻击(仅Techmino中有)。",
},
@@ -554,46 +603,46 @@ return{
"三类特殊T2的名字,不同的游戏内的攻击可能不一样,实战中基本没有特殊价值,可以不详细了解。",
},
{"现代方块",
- "现代方块 modern xiandaikuai tetris",
+ "modern xiandaikuai tetris",
"term",
- "现代方块是一个模糊的概念,这里列出一部分“标准”规则,满足大部分的都可以认为是现代方块:\n1.可见场地大小是10×20,不过上方空间也是存在的,上限可以自己定,一些游戏用的是40;\n2.七种方块从顶部正中间出现(奇数宽方块偏左,高度可以是方块底部或顶部贴着场地顶),同一种方块的朝向(一般是平的面朝下)和颜色都一致;\n3.一个合适的随机出块机制(常见的详见Bag7词条和His词条);\n4.一个合适的的旋转系统(至少有双旋,详见双旋词条)(最好是SRS或类SRS,详见SRS词条);\n5.一个合适的锁定延迟系统,详见锁定延迟词条;\n6.一个合适的死亡判定,详见死亡判定词条;\n7.有Next功能(一般是3~6个,也有1个的),详见Next词条,并且方向和出现时候的方向一致;\n8.有Hold功能,详见Hold词条;\n9.有DAS系统负责精密并且快速的左右移动,详见DAS词条;\n10.如果有出块延迟和消行延迟,那么需要有提前旋转/Hold系统,详见IRS和IHS词条,IMS是本游戏特有。",
+ "现代方块是一个模糊的概念,这里列出一部分 “标准” 规则,满足大部分的都可以认为是现代方块:\n1.可见场地大小是10×20,不过上方空间也是存在的,上限可以自己定,一些游戏用的是40;\n2.七种方块从顶部正中间出现(奇数宽方块偏左,高度可以是方块底部或顶部贴着场地顶),同一种方块的朝向(一般是平的面朝下)和颜色都一致;\n3.一个合适的随机出块机制(常见的详见Bag7词条和His词条);\n4.一个合适的的旋转系统(至少有双旋,详见双旋词条)(最好是SRS或类SRS,详见SRS词条);\n5.一个合适的锁定延迟系统,详见锁定延迟词条;\n6.一个合适的死亡判定,详见死亡判定词条;\n7.有Next功能(一般是3~6个,也有1个的),详见Next词条,并且方向和出现时候的方向一致;\n8.有Hold功能,详见Hold词条;\n9.有DAS系统负责精密并且快速的左右移动,详见DAS词条;\n10.如果有出块延迟和消行延迟,那么需要有提前旋转/Hold系统,详见IRS和IHS词条,IMS是Techmino特有。",
},
{"方块形状",
- "形状 xingzhuang shape tetromino tetrimino",
+ "xingzhuang shape tetromino tetrimino",
"term",
- "在标准的方块游戏中,用到的方块是所有的“四连块”,即四个正方形共用边连接成的形状。\n在不允许翻转,只允许旋转的情况下,四连块一共有七种,根据它们的形状一般分别叫做Z、S、J、L、T、O、I。",
+ "在标准的方块游戏中,用到的方块是所有的 “四连块”,即四个正方形共用边连接成的形状。\n在不允许翻转,只允许旋转的情况下,四连块一共有七种,根据它们的形状一般分别叫做Z、S、J、L、T、O、I。\n\n详见下方 “方块名称”。",
},
{"方块颜色",
- "颜色 yanse color colour tetromino tetrimino",
+ "yanse color colour tetromino tetrimino",
"term",
- "主流方块游戏中七种块的颜色会使用同一套彩虹配色:\nZ:红 S:绿 J:蓝 L:橙 T:紫 O:黄 I:青\n\nTechmino默认也使用这一套“标准”配色。",
+ "主流方块游戏中七种块的颜色会使用同一套彩虹配色:\nZ:红 S:绿 J:蓝 L:橙 T:紫 O:黄 I:青\n\nTechmino默认也使用这一套 “标准” 配色。",
},
- {"提前旋转 IRS",
- "提前 irs initialrotatesystem",
+ {"提前旋转(IRS)",
+ "irs initialrotatesystem",
"term",
"Initial Rotation System 提前旋转系统\n方块出现前提前按下旋转后,出现时就是转好的形状,有时可以避免死亡。",
},
- {"提前暂存 IHS",
- "提前 ihs initialholdsystem",
+ {"提前暂存(IHS)",
+ "ihs initialholdsystem",
"term",
"Initial Hold System 提前Hold系统\n方块出现前提前按下hold后,直接出现hold里的方块,有时可以避免死亡。",
},
- {"提前移动 IMS",
- "提前 ims initialmovesystem",
+ {"提前移动(IMS)",
+ "ims initialmovesystem",
"term",
"Initial Move System 提前移动系统\n方块出现前提前按住移动后,出现时会朝移动方向偏一格,有时可以避免死亡(Techmino限定)。\n注:需要块出现时das已充满",
},
- {"预览 Next",
- "预览 下一个 next yulan xiayige",
+ {"预览(Next)",
+ "下一个 next yulan xiayige",
"term",
- "指示后边几个块的顺序。\n提前思考手上这块怎么摆可以让后面轻松是玩家提升的必需技能。\n\n关于玩家玩的时候到底看了几个Next:这个数字并不固定,不同玩家、不同模式、不同局面,计算next的数量都不一样,通过调整可见Next数量打40L比较时间等方式测得的数据并不准确。\n\n具体例如,一个比较熟练的玩家几乎永远会提前算好一个Next,不然不会锁定手里的块;场地上将要出现或可以构造消四洞(T坑)的时候会找最近的I(T)什么时候来,如果太远了就会直接挖掉放弃本次攻击以防被对手偷袭。这两种情况并不独立,有很多介于中间的情况。所以,一个玩家看的Next数量是时刻在变的,“某人看几个Next”没有精确答案,必须在指明情况的时候数字才能作为参考。",
+ "指示后边几个块的顺序。\n提前思考手上这块怎么摆可以让后面轻松是玩家提升的必需技能。\n\n关于玩家玩的时候到底看了几个Next:这个数字并不固定,不同玩家、不同模式、不同局面,计算next的数量都不一样,通过调整可见Next数量打40L比较时间等方式测得的数据并不准确。\n\n具体例如,一个比较熟练的玩家几乎永远会提前算好一个Next,不然不会锁定手里的块;场地上将要出现或可以构造消四洞(T坑)的时候会找最近的I(T)什么时候来,如果太远了就会直接挖掉放弃本次攻击以防被对手偷袭。这两种情况并不独立,有很多介于中间的情况。所以,一个玩家看的Next数量是时刻在变的,“某人看几个Next” 没有精确答案,必须在指明情况的时候数字才能作为参考。",
},
- {"暂存 Hold",
- "暂存 交换 hold zancun",
+ {"暂存(Hold)",
+ "交换 hold zancun",
"term",
- "将手里的方块和Hold槽中的交换,一般不能连续使用。\n用来调整块序,更容易摆出你想要的形状。\n本游戏中有一个“物理Hold”机制,开启后Hold换出的方块会直接出现在当前方块所在的位置\n\n用不用Hold各有好处,不用的话看到序列是什么就是什么,减少了思考量;并且减少了按键的种类,操作简单容易提升KPS,有些人的40L记录就是不用Hold打出的。用Hold可以灵活地调整序列,减少高重力等规则带来的难度,算力足够的情况下可以达成更复杂的目标,甚至反过来显著减少总按键数。",
+ "将手里的方块和Hold槽中的交换,一般不能连续使用。\n用来调整块序,更容易摆出你想要的形状。\nTechmino中有一个 “物理Hold” 机制,开启后Hold换出的方块会直接出现在当前方块所在的位置\n\n用不用Hold各有好处,不用的话看到序列是什么就是什么,减少了思考量;并且减少了按键的种类,操作简单容易提升KPS,有些人的40L记录就是不用Hold打出的。用Hold可以灵活地调整序列,减少高重力等规则带来的难度,算力足够的情况下可以达成更复杂的目标,甚至反过来显著减少总按键数。",
},
- {"置换 Swap",
+ {"置换(Swap)",
"交换 swap hold jiaohuan zancun",
"term",
"Hold的另一种表现形式,将手里的方块和Next槽中的第一个交换,一般同样不能连续使用。",
@@ -604,200 +653,220 @@ return{
"开启后当方块触底时,再次按下软降会让方块尝试向下穿墙寻找放得下的地方,如果有就会直接瞬移到那\n该功能更偏向用于技术研究,对于AI来说有了它可以完全不用再考虑旋转系统,形状能容得下的地方一定都能到达",
},
{"Misdrop",
- "误 md misdrop",
+ "误 md",
"term",
"误放,就是不小心放错了地方。简称MD。",
},
{"Mishold",
- "误hold mh mishold",
+ "误hold mh",
"term",
"误hold,就是不小心按到Hold导致死亡或失去PC机会等。简称MH。",
},
{"sub",
- "sub",
+ "",
"term",
"在……之下\n用于表示成绩,单位一般可不写,比如40L成绩Sub 30是秒,1000行Sub 15是分钟,不写项目默认是40L\n\n例:39.95s是Sub 40,40.###s不是Sub 40。\n请不要使用Sub 62之类的词,因为sub本身就是表示大约, 一分钟左右的成绩精确到5~10s就可以了,一般30s以内的成绩用sub## 的时候才会精确到1s。",
},
- {"挖掘 Dig",
- "挖掘 dig downstack ds wajue",
+ {"挖掘(Dig)",
+ "挖掘 downstack ds wajue",
"term",
"指消除从场地底部进入的垃圾行(对手攻击打过来或者模式中自动生成)。也叫downstack(DS)。",
},
- {"捐赠 Donate",
- "捐赠 捐献 donate juanzeng",
+ {"捐赠(Donate)",
+ "捐献 juanzeng",
"term",
"指刻意临时堵住(可以消四的)洞做T-spin,打出T-spin后就会解开,是比较进阶的保持/提升火力的技巧。\n不标准用法:有时候只要堵住了个坑,即使不是消四洞也会用这个词。",
},
{"欠债",
- "欠债 qianzhai debt",
+ "qianzhai debt",
"term",
"欠债\n指必须完全堆好才能开始转下T旋打出攻击,堆完之前T下不去的形状。对战实战中如果要做此类(中局)定式时一定要观察对手情况确保自己安全,不然可能被半途打死\n\n一般只用来描述类似双T3/T3塔的大型组合炮,堆完之前完全不能打出攻击。",
},
- {"攻守",
- "攻守 gong shou",
+ {"攻防",
+ "gongfang gongshou",
"term",
"攻击指通过消除给对手发送垃圾行;\n防御(相杀)指别人打过来攻击之后用攻击抵消;\n反击指抵消/吃下所有攻击后打出攻击。\n\n注:大多数方块游戏的攻防是1:1的,4行攻击抵消对手的4行攻击。",
},
- {"连击 Combo",
- "连击 ren combo",
+ {"连击(Combo)",
+ "ren lianji",
"term",
- "从第二次消除起叫1 REN/Combo,打出的攻击根据游戏设计的不同也不同。“REN”这个名称来源于日语中的”連”(れん)。",
+ "从第二次消除起叫1 REN/Combo,打出的攻击根据游戏设计的不同也不同。“REN” 这个名称来源于日语中的 “連”(れん)。",
},
{"Spike",
- "spike baofa xingbao",
+ "baofa xingbao",
"term",
- "爆发攻击\n指短时间内打出大量的攻击,本游戏和TETR.IO中有Spike计数器,可以看到自己短时间内打出了多少攻击。\n注意,网络卡顿导致的累计攻击瞬间释放不算Spike。",
+ "爆发攻击\n指短时间内打出大量的攻击,Techmino和TETR.IO中有Spike计数器,可以看到自己短时间内打出了多少攻击。\n注意,网络卡顿导致的累计攻击瞬间释放不算Spike。",
},
{"Side",
- "连击 ·side",
+ "连击 sidewell",
"term",
"在场地旁边空出几列的堆叠法\n用来制造连击,对于新人是一个不错的进攻方法。但由于起楼的时候可能会被顶死而且总效率不高,导致高端玩家不会单独做Wide,更可能会在中局堆好炮并且观察到对手短时间内不会打出伤害的时候可以造,用来大幅加强瞬时火力。",
},
+ {"Center",
+ "连击 centerwell",
+ "term",
+ "在场地正中间空出几列的堆叠法",
+ },
+ {"Partial",
+ "连击 partialwell",
+ "term",
+ "在场地边和正中之间的位置空出几列的堆叠法",
+ },
{"S1W",
- "s1w side1wide tetrisstacking",
+ "side1wide tetrisstacking",
"term",
"Side 1 Wide\n旁边空1列,是传统方块游戏里常见的消四打法。\n在现代方块对战中新手可以使用,短时间能打出大量攻击,但在高手场出场率不高,因为效率低,容易被对面一波打死,故只在极少数情况合适的时候用。",
},
{"S2W",
- "连击 ·s2w side2wide",
+ "连击 lianji ren side2wide",
"term",
"Side 2 Wide\n旁边空2列,是常见的连击打法。\n难度很低,现代方块对战中新手可以使用,结合Hold可以很轻松地打出大连击。高手场使用不多,因为准备时间太长,会被对面提前打进垃圾行,导致连击数减少或者直接Top Out,效率也没有特别高,故一套打完也不一定能杀人。",
},
{"S3W",
- "连击 ·s3w side2wide",
+ "连击 lianji ren side2wide",
"term",
"Side 3 Wide\n旁边空3列,不如2w常见的连击打法。能打出的连击数比2w多,但是难度偏大很容易断连。",
},
{"S4W",
- "连击 ·s4w side4wide",
+ "连击 lianji ren side4wide",
"term",
"Side 4 Wide\n旁边空4列,一种连击打法,能打出很高的连击,并且准备时间比别的Wide打法短,故动作快的话可以抢在对手打进垃圾之前堆很高然后打出超大连击。\n(因为可能会被提前打死,风险挺大,所以没有c4w那么不平衡)。",
},
{"C1W",
- "c1w center1wide centre1wide",
+ "center1wide centre1wide",
"term",
"Center 1 Wide\n中间空1列,一种实战里消4同时辅助打TSD的打法,需要玩家理解<平衡法>,熟练之后可以轻松消四+T2输出,难度也不是特别大。",
},
{"C2W",
- "连击 ·c2w center2wide centre2wide",
+ "连击 lianji ren center2wide centre2wide",
"term",
"Center 2 Wide\n中间空2列,一种可能的连击打法(不常见)。",
},
{"C3W",
- "连击 ·c3w center3wide centre3wide",
+ "连击 lianji ren center3wide centre3wide",
"term",
"Center 3 Wide\n中间空3列,一种可能的连击打法(不常见)。",
},
{"C4W",
- "连击 ·c4w center4wide centre4wide",
+ "连击 lianji ren center4wide centre4wide",
"term",
- "Center 4 Wide\n中间空四列,一种连击打法,能打出很高的连击,利用了大多数专业对战方块游戏的死亡判定机制,可以放心堆高不担心被顶死,然后开始连击。是一种利用游戏机制的不平衡策略(尤其在开局时),观赏性不是很强还可以以弱胜强,成本太低所以成为了部分游戏中约定的类似“禁招”的东西,请在了解情况后再使用,不然可能会被别人骂。\n本游戏里考虑到了平衡问题,所以c4w的强度没有别的游戏那么夸张。",
+ "Center 4 Wide\n中间空四列,一种连击打法,能打出很高的连击,利用了大多数专业对战方块游戏的死亡判定机制,可以放心堆高不担心被顶死,然后开始连击。是一种利用游戏机制的不平衡策略(尤其在开局时),观赏性不是很强还可以以弱胜强,成本太低所以成为了部分游戏中约定的类似 “禁招” 的东西,请在了解情况后再使用,不然可能会被别人骂。\nTechmino中虑到了平衡问题,所以c4w的强度没有别的游戏那么夸张。",
},
{"N-Res",
- "连击 ·residual c4w s4w",
+ "连击 lianji ren residual c4w s4w",
"term",
- "N-Residual\nN-剩余,指4w连击楼底部留几个方格,常用的是3-Res和6-Res。\n3-Res路线少比较好学,成功率也很高,实战完全够用\n6-Res路线多更难用,但是计算力很强的话比3-Res更稳,也可以用来完成特殊挑战(比如本游戏的c4w练习要求100连击通关)",
+ "N-Residual\nN-剩余,指4w连击楼底部留几个方格,常用的是3-Res和6-Res。\n3-Res路线少比较好学,成功率也很高,实战完全够用\n6-Res路线多更难用,但是计算力很强的话比3-Res更稳,也可以用来完成特殊挑战(比如Techmino的c4w练习要求100连击通关)。\n\n注:优先使用6-Res,然后是3-res和5-Res,最后是4-Res",
},
- {"6-3堆叠法",
+ {"6–3堆叠法",
"六三 63",
"term",
"指左边6列右边3列的堆叠方式。在玩家有足够的计算能力后可以减少堆叠所用的按键数(反之可能甚至会增加),是主流的用于减少操作数的高端40L堆叠方式,原理跟出块位置是中间偏左有关。",
},
{"Freestyle",
- "freestyle ziyou",
+ "ziyou",
"term",
"自由发挥的意思,常用于freestyle TSD(T2),指不用固定的堆叠方式而是随机应变完成20TSD。比用LST或者垃圾分类完成的20 TSD的难度要大,成绩也更能代表实战水平。",
},
{"死亡判定",
- "死亡判定 die death siwang",
+ "die death siwang",
"term",
- "现代方块普遍使用的死亡判定:\n1. 新出现的方块和场地方块有重叠(窒息,Block Out)(c4w比s4w强的原因,因为被打进18行都不会窒息);\n2. 方块锁定时完全在场地的外面(Lock Out);\n3. 场地内现存方块总高度大于40。(超高,Top Out)\n\n注:本游戏使用的死亡判定默认不开启第二、三条。",
+ "现代方块普遍使用的死亡判定:\n1. 新出现的方块和场地方块有重叠(窒息,Block Out)(c4w比s4w强的原因,因为被打进18行都不会窒息);\n2. 方块锁定时完全在场地的外面(Lock Out);\n3. 场地内现存方块总高度大于40。(超高,Top Out)\n\n注:Techmino使用的死亡判定默认不开启第二、三条。",
},
{"缓冲区",
- "缓冲区 buffer zone huanchongqu",
+ "buffer zone huanchongqu",
"term",
- "(不是所有游戏都有这个概念)指10×20可见场地之上的21~40行。因为垃圾行顶起后两边堆高的方块可能会超出屏幕,消行后这些方块要重新回到场地内所以需要保存下来,由于程序上要求场地尺寸有限(部分游戏可以无限),故设定为40,一般都够用。\n\n另见“消失区”词条。",
+ "(不是所有游戏都有这个概念)指10×20可见场地之上的21~40行。因为垃圾行顶起后两边堆高的方块可能会超出屏幕,消行后这些方块要重新回到场地内所以需要保存下来,由于程序上要求场地尺寸有限(部分游戏可以无限),故设定为40,一般都够用。\n\n另见 “消失区” 词条。",
},
{"消失区",
- "消失区 vanish zone xiaoshiqu",
+ "vanish zone xiaoshiqu",
"term",
"在缓冲区的基础上,指比40行缓冲区还高的区域。\n标准的死亡判定涉及了这个概念,在垃圾行升起后如果场地上有任何方块超出了40高的缓冲区(也就是达到了消失区)时游戏直接结束。\n但事实上这块区域在不同游戏中表现不同,甚至有设计者考虑不周导致方块挪到40行以上,但是程序没考虑导致方块接触消失区直接报错闪退的游戏。通常出现在玩家堆了c4w然后被打入大量垃圾行时才会考虑这个概念。其他游戏中方块进入消失区可能直接导致游戏结束,也有可能会出现一些奇怪的bug(附带链接是ppt的复制40行无限Ren视频)。\n\n另,Jstris中22行及以上可以理解为消失区,锁定在21行之外的格子会消失。",
"https://www.bilibili.com/video/BV1ZE411Y7GD",
},
{"下落速度",
- "下落速度 重力 drop speed zhongli gravity",
+ "重力 drop speed zhongli gravity",
"term",
- "一般用*G表示方块的下落速度,意思是每一帧方块往下移动多少格,一秒下落一格就是1/60G(默认60fps),可以看出G是一个很大的单位。因为场地就20格,所以一般认为20G即为上限,详见20G词条。",
+ "一般用*G表示方块的下落速度,意思是每一帧方块往下移动多少格,一秒下落一格就是1/60G(默认60fps),可以看出G是一个很大的单位。因为场地就20格,所以一般认为20G即为上限,详见20G词条。\n在Techmino中描述重力的方式是 “每过多少帧下落一格”,例如一秒落一格就对应60(默认60fps)",
},
{"20G",
- "高重力 20g",
+ "高重力",
"term",
- "现代方块的最高下落速度,表观就是方块瞬间到底,不存在中间的下落过程,可能会让方块无法跨越壕沟/从山谷爬出。\n20G一般指的其实是“无限下落速度”,就算场地不止20格,“20G”也会让方块瞬间到底。\n本游戏(和部分其他游戏,推荐这么设计)中20G的优先级比其他玩家操作都高,即使是0arr的水平方向“瞬间移动”中途也会受到20G的影响。",
+ "现代方块的最高下落速度,表观就是方块瞬间到底,不存在中间的下落过程,可能会让方块无法跨越壕沟/从山谷爬出。\n20G一般指的其实是 “无限下落速度” ,就算场地不止20格,“20G” 也会让方块瞬间到底。\nTechmino(和部分其他游戏,推荐这么设计)中20G的优先级比其他玩家操作都高,即使是0arr的水平方向 “瞬间移动” 中途也会受到20G的影响。",
},
- {"锁定延迟 LD",
- "锁定延迟 重力 lock delay lockdown delay suoyan zhongli gravity",
+ {"锁定延迟(LD)",
+ "重力 lock delay lockdown delay suoyan zhongli gravity",
"term",
- "方块<碰到地面到锁定>之间的时间。经典块仅方块下落一格时刷新倒计时,而现代方块中往往任何操作都将重置该倒计时(但是方块本身必须可以移动/旋转),所以连续移动和操作可以让方块不马上锁定,拖一会时间(本游戏和部分游戏重置次数有限,一般是15)。",
+ "方块<碰到地面到锁定>之间的时间。经典块仅方块下落一格时刷新倒计时,而现代方块中往往任何操作都将重置该倒计时(但是方块本身必须可以移动/旋转),所以连续移动和操作可以让方块不马上锁定,拖一会时间(Techmino和部分游戏重置次数有限,一般是15)。",
},
- {"出块延迟 ARE",
- "出块延迟 are delay chukuaiyanchi",
+ {"出块延迟(ARE)",
+ "delay chukuaiyanchi",
"term",
"ARE。方块<锁定完成到下一个方块出现>之间的时间。",
},
- {"消行延迟 ARE",
- "消行延迟 line are delay xiaohangyanchi",
+ {"消行延迟(ARE)",
+ "line delay xiaohangyanchi",
"term",
"Line ARE。方块<锁定完成能消行时的消行动画>占据的时间。",
},
- {"窒息延迟 DD",
- "窒息延迟 choke are delay zhixiyanchi",
+ {"窒息延迟(DD)",
+ "choke are delay zhixiyanchi",
"term",
"当前方块锁定后如果下一块的生成位置被阻挡,那么下一块的出块延迟会被再额外加上这个延迟的值,方便使用提前系统来避免死亡\n想法来自NOT_A_ROBOT",
},
- {"极简 Finesse",
+ {"极简(Finesse)",
"极简操作 最简操作 finesse jijiancaozuo zuijiancaozuo",
"term",
- "用最少的按键数将方块移到想去的位置的技术(大多数时候只考虑纯硬降的落点),节约时间和减少Misdrop。\n\n该技能学习越早越好,建议先去找教程视频,看懂了然后自己多练习,开始以准确率第一,速度快慢不重要,熟练后自然就快了。\n\n注意,本游戏使用的极简判定系统不是说完全和理论最少操作数一样,而是不需要软降就能达到的位置才会按照标准出块方向和你的按键次数执行极简检测,故在此不像js存在软降后误杀。但是多了一些新的条件,比如【手上和Hold一样/已经按了超过3次按键后】再hold后按键次数不重置(让下一块极简失误)。\n极简率计算:\n没有超过标准极简法操作数的为Perfect计100%,超出一步为Great计50%,超出两步为Bad计25%,两步以上为Miss计0%,其中Bad和Miss会断连\n\n注:20G下极简系统和0G一样工作,所以得到的数值不准确,参考价值偏低。",
+ "用最少的按键数将方块移到想去的位置的技术(大多数时候只考虑纯硬降的落点),节约时间和减少Misdrop。\n\n该技能学习越早越好,建议先去找教程视频,看懂了然后自己多练习,开始以准确率第一,速度快慢不重要,熟练后自然就快了。\n\n注意,Techmino使用的极简判定系统不是说完全和理论最少操作数一样,而是不需要软降就能达到的位置才会按照标准出块方向和你的按键次数执行极简检测,故在此不像js存在软降后误杀。但是多了一些新的条件,比如【手上和Hold一样/已经按了超过3次按键后】再hold后按键次数不重置(让下一块极简失误)。\n极简率计算:\n没有超过标准极简法操作数的为Perfect计100%,超出一步为Great计50%,超出两步为Bad计25%,两步以上为Miss计0%,其中Bad和Miss会断连\n\n注1:一般说的极简不考虑带软降/高重力/场地很高的情况,仅研究空中移动/旋转后硬降。绝对理想的“极简”建议使用“最少按键数/操作数”表达。\n注2:20G下极简系统和0G一样工作,所以得到的数值不准确,参考价值偏低。",
},
{"科研",
- "科研 keyan",
+ "keyan",
"term",
- "常用语,指在低重力的单人模式里减速研究怎么做各种T-spin,本游戏中拓展了含义,用于称呼几乎需要全程Spin的游戏模式。",
+ "常用语,指在低重力的单人模式里减速研究怎么做各种T-spin,Techmino中拓展了含义,用于称呼几乎需要全程Spin的游戏模式。",
},
- {"手感 Handling",
+ {"键位",
+ "keyboard mapping jianwei",
+ "term",
+ "键位设置原则参考:\n1.不要让一个手指管两个可能同时按的键,通常只有几个旋转键不需要同时按,其他功能推荐都单独给一个手指\n2.除非已经在别的游戏里锻炼过小拇指,最好不要用,一般食指和中指最灵活,自己觉得舒服为准\n3.没必要参考别人的键位设置,每个人都不一样,只要不违反前几条规则,就几乎不会对成绩产生影响。",
+ },
+ {"手感(Handling)",
"手感 feel shougan",
"term",
"决定手感的几个主要因素:\n1. 输入延迟受设备配置或者设备状况影响。可以重启/换设备解决;\n2. 程序运行稳定性程序设计或.实现)得不好,时不时会卡一下。把设置画面效果拉低可能可以缓解;\n3. 游戏设计故意的。自己适应;\n4. 参数设置设置不当。去改设置;\n5. 游玩姿势姿势不当。不便用力,换个姿势;\n6. 换键位或者换设备后不适应,操作不习惯。多习惯习惯,改改设置;\n7. 肌肉疲劳反应和协调能力下降。睡一觉或者做点体育运动,过段时间(也可能要几天)再来玩。",
},
{"DAS通俗",
- "das arr simple",
+ "das arr simple tongsu",
"term",
- "打字时按住o,你会看到:ooooooooooo\n在时间轴上:o-----------o-o-o-o-o-o-o-o-o-o\n-----------就是das长度,-就是arr长度。\n详见 DAS & ARR 词条。",
+ "打字时按住o,你会看到:ooooooooooo…\n在时间轴上:o—————o-o-o-o-o-o-o-o-o…\n—————就是das长度,-就是arr长度。\n详见 DAS & ARR 词条。",
},
{"DAS & ARR",
- "灵敏度 das arr",
+ "灵敏度 arr",
"term",
"DAS(Delay-auto-shift,自动加(延迟)具体指从<按下移动键时动了一格>到<开始自动移动>之间的时间。\nARR(Auto-repeat-rate),自动重复速率,指<每次自动移动>之间的时间\n单位都是f(帧,1帧=1/60秒)\n别的游戏里用的单位可能是ms(毫秒),乘16.7就可得出大约的对应数值,例如4f≈67ms。",
},
{"DAS调节",
- "调节 das arr tuning",
+ "调节 arr tuning tiaojie",
"term",
"对于不是刚入门的并且了解极简操作的玩家来说推荐ARR=0,DAS=4~6(具体看个人手部协调性,只要能控制区别就不大)。\n新人如果实在觉得太快可以适当增加一点DAS,ARR要改的话强烈建议不要超过2\n\n最佳调整方法:DAS越小越好,小到依然能准确区分单点/长按为止;ARR能0就0,游戏不允许的话就能拉多小拉多小。",
},
- {"DAS打断 DCD",
+ {"DAS打断(DCD)",
"dascut dcd daduan",
"term",
- "本游戏中指玩家的操作焦点转移到新方块的瞬间,此时减小(重置)DAS计时器,让自动移动不会立刻生效,减少“移动键松开晚了导致下一块一出来就立即开始移动”的情况\n注:其他游戏中的DAS打断机制可能和本游戏的有区别,仅供参考。",
+ "Techmino中指玩家的操作焦点转移到新方块的瞬间,此时减小(重置)DAS计时器,让自动移动不会立刻生效,减少 “移动键松开晚了导致下一块一出来就立即开始移动” 的情况\n注:其他游戏中的DAS打断机制可能和Techmino的有区别,仅供参考。",
},
- {"误硬降打断 HCD",
+ {"误硬降打断(HCD)",
"autolockcut mdcut daduan",
"term",
- "为了防止玩家硬降时当前方块已经锁定,下一块出现就被立刻硬降导致严重md,所以设计了此打断参数。\n方块自然锁定之后几帧内硬降键是无效的,具体看设置了多久。\n注:其他游戏中的防误硬降机制可能和本游戏的有区别,仅供参考。",
+ "为了防止玩家硬降时当前方块已经锁定,下一块出现就被立刻硬降导致严重md,所以设计了此打断参数。\n方块自然锁定之后几帧内硬降键是无效的,具体看设置了多久。\n注:其他游戏中的防误硬降机制可能和Techmino的有区别,仅供参考。",
},
- {"软降倍率 SDF",
+ {"软降倍率(SDF)",
"软降速度 sdf softdropfactor",
"term",
- "Soft Drop Factor,软降速度因子(倍率)\n部分游戏中的软降机制就是在按住软降键时方块受到的重力变为原来的若干倍,SDF就是这个变大的倍数。\n基本所有官块和TETR.IO使用这个机制,但本游戏不使用。",
+ "Soft Drop Factor,软降速度因子(倍率)\n部分游戏中的软降机制就是在按住软降键时方块受到的重力变为原来的若干倍,SDF就是这个变大的倍数。\n基本所有官块和TETR.IO使用这个机制,但Techmino不使用。",
+ },
+ {"方块名称",
+ "mino",
+ "term",
+ "这是一个Techmino使用的所有方块的名称和其对应的形状:\n四连块:\nZ: "..CHAR.mino.Z..", S: "..CHAR.mino.S..", J: "..CHAR.mino.J..", L: "..CHAR.mino.L..", T: "..CHAR.mino.T..", O: "..CHAR.mino.O..", I: "..CHAR.mino.I..";\n\n五连块:\nZ5: "..CHAR.mino.Z5..", S5: "..CHAR.mino.S5..", P: "..CHAR.mino.P..", Q: "..CHAR.mino.Q..", F: "..CHAR.mino.F..", E: "..CHAR.mino.E..", T5: "..CHAR.mino.T5..", U: "..CHAR.mino.U..", V: "..CHAR.mino.V..", W: "..CHAR.mino.W..", X: "..CHAR.mino.X..", J5: "..CHAR.mino.J5..", L5: "..CHAR.mino.L5..", R: "..CHAR.mino.R..", Y: "..CHAR.mino.Y..", N: "..CHAR.mino.N..", H: "..CHAR.mino.H..", I5: "..CHAR.mino.I5..";\n\n一至三连块:\nI3: "..CHAR.mino.I3..", C: "..CHAR.mino.C..", I2: "..CHAR.mino.I2..", O1: "..CHAR.mino.O1..".",
},
{"Bag7出块",
"bag出块 bag7bag",
@@ -805,39 +874,39 @@ return{
"一种出块方式,现代方块普遍使用该规则,开局起每7个块是7种形状各出现一次,避免了很久不出某个块和某个块来得特别多,是一些现代方块战术的基础。\n\n例如:\nZSJLTOI OTSLZIJ LTISZOJ",
},
{"His出块",
- "his出块 history",
+ "history",
"term",
- "一种的出块方式,例如His4 Roll6 (h4r6)就是在随机生成新的 Next 的时候,随机一个跟最后4次生成的Next中有一样的,就重新随机,直到已经尝试6次或和那4个都不一样。\n本游戏的His序列模式中最大Roll次数为序列长度的一半(向上取整)\n\n是纯随机出块的一大改进,大大减小了连续出几个SZ(洪水)的概率。",
+ "一种的出块方式,例如His4 Roll6 (h4r6)就是在随机生成新的 Next 的时候,随机一个跟最后4次生成的Next中有一样的,就重新随机,直到已经尝试6次或和那4个都不一样。\nTechmino的His序列模式中最大Roll次数为序列长度的一半(向上取整)\n\n是纯随机出块的一大改进,大大减小了连续出几个SZ(洪水)的概率。",
},
{"HisPool出块",
- "hisPool出块 history pool hispool",
+ "history pool hispool",
"term",
"一种出块方式,History Pool,his算法的分支,比较复杂,这里只提供大概的说明:\n在His的基础上添加了一个Pool(池),在取块的时候his是直接随机和历史序列(最后4次生成的next)比较,而HisPool是从Pool里面随机取(然后补充一个最旱的块增加他的概率)然后和历史序列比较。\n\n这个算法让序列更稳定,介于His和Bag之间,在理论上保证了干旱时间不会无限长。",
},
{"bagES出块",
"bages出块",
"term",
- "(该词仅在本游戏内使用)Bag Easy-Start(Bag简单开局),Bag算法的分支,开局第一包的第一块不会是S/Z/O/S5/Z5/F/E/W/X/N/H。",
+ "(该词仅在Techmino内使用)Bag Easy-Start(Bag简单开局),Bag算法的分支,开局第一包的第一块不会是S/Z/O/S5/Z5/F/E/W/X/N/H。",
},
{"Reverb出块",
"reverb出块",
"term",
- "(该词仅在本游戏内使用)回声出块,Bag算法的分支,把Bag的每一块重复随机次数(重复越多概率越小,理论范围是0~6,具体比较复杂这里不展开)",
+ "(该词仅在Techmino内使用)回声出块,Bag算法的分支,把Bag的每一块重复随机次数(重复越多概率越小,理论范围是0~6,具体比较复杂这里不展开)",
},
- {"超连点 Hypertap",
- "超连点 hypertap chaoliandian",
+ {"超连点(Hypertap)",
+ "chaoliandian",
"term",
- "快速震动手指,实现比长按更快速+灵活的高速单点移动,主要在经典块的高难度下(因为DAS不可调而且特别慢,高速下很容易md导致失败,此时手动连点就比自动移动更快)或者受特殊情况限制不适合用自动移动时使用。会使用这个技术的人称为“Hypertapper”。",
+ "快速震动手指,实现比长按更快速+灵活的高速单点移动,主要在经典块的高难度下(因为DAS不可调而且特别慢,高速下很容易md导致失败,此时手动连点就比自动移动更快)或者受特殊情况限制不适合用自动移动时使用。会使用这个技术的人称为 “Hypertapper”。",
},
- {"轮指 Rolling",
- "轮指 rolling lunzhi liandian",
+ {"轮指(Rolling)",
+ "lunzhi liandian",
"term",
- "另一种快速连点方法,用于DAS/ARR设置非常慢时的高重力(1G左右)模式。\n先把手柄(键盘……可能也行吧)悬空摆好,比如架在腿上,要连点某个键的时候一只手虚按按键,另外一只手的几根手指轮流敲打手柄背面,“反向按键”实现连点。这种控制方法可以让玩家更轻松地获得比直接抖动手指的Hypertap(详见超连点词条)更快的控制速度。\n此方法最先由Cheez-fish发明,他本人则使用Rolling达到过超过20Hz的点击频率。",
+ "另一种快速连点方法,用于DAS/ARR设置非常慢时的高重力(1G左右)模式。\n先把手柄(键盘……可能也行吧)悬空摆好,比如架在腿上,要连点某个键的时候一只手虚按按键,另外一只手的几根手指轮流敲打手柄背面, “反向按键” 实现连点。这种控制方法可以让玩家更轻松地获得比直接抖动手指的Hypertap(详见超连点词条)更快的控制速度。\n此方法最先由Cheez-fish发明,他本人则使用Rolling达到过超过20Hz的点击频率。",
},
- {"穿透 Passthrough",
- "穿透 passthrough pingthrough chuantou",
+ {"穿透(Passthrough)",
+ "pingthrough chuantou",
"term",
- "(攻击)穿透,指双方的攻击打出后没有抵消,互相都收到的现象。\nTETR.IO中自定义房间如果开启Passthrough规则(曾经天梯默认开启),那么对手消行攻击的瞬间能看到自己的红条出现但其处于“无敌时间”内,不会触发也不能抵消,此时你的攻击会直接打给对手。(应该是给攻击的飞行动画预留时间,同时也让玩家能反应过来并主动选择要不要抵消,要的话就再等一会)\n另有pingthrough的说法,只是原因是由于不可避免的网络传输延迟,效果同passthrough,设计比较简单的联网对战块没有特殊考虑的话可能自然就会带有这个机制。",
+ "(攻击)穿透,指双方的攻击打出后没有抵消,互相都收到的现象。\nTETR.IO中自定义房间如果开启Passthrough规则(曾经天梯默认开启),那么对手消行攻击的瞬间能看到自己的红条出现但其处于 “无敌时间” 内,不会触发也不能抵消,此时你的攻击会直接打给对手。(应该是给攻击的飞行动画预留时间,同时也让玩家能反应过来并主动选择要不要抵消,要的话就再等一会)\n另有pingthrough的说法,只是原因是由于不可避免的网络传输延迟,效果同passthrough,设计比较简单的联网对战块没有特殊考虑的话可能自然就会带有这个机制。",
},
{"TOP攻击表",
"攻击表 top attack",
@@ -850,232 +919,269 @@ return{
"详见主菜单右下角的说明书页面。",
},
{"C2序列",
- "c2序列 seq",
+ "seq",
"term",
- "(七个块初始权重设为0)\n要取块的时候,\n先把七个数都除以2然后加上0~1的随机数,\n最大的数字是第几个的就出对应的块,然后将其权重除以3.5\n循环。",--Discovered by zxc
+ "(七个块初始权重设为0)\n要取块的时候,\n先把七个数都除以2然后加上0~1的随机数,\n最大的数字是第几个的就出对应的块,然后将其权重除以3.5\n循环。",
+ -- _comment: 原Lua文件中包含此注释:"Discovered by zxc"
},
- {"C2踢墙",
- "c2踢墙 kick",
- "term",
- "左,右,下,左下,右下,左2,右2\n(任何方块的任何旋转都使用这个表)。",
- },
- {"堆叠 Stack",
- "堆叠 duidie stacking",
+ {"堆叠(Stack)",
+ "duidie stacking",
"term",
"将方块无缝隙地堆起来,需要玩家有预读Next的能力,可以通过不使用Hold并且用十个消四完成40L模式进行练习。\n这项能力从入坑到封神都是非常重要的。",
},
{"双旋",
- "双旋 shuangxuan",
+ "shuangxuan",
"term",
"指能够使用顺时针+逆时针两个旋转键的技术,原来要转三下的情况可以反向转一下就够,减少烦琐操作。\n同时双旋也是学习Finesse的必要前提。\n\n另见 三旋。",
},
{"三旋",
- "三旋 sanxuan",
+ "sanxuan",
"term",
"指能够使用顺+逆时针+180°旋转三个旋转键的技术,任何方块放哪只需要旋转一次即可(Spin不算)。\n但由于只有部分游戏有180°旋转所以改操作并不通用,而且对速度提升的效果不如从单旋转双旋显著,不追求极限速度的玩家可不学。",
},
- {"干旱 Drought",
- "干旱 drought ganhan",
+ {"干旱(Drought)",
+ "ganhan",
"term",
"经典块术语,指长时间不来I方块(长条)。现代方块使用的Bag7出块规则下干旱几乎不可能,平均7块就会有一个I,理论极限两个I最远中间隔12块。",
},
- {"骨块 Bone",
- "骨块 gukuai bone tgm",
+ {"骨块(Bone)",
+ "gukuai bone tgm",
"term",
- "最早的方块游戏使用的方块样式。\n很久以前的电脑没有可以显示复杂图案的屏幕,只能往上打字,所以一格方块用两个方括号[ ]表示,长得像骨头所以叫骨块。\n基于骨块的特点,本游戏把骨块重新定义为,“所有形状使用的同一个比较花眼的贴图”,不同的皮肤有不同的骨块样式。",
+ "最早的方块游戏使用的方块样式。\n很久以前的电脑没有可以显示复杂图案的屏幕,只能往上打字,所以一格方块用两个方括号[ ]表示,长得像骨头所以叫骨块。\n基于骨块的特点,Techmino把骨块重新定义为, “所有形状使用的同一个比较花眼的贴图”,不同的皮肤有不同的骨块样式。",
},
{"半隐",
- "半隐 banyin half semi invisible",
+ "banyin half semi invisible",
"term",
- "指方块锁定经过一段时间后会变隐形的规则\n注:从锁定开始到消失的具体时长不定,可以描述为“过几秒种后消失”。",
+ "指方块锁定经过一段时间后会变隐形的规则\n注:从锁定开始到消失的具体时长不定,可以描述为 “过几秒种后消失”。",
},
{"全隐",
- "全隐 quanyin invisible",
+ "quanyin invisible",
"term",
- "指方块锁定后会马上完全隐藏\n注:锁定时有消失动画的话也可以叫全隐,但其实难度会小一点,故本游戏中没有动画的隐形模式叫瞬隐。",
+ "指方块锁定后会马上完全隐藏\n注:锁定时有消失动画的话也可以叫全隐,但其实难度会小一点,故Techmino中没有动画的隐形模式叫瞬隐。",
},
{"场地重力",
"重力 zhongli liansuo cascade chain",
"term",
- "(由于“重力”有歧义所以本词典里称为场地重力,也有重力连锁等叫法。)\n部分游戏的部分模式可能包含此规则。此规则下玩家的四格方块四个方向有连接关系,连起来的几个格整体会受到重力影响,悬空了会往下落。在这个规则下可以构造复杂的连锁消除,一个主打连锁消除对战的游戏是Qudra(老游戏,现在基本没人玩)。",
+ "(由于 “重力” 有歧义所以本词典里称为场地重力,也有重力连锁等叫法。)\n部分游戏的部分模式可能包含此规则。此规则下玩家的四格方块四个方向有连接关系,连起来的几个格整体会受到重力影响,悬空了会往下落。在这个规则下可以构造复杂的连锁消除,一个主打连锁消除对战的游戏是Qudra(老游戏,现在基本没人玩)。",
},
{"MPH模式",
- "mph",
+ "",
"term",
- "一个游戏模式:\nMemoryless,Previewless,Holdless\n纯随机+无Next+无Hold完成40L,一个非常考验玩家反应速度的模式。",
+ "一个游戏模式:\nMemoryless,Previewless,Holdless\n纯随机块序+无Next+无Hold完成40L,一个非常考验玩家反应速度的模式。",
},
{"输入延迟",
- "输入延迟 input delay yanchi",
+ "input delay yanchi",
"term",
"用任何设备玩任何游戏时,所有的操作(按键盘,点鼠标等)都会晚一点点(很短,几毫秒到几十毫秒)才到达游戏,如果过长就会很影响游戏手感,作用效果类似于你拿QQ远程控制打FPS游戏\nTOP、TE等游戏比较明显\n这个延迟一般由硬件性能,硬件状态影响,通常来说不可设置,开启性能模式(或者关闭节能模式)可能会好一点。",
},
+ {"秘密段位",
+ "大于号 secret grade dayuhao",
+ "term",
+ "出自TGM系列的彩蛋玩法。不按照TGM的一般目标去玩,而是去拼图拼出 “每行仅有一个洞的大于号” 图形(不能是小于号),拼得越多获得的秘密段位越高(没特殊功能,只是好玩),最高目标是完成19行并封顶\n更多内容见Hard Drop Wiki。",
+ "https://harddrop.com/wiki?search=Secret_Grade_Techniques",
+ },
{"Cold Clear",
"机器人 电脑 cc coldclear ai bot jiqiren",
"term",
- "一个AI的名字(就跟AlphaGo一样)\n本身是为PPT开发,故在本游戏中使用效果欠佳,版本也较旧。",
+ "一个AI的名字(就跟AlphaGo一样)\n由MinusKelvin开发,本来是用于PPT的。在Techmino中经过调整后支持all-spin和TRS旋转系统",
},
{"ZZZbot",
- "机器人 电脑 zzzbot ai bot jiqiren",
+ "机器人 电脑 ai bot jiqiren zzztoj",
"term",
"一个AI的名字(就跟AlphaGo一样)\n由研究群群友奏之章开发,重新调参后在各个游戏平台上的表现都很不错。",
},
-
- --定式
- {"开局定式 Setup",
- "开局定式 setup opening kaijudingshi opener",
+ -- # 定式
+ {"开局定式(Setup)",
+ "opening kaijudingshi opener",
"setup",
"开局定式,定式一般指开局定式这个概念。\n指开局后可以使用的套路摆法。局中情况合适的时候也可以摆出同样的形状,但是和摆法开局一般都不一样。\n\n能称为定式的摆法要尽量满足以下至少2~3条:\n能适应大多数块序\n输出高,尽量不浪费T块\n很多方块无需软降,极简操作数少\n有明确后续,分支尽量少。\n\n注:绝大多数定式基于bag7,序列规律性强才有发明定式的可能。",
},
{"DT炮",
- "dt炮 dt cannon",
+ "dt cannon",
"setup",
- "Double-Triple Cannon。\n"..HDwiki,
- HDsearch.."dt",
+ "Double-Triple Cannon。\n更多内容见Hard Drop Wiki。",
+ "https://harddrop.com/wiki?search=dt",
},
{"DTPC",
"dtpc",
"setup",
- "DT炮一个能接PC的分支。\n"..HDwiki,
- HDsearch.."dt",
+ "DT炮一个能接PC的分支。\n更多内容见Hard Drop Wiki。",
+ "https://harddrop.com/wiki?search=dt",
},
{"BT炮",
- "bt炮 bt cannon",
+ "bt cannon",
"setup",
- "β炮(Beta炮)。\n"..HDwiki,
- HDsearch.."bt_cannon",
+ "β炮(Beta炮)。\n更多内容见Hard Drop Wiki。",
+ "https://harddrop.com/wiki?search=bt_cannon",
},
{"BTPC",
"btpc",
"setup",
- "BT炮一个能接PC的分支。\n"..HDwiki,
- HDsearch.."bt_cannon",
+ "BT炮一个能接PC的分支。\n更多内容见Hard Drop Wiki。",
+ "https://harddrop.com/wiki?search=bt_cannon",
},
{"DDPC",
"ddpc",
"setup",
- "开局TSD的一个能接Double-Double-PC的分支。\n"..HDwiki,
- HDsearch.."TKI_3_Perfect_Clear",
+ "开局TSD的一个能接Double-Double-PC的分支。\n更多内容见Hard Drop Wiki。",
+ "https://harddrop.com/wiki?search=TKI_3_Perfect_Clear",
},
{"QT炮",
- "qt炮 qt cannon",
+ "qt cannon",
"setup",
- "QT炮,细节未知。",
+ "一种能以更高的概率搭出开局DT Attack的类似DT炮的定式。\n更多内容见Hard Drop Wiki。",
+ "https://harddrop.com/wiki?search=dt",
},
{"MT",
"mt",
"setup",
"Mini-Triple\n一个TSM+TST的结构。",
- HDsearch.."mt",
+ "https://harddrop.com/wiki?search=mt",
},
- {"狼月炮",
- "狼月炮 wolfmoon",
+ {"Trinity",
+ "trinity",
"setup",
- "狼月炮。\n"..HDwiki,
- HDsearch.."wolfmoon_cannon",
+ "Trinity\n一个TSD+TSD+TSD或TSM+TST+TSD的结构。",
+ "https://harddrop.com/wiki?search=trinity",
},
- {"ASC",
- "asc",
+ {"狼月炮",
+ "wolfmoon",
"setup",
- "ASC开局,细节未知。",
+ "狼月炮。\n更多内容见Hard Drop Wiki。",
+ "https://harddrop.com/wiki?search=wolfmoon_cannon",
},
{"Sewer",
"sewer",
"setup",
- "Sewer开局。\n"..HDwiki,
- HDsearch.."sewer",
+ "Sewer开局。\n更多内容见Hard Drop Wiki。",
+ "https://harddrop.com/wiki?search=sewer",
},
{"TKI",
- "tki",
+ "tki-3",
"setup",
- "TKI开局\n有两种解释,一个是TSD开局,另一个是Cspin开局。\n"..HDwiki,
- HDsearch.."tki",
+ "TKI-3开局\n有两种解释,一个是TSD开局的TKI-3,另一个是TST开局的TKI堆积(C-Spin)。\n更多内容见Hard Drop Wiki。",
+ "https://harddrop.com/wiki?search=TKI_3_Opening",
},
{"God Spin",
"god",
"setup",
- "God Spin\nwindkey发明的一个观赏性很强但实战没啥用的炫酷特殊T2+T3开局定式。\n"..HDwiki,
- HDsearch.."godspin",
+ "God Spin\nwindkey发明的一个观赏性很强但实战没啥用的炫酷特殊T2+T3开局定式。\n更多内容见Hard Drop Wiki。",
+ "https://harddrop.com/wiki?search=godspin",
},
{"信天翁",
- "信天翁 xintianweng",
+ "xintianweng albatrosssp albatrossspecial",
"setup",
- "一种高观赏性几乎不浪费T的快节奏强力T2-T3-T2-PC开局。",
+ "一种高观赏性几乎不浪费T的快节奏强力T2-T3-T2-PC开局。\n更多内容见Hard Drop Wiki。",
+ "https://harddrop.com/wiki?search=Albatross_Special",
},
{"鹈鹕",
- "鹈鹕 tihu",
+ "tihu pelican",
"setup",
"一种类似信天翁的定式,在块序不能信天翁的时候可以用。",
+ "https://harddrop.com/wiki?search=Pelican",
},
- {"七巧板",
- "七巧板 qiqiaoban",
+ {"全清开局",
+ "qiqiaoban tangram pco 1stpc",
+ "setup",
+ "Perfect Clear Opener,一种极大概率能摆出来,有概率(hold I约84.6%,不hold I约61.2%)能做到PC的定式,Techmino中的pc练习中空出不规则区域的那个就是PCO。\n更多内容见Hard Drop Wiki。",
+ "https://harddrop.com/wiki?search=Perfect_Clear_Opener",
+ },
+ {"六巧板",
+ "liuqiaoban gracesystem 1stpc",
"setup",
- "一种极大概率能摆出来并且很大概率能做到PC的定式,本游戏中的pc练习中空出不规则区域的那个就是七巧板。",
+ "Grace System,大约有88.57%概率能做到PC的定式,Techmino中的PC练习中空出4×4方形区域就是六巧板。",
},
-
- --形状
+ {"DPC",
+ "DPC",
+ "setup",
+ "在场地空白,7bag还剩一块的情况下,能在很多情况下达到100%搭建率的TSD+PC的定式。更多信息见tetristemplate.info",
+ "https://tetristemplate.info/dpc/",
+ },
+ {"Gamushiro堆叠",
+ "gamushiro",
+ "setup",
+ "ガムシロ積み(Gamushiro堆叠),一种开局TD-Attack的定式。\n更多内容见Hard Drop Wiki。",
+ "https://harddrop.com/wiki?search=Gamushiro_Stacking",
+ },
+ -- # 形状
{"中局定式",
- "中局定式 setup dingshi",
+ "setup dingshi",
"pattern",
"指一些特定的能打出较高伤害的常见典型形状,是中局输出的途径之一,部分也可以在开局做不过不是很有必要,主要见于中局\n另见开局定式,只说定式两个字一般指开局定式而非中局。",
},
- {"Cspin",
- "cspin",
+ {"C-Spin",
+ "cspin tki tdattack",
"pattern",
- "JL脚对脚立起来形成一个C形,缺口做适当的填充后可以打T3+T2。\n"..HDwiki,
- HDsearch.."c-spin",
+ "也被称为TKI堆积,TD-Attack。\n更多内容见Hard Drop Wiki。",
+ "https://harddrop.com/wiki?search=c-spin",
},
{"STSD",
"stsd",
"pattern",
- "Super T-spin Double\n一种能做两个T2的形状。\n如果垃圾行正好空在STSD正下方会暴毙。\n"..HDwiki,
- HDsearch.."stsd",
+ "Super T-spin Double\n一种能做两个T2的形状。\n如果垃圾行正好空在STSD正下方会暴毙。\n更多内容见Hard Drop Wiki。",
+ "https://harddrop.com/wiki?search=stsd",
},
{"STMB",
"stmb",
"pattern",
- "STMB cave\n在高空3宽坑架SZ捐一个T2的形状。\n"..HDwiki,
- HDsearch.."stmb_cave",
+ "STMB cave\n在3宽坑架SZ捐一个T2的形状。\n更多内容见Hard Drop Wiki。",
+ "https://harddrop.com/wiki?search=stmb_cave",
+ },
+ {"双刃剑",
+ "shuangrenjian fractal spider",
+ "pattern",
+ "两个T2形状叠在一起。\n更多内容见Hard Drop Wiki。",
+ "https://harddrop.com/wiki?search=Fractal",
},
{"LST堆叠",
"lst",
"pattern",
- "一种不断b2b一直做T2的堆叠方法。\n"..HDwiki,
- HDsearch.."st_stacking",
+ "一种不断b2b一直做T2的堆叠方法。",
+ "https://www.bilibili.com/read/cv7946210",
},
{"汉堡包",
- "汉堡 hamburger hanbaobao",
+ "hamburger hanbaobao",
"pattern",
- "一种边缘捐T不影响消四的堆叠法。\n"..HDwiki,
- HDsearch.."hamburger",
+ "一种边缘捐T不影响消四的堆叠法。\n更多内容见Hard Drop Wiki。",
+ "https://harddrop.com/wiki?search=hamburger",
},
{"皇家十字",
- "皇家十字 皇十 imperial cross huangjiashizi huangshi",
+ "皇十 imperial cross huangjiashizi huangshi",
"pattern",
- "在一个十字形洞口盖屋檐后可以做两个T2的形状。\n"..HDwiki,
- HDsearch.."imperial_cross",
+ "在一个十字形洞口盖屋檐后可以做两个T2的形状。\n更多内容见Hard Drop Wiki。",
+ "https://harddrop.com/wiki?search=imperial_cross",
},
- {"雨宫炮",
- "雨宫炮 yugong",
+ {"阶梯捐",
+ "jieti kaidan stairs",
"pattern",
- "一种捐T2后可消四的形状,常见于DT的一个分支。",
+ "一种在看起来像阶梯的洞口捐一个T2的形状。\n更多内容见Hard Drop Wiki。",
+ "https://harddrop.com/wiki?search=kaidan",
},
- {"千鸟格子",
- "千鸟格子 qianniaoge",
+ {"社畜train",
+ "shachikutrain shechu",
"pattern",
- "一种在小洞上捐一个T2后还能做一个T2的形状。",
+ "一种在常见T3屋檐上捐两个T2的形状。\n更多内容见Hard Drop Wiki。",
+ "https://harddrop.com/wiki?search=Shachiku_Train",
},
- {"六巧板",
- "六巧板 liuqiaoban",
+ {"千鸟格子",
+ "qianniaoge cutcopy",
"pattern",
- "一种常用于增加中局PC概率的形状,本游戏中的PC练习中空出4×4方形区域就是六巧板。",
+ "一种在小洞上捐一个T2后还能做一个T2的形状。\n更多内容见Hard Drop Wiki。",
+ "https://harddrop.com/wiki?search=Cut_copy",
},
{"绯红之王",
- "绯红之王 feihongzhiwang",
+ "feihongzhiwang king crimson",
"pattern",
- "在STSD上叠若干个T3的形状。",
+ "在STSD上叠若干个T3的形状。\n更多内容见Hard Drop Wiki。",
+ "https://harddrop.com/wiki?search=King_Crimson",
},
-
- --存档管理
+ {"连续PC",
+ "lianxuquanxiao lianxupc pcloop",
+ "pattern",
+ "研究群群友加加编写的一份连续PC教程",
+ "https://docs.qq.com/sheet/DRmxvWmt3SWxwS2tV",
+ },
+ -- # 存档管理
{"控制台",
"console cmd commamd minglinghang kongzhitai",
"command",
@@ -1084,308 +1190,62 @@ return{
{"重置设置",
"reset setting chongzhi qingkong shezhi",
"command",
- "前往控制台输入“rm conf/setting”并回车\n需要重启游戏生效,若反悔,进入设置菜单再退出即可恢复文件。",
+ "前往控制台输入 “rm conf/setting” 并回车\n需要重启游戏生效,若反悔,进入设置菜单再退出即可恢复文件。",
},
{"重置统计数据",
"reset statistic data chongzhi tongji shuju",
"command",
- "前往控制台输入“rm conf/data”并回车\n需要重启游戏生效,若反悔,玩一局并触发结算即可恢复文件。",
+ "前往控制台输入 “rm conf/data” 并回车\n需要重启游戏生效,若反悔,玩一局并触发结算即可恢复文件。",
},
{"重置解锁状态",
"reset unlock chongzhi qingkong jiesuo",
"command",
- "前往控制台输入“rm conf/unlock”并回车\n需要重启游戏生效,若反悔,刷新任意一个模式在地图上的状态即可恢复文件。",
+ "前往控制台输入 “rm conf/unlock” 并回车\n需要重启游戏生效,若反悔,刷新任意一个模式在地图上的状态即可恢复文件。",
},
{"重置本地排行榜",
"reset chongzhi paihangbang",
"command",
- "前往控制台输入“rm -s record”并回车\n需要重启游戏生效,若反悔,玩一局并更新模式排行榜即可恢复对应模式的单个排行榜文件。",
+ "前往控制台输入 “rm -s record” 并回车\n需要重启游戏生效,若反悔,玩一局并更新模式排行榜即可恢复对应模式的单个排行榜文件。",
},
{"删除键位",
"reset virtualkey",
"command",
- "前往控制台输入“rm conf/键位文件”并回车\n键盘是key,虚拟按键是virtualkey,虚拟按键预设是vkSave1(2)\n前两者重启生效,若反悔,进入对应的设置菜单再返回即可恢复文件。",
+ "前往控制台输入 “rm conf/键位文件” 并回车\n键盘是key,虚拟按键是virtualkey,虚拟按键预设是vkSave1(2)\n前两者重启生效,若反悔,进入对应的设置菜单再返回即可恢复文件。",
},
{"删除录像",
"reset replay luxiang",
"command",
- "前往控制台输入“rm -s replay”并回车。\n立即生效。",
+ "前往控制台输入 “rm -s replay” 并回车。\n立即生效。",
},
{"删除缓存",
"reset cache huancun touxiang",
"command",
- "前往控制台输入“rm -s cache”并回车。\n立即生效。",
+ "前往控制台输入 “rm -s cache” 并回车。\n立即生效。",
},
-
- --英文
+ -- # 英文
{"SFX",
- "sfx",
+ "",
"english",
"Sound Effects\n音效(也叫SE)。",
},
{"BGM",
- "bgm",
+ "",
"english",
"Background Music\n背景音乐。",
},
{"TAS",
- "tas",
+ "",
"english",
- "Tool-Assisted Speedrun(Supergaming)\n使用特殊工具在不破坏游戏规则(允许超越人类操作,只是在程序层面不作弊)进行的游戏。\n一般用于冲击理论值或者达成各种有趣的目标用来观赏。\n本游戏中内置了非常简单的TAS工具。",
+ "Tool-Assisted Speedrun(Supergaming)\n使用特殊工具在不破坏游戏规则(允许超越人类操作,只是在程序层面不作弊)进行的游戏。\n一般用于冲击理论值或者达成各种有趣的目标用来观赏。\nTechmino中内置了非常简单的TAS工具。",
},
{"AFK",
- "afk",
+ "",
"english",
"Away from keyboard\n一段时间不接触键盘,就是不玩一段时间,可以缓解手部疲劳,休息好之后马上破纪录也是可能的。",
},
-
- --人物
- {"吉备宏纯",
- "吉备宏纯 hebomai hbm jibei",
- "name",
- "一流玩家(在最强大脑上以3:0击败模电)。",
- },
- {"雨宫太阳",
- "雨宫太阳 amemiya taiyou yugong",
- "name",
- "一流玩家,曾获得PPT的Swap模式冠军。",
- },
- {"Ajanba",
- "ajanba ajb",
- "name",
- "一流玩家,得过Jscup冠军。",
- },
- {"Blink",
- "blink",
- "name",
- "一流玩家,很强。",
- },
- {"Doremy",
- "哆来咪 doremy 123",
- "name",
- "一流玩家,雨宫说他是世界第二。",
- },
- {"Dr.Ocelot",
- "drocelot",
- "name",
- "国外方块游戏开发者,独自开发了Tetra Legends。\n\n和Mine一起开发了Tetra Online,质量欠佳的半成品上架Steam 后受到大量圈内人士批评(但都虚心采纳并修改)。",
- },
- {"Firestorm",
- "firestorm fst",
- "name",
- "一流玩家,得过Jscup冠军。",
- },
- {"Furea",
- "furea fuleiya jk",
- "name",
- "一流玩家,PPT的Ultra的WR保持者。",
- },
- {"Iljain",
- "iljain yijianlian",
- "name",
- "一流玩家,得过C2 Rank1。",
- },
- {"Jonas",
- "jonas",
- "name",
- "(1981-2021)经典块一流玩家,曾经的经典块第一,CTWC4连冠。",
- },
- {"Joseph",
- "joseph",
- "name",
- "经典块一流玩家,CTWC连冠,多项任天堂方块记录保持者。",
- },
- {"Kazu",
- "kazu mdking",
- "name",
- "(也叫“GAMEOVER” “GAMAOVER” “GAME_OVER_RETRY”)\n一流玩家,以熟练md转捐赠闻名(雾)。",
- },
- {"Microblizz",
- "microblizz",
- "name",
- "一流玩家,曾经的世界40L WR。",
- },
- {"Vince",
- "vincehd",
- "name",
- "一流玩家,上任世界最速保持者(无延迟方块)。",
- },
- {"Wumbo",
- "wumbo wangbo",
- "name",
- "一流玩家,有名的爱在对战用开局c4w的世界级玩家(别的能力也很强,只是喜欢开局c4w而已,所以名声不太好)。\n因为名字读音酷似王勃就得了个王勃的外号。",
- },
- {"Yakine",
- "yakine heshui",
- "name",
- "一流玩家,有名的花式T-spin选手,实战压力不大的时候常常做出一些很神仙的高空捐赠,Jstris的20TSD速度榜全球第三名并且没有使用定式(前两名都用了LST),故群友戏称Yakine捐T如喝水。",
- },
-
- {"小Z",
- "小Z xiaoz zictionary tetrodictionary littlez",
- "name",
- "这个词典的名字!\n收录了各种常见术语的简单介绍和一些常用问题的回答,不是那种很详细的百科全书哦~\n曾经是群里的答疑机器人,主要用于方便地给新人答疑解惑,词典的数据开始也是沿用的机器人问答库。\n这个词典在编写的过程中参考了Hard Drop Wiki, Tetris Wiki和灰机Wiki等来源~",
- },
- {"MrZ",
- "mrz zjiang t026 t626",
- "name",
- "【研究群】「T026」\n40L 25.95s,MPH40L 57s排世界第8(Jstris),TETR.IO段位X,TGM3(W)Shirase金1300通关。\n这个游戏的作者!",
- "https://space.bilibili.com/225238922",
- },
-
- {"Circu1ation",
- "circu1ation",
- "name",
- "一流玩家,国内第一个40L Sub20的玩家,TETR.IO段位X。",
- "https://space.bilibili.com/557547205",
- },
- {"Farter",
- "farteryhr pi TTT t000",
- "name",
- "【研究群】「TTTT」\n40L 26.193s\nCN块圈元老之一,T-ex和屁块的作者。",
- "https://space.bilibili.com/132966",
- },
- {"Teatube",
- "teatube ttb chaguan chanaiye sifangchaye t022",
- "name",
- "【研究群】「T022」\n40L 33s top数据高峰约50L70A\n研究群管理,探索群群主,茶服服主,人形方块百科史书,现中文方块维基主催。\n自2011年正式加入CN方块社区以来,以探索方块有趣的思想作为主动力,茶茶今天也在茶馆里当着茶房管理员——\n\n其他名称:TTB,永远旋转的炸弹,茶乃叶,四方茶叶\n明明茶管是蓝孩子却被群友叫茶娘…怎么想都很奇怪啊!嘛大家喜欢的话就随便啦——",
- "https://space.bilibili.com/834903",
- },
- {"Sniraite",
- "sniraite shege 11renpc t024",
- "name",
- "【研究群】「T024」\n40L Sub 23\n国内一流方块玩家,应该是大陆最速。",
- "https://space.bilibili.com/561589",
- },
- {"xb",
- "xb t043",
- "name",
- "【研究群】「T043」\n俄罗斯方块中文维基(灰机wiki)主要编者(之一。",
- "https://space.bilibili.com/226132",
- },
- {"Flyz",
- "flyz fxg t114",
- "name",
- "【研究群】「T114」\n高技术力。",
- "https://space.bilibili.com/787096",
- },
- {"gggf",
- "xiaoqi kissne gggf t127",
- "name",
- "【研究群】「T127」\n40L 22.677s(手机25.483),tetr.io段位X\n20G规则国内一流玩家,拿到了TGM3几乎全部的最终成就(全世界都没几个)。\n其他名称:小柒 kissne 127。\n还是车车人,几个正作成绩:永EX NM 1B FS 风L NM。",
- "https://space.bilibili.com/287769888",
- },
- {"蕴空之灵",
- "蕴空之灵 ykzl yunkongzhiling niao bird t196",
- "name",
- "【研究群】「T196」\n40L 33s。\nvup,效率之光,不能吃辣。\n常用定式:信天翁 TKI3 开局PC。",
- "https://space.bilibili.com/9964553",
- },
- {"口〇口",
- "口〇口 mono kouquankou dongxi t210",
- "name",
- "【研究群】「T210」\n【不是虚拟主播哦】,Techmino配音之一。",
- "https://space.bilibili.com/1048531896",
- },
- {"奏之章",
- "奏之章 zzz zouzhizhang t274",
- "name",
- "【研究群】「T274」\nzzzbot的作者,CN块圈人工智能技术发展重要人物之一。",
- "https://space.bilibili.com/311039",
- },
- {"吴淞昊",
- "吴淞昊 模电 wusonghao electric modian zhunbei t283",
- "name",
- "【研究群】「T283」\n国内一流隐形方块玩家,TGM3 World S13+GM,上过最强大脑。",
- "https://space.bilibili.com/17583394",
- },
- {"他天一",
- "他天一 tty tatianyi hydrofierus t512",
- "name",
- "【研究群】「T512」\n其他名称:Hydrofierus\n40L 21.908s,IO段位X\nC2/SRS对战水平国内一流\n常用定式:TKI 开局PC。",
- "https://space.bilibili.com/3895759",
- },
- {"Mars608",
- "mars huoxingge t608",
- "name",
- "【研究群】「T608」\n拿过NS PPT国区榜首。",
- "https://space.bilibili.com/1471400",
- },
- {"Mifu",
- "mifu swl nanmaomao t616",
- "name",
- "【研究群】「T616」\n40L 28.445s。\nvup,miya的哥哥。",
- "https://space.bilibili.com/109356367",
- },
- {"ZXC",
- "zxc thtsod flag ctf t655",
- "name",
- "【研究群】「T655」\n高技术力。",
- "https://space.bilibili.com/4610502",
- },
- {"Tinko",
- "tinko t665",
- "name",
- "【研究群】「T665」\n高技术力。",
- "https://tinko.moe",
- },
- {"T0722",
- "t0722",
- "name",
- "【研究群】「T0722」\n音乐人。",
- "https://space.bilibili.com/30452985",
- },
- {"Diao",
- "diao mengxin t872",
- "name",
- "【研究群】「T872」\n(但这人老故意空着群名片啥都不写),一流对战选手,得过Jscup亚军,TTT冠军,HDO XII冠军\n有大量曾用名(nmdtql/diao/nanami等,还有一大堆高仿名)。",
- "https://space.bilibili.com/471341780",
- },
- {"思竣",
- "思竣 sijun t942 acm oi",
- "name",
- "【研究群】「T942」\n算力极强的思维型选手。",
- "https://space.bilibili.com/403250559",
- },
- {"柒栎流星",
- "t1013",
- "name",
- "【研究群】「T1013」\n音乐人。",
- "https://space.bilibili.com/201145153",
- },
- {"Particle_G",
- "particleg t1080",
- "name",
- "【研究群】「T1080」\n40L 59.4s\nTechmino后端(服务器)主要开发人员。",
- "https://space.bilibili.com/3306106",
- },
- {"琳雨空",
- "琳雨空 linyukong t1505",
- "name",
- "【研究群】「T1505」\n40L 38.3s,五连块最高评级,黑屏隐形最高评级(世界首位)。",
- "https://space.bilibili.com/263909369",
- },
- {"子心",
- "子心 koishi zixin t1934",
- "name",
- "【研究群】「T1934」\nvup,T99国内一流战术型玩家。",
- "https://space.bilibili.com/147529",
- },
- {"ditoly",
- "葵 ditoly icrem kuimei bingqilin jk t3055",
- "name",
- "【研究群】「T3055」\n被清华劝退现于北大的打块天才jk(雾\n(好像也被北大劝退了?不知道)\n正在进行Nanamino的开发。",
- "https://space.bilibili.com/13014410",
- },
- {"蓝绿",
- "蓝绿 lanlv lanlyu gompyn imple lee blari'o blariho t3182",
- "name",
- "【研究群】「T3182」\n高技术力,参与了。",--Techmino后端开发
- },
- {"喵田弥夜",
- "喵田弥夜 miya miaotianmiye mao t7023",
- "name",
- "【研究群】「T7023」\nvup,喜欢打块的猫猫(Z酱单推),Techmino配音之一。",
- "https://space.bilibili.com/846180",
+ {"Timing",
+ "timing shiji fanji",
+ "term",
+ "Time作动词时的动名词形式,意为抓时机。在方块中往往指根据双方形势选择打出攻击的时机,和要不要故意吃下对手的攻击防止抵消,然后再把自己的攻击打过去。可以一定程度上提高对战的优势,但对于新人来说连自己场地都看不明白还看啥对面,有时间分析形势不如提速提效来得更好。",
},
}
diff --git a/parts/language/lang_en.lua b/parts/language/lang_en.lua
index 0972b5bb9..a2d6e7324 100644
--- a/parts/language/lang_en.lua
+++ b/parts/language/lang_en.lua
@@ -1,5 +1,5 @@
local C=COLOR
-return{
+return {
loadText={
loadSFX="Loading sound effects",
loadSample="Loading instrument samples",
@@ -14,15 +14,17 @@ return{
sureReset="Press again to reset",
sureDelete="Press again to delete",
newDay="A new day, a new beginning!",
- playedLong="You have been playing for a long time. Time to a break!",
+ playedLong="You have been playing for a long time. Time to take a break!",
playedTooMuch="You have been playing for far too long! Techmino is fun, but remember to take some rests!",
- settingWarn="Careful - you're about to change some uncommon settings!",
+ settingWarn="Careful — you’re about to change some uncommon settings!",
+ settingWarn2="This setting takes effect after restart",
atkModeName={"Random","Badges","K.O.s","Attackers"},
royale_remain="$1 Players Left",
powerUp={[0]="+000%","+025%","+050%","+075%","+100%"},
cmb={nil,"1 Combo","2 Combo","3 Combo","4 Combo","5 Combo","6 Combo","7 Combo","8 Combo","9 Combo","10 Combo!","11 Combo!","12 Combo!","13 Combo!","14 Combo!!","15 Combo!!","16 Combo!!","17 Combo!!!","18 Combo!!!","19 Combo!!!","MEGACMB"},
- spin="-spin",
+ spin="-spin ",
+ spinNC="-spin",
clear={"Single","Double","Triple","Techrash","Pentacrash","Hexacrash","Heptacrash","Octacrash","Nonacrash","Decacrash","Undecacrash","Dodecacrash","Tridecacrash","Tetradecacrash","Pentadecacrash","Hexadecacrash","Heptadecacrash","Octadecacrash","Nonadecacrash","Ultracrash","Impossicrash"},
cleared="$1 lines",
mini="Mini",b2b="B2B ",b3b="B2B2B ",
@@ -59,7 +61,7 @@ return{
finesse_ap="All Perfect",
finesse_fc="Full Combo",
- page="Page:",
+ page="Page ",
cc_fixed="CC is incompatible with fixed sequences.",
cc_swap="CC is incompatible when the hold mode is set to Swap.",
@@ -103,47 +105,98 @@ return{
dictNote="==Copied from TetroDictionary==",
- getNoticeFail="Failed to fetch announcements",
+
+
+ -- Server's warn/error messages
+ Techrater={
+ internalError="Internal error",
+ databaseError="Database error",
+ invalidFormat="Invalid format",
+ invalidArguments="Invalid arguments",
+ tooFrequent="Too frequent",
+ notAvailable="Not available",
+ noPermission="No permission",
+ roomNotFound="Room not found",
+
+ -- Controllers
+ WebSocket={
+ invalidConnection="Invalid connection",
+ invalidAction="Invalid action",
+ playerNotFound="Player not found",
+ connectionFailed="Connection failed",
+ },
+ -- Filters
+ CheckPermission={
+ playerNotFound="Player not found",
+ },
+ -- Plugins
+ ConnectionManager={
+ playerInvalid="Player invalid",
+ playerNotFound="Player not found",
+ connectionReplaced="Connection replaced",
+ },
+ NoticeManager={
+ noticeNotFound="Notice not found",
+ },
+ PlayerManager={
+ invalidCode="Invalid code",
+ invalidEmail="Invalid email",
+ playerNotFound="Player not found",
+ invalidEmailPass="Invalid email or password",
+ emailExists="Email exists",
+ emailSendError="Email send error",
+ },
+ -- Strategies
+ PlayerRole={
+ invalidRole="Invalid role",
+ invalidTarget="Invalid target",
+ },
+ PlayerType={
+ invalidType="Invalid type",
+ roomFull="Room full",
+ },
+ RoomJoin={
+ wrongPassword="Wrong password",
+ },
+ },
+
+ tooFrequent="Request too frequently",
+ roomPasswordChanged="Room password changed",
oldVersion="Version $1 is now available",
- needUpdate="Newer version required!",
versionNotMatch="Versions do not match!",
notFinished="Coming soon!",
- jsonError="JSON error",
-
noUsername="Please enter your username",
wrongEmail="Invalid email address",
+ wrongCode="Invalid verification code",
noPassword="Please enter your password",
- diffPassword="Passwords don't match",
- registerRequestSent="A sign up request has been sent.",
- registerSuccessed="Sign up successful!",
- loginSuccessed="You are now logged in!",
- accessSuccessed="Access granted",
-
- wsConnecting="Websocket connecting…",
- wsFailed="WebSocket connection failed",
- wsClose="WebSocket closed:",
+ diffPassword="Passwords don’t match",
+ checkEmail="A sign up request has been sent.",
+
+ wsFailed="WebSocket connection failed: $1",
+ wsClose="WebSocket closed: $1",
netTimeout="Connection timed out",
+ serverDown="Oops! Server is down",
+ requestFailed="Request failed",
- onlinePlayerCount="Online",
+ onlinePlayerCount="Online: $1",
createRoomSuccessed="Room created",
+ playerKicked="$1 removed $2 from room",
+ becomeHost="$1 become host",
started="Playing",
- joinRoom="has entered the room.",
- leaveRoom="has left the room.",
+ joinRoom="$1 has entered the room.",
+ leaveRoom="$1 has left the room.",
+ roomRemoved="Room was removed",
ready="Ready",
- connStream="Connecting",
- waitStream="Waiting",
spectating="Spectating",
- chatRemain="Online",
- chatStart="------Beginning of log------",
- chatHistory="------New messages below------",
+
+
keySettingInstruction="Press to bind key\nescape: cancel\nbackspace: delete",
customBGhelp="Drop image file here to apply custom background",
customBGloadFailed="Unsupport image format for custom background",
errorMsg="Techmino ran into a problem and needs to restart.\nYou can send the error log to the developers.",
- tryAnotherBuild="[Invalid UTF-8] If you are on Windows, try downloading Techmino-win32 or Techmino-win64 (different from what you are using now).",
modInstruction="Choose your modifiers!\nMods allow you to change the game,\nbut they may also crash the game.\nScores will not be saved when using mods.",
modInfo={
@@ -183,7 +236,7 @@ return{
"Finesse:",
},
radar={"DEF","OFF","ATK","SEND","SPD","DIG"},
- radarData={"D'PM","ADPM","APM","SPM","L'PM","DPM"},
+ radarData={"D’PM","ADPM","APM","SPM","L’PM","DPM"},
stat={
"Times Launched:",
"Play Count:",
@@ -198,16 +251,16 @@ return{
"Fns. Errs/Rate:",
},
aboutTexts={
- "This is just an *ordinary* block stacker. Really, that's it.",
+ "This is just an *ordinary* block stacker. Really, that’s it.",
"Inspired by C2/IO/JS/WWC/KOS etc.",
"",
"Powered by LÖVE",
"Any suggestions or bug reports are appreciated!",
"Make sure to get the game only from official sources,",
- "as we can't make sure you're safe if you got it elsewhere.",
+ "as we can’t make sure you’re safe if you got it elsewhere.",
"The author is not responsible for any modifications.",
- FNNS and"/"or"While the game is free, donations are appreciated.",
- FNNS and"/"or"Check Zictionary for more",
+ FNNS and "/" or "While the game is free, donations are appreciated.",
+ FNNS and "/" or "Check Zictionary for more",
},
staff={
"ORIGINALLY BY MrZ",
@@ -250,6 +303,12 @@ return{
"(旋律星萤)",
"(T0722)",
"",
+ "Illustrations",
+ "Miya",
+ "Mono",
+ "Xiaoya",
+ "葉枭",
+ "",
"Musical Designs",
"MrZ",
"柒栎流星",
@@ -275,7 +334,9 @@ return{
"ScF",
"C₂₉H₂₅N₃O₅",
"NOT_A_ROBOT",
- "sakurw",
+ "XMiao",
+ "sakurw, Airun, 幽灵3383",
+ "Shard Nguyễn, Squishy, TVN community",
"",
"Performances",
"Electric283",
@@ -314,13 +375,49 @@ return{
Cold_Clear [MinusKelvin]
json.lua [rxi]
profile.lua [itraykov]
- simple-love-lights [dylhunn]
+ sha2 [Egor Skriptunoff]
]],
support="Support the author",
+ dict={
+ sizeChanged="Changed font size: $1",
+ sizeReset="Font size has been reset!",
+ helpText=
+[[
+INSTRUCTIONS FOR NAVIGATION IN TETRODICTIONARY
+
+A. Mouse / Touchscreen
+ - Press/touch a term in the list on the left to select the entry
+
+ - Press/touch [$14] to copy the content of the current entry
+ - Press/touch [$15] to open the link of the current entry (if available)
+
+B. Keyboard
+ Press...
+ - [F1] to display Help
+ - [$1] or [$2] to scroll through the text
+ - [$3] to open the previous entry and [$4] to open the next entry, speed up with [Ctrl]
+
+ - [-] to decrease the font size, [+] to increase the font size
+ - [0] to restore the default font size
+
+ - [Ctrl + C] to copy text
+ - [$16] (Context Menu key/Application key) to open the link of the current entry (if available)
+
+C. Gamepad
+ - Press $10 to display Help
+ - Press $5 or $6 to scroll through the text, speed up with $11
+ - Press $7 to open the previous entry and $8 to open the next entry. Speed up with $11
+ - Hold $11 and press $6 to decrease the font size or $5 to increase
+]]
+ -- 1-4: Up, Down, Left, Right
+ -- 5-8: Up, Down, Left, Right but D-Pad
+ -- 9-12: X, Y, A, B
+ -- 13-16: Help, Copy, Open, MENU
+ },
WidgetText={
main={
offline="Single Player",
- qplay="Last Played",
+ qplay="Last Played: ",
online="Multiplayer",
custom="Custom Game",
setting="Settings",
@@ -354,6 +451,7 @@ return{
league="Tech League",
ffa="FFA",
rooms="Rooms",
+ resetPW="Reset password",
logout="Log out",
},
net_league={
@@ -369,7 +467,7 @@ return{
},
net_newRoom={
title="Room Config",
- roomName="Room name (Default: \"[username]'s room\")",
+ roomName="Room name (Default: “[username]'s room”)",
password="Password",
description="Room Description",
@@ -430,7 +528,6 @@ return{
sysCursor="Use System Cursor",
autoPause="Pause When Unfocused",
autoSave="Auto-save New Records",
- autoLogin="Auto-login on Start",
simpMode="Simplistic Mode",
},
setting_video={
@@ -458,7 +555,6 @@ return{
atkFX="Atk FX",
frame="Render Frame Rate (%)",
- FTlock="Frame skip",
text="Line Clear Pop-Ups",
score="Score Pop-Ups",
@@ -472,6 +568,8 @@ return{
power="Battery Info",
clean="Quick Draw",
fullscreen="Fullscreen",
+ portrait="Portrait",
+ msaa="MSAA level",
bg_on="Normal B.G.",
bg_off="No B.G.",
@@ -550,11 +648,11 @@ return{
shape="Shape",
},
setting_touchSwitch={
- b1= "Move Left:", b2="Move Right:", b3="Rotate Right:", b4="Rotate Left:",
- b5= "Rotate 180°:", b6="Hard Drop:", b7="Soft Drop:", b8="Hold:",
- b9= "Function 1:", b10="Function 2:", b11="Instant Left:", b12="Instant Right:",
- b13="Sonic Drop:", b14="Down 1:", b15="Down 4:", b16="Down 10:",
- b17="Left Drop:", b18="Right Drop:",b19="Left Zangi:", b20="Right Zangi:",
+ b1= "Move Left:", b2="Move Right:", b3="Rotate Right:", b4="Rotate Left:",
+ b5= "Rotate 180°:", b6="Hard Drop:", b7="Soft Drop:", b8="Hold:",
+ b9= "Function 1:", b10="Function 2:", b11="Instant Left:", b12="Instant Right:",
+ b13="Sonic Drop:", b14="Down 1:", b15="Down 4:", b16="Down 10:",
+ b17="Left Drop:", b18="Right Drop:", b19="Left Zangi:", b20="Right Zangi:",
norm="Normal",
pro="Advanced",
@@ -629,7 +727,7 @@ return{
push="Add Line (K)",
del="Del Line (L)",
- demo="Don't Show ×",
+ demo="Don’t Show “×”",
newPg="New Page (N)",
delPg="Del Page (M)",
@@ -684,21 +782,18 @@ return{
},
login={
title="Sign In",
- register="Sign Up",
- email="Email Address",
- password="Password",
- keepPW="Remember me",
- login="Log In",
- },
- register={
- title="Sign Up",
- login="Sign In",
- username="Username",
- email="Email Address",
+ ticket="Auth Ticket",
+ authorize="Go Authorizing",
+ paste="Paste Ticket",
+ submit="Submit",
+ },
+ reset_password={
+ title="Reset Password",
+ send="Send code",
+ code="Verification Code",
password="Password",
password2="Re-enter Password",
- register="Sign Up",
- registering="Waiting for response…",
+ setPW="Set Password",
},
account={
title="Account",
@@ -755,112 +850,122 @@ return{
},
},
modes={
- ['sprint_10l']= {"Sprint", "10L", "Clear 10 lines!"},
- ['sprint_20l']= {"Sprint", "20L", "Clear 20 lines!"},
- ['sprint_40l']= {"Sprint", "40L", "Clear 40 lines!"},
- ['sprint_100l']= {"Sprint", "100L", "Clear 100 lines!"},
- ['sprint_400l']= {"Sprint", "400L", "Clear 400 lines!"},
- ['sprint_1000l']= {"Sprint", "1,000L", "Clear 1,000 lines!"},
- ['sprintPenta']= {"Sprint", "PENTOMINO", "40L with 18 pentominoes"},
- ['sprintMPH']= {"Sprint", "MPH", "Memoryless\nPreviewless\nHoldless"},
- ['dig_10l']= {"Dig", "10L", "Dig 10 garbage lines"},
- ['dig_40l']= {"Dig", "40L", "Dig 40 garbage lines"},
- ['dig_100l']= {"Dig", "100L", "Dig 100 garbage lines"},
- ['dig_400l']= {"Dig", "400L", "Dig 400 garbage lines"},
- ['drought_n']= {"Drought", "100L", "No I-pieces available"},
- ['drought_l']= {"Drought+", "100L", "W T F"},
- ['marathon_n']= {"Marathon", "NORMAL", "200-line marathon with increasing speed"},
- ['marathon_h']= {"Marathon", "HARD", "200-line high-speed marathon"},
- ['solo_e']= {"Battle", "EASY", "Defeat the AI!"},
- ['solo_n']= {"Battle", "NORMAL", "Defeat the AI!"},
- ['solo_h']= {"Battle", "HARD", "Defeat the AI!"},
- ['solo_l']= {"Battle", "LUNATIC", "Defeat the AI!"},
- ['solo_u']= {"Battle", "ULTIMATE", "Defeat the AI!"},
- ['techmino49_e']= {"Tech 49", "EASY", "49-player battle.\nThe last one standing wins"},
- ['techmino49_h']= {"Tech 49", "HARD", "49-player battle.\nThe last one standing wins"},
- ['techmino49_u']= {"Tech 49", "ULTIMATE", "49-player battle.\nThe last one standing wins"},
- ['techmino99_e']= {"Tech 99", "EASY", "99-player battle.\nThe last one standing wins"},
- ['techmino99_h']= {"Tech 99", "HARD", "99-player battle.\nThe last one standing wins"},
- ['techmino99_u']= {"Tech 99", "ULTIMATE", "99-player battle.\nThe last one standing wins"},
- ['round_e']= {"Turn-Based", "EASY", "Take turns to play against the AI!"},
- ['round_n']= {"Turn-Based", "NORMAL", "Take turns to play against the AI!"},
- ['round_h']= {"Turn-Based", "HARD", "Take turns to play against the AI!"},
- ['round_l']= {"Turn-Based", "LUNATIC", "Take turns to play against the AI!"},
- ['round_u']= {"Turn-Based", "ULTIMATE", "Take turns to play against the AI!"},
- ['master_n']= {"Master", "NORMAL", "For 20G beginners"},
- ['master_h']= {"Master", "HARD", "For 20G pros"},
- ['master_m']= {"Master", "M21", "For 20G Masters"},
- ['master_final']= {"Master", "FINAL", "20G and beyond"},
- ['master_ph']= {"Master", "PHANTASM", "???"},
- ['master_ex']= {"GrandMaster", "EXTRA", "An eternity shorter than an instant"},
- ['master_instinct']={"Master", "INSTINCT", "What if the active piece turned invisible?"},
- ['strategy_e']= {"Strategy", "EASY", "Fast 20G decision"},
- ['strategy_h']= {"Strategy", "HARD", "Fast 20G decision"},
- ['strategy_u']= {"Strategy", "ULTIMATE", "Fast 20G decision"},
- ['strategy_e_plus']={"Strategy", "EASY+", "Fast 20G decision"},
- ['strategy_h_plus']={"Strategy", "HARD+", "Fast 20G decision"},
- ['strategy_u_plus']={"Strategy", "ULTIMATE+", "Fast 20G decision"},
- ['blind_e']= {"Invisible", "HALF", "For novices"},
- ['blind_n']= {"Invisible", "ALL", "For intermediates"},
- ['blind_h']= {"Invisible", "SUDDEN", "For the experienced"},
- ['blind_l']= {"Invisible", "SUDDEN+", "For professionals"},
- ['blind_u']= {"Invisible", "?", "Are you ready?"},
- ['blind_wtf']= {"Invisible", "WTF", "You're not ready"},
- ['classic_e']= {"Classic", "EASY", "A very low-speed recreation from the 80s"},
- ['classic_h']= {"Classic", "HARD", "A medium speed recreation from the 80s"},
- ['classic_u']= {"Classic", "ULTIMATE", "A very high-speed recreation from the 80s"},
- ['survivor_e']= {"Survival", "EASY", "How long can you survive?"},
- ['survivor_n']= {"Survival", "NORMAL", "How long can you survive?"},
- ['survivor_h']= {"Survival", "HARD", "How long can you survive?"},
- ['survivor_l']= {"Survival", "LUNATIC", "How long can you survive?"},
- ['survivor_u']= {"Survival", "ULTIMATE", "How long can you survive?"},
- ['attacker_h']= {"Attacker", "HARD", "Practice your attacking skills!"},
- ['attacker_u']= {"Attacker", "ULTIMATE", "Practice your attacking skills!"},
- ['defender_n']= {"Defender", "NORMAL", "Practice your defencing skills!"},
- ['defender_l']= {"Defender", "LUNATIC", "Practice your defencing skills!"},
- ['dig_h']= {"Driller", "HARD", "Digging practice!"},
- ['dig_u']= {"Driller", "ULTIMATE", "Digging practice!"},
- ['clearRush']= {"Clear Rush", "NORMAL", "All-spin tutorial!\n[Under construction]"},
- ['c4wtrain_n']= {"C4W Training", "NORMAL", "Infinite combos"},
- ['c4wtrain_l']= {"C4W Training", "LUNATIC", "Infinite combos"},
- ['pctrain_n']= {"PC Training", "NORMAL", "Perfect Clear practice"},
- ['pctrain_l']= {"PC Training", "LUNATIC", "A harder Perfect Clear practice"},
- ['pc_n']= {"PC Challenge", "NORMAL", "Get PCs within 100 lines!"},
- ['pc_h']= {"PC Challenge", "HARD", "Get PCs within 100 lines!"},
- ['pc_l']= {"PC Challenge", "LUNATIC", "Get PCs within 100 lines!"},
- ['pc_inf']= {"Inf. PC Challenge", "", "Get PCs as much as you can"},
- ['tech_n']= {"Tech", "NORMAL", "Try to keep the\nBack-to-Back chain!"},
- ['tech_n_plus']= {"Tech", "NORMAL+", "Spins & PCs only"},
- ['tech_h']= {"Tech", "HARD", "Try to keep the\nBack-to-Back chain!"},
- ['tech_h_plus']= {"Tech", "HARD+", "Spins & PCs only"},
- ['tech_l']= {"Tech", "LUNATIC", "Try to keep the\nBack-to-Back chain!"},
- ['tech_l_plus']= {"Tech", "LUNATIC+", "Spins & PCs only"},
- ['tech_finesse']= {"Tech", "FINESSE", "No finesse faults!"},
- ['tech_finesse_f']= {"Tech", "FINESSE+", "No normal clears and finesse faults!"},
- ['tsd_e']= {"TSD Challenge", "EASY", "T-Spin Doubles only!"},
- ['tsd_h']= {"TSD Challenge", "HARD", "T-Spin Doubles only!"},
- ['tsd_u']= {"TSD Challenge", "ULTIMATE", "T-Spin Doubles only!"},
- ['backfire_n']= {"Backfire", "NORMAL", "Hold back the backfiring garbage lines"},
- ['backfire_h']= {"Backfire", "HARD", "Hold back the backfiring garbage lines"},
- ['backfire_l']= {"Backfire", "LUNATIC", "Hold back the backfiring garbage lines"},
- ['backfire_u']= {"Backfire", "ULTIMATE", "Hold back the backfiring garbage lines"},
- ['sprintAtk']= {"Sprint", "100 Attack", "Send 100 lines!"},
- ['sprintEff']= {"Sprint", "Efficiency", "Send more attack in 40lines!"},
- ['zen']= {'Zen', "200", "A 200-line run without a time limit"},
- ['ultra']= {'Ultra', "EXTRA", "A 2-minute score attack"},
- ['infinite']= {"Infinite", "", "Just a sandbox"},
- ['infinite_dig']= {"Infinite: Dig", "", "Dig-diggin'-dug"},
- ['marathon_inf']= {"Marathon", "INFINITE", "Infinite marathon."},
+ ['sprint_10l']= {"Sprint", "10L", "Clear 10 lines!"},
+ ['sprint_20l']= {"Sprint", "20L", "Clear 20 lines!"},
+ ['sprint_40l']= {"Sprint", "40L", "Clear 40 lines!"},
+ ['sprint_100l']= {"Sprint", "100L", "Clear 100 lines!"},
+ ['sprint_400l']= {"Sprint", "400L", "Clear 400 lines!"},
+ ['sprint_1000l']= {"Sprint", "1,000L", "Clear 1,000 lines!"},
+ ['sprintPenta']= {"Sprint", "PENTOMINO", "40L with 18 pentominoes"},
+ ['sprintMPH']= {"Sprint", "MPH", "Memoryless\nPreviewless\nHoldless"},
+ ['sprint123']= {"Sprint", "M123", "40L with only monominoes, dominoes, and triminoes"},
+ ['secret_grade']= {"Secret Grade", "", "Build a zig-zag hole formation, following to the guide!"},
+ ['dig_10l']= {"Dig", "10L", "Dig 10 garbage lines as fast as you can!"},
+ ['dig_40l']= {"Dig", "40L", "Dig 40 garbage lines as fast as you can!"},
+ ['dig_100l']= {"Dig", "100L", "Dig 100 garbage lines as fast as you can!"},
+ ['dig_400l']= {"Dig", "400L", "Dig 400 garbage lines as fast as you can!"},
+ ['dig_eff_10l']= {"Dig", "EFFICIENCY 10L", "Dig 10 garbage lines with the least pieces!"},
+ ['dig_eff_40l']= {"Dig", "EFFICIENCY 40L", "Dig 40 garbage lines with the least pieces!"},
+ ['dig_eff_100l']= {"Dig", "EFFICIENCY 100L","Dig 100 garbage lines with the least pieces!"},
+ ['dig_eff_400l']= {"Dig", "EFFICIENCY 400L","Dig 400 garbage lines with the least pieces!"},
+ ['dig_quad_10l']= {"Dig", "TECHRASH 10L", "Dig 10 garbage lines using only techrash!"},
+ ['drought_n']= {"Drought", "100L", "No I-pieces available"},
+ ['drought_l']= {"Drought+", "100L", "W T F"},
+ ['marathon_n']= {"Marathon", "NORMAL", "200-line marathon with increasing speed"},
+ ['marathon_h']= {"Marathon", "HARD", "200-line high-speed marathon"},
+ ['solo_e']= {"Battle", "EASY", "Defeat the AI!"},
+ ['solo_n']= {"Battle", "NORMAL", "Defeat the AI!"},
+ ['solo_h']= {"Battle", "HARD", "Defeat the AI!"},
+ ['solo_l']= {"Battle", "LUNATIC", "Defeat the AI!"},
+ ['solo_u']= {"Battle", "ULTIMATE", "Defeat the AI!"},
+ ['techmino49_e']= {"Tech 49", "EASY", "49-player battle.\nThe last one standing wins"},
+ ['techmino49_h']= {"Tech 49", "HARD", "49-player battle.\nThe last one standing wins"},
+ ['techmino49_u']= {"Tech 49", "ULTIMATE", "49-player battle.\nThe last one standing wins"},
+ ['techmino99_e']= {"Tech 99", "EASY", "99-player battle.\nThe last one standing wins"},
+ ['techmino99_h']= {"Tech 99", "HARD", "99-player battle.\nThe last one standing wins"},
+ ['techmino99_u']= {"Tech 99", "ULTIMATE", "99-player battle.\nThe last one standing wins"},
+ ['round_e']= {"Turn-Based", "EASY", "Take turns to play against the AI!"},
+ ['round_n']= {"Turn-Based", "NORMAL", "Take turns to play against the AI!"},
+ ['round_h']= {"Turn-Based", "HARD", "Take turns to play against the AI!"},
+ ['round_l']= {"Turn-Based", "LUNATIC", "Take turns to play against the AI!"},
+ ['round_u']= {"Turn-Based", "ULTIMATE", "Take turns to play against the AI!"},
+ ['big_n']= {"Big", "NORMAL", "Play in a smaller field!"},
+ ['big_h']= {"Big", "HARD", "Play in a smaller field!"},
+ ['master_n']= {"Master", "NORMAL", "For 20G beginners"},
+ ['master_h']= {"Master", "HARD", "For 20G pros"},
+ ['master_m']= {"Master", "M21", "For 20G Masters"},
+ ['master_final']= {"Master", "FINAL", "20G and beyond"},
+ ['master_ph']= {"Master", "PHANTASM", "???"},
+ ['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 turned invisible?"},
+ ['strategy_e']= {"Strategy", "EASY", "Fast 20G decision"},
+ ['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", "HALF", "For novices"},
+ ['blind_n']= {"Invisible", "ALL", "For intermediates"},
+ ['blind_h']= {"Invisible", "SUDDEN", "For the experienced"},
+ ['blind_l']= {"Invisible", "SUDDEN+", "For professionals"},
+ ['blind_u']= {"Invisible", "?", "Are you ready?"},
+ ['blind_wtf']= {"Invisible", "WTF", "You’re not ready"},
+ ['classic_e']= {"Classic", "EASY", "A low-speed recreation from the 80s"},
+ ['classic_h']= {"Classic", "HARD", "A medium-speed recreation from the 80s"},
+ ['classic_l']= {"Classic", "LUNATIC", "A high-speed recreation from the 80s"},
+ ['classic_u']= {"Classic", "ULTIMATE", "A very high-speed recreation from the 80s"},
+ ['survivor_e']= {"Survival", "EASY", "How long can you survive?"},
+ ['survivor_n']= {"Survival", "NORMAL", "How long can you survive?"},
+ ['survivor_h']= {"Survival", "HARD", "How long can you survive?"},
+ ['survivor_l']= {"Survival", "LUNATIC", "How long can you survive?"},
+ ['survivor_u']= {"Survival", "ULTIMATE", "How long can you survive?"},
+ ['attacker_h']= {"Attacker", "HARD", "Practice your attacking skills!"},
+ ['attacker_u']= {"Attacker", "ULTIMATE", "Practice your attacking skills!"},
+ ['defender_n']= {"Defender", "NORMAL", "Practice your defensing skills!"},
+ ['defender_l']= {"Defender", "LUNATIC", "Practice your defensing skills!"},
+ ['dig_h']= {"Driller", "HARD", "Digging practice!"},
+ ['dig_u']= {"Driller", "ULTIMATE", "Digging practice!"},
+ ['c4wtrain_n']= {"C4W Training", "NORMAL", "Infinite combos"},
+ ['c4wtrain_l']= {"C4W Training", "LUNATIC", "Infinite combos"},
+ ['pctrain_n']= {"PC Training", "NORMAL", "Perfect Clear practice"},
+ ['pctrain_l']= {"PC Training", "LUNATIC", "A harder Perfect Clear practice"},
+ ['pc_n']= {"PC Challenge", "NORMAL", "Get PCs within 100 lines!"},
+ ['pc_h']= {"PC Challenge", "HARD", "Get PCs within 100 lines!"},
+ ['pc_l']= {"PC Challenge", "LUNATIC", "Get PCs within 100 lines!"},
+ ['pc_inf']= {"Inf. PC Challenge", "", "Get PCs as much as you can"},
+ ['tech_n']= {"Tech", "NORMAL", "Try to keep the\nBack-to-Back chain!"},
+ ['tech_n_plus']= {"Tech", "NORMAL+", "Spins & PCs only"},
+ ['tech_h']= {"Tech", "HARD", "Try to keep the\nBack-to-Back chain!"},
+ ['tech_h_plus']= {"Tech", "HARD+", "Spins & PCs only"},
+ ['tech_l']= {"Tech", "LUNATIC", "Try to keep the\nBack-to-Back chain!"},
+ ['tech_l_plus']= {"Tech", "LUNATIC+", "Spins & PCs only"},
+ ['tech_finesse']= {"Tech", "FINESSE", "No finesse faults!"},
+ ['tech_finesse_f']= {"Tech", "FINESSE+", "No normal clears and finesse faults!"},
+ ['tsd_e']= {"TSD Challenge", "EASY", "T-Spin Doubles only!"},
+ ['tsd_h']= {"TSD Challenge", "HARD", "T-Spin Doubles only!"},
+ ['tsd_u']= {"TSD Challenge", "ULTIMATE", "T-Spin Doubles only!"},
+ ['backfire_n']= {"Backfire", "NORMAL", "Hold back the backfiring garbage lines"},
+ ['backfire_h']= {"Backfire", "HARD", "Hold back the backfiring garbage lines"},
+ ['backfire_l']= {"Backfire", "LUNATIC", "Hold back the backfiring garbage lines"},
+ ['backfire_u']= {"Backfire", "ULTIMATE", "Hold back the backfiring garbage lines"},
+ ['sprintAtk']= {"Sprint", "100 Attack", "Send 100 lines!"},
+ ['sprintEff']= {"Sprint", "Efficiency", "Send more attack in 40lines!"},
+ ['zen']= {'Zen', "200", "A 200-line run without a time limit"},
+ ['ultra']= {'Ultra', "EXTRA", "A 2-minute score attack"},
+ ['infinite']= {"Infinite", "", "Just a sandbox"},
+ ['infinite_dig']= {"Infinite: Dig", "", "Dig-diggin’-dug"},
+ ['marathon_inf']= {"Marathon", "INFINITE", "Infinite marathon."},
['custom_clear']= {"Custom", "NORMAL"},
['custom_puzzle']= {"Custom", "PUZZLE"},
},
getTip={refuseCopy=true,
":pog:",
- "(RUR'U')R'FR2U'R'U'(RUR'F')",
- "\"Techmino.app\" cannot be opened because the developer cannot be verified.",
- "\"Techmino.app\" will damage your computer. You should move it to the Bin.",
- "\"TechminOS\"",
+ "“Techmino.app” cannot be opened because the developer cannot be verified.",
+ "“Techmino.app” will damage your computer. You should move it to the Bin.",
+ "“TechminOS”",
+ "(RUR’U’)R’FR2U’R’U’(RUR’F’)",
"\\jezevec/\\jezevec/\\jezevec/",
"\\osk/\\osk/\\osk/",
"↑↑↓↓←→←→BA",
@@ -870,10 +975,10 @@ return{
"1next 1hold!",
"1next 6hold!",
"20G actually is a brand new game rule!",
- "40-line Sprint WR: 14.915s by Reset_",
+ "40-line Sprint WR: 14.708s by hiryu",
"6next 1hold!",
"6next 6hold?!",
- "Achievement system coming soon!",
+ "A choke a day keeps record away",
"ALL SPIN!",
"Am G F G",
"B2B2B???",
@@ -883,32 +988,32 @@ return{
"Bridge clear coming soon!",
"Can you master this modern yet familiar stacker?",
"Certainly within this heart lies my M@STERPIECE.",
- "Change logs in English can be found on Discord.",
+ "Changelogs in English can be found on Discord.",
"Color clear coming soon!",
"Decreasing DAS and ARR makes your game faster but harder to control.",
"Did I just see a Back-to-Back-to-Back?",
"Does B2B2B2B exist?",
- "Don't let a small glitch ruin your entire day!",
- "Don't look directly at the bugs!",
+ "Don’t let a small glitch ruin your entire day!",
+ "Don’t look directly at the bugs!",
"Enjoy the Techmino rotation system!",
- "Excellent, but let's go better next time…",
- "Find out what's in the settings!",
+ "Excellent, but let’s go better next time…",
+ "Find out what’s in the settings!",
"Found any bugs? Open up an issue in our GitHub page!",
"Free-to-play block stacking game with a Battle Royale mode!",
"git commit",
"git push -f",
"Got any suggestions? Post them in our Discord!",
- "Have you noticed what \"rotating\" does do to a block?",
+ "Have you noticed what “rotating” does do to a block?",
"Headphones recommended for a better experience.",
"Hello world!",
"I3 and L3 are the only two unique triminoes.",
- "if a==true",
+ " if a==true",
"Increase your frame rate for a better experience.",
"Initial [insert action] system can save you.",
"Is B2B2B2B possible?",
"It is loading! Not just a cutscene!",
- "It's possible to finish 40L without left/right buttons.",
- "It's possible to finish 40L without rotation buttons.",
+ "It’s possible to finish 40L without left/right buttons.",
+ "It’s possible to finish 40L without rotation buttons.",
"Join our Discord!",
"l-=-1",
"Let the bass kick!",
@@ -917,6 +1022,7 @@ return{
"Lua No.1",
"Mix clear coming soon!",
"Most of the button icons are realized by using self-drawn glyphs in the Unicode Private Use Area.",
+ "Most of the music tracks in this game are made using Beepbox.",
"Music too distracting? You can turn it off.",
"No easter eggs in this menu if you have the simplistic style turned on!",
"O-Spin Triple!",
@@ -928,15 +1034,15 @@ return{
"pps-0.01",
"Server down randomly",
"Some requirements to achieve rank X are intentionally set to be difficult for even the best players.",
- "Soon you'll be able to play against friends and foes all over the world.",
+ "Soon, you’ll be able to play against friends and foes all over the world.",
"Split clear coming soon!",
"sudo rm -rf /*",
- "Techmino is a portmanteau of \"technique\" and \"tetromino\".",
+ "Techmino is a portmanteau of “technique” and “tetromino”.",
"Techmino is so fun!",
- "Techmino on Nspire-CX: yes it exists, no it's not the same game.",
+ "Techmino on Nspire-CX: yes it exists, no it’s not the same game.",
"TetroDictionary is now available in English.",
- "Most of the music tracks in this game are made using Beepbox.",
"The names that appeared in the background of the Staff page is a list of our sponsors.",
+ "The soundtracks of this game is now available on Soundcloud for free!",
"The stacker future is yours in Techmino!",
"There are several hidden modes in the game that cannot be entered using the map.",
"There is a total of 18 different pentominoes.",
@@ -949,7 +1055,7 @@ return{
"What about 23 PCs in 100 lines?",
"What about 26 TSDs?",
"What is this cheap UI & music smh",
- "while(false)",
+ " while (false)",
"You are a Grand Master!",
"You are welcome to help us to make BGMs and SFXs!",
"You can connect a keyboard to your phone or tablet (not functional on iOS though).",
@@ -966,7 +1072,7 @@ return{
{C.C,"Also try osu!"},
{C.C,"Also try Phigros!"},
{C.C,"Also try Puyo Puyo!"},
- {C.C,"Also try Rubik's cube!"},
+ {C.C,"Also try Rubik’s cube!"},
{C.C,"Also try Terraria!"},
{C.C,"Also try Touhou Project!"},
{C.C,"Also try VVVVVV!"},
@@ -978,12 +1084,13 @@ return{
{C.lY,"COOL!!"},
{C.N,"Lua",C.Z," No.1"},
{C.P,"T-spin!"},
- {C.R,"\"DMCA abusing\""},
- {C.R,"\"Intellectual property law\""},
+ {C.R,"“DMCA abusing”"},
+ {C.R,"“Intellectual property law”"},
{C.R,"DD",C.Z," Cannon=",C.P,"TS",C.R,"D",C.Z,"+",C.P,"TS",C.R,"D",C.Z," Cannon"},
{C.R,"DT",C.Z," Cannon=",C.P,"TS",C.R,"D",C.Z,"+",C.P,"TS",C.R,"T",C.Z," Cannon"},
{C.R,"LrL ",C.G,"RlR ",C.B,"LLr ",C.O,"RRl ",C.P,"RRR ",C.P,"LLL ",C.C,"FFF ",C.Y,"RfR ",C.Y,"RRf ",C.Y,"rFF"},
{C.Y,"O-Spin Triple!"},
{C.Z,"What? ",C.lC,"Xspin?"},
- }
+ },
+ pumpkin="I'm a pumpkin",
}
diff --git a/parts/language/lang_es.lua b/parts/language/lang_es.lua
index 9d7e120e7..ae5ce308e 100644
--- a/parts/language/lang_es.lua
+++ b/parts/language/lang_es.lua
@@ -1,5 +1,15 @@
-return{
+return {
fallback='en',
+ loadText={
+ loadSFX="Cargando efectos de sonido",
+ loadSample="Cargando samples de música",
+ loadVoice="Cargando voces",
+ loadFont="Cargando fuentes",
+ loadModeIcon="Cargando íconos",
+ loadMode="Cargando modos",
+ loadOther="Cargando otros assets",
+ finish="Pulsa cualquier tecla",
+ },
sureQuit="Pulsa de nuevo para salir",
sureReset="Pulsa de nuevo para reiniciar",
sureDelete="Pulsa de nuevo para borrar",
@@ -7,11 +17,13 @@ return{
playedLong="[Anti-adicción] Estuviste jugando un buen rato hoy. Recuerda descansar de vez en cuando.",
playedTooMuch="[Anti-adicción] ¡Has jugado mucho por hoy! No puedes jugar más.",
settingWarn="¡Ten cuidado con modificar esto!",
+ settingWarn2="Los ajustes se aplicarán luego de reiniciar",
atkModeName={"Al azar","Medallas","KOs","Atacantes"},
royale_remain="$1 Jugadores Restantes",
cmb={nil,"Combo de 1","Combo de 2","Combo de 3","Combo de 4","Combo de 5","Combo de 6","Combo de 7","Combo de 8","Combo de 9","¡Combo de 10!","¡Combo de 11!","¡Combo de 12!","¡Combo de 13!","¡Combo de 14!","¡Combo de 15!","¡Combo de 16!","¡Combo de 17!","¡Combo de 18!","¡Combo de 19!","MEGACOMBO"},
- spin="-spin",
+ spin="-spin ",
+ spinNC="-spin",
clear={"Single","Doble","Triple","Techrash","Pentacrash","Hexacrash","Heptacrash","Octacrash","Nonacrash","Decacrash","Undecacrash","Dodecacrash","Tridecacrash","Tetradecacrash","Pentadecacrash","Hexadecacrash","Heptadecacrash","Octadecacrash","Nonadecacrash","Ultracrash","Impossicrash"},
cleared="$1 líneas",
mini="Mini",b2b="B2B ",b3b="B2B2B ",
@@ -22,7 +34,7 @@ return{
stage="Fase $1 Completada",
great="¡Genial!",
awesome="¡Fantástico!",
- almost="¡Casi!",
+ almost="¡Ya casi!",
continue="¡Continúa!",
maxspeed="¡Máx. Velocidad!",
speedup="¡Más rápido!",
@@ -34,13 +46,13 @@ return{
grade="Grado",techrash="Techrash",
wave="Ronda",nextWave="Sig. ronda",
combo="Combo",maxcmb="Combo Máx.",
- pc="Perfect Clear",ko="KO",
+ pc="Perfect Clear",ko="KOs",
- win="Victoria",
+ win="¡Victoria!",
lose="Derrota",
- finish="Fin",
- gamewin="Victoria",
+ finish="Finalizado",
+ gamewin="Has ganado",
gameover="Fin del Juego",
pause="Pausa",
@@ -55,7 +67,7 @@ return{
ai_prebag="La IA no es compatible con piezas que no sean Tetrominos.",
ai_mission="La IA no es compatible con misiones personalizadas.",
switchSpawnSFX="Habilita los sonidos de aparición de las piezas ;)",
- needRestart="Reinicia Techmino para que los cambios tengan efecto.",
+ needRestart="Reinicia para aplicar los cambios.",
loadError_errorMode="'$1' Error al cargar: no hay modo '$2'",
loadError_read="'$1' Error al cargar: error de lectura",
@@ -92,40 +104,92 @@ return{
dictNote="==Copia de TetroDictionary==",
- getNoticeFail="Error al buscar novedades.",
+
+
+ -- Server's warn/error messages
+ Techrater={
+ internalError="Internal error",
+ databaseError="Database error",
+ invalidFormat="Formato inválido",
+ invalidArguments="Argumentos inválidos",
+ tooFrequent="Exceso de requests",
+ notAvailable="No disponible",
+ noPermission="No hay permisos suficientes",
+ roomNotFound="Sala no encontrada",
+
+ -- Controllers
+ WebSocket={
+ invalidConnection="Conexión inválida",
+ invalidAction="Acción inválida",
+ playerNotFound="Jugador no encontrado",
+ connectionFailed="Error de conexión",
+ },
+ -- Filters
+ CheckPermission={
+ playerNotFound="Jugador no encontrado",
+ },
+ -- Plugins
+ ConnectionManager={
+ playerInvalid="Jugador inválido",
+ playerNotFound="Jugador no encontrado",
+ connectionReplaced="Conexión reiniciada",
+ },
+ NoticeManager={
+ noticeNotFound="Aviso no encontrado",
+ },
+ PlayerManager={
+ invalidCode="Código incorrecto",
+ invalidEmail="Correo inválido",
+ playerNotFound="Jugador no encontrado",
+ invalidEmailPass="Correo o contraseña incorrecta",
+ emailExists="Correo ya existente",
+ emailSendError="Error al enviar solicitud",
+ },
+ -- Strategies
+ PlayerRole={
+ invalidRole="Rol inválido",
+ invalidTarget="Objetivo inválido",
+ },
+ PlayerType={
+ invalidType="Clase inválida",
+ roomFull="Esta sala está llena.",
+ },
+ RoomJoin={
+ wrongPassword="Contraseña incorrecta",
+ },
+ },
+
+ tooFrequent="Requests demasiado frecuentes",
+ roomPasswordChanged="Contraseña de sala cambiada",
oldVersion="¡Está disponible la nueva versión $1!",
versionNotMatch="¡Las versiones no coinciden!",
- needUpdate="¡Nueva versión requerida!",
notFinished="Próximamente",
- jsonError="Error en Json",
-
noUsername="Por favor ingresa un nombre de usuario",
- wrongEmail="Correo electrónico incorrecto",
- noPassword="Por favor ingresa una contraseña",
+ wrongEmail="Correo electrónico inválido",
+ wrongCode="Código de Verif. incorrecto",
+ noPassword="Por favor ingresa la contraseña",
diffPassword="Las contraseñas no coinciden",
- registerRequestSent="Petición de registro enviada con éxito",
- registerSuccessed="¡Registro exitoso!",
- loginSuccessed="¡Ingreso con éxito!",
- accessSuccessed="¡Autorizado exitoso!",
-
- wsConnecting="Websocket Conectando",
- wsFailed="WebSocket conexión fallida",
- wsClose="WebSocket cerrado:",
+ checkEmail="Petición de registro enviada con éxito",
+
+ wsFailed="WebSocket conexión fallida: $1",
+ wsClose="WebSocket cerrado: $1",
netTimeout="Tiempo de conexión agotado",
+ serverDown="Server caído, F",
+ requestFailed="Error de Request",
- onlinePlayerCount="En línea",
+ onlinePlayerCount="En línea: $1",
createRoomSuccessed="¡Sala creada con éxito!",
+ playerKicked="$2 quitado de la sala por $1",
+ becomeHost="$1 ahora es el host",
started="En juego",
- joinRoom="entró a la sala.",
- leaveRoom="salió de la sala.",
+ joinRoom="$1 entró a la sala.",
+ leaveRoom="$1 salió de la sala.",
+ roomRemoved="Sala removida",
ready="LISTO",
- connStream="CONECTANDO",
- waitStream="ESPERANDO",
- spectating="Espectando",
- chatRemain="Usuarios en línea:",
- chatStart="------Comienzo del historial------",
- chatHistory="------Nuevos mensajes------",
+ spectating="Especteando",
+
+
keySettingInstruction="Pulsa la tecla a mapear\nEsc.: Cancelar\nBackspace: Borrar",
customBGhelp="Suelta una imagen aquí para aplicarla de fondo",
@@ -134,8 +198,31 @@ return{
errorMsg="Ha ocurrido un error y Techmino necesita reiniciarse.\nSe creó un registro de error, puedes enviarlo al autor.",
tryAnotherBuild="[UTF-8 Inválido] Si estás usando Windows, intenta descargar Techmino-win32 o Techmino-win64 (el que no estés usando ahora).",
- -- modInstruction="",
- -- modInfo={},--See lang_en.lua
+ modInstruction="¡Elige tus mods!\nLos mods permiten modificar el juego,\npero también es posible que lo crasheen.\nLos scores no se guardan durante el uso de mods.",
+ modInfo={
+ next="NEXT\nSobreescribe el nro. de piezas siguientes a mostrar.",
+ hold="HOLD\nSobreescribe el nro. de piezas en reserva disponibles.",
+ hideNext="Hidden NEXT\nOculta el nro. de pzas. especificado en la cola de pzas. siguientes.",
+ infHold="InfiniHold\nPermite usar la reserva indefinidamente.",
+ hideBlock="Hide Current Piece:\nHace invisible la pieza en juego.",
+ hideGhost="No Ghost\nHace invisible la pieza fantasma.",
+ hidden="Hide Locked Pieces.\nLas piezas ya puestas se vuelven invisibles tras un tiempo a especificar.",
+ hideBoard="Hide Board\nEsconde el tablero parcial o totalmente.",
+ flipBoard="Flip Board\nGira o invierte el tablero.",
+ dropDelay="Gravity\nSobreescribe la velocidad de caída, en frames por bloque.",
+ lockDelay="Lock Delay\nSobreescribe el retraso de bloqueo (en frames).",
+ waitDelay="Spawn Delay\nSobreescribe el retraso de spawneo (en frames).",
+ fallDelay="Line Clear Delay\nSobreescribe el retraso de limpieza de líneas, en frames.",
+ life="Life\nCambia el nro inicial de vidas.",
+ forceB2B="B2B Only\nTermina el juego si la barra de B2B baja por debajo del valor inicial.",
+ forceFinesse="Finesse Only\nTermina el juego si se comete un error de finesse.",
+ tele="Teleport\nFuerza DAS 0 y ARR 0.",
+ noRotation="No Rotation\nDeshabilita la rotación de piezas.",
+ noMove="No Movement\nDeshabilita mover las piezas a los lados.",
+ customSeq="Randomizer\nSobreescribe el randomizador de la secuencia de piezas.",
+ pushSpeed="Garbage Speed\nSobreescribe la velocidad de subida de lineas basura (bloques/frame).",
+ boneBlock="[ ]\n Juega con bloques [ ], a la Electronika 60.",
+ },
pauseStat={
"Tiempo:",
"Tecla/Rot./Reserva:",
@@ -164,18 +251,120 @@ return{
"Err.Fns./RatioFns:",
},
aboutTexts={
- "Este es simplemente un juego de puzzle ordinario, no pienses de él como un juego promedio.",
- "Está inspirado en otros como C2/IO/JS/WWC/KOS.",
+ "Este es simplemente un juego de puzzle *ordinario*. En serio, eso es todo.",
+ "Inspirado en C2/IO/JS/WWC/KOS etc.",
"",
"Creado con LÖVE",
- "Puedes reportar errores o enviar sugerencias al grupo de testeo del autor o por email ~",
- "Descarga disponible únicamente vía el grupo de testeo y discord.gg/f9pUvkh",
- "Descargas desde otros sitios pueden contener malware/viruses, y en smartphones sólo requiere permisos de internet y vibración.",
+ "¡Se aprecia cualquier tipo de sugerencia o reporte de bugs!",
+ "Por favor descarga el juego únicamente desde los sitios oficiales,",
+ "ya que no podemos asegurar que sea seguro si proviene de otro lado.",
"El autor no se responabiliza por daños ocasionados debido a modificaciones del juego.",
- FNNS and"/"or"Por favor descarga las últimas versiones desde los sitios oficiales. El juego es gratuito",
- FNNS and"/"or"Ve el Zictionary (en inglés) para más info",
+ FNNS and "/" or "El juego es gratuito, pero se aprecian donaciones.",
+ FNNS and "/" or "Ve el Zictionary (en inglés) para más info.",
+ },
+ staff={
+ "ORIGINAL DE MrZ",
+ "E-mail: 1046101471@qq.com",
+ "",
+ "Programado, Desarrollado y Diseñado Por",
+ "MrZ",
+ "",
+ "Música hecha con",
+ "Beepbox",
+ "FL Studio",
+ "FL Mobile",
+ "Logic Pro X",
+ "",
+ "[CREADO CON LÖVE]",
+ "",
+ "Programación",
+ "MrZ",
+ "ParticleG",
+ "Gompyn",
+ "Trebor",
+ "(scdhh)",
+ "(FinnTenzor)",
+ "(NOT_A_ROBOT)",
+ "(user670)",
+ "",
+ "CI en GitHub, Packaging y Backend",
+ "ParticleG",
+ "Trebor",
+ "LawrenceLiu",
+ "Gompyn",
+ "flaribbit",
+ "scdhh",
+ "",
+ "Diseño Visual, Interfaz y UX",
+ "MrZ",
+ "Gnyar",
+ "C₂₉H₂₅N₃O₅",
+ "ScF",
+ "(旋律星萤)",
+ "(T0722)",
+ "",
+ "Ilustraciones",
+ "Miya",
+ "Mono",
+ "Xiaoya",
+ "葉枭",
+ "",
+ "Compositores",
+ "MrZ",
+ "柒栎流星",
+ "ERM",
+ "Trebor",
+ "C₂₉H₂₅N₃O₅",
+ "(T0722)",
+ "(Aether)",
+ "(Hailey)",
+ "",
+ "Efectos de sonido y Voces",
+ "Miya",
+ "Xiaoya",
+ "Mono",
+ "MrZ",
+ "Trebor",
+ "",
+ "Traducciones y Localizaciones",
+ "User670",
+ "MattMayuga",
+ "Mizu",
+ "Mr.Faq",
+ "ScF",
+ "C₂₉H₂₅N₃O₅",
+ "NOT_A_ROBOT",
+ "XMiao",
+ "sakurw, Airun, 幽灵3383",
+ "Shard Nguyễn, Squishy, TVN community",
+ "",
+ "Performances",
+ "Electric283",
+ "Hebomai",
+ "",
+ "Agradecimientos",
+ "Flyz",
+ "Big_True",
+ "NOT_A_ROBOT",
+ "思竣",
+ "yuhao7370",
+ "Farter",
+ "Teatube",
+ "蕴空之灵",
+ "T9972",
+ "No-Usernam8",
+ "andrew4043",
+ "smdbs-smdbs",
+ "paoho",
+ "Allustrate",
+ "Haoran SUN",
+ "Tianling Lyu",
+ "huaji2369",
+ "Lexitik",
+ "Tourahi Anime",
+ "[Todo el staff de testeo]",
+ "…Y a ti!",
},
-
used=[[
Herramientas utilizadas:
Beepbox
@@ -186,13 +375,13 @@ return{
Cold_Clear [MinusKelvin]
json.lua [rxi]
profile.lua [itraykov]
- simple-love-lights [dylhunn]
+ sha2 [Egor Skriptunoff]
]],
support="Apoyen al Autor",
WidgetText={
main={
- offline="1 Jugador",
- qplay="Jgo. Ráp.",
+ offline="Mapa de Modos",
+ qplay="Reciente: ",
online="Multijugador",
custom="Personalizado",
setting="Opciones",
@@ -226,6 +415,7 @@ return{
league="Liga Tech",
ffa="FFA",
rooms="Salas",
+ resetPW="Restabl. Contraseña",
logout="Desconec.",
},
net_league={
@@ -245,7 +435,7 @@ return{
password="Contraseña",
description="Descripción",
- life="Vida",
+ life="Vidas",
pushSpeed="Velocidad de Subida",
garbageSpeed="Velocidad de Basura",
visible="Visibilidad",
@@ -302,7 +492,6 @@ return{
sysCursor="Usar cursor del sistema",
autoPause="Pausar cuando la ventana no está enfocada",
autoSave="Autograbar Récords",
- autoLogin="Autologueo al Iniciar",
simpMode="Modo Sencillo",
},
setting_video={
@@ -330,7 +519,6 @@ return{
atkFX="FX Vis. de Ataque",
frame="Ratio de FPSs(%)",
- FTlock="Bloqueo por frames",
text="Texto de Acciones",
score="Puntaje en Pantalla",
@@ -344,6 +532,8 @@ return{
power="Inf. de Batería",
clean="Fast Draw",
fullscreen="Pant. Completa",
+ portrait="Vertical",
+ msaa="Nivel de MSAA",
bg_on="Fondo Normal",
bg_off="Sin Fondo",
@@ -547,22 +737,19 @@ return{
label="Etiq.",
},
login={
- title="Entrar",
- register="Registrarse",
- email="Correo Elec.",
- password="Contraseña",
- keepPW="Recordar credenciales",
- login="Entrar",
- },
- register={
title="Registrarse",
- login="Entrar",
- username="Nombre de Usuario",
- email="Correo Elec.",
+ ticket="Ticket de Verif.",
+ authorize="Abrir página de Verificación",
+ paste="Paste Ticket",
+ submit="Enviar",
+ },
+ reset_password={
+ title="Restablecer Contraseña",
+ send="Enviar código",
+ code="Código de Verif.",
password="Contraseña",
password2="Repetir Contr.",
- register="Registrarse",
- registering="Esperando respuesta...",
+ setPW="Establecer",
},
account={
title="Cuenta",
@@ -626,10 +813,17 @@ return{
['sprint_1000l']= {"Sprint", "1000L", "¡Limpia 1000 líneas!"},
['sprintPenta']= {"Sprint", "Pentominos", "¡Limpia 40 líneas con los 18 pentominos distintos!"},
['sprintMPH']= {"Sprint", "MPH", "Memoryless (sin memoria)\nPreviewless (sin pzas. siguientes)\nHoldless (sin reserva)."},
- ['dig_10l']= {"Queso", "10L", "Limpia 10 líneas de queso."},
- ['dig_40l']= {"Queso", "40L", "Limpia 40 líneas de queso."},
- ['dig_100l']= {"Queso", "100L", "Limpia 100 líneas de queso."},
- ['dig_400l']= {"Queso", "400L", "Limpia 400 líneas de queso."},
+ ['sprint123']= {"Sprint", "M123", "Limpia 40 líneas con monominos, biminos y triminos"},
+ ['secret_grade']= {"Secret Grade", "", "¡Arma dejando huecos en escalera, sigue la guía!"},
+ ['dig_10l']= {"Dig", "10L", "¡Limpia 10 líneas de queso lo más rápido que puedas!"},
+ ['dig_40l']= {"Dig", "40L", "¡Limpia 40 líneas de queso lo más rápido que puedas!"},
+ ['dig_100l']= {"Dig", "100L", "¡Limpia 100 líneas de queso lo más rápido que puedas!"},
+ ['dig_400l']= {"Dig", "400L", "¡Limpia 400 líneas de queso lo más rápido que puedas!"},
+ ['dig_eff_10l']= {"Dig", "Efic. 10L", "¡Limpia 10 líneas de queso con la menor cantidad de piezas posible!"},
+ ['dig_eff_40l']= {"Dig", "Efic. 40L", "¡Limpia 40 líneas de queso con la menor cantidad de piezas posible!"},
+ ['dig_eff_100l']= {"Dig", "Efic. 100L", "¡Limpia 100 líneas de queso con la menor cantidad de piezas posible!"},
+ ['dig_eff_400l']= {"Dig", "Efic. 400L", "¡Limpia 400 líneas de queso con la menor cantidad de piezas posible!"},
+ ['dig_quad_10l']= {"Dig", "TECHRASH 10L", "¡Limpia 10 líneas de queso sólo con Tecrashes!"},
['drought_n']= {"Sequía", "100L", "¡Sin piezas I!"},
['drought_l']= {"Sequía+", "100L", "Qué es esto..."},
['marathon_n']= {"Maratón", "Normal", "Maratón de 200 líneas con velocidad en aumento."},
@@ -650,26 +844,32 @@ return{
['round_h']= {"Por Turnos", "Difícil", "Modo ajedrez."},
['round_l']= {"Por Turnos", "Lunático", "Modo ajedrez."},
['round_u']= {"Por Turnos", "Supremo", "Modo ajedrez."},
- ['master_n']= {"Master", "Normal", "Para principiantes en 20G"},
- ['master_h']= {"Master", "Difícil", "¡Desafío profesional de 20G!"},
- ['master_m']= {"Master", "M21", "Para Maestros del 20G."},
- ['master_final']= {"Master", "FINAL", "El verdadero 20G Supremo:\nel final es inalcanzable."},
- ['master_ex']= {"GrandMaster", "EXTRA", "Para ser un gran maestro,\nacepta este desafío"},
- ['strategy_e']= {"Strategy", "EASY", "Decisiones rápidas en 20G."},
- ['strategy_h']= {"Strategy", "HARD", "Decisiones rápidas en 20G."},
- ['strategy_u']= {"Strategy", "ULTIMATE", "Decisiones rápidas en 20G."},
- ['strategy_e_plus']={"Strategi", "MUDAH+", "Decisiones rápidas en 20G."},
- ['strategy_h_plus']={"Strategi", "SULIT+", "Decisiones rápidas en 20G."},
- ['strategy_u_plus']={"Strategi", "TERAKHIR+", "Decisiones rápidas en 20G."},
+ ['big_n']= {"Big", "Normal", "¡La matriz es más pequeña!"},
+ ['big_h']= {"Big", "Difícil", "¡La matriz es más pequeña!"},
+ ['master_n']= {"Master", "Normal", "Para principiantes en 20G."},
+ ['master_h']= {"Master", "Difícil", "Para entusiastas en 20G."},
+ ['master_m']= {"Master", "M21", "Para maestros del 20G."},
+ ['master_final']= {"Master", "Final", "Al 20Ginito y más allá!"},
+ ['master_ph']= {"Master", "Phantasm", "???"},
+ ['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_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']= {"A Ciegas", "Parcial", "Para novatos."},
['blind_n']= {"A Ciegas", "Total", "Para jugadores intermedios."},
- ['blind_h']= {"A Ciegas", "Inmediato", "Para jugadores experimentados"},
+ ['blind_h']= {"A Ciegas", "Inmediato", "Para jugadores experimentados."},
['blind_l']= {"A Ciegas", "Inmediato+", "Para profesionales."},
['blind_u']= {"A Ciegas", "?", "¿Estás preparado?"},
['blind_wtf']= {"A Ciegas", "ELFUF", "No, no lo estás."},
- ['classic_e']= {"Classic", "EASY", "Modo clásico con alta velocidad."},
- ['classic_h']= {"Clásico", "Difícil", "Modo clásico con alta velocidad."},
- ['classic_u']= {"Clásico", "Supremo", "Modo clásico con alta velocidad."},
+ ['classic_e']= {"Clásico", "Fácil", "Modo clásico con velocidad baja."},
+ ['classic_h']= {"Clásico", "Difícil", "Modo clásico con velocidad media."},
+ ['classic_l']= {"Clásico", "Lunático", "Modo clásico con velocidad alta."},
+ ['classic_u']= {"Clásico", "Supremo", "Modo clásico con velocidad infernal :D"},
['survivor_e']= {"Supervivencia", "Fácil", "¿Cuánto tiempo podrás sobrevivir?"},
['survivor_n']= {"Supervivencia", "Normal", "¿Cuánto tiempo podrás sobrevivir?"},
['survivor_h']= {"Supervivencia", "Difícil", "¿Cuánto tiempo podrás sobrevivir?"},
@@ -681,11 +881,10 @@ return{
['defender_l']= {"Defensor", "Lunático", "¡Practica la defensa!"},
['dig_h']= {"Downstack", "Difícil", "¡Practica el downstackeo!"},
['dig_u']= {"Downstack", "Supremo", "¡Practica el downstackeo!"},
- ['clearRush']= {"Clear Rush", "NORMAL", "¡Tutorial de Allspins!\n[En construcción]"},
['c4wtrain_n']= {"Entrenar C4W", "Normal", "Combos infinitos."},
['c4wtrain_l']= {"Entrenar C4W", "Lunático", "Combos infinitos."},
['pctrain_n']= {"Entrenar PC", "Normal", "Modo sencillo para practicar Perfect Clears."},
- ['pctrain_l']= {"Entrenar PC", "Lunático", "Modo duro para practicar Perfect Clears."},
+ ['pctrain_l']= {"Entrenar PC", "Lunático", "Modo complejo para practicar Perfect Clears."},
['pc_n']= {"Desafío de PCs", "Normal", "¡Consigue los PCs que puedas en 100 líneas!"},
['pc_h']= {"Desafío de PCs", "Difícil", "¡Consigue los PCs que puedas en 100 líneas!"},
['pc_l']= {"Desafío de PCs", "Lunático", "¡Consigue los PCs que puedas en 100 líneas!"},
@@ -701,19 +900,20 @@ return{
['tsd_e']= {"Desafío de TSD", "Fácil", "¡Sólo se permiten T-Spin Dobles!"},
['tsd_h']= {"Desafío de TSD", "Difícil", "¡Sólo se permiten T-Spin Dobles!"},
['tsd_u']= {"Desafío de TSD", "Supremo", "¡Sólo se permiten T-Spin Dobles!"},
- ['backfire_n']= {"Retorno", "Normal", "Lidia con tus propias líneas basura."},
- ['backfire_h']= {"Retorno", "Difícil", "Lidia con tus propias líneas basura."},
- ['backfire_l']= {"Retorno", "Lunático", "Lidia con tus propias líneas basura."},
- ['backfire_u']= {"Retorno", "Supremo", "Lidia con tus propias líneas basura."},
- ['sprintAtk']= {"Sprint", "100L - Ataque", "¡Envía 100 líneas de ataque!"},
- ['sprintEff']= {"Sprint", "Efficiency", "¡Envía ataque eficiente en 40 líneas!"},
+ ['backfire_n']= {"Retorno", "Normal", "Cancela tus propias líneas basura."},
+ ['backfire_h']= {"Retorno", "Difícil", "Cancela tus propias líneas basura."},
+ ['backfire_l']= {"Retorno", "Lunático", "Cancela tus propias líneas basura."},
+ ['backfire_u']= {"Retorno", "Supremo", "Cancela tus propias líneas basura."},
+ ['sprintAtk']= {"Sprint", "100L - Ataque", "¡Envía 100 líneas de ataque!"},
+ ['sprintEff']= {"Sprint", "Eficiencia", "¡Envía ataque eficiente en 40 líneas!"},
['zen']= {'Zen', "200L", "200 líneas sin límite de tiempo."},
- ['ultra']= {'Ultra', "Extra", "¡Consigue el mayor puntaje posible en 2 minutos!"},
+ ['ultra']= {'Ultra', "Extra", "¡Consigue el mayor puntaje /nposible en 2 minutos!"},
['infinite']= {"Infinito", "", "Modo Sandbox."},
['infinite_dig']= {"Infinito: Queso", "", "Limpia, limpia, más limpia que tú."},
- ['marathon_inf']= {"Maratón", "Infinito", "Infinito maratón."},
+ ['marathon_inf']= {"Maratón", "Infinito", "Maratón infinita."},
['custom_clear']= {"Personalizado", "Normal"},
['custom_puzzle']= {"Personalizado", "Puzzle"},
},
+ pumpkin="Todos alaben al rey Calabaza",
}
diff --git a/parts/language/lang_fr.lua b/parts/language/lang_fr.lua
index 530554e2f..5e417ea10 100644
--- a/parts/language/lang_fr.lua
+++ b/parts/language/lang_fr.lua
@@ -1,4 +1,4 @@
-return{
+return {
fallback='en',
sureQuit="Appuyez à nouveau pour sortir",
-- sureReset="Press again to reset",
@@ -7,11 +7,13 @@ return{
playedLong="[Anti-addiction] Vous avez joué pendant un bon bout de temps aujourd'hui. Faites des pauses.",
playedTooMuch="[Anti-addiction] Vous avez joué trop longtemps ! Vous ne pouvez plus jouer.",
-- settingWarn="Modifing uncommon setting, be careful!",
+ -- settingWarn2="This setting takes effect after restart",
atkModeName={"Aléatoire","Badges","K.O.s faciles","Attaquants"},
royale_remain="$1 Joueurs restants",
cmb={nil,"1 Combo","2 Combo","3 Combo","4 Combo","5 Combo","6 Combo","7 Combo","8 Combo","9 Combo","10 Combo!","11 Combo!","12 Combo!","13 Combo!","14 Combo!!","15 Combo!!","16 Combo!!","17 Combo!!!","18 Combo!!!","19 Combo!!!","MEGACMB"},
- spin="-spin",
+ spin="-spin ",
+ spinNC="-spin",
clear={"Simple","Double","Triple","Techrash","Pentacrash","Hexacrash","Heptacrash","Octacrash","Nonacrash","Decacrash","Undecacrash","Dodecacrash","Tridecacrash","Tetradecacrash","Pentadecacrash","Hexadecacrash","Heptadecacrash","Octadecacrash","Nonadecacrash","Ultracrash","Impossicrash"},
-- cleared="$1 lines",
mini="Mini",b2b="B2B ",b3b="B2B2B ",
@@ -53,7 +55,7 @@ return{
-- cc_fixed="CC is incompatible with fixed sequences",
-- cc_swap="CC is incompatible with swap holdmode",
- --ai_prebag="The AI is incompatible with custom sequences which have nontetromino.",'IA est incompatible avec les séquences personnalisées.",
+ -- ai_prebag="The AI is incompatible with custom sequences which have nontetromino.",'IA est incompatible avec les séquences personnalisées.",
ai_mission="L'IA est incompatible avec les missions personnalisées.",
switchSpawnSFX="Activez les effets sonores d'apparition des pièces pour jouer",
needRestart="Fonctionnera dès la prochaine partie",
@@ -93,40 +95,93 @@ return{
-- dictNote="==Copied from TetroDictionary==",
- getNoticeFail="Echec de l'obtention de la notice",
+
+
+ -- Server's warn/error messages
+ Techrater={
+ -- internalError="Internal error",
+ -- databaseError="Database error",
+ -- invalidFormat="Invalid format",
+ -- invalidArguments="Invalid arguments",
+ -- tooFrequent="Too frequent",
+ -- notAvailable="Not available",
+ -- noPermission="No permission",
+ -- roomNotFound="Room not found",
+
+ -- Controllers
+ WebSocket={
+ -- invalidConnection="Invalid connection",
+ -- invalidAction="Invalid action",
+ -- playerNotFound="Player not found",
+ -- connectionFailed="Connection failed",
+ },
+ -- Filters
+ CheckPermission={
+ -- playerNotFound="Player not found",
+ },
+ -- Plugins
+ ConnectionManager={
+ -- playerInvalid="Player invalid",
+ -- playerNotFound="Player not found",
+ -- connectionReplaced="Connection replaced",
+ },
+ NoticeManager={
+ -- noticeNotFound="Notice not found",
+ },
+ PlayerManager={
+ -- invalidCode="Invalid code",
+ -- invalidEmail="Invalid email",
+ -- playerNotFound="Player not found",
+ -- invalidEmailPass="Invalid email or password",
+ -- emailExists="Email exists",
+ -- emailSendError="Email send error",
+ },
+ -- Strategies
+ PlayerRole={
+ -- invalidRole="Invalid role",
+ -- invalidTarget="Invalid target",
+ },
+ PlayerType={
+ -- invalidType="Invalid type",
+ -- roomFull="Room full",
+ },
+ RoomJoin={
+ -- wrongPassword="Wrong password",
+ },
+ },
+
+ -- tooFrequent="Request too frequently",
+ -- roomPasswordChanged="Room password changed",
oldVersion="La version $1 est disponible !",
-- versionNotMatch="Version do not match!",
-- needUpdate="Newer version required!",
-- notFinished="Coming soon!",
- jsonError="Erreur json",
-
noUsername="Entrez votre nom d'utilisateur",
wrongEmail="Mauvaise adresse email",
+ -- wrongCode="Invalid verification code",
noPassword="Entrez votre mot de passe",
diffPassword="Les mots de passe ne se correspondent pas",
- -- registerRequestSent="Registration request sent",
- registerSuccessed="Enregistré avec succès !",
- loginSuccessed="Connecté avec succès !",
- accessSuccessed="Autorisé avec succès !",
-
- -- wsConnecting="Websocket Connecting",
- wsFailed="WebSocket connection échouée",
- -- wsClose="WebSocket Closed:",
+ -- checkEmail="Registration request sent",
+
+ wsFailed="WebSocket connection échouée: $1",
+ -- wsClose="WebSocket Closed: $1",
-- netTimeout="Network connection timeout",
+ -- serverDown="Oops! Server is down",
+ -- requestFailed="Request failed",
- -- onlinePlayerCount="Online",
+ -- onlinePlayerCount="Online: $1",
createRoomSuccessed="Salon créé avec succès !",
+ -- playerKicked="$1 removed $2 from room",
+ -- becomeHost="$1 become host",
-- started="Playing",
- joinRoom="a rejoint le salon.",
- leaveRoom="a quitté le salon.",
+ joinRoom="$1 a rejoint le salon.",
+ leaveRoom="$1 a quitté le salon.",
+ -- roomRemoved="Room was removed",
-- ready="READY",
- -- connStream="CONNECTING",
- -- waitStream="WAITING",
-- spectating="Spectating",
- chatRemain="En ligne : ",
- chatStart="--------Début des logs--------",
- chatHistory="-Nouveaux messages en dessous-",
+
+
-- keySettingInstruction="Press to bind key\nescape: cancel\nbackspace: delete",
-- customBGhelp="Drop image file here to apply custom background",
@@ -169,11 +224,11 @@ return{
"On y joue comme sur C2/IO/JS/WWC/KOS et autres.",
"",
"Vous pouvez envoyer des rapports de bogues ou des suggastions via le groupe de test ou l'email du créateur ~",
- "Ce jeu est gratuit et est uniquement disponible via discord.gg/f9pUvkh",
+ "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,",
"et vous n'avez besoin que des permissions de vibration et de communication réseau pour les versions mobiles !",
- FNNS and"/"or"Le créateur n'est pas responsable pour n'importe quel type de perte de données suite à une modification du jeu.",
- -- FNNS and"/"or"Check Zictionary for more",
+ FNNS and "/" or "Le créateur n'est pas responsable pour n'importe quel type de perte de données suite à une modification du jeu.",
+ -- FNNS and "/" or "Check Zictionary for more",
},
staff={
"À L'ORIGINE PAR MrZ",
@@ -216,6 +271,12 @@ return{
"(旋律星萤)",
"(T0722)",
"",
+ "Illustrations",
+ "Miya",
+ "Mono",
+ "Xiaoya",
+ "葉枭",
+ "",
"Conceptions Musicales",
"MrZ",
"柒栎流星",
@@ -241,7 +302,9 @@ return{
"ScF",
"C₂₉H₂₅N₃O₅",
"NOT_A_ROBOT",
- "sakurw",
+ "XMiao",
+ "sakurw, Airun, 幽灵3383",
+ "Shard Nguyễn, Squishy, TVN community",
"",
"Performance",
"Electric283",
@@ -280,13 +343,13 @@ return{
Cold_Clear [MinusKelvin]
json.lua [rxi]
profile.lua [itraykov]
- simple-love-lights [dylhunn]
+ sha2 [Egor Skriptunoff]
]],
support="Aider le créateur",
WidgetText={
main={
-- offline="Solo",
- -- qplay="Last Play",
+ -- qplay="Last Play: ",
-- online="Multi",
-- custom="Mode perso.",
setting="Paramètres",
@@ -316,6 +379,7 @@ return{
-- league="Tech League",
ffa="FFA",
rooms="Salons",
+ -- resetPW="Reset password",
-- logout="Log out",
},
net_league={
@@ -392,7 +456,6 @@ return{
-- sysCursor="Use system cursor",
autoPause="Mettre en pause en cas de perte de focus",
-- autoSave="Auto save new-best",
- -- autoLogin="Auto Login on Start",
-- simpMode="Simple mode",
},
setting_video={
@@ -421,7 +484,6 @@ return{
atkFX="Effets d'attaque",
frame="Montrer les FPS(%)",
- -- FTlock="Frame-Time Lock",
text="Texte d'action",
score="Pop-up de score",
@@ -435,6 +497,8 @@ return{
power="Infos d'alimentation",
-- clean="Fast Draw",
fullscreen="Plein écran",
+ -- portrait="Portrait",
+ -- msaa="MSAA level",
-- bg_on="Normal B.G.",
-- bg_off="No B.G.",
@@ -636,22 +700,19 @@ return{
-- label="label",
},
login={
- title="Connexion",
- register="Enregistrement",
- email="E-mail",
- password="Mot de passe",
- -- keepPW="Remember me",
- login="Connexion",
- },
- register={
- title="Enregistrement",
- login="Connexion",
- username="Nom d'utilisateur",
- email="E-mail",
+ -- title="Sign In",
+ -- ticket="Auth Ticket",
+ -- authorize="Go Authorizing",
+ -- paste="Paste Ticket",
+ -- submit="Submit",
+ },
+ reset_password={
+ -- title="Reset Password",
+ -- send="Send code",
+ -- code="Verification Code",
password="Mot de passe",
password2="Confirmer le mot de passe",
- register="Enregistrement",
- -- registering="Waiting for response...",
+ -- setPW="Set Password",
},
account={
title="Compte",
@@ -724,6 +785,7 @@ return{
['dig_40l']= {"Dig", "40L", "Creusez 40 lines"},
['dig_100l']= {"Dig", "100L", "Creusez 100 lines"},
['dig_400l']= {"Dig", "400L", "Creusez 400 lines"},
+ --['dig_quad_10l']= {"Dig", "TECHRASH 10L", "Dig 10 garbage lines using only techrash!"},
['drought_n']= {"Drought", "100L", "Pas de pièce I !"},
['drought_l']= {"Drought+", "100L", "WTF ??!!"},
-- ['stack_e']= {"Stack", "FACILE", "Pack them!"},
@@ -740,7 +802,7 @@ return{
['techmino49_u']= {"Tech 49", "ULTIME", "Bataille de 49 joueurs.\nLe dernier en vie gagne."},
['techmino99_e']= {"Tech 99", "FACILE", "Bataille de 99 joueurs.\nLe dernier en vie gagne."},
['techmino99_h']= {"Tech 99", "DIFFICILE", "Bataille de 99 joueurs.\nLe dernier en vie gagne."},
- ['techmino99_u']= {"Tech 99", "ULTIMe", "Bataille de 99 joueurs.\nLe dernier en vie gagne."},
+ ['techmino99_u']= {"Tech 99", "ULTIME", "Bataille de 99 joueurs.\nLe dernier en vie gagne."},
['round_e']= {"Tour à tour", "FACILE", "Mode échecs"},
['round_n']= {"Tour à tour", "NORMAL", "Mode échecs"},
['round_h']= {"Tour à tour", "DIFFICILE", "Mode échecs"},
@@ -750,14 +812,14 @@ return{
['master_h']= {"Master", "DIFFICILE", "Challenge 20G pro !"},
-- ['master_m']= {"Master", "M21", "For 20G Masters."},
['master_final']= {"Master", "FINAL", "20G : Un point final impossible à atteindre !"},
- -- ['master_ph']= {"Mester", "FANTASMA", "20G: ???"},
+ -- ['master_ph']= {"Master", "FANTASMA", "20G: ???"},
['master_ex']= {"GrandMaster", "EXTRA", "Tentez de devenir un Grandmaster."},
- ['strategy_e']= {"Strategy", "EASY", "Fast 20G decision"},
- ['strategy_h']= {"Strategy", "HARD", "Fast 20G decision"},
- ['strategy_u']= {"Strategy", "ULTIMATE", "Fast 20G decision"},
- -- ['strategy_e_plus']={"Strategi", "MUDAH+", "Keputusan 20G cepat"},
- -- ['strategy_h_plus']={"Strategi", "SULIT+", "Keputusan 20G cepat"},
- -- ['strategy_u_plus']={"Strategi", "TERAKHIR+", "Keputusan 20G cepat"},
+ ['strategy_e']= {"Stratégie", "FACILE", "Décision rapide 20G"},
+ ['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']= {"Aveugle", "MOITIE", "Pour les novices."},
['blind_n']= {"Aveugle", "TOUT", "Pour les joueurs intermédiaires."},
['blind_h']= {"Aveugle", "SOUDAIN", "Pour les bons jooeurs."},
@@ -766,6 +828,7 @@ return{
['blind_wtf']= {"Aveugle", "WTF", "Vous n'êtes pas prêt."},
['classic_e']= {"Classic", "EASY", "Un mode classique rapide."},
['classic_h']= {"Classic", "DIFFICILE", "Un mode classique rapide."},
+ ['classic_l']= {"Classic", "LUNATIQUE", "Un mode classique rapide."},
['classic_u']= {"Classic", "ULTIME", "Un mode classique rapide."},
['survivor_e']= {"Survivor", "FACILE", "Pendant combien de temps survivrez-vous ?"},
['survivor_n']= {"Survivor", "NORMAL", "Pendant combien de temps survivrez-vous ?"},
@@ -778,7 +841,6 @@ return{
['defender_l']= {"Défendant", "LUNATIQUE", "Soyez défensifs !"},
['dig_h']= {"Perceuse", "DIFFICILE", "Essayez de creuser !"},
['dig_u']= {"Perceuse", "ULTIME", "Essayez de creuser !"},
- -- ['clearRush']= {"Clear Rush", "NORMAL", "All-spin tutorial!\n[Under construction]"},
['c4wtrain_n']= {"Mode essai C4W", "NORMAL", "Combos infinis."},
['c4wtrain_l']= {"Mode essai C4W", "LUNATIQUE", "Combos infinis."},
['pctrain_n']= {"Mode essai PC", "NORMAL", "Mode Perfect Clear simple"},
@@ -798,10 +860,10 @@ return{
['tsd_e']= {"TSD Challenge", "FACILE", "T-spin doubles uniquement !"},
['tsd_h']= {"TSD Challenge", "DIFFICILE", "T-spin doubles uniquement !"},
['tsd_u']= {"TSD Challenge", "ULTIME", "T-spin doubles uniquement !"},
- -- ['backfire_n']= {"Backfire", "NORMAL", "Self-send garbages"},
- -- ['backfire_h']= {"Backfire", "HARD", "Self-send garbages"},
- -- ['backfire_l']= {"Backfire", "LUNATIC", "Self-send garbages"},
- -- ['backfire_u']= {"Backfire", "ULTIMATE", "Self-send garbages"},
+ -- ['backfire_n']= {"Backfire", "NORMAL", "Hold back the backfiring garbage lines"},
+ -- ['backfire_h']= {"Backfire", "HARD", "Hold back the backfiring garbage lines"},
+ -- ['backfire_l']= {"Backfire", "LUNATIC", "Hold back the backfiring garbage lines"},
+ -- ['backfire_u']= {"Backfire", "ULTIMATE", "Hold back the backfiring garbage lines"},
-- ['sprintAtk']= {"Sprint", "100 Attack", "Send 100 lines!"},
-- ['sprintEff']= {"Sprint", "Efficiency", "Send more attack in 40lines!"},
['zen']= {'Zen', "200", "200 lignes sans limites de temps."},
@@ -813,4 +875,5 @@ return{
['custom_clear']= {"Perso.", "NORMAL"},
['custom_puzzle']= {"Perso.", "PUZZLE"},
},
+ -- pumpkin="I'm a pumpkin",
}
diff --git a/parts/language/lang_id.lua b/parts/language/lang_id.lua
index c3334dcb2..5309a7931 100644
--- a/parts/language/lang_id.lua
+++ b/parts/language/lang_id.lua
@@ -1,5 +1,5 @@
local C=COLOR
-return{
+return {
fallback='en',
loadText={
loadSFX="Memuat efek suara",
@@ -18,20 +18,22 @@ return{
playedLong="Anda telah bermain lama. Waktunya istirahat!",
playedTooMuch="Anda telah bermain terlalu lama! Techmino sangat menyenangkan, tetapi jangan lupa istirahat!",
settingWarn="Awas, Anda akan mengubah beberapa pengaturan yang tidak biasanya diubah!",
+ -- settingWarn2="This setting takes effect after restart",
atkModeName={"Acak","Badge","K.O.","Penyerang"},
royale_remain="$1 Pemain Tersisa",
powerUp={[0]="+000%","+025%","+050%","+075%","+100%"},
cmb={nil,"1 Kombo","2 Kombo","3 Kombo","4 Kombo","5 Kombo","6 Kombo","7 Kombo","8 Kombo","9 Kombo","10 Kombo!","11 Kombo!","12 Kombo!","13 Kombo!","14 Kombo!!","15 Kombo!!","16 Kombo!!","17 Kombo!!!","18 Kombo!!!","19 Kombo!!!","MEGA KOMBO"},
- spin=" spin",
- clear={"Single","Double","Triple","Techrash","Pentacrash","Hexacrash","Heptacrash","Octacrash","Nonacrash","Decacrash","Undecacrash","Dodecacrash","Tridecacrash","Tetradecacrash","Pentadecacrash","Hexadecacrash","Heptadecacrash","Octadecacrash","Nonadecacrash","Ultracrash","Impossicrash"},
+ spin=" spin ",
+ spinNC=" spin",
+ clear={"Single","Double","Triple","Techrash","Pentacrash","Hexacrash","Heptacrash","Oktacrash","Nonacrash","Decacrash","Undecacrash","Dodecacrash","Tridecacrash","Tetradecacrash","Pentadecacrash","Hexadecacrash","Heptadecacrash","Octadecacrash","Nonadecacrash","Ultracrash","Impossicrash"},
cleared="$1 baris",
mini="Mini",b2b="B2B ",b3b="B2B2B ",
- PC="PC",HPC="Hampir PC",
+ PC="PC",HPC="Setengah PC",
replaying="[Diulang]",
tasUsing="[TAS]",
- stage="Tahap $1 selesai!",
+ stage="Bagian $1 selesai!",
great="Bagus!",
awesome="Luar biasa!",
almost="Hampir!",
@@ -40,7 +42,7 @@ return{
speedup="Percepatkan!",
missionFailed="Salah",
- speedLV="Kecepatan lvl",
+ speedLV="Kecptn lvl",
piece="Blok",line="Baris",atk="Baris Terkirim",eff="Efisiensi",
rpm="RPM",tsd="TSD",
grade="Nilai",techrash="Techrash",
@@ -56,11 +58,11 @@ return{
gameover="Tamat",
pause="Terjeda",
- pauseCount="Jeda-jeda",
+ pauseCount="Jeda",
finesse_ap="Semua sempurna",
finesse_fc="Kombo penuh",
- page="Halaman:",
+ page="Halaman: ",
cc_fixed="CC tidak cocok dengan urutan tetap.",
cc_swap="CC tidak cocok dengan mode simpan tukar.",
@@ -75,7 +77,7 @@ return{
loadError_other="'$1' eror memuat: $2",
loadError_unknown="'$1' eror memuat: alasan tidak diketahui",
- saveError_duplicate="'$1' eror menyimpan: nama file tergAnda",
+ saveError_duplicate="'$1' eror menyimpan: nama file terganda",
saveError_encode="'$1' eror menyimpan: gagal menyandi",
saveError_other="'$1' eror menyimpan: $2",
saveError_unknown="'$1' eror menyimpan: alasan tidak diketahui",
@@ -85,10 +87,10 @@ return{
exportSuccess="Ekspor berhasil",
importSuccess="Impor berhasil",
dataCorrupted="Data rusak",
- pasteWrongPlace="Menempel di tempat yang salah?",
+ pasteWrongPlace="Apakah Anda menempelkannya di tempat yang salah?",
noFile="File tidak ada",
- nowPlaying="Sekarang mendengarkan:",
+ nowPlaying="Musik:",
VKTchW="Berat sentuhan",
VKOrgW="Berat asal",
@@ -104,63 +106,114 @@ return{
dictNote="==Tersalin dari TetroDictionary==",
- getNoticeFail="Gagal mengambil pengumuman-pengumuman",
+
+
+ -- Server's warn/error messages
+ Techrater={
+ -- internalError="Internal error",
+ -- databaseError="Database error",
+ -- invalidFormat="Invalid format",
+ -- invalidArguments="Invalid arguments",
+ -- tooFrequent="Too frequent",
+ -- notAvailable="Not available",
+ -- noPermission="No permission",
+ -- roomNotFound="Room not found",
+
+ -- Controllers
+ WebSocket={
+ -- invalidConnection="Invalid connection",
+ -- invalidAction="Invalid action",
+ -- playerNotFound="Player not found",
+ -- connectionFailed="Connection failed",
+ },
+ -- Filters
+ CheckPermission={
+ -- playerNotFound="Player not found",
+ },
+ -- Plugins
+ ConnectionManager={
+ -- playerInvalid="Player invalid",
+ -- playerNotFound="Player not found",
+ -- connectionReplaced="Connection replaced",
+ },
+ NoticeManager={
+ -- noticeNotFound="Notice not found",
+ },
+ PlayerManager={
+ -- invalidCode="Invalid code",
+ -- invalidEmail="Invalid email",
+ -- playerNotFound="Player not found",
+ -- invalidEmailPass="Invalid email or password",
+ -- emailExists="Email exists",
+ -- emailSendError="Email send error",
+ },
+ -- Strategies
+ PlayerRole={
+ -- invalidRole="Invalid role",
+ -- invalidTarget="Invalid target",
+ },
+ PlayerType={
+ -- invalidType="Invalid type",
+ -- roomFull="Room full",
+ },
+ RoomJoin={
+ -- wrongPassword="Wrong password",
+ },
+ },
+
+ -- tooFrequent="Request too frequently",
+ -- roomPasswordChanged="Room password changed",
oldVersion="Versi $1 sekarang tersedia",
- needUpdate="Butuh versi lebih baru!",
versionNotMatch="Versi tidak sama!",
notFinished="Segera akan datang!",
- jsonError="Eror JSON",
-
- noUsername="Silahkan masukki username Anda",
+ noUsername="Silahkan memasukan username Anda",
wrongEmail="Alamat email tidak sah",
- noPassword="Silahkan masukki kata sandi Anda",
+ -- wrongCode="Invalid verification code",
+ noPassword="Silahkan memasukan kata sandi Anda",
diffPassword="Kata sandi tidak sama",
- registerRequestSent="Permintaan daftar telah terkirim.",
- registerSuccessed="Pendaftaran sukses!",
- loginSuccessed="Anda sekarang tergabung!",
- accessSuccessed="Akses diberikan",
-
- wsConnecting="Menghubungkan websocket…",
- wsFailed="Koneksi websocket gagal",
- wsClose="Websocket tertutup:",
+ checkEmail="Permintaan daftar telah terkirim.",
+
+ wsFailed="Koneksi websocket gagal: $1",
+ wsClose="Websocket tertutup: $1",
netTimeout="Koneksi waktu habis",
+ -- serverDown="Oops! Server is down",
+ -- requestFailed="Request failed",
- onlinePlayerCount="Online",
- createRoomSuccessed="Ruang dibuat",
+ onlinePlayerCount="Online: $1",
+ createRoomSuccessed="Ruang terbuat",
+ -- playerKicked="$1 removed $2 from room",
+ -- becomeHost="$1 become host",
started="Bermain",
- joinRoom="telah memasuki ruangan.",
- leaveRoom="telah keluar dari ruangan.",
+ joinRoom="$1 telah memasuki ruangan.",
+ leaveRoom="$1 telah keluar dari ruangan.",
+ -- roomRemoved="Room was removed",
ready="Siap",
- connStream="Menghubungi",
- waitStream="Menunggu",
spectating="Menonton",
- chatRemain="Online",
- chatStart="------Awal percakapan------",
- chatHistory="------Pesan-pesan baru di bawah ini------",
+
+
keySettingInstruction="Tekan untuk menghubung tombol ke aksi tertentu\nescape: batal\nbackspace: hapus",
customBGhelp="Seret file gambar di sini untuk memasangkan background",
customBGloadFailed="Format file gambar tidak didukung untuk background",
errorMsg="Techmino mengalami eror dan harus memuat ulang.\nAnda bisa mengirim log eror ke developer.",
- tryAnotherBuild="[Invalid UTF-8] Jika Anda di Windows, coba download Techmino-win32 atau Techmino-win64 (berbeda dari yang Anda menggunakan sekarang).",
modInstruction="Pilih mod Anda!\nMod memungkinkan Anda untuk mengubah permainan,\ntetapi juga bisa menghancur permainan.\nNilai-nilai tidak akan disimpan saat menggunakan mod.",
modInfo={
- next="BLOK LANJUT\nMengubah jumlah blok lanjut yang ditampilkan.",
+ next="BLOK LANJUT\nMengubah jumlah pratinjau blok lanjut yang ditampilkan.",
hold="SIMPAN\nMengubah jumlah blok yang bisa disimpan.",
- hideNext="BLOK LANJUT Tersembunyi\nMenyembunyikan beberapa blok lanjut.",
- infHold="SIMPAN SELAMANYA\nMemungkinkan Anda untuk menyimpan blok-blok selamanya.",
- hideBlock="Sembunyikan Blok Aktif\nMenyembunyikan blok yang Anda mengontrol.",
- hideGhost="Sembunyikan Blok Hantu\nMenyembunyikan blok yang menunjukkan tempat blok yang sedang dikontrol akan jatuh.",
- hidden="Sembunyikan Blok Terdarat\nMenyembunyikan blok yang sudah mendarat setelah waktu yang tertentu.",
- hideBoard="Sembunyikan Tempat Main\nMenyembunyikan bagian atau seluruh tempat main.",
+ hideNext="BLOK LANJUT Tersembunyi\nMengubah jumlah pratinjau blok lanjut yang disembunyikan.",
+ infHold="SIMPAN TAK TERBATAS\nMemungkinkan Anda untuk menyimpan blok-blok tidak terbatas.",
+ hideBlock="Sembunyikan Blok Aktif\nMenyembunyikan blok aktif.",
+ hideGhost="Sembunyikan Blok Hantu\nMenyembunyikan blok hantu.",
+ hidden="Sembunyikan Blok Terdarat\nMenyembunyikan blok terkunci.",
+ hideBoard="Sembunyikan Tempat Main\nMenyembunyikan sebagian atau seluruh tempat main.",
flipBoard="Putar Tempat Main\nMembalik atau memutar tempat main.",
dropDelay="Gravitasi\nMengubah gravitasi dalam frame per blok.",
- lockDelay="Tunda Mengunci\nMengubah tunda mengunci dalam frame.",
+ lockDelay="Tunda Mengunci\nMengubah tunda kunci dalam frame.",
waitDelay="Tunda Muncul\nMengubah tunda muncul blok dalam frame.",
- fallDelay="Tunda Baris\nMengubah tunda saat membuat baris dalam frame.",
+ fallDelay="Tunda Baris\nMengubah tunda baris jatuh dalam frame.",
life="Nyawa\nMengubah nomor awal nyawa.",
forceB2B="Hanya B2B\nMengakhirkan permainan jika meter B2B jatuh ke 0.",
forceFinesse="Efisiensi Tombol Maximum\nMengakhirkan permainan jika efisiensi tombol tidak maksimum.",
@@ -178,12 +231,12 @@ return{
"Baris/Baris Gali:",
"Serangan/Serangan Gali:",
"Diterima:",
- "Jumlah Tindakan Membuat Baris:",
+ "Baris:",
"Spins:",
- "B2B/B3B/PC/Hampir PC:",
+ "B2B/B3B/PC/Setengah PC:",
"Efisiensi Tombol:",
},
- radar={"BLOK","SERANGAN","SRGN + BLOK","SRGN TERKIRIM","KECEPATAN","GALI"},
+ radar={"BLOK","SERANGAN","KEKUATAN","KIRIMAN","KECEPATAN","GALI"},
radarData={"D'PM","ADPM","APM","SPM","L'PM","DPM"},
stat={
"Jumlah Pembukaan:",
@@ -191,12 +244,12 @@ return{
"Jumlah Waktu Bermain:",
"Tombol/Putar/Simpan:",
"Blok/Baris/Serangan:",
- "Serangan Diterima/Ditolak/Muncul:", -- what is this
+ "Serangan Diterima/Ditolak/Muncul:",
"Gali/Serangan Gali:",
"Efisiensi/Efisiensi Gali:",
"B2B/B2B2B:",
- "PC/Hampir PC:",
- "Efisiensi Tombol Tidak Maksimal/Nilai:",
+ "PC/Setengah PC:",
+ "Kesalahan Efisiensi Tombol/Nilai:",
},
aboutTexts={
"Ini hanya penyusun blok *normal*. Sungguh, hanya itu saja.",
@@ -207,8 +260,8 @@ return{
"Pastikan untuk mendapat permainan ini hanya dari sumber resmi,",
"karena kita tidak bisa meyakinkan Anda aman jika Anda mendapat permainan ini dari sumber lain.",
"Penciptanya tidak bertanggung jawab untuk modifikasi.",
- FNNS and"/"or"Permainan ini gratis, tetapi sumbangan sangat dihargai.",
- -- FNNS and"/"or"Check Zictionary for more",
+ FNNS and "/" or "Permainan ini gratis, tetapi sumbangan sangat dihargai.",
+ -- FNNS and "/" or "Check Zictionary for more",
},
staff={
"ASLI OLEH MrZ",
@@ -251,6 +304,12 @@ return{
"(旋律星萤)",
"(T0722)",
"",
+ "Ilustrasi",
+ "Miya",
+ "Mono",
+ "Xiaoya",
+ "葉枭",
+ "",
"Desain Musik",
"MrZ",
"柒栎流星",
@@ -276,7 +335,9 @@ return{
"ScF",
"C₂₉H₂₅N₃O₅",
"NOT_A_ROBOT",
- "sakurw",
+ "XMiao",
+ "sakurw, Airun, 幽灵3383",
+ "Shard Nguyễn, Squishy, TVN community",
"",
"Pertunjukan",
"Electric283",
@@ -302,8 +363,8 @@ return{
"huaji2369",
"Lexitik",
"Tourahi Anime",
- "[All other test staff]",
- "…And You!",
+ "[Semua staf penguji lainnya]",
+ "…Dan Anda!",
},
used=[[
Alat-alat yang digunakan:
@@ -315,13 +376,13 @@ return{
Cold_Clear [MinusKelvin]
json.lua [rxi]
profile.lua [itraykov]
- simple-love-lights [dylhunn]
+ sha2 [Egor Skriptunoff]
]],
support="Dukung pencipta",
WidgetText={
main={
offline="Main Sendiri",
- qplay="Terakhir Dimain",
+ qplay="Terakhir Dimain: ",
online="Multipemain",
custom="Permainan Tersesuai",
setting="Pengaturan",
@@ -345,7 +406,7 @@ return{
pause={
setting="Pengaturan (S)",
replay="Ulang (P)",
- save="Simpan Pengulangan (O)",
+ save="Simpan (O)",
resume="Lanjut (esc)",
restart="Coba lagi (R)",
quit="Berhenti (Q)",
@@ -355,6 +416,7 @@ return{
league="Tech League",
ffa="FFA",
rooms="Ruang-ruang",
+ -- resetPW="Reset password",
logout="Log out",
},
net_league={
@@ -431,7 +493,6 @@ return{
sysCursor="Guna Mouse Bawaan",
autoPause="Jeda Jika Tidak Difokus",
autoSave="Simpan Rekor Otomatis",
- autoLogin="Auto-login Saat Membuka",
simpMode="Mode Sederhana",
},
setting_video={
@@ -459,7 +520,6 @@ return{
atkFX="Efek Serang",
frame="Kecepatan Bingkai (%)",
- FTlock="Lewat Bingkai",
text="Teks Baris",
score="Teks Nilai",
@@ -473,6 +533,8 @@ return{
power="Info Baterai",
clean="Gambar Cepat",
fullscreen="Layar Penuh",
+ -- portrait="Portrait",
+ -- msaa="MSAA level",
bg_on="B.G. Normal",
bg_off="Tidak Ada B.G.",
@@ -684,22 +746,19 @@ return{
label="label",
},
login={
- title="Masuk",
- register="Daftar",
- email="Alamat Email",
- password="Password",
- keepPW="Ingat Saya",
- login="Masuk",
- },
- register={
- title="Daftar",
- login="Masuk",
- username="Username",
- email="Alamat Email",
+ -- title="Sign In",
+ -- ticket="Auth Ticket",
+ -- authorize="Go Authorizing",
+ -- paste="Paste Ticket",
+ -- submit="Submit",
+ },
+ reset_password={
+ -- title="Reset Password",
+ -- send="Send code",
+ -- code="Verification Code",
password="Password",
password2="Ulangi Password",
- register="Daftar",
- registering="Menunggu respon…",
+ -- setPW="Set Password",
},
account={
title="Akun",
@@ -756,117 +815,127 @@ return{
},
},
modes={
- ['sprint_10l']= {"Balapan", "10L", "Buat 10 baris!"},
- ['sprint_20l']= {"Balapan", "20L", "Buat 20 baris!"},
- ['sprint_40l']= {"Balapan", "40L", "Buat 40 baris!"},
- ['sprint_100l']= {"Balapan", "100L", "Buat 100 baris!"},
- ['sprint_400l']= {"Balapan", "400L", "Buat 400 baris!"},
- ['sprint_1000l']= {"Balapan", "1.000L", "Buat 1.000 baris!"},
- ['sprintPenta']= {"Balapan", "PENTOMINO", "40L dengan pentomino!"},
- ['sprintMPH']= {"Balapan", "MPH", "Tanpa ingatan\nTanpa pratinjau\nTanpa simpan"},
- ['dig_10l']= {"Gali", "10L", "Gali 10 baris!"},
- ['dig_40l']= {"Gali", "40L", "Gali 40 baris!"},
- ['dig_100l']= {"Gali", "100L", "Gali 100 baris!"},
- ['dig_400l']= {"Gali", "400L", "Gali 400 baris!"},
- ['drought_n']= {"Nasib Buruk", "100L", "Tidak ada blok I..."},
- ['drought_l']= {"Nasib Buruk+", "100L", "Nasib sangat buruk..."},
- ['marathon_n']= {"Maraton", "NORMAL", "200-baris maraton dengan kecepatan meningkat"},
- ['marathon_h']= {"Maraton", "SULIT", "200-baris maraton dengan kecepatan tinggi"},
- ['solo_e']= {"Tarung", "MUDAH", "Kalahkan AInya!"},
- ['solo_n']= {"Tarung", "NORMAL", "Kalahkan AInya!"},
- ['solo_h']= {"Tarung", "SULIT", "Kalahkan AInya!"},
- ['solo_l']= {"Tarung", "GILA", "Kalahkan AInya!"},
- ['solo_u']= {"Tarung", "TERAKHIR", "Kalahkan AInya!"},
- ['techmino49_e']= {"Tech 49", "MUDAH", "Pertarungan dengan 49 pemain."},
- ['techmino49_h']= {"Tech 49", "SULIT", "Pertarungan dengan 49 pemain."},
- ['techmino49_u']= {"Tech 49", "TERAKHIR", "Pertarungan dengan 49 pemain."},
- ['techmino99_e']= {"Tech 99", "MUDAH", "Pertarungan dengan 99 pemain."},
- ['techmino99_h']= {"Tech 99", "SULIT", "Pertarungan dengan 99 pemain."},
- ['techmino99_u']= {"Tech 99", "TERAKHIR", "Pertarungan dengan 99 pemain."},
- ['round_e']= {"Giliran", "MUDAH", "Giliran main melawan AI!"},
- ['round_n']= {"Giliran", "NORMAL", "Giliran main melawan AI!"},
- ['round_h']= {"Giliran", "SULIT", "Giliran main melawan AI!"},
- ['round_l']= {"Giliran", "GILA", "Giliran main melawan AI!"},
- ['round_u']= {"Giliran", "TERAKHIR", "Giliran main melawan AI!"},
- ['master_n']= {"Jago", "NORMAL", "Untuk pemula 20G"},
- ['master_h']= {"Jago", "SULIT", "Untuk pro 20G"},
- ['master_m']= {"Jago", "M21", "Untuk jago 20G"},
- ['master_final']= {"Jago", "TERAKHIR", "Lebih dari 20G"},
- ['master_ph']= {"Jago", "KHAYALAN", "???"},
- ['master_ex']= {"Sangat Jago", "EKSTRA", "Blok tidak kelihatan"},
- ['master_instinct']={"Jago", "INSTINK", "Bagaimana jika blok terkontrol tersembunyi?"},
- ['strategy_e']= {"Strategi", "MUDAH", "Keputusan 20G cepat"},
- ['strategy_h']= {"Strategi", "SULIT", "Keputusan 20G cepat"},
- ['strategy_u']= {"Strategi", "TERAKHIR", "Keputusan 20G cepat"},
- ['strategy_e_plus']={"Strategi", "MUDAH+", "Keputusan 20G cepat"},
- ['strategy_h_plus']={"Strategi", "SULIT+", "Keputusan 20G cepat"},
- ['strategy_u_plus']={"Strategi", "TERAKHIR+", "Keputusan 20G cepat"},
- ['blind_e']= {"Tak Terlihat", "MUDAH", "Untuk pemula"},
- ['blind_n']= {"Tak Terlihat", "NORMAL", "Untuk amatir"},
- ['blind_h']= {"Tak Terlihat", "SULIT", "Untuk orang berpengalaman"},
- ['blind_l']= {"Tak Terlihat", "GILA", "Untuk profesional"},
- ['blind_u']= {"Tak Terlihat", "???", "Apakah Anda siap?"},
- ['blind_wtf']= {"Tak Terlihat", "TERAKHIR", "Anda belum siap"},
- ['classic_e']= {"Klasik", "MUDAH", "Rekreasi berkecepatan rendah dari tahun 80-an"},
- ['classic_h']= {"Klasik", "SULIT", "Rekreasi berkecepatan medium dari tahun 80-an"},
- ['classic_u']= {"Klasik", "TERAKHIR", "Rekreasi berkecepatan tinggi dari tahun 80-an"},
- ['survivor_e']= {"Bertahan", "MUDAH", "Berapa lama Anda bisa bertahan?"},
- ['survivor_n']= {"Bertahan", "NORMAL", "Berapa lama Anda bisa bertahan?"},
- ['survivor_h']= {"Bertahan", "SULIT", "Berapa lama Anda bisa bertahan?"},
- ['survivor_l']= {"Bertahan", "GILA", "Berapa lama Anda bisa bertahan?"},
- ['survivor_u']= {"Bertahan", "TERAKHIR", "Berapa lama Anda bisa bertahan?"},
- ['attacker_h']= {"Penyerang", "SULIT", "Praktekkan keahlian menyerang Anda!"},
- ['attacker_u']= {"Penyerang", "TERAKHIR", "Praktekkan keahlian menyerang Anda!"},
- ['defender_n']= {"Pembela", "NORMAL", "Praktekkan keahlian membela Anda!"},
- ['defender_l']= {"Pembela", "GILA", "Praktekkan keahlian membela Anda!"},
- ['dig_h']= {"Pembor", "SULIT", "Praktekkan keahlian menggali Anda!"},
- ['dig_u']= {"Pembor", "TERAKHIR", "Praktekkan keahlian menggali Anda!"},
- ['clearRush']= {"Gegas Baris", "NORMAL", "Tutorial all-spin!\n[Dalam pengembangan]"},
- ['c4wtrain_n']= {"Latihan C4W", "NORMAL", "Kombo tidak terbatas."},
- ['c4wtrain_l']= {"Latihan C4W", "GILA", "Kombo tidak terbatas."},
- ['pctrain_n']= {"Latihan PC", "NORMAL", "Latihan PC"},
- ['pctrain_l']= {"Latihan PC", "GILA", "Latihan PC yang lebih sulit"},
- ['pc_n']= {"Tantangan PC", "NORMAL", "Dapatkan PC sampai 100 baris!"},
- ['pc_h']= {"Tantangan PC", "SULIT", "Dapatkan PC sampai 100 baris!"},
- ['pc_l']= {"Tantangan PC", "GILA", "Dapatkan PC sampai 100 baris!"},
- ['pc_inf']= {"Tantangan PC", "TAK TERBATAS", "Dapatkan PC sebanyaknya!"},
- ['tech_n']= {"Tech", "NORMAL", "Coba jaga deret Back-To-Back!"},
- ['tech_n_plus']= {"Tech", "NORMAL+", "Hanya Spins & PCs dibolehkan"},
- ['tech_h']= {"Tech", "SULIT", "Coba jaga deret Back-To-Back!"},
- ['tech_h_plus']= {"Tech", "SULIT+", "Hanya Spins & PCs dibolehkan"},
- ['tech_l']= {"Tech", "GILA", "Coba jaga deret Back-To-Back!"},
- ['tech_l_plus']= {"Tech", "GILA+", "Hanya Spins & PCs dibolehkan"},
- ['tech_finesse']= {"Tech", "EF. TOMBOL", "Efisiensi tombol harus maksimal!"},
- ['tech_finesse_f']= {"Tech", "EF. TOMBOL+", "Efisiensi tombol maksimal dan tidak ada garis normal!"},
- ['tsd_e']= {"Tantangan TSD", "MUDAH", "Hanya T-Spin Double dibolehkan!"},
- ['tsd_h']= {"Tantangan TSD", "SULIT", "Hanya T-Spin Double dibolehkan!"},
- ['tsd_u']= {"Tantangan TSD", "TERAKHIR", "Hanya T-Spin Double dibolehkan!"},
- ['backfire_n']= {"Serangan Balik", "NORMAL", "Tahankan serang baliknya!"},
- ['backfire_h']= {"Serangan Balik", "SULIT", "Tahankan serang baliknya!"},
- ['backfire_l']= {"Serangan Balik", "GILA", "Tahankan serang baliknya!"},
- ['backfire_u']= {"Serangan Balik", "TERAKHIR", "Tahankan serang baliknya!"},
- ['sprintAtk']= {"Balapan", "100 Serangan", "Kirim 100 baris serangan!"},
- ['sprintEff']= {"Balapan", "Efisiensi", "Kirim lebih banyak serangan sampai 40 baris!"},
- ['zen']= {"Zen", "200L", "Permainan 200-garis tanpa batas waktu"},
- ['ultra']= {"Ultra", "EKSTRA", "Permainan 2 menit. Dapatkan nilai sebanyaknya!"},
- ['infinite']= {"Tak Terbatas", "", "Bak pasir"},
- ['infinite_dig']= {"Tak Terbatas: Gali","", "Gali, gali, gali"},
- ['marathon_inf']= {"Maraton", "TAK TERBATAS", "Maraton tanpa akhir."},
-
- ['custom_clear']= {"Tersesuai", "NORMAL"},
- ['custom_puzzle']= {"Tersesuai", "TEKA-TEKI"},
+ ['sprint_10l']= {"Balapan", "10L", "Buat 10 baris!"},
+ ['sprint_20l']= {"Balapan", "20L", "Buat 20 baris!"},
+ ['sprint_40l']= {"Balapan", "40L", "Buat 40 baris!"},
+ ['sprint_100l']= {"Balapan", "100L", "Buat 100 baris!"},
+ ['sprint_400l']= {"Balapan", "400L", "Buat 400 baris!"},
+ ['sprint_1000l']= {"Balapan", "1.000L", "Buat 1.000 baris!"},
+ ['sprintPenta']= {"Balapan", "PENTOMINO", "40L dengan pentomino!"},
+ ['sprintMPH']= {"Balapan", "MPH", "Tanpa ingatan\nTanpa pratinjau\nTanpa simpan"},
+ ['sprint123']= {"Balapan", "M123", "40L dengan hanya monomino, domino, dan trimino"},
+ ['secret_grade']= {"Secret Grade", "", "Buatlah formasi lubang zigzag, menuruti panduannya!"},
+ ['dig_10l']= {"Gali", "10L", "Gali 10 baris!"},
+ ['dig_40l']= {"Gali", "40L", "Gali 40 baris!"},
+ ['dig_100l']= {"Gali", "100L", "Gali 100 baris!"},
+ ['dig_400l']= {"Gali", "400L", "Gali 400 baris!"},
+ ['dig_eff_10l']= {"Gali", "EFISIENSI 10L", "Gali 10 baris!"},
+ ['dig_eff_40l']= {"Gali", "EFISIENSI 40L", "Gali 40 baris!"},
+ ['dig_eff_100l']= {"Gali", "EFISIENSI 100L","Gali 100 baris!"},
+ ['dig_eff_400l']= {"Gali", "EFISIENSI 400L","Gali 400 baris!"},
+ ['dig_quad_10l']= {"Gali", "TECHRASH 10L", "Gali 10 baris hanya dengan techrash!"},
+ ['drought_n']= {"Nasib Buruk", "100L", "Tidak ada blok I..."},
+ ['drought_l']= {"Nasib Buruk+", "100L", "Nasib sangat buruk..."},
+ ['marathon_n']= {"Maraton", "NORMAL", "200-baris maraton dengan kecepatan meningkat"},
+ ['marathon_h']= {"Maraton", "SULIT", "200-baris maraton dengan kecepatan tinggi"},
+ ['solo_e']= {"Tarung", "MUDAH", "Kalahkan AInya!"},
+ ['solo_n']= {"Tarung", "NORMAL", "Kalahkan AInya!"},
+ ['solo_h']= {"Tarung", "SULIT", "Kalahkan AInya!"},
+ ['solo_l']= {"Tarung", "GILA", "Kalahkan AInya!"},
+ ['solo_u']= {"Tarung", "TERAKHIR", "Kalahkan AInya!"},
+ ['techmino49_e']= {"Tech 49", "MUDAH", "Pertarungan dengan 49 pemain."},
+ ['techmino49_h']= {"Tech 49", "SULIT", "Pertarungan dengan 49 pemain."},
+ ['techmino49_u']= {"Tech 49", "TERAKHIR", "Pertarungan dengan 49 pemain."},
+ ['techmino99_e']= {"Tech 99", "MUDAH", "Pertarungan dengan 99 pemain."},
+ ['techmino99_h']= {"Tech 99", "SULIT", "Pertarungan dengan 99 pemain."},
+ ['techmino99_u']= {"Tech 99", "TERAKHIR", "Pertarungan dengan 99 pemain."},
+ ['round_e']= {"Giliran", "MUDAH", "Giliran main melawan AI!"},
+ ['round_n']= {"Giliran", "NORMAL", "Giliran main melawan AI!"},
+ ['round_h']= {"Giliran", "SULIT", "Giliran main melawan AI!"},
+ ['round_l']= {"Giliran", "GILA", "Giliran main melawan AI!"},
+ ['round_u']= {"Giliran", "TERAKHIR", "Giliran main melawan AI!"},
+ ['big_n']= {"Besar", "NORMAL", "Main dalam tempat main lebih kecil!"},
+ ['big_h']= {"Besar", "SULIT", "Main dalam tempat main lebih kecil!"},
+ ['master_n']= {"Ahli", "NORMAL", "Untuk pemula 20G"},
+ ['master_h']= {"Ahli", "SULIT", "Untuk pro 20G"},
+ ['master_m']= {"Ahli", "M21", "Untuk jago 20G"},
+ ['master_final']= {"Ahli", "TERAKHIR", "Lebih dari 20G"},
+ ['master_ph']= {"Ahli", "KHAYALAN", "???"},
+ ['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_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", "MUDAH", "Untuk pemula"},
+ ['blind_n']= {"Tak Terlihat", "NORMAL", "Untuk amatir"},
+ ['blind_h']= {"Tak Terlihat", "SULIT", "Untuk orang berpengalaman"},
+ ['blind_l']= {"Tak Terlihat", "GILA", "Untuk profesional"},
+ ['blind_u']= {"Tak Terlihat", "???", "Apakah Anda siap?"},
+ ['blind_wtf']= {"Tak Terlihat", "TERAKHIR", "Anda belum siap"},
+ ['classic_e']= {"Klasik", "MUDAH", "Rekreasi berkecepatan rendah dari tahun 80-an"},
+ ['classic_h']= {"Klasik", "SULIT", "Rekreasi berkecepatan medium dari tahun 80-an"},
+ ['classic_l']= {"Klasik", "GILA", "Rekreasi berkecepatan medium-tinggi dari tahun 80-an"},
+ ['classic_u']= {"Klasik", "TERAKHIR", "Rekreasi berkecepatan tinggi dari tahun 80-an"},
+ ['survivor_e']= {"Bertahan", "MUDAH", "Berapa lama Anda bisa bertahan?"},
+ ['survivor_n']= {"Bertahan", "NORMAL", "Berapa lama Anda bisa bertahan?"},
+ ['survivor_h']= {"Bertahan", "SULIT", "Berapa lama Anda bisa bertahan?"},
+ ['survivor_l']= {"Bertahan", "GILA", "Berapa lama Anda bisa bertahan?"},
+ ['survivor_u']= {"Bertahan", "TERAKHIR", "Berapa lama Anda bisa bertahan?"},
+ ['attacker_h']= {"Penyerang", "SULIT", "Praktekkan keahlian menyerang Anda!"},
+ ['attacker_u']= {"Penyerang", "TERAKHIR", "Praktekkan keahlian menyerang Anda!"},
+ ['defender_n']= {"Pembela", "NORMAL", "Praktekkan keahlian membela Anda!"},
+ ['defender_l']= {"Pembela", "GILA", "Praktekkan keahlian membela Anda!"},
+ ['dig_h']= {"Pembor", "SULIT", "Praktekkan keahlian menggali Anda!"},
+ ['dig_u']= {"Pembor", "TERAKHIR", "Praktekkan keahlian menggali Anda!"},
+ ['c4wtrain_n']= {"Latihan C4W", "NORMAL", "Kombo tidak terbatas."},
+ ['c4wtrain_l']= {"Latihan C4W", "GILA", "Kombo tidak terbatas."},
+ ['pctrain_n']= {"Latihan PC", "NORMAL", "Latihan PC"},
+ ['pctrain_l']= {"Latihan PC", "GILA", "Latihan PC yang lebih sulit"},
+ ['pc_n']= {"Tantangan PC", "NORMAL", "Dapatkan PC sampai 100 baris!"},
+ ['pc_h']= {"Tantangan PC", "SULIT", "Dapatkan PC sampai 100 baris!"},
+ ['pc_l']= {"Tantangan PC", "GILA", "Dapatkan PC sampai 100 baris!"},
+ ['pc_inf']= {"Tantangan PC", "TAK TERBATAS", "Dapatkan PC sebanyaknya!"},
+ ['tech_n']= {"Tech", "NORMAL", "Coba jaga deret Back-To-Back!"},
+ ['tech_n_plus']= {"Tech", "NORMAL+", "Hanya Spins & PCs dibolehkan"},
+ ['tech_h']= {"Tech", "SULIT", "Coba jaga deret Back-To-Back!"},
+ ['tech_h_plus']= {"Tech", "SULIT+", "Hanya Spins & PCs dibolehkan"},
+ ['tech_l']= {"Tech", "GILA", "Coba jaga deret Back-To-Back!"},
+ ['tech_l_plus']= {"Tech", "GILA+", "Hanya Spins & PCs dibolehkan"},
+ ['tech_finesse']= {"Tech", "EF. TOMBOL", "Efisiensi tombol harus maksimal!"},
+ ['tech_finesse_f']= {"Tech", "EF. TOMBOL+", "Efisiensi tombol maksimal dan tidak ada garis normal!"},
+ ['tsd_e']= {"Tantangan TSD", "MUDAH", "Hanya T-Spin Double dibolehkan!"},
+ ['tsd_h']= {"Tantangan TSD", "SULIT", "Hanya T-Spin Double dibolehkan!"},
+ ['tsd_u']= {"Tantangan TSD", "TERAKHIR", "Hanya T-Spin Double dibolehkan!"},
+ ['backfire_n']= {"Serangan Balik", "NORMAL", "Tahankan serang baliknya!"},
+ ['backfire_h']= {"Serangan Balik", "SULIT", "Tahankan serang baliknya!"},
+ ['backfire_l']= {"Serangan Balik", "GILA", "Tahankan serang baliknya!"},
+ ['backfire_u']= {"Serangan Balik", "TERAKHIR", "Tahankan serang baliknya!"},
+ ['sprintAtk']= {"Balapan", "100 Serangan", "Kirim 100 baris serangan!"},
+ ['sprintEff']= {"Balapan", "Efisiensi", "Kirim lebih banyak serangan sampai 40 baris!"},
+ ['zen']= {"Zen", "200L", "Permainan 200-garis tanpa batas waktu"},
+ ['ultra']= {"Ultra", "EKSTRA", "Permainan 2 menit. Dapatkan nilai sebanyaknya!"},
+ ['infinite']= {"Tak Terbatas", "", "Bak pasir"},
+ ['infinite_dig']= {"Tak Terbatas: Gali","", "Gali, gali, gali"},
+ ['marathon_inf']= {"Maraton", "TAK TERBATAS", "Maraton tanpa akhir."},
+
+ ['custom_clear']= {"Tersesuai", "NORMAL"},
+ ['custom_puzzle']= {"Tersesuai", "TEKA-TEKI"},
},
getTip={refuseCopy=true,
"(RUR'U')R'FR2U'R'U'(RUR'F')",
- "\"Techmino.app\" tidak bisa dibuka karena penciptanya tidak bisa diverifikasi.",
- "\"Techmino.app\" akan merusak komputer Anda. Anda sebaiknya memindah itu ke tempat sampah.",
+ "\"Techmino.app\" tidak bisa dibuka karena pengembang tidak bisa diverifikasi.",
+ "\"Techmino.app\" akan merusak komputer Anda. Anda harus memindahnya ke tong sampah.",
"\"TechminOS\"",
"\\jezevec/\\jezevec/\\jezevec/",
"\\osk/\\osk/\\osk/",
"↑↑↓↓←→←→BA",
"$include",
"20G sebenarnya peraturan permainan baru!",
- "Rekor dunia 40L: 14.915s dari Reset_",
+ "Rekor dunia 40L: 14.708s dari hiryu",
"Sistem pencapaian segera akan datang!",
"ALL SPIN!",
"Am G F G",
@@ -895,7 +964,7 @@ return{
"Headphone direkomendasikan untuk pengalaman yang lebih baik.",
"Hello world!",
"Hanya ada 2 jenis trimino, yaitu I3 dan L3.",
- "if a==true",
+ " if a==true",
"Tingkatkan frekuensi gambar Anda untuk pengalaman yang lebih baik.",
"Sistem [tindakan] awal dapat menyelamatkan Anda.",
"Apakah B2B2B2B mungkin?",
@@ -916,8 +985,8 @@ return{
"OHHHHHHHHHHHHHH",
"Main dengan satu tangan!",
"Bermain bagus membutuhkan waktu!",
- "dipersembahkan oleh LÖVE",
- "dipersembahkan oleh Un..LÖVE",
+ "Dipersembahkan oleh LÖVE",
+ "Dipersembahkan oleh Un..LÖVE",
"Server kadang tidak berfungsi",
"Beberapa persyaratan untuk mencapai peringkat X sengaja dibuat sulit bahkan untuk pemain terbaik.",
"Segera Anda akan dapat bermain melawan teman dan musuh di seluruh dunia.",
@@ -939,7 +1008,7 @@ return{
"Bagaimana dengan 20 PCs?",
"Bagaimana dengan 23 PCs dalam 100 baris?",
"Bagaimana dengan 26 TSDs?",
- "while(false)",
+ " while (false)",
"Anda adalah seorang jago!",
"Anda dipersilakan untuk membantu kami membuat musik dan efek suara!",
"Anda dapat menghubungkan keyboard ke ponsel atau tablet Anda (tetapi tidak berfungsi di iOS).",
@@ -976,5 +1045,6 @@ return{
{C.R,"LrL ",C.G,"RlR ",C.B,"LLr ",C.O,"RRl ",C.P,"RRR ",C.P,"LLL ",C.C,"FFF ",C.Y,"RfR ",C.Y,"RRf ",C.Y,"rFF"},
{C.Y,"O-Spin Triple!"},
{C.Z,"Apa? ",C.lC,"X-spin?"},
- }
+ },
+ -- pumpkin="I'm a pumpkin",
}
diff --git a/parts/language/lang_ja.lua b/parts/language/lang_ja.lua
index 8983be8d6..3f51ee03f 100644
--- a/parts/language/lang_ja.lua
+++ b/parts/language/lang_ja.lua
@@ -1,50 +1,53 @@
local C=COLOR
-return{
+return {
+ fallback='en',
loadText={
- loadSFX="Loading Sound Effects",
- loadSample="Loading Instrument Samples",
- loadVoice="Loading Voice Packs",
- loadFont="Loading Fonts",
- loadModeIcon="Loading Mode Icons",
- loadMode="Loading Modes",
- loadOther="Loading Other Assets",
- finish="Press Any Key to Start!",
+ loadSFX="効果音をロード中",
+ loadSample="楽器のサンプル音をロード中",
+ loadVoice="ボイスパックをロード中",
+ loadFont="フォントをロード中",
+ loadModeIcon="モードアイコンをロード中",
+ loadMode="モードをロード中",
+ loadOther="他の重要なアセット等をロード中",
+ finish="好きなキーを押してスタート!",
},
- sureQuit="終了するにはもう一度押してください",
- sureReset="リセットするにはもう一度押してください",
- sureDelete="削除するにはもう一度押してください",
- newDay="新しい1日、新しい始まりです!",
- playedLong="長時間プレイしています、適度に休憩を",
- playedTooMuch="かなり長くプレイしています! Techminoは楽しいですが、休憩を忘れずに!",
- settingWarn="注意: 通常ではない設定に変更しました!",
-
- atkModeName={"ランダム","バッジねらい","ととめうち","カウンター"},
+ sureQuit="終了するにはもう一度押してください!",
+ sureReset="リセットするにはもう一度押してください!",
+ sureDelete="削除するにはもう一度押してください!",
+ newDay="新しい1日の始まりです!",
+ playedLong="長時間プレイしています、適度な休憩を",
+ playedTooMuch="長時間プレイしています! Techminoは楽しいですが、休憩を忘れずに!",
+ settingWarn="使用頻度の少ない設定を変更しています。注意してください。",
+ settingWarn2="この設定は再起動後に適用されます",
+
+ atkModeName={"ランダム","バッジ狙い","トドメ撃ち","カウンター"},
royale_remain="残り $1 人",
powerUp={[0]="+000%","+025%","+050%","+075%","+100%"},
cmb={nil,"1 REN","2 REN","3 REN","4 REN","5 REN","6 REN","7 REN","8 REN","9 REN","10 REN!","11 REN!","12 REN!","13 REN!","14 REN!!","15 REN!!","16 REN!!","17 REN!!!","18 REN!!!","19 REN!!!","MEGAREN"},
- spin="-spin",
+ spin="-spin ",
+ spinNC="-spin",
clear={"Single","Double","Triple","Techrash","Pentacrash","Hexacrash","Heptacrash","Octacrash","Nonacrash","Decacrash","Undecacrash","Dodecacrash","Tridecacrash","Tetradecacrash","Pentadecacrash","Hexadecacrash","Heptadecacrash","Octadecacrash","Nonadecacrash","Ultracrash","Impossicrash"},
cleared="$1 Lines",
mini="Mini",b2b="B2B ",b3b="B2B2B ",
- PC="Perfect Clear",HPC="Hemi-Perfect Clear",
+ PC="Perfect Clear",HPC="Half-Perfect Clear",
replaying="[Replay]",
tasUsing="[TAS]",
- stage="Stage $1 Cleared!",
- great="Great!",
- awesome="Awesome!",
- almost="Almost There!",
- continue="Keep Going!",
- maxspeed="MAX SPEED!",
- speedup="Speed Up!",
- missionFailed="Wrong Clear",
-
- speedLV="Speed Level",
- piece="Piece",line="Lines",atk="火力",eff="効率",
+ stage="ステージ $1 クリア!",
+ great="GREAT",
+ awesome="AWESOME!!",
+ almost="もう少し……",
+ continue="まだ行ける!",
+ maxspeed="最高速度!",
+ speedup="スピードアップ!",
+ missionFailed="ミッション失敗",
+
+ speedLV="レベル",
+ piece="ミノ数",line="line数",atk="火力",eff="効率",
rpm="RPM",tsd="TSD",
grade="Grade",techrash="Techrash",
wave="Wave",nextWave="Next",
- combo="Combo",maxcmb="Max Combo",
+ combo="REN",maxcmb="Max REN",
pc="Perfect Clear",ko="KOs",
win="Win!",
@@ -54,98 +57,150 @@ return{
gamewin="You Won",
gameover="Game Over",
- pause="Pause",
- pauseCount="Pause回数",
+ pause="ポーズ",
+ pauseCount="ポーズ回数",
finesse_ap="All Perfect",
finesse_fc="Full Combo",
- page="Page:",
+ page="ページ:",
- cc_fixed="CCは、固定されたミノ順には非対応です",
- cc_swap="ホールドがSwapの時、CCは非対応です",
- ai_prebag="AIはテトロミノではないものを含み、カスタムされたミノ順には非対応です",
- ai_mission="AIは、カスタムミッションに非対応です",
- switchSpawnSFX="ブロック出現時のSFXをONにしてください!",
- needRestart="すべての変更を適用するために再起動してください",
+ cc_fixed="CCはミノ順の指定に非対応です!",
+ cc_swap="CCはホールドモード、Swapに非対応です!",
+ ai_prebag="AIは通常のテトロミノ以外やミノ順指定に非対応です!",
+ ai_mission="AIはカスタムミッションに非対応です!",
+ switchSpawnSFX="ブロック出現時の効果音をONにしてください!",
+ needRestart="すべての変更を適用する為にリスタートしてください!",
loadError_errorMode="'$1'の読み込みに失敗: ロードモード'$2'が存在しません",
loadError_read="'$1'の読み込みに失敗: 読み込みに失敗しました",
loadError_noFile="'$1'の読み込みに失敗: ファイルが存在しません",
loadError_other="'$1'の読み込みに失敗: $2",
- loadError_unknown="'$1'の読み込みに失敗: 理由不明",
+ loadError_unknown="'$1'の読み込みに失敗: 原因不明",
- saveError_duplicate="'$1'の保存に失敗:既に同じ名前のファイルがあります",
- saveError_encode="'$1'の保存に失敗:エンコードエラー",
+ saveError_duplicate="'$1'の保存に失敗: 既に同じ名前のファイルがあります",
+ saveError_encode="'$1'の保存に失敗: エンコードエラー",
saveError_other="'$1'の保存に失敗: $2",
- saveError_unknown="'$1'の読み込みに失敗:理由不明",
+ saveError_unknown="'$1'の保存に失敗: 原因不明です",
copyDone="コピーしました!",
saveDone="データを保存しました!",
- exportSuccess="出力成功!",
- importSuccess="入力成功!",
+ exportSuccess="書き出し成功!",
+ importSuccess="読み取り成功!",
dataCorrupted="データが破損してます",
- pasteWrongPlace="貼り付ける位置が間違ってませんか?",
- noFile="ファイルがないです",
+ pasteWrongPlace="貼り付ける位置を間違っていませんか?",
+ noFile="ファイルが見つかりません",
- nowPlaying="Now playing:",
+ nowPlaying="再生中:",
VKTchW="タッチ感度",
VKOrgW="オリジナル感度",
VKCurW="現在の配置",
- noScore="No scores",
- modeLocked="Locked",
- unlockHint="RankB以上を取得すると解放されます",
- highScore="High Scores",
- newRecord="New Record!",
+ noScore="スコア無し",
+ modeLocked="未開放",
+ unlockHint="前のステージでBランク以上を取得すると解放されます!",
+ highScore="最高記録",
+ newRecord="新記録!",
- replayBroken="リプレイが読み込めません",
+ replayBroken="リプレイが読み込めませんでした",
dictNote="==TetroDictionaryからコピーしました==",
- getNoticeFail="お知らせ情報が取得できませんでした",
- oldVersion="Version $1が取得できます",
- needUpdate="最新のVersionを取得してください!",
- versionNotMatch="Versionsが一致しません!",
- notFinished="工事中!",
-
- jsonError="JSON Error",
-
- noUsername="ユーザーネームを入力してください",
- wrongEmail="メールアドレスが無効です",
- noPassword="パスワードを入力してください",
- diffPassword="パスワードが一致しません",
- registerRequestSent="Sign Upリクエストを送信しました",
- registerSuccessed="Sign Up成功!",
- loginSuccessed="ログインしています!",
- accessSuccessed="アクセス権限を取得しました",
-
- wsConnecting="Websocket connecting…",
- wsFailed="WebSocket Connection Failed",
- wsClose="WebSocket Closed:",
+
+
+ -- Server's warn/error messages
+ Techrater={
+ internalError="内部エラー",
+ databaseError="データベースエラー",
+ invalidFormat="非対応の形式です",
+ invalidArguments="無効な引数です",
+ tooFrequent="リクエストが多すぎます",
+ notAvailable="無効なリクエスト",
+ noPermission="権限がありません",
+ roomNotFound="部屋が見つかりません",
+
+ -- Controllers
+ WebSocket={
+ invalidConnection="接続されていません",
+ invalidAction="無効な操作",
+ playerNotFound="プレイヤーが見つかりませんでした",
+ connectionFailed="接続失敗",
+ },
+ -- Filters
+ CheckPermission={
+ playerNotFound="プレイヤーが見つかりませんでした",
+ },
+ -- Plugins
+ ConnectionManager={
+ playerInvalid="無効なプレイヤー",
+ playerNotFound="プレイヤーが見つかりませんでした",
+ connectionReplaced="接続切替",
+ },
+ NoticeManager={
+ noticeNotFound="通知はありません",
+ },
+ PlayerManager={
+ invalidCode="無効なコード",
+ invalidEmail="無効なEメールアドレス",
+ playerNotFound="プレイヤーが見つかりませんでした",
+ invalidEmailPass="Eメールアドレスもしくはパスワードが違います",
+ emailExists="Eメールアドレスは存在します",
+ emailSendError="送信できませんでした",
+ },
+ -- Strategies
+ PlayerRole={
+ invalidRole="無効なロールです",
+ invalidTarget="無効なターゲットです",
+ },
+ PlayerType={
+ invalidType="無効なタイプです",
+ roomFull="部屋がいっぱいです",
+ },
+ RoomJoin={
+ wrongPassword="パスワードが違います",
+ },
+ },
+
+ tooFrequent="リクエストが多すぎます",
+ roomPasswordChanged="部屋のパスワードを変更しました",
+ oldVersion="バージョン$1のダウンロードが可能になりました",
+ versionNotMatch="バージョンが一致しません",
+ notFinished="未完成です、ご期待ください",
+
+ noUsername="ユーザーネームを入力してください!",
+ wrongEmail="メールアドレスが無効です!",
+ wrongCode="認証コードが違います",
+ noPassword="パスワードを入力してください!",
+ diffPassword="パスワードが一致しません!",
+ checkEmail="Sign Upリクエストを送信しました!",
+
+ wsFailed="ウェブソケットとの通信に失敗しました: $1",
+ wsClose="ウェブソケットとの通信を終了: $1",
netTimeout="接続がタイムアウトしました",
+ serverDown="あー、サーバーが落ちています...",
+ requestFailed="リクエスト失敗",
- onlinePlayerCount="Online",
+ onlinePlayerCount="オンライン人数: $1",
createRoomSuccessed="部屋を建てました",
- started="Playing",
- joinRoom="が入室しました",
- leaveRoom="が退出しました",
- ready="Ready",
- connStream="接続中...",
- waitStream="待機中...",
- spectating="Spectating",
- chatRemain="Online",
- chatStart="------チャットの先頭------",
- chatHistory="------新しいメッセージ------",
+ playerKicked="$1 は、$2 を部屋から追放しました",
+ becomeHost="$1 がホストになりました",
+ started="プレイ中",
+ joinRoom="$1 が入室しました",
+ leaveRoom="$1 が退出しました",
+ roomRemoved="部屋が解散しました",
+ ready="準備OK",
+ spectating="観戦中",
+
+
keySettingInstruction="選択してキーを入力\nEscape: キャンセル\nBackspace: キーを削除",
- customBGhelp="カスタム背景にする画像ファイルをドロップ",
- customBGloadFailed="サポートされていないフォーマットのファイルです",
+ customBGhelp="背景にする画像ファイルをドロップ",
+ customBGloadFailed="非対応のファイル形式です",
- errorMsg="問題が発生しました、エラーログを開発者に送り、再起動してください",
- tryAnotherBuild="[Invalid UTF-8]使用しているOSがWindowsであればTechmino-win32かTechmino-win64をダウンロードしてください (現在使用しているものは違うものです)",
+ errorMsg="問題が発生! ゲームを再起動し、エラーログを開発者に送ってください",
+ tryAnotherBuild="[Invalid UTF-8]使用しているOSがMicrosoft WindowsであればTechmino-win32かTechmino-win64をダウンロードしてください! (現在使用しているソフトは違うバージョンです)",
- modInstruction="Modを選択してください!\nModはゲームの中身を変えます\nしかしゲームが破損することもあります\nModを使用した場合スコアは保存されません",
+ modInstruction="Modを選択してください!\nModはゲームルールを変えられますが正常にプレイできなくなる可能性があります\nModを使用した場合、スコアは保存されません",
modInfo={
next="NEXT\nNEXTの個数を変更します",
hold="HOLD\nHOLDの個数を変更します",
@@ -153,9 +208,9 @@ return{
infHold="InfiniHold\nHOLDできる回数を無限にします",
hideBlock="Hide Current Piece:\n現在出現しているピースを隠します",
hideGhost="No Ghost\nゴーストを消します",
- hidden="Hide Locked Pieces.\n設置されたピースが時間内に見えなくなります",
+ hidden="Hide Locked Pieces\n設置されたピースが時間内に見えなくなります",
hideBoard="Hide Board\n盤面の一部もしくは、全体を隠します",
- flipBoard="Flip Board\n盤面が回転もしくは滑ります",
+ flipBoard="Flip Board\n盤面が回転もしくは、滑ります",
dropDelay="Gravity\n落下速度をフレーム単位で変更します",
lockDelay="Lock Delay\n設置猶予をフレーム単位で変更します",
waitDelay="Spawn Delay\nブロックの出現猶予をフレーム単位で変更します",
@@ -163,66 +218,66 @@ return{
life="Life\n残機数を変更します",
forceB2B="B2B Only\nB2Bが途切れるとゲームオーバーです",
forceFinesse="Finesse Only\n最適化を失敗するとゲームオーバーです",
- tele="Teleport\nDAS:0,ARR:0になります",
+ tele="Teleport\nDAS: 0, ARR: 0になります",
noRotation="No Rotation\n回転出来なくなります",
noMove="No Movement\n左右移動が出来なくなります",
customSeq="Randomizer\nミノの出現法則を変更します",
pushSpeed="Garbage Speed\n下穴がせり上がるまでに置けるブロック数を変更します (ブロック数/フレーム)",
- boneBlock="[ ]\n[ ]ブロックで遊ぼう",
+ boneBlock="[ ]\n骨ブロックで遊ぼう",
},
pauseStat={
- "Time:",
- "入力/回転/Hold:",
- "Pieces:",
- "Row/Dig:",
- "Attack/DigAtk:",
- "Received:",
- "Line消去数:",
- "Spins:",
+ "時間:",
+ "入力数/回転数/ホールド数:",
+ "ミノ数:",
+ "line数/掘line:",
+ "火力数/掘火力:",
+ "受けたline数:",
+ "line消去数:",
+ "スピン:",
"B2B/B3B/PC/HPC:",
"最適化:",
},
radar={"DEF","OFF","ATK","SEND","SPD","DIG"},
- radarData={"DPM","ADPM","APM","SPM","LPM","DPM"},
+ radarData={"DPM","ADPM","APM","SPM","L'PM","DPM"},
stat={
"起動回数:",
"プレイ回数:",
"プレイ時間:",
- "入力/回転/Hold:",
- "Block/Row/Atk.:",
- "Recv./Res./Asc.:",
- "Dig/Dig Atk.:",
- "Eff./Dig Eff.:",
- "B2B/B3B:",
- "PC/HPC:",
- "最適化 ミス/Rate:",
+ "入力数/回転数/ホールド数:",
+ "ミノ数/line数/火力数:",
+ "送られたline数/相殺/受け:",
+ "掘line/掘火力:",
+ "効率/掘の効率:",
+ "B2B数/B3B数:",
+ "PC数/HPC数:",
+ "最適化ミス数/率:",
},
aboutTexts={
- "これは「ただの」落ちものパズルゲームです。本当ですよ",
- "Inspired by C2/IO/JS/WWC/KOS etc.",
+ "これは“ただの”落ちものパズルゲームです。本当ですよ",
+ "C2/IO/JS/WWC/KOS等からアイデアを得ました",
"",
- "Powered by LÖVE",
- "ご意見、ご感想、バグ報告など大歓迎です!",
+ "「LÖVE」搭載",
+ "ご意見、ご感想、バグ報告など、全て大歓迎です!",
"ゲームは、必ず公式から入手してください",
"他から入手した場合は、安全性を保証しません",
- "同時に作者は、責任を負いません",
- FNNS and"/"or"ゲーム自体は、無料ですが寄付をお願いします",
- FNNS and"/"or"詳しくはZictionaryをご覧ください",
+ "同時に制作者は、責任を負いません",
+ FNNS and "/" or "ゲームは無料ですが寄付はありがたいです!",
+ FNNS and "/" or "詳しくはZictionaryをご覧ください",
},
staff={
- "ORIGINALLY BY MrZ",
- "E-Mail: 1046101471@qq.com",
+ "制作者: “MrZ”",
+ "Eメール: “1046101471@qq.com”",
"",
- "Programmed, Developed, And Designed By",
+ "プログラム、開発、デザイン",
"MrZ",
"",
- "Music Made Using",
+ "楽曲作成ツール",
"Beepbox",
"FL Studio",
"FL Mobile",
"Logic Pro X",
"",
- "[POWERED BY LÖVE]",
+ "[LÖVE]搭載",
"",
"プログラミング",
"MrZ",
@@ -250,6 +305,12 @@ return{
"(旋律星萤)",
"(T0722)",
"",
+ "イラスト",
+ "Miya",
+ "Mono",
+ "Xiaoya",
+ "葉枭",
+ "",
"ミュージカルデザイン",
"MrZ",
"柒栎流星",
@@ -260,7 +321,7 @@ return{
"(Aether)",
"(Hailey)",
"",
- "SFXとボイスパック",
+ "効果音とボイスパック",
"Miya",
"Xiaoya",
"Mono",
@@ -275,6 +336,9 @@ return{
"ScF",
"C₂₉H₂₅N₃O₅",
"NOT_A_ROBOT",
+ "XMiao",
+ "sakurw, Airun, 幽灵3383",
+ "Shard Nguyễn, Squishy, TVN community",
"",
"パフォーマンス",
"Electric283",
@@ -313,13 +377,13 @@ return{
Cold_Clear [MinusKelvin]
json.lua [rxi]
profile.lua [itraykov]
- simple-love-lights [dylhunn]
+ sha2 [Egor Skriptunoff]
]],
- support="Support the Author",
+ support="制作者を支援する",
WidgetText={
main={
offline="ソロプレイ",
- qplay="続きからプレイ",
+ qplay="続きから: ",
online="マルチプレイ",
custom="カスタムプレイ",
setting="設定",
@@ -328,17 +392,17 @@ return{
replays="リプレイ",
},
main_simple={
- sprint="Sprint",
- marathon="Marathon",
+ sprint="スプリント",
+ marathon="マラソン",
},
mode={
mod="Mods (F1)",
- start="Start",
+ start="スタート",
},
mod={
title="Mods",
reset="リセット (tab)",
- unranked="Unranked",
+ unranked="記録不可",
},
pause={
setting="設定 (S)",
@@ -350,17 +414,18 @@ return{
tas="TAS (T)",
},
net_menu={
- league="リーグ",
+ league="テクリーグ",
ffa="FFA",
- rooms="クラブ",
- logout="Log Out",
+ rooms="ルーム",
+ resetPW="パスワード再設定",
+ logout="ログアウト",
},
net_league={
match="対戦相手を探す",
},
net_rooms={
password="パスワード",
- refreshing="探索中",
+ refreshing="探索中…",
noRoom="部屋が存在しません",
refresh="更新",
new="部屋を建てる",
@@ -368,24 +433,24 @@ return{
},
net_newRoom={
title="部屋設定",
- roomName="部屋名 (デフォルト: \"[ユーザーネーム]'s room\")",
+ roomName="部屋名 (デフォルト名: \"[username]'s room\")",
password="パスワード",
- description="部屋説明",
+ description="部屋の説明",
life="残機数",
- pushSpeed="せり上がり速度",
- garbageSpeed="せり上がり猶予",
- visible="設置ミノの視認性",
+ pushSpeed="迫り上がり速度",
+ garbageSpeed="迫り上がり猶予",
+ visible="ミノの視認性",
freshLimit="設置時間のリセット回数",
fieldH="盤面の高さ",
bufferLimit="ダメージの保持上限",
- heightLimit="致死Lineの高さ",
+ heightLimit="致死ラインの高さ",
drop="自然落下時間",
lock="設置時間",
wait="操作硬直時間",
- fall="Line消去時間",
+ fall="line消去時間",
hang="死後硬直時間",
hurry="AREキャンセル時間",
@@ -395,28 +460,28 @@ return{
ospin="O-spin",
fineKill="最適化のみ",
b2bKill="B2B継続",
- lockout="盤面内でのみ設置",
+ lockout="盤面外設置禁止",
easyFresh="通常の設置時間リセット",
deepDrop="ディープドロップ",
bone="骨ブロック",
eventSet="ルール設定",
- holdMode="Hold設定",
- nextCount="Next",
- holdCount="Hold",
- infHold="Infinite Hold",
- phyHold="In-place Hold",
+ holdMode="ホールド設定",
+ nextCount="ネクスト数",
+ holdCount="ホールド数",
+ infHold="無限ホールド",
+ phyHold="その場ホールド",
},
net_game={
- ready="Ready",
- spectate="Spectate",
- cancel="Cancel ready",
+ ready="準備OK",
+ spectate="観戦",
+ cancel="キャンセル",
},
setting_game={
- title="game設定",
- graphic="←Video",
- sound="Audio→",
+ title="ゲームの設定",
+ graphic="←画面",
+ sound="音声→",
style="スタイル",
ctrl="チューニング",
@@ -428,19 +493,18 @@ return{
menuPos="メニューの位置",
sysCursor="システムカーソル",
autoPause="ゲーム中断時のオートポーズ",
- autoSave="オートセーブ",
- autoLogin="オートログイン",
- simpMode="シンプルなホーム画面",
+ autoSave="最高記録を更新時にオートセーブ",
+ simpMode="シンプルなホーム",
},
setting_video={
- title="video設定",
- sound="←Audio",
- game="Game→",
+ title="画面の設定",
+ sound="←音声",
+ game="ゲーム→",
block="操作ブロックの描画",
smooth="滑らかな自然落下",
upEdge="3D Block",
- bagLine="7bagの境界線",
+ bagLine="7-Bagの境界線",
ghostType="ゴーストタイプ",
ghost="ゴースト",
@@ -451,15 +515,14 @@ return{
lockFX="設置演出",
dropFX="落下演出",
moveFX="左右移動演出",
- clearFX="Line消去演出",
+ clearFX="line消去演出",
splashFX="消去時の弾ける演出",
shakeFX="盤面移動演出",
atkFX="攻撃演出",
frame="レンダリングフレームレート(%)",
- FTlock="フレームスキップ",
- text="Line消去ポップ",
+ text="line消去ポップ",
score="スコアポップ",
bufferWarn="ダメージアラート",
showSpike="スパイクカウンター",
@@ -468,26 +531,28 @@ return{
warn="警告演出",
clickFX="クリック演出",
- power="バッテリー情報",
- clean="素早い描画",
+ power="バッテリー",
+ clean="描画処理の最適化",
fullscreen="フルスクリーン",
+ portrait="縦画面",
+ msaa="アンチエイリアス(MSAA)レベル",
bg_on="通常背景",
- bg_off="背景なし",
+ bg_off="背景なし ",
bg_custom="カスタム背景",
blockSatur="ブロックデザイン",
fieldSatur="設置ブロックデザイン",
},
setting_sound={
- title="Audio設定",
+ title="音声の設定",
- game="←Game",
- graphic="Video→",
+ game="←ゲーム",
+ graphic="画面→",
mainVol="主音量",
- bgm="BGM",
- sfx="SFX",
+ bgm="音楽",
+ sfx="効果音",
stereo="ステレオ",
spawn="ブロックの出現音",
warn="警告音",
@@ -496,7 +561,7 @@ return{
autoMute="ゲーム中断時のオートミュート",
fine="最適化失敗音",
- sfxPack="SFXパック",
+ sfxPack="効果音パック",
vocPack="ボイスパック",
apply="適用",
},
@@ -505,39 +570,39 @@ return{
preview="preview",
das="DAS",arr="ARR",
- dascut="DAS cut",
- dropcut="Auto-lock cut",
- sddas="Soft Drop DAS",sdarr="Soft Drop ARR",
- ihs="Initial Hold",
- irs="Initial Rotation",
- ims="Initial Movement",
+ dascut="DASカット",
+ dropcut="自動設置カット",
+ sddas="ソフトドロップDAS",sdarr="ソフトドロップARR",
+ ihs="先行ホールド",
+ irs="先行回転",
+ ims="先行移動",
reset="リセット",
},
setting_key={
- a1="Move Left",
- a2="Move Right",
- a3="Rotate Right",
- a4="Rotate Left",
- a5="Rotate 180°",
- a6="Hard Drop",
- a7="Soft Drop",
- a8="Hold",
- a9="Function 1",
- a10="Function 2",
- a11="Instant Left",
- a12="Instant Right",
- a13="Sonic Drop",
- a14="Down 1",
- a15="Down 4",
- a16="Down 10",
- a17="Left Drop",
- a18="Right Drop",
- a19="Left Zangi",
- a20="Right Zangi",
- restart="Retry",
+ a1="左移動",
+ a2="右移動",
+ a3="右回転",
+ a4="左回転",
+ a5="180°回転",
+ a6="ハードドロップ",
+ a7="ソフトドロップ",
+ a8="ホールド",
+ a9="機能 1",
+ a10="機能 2",
+ a11="即左移動",
+ a12="即右移動",
+ a13="ソニックドロップ",
+ a14="落下移動 1",
+ a15="落下移動 4",
+ a16="落下移動 10",
+ a17="左端ハードドロップ",
+ a18="右端ハードドロップ",
+ a19="左ザンギ",
+ a20="右ザンギ",
+ restart="リトライ",
},
setting_skin={
- skinSet="ブロックスキン",
+ skinSet="ミノのスキン",
title="スタイル設定",
skinR="色をリセット",
faceR="方向をリセット",
@@ -546,20 +611,20 @@ return{
default="デフォルト",
snap="グリッドにスナップ",
size="サイズ",
- shape="シャープ",
+ shape="シェイプ",
},
setting_touchSwitch={
- b1= "Move Left:", b2="Move Right:", b3="Rotate Right:", b4="Rotate Left:",
- b5= "Rotate 180°:", b6="Hard Drop:", b7="Soft Drop:", b8="Hold:",
- b9= "Function 1:", b10="Function 2:", b11="Instant Left:", b12="Instant Right:",
- b13="Sonic Drop:", b14="Down 1:", b15="Down 4:", b16="Down 10:",
- b17="Left Drop:", b18="Right Drop:",b19="Left Zangi:", b20="Right Zangi:",
-
- norm="Normal",
- pro="Advanced",
+ b1= "左移動:", b2="右移動:", b3="右回転:", b4="左回転:",
+ b5= "180°回転:", b6="ハードドロップ:", b7="ソフトドロップ:", b8="ホールド:",
+ b9= "ファンクション 1:", b10="ファンクション 2:", b11="即左移動:", b12="即右移動:",
+ b13="ソニックドロップ:", b14="下1移動:", b15="下4移動:", b16="下10移動:",
+ b17="左ドロップ:", b18="右ドロップ:",b19="左ザンギ:", b20="右ザンギ:",
+
+ norm="ノーマル",
+ pro="アドバンス",
icon="アイコン",
- sfx="SFX",
- vib="VIB",
+ sfx="効果音",
+ vib="振動",
alpha="Alpha",
track="オートトラック",
@@ -567,13 +632,13 @@ return{
},
customGame={
title="カスタムプレイ",
- defSeq="デフォルトのミノ順",
+ defSeq="通常のミノ順",
noMsn="ミッションなし",
drop="自然落下時間",
lock="設置時間",
wait="操作硬直時間",
- fall="Line消去時間",
+ fall="line消去時間",
hang="死後硬直時間",
hurry="AREキャンセル時間",
@@ -594,28 +659,28 @@ return{
eventSet="ルール設定",
- holdMode="Hold設定",
- nextCount="Next",
- holdCount="Hold",
- infHold="Infinite Hold",
- phyHold="In-place Hold",
+ holdMode="ホールド設定",
+ nextCount="ネクスト数",
+ holdCount="ホールド数",
+ infHold="無限ホールド",
+ phyHold="その場ホールド",
fieldH="盤面の高さ",
visible="設置ミノの視認性",
freshLimit="設置時間のリセット回数",
opponent="相手",
life="残機数",
- pushSpeed="せり上がり速度",
- garbageSpeed="せり上がり猶予",
+ pushSpeed="迫り上がり速度",
+ garbageSpeed="迫り上がり猶予",
bufferLimit="ダメージの保持上限",
- heightLimit="致死Lineの高さ",
- ospin="O-Spin",
+ heightLimit="致死ラインの高さ",
+ ospin="Oスピン",
fineKill="最適化のみ",
b2bKill="B2B継続",
- lockout="Fail on Lock Out",
+ lockout="盤面外設置禁止",
easyFresh="通常の設置時間リセット",
- deepDrop="Deep Drop",
+ deepDrop="ディープドロップ",
bone="骨ブロック",
},
custom_field={
@@ -625,7 +690,7 @@ return{
any="消しゴム",
smart="自動着色",
- push="せり上がり (K)",
+ push="迫り上がり (K)",
del="Line消去 (L)",
demo="×を非表示",
@@ -651,12 +716,12 @@ return{
Z2="Z2",S2="S2",J2="J2",L2="L2",T2="T2",O2="O2",I2="I2",
Z3="Z3",S3="S3",J3="J3",L3="L3",T3="T3",O3="O3",I3="I3",
O4="O4",I4="I4",
- mission="強制ミッション",
+ mission="ミッションを強制",
},
about={
- staff="staff",
- his="History",
- legals="Legals",
+ staff="スタッフ",
+ his="更新情報",
+ legals="法的情報",
},
dict={
title="TetroDictionary",
@@ -666,78 +731,75 @@ return{
save="データ管理",
},
music={
- title="music room",
+ title="ミュージックルーム",
arrow="→",
- now="Now Playing:",
+ now="再生中:",
- bgm="BGM",
- sound="SFXs",
+ bgm="音楽",
+ sound="効果音",
},
launchpad={
- title="SFX Room",
- bgm="BGM",
- sfx="SFX",
- voc="VOC",
- music="BGM",
+ title="ミュージックルーム",
+ bgm="音楽",
+ sfx="効果音",
+ voc="ボイス",
+ music="曲",
label="ラベル",
},
- login={
- title="Sign In",
- register="Sign Up",
- email="Email Address",
- password="Password",
- keepPW="Remember me",
- login="Log In",
- },
- register={
- title="Sign Up",
- login="Sign In",
- username="ユーザーネーム",
- email="メールアドレス",
+ logi={
+ title="サインイン",
+ ticket="認証チケット",
+ authorize="認証ページにアクセス",
+ paste="認証チケット貼り付け",
+ submit="送信",
+ },
+ reset_password={
+ title="パスワード再設定",
+ send="認証コード送信",
+ code="認証コード",
password="パスワード",
- password2="パスワード",
- register="Sign Up",
- registering="応答待機中...",
+ password2="パスワード(確認)",
+ setPW="パスワード設定",
},
account={
title="アカウント",
},
app_15p={
- color="Color",
- invis="Invis",
- slide="Slide",
- pathVis="Show Path",
- revKB="Reverse",
+ color="色",
+ invis="インビジブル",
+ slide="スライド",
+ pathVis="ポインター",
+ revKB="逆順",
},
app_schulteG={
- rank="Size",
- invis="Invis",
- disappear="Hide",
- tapFX="Tap FX",
+ rank="サイズ",
+ invis="インビジブル",
+ disappear="済消去",
+ tapFX="効果音",
},
app_AtoZ={
- level="Level",
- keyboard="Keyboard",
+ level="レベル",
+ keyboard="キーボード",
},
app_2048={
- invis="Invis",
- tapControl="Tap controls",
+ invis="インビジブル",
+ tapControl="タッチ操作",
- skip="Skip Round",
+ skip="スキップ",
},
app_ten={
next="Next",
- invis="Invis",
- fast="Fast",
+ invis="インビジブル",
+ fast="高速落下",
},
app_dtw={
- color="Color",
- mode="Mode",
+ color="色",
+ mode="モード",
bgm="BGM",
- arcade="Arcade",
+ arcade="アーケード",
},
app_link={
- invis="Invis",
+ invis="インビジブル",
},
savedata={
export="クリップボードにコピー",
@@ -747,111 +809,258 @@ return{
setting="設定",
vk="仮想キーレイアウト",
- couldSave="クラウドに保存(注意:テスト段階)",
+ couldSave="クラウドに保存 (注意:テスト段階)",
notLogin="[クラウドにアクセス中]",
upload="アップロード",
download="ダウンロード",
},
},
modes={
- ['sprint_10l']= {"Sprint", "10L", "10 Line消去!"},
- ['sprint_20l']= {"Sprint", "20L", "20 Line消去!"},
- ['sprint_40l']= {"Sprint", "40L", "40 Line消去!"},
- ['sprint_100l']= {"Sprint", "100L", "100 Line消去!"},
- ['sprint_400l']= {"Sprint", "400L", "400 Line消去!"},
- ['sprint_1000l']= {"Sprint", "1,000L", "1,000 Line消去!"},
- ['sprintPenta']= {"Sprint", "PENTOMINO", "18のペントミノで40 Line消去!"},
- ['sprintMPH']= {"Sprint", "MPH", "ミノ順なし\nNextなし\nHoldなし"},
- ['dig_10l']= {"Dig", "10L", "10 Line下穴を消去"},
- ['dig_40l']= {"Dig", "40L", "40 Line下穴を消去"},
- ['dig_100l']= {"Dig", "100L", "100 Line下穴を消去"},
- ['dig_400l']= {"Dig", "400L", "400 Line下穴を消去"},
- ['drought_n']= {"Drought", "100L", "Iミノなし"},
- ['drought_l']= {"Drought+", "100L", "W T F"},
- ['marathon_n']= {"Marathon", "NORMAL", "速くなる中200 Lineのマラソン"},
- ['marathon_h']= {"Marathon", "HARD", "速い中200 Lineのマラソン"},
- ['solo_e']= {"Battle", "EASY", "AI討伐!"},
- ['solo_n']= {"Battle", "NORMAL", "AI討伐!"},
- ['solo_h']= {"Battle", "HARD", "AI討伐!"},
- ['solo_l']= {"Battle", "LUNATIC", "AI討伐!"},
- ['solo_u']= {"Battle", "ULTIMATE", "AI討伐!"},
- ['techmino49_e']= {"Tech 49", "EASY", "49人で勝負\n最後の1人になれ!"},
- ['techmino49_h']= {"Tech 49", "HARD", "49人で勝負\n最後の1人になれ!"},
- ['techmino49_u']= {"Tech 49", "ULTIMATE", "49人で勝負\n最後の1人になれ!"},
- ['techmino99_e']= {"Tech 99", "EASY", "99人で勝負\n最後の1人になれ!"},
- ['techmino99_h']= {"Tech 99", "HARD", "99人で勝負\n最後の1人になれ!"},
- ['techmino99_u']= {"Tech 99", "ULTIMATE", "99人で勝負\n最後の1人になれ!"},
- ['round_e']= {"Turn-Based", "EASY", "ターン制のAIと勝負!"},
- ['round_n']= {"Turn-Based", "NORMAL", "ターン制のAIと勝負!"},
- ['round_h']= {"Turn-Based", "HARD", "ターン制のAIと勝負!"},
- ['round_l']= {"Turn-Based", "LUNATIC", "ターン制のAIと勝負!"},
- ['round_u']= {"Turn-Based", "ULTIMATE", "ターン制のAIと勝負!"},
- ['master_n']= {"Master", "NORMAL", "20G 初心者方へ"},
- ['master_h']= {"Master", "HARD", "20G プロの方へ"},
- ['master_m']= {"Master", "M21", "20G マスターの方へ"},
- ['master_final']= {"Master", "FINAL", "20G その先へ"},
- ['master_ph']= {"Master", "PHANTASM", "???"},
- ['master_ex']= {"GrandMaster", "EXTRA", "刹那よりも短い永遠"},
- ['master_instinct']={"Master", "INSTINCT", "もしミノが見えなくなったら?"},
- ['strategy_e']= {"Strategy", "EASY", "20Gでの素早い判断"},
- ['strategy_h']= {"Strategy", "HARD", "20Gでの素早い判断"},
- ['strategy_u']= {"Strategy", "ULTIMATE", "20Gでの素早い判断"},
- ['strategy_e_plus']={"Strategy", "EASY+", "20Gでの素早い判断"},
- ['strategy_h_plus']={"Strategy", "HARD+", "20Gでの素早い判断"},
- ['strategy_u_plus']={"Strategy", "ULTIMATE+", "20Gでの素早い判断"},
- ['blind_e']= {"Invisible", "HALF", "初心者用"},
- ['blind_n']= {"Invisible", "ALL", "中級者用"},
- ['blind_h']= {"Invisible", "SUDDEN", "上級者用"},
- ['blind_l']= {"Invisible", "SUDDEN+", "プロフェッショナル用"},
- ['blind_u']= {"Invisible", "?", "覚悟はいいかい?"},
- ['blind_wtf']= {"Invisible", "WTF", "まだ覚悟が足りない"},
- ['classic_e']= {"Classic", "EASY", "80年代を超低速で体験"},
- ['classic_h']= {"Classic", "HARD", "80年代を通常速度で体験"},
- ['classic_u']= {"Classic", "ULTIMATE", "80年代を超高速で体験"},
- ['survivor_e']= {"Survival", "EASY", "どれだけ生き残れる?"},
- ['survivor_n']= {"Survival", "NORMAL", "どれだけ生き残れる?"},
- ['survivor_h']= {"Survival", "HARD", "どれだけ生き残れる?"},
- ['survivor_l']= {"Survival", "LUNATIC", "どれだけ生き残れる?"},
- ['survivor_u']= {"Survival", "ULTIMATE", "どれだけ生き残れる?"},
- ['attacker_h']= {"Attacker", "HARD", "攻撃力を磨け!"},
- ['attacker_u']= {"Attacker", "ULTIMATE", "攻撃力を磨け!"},
- ['defender_n']= {"Defender", "NORMAL", "防御力を磨け!"},
- ['defender_l']= {"Defender", "LUNATIC", "防御力を磨け!"},
- ['dig_h']= {"Driller", "HARD", "回復力を磨け!"},
- ['dig_u']= {"Driller", "ULTIMATE", "回復力を磨け!"},
- ['clearRush']= {"Clear Rush", "NORMAL", "All-Spinチュートリアル!\n[開発中]"},
- ['c4wtrain_n']= {"C4W Training", "NORMAL", "無限コンボ"},
- ['c4wtrain_l']= {"C4W Training", "LUNATIC", "無限コンボ"},
- ['pctrain_n']= {"PC Training", "NORMAL", "パフェ練習"},
- ['pctrain_l']= {"PC Training", "LUNATIC", "もっと難しいパフェ練習"},
- ['pc_n']= {"PC Challenge", "NORMAL", "100Line以内にパフェをたくさん!"},
- ['pc_h']= {"PC Challenge", "HARD", "100Line以内にパフェをたくさん!"},
- ['pc_l']= {"PC Challenge", "LUNATIC", "100Line以内にパフェをたくさん!"},
- ['pc_inf']= {"Inf. PC Challenge", "", "できる限りたくさんのパフェを"},
- ['tech_n']= {"Tech", "NORMAL", "B2Bを繋げ続けよう!"},
- ['tech_n_plus']= {"Tech", "NORMAL+", "回転入れとパフェだけ"},
- ['tech_h']= {"Tech", "HARD", "B2Bを繋げ続けよう!"},
- ['tech_h_plus']= {"Tech", "HARD+", "回転入れとパフェだけ"},
- ['tech_l']= {"Tech", "LUNATIC", "回転入れとパフェだけ"},
- ['tech_l_plus']= {"Tech", "LUNATIC+", "回転入れとパフェだけ"},
- ['tech_finesse']= {"Tech", "FINESSE", "最適化!"},
- ['tech_finesse_f']= {"Tech", "FINESSE+", "最適化はそのまま、普通のLine消去禁止!"},
- ['tsd_e']= {"TSD Challenge", "EASY", "TSDだけ!"},
- ['tsd_h']= {"TSD Challenge", "HARD", "TSDだけ!"},
- ['tsd_u']= {"TSD Challenge", "ULTIMATE", "TSDだけ!"},
- ['backfire_n']= {"Backfire", "NORMAL", "撃った火力が戻ってくる"},
- ['backfire_h']= {"Backfire", "HARD", "撃った火力が戻ってくる"},
- ['backfire_l']= {"Backfire", "LUNATIC", "撃った火力が戻ってくる"},
- ['backfire_u']= {"Backfire", "ULTIMATE", "撃った火力が戻ってくる"},
- ['sprintAtk']= {"Sprint", "100 Attack", "100line送れ!"},
- ['sprintEff']= {"Sprint", "Efficiency", "40lineの間にできるだけ火力を出せ!"},
- ['zen']= {'Zen', "200", "時間制限なしで200Line消去"},
- ['ultra']= {'Ultra', "EXTRA", "2分間のスコアアタック"},
- ['infinite']= {"Infinite", "", "ただのサンドボックス"},
- ['infinite_dig']= {"Infinite: Dig", "", "掘れ掘れ掘れ"},
- ['marathon_inf']= {"Marathon", "INFINITE", "マラソン"},
-
- ['custom_clear']= {"Custom", "NORMAL"},
- ['custom_puzzle']= {"Custom", "PUZZLE"},
+ ['sprint_10l']= {"スプリント", "10L", "10line消せ!"},
+ ['sprint_20l']= {"スプリント", "20L", "20line消せ!"},
+ ['sprint_40l']= {"スプリント", "40L", "40line消せ!"},
+ ['sprint_100l']= {"スプリント", "100L", "100line消せ!"},
+ ['sprint_400l']= {"スプリント", "400L", "400line消せ!"},
+ ['sprint_1000l']= {"スプリント", "1,000L", "1,000line消せ!"},
+ ['sprintPenta']= {"スプリント", "PENTOMINO", "ペントミノで40line"},
+ ['sprintMPH']= {"スプリント", "MPH", "ミノ順なし\nネクストなし\nホールドなし!"},
+ ['sprint123']= {"スプリント", "M123", "モノミノ、ドミノ、トリミノで40line"},
+ ['secret_grade']= {"裏GM", "", "ガイドに従ってジグザグに穴を作れ!"},
+ ['dig_10l']= {"掘り", "10L", "10line下穴を掘れ!"},
+ ['dig_40l']= {"掘り", "40L", "40line下穴を掘れ!"},
+ ['dig_100l']= {"掘り", "100L", "100line下穴を掘れ!"},
+ ['dig_400l']= {"掘り", "400L", "400line下穴を掘れ!"},
+ ['dig_eff_10l']= {"掘り", "EFFICIENCY 10L", "最小のミノ数で10line掘れ!"},
+ ['dig_eff_40l']= {"掘り", "EFFICIENCY 40L", "最小のミノ数で40line掘れ!"},
+ ['dig_eff_100l']= {"掘り", "EFFICIENCY 100L","最小のミノ数で100line掘れ!"},
+ ['dig_eff_400l']= {"掘り", "EFFICIENCY 400L","最小のミノ数で400line掘れ!"},
+ ['dig_quad_10l']= {"掘り", "TECHRASH 10L", "techrashだけで10line下穴を掘れ!"},
+ ['drought_n']= {"ドラウト", "100L", "Iミノ一切無し!"},
+ ['drought_l']= {"ドラウト+", "100L", "わったーふ◯っく!"},
+ ['marathon_n']= {"マラソン", "NORMAL", "加速する中で200lineマラソン!"},
+ ['marathon_h']= {"マラソン", "HARD", "高速の中で200lineマラソン!"},
+ ['solo_e']= {"バトル", "EASY", "低レベルのAIに勝て!"},
+ ['solo_n']= {"バトル", "NORMAL", "通常レベルのAIに勝て!"},
+ ['solo_h']= {"バトル", "HARD", "高レベルのAIに勝て!"},
+ ['solo_l']= {"バトル", "LUNATIC", "プロレベルのAIに勝て!"},
+ ['solo_u']= {"バトル", "ULTIMATE", "神レベルのAIに勝て!"},
+ ['techmino49_e']= {"テック 49", "EASY", "低レベルAIと49人で勝負\n最後の1人まで生き残れ!"},
+ ['techmino49_h']= {"テック 49", "HARD", "高レベルAIと49人で勝負\n最後の1人まで生き残れ!"},
+ ['techmino49_u']= {"テック 49", "ULTIMATE", "神レベルAIと49人で勝負\n最後の1人まで生き残れ!"},
+ ['techmino99_e']= {"テック 99", "EASY", "低レベルAIと99人で勝負\n最後の1人まで生き残れ!"},
+ ['techmino99_h']= {"テック 99", "HARD", "高レベルAIと99人で勝負\n最後の1人まで生き残れ!"},
+ ['techmino99_u']= {"テック 99", "ULTIMATE", "神レベルAIと99人で勝負\n最後の1人まで生き残れ!"},
+ ['round_e']= {"ターン制", "EASY", "ターン制で低レベルAIと勝負!"},
+ ['round_n']= {"ターン制", "NORMAL", "ターン制で通常レベルAIと勝負!"},
+ ['round_h']= {"ターン制", "HARD", "ターン制で高レベルAIと勝負!"},
+ ['round_l']= {"ターン制", "LUNATIC", "ターン制でプロレベルAIと勝負!"},
+ ['round_u']= {"ターン制", "ULTIMATE", "ターン制で神レベルAIと勝負!"},
+ ['big_n']= {"ビッグ", "NORMAL", "小さい盤面でプレイ!"},
+ ['big_h']= {"ビッグ", "HARD", "小さい盤面でプレイ!"},
+ ['master_n']= {"マスター", "NORMAL", "20G 初心者方へ"},
+ ['master_h']= {"マスター", "HARD", "20G 中級者の方へ"},
+ ['master_m']= {"マスター", "M21", "20G 上級者の方へ"},
+ ['master_final']= {"マスター", "FINAL", "20G その先へ"},
+ ['master_ph']= {"マスター", "PHANTASM", "???"},
+ ['master_g']= {"マスター", "GRADED", "最高段位を取れ!"},
+ ['master_ex']= {"グランドマスター", "EXTRA", "一瞬よりも短い永遠"},
+ ['master_instinct']={"マスター", "INSTINCT", "もしミノが一切見えなくなったら?"},
+ ['strategy_e']= {"ストラテジー", "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", "上級者用"},
+ ['blind_l']= {"インビジブル", "SUDDEN+", "プロフェッショナル用"},
+ ['blind_u']= {"インビジブル", "?", "覚悟は良いかい?"},
+ ['blind_wtf']= {"インビジブル", "WTF", "まだ覚悟が足りない"},
+ ['classic_e']= {"クラシック", "EASY", "低速クラシック"},
+ ['classic_h']= {"クラシック", "HARD", "通常速度クラシック"},
+ ['classic_l']= {"クラシック", "LUNATIC", "中高速度クラシック"},
+ ['classic_u']= {"クラシック", "ULTIMATE", "高速クラシック"},
+ ['survivor_e']= {"サバイバル", "EASY", "どれだけ生き残れるかな?"},
+ ['survivor_n']= {"サバイバル", "NORMAL", "どれだけ生き残れるかな?"},
+ ['survivor_h']= {"サバイバル", "HARD", "どれだけ生き残れるかな?"},
+ ['survivor_l']= {"サバイバル", "LUNATIC", "どれだけ生き残れるかな?"},
+ ['survivor_u']= {"サバイバル", "ULTIMATE", "どれだけ生き残れるかな?"},
+ ['attacker_h']= {"火力王", "HARD", "攻撃力を磨け!"},
+ ['attacker_u']= {"火力王", "ULTIMATE", "攻撃力を磨け!"},
+ ['defender_n']= {"相殺王", "NORMAL", "防御力を磨け!"},
+ ['defender_l']= {"相殺王", "LUNATIC", "防御力を磨け!"},
+ ['dig_h']= {"掘王", "HARD", "掘りを磨け"},
+ ['dig_u']= {"掘王", "ULTIMATE", "掘りを磨け"},
+ ['c4wtrain_n']= {"C4Wトレーニング", "NORMAL", "無限中開け"},
+ ['c4wtrain_l']= {"C4Wトレーニング", "LUNATIC", "無限中開け"},
+ ['pctrain_n']= {"パフェトレーニング", "NORMAL", "パフェの練習!"},
+ ['pctrain_l']= {"パフェトレーニング", "LUNATIC", "もっと難しいパフェの練習!"},
+ ['pc_n']= {"パフェチャレンジ", "NORMAL", "100Line以内で パフェをできるだけたくさん取れ!"},
+ ['pc_h']= {"パフェチャレンジ", "HARD", "100Line以内で パフェをできるだけたくさん取れ!"},
+ ['pc_l']= {"パフェチャレンジ", "LUNATIC", "100Line以内で パフェをできるだけたくさん取れ!"},
+ ['pc_inf']= {"無限パフェチャレンジ", "", "できる限りたくさんのパフェを取れ!"},
+ ['tech_n']= {"テクニック", "NORMAL", "B2Bを繋げ続けよう!"},
+ ['tech_n_plus']= {"テクニック", "NORMAL+", "回転入れとパフェだけ!"},
+ ['tech_h']= {"テクニック", "HARD", "B2Bを繋げ続けよう!"},
+ ['tech_h_plus']= {"テクニック", "HARD+", "回転入れとパフェだけ!"},
+ ['tech_l']= {"テクニック", "LUNATIC", "回転入れとパフェだけ!"},
+ ['tech_l_plus']= {"テクニック", "LUNATIC+", "回転入れとパフェだけ!"},
+ ['tech_finesse']= {"テクニック", "FINESSE", "最適化!"},
+ ['tech_finesse_f']= {"テクニック", "FINESSE+", "最適化はそのまま、通常line消去禁止!"},
+ ['tsd_e']= {"TSDチャレンジ", "EASY", "TSDだけ!"},
+ ['tsd_h']= {"TSDチャレンジ", "HARD", "TSDだけ!"},
+ ['tsd_u']= {"TSDチャレンジ", "ULTIMATE", "TSDだけ!"},
+ ['backfire_n']= {"バックファイヤー", "NORMAL", "撃った火力が戻ってくる!"},
+ ['backfire_h']= {"バックファイヤー", "HARD", "撃った火力が戻ってくる!"},
+ ['backfire_l']= {"バックファイヤー", "LUNATIC", "撃った火力が戻ってくる!"},
+ ['backfire_u']= {"バックファイヤー", "ULTIMATE", "撃った火力が戻ってくる!"},
+ ['sprintAtk']= {"スプリント", "100 Attack", "100line送れ!"},
+ ['sprintEff']= {"スプリント", "Efficiency", "40lineの間にできるだけ火力を出せ!"},
+ ['zen']= {'zen', "200", "時間制限なしで200line消去"},
+ ['ultra']= {'ウルトラ', "EXTRA", "2分以内にできるだけ多くの点数を取る"},
+ ['infinite']= {"無限", "", "サンドボックス"},
+ ['infinite_dig']= {"無限: 掘り", "", "掘れ掘れ掘れ"},
+ ['marathon_inf']= {"マラソン", "INFINITE", "ずっとマラソン"},
+
+ ['custom_clear']= {"カスタム", "NORMAL"},
+ ['custom_puzzle']= {"カスタム", "PUZZLE"},
+ },
+getTip={refuseCopy=true,
+ ":pog:",
+ "(RUR'U')R'FR2U'R'U'(RUR'F')",
+ "“Techmino.app”は、開発元を検証できないためあけません。",
+ "“Techmino.app”を開くとコンピュータが破損します。ゴミ箱に入れる必要があります。",
+ "\"TechminOS\"",
+ "\\jezevec/\\jezevec/\\jezevec/",
+ "\\osk/\\osk/\\osk/",
+ "↑↑↓↓←→←→BA",
+ "$include",
+ "0next 0hold.",
+ "100Line以内に23PC?",
+ "1next 0hold",
+ "1next 1hold!",
+ "1next 6hold!",
+ "20Gは全く新しい種類のゲームルールです!",
+ "20PCって何?",
+ "26TSDって何?",
+ "2つの回転を使ってみよう、3つ使うとさらにいいです!",
+ "40-line Sprint WR: 14.708s by hiryu",
+ "6next 1hold!",
+ "6next 6hold?!",
+ "低音を響かせろ!",
+ "低いフレームレートほど重く感じます",
+ "複数のHoldを使ってみよう!",
+ "回転がブロックにどう作用しているか気づいたかい?",
+ "回転なしで40 Lineを完走できる?",
+ "今、B2B2Bを見なかったかい?",
+ "今日も全力で頑張ってください!",
+ "今日も一日がんばるぞい!",
+ "警告: プログラマーアート",
+ "君もGrand Masterだ!",
+ "良いプレイには時間がかかります!",
+ "全部で18種類のペントミノがあります",
+ "全部で7種類のテトリミノがあります",
+ "設定でキーコンフィグを変えられます!",
+ "設定を確認しましょう!",
+ "世界中の友達や敵ともうすぐ対戦できます!",
+ "心の中には確かにM@STERPIECEがあります!",
+ "素晴らしい! しかし次はもっと良くなる……",
+ "統計からセーブフォルダを開くことができます!",
+ "偉大なシステムが間もなく実装されます!",
+ "現代的で親しみやすいこの積みを使いこなしてるかい?",
+ "小さな不具合で一日を無駄にしないように!",
+ "一人用モードを遊ぼう!",
+ "音楽が煩わしい? 無音にすることができます",
+ "英語のアプデ情報はDiscordで見られます",
+ "左右移動なしで40 Lineを完走できる?",
+ "ALL SPIN!",
+ "Am G F G",
+ "B2B2B???",
+ "B2B2B2Bなんて存在するの?",
+ "B2B2B2Bは存在しません",
+ "B2B2B2Bは可能?",
+ "Back-to-Back Techrash, 10 REN, PC!",
+ "テトリスHPC->PCは犯罪です",
+ "ぐわー何をするくぁwせdrftgyふじこlp",
+ "音楽や効果音の制作に協力いただける方は大歓迎です!",
+ "ここに流れるネタも募集中です!",
+ "Bridge Clearが間もなく実装されます!",
+ "Color Clearが間もなく実装されます!",
+ "DASとARRを低くすると、速くなるけど操作が難しくなる!",
+ "Hello World!",
+ "先行[移動/回転/ホールド]は君を救うだろう",
+ "I3とL3の2つだけはユニークなトリミノだ",
+ "l-=-1",
+ "LrL RlR LLr RRl RRR LLL FFF RfR RRf rFF",
+ "Lua最高!",
+ "Mix Clearは間もなく実装されます!",
+ "Nspire-CXのTechmino: 存在はしますが同じゲームではありません",
+ "O-Spin Triple!",
+ "OHHHHHHHHHHHHHH",
+ "Powered by LÖVE",
+ "Powered by Un... LÖVE",
+ "Rank Xの条件は、上級者でも難しくなるように設定されています",
+ "Split Clearが間もなく実装されます!",
+ "sudo rm -rf /*",
+ "Techmino rotation system(TRS)を楽しんで!",
+ "Techmino楽しい!",
+ "TechminoのDiscord鯖に入りましょう!",
+ "Techminoは\"Technique\"と\"Tetromino\"を掛け合わせ造語です!",
+ "Techminoプレイヤーの未来はあなた達のものです!",
+ "TetroDictionary is now available in English.",
+ "TetroDictionaryの日本語版もあります",
+ " while (false)",
+ "ZS JL T O I",
+ "ゲーム内にはモード選択マップからじゃ入れない隠しモードがいくつかあります!",
+ "このゲームでは全てのSpinに火力補正があります!",
+ "テクミノのAll spin気持ちよすぎだろ!!",
+ "このゲームのほとんどの楽曲はBeepboxを用いて作曲されました!",
+ "サーバーが不規則に落ちます",
+ "スタッフロールの背景に流れている名前はスポンサーの名前です!",
+ "タブレットやスマホでもキーボードを接続できます!(iOSにはそんな機能ないと思うけど)",
+ "なにかアイデアがありますか? Discordで提案してください!",
+ "何だこの安っぽいUIと音楽……呆れた",
+ "何? バグを見つけた? GitHubのIssueに報告しよう!",
+ "バグを直接見ないで!",
+ "バトルロワイアルモード実装! 無料で遊べる落ちものパズルゲーム!",
+ "ピースごとに出現する方向を変えられます!",
+ "フレームレートを上げればより快適に!",
+ "ヘッドフォンを付ければより快適に!",
+ "ほとんどのメニューアイコンはUnicode PUAにある自作Glyphsを用いて作られています!",
+ "マルチプレイで遊ぼう! 衝撃を受けるでしょう!!",
+ "メニューをシンプルモードにした場合、イースターエッグがなくなります",
+ "ローディング中! シーンチェンジの間だけじゃないです!",
+ "Zのおすすめ[01]東方原作ゲームをやってみよう!",
+ "Zのおすすめ[02]マイクラをやってみよう!",
+ "Zのおすすめ[03]Osu!をやってみよう!",
+ "Zのおすすめ[04]Quatrackをやってみよう!",
+ "Zのおすすめ[05]テラリアをやってみよう!",
+ "Zのおすすめ[06]Celesteをやってみよう!",
+ "Zのおすすめ[07]グーの惑星をやってみよう!",
+ "Zのおすすめ[08]Orzmicをやってみよう!",
+ "Zのおすすめ[09]ぷよぷよをやってみよう!",
+ "Zのおすすめ[10]Phigrosをやってみよう!",
+ "Zのおすすめ[11]VVVVVVをやってみよう!",
+ "Zのおすすめ[12]Ballanceをやってみよう!",
+ "Zのおすすめ[13]Zumaをやってみよう!",
+ "Zのおすすめ[14]ルービックキューブをやってみよう!",
+ "Zのおすすめ[15]15puzzleをやってみよう!",
+ "Zのおすすめ[16]マインスイーパーをやってみよう!",
+ {C.H,"REGRET!!"},
+ {C.lP,"Secret Number: 626"},
+ {C.lR,"Z ",C.lG,"S ",C.lS,"J ",C.lO,"L ",C.lP,"T ",C.lY,"O ",C.lC,"I"},
+ {C.lY,"COOL!!"},
+ {C.N,"Lua",C.Z," No.1"},
+ {C.P,"T-spin!"},
+ {C.R,"\"知的財産権関連法\""},
+ {C.R,"\"DMCA濫用\""},
+ {C.R,"DD",C.Z," 砲=",C.P,"TS",C.R,"D",C.Z,"+",C.P,"TS",C.R,"D",C.Z," 砲"},
+ {C.R,"DT",C.Z," 砲=",C.P,"TS",C.R,"D",C.Z,"+",C.P,"TS",C.R,"T",C.Z," 砲"},
+ {C.R,"DKS",C.Z,"=",C.P,"TS",C.R,"T",C.Z,"+",C.R,"DT",C.Z," 砲"},
+ {C.R,"LrL ",C.G,"RlR ",C.B,"LLr ",C.O,"RRl ",C.P,"RRR ",C.P,"LLL ",C.C,"FFF ",C.Y,"RfR ",C.Y,"RRf ",C.Y,"rFF"},
+ {C.Y,"O-Spin Triple!"},
+ {C.Z,"なんだって? ",C.lC,"X-Spin?"},
},
-}
\ No newline at end of file
+ pumpkin="どうも、かぼちゃです",
+}
diff --git a/parts/language/lang_pt.lua b/parts/language/lang_pt.lua
index 55281c5c0..61f52ee88 100644
--- a/parts/language/lang_pt.lua
+++ b/parts/language/lang_pt.lua
@@ -1,5 +1,5 @@
local C=COLOR
-return{
+return {
fallback='en',
sureQuit="Aparte novamente para sair",
-- sureReset="Press again to reset",
@@ -8,11 +8,13 @@ return{
playedLong="[Anti-vício] Você andou jogando bastante hoje. Certifique-se de fazer pausas.",
playedTooMuch="[Anti-vício] Você esteve jogando demais hoje! Você não pode jogar mais.",
-- settingWarn="Modifing uncommon setting, be careful!",
+ -- settingWarn2="This setting takes effect after restart",
atkModeName={"Aleatório","Emblemas","K.O.s","Atacantes"},
royale_remain="$1 Jogadores restantes",
cmb={nil,"1 Combo","2 Combo","3 Combo","4 Combo","5 Combo","6 Combo","7 Combo","8 Combo","9 Combo","10 Combo!","11 Combo!","12 Combo!","13 Combo!","14 Combo!!","15 Combo!!","16 Combo!!","17 Combo!!!","18 Combo!!!","19 Combo!!!","MEGACMB"},
- spin="-spin",
+ spin="-spin ",
+ spinNC="-spin",
clear={"Single","Double","Triple","Techrash","Pentacrash","Hexacrash","Heptacrash","Octacrash","Nonacrash","Decacrash","Undecacrash","Dodecacrash","Tridecacrash","Tetradecacrash","Pentadecacrash","Hexadecacrash","Heptadecacrash","Octadecacrash","Nonadecacrash","Ultracrash","Impossicrash"},
-- cleared="$1 lines",
mini="Mini",b2b="B2B ",b3b="B2B2B ",
@@ -53,7 +55,7 @@ return{
-- cc_fixed="CC is incompatible with fixed sequences",
-- cc_swap="CC is incompatible with swap holdmode",
- --ai_prebag="The AI is incompatible with custom sequences which have nontetromino.", inteligência é incompatível com sequências fixas.",
+ -- ai_prebag="The AI is incompatible with custom sequences which have nontetromino.", inteligência é incompatível com sequências fixas.",
ai_mission="A inteligência é incompatível com missões costumizadas.",
switchSpawnSFX="Switch on spawn SFX to play",
needRestart="Funciona após reiniciar",
@@ -91,40 +93,92 @@ return{
-- dictNote="==Copied from TetroDictionary==",
- getNoticeFail="Não conseguiu ter anúncios",
+
+
+ -- Server's warn/error messages
+ Techrater={
+ -- internalError="Internal error",
+ -- databaseError="Database error",
+ -- invalidFormat="Invalid format",
+ -- invalidArguments="Invalid arguments",
+ -- tooFrequent="Too frequent",
+ -- notAvailable="Not available",
+ -- noPermission="No permission",
+ -- roomNotFound="Room not found",
+
+ -- Controllers
+ WebSocket={
+ -- invalidConnection="Invalid connection",
+ -- invalidAction="Invalid action",
+ -- playerNotFound="Player not found",
+ -- connectionFailed="Connection failed",
+ },
+ -- Filters
+ CheckPermission={
+ -- playerNotFound="Player not found",
+ },
+ -- Plugins
+ ConnectionManager={
+ -- playerInvalid="Player invalid",
+ -- playerNotFound="Player not found",
+ -- connectionReplaced="Connection replaced",
+ },
+ NoticeManager={
+ -- noticeNotFound="Notice not found",
+ },
+ PlayerManager={
+ -- invalidCode="Invalid code",
+ -- invalidEmail="Invalid email",
+ -- playerNotFound="Player not found",
+ -- invalidEmailPass="Invalid email or password",
+ -- emailExists="Email exists",
+ -- emailSendError="Email send error",
+ },
+ -- Strategies
+ PlayerRole={
+ -- invalidRole="Invalid role",
+ -- invalidTarget="Invalid target",
+ },
+ PlayerType={
+ -- invalidType="Invalid type",
+ -- roomFull="Room full",
+ },
+ RoomJoin={
+ -- wrongPassword="Wrong password",
+ },
+ },
+ -- tooFrequent="Request too frequently",
+ -- roomPasswordChanged="Room password changed",
oldVersion="Versão $1 esta disponível agora!",
-- versionNotMatch="Version do not match!",
-- needUpdate="Newer version required!",
-- notFinished="Coming soon!",
- jsonError="Json error",
-
noUsername="Insira seu nome de usuário",
wrongEmail="Endereço de email errado",
+ -- wrongCode="Invalid verification code",
noPassword="Insira sua senha ",
diffPassword="Senhas não combinam",
- -- registerRequestSent="Registration request sent",
- registerSuccessed="Registrado com sucesso!",
- loginSuccessed="Logado com sucesso!",
- accessSuccessed="Autorizado com sucesso!",
-
- -- wsConnecting="Websocket Connecting",
- wsFailed="WebSocket falha na conexão",
- wsClose="WebSocket closed:",
+ -- checkEmail="Registration request sent",
+
+ wsFailed="WebSocket falha na conexão: $1",
+ wsClose="WebSocket closed: $1",
-- netTimeout="Network connection timeout",
+ -- serverDown="Oops! Server is down",
+ -- requestFailed="Request failed",
- -- onlinePlayerCount="Online",
+ -- onlinePlayerCount="Online: $1",
-- createRoomSuccessed="Room successfully created!",
+ -- playerKicked="$1 removed $2 from room",
+ -- becomeHost="$1 become host",
-- started="Playing",
- joinRoom="Entrou a sala.",
- leaveRoom="Saiu da sala.",
+ joinRoom="$1 Entrou a sala.",
+ leaveRoom="$1 Saiu da sala.",
+ -- roomRemoved="Room was removed",
-- ready="READY",
- -- connStream="CONNECTING",
- -- waitStream="WAITING",
-- spectating="Spectating",
- chatRemain="Online",
- chatStart="------Começo do log------",
- chatHistory="------Novas mensagens abaixo------",
+
+
-- keySettingInstruction="Press to bind key\nescape: cancel\nbackspace: delete",
-- customBGhelp="Drop image file here to apply custom background",
@@ -194,8 +248,8 @@ return{
"certifique-se de pegar o jogo de fontes oficiais;",
"binários obtidos em outros lugares pode conter malware.",
"O autor não é responsável por qualquer binários modificados",
- FNNS and"/"or"O jogo é gratis, mas doações são apreciadas.",
- -- FNNS and"/"or"Check Zictionary for more",
+ FNNS and "/" or "O jogo é gratis, mas doações são apreciadas.",
+ -- FNNS and "/" or "Check Zictionary for more",
},
staff={
"ORIGINALMENTE POR MrZ",
@@ -238,6 +292,12 @@ return{
"(旋律星萤)",
"(T0722)",
"",
+ "Ilustrações",
+ "Miya",
+ "Mono",
+ "Xiaoya",
+ "葉枭",
+ "",
"Desenhos Musicais",
"MrZ",
"柒栎流星",
@@ -263,7 +323,9 @@ return{
"ScF",
"C₂₉H₂₅N₃O₅",
"NOT_A_ROBOT",
- "sakurw",
+ "XMiao",
+ "sakurw, Airun, 幽灵3383",
+ "Shard Nguyễn, Squishy, TVN community",
"",
"Performance",
"Electric283",
@@ -302,13 +364,13 @@ return{
Cold_Clear [MinusKelvin]
json.lua [rxi]
profile.lua [itraykov]
- simple-love-lights [dylhunn]
+ sha2 [Egor Skriptunoff]
]],
support="Support author",
WidgetText={
main={
offline="Solo",
- -- qplay="Last Play",
+ -- qplay="Last Play: ",
online="Multi",
custom="Custom",
setting="Config.",
@@ -342,6 +404,7 @@ return{
-- league="Tech League",
ffa="FFA",
rooms="Salas",
+ -- resetPW="Reset password",
-- logout="Log out",
},
net_league={
@@ -418,7 +481,6 @@ return{
-- sysCursor="Use system cursor",
autoPause="Pausar quando foco for perco",
-- autoSave="Auto save new-best",
- -- autoLogin="Auto Login on Start",
-- simpMode="Simple mode",
},
setting_video={
@@ -446,7 +508,6 @@ return{
atkFX="Nível FX Atk.",
frame="Render Frame Rate(%)",
- -- FTlock="Frame-Time Lock",
text="Texto de ação",
score="Pop-up de pontos",
@@ -460,6 +521,8 @@ return{
power="Informação bateria",
-- clean="Fast Draw",
fullscreen="Tela cheia",
+ -- portrait="Portrait",
+ -- msaa="MSAA level",
-- bg_on="Normal B.G.",
-- bg_off="No B.G.",
@@ -672,22 +735,19 @@ return{
-- label="label",
},
login={
- title="Log in",
- register="Registrar",
- email="Endereço De Email",
- password="Senha",
- -- keepPW="Remember me",
- login="Log in",
- },
- register={
- title="Registrar",
- login="Log in",
- username="Nome De Usuário",
- email="Endereço De Email",
+ -- title="Sign In",
+ -- ticket="Auth Ticket",
+ -- authorize="Go Authorizing",
+ -- paste="Paste Ticket",
+ -- submit="Submit",
+ },
+ reset_password={
+ -- title="Reset Password",
+ -- send="Send code",
+ -- code="Verification Code",
password="Senha",
password2="Entre Senha Novamente",
- register="Registrar",
- -- registering="Waiting for response...",
+ -- setPW="Set Password",
},
account={
title="Conta",
@@ -755,6 +815,7 @@ return{
['dig_40l']= {"Cave", "40L", "Cave 40 linhas de lixo."},
['dig_100l']= {"Cave", "100L", "Cave 100 linhas de lixo."},
['dig_400l']= {"Cave", "400L", "Cave 400 linhas de lixo."},
+ --['dig_quad_10l']= {"Dig", "TECHRASH 10L", "Dig 10 garbage lines using only techrash!"},
['drought_n']= {"Drought", "100L", "Sem peça I !"},
['drought_l']= {"Drought+", "100L", "WTF"},
-- ['stack_e']= {"Stack", "FÁCIL", "Pack them!"},
@@ -764,7 +825,7 @@ return{
['solo_e']= {"Batalha", "FÁCIL", "Derrote a inteligência!"},
['solo_n']= {"Batalha", "NORMAL", "Derrote a inteligência!"},
['solo_h']= {"Batalha", "DIFÍCIL", "Derrote a inteligência!"},
- ['solo_l']= {"Batalha", "LUNATICO", "Defeat the AI!"},
+ ['solo_l']= {"Batalha", "LUNÁTICO", "Defeat the AI!"},
['solo_u']= {"Batalha", "ULTIMATE", "Defeat the AI!"},
['techmino49_e']= {"Tech 49", "FÁCIL", "Batalha de 49 jogadores.\nO último vence"},
['techmino49_h']= {"Tech 49", "DIFÍCIL", "Batalha de 49 jogadores.\nO último vence."},
@@ -786,9 +847,9 @@ return{
-- ['strategy_e']= {"Strategy", "EASY", "Fast 20G decision"},
-- ['strategy_h']= {"Strategy", "HARD", "Fast 20G decision"},
-- ['strategy_u']= {"Strategy", "ULTIMATE", "Fast 20G decision"},
- -- ['strategy_e_plus']={"Strategi", "MUDAH+", "Keputusan 20G cepat"},
- -- ['strategy_h_plus']={"Strategi", "SULIT+", "Keputusan 20G cepat"},
- -- ['strategy_u_plus']={"Strategi", "TERAKHIR+", "Keputusan 20G cepat"},
+ -- ['strategy_e_plus']={"Strategy", "EASY+", "Holdless strategy"},
+ -- ['strategy_h_plus']={"Strategy", "HARD+", "Holdless strategy"},
+ -- ['strategy_u_plus']={"Strategy", "ULTIMATE+", "Holdless strategy"},
['blind_e']= {"Cego", "METADE", "Para novatos."},
['blind_n']= {"Cego", "TUDO", "Para intermediários."},
['blind_h']= {"Cego", "DE REPENTE", "Para experientes."},
@@ -796,7 +857,8 @@ return{
['blind_u']= {"Cego", "?", "Are you ready?"},
['blind_wtf']= {"Cego", "WTF", "You're not ready."},
['classic_e']= {"Classic", "EASY", "Modo clássico rápido."},
- ['classic_h']= {"Classic", "DIFÍCIL", "Modo clássico rápido."},
+ ['classic_h']= {"Classic", "DIFÍCIL", "Modo clássico rápido."},
+ ['classic_l']= {"Classic", "LUNÁTICO", "Modo clássico rápido."},
['classic_u']= {"Classic", "ULTIMATE", "Modo clássico rápido."},
['survivor_e']= {"Sobrevivente", "FACIL", "Por quanto sobrevive?"},
['survivor_n']= {"Sobrevivente", "NORMAL", "Por quanto sobrevive?"},
@@ -809,7 +871,6 @@ return{
['defender_l']= {"Defensor", "LUNÁTICO", "Prática de defensiva!"},
['dig_h']= {"Cavador", "DIFÍCIL", "Prática de cavar!"},
['dig_u']= {"Cavador", "ULTIMATE", "Prática de cavar!"},
- -- ['clearRush']= {"Clear Rush", "NORMAL", "All-spin tutorial!\n[Under construction]"},
['c4wtrain_n']= {"Treinamento C4W", "NORMAL", "Combos infinitos."},
['c4wtrain_l']= {"Treinamento C4W", "LUNÁTICO", "Combos infinitos."},
['pctrain_n']= {"Treinamento PC", "NORMAL", "Modo simples de limpeza perfeita."},
@@ -859,7 +920,7 @@ return{
"1next 1hold!",
"1next 6hold!",
"Na verdade 20G é uma regra de jogo nova.",
- "40-lines Sprint WR: 14.915s by Reset_",
+ "40-lines Sprint WR: 14.708s by hiryu",
"6next 1hold!",
"6next 6hold?!",
"ALL SPIN!",
@@ -882,7 +943,7 @@ return{
"Tem alguma sugestão? Posta elas em nosso Discord!",
"Fones recomendados para uma melhor experiência.",
"Olá mundo!",
- "if a==true",
+ " if a==true",
"Aumente sua frame rate para uma experiência melhor.",
"O sistema de [ação] inicial pode salvar sua vida.",
"Será B2B2B2B possível?",
@@ -917,7 +978,7 @@ return{
"Que tal 20 PCs?",
"Que tal 23 PCs em 100 linhas?",
"Que tal 26 TSDs?",
- "while(false)",
+ " while (false)",
"Você e um Grand Master!",
"Pode conectar um teclado ao seu celular!",
"Você pode fazer spins com 28 de 29 minoes!",
@@ -959,5 +1020,6 @@ return{
{C.Y,"暫定段位:MO"},
{C.Y,"暫定段位:MV"},
{C.Y,"O-spin Triple!"},
- }
+ },
+ -- pumpkin="I'm a pumpkin",
}
diff --git a/parts/language/lang_symbol.lua b/parts/language/lang_symbol.lua
index a85c8080e..b9b33dcc0 100644
--- a/parts/language/lang_symbol.lua
+++ b/parts/language/lang_symbol.lua
@@ -1,6 +1,5 @@
-return{
+return {
fallback='en',
-
loadText={
loadSFX="#!#",
loadSample="#~#",
@@ -22,7 +21,8 @@ return{
atkModeName={"?","( )","!","←→"},
royale_remain="$1 ~",
cmb={nil,"!","!!","!!!","!!!!","!!!!!","!!!!!!","!!!!!!!","!!!!!!!!","!!!!!!!!!","!!!!!!!!!!","!!!!!!!!!!!","!!!!!!!!!!!!","!!!!!!!!!!!!!","!!!!!!!!!!!!!!","!!!!!!!!!!!!!!!","!!!!!!!!!!!!!!!!","!!!!!!!!!!!!!!!!!","!!!!!!!!!!!!!!!!!!","!!!!!!!!!!!!!!!!!!!","!!!!!!!!!!!!!!!!!!!!",},
- spin=" ~",
+ spinNC=" ~",
+ spin=" ~ ",
clear={"1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","20+"},
cleared="",
mini="v",b2b="^ ",b3b="^^ ",
@@ -135,7 +135,7 @@ return{
WidgetText={
main={
offline="!",
- qplay="(!)",
+ qplay="(!): ",
online="!!!",
custom="_?!",
setting="_?_",
@@ -165,6 +165,7 @@ return{
league="TL",
ffa="FFA",
rooms="< >",
+ resetPW="R ***",
logout="@_@x",
},
net_league={
@@ -234,14 +235,13 @@ return{
ctrl="=?=",
key="=?",
touch="_?",
- showVK="--?",
+ showVK="-- ?",
reTime="3-2-1",
RS="''?",
menuPos="←M→?",
sysCursor="?→*",
autoPause="A||",
autoSave="!!!>%",
- autoLogin="#Log in#",
simpMode=".",
},
setting_video={
@@ -258,7 +258,7 @@ return{
ghost="__↓__",
center="+",
grid="#",
- lineNum="--No.",
+ lineNum="-- No.",
lockFX="↓_~",
dropFX="↓~",
@@ -269,7 +269,6 @@ return{
atkFX="→→~",
frame="|=|%",
- FTlock="||=|→→|=||",
text="ABC",
score="+123",
@@ -283,6 +282,8 @@ return{
power="+.",
clean="[]→→O",
fullscreen="|←→|",
+ portrait="↑▉↓",
+ msaa="/ _",
bg_on="__?__",
bg_off="__.__",
@@ -485,22 +486,19 @@ return{
label="...",
},
login={
- title="Log in",
- register="Sign up",
- email="@",
- password="*",
- -- keepPW="I",
- login="Log in",
- },
- register={
- title="Sign up",
- login="Log in",
- username="#",
- email="@",
+ title="Sign In",
+ ticket="***",
+ authorize="**?",
+ paste="_*",
+ submit="",
+ },
+ reset_password={
+ title="R ***",
+ send="→",
+ code="←",
password="*",
password2="*",
- register="Sign up",
- registering="......",
+ setPW="##",
},
account={
title="@_@",
@@ -509,7 +507,7 @@ return{
color="~~~",
invis="???",
slide="~_~",
- pathVis="--==>",
+ pathVis="-- ==>",
revKB="Reverse",
},
app_schulteG={
@@ -542,7 +540,7 @@ return{
getTip=function()
local L="!@#$%^&*()-=_+[]{}\\|;:\'\",<.>/?"
local s=""
- for _=1,math.random(16,26)do
+ for _=1,math.random(16,26) do
local p=math.random(#L)
s=s..L:sub(p,p)
end
diff --git a/parts/language/lang_vi.lua b/parts/language/lang_vi.lua
new file mode 100644
index 000000000..2732b3b1d
--- /dev/null
+++ b/parts/language/lang_vi.lua
@@ -0,0 +1,1302 @@
+local C=COLOR
+local all_month={"T01","T02","T03","T04","T05","T06","T07","T08","T09","T10","T11","T12"}
+
+-- There are some strings, due to game's history, temproary be commented just in case
+-- If it is not used anymore, it will be removed, in one day…
+
+return {
+ fallback='en',
+ loadText={
+ loadSFX="Đang tải các hiệu ứng âm thanh",
+ loadSample="Đang tải các mẫu nhạc cụ",
+ loadVoice="Đang tải các gói voice",
+ loadFont="Đang tải phông chữ",
+ loadModeIcon="Đang tải các biểu tượng",
+ loadMode="Đang tải các chế độ chơi",
+ loadOther="Đang tải các tài nguyên khác",
+ finish="Nhấn một phím bất kỳ để bắt đầu!",
+ },
+ sureQuit="Nhấn thêm một lần nữa để thoát",
+ sureReset="Nhấn thêm một lần nữa để đặt lại",
+ sureDelete="Nhấn thêm một lần nữa để xoá",
+ newDay="Một ngày mới, một khởi đầu mới!",
+ playedLong="Bạn chơi cũng lâu rồi. Hãy dành chút thời gian nghỉ ngơi đi",
+ playedTooMuch="Có lẽ bạn chơi quá nhiều rồi! Đặt máy xuống và nghỉ ngơi đi bạn!",
+ settingWarn="CẨN THẬN - Bạn vừa sửa một cài đặt quan trọng của game!",
+ settingWarn2="Cài đặt này sẽ có hiệu lực sau khi khởi động lại",
+
+ atkModeName={"Ngẫu nhiên","Huy hiệu","K.O.","Phản công"},
+ royale_remain="Còn $1 người chơi",
+ powerUp={[0]="+000%","+025%","+050%","+075%","+100%"},
+ cmb={nil,"1 Combo","2 Combo","3 Combo","4 Combo","5 Combo","6 Combo","7 Combo","8 Combo","9 Combo","10 Combo!","11 Combo!","12 Combo!","13 Combo!","14 Combo!!","15 Combo!!","16 Combo!!","17 Combo!!!","18 Combo!!!","19 Combo!!!","MEGACMB"},
+ spin="-spin ",
+ spinNC="-spin",
+ clear={"Single","Double","Triple","Techrash","Pentacrash","Hexacrash","Heptacrash","Octacrash","Nonacrash","Decacrash","Undecacrash","Dodecacrash","Tridecacrash","Tetradecacrash","Pentadecacrash","Hexadecacrash","Heptadecacrash","Octadecacrash","Nonadecacrash","Ultracrash","Impossicrash"},
+ cleared="$1 hàng",
+ mini="Mini",b2b="B2B ",b3b="B2B2B ",
+ PC="Perfect Clear",HPC="Hemi-Perfect Clear",
+ replaying="[Đang phát lại]",
+ tasUsing="[TAS]",
+
+ stage="Chặng $1 hoàn thành!",
+ great="Tốt lắm!",
+ awesome="Tuyệt vời!",
+ almost="Gần được rồi!",
+ continue="Cố gắng lên!",
+ maxspeed="TỐC ĐỘ TỐI ĐA!",
+ speedup="Tăng tốc nào!",
+ missionFailed="Nhiệm vụ thất bại",
+
+ speedLV="Tốc độ rơi",
+ piece="Gạch",line="Hàng",atk="Attack",eff="Efficiency",
+ rpm="RPM",tsd="TSD",
+ grade="Grade",techrash="Techrash",
+ wave="Wave",nextWave="Next",
+ combo="Combo",maxcmb="Max Combo",
+ pc="Perfect Clear",ko="KOs",
+
+ win="Thắng!",
+ lose="Thua",
+
+ finish="Hoàn thành",
+ gamewin="Bạn đã thắng",
+ gameover="Kết thúc",
+
+ pause="Tạm dừng",
+ pauseCount="Số lần tạm dừng",
+ finesse_ap="All Perfect",
+ finesse_fc="Full Combo",
+
+ page="Trang ",
+
+ cc_fixed="CC không tương thích với trình xáo gạch cố định",
+ cc_swap="CC không tương thích với chế độ Hold là Chuyển",
+ ai_prebag="AI không tương thích với trình xáo gạch chứa gạch không phải là tetromino.",
+ ai_mission="AI không tương thích với nhiệm vụ tuỳ chọn.",
+ switchSpawnSFX="Vui lòng bật Spawn SFX để chơi!",
+ needRestart="Khởi động lại để áp dụng mọi thay đổi.",
+
+ loadError_errorMode="Tải '$1' thất bại: không có chế độ tải '$2'",
+ loadError_read="Tải tệp '$1' thất bại: đọc thất bại",
+ loadError_noFile="Tải tệp '$1' thất bại: không có tệp",
+ loadError_other="Tải tệp '$1' thất bại: $2",
+ loadError_unknown="Tải tệp '$1' thất bại: không rõ lý do",
+
+ saveError_duplicate="Lưu tệp '$1' thất bại: trùng tên tệp",
+ saveError_encode="Lưu tệp '$1' thất bại: mã hoá thất bại",
+ saveError_other="Lưu tệp '$1' thất bại: $2",
+ saveError_unknown="Lưu tệp '$1' thất bại: không rõ lý do",
+
+ copyDone="Đã sao chép!",
+ saveDone="Đã lưu dữ liệu",
+ exportSuccess="Đã xuất thành công",
+ importSuccess="Đã nhập thành công",
+ dataCorrupted="Dữ liệu bị hỏng",
+ pasteWrongPlace="Bạn đã dán ở nhầm nơi rồi",
+ noFile="Thiếu tệp",
+
+ nowPlaying="Đang phát:",
+
+ VKTchW="Trọng số chạm",
+ VKOrgW="Trọng số nút",
+ VKCurW="Trọng số hiện tại",
+
+ noScore="Không có điểm",
+ modeLocked="Bị khoá",
+ unlockHint="Đạt hạng B trở lên trong các chế độ trước đó để mở khóa",
+ highScore="Điểm cao",
+ newRecord="Thành tích mới!",
+
+ replayBroken="Không thể tải bản phát lại",
+
+ dictNote="==Đã sao chép từ TetroDictionary==",
+
+
+
+ -- Server's warn/error messages
+ Techrater={
+ internalError="Lỗi nội bộ",
+ databaseError="Lỗi cơ sở dữ liệu",
+ invalidFormat="Định dạng không hợp lệ",
+ invalidArguments="Đối số không hợp lệ",
+ tooFrequent="Quá thường xuyên",
+ notAvailable="Không khả dụng",
+ noPermission="Không có quyền",
+ roomNotFound="Không tìm thấy phòng",
+
+ -- Controllers
+ WebSocket={
+ invalidConnection="Kết nối không hợp lệ",
+ invalidAction="Hành động không hợp lệ",
+ playerNotFound="Không tìm thấy người chơi",
+ connectionFailed="Kết nối thất bại",
+ },
+ -- Filters
+ CheckPermission={
+ playerNotFound="Không tìm thấy người chơi",
+ },
+ -- Plugins
+ ConnectionManager={
+ playerInvalid="Người chơi không hợp lệ",
+ playerNotFound="Không tìm thấy người chơi",
+ connectionReplaced="Đã thay đổi kết nối",
+ },
+ NoticeManager={
+ noticeNotFound="Không có thông báo",
+ },
+ PlayerManager={
+ -- invalidEmail="Email không hợp lệ",
+ -- playerNotFound="Không tìm thấy người chơi",
+ -- invalidEmailPass="Email hoặc người chơi không hợp lệ",
+ -- emailExists="Email đã tồn tại",
+ -- emailSendError="Lỗi gửi email",
+ invalidCode="Mã không hợp lệ",
+ invalidAccessToken="Mã xác thực không hợp lệ",
+ },
+ -- Strategies
+ PlayerRole={
+ invalidRole="Vị trí không hợp lệ",
+ invalidTarget="Mục tiêu không hợp lệ",
+ },
+ PlayerType={
+ invalidType="Invalid type",
+ roomFull="Phòng đã đầy",
+ },
+ RoomJoin={
+ wrongPassword="Sai mật khẩu",
+ },
+ },
+
+ tooFrequent="Yêu cầu vào quá nhiều",
+ roomPasswordChanged="Mật khẩu của phòng đã thay đổi",
+ oldVersion="Phiên bản $1 hiện đã ra mắt",
+ versionNotMatch="Phiên bản không khớp",
+ notFinished="Sắp ra mắt!",
+
+ -- Deprecated
+ -- noUsername="Vui lòng nhập email của bạn",
+ -- wrongEmail="Địa chỉ email không hợp lệ",
+ -- wrongCode="Mã xác minh không hợp lệ",
+ -- noPassword="Vui lòng nhập mật khẩu của bạn",
+ -- diffPassword="Mật khẩu không đúng",
+ -- checkEmail="Yêu cầu đăng ký đã được gửi.",
+
+ wsFailed="Kết nối WebSocket đã thất bại: $1",
+ wsClose="WebSocket đã đóng: $1",
+ netTimeout="Kết nối đã quá hạn",
+ serverDown="Ối! Server sập! Hãy quay lại sau",
+ requestFailed="Yêu cầu thất bại",
+
+ onlinePlayerCount="Trực tuyến: $1",
+ createRoomSuccessed="Tạo phòng thành công",
+ playerKicked="$1 đã đá $2 khỏi phòng",
+ becomeHost="$1 giờ là chủ phòng",
+ started="Đang chơi",
+ joinRoom="$1 vừa vào phòng.",
+ leaveRoom="$1 vừa rời phòng.",
+ roomRemoved="Phòng đã bị xoá",
+ ready="Sẵn sàng",
+ spectating="Đang theo dõi",
+
+
+
+ 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",
+ 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.",
+
+ modInstruction="Hãy chọn mod bạn muốn.\nMod cho phép bạn có thể tùy biến game, nhưng cũng có thể làm game sập.\nĐiểm sẽ không được lưu lại khi dùng mod.",
+ modInfo={
+ next="NEXT\nGhi đè số gạch hiển thị ở cột NEXT",
+ hold="HOLD\nGhi đè số lượng gạch được giữ ở cột HOLD",
+ hideNext="Hidden NEXT\nẨn số lượng gạch ở cột NEXT (Tính từ ô đầu tiên)",
+ infHold="InfiniHold\nCho phép bạn HOLD vô số lần",
+ hideBlock="Hide Current Piece\nGạch đang rơi trong bảng sẽ bị tàng hình",
+ hideGhost="No Ghost\nBóng gạch sẽ bị tắt",
+ hidden="Hide Locked Pieces\nGạch sẽ bị ẩn sau một khoảng thời gian",
+ hideBoard="Hide Board\nChe một phần của bảng hay che nguyên bảng",
+ flipBoard="Flip Board\nXoay bảng hay lật bảng",
+ dropDelay="Gravity\nĐiều chỉnh tốc độ rơi của gạch",
+ lockDelay="Lock Delay\nGhi đè thời gian chờ khoá của gạch",
+ waitDelay="Spawn Delay\nGhi đè thời gian gạch xuất hiện",
+ fallDelay="Line Clear Delay\nGhi đè thời gian xoá hàng",
+ life="Life\nThay đổi số mạng",
+ forceB2B="B2B Only\nKết thúc trò chơi khi cột B2B giảm xuống dưới vạch ban đầu",
+ forceFinesse="Finesse Only\nKết thúc trò chơi khi có lỗi di chuyển",
+ tele="Teleport\nDAS = 0, ARR = 0",
+ noRotation="No Rotation\nKhông thể xoay gạch",
+ noMove="No Movement\nKhông thể di chuyển trái phải",
+ customSeq="Randomizer\nGhi đè trình xáo gạch",
+ pushSpeed="Garbage Speed\nGhi đề tốc độ xuất hiện của hàng rác",
+ boneBlock="[ ]\nChơi với skin [ ]",
+ },
+ pauseStat={
+ "Thời gian chơi:",
+ "Phím/Xoay/Giữ:",
+ "Số gạch:",
+ "Hàng/Đào:",
+ "Gửi/Gửi khi đào:",
+ "Nhận:",
+ "Xóa:",
+ "Spin:",
+ "B2B/B3B/PC/HPC:",
+ "Lỗi di chuyển:",
+ },
+ radar={"DEF","OFF","ATK","SEND","SPD","DIG"},
+ radarData={"D’PM","ADPM","APM","SPM","L’PM","DPM"},
+ stat={
+ "Số lần bật trò chơi:",
+ "Số ván đã chơi:",
+ "Thời gian chơi:",
+ "Phím/Xoay/Giữ:",
+ "Gạch/Hàng/Gửi:",
+ "Nhận/Phản/Đẩy:",
+ "Đào/Gửi khi đào:",
+ "H.quả/H.quả khi Đào:",
+ "B2B/B3B:",
+ "PC/HPC:",
+ "Lỗi di chuyển/Tỉ lệ ko mắc:",
+ },
+ aboutTexts={
+ "Đây chỉ là một trò chơi xếp gạch *thông thường*. Không, thật đấy, chỉ có vậy thôi",
+ "Lấy cảm hứng từ C2/IO/JS/WWC/KOS v.v.",
+ "",
+ "Chạy bằng LÖVE",
+ "Chúng tôi đánh giá cao mọi đề xuất và báo cáo lỗi do các bạn gửi đến",
+ "Hãy đảm bảo trò chơi được tải về từ nguồn chính thức",
+ "vì các nguồn khác có thể không an toàn.",
+ "Tác giả KHÔNG CHỊU TRÁCH NHIỆM với bất kỳ bản sửa đổi nào.",
+ FNNS and "" or "Trò chơi này hoàn toàn miễn phí! Nếu các bạn thích nó, các bạn có thể ủng hộ chúng tôi!",
+ FNNS and "" or "Kiểm tra Zictionary để có thêm thông tin chi tiết",
+ },
+ staff={
+ "ĐƯỢC SÁNG TÁC BỞI MrZ",
+ "E-mail: 1046101471@qq.com",
+ "",
+ "Được lập trình, Phát triển và Thiết kế bởi",
+ "MrZ",
+ "",
+ "Âm nhạc được sản xuất với",
+ "Beepbox",
+ "FL Studio",
+ "FL Mobile",
+ "Logic Pro X",
+ "",
+ "[ĐƯỢC XÂY DỰNG BẰNG LÖVE]",
+ "",
+ "Lập trình",
+ "MrZ",
+ "ParticleG",
+ "Gompyn",
+ "Trebor",
+ "(scdhh)",
+ "(FinnTenzor)",
+ "(NOT_A_ROBOT)",
+ "(user670)",
+ "",
+ "GitHub CI, Đóng gói & BackEnd",
+ "ParticleG",
+ "Trebor",
+ "LawrenceLiu",
+ "Gompyn",
+ "flaribbit",
+ "scdhh",
+ "",
+ "Thiết kế đồ hoạ, UI & UX",
+ "MrZ",
+ "Gnyar",
+ "C₂₉H₂₅N₃O₅",
+ "ScF",
+ "(旋律星萤)",
+ "(T0722)",
+ "",
+ "Minh hoạ",
+ "Miya",
+ "Mono",
+ "Xiaoya",
+ "葉枭",
+ "",
+ "Thiết kế âm nhạc",
+ "MrZ",
+ "柒栎流星",
+ "ERM",
+ "Trebor",
+ "C₂₉H₂₅N₃O₅",
+ "(T0722)",
+ "(Aether)",
+ "(Hailey)",
+ "",
+ "Hiệu ứng âm thanh & Voice packs",
+ "Miya",
+ "Xiaoya",
+ "Mono",
+ "MrZ",
+ "Trebor",
+ "",
+ "Dịch thuật",
+ "User670",
+ "MattMayuga",
+ "Mizu",
+ "Mr.Faq",
+ "ScF",
+ "C₂₉H₂₅N₃O₅",
+ "NOT_A_ROBOT",
+ "XMiao",
+ "sakurw, Airun, 幽灵3383",
+ "Shard Nguyễn, Squishy, cộng đồng TVN",
+ "",
+ "Performances",
+ "Electric283",
+ "Hebomai",
+ "",
+ "Xin gửi lời cảm ơn chân thành tới",
+ "Flyz",
+ "Big_True",
+ "NOT_A_ROBOT",
+ "思竣",
+ "yuhao7370",
+ "Farter",
+ "Teatube",
+ "蕴空之灵",
+ "T9972",
+ "No-Usernam8",
+ "andrew4043",
+ "smdbs-smdbs",
+ "paoho",
+ "Allustrate",
+ "Haoran SUN",
+ "Tianling Lyu",
+ "huaji2369",
+ "Lexitik",
+ "Tourahi Anime",
+ "[cùng với các thành viên thử nghiệm khác]",
+ "…và BẠN!",
+ },
+ used=[[
+ Các công cụ đã sử dụng:
+ BeepBox
+ GoldWave
+ GFIE
+ FL Mobile
+ Các thư viện đã sử dụng:
+ Cold_Clear [MinusKelvin]
+ json.lua [rxi]
+ profile.lua [itraykov]
+ sha2 [Egor Skriptunoff]
+ ]],
+ support="Hỗ trợ người làm game",
+ dict={
+ sizeChanged="Đã đổi cỡ phông: $1",
+ sizeReset="Đã đặt lại cỡ phông!",
+ helpText=
+[[
+HƯỚNG DẪN ĐIỀU HƯỚNG TRONG TETRODICTIONARY
+
+A. Chuột và màn hình cảm ứng
+ - Giữ và kéo lên/xuống hoặc lăn chuột để cuộn văn bản
+
+ - Nhấn/chạm [$14] để sao chép nội dung của mục đang xem
+ - Nhấn/chạm [$15] để mở link của mục đang xem (nếu có)
+
+B. Bàn phím: Nhấn…
+ - [F1] để hiển thị Trợ giúp
+ - [$1] hoặc [$2] để cuộn qua văn bản
+ - [$3] để mở mục trước đó và [$4] để mở mục tiếp theo, giữ [Ctrl] để lướt nhanh hơn
+
+ - [-] để giảm cỡ chữ, [+] để tăng cỡ chữ
+ - [0] để khôi phục về cỡ chữ mặc định
+
+ - [Ctrl + C] để sao chép văn bản
+ - [$16] (phím Menu ngữ cảnh/phím Ứng dụng) để mở link (nếu có)
+
+C. Tay cầm chơi game (Gamepad):
+ - Nhấn $10 để hiển thị trợ giúp
+ - Nhấn $5 hoặc $6 để cuộn văn bản, giữ $11 để cuộn nhanh hơn
+ - Nhấn $7 để mở mục trước và $8 để mở mục tiếp theo
+ - Giữ $11 và nhấn $6 để giảm cỡ chữ hoặc $5 để tăng lên
+]]
+ -- 1-4: Up, Down, Left, Right
+ -- 5-8: Up, Down, Left, Right but D-Pad
+ -- 9-12: X, Y, A, B
+ -- 13-16: Help, Copy, Open, MENU
+ },
+ WidgetText={
+ main={
+ offline="Chơi đơn",
+ qplay="Chơi nhanh: ",
+ online="Nhiều người chơi",
+ custom="Chế độ Tự do",
+ setting="Cài đặt",
+ stat="Thống kê",
+ dict="Zictionary",
+ replays="Phòng phát lại",
+ },
+ main_simple={
+ sprint="Sprint",
+ marathon="Marathon",
+ },
+ mode={
+ mod="Mods (F1)",
+ start="Bắt đầu!",
+ },
+ mod={
+ title="Mods",
+ reset="Đặt lại (tab)",
+ unranked="Không tính điểm",
+ },
+ pause={
+ setting="Cài đặt (S)",
+ replay="Phát lại (P)",
+ save="Lưu (O)",
+ resume="Tiếp tục (esc)",
+ restart="Thử lại (R)",
+ quit="Thoát (Q)",
+ tas="TAS (T)",
+ },
+ net_menu={
+ league="Tech League",
+ ffa="FFA",
+ 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_rooms={
+ password="Mật khẩu",
+ refreshing="Đang làm mới…",
+ noRoom="Hiện không có phòng nào",
+ refresh="Làm mới",
+ new="Phòng mới",
+ join="Vào phòng",
+ },
+ net_newRoom={
+ title="Cấu hình phòng",
+ roomName="Tên phòng (Mặc định: “[username]'s room”)",
+ password="Mật khẩu",
+ description="Mô tả phòng",
+
+ life="Mạng",
+ pushSpeed="Tốc độ đẩy rác vào",
+ garbageSpeed="Tốc độ gửi rác",
+ visible="Chế độ hiện gạch",
+ freshLimit="Lock Reset tối đa",
+
+ fieldH="Độ cao bảng",
+ bufferLimit="Giới hạn nhận rác",
+ heightLimit="Giới hạn độ cao",
+
+ drop="Drop Delay",
+ lock="Lock Delay",
+ wait="Entry Delay",
+ fall="Line Delay",
+ hang="Death Delay",
+ hurry="ARE Interruption",
+
+ capacity="Giới hạn số người",
+ create="Tạo phòng",
+
+ ospin="O-spin",
+ fineKill="100% Finesse",
+ b2bKill="Không phá B2B",
+ lockout="Thua khi Lock Out",
+ easyFresh="Lock Reset Thường",
+ deepDrop="Thả rơi sâu",
+ bone="Dùng skin []",
+
+ eventSet="Rule Set",
+
+ holdMode="Chế độ Hold",
+ nextCount="Next",
+ holdCount="Hold",
+ infHold="Hold vô tận",
+ phyHold="Hold tại chỗ",
+ },
+ net_game={
+ ready="Sẵn sàng",
+ spectate="Theo dõi",
+ cancel="Huỷ",
+ },
+ setting_game={
+ title="Cài đặt trò chơi",
+ graphic="←Đồ hoạ",
+ sound="Âm thanh→",
+ style="Trang trí",
+
+ -- ctrl="Cài đặt điều khiển",
+ -- key="Cài đặt bố cục phím",
+ -- touch="Cài đặt cảm ứng",
+ ctrl="Điều chỉnh thg. số", -- ctrl="Điều chỉnh độ nhạy"
+ key="Sửa bố cục bàn phím",
+ touch="Sửa bố cục cảm ứng",
+ showVK="Bật điều khiển bằng cảm ứng", -- Pull from Galaxy
+
+ reTime="Đếm ngược bắt đầu",
+ RS="Hệ thống xoay gạch",
+ menuPos="Vị trí nút Menu",
+ sysCursor="Sử dụng con trỏ chuột của hệ thống",
+ autoPause="Tạm dừng khi ở ngoài game",
+ autoSave="Tự động lưu thành tích mới",
+ simpMode="Chế độ Đơn giản",
+ },
+ setting_video={
+ title="Cài đặt đồ hoạ",
+ sound="←Âm thanh",
+ game="Trò chơi→",
+
+ block="Hiện gạch đang rơi",
+ smooth="Rơi mượt",
+ upEdge="Gạch 3D",
+ bagLine="Vạch tách Túi gạch",
+
+ ghostType="Loại bóng gạch",
+ ghost="Độ bóng",
+ center="Tâm xoay",
+ grid="Lưới",
+ lineNum="# hàng",
+
+ lockFX="H.ứng Khóa gạch",
+ dropFX="H.ứng Thả nhẹ",
+ moveFX="H.ứng Di chuyển",
+ clearFX="H.ứng Xóa hàng",
+ splashFX="H.ứng Gạch “rụng”",
+ shakeFX="Độ nảy bảng",
+ atkFX="H.ứng Tấn công",
+
+ frame="Tần suất cập nhật khung hình (%)",
+
+ text="Hiện loại xoá hàng",
+ score="Hiện điểm thành phần",
+ bufferWarn="Hiện số hàng rác",
+ showSpike="Hiện độ lớn spike",
+ nextPos="Hiện chỗ spawn",
+ highCam="Trượt bảng",
+ warn="Cảnh báo nguy hiểm",
+
+ clickFX="Click FX",
+ power="Hiện thanh pin",
+ clean="Vẽ nhanh",
+ fullscreen="Toàn màn hình",
+ portrait="Để dọc",
+ msaa="Khử r.cưa (MSAA)",
+
+ bg_on="Ảnh nền thường",
+ bg_off="Không ảnh nền",
+ bg_custom="Ảnh nền tự chọn",
+
+ blockSatur="Độ đậm gạch",
+ fieldSatur="Độ đậm bảng",
+ },
+ setting_sound={
+ title="Cài đặt âm thanh",
+
+ game="←Trò chơi",
+ graphic="Đồ hoạ→",
+
+ mainVol="Âm lượng tổng",
+ bgm="Nhạc nền",
+ sfx="Hiệu ứng",
+ stereo="Stereo",
+ spawn="Hiệu ứng spawn",
+ warn="Hiệu ứng cảnh báo",
+ vib="Rung",
+ voc="Giọng",
+
+ autoMute="Tắt tiếng nếu đang ở ngoài game",
+ fine="Âm thanh báo lỗi di chuyển",
+ sfxPack="Gói SFX",
+ vocPack="Gói Voice",
+ apply="Chọn",
+ },
+ setting_control={
+ -- title="Cài đặt Điều khiển",
+ title="Đ.chỉnh thg. số",
+ preview="Xem trước",
+
+ das="DAS",arr="ARR",
+ dascut="DAS cut",
+ dropcut="Auto-lock cut",
+ sddas="DAS thả nhẹ",sdarr="ARR thả nhẹ",
+ ihs="Giữ tức thì",
+ irs="Xoay tức thì",
+ ims="Di chuyển tức thì",
+ reset="Đặt lại",
+ },
+ setting_key={
+ a1 ="Sang Trái",
+ a2 ="Sang Phải",
+ a3 ="Xoay Phải",
+ a4 ="Xoay Trái",
+ a5 ="Xoay 180°",
+ a6 ="Thả Mạnh",
+ a7 ="Thả Nhẹ",
+ a8 ="Giữ",
+ a9 ="Chức năng 1 (F1)",
+ a10="Chức năng 2 (F2)",
+ a11="Trái tức thì",
+ a12="Phải tức thì",
+ a13="Thả Nhanh",
+ a14="Xuống 1",
+ a15="Xuống 4",
+ a16="Xuống 10",
+ a17="Thả Trái",
+ a18="Thả Phải",
+ a19="Zangi Trái",
+ a20="Zangi Phải",
+ restart="Thử lại",
+ },
+ setting_skin={
+ skinSet="Tên Skin",
+ title="Trang Trí",
+ skinR="Đặt lại màu",
+ faceR="Đặt lại hướng",
+ },
+ setting_touch={
+ default="Mặc định",
+ snap="Bám theo khung",
+ size="Kích cỡ",
+ shape="Hình dạng",
+ },
+ setting_touchSwitch={
+ b1 ="Sang Trái:",
+ b2 ="Sang Phải:",
+ b3 ="Xoay Phải:",
+ b4 ="Xoay Trái:",
+ b5 ="Xoay 180° (F):",
+ b6 ="Thả Mạnh:",
+ b7 ="Thả Nhẹ:",
+ b8 ="Giữ (H):",
+ b9 ="Chức năng 1 (F1):",
+ b10="Chức năng 2 (F2):",
+ b11="Trái tức thì:",
+ b12="Phải tức thì:",
+ b13="Thả Nhanh:",
+ b14="Xuống 1:",
+ b15="Xuống 4:",
+ b16="Xuống 10:",
+ b17="Thả Trái:",
+ b18="Thả Phải:",
+ b19="Zangi Trái:",
+ b20="Zangi Phải:",
+
+ norm="Thường",
+ pro="Nâng cao",
+ icon="Icon",
+ sfx="SFX",
+ vib="Rung",
+ alpha="Độ đậm",
+
+ track="Tự động theo",
+ dodge="Tự động tránh",
+ },
+ customGame={
+ title="Chế độ Tự do",
+ defSeq="Tr.xáo cố định",
+ noMsn="Không có nhiệm vụ",
+
+ drop="Drop Delay",
+ lock="Lock Delay",
+ wait="Entry Delay",
+ fall="Line Delay",
+ hang="Death Delay",
+ hurry="ARE Interruption",
+
+ bg="Ảnh nền",
+ bgm="Nhạc",
+
+ copy="Chép Bảng+Tr.xáo+N.vụ",
+ paste="Dán Bảng+Tr.xáo+N.vụ",
+ play_clear="Bắt đầu-Clear",
+ play_puzzle="Bắt đầu-Puzzle",
+
+ reset="Đặt lại (del)",
+ advance="More (A)",
+ mod="Mod (F1)",
+ field="Cài đặt bảng (F)",
+ sequence="C. đặt Trình xáo gạch (S)",
+ mission="Cài đặt Nhiệm vụ (M)",
+
+ eventSet="Rule Set",
+
+ holdMode="Chế độ Hold",
+ nextCount="Next",
+ holdCount="Hold",
+ infHold="Hold vô tận",
+ phyHold="Hold tại chỗ",
+
+ fieldH="Độ cao bảng",
+ visible="Chế độ hiển thị",
+ freshLimit="Lock Reset tối đa",
+ opponent="Đối thủ",
+ life="Mạng",
+ pushSpeed="Tốc độ đẩy rác vào",
+ garbageSpeed="Tốc độ gửi rác",
+
+ bufferLimit="Giới hạn nhận rác",
+ heightLimit="Giới hạn độ cao",
+ ospin="O-Spin",
+ fineKill="100% Finesse",
+ b2bKill="Không phá B2B",
+ lockout="Thua khi Lock Out",
+ easyFresh="Lock Reset Thường",
+ deepDrop="Thả Sâu",
+ bone="Dùng gạch []",
+ },
+ custom_field={
+ title="Chế độ Tự do",
+ subTitle="Bảng",
+
+ any="Xoá",
+ smart="Thông minh",
+
+ push="Thêm Hàng (K)",
+ del="Xoá Hàng (L)",
+
+ demo="Không hiện “×”",
+
+ newPg="Trang mới (N)",
+ delPg="Xoá trang (M)",
+ prevPg="Trang trước",
+ nextPg="Trang tiếp",
+ },
+ custom_sequence={
+ title="Chế độ Tự do",
+ subTitle="Trình xáo gạch",
+ sequence="Cách xáo",
+ },
+ custom_mission={
+ title="Chế độ Tự do",
+ subTitle="Nhiệm vụ",
+
+ _1="1",_2="2",_3="3",_4="4",
+ any1="Spin1",any2="Spin2",any3="Spin3",any4="Spin4",
+ PC="PC",
+ Z1="Z1",S1="S1",J1="J1",L1="L1",T1="T1",O1="O1",I1="I1",
+ Z2="Z2",S2="S2",J2="J2",L2="L2",T2="T2",O2="O2",I2="I2",
+ Z3="Z3",S3="S3",J3="J3",L3="L3",T3="T3",O3="O3",I3="I3",
+ O4="O4",I4="I4",
+ mission="Đúng trình tự!",
+ },
+ about={
+ staff="Đội ngũ",
+ his="Thay đổi",
+ legals="Pháp lý",
+ },
+ dict={
+ title="Từ điển Tetro",
+ },
+ stat={
+ path="Mở thư mục chứa dữ liệu",
+ save="Trình quản lý dữ liệu",
+ },
+ music={
+ title="Phòng Nhạc",
+ arrow="→",
+ now="Đang phát:",
+
+ bgm="BGM",
+ sound="SFXs",
+ },
+ launchpad={
+ title="Phòng SFX",
+ bgm="BGM",
+ sfx="SFX",
+ voc="VOC",
+ music="BGMs",
+ label="nhãn",
+ },
+ login={
+ title="Đăng Nhập",
+ ticket="Mã uỷ quyền",
+ authorize="Mở trang uỷ quyền",
+ paste="Dán mã",
+ submit="Gửi",
+ },
+ -- reset_password={
+ -- title="Đặt lại Mật khẩu",
+ -- send="Gửi mã",
+ -- code="Mã xác nhận",
+ -- password="Mật khẩu",
+ -- password2="Nhập lại Mật khẩu",
+ -- setPW="Đặt mật khẩu",
+ -- },
+ account={
+ title="Tài khoản",
+ },
+ app_15p={
+ color="Màu",
+ invis="Tàng hình",
+ slide="Lướt",
+ pathVis="Hiện con trỏ",
+ revKB="Ngược",
+ },
+ app_schulteG={
+ rank="Độ khó",
+ invis="Tàng hình",
+ disappear="Biến mất",
+ tapFX="Tap FX",
+ },
+ app_AtoZ={
+ level="Level",
+ keyboard="Bàn phím",
+ },
+ app_2048={
+ invis="Tàng hình",
+ tapControl="Chạm trong bảng",
+
+ skip="Bỏ qua",
+ },
+ app_ten={
+ next="Next",
+ invis="Tàng hình",
+ fast="Nhanh",
+ },
+ app_dtw={
+ color="Màu",
+ mode="Chế độ",
+ bgm="BGM",
+ arcade="Chế độ đuổi kịp",
+ },
+ app_link={
+ invis="Tàng hình",
+ },
+ savedata={
+ export="Xuất từ clipboard",
+ import="Nhập vào clipboard",
+ unlock="Tiến trình",
+ data="Thống kê",
+ setting="Cài đặt",
+ vk="Bố cục cảm ứng",
+
+ couldSave="Lưu qua Cloud (CẢNH BÁO: ĐANG THỬ NGHIỆM!)",
+ notLogin="[Đăng nhập để lưu]",
+ upload="Tải lên Cloud",
+ download="Tải xuống từ Cloud",
+ },
+ },
+ modes={
+ ['sprint_10l']= {"Sprint", "10L", "Xoá 10 hàng!"},
+ ['sprint_20l']= {"Sprint", "20L", "Xoá 20 hàng!"},
+ ['sprint_40l']= {"Sprint", "40L", "Xoá 40 hàng!"},
+ ['sprint_100l']= {"Sprint", "100L", "Xoá 100 hàng!"},
+ ['sprint_400l']= {"Sprint", "400L", "Xoá 400 hàng!"},
+ ['sprint_1000l']= {"Sprint", "1,000L", "Xoá 1,000 hàng!"},
+ ['sprintPenta']= {"Sprint", "PENTOMINO", "Xoá 40 hàng với 18 pentomino"},
+ ['sprintMPH']= {"Sprint", "MPH", "Memoryless\nPreviewless\nHoldless"},
+ ['sprint123']= {"Sprint", "M123", "Xoá 40 hàng chỉ với monomino, domino, và trimino"},
+ ['secret_grade']= {"Secret Grade", "", "Xây một đường lỗ theo hình dích dắc!"},
+ ['dig_10l']= {"Dig", "10L", "Đào 10 hàng rác càng nhanh càng tốt"},
+ ['dig_40l']= {"Dig", "40L", "Đào 40 hàng rác càng nhanh càng tốt!"},
+ ['dig_100l']= {"Dig", "100L", "Đào 100 hàng rác càng nhanh càng tốt!"},
+ ['dig_400l']= {"Dig", "400L", "Đào 400 hàng rác càng nhanh càng tốt!"},
+ ['dig_eff_10l']= {"Dig", "EFFICIENCY 10L", "Đào 10 hàng rác càng ít gạch càng tốt!"},
+ ['dig_eff_40l']= {"Dig", "EFFICIENCY 40L", "Đào 40 hàng rác càng ít gạch càng tốt!"},
+ ['dig_eff_100l']= {"Dig", "EFFICIENCY 100L","Đào 100 hàng rác càng ít gạch càng tốt!"},
+ ['dig_eff_400l']= {"Dig", "EFFICIENCY 400L","Đào 400 hàng rác càng ít gạch càng tốt!"},
+ ['dig_quad_10l']= {"Dig", "TECHRASH 10L", "Đào 10 hàng rác nhưng chỉ dùng techrash!"},
+ ['drought_n']= {"Drought", "100L", "Không có thanh dài"},
+ ['drought_l']= {"Drought+", "100L", "C L G T"},
+ ['marathon_n']= {"Marathon", "THƯỜNG", "Xoá 200 hàng với tốc độ nhanh dần"},
+ ['marathon_h']= {"Marathon", "KHÓ", "Xoá 200 hàng với tốc độ cao"},
+ ['solo_e']= {"Battle", "DỄ", "Đánh bại AI!"},
+ ['solo_n']= {"Battle", "THƯỜNG", "Đánh bại AI!"},
+ ['solo_h']= {"Battle", "KHÓ", "Đánh bại AI!"},
+ ['solo_l']= {"Battle", "RẤT KHÓ", "Đánh bại AI!"},
+ ['solo_u']= {"Battle", "THÁCH ĐẤU", "Đánh bại AI!"},
+ ['techmino49_e']= {"Tech 49", "DỄ", "Cuộc chiến 49 người.\nNgười trụ lại cuối cùng giành chiến thắng"},
+ ['techmino49_h']= {"Tech 49", "KHÓ", "Cuộc chiến 49 người.\nNgười trụ lại cuối cùng giành chiến thắng"},
+ ['techmino49_u']= {"Tech 49", "THÁCH ĐẤU", "Cuộc chiến 49 người.\nNgười trụ lại cuối cùng giành chiến thắng"},
+ ['techmino99_e']= {"Tech 99", "DỄ", "Cuộc chiến 99 người.\nNgười trụ lại cuối cùng giành chiến thắng"},
+ ['techmino99_h']= {"Tech 99", "KHÓ", "Cuộc chiến 99 người.\nNgười trụ lại cuối cùng giành chiến thắng"},
+ ['techmino99_u']= {"Tech 99", "THÁCH ĐẤU", "Cuộc chiến 99 người.\nNgười trụ lại cuối cùng giành chiến thắng"},
+ ['round_e']= {"Turn-Based", "DỄ", "Chơi theo lượt và đánh bại AI!"},
+ ['round_n']= {"Turn-Based", "THƯỜNG", "Chơi theo lượt và đánh bại AI!"},
+ ['round_h']= {"Turn-Based", "KHÓ", "Chơi theo lượt và đánh bại AI!"},
+ ['round_l']= {"Turn-Based", "RẤT KHÓ", "Chơi theo lượt và đánh bại AI!"},
+ ['round_u']= {"Turn-Based", "THÁCH ĐẤU", "Chơi theo lượt và đánh bại AI!"},
+ ['big_n']= {"Big", "THƯỜNG", "Chơi với một bảng nhỏ hơn!"},
+ ['big_h']= {"Big", "KHÓ", "Chơi với một bảng nhỏ hơn!"},
+ ['master_n']= {"Master", "THƯỜNG", "Dành cho người mới chơi 20G"},
+ ['master_h']= {"Master", "KHÓ", "Dành cho người chơi đã quen 20G"},
+ ['master_m']= {"Master", "M21", "Dành cho cao thủ 20G"},
+ ['master_final']= {"Master", "FINAL", "Dành cho các pháp sư 20G"},
+ ['master_ph']= {"Master", "PHANTASM", "Hả???"},
+ ['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_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"},
+ ['blind_l']= {"Invisible", "KHÓ+", "Dành cho người chơi chuyên nghiệp"},
+ ['blind_u']= {"Invisible", "?", "Bạn đã sẵn sàng chưa?"},
+ ['blind_wtf']= {"Invisible", "CLGT?", "Bạn chưa đủ trình cho màn này đâu!"},
+ ['classic_e']= {"Classic", "DỄ", "Chế độ cổ điển từ thập niên 80"},
+ ['classic_h']= {"Classic", "KHÓ", "Chế độ cổ điển từ thập niên 80 với tốc độ cao hơn"},
+ ['classic_l']= {"Classic", "RẤT KHÓ", "Chế độ cổ điển từ thập niên 80 với tốc độ rất cao"},
+ ['classic_u']= {"Classic", "THÁCH ĐẤU", "Chế độ cổ điển từ thập niên 80 với tốc độ nhanh như chớp"},
+ ['survivor_e']= {"Survival", "DỄ", "Bạn có thể trụ được bao lâu?"},
+ ['survivor_n']= {"Survival", "THƯỜNG", "Bạn có thể trụ được bao lâu?"},
+ ['survivor_h']= {"Survival", "KHÓ", "Bạn có thể trụ được bao lâu?"},
+ ['survivor_l']= {"Survival", "RẤT KHÓ", "Bạn có thể trụ được bao lâu?"},
+ ['survivor_u']= {"Survival", "THÁCH ĐẤU", "Bạn có thể trụ được bao lâu?"},
+ ['attacker_h']= {"Attacker", "KHÓ", "Luyện tập kỹ năng tấn công!"},
+ ['attacker_u']= {"Attacker", "THÁCH ĐẤU", "Luyện tập kỹ năng tấn công!"},
+ ['defender_n']= {"Defender", "THƯỜNG", "Luyện tập kỹ năng phòng thủ!"},
+ ['defender_l']= {"Defender", "RẤT KHÓ", "Luyện tập kỹ năng phòng thủ!"},
+ ['dig_h']= {"Driller", "KHÓ", "Luyện tập kỹ năng đào xuống!"},
+ ['dig_u']= {"Driller", "THÁCH ĐẤU", "Luyện tập kỹ năng đào xuống!"},
+ ['c4wtrain_n']= {"C4W Training", "THƯỜNG", "Combo vô tận"},
+ ['c4wtrain_l']= {"C4W Training", "RẤT KHÓ", "Combo vô tận"},
+ ['pctrain_n']= {"PC Training", "THƯỜNG", "Luyện tập Perfect Clear"},
+ ['pctrain_l']= {"PC Training", "RẤT KHÓ", "Luyện tập Perfect Clear nhưng khó hơn"},
+ ['pc_n']= {"PC Challenge", "THƯỜNG", "Lấy càng nhiều PC càng tốt trong 100 hàng!"},
+ ['pc_h']= {"PC Challenge", "KHÓ", "Lấy càng nhiều PC càng tốt trong 100 hàng!"},
+ ['pc_l']= {"PC Challenge", "RẤT KHÓ", "Lấy càng nhiều PC càng tốt trong 100 hàng!"},
+ ['pc_inf']= {"Inf. PC Challenge", "", "Lấy càng nhiều PC càng tốt"},
+ ['tech_n']= {"Tech", "THƯỜNG", "Cố gắng không phá B2B!"},
+ ['tech_n_plus']= {"Tech", "THƯỜNG+", "Chỉ được clear Spin hoặc PC"},
+ ['tech_h']= {"Tech", "KHÓ", "Cố gắng không phá B2B!"},
+ ['tech_h_plus']= {"Tech", "KHÓ+", "Chỉ được clear Spin hoặc PC"},
+ ['tech_l']= {"Tech", "RẤT KHÓ", "Cố gắng không phá B2B!"},
+ ['tech_l_plus']= {"Tech", "RẤT KHÓ+", "Chỉ được clear Spin hoặc PC"},
+ ['tech_finesse']= {"Tech", "HOÀN HẢO", "Không được phép có lỗi di chuyển!"},
+ ['tech_finesse_f']= {"Tech", "HOÀN HẢO+", "Không được phép có lỗi di chuyển hoặc loại Xoá hàng thường!"},
+ ['tsd_e']= {"TSD Challenge", "DỄ", "Chỉ được làm T-Spin Double!"}, -- Chỉ được clear…
+ ['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!"},
+ ['backfire_n']= {"Backfire", "THƯỜNG", "Sống sót những hàng rác do chính bạn gửi"},
+ ['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"},
+ ['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."},
+
+ ['custom_clear']= {"Custom", "NORMAL"},
+ ['custom_puzzle']= {"Custom", "PUZZLE"},
+ },
+ getTip={refuseCopy=true,
+ -- Lưu ý dành cho những bạn sửa phần này: Nguyên đoạn này là lấy từ bản tiếng Anh
+ -- Nhưng User670 khi dịch từ tiếng Trung sang đã chọn lược bỏ bớt một số câu
+ ":dcgpray:",
+ "Không thể mở “Techmino.app” vì người làm game đã bay màu",
+ "“Techmino.app” là vi rút đấy. Xoá đi",
+ "“TechminOS”",
+ "(RUR’U’)R’FR2U’R’U’(RUR’F’)",
+ "\\jezevec/\\jezevec/\\jezevec/",
+ "\\osk/\\osk/\\osk/",
+ "↑↑↓↓←→←→BA",
+ "$include",
+ "0next 0hold",
+ "1next 0hold",
+ "1next 1hold!",
+ "1next 6hold!",
+ "20G thực chất là một chế độ mới đấy!",
+ "Kỷ lục Sprint 40 hàng: 14.708s (hiryu)",
+ "6next 1hold!",
+ "6next 6hold?!",
+ "Rất gần nhưng lại rất xa",
+ "ALL SPIN!",
+ "Am G F G",
+ "B2B2B???",
+ "B2B2B2B không có thật",
+ "Back-to-Back Techrash, 10 Combo, PC!",
+ "Nhớ dốc hết sức cho ngày hôm nay nha bạn!",
+ "Bridge clear sắp ra mắt!",
+ "Bạn có thể chinh phục game xếp gạch này không?",
+ "Con tim này luôn hướng về 3M",
+ "Mọi thay đổi của game (tiếng Anh) sẽ được ghi lại trên Discord",
+ "Color clear sắp ra mắt!",
+ "Giảm DAS và ARR sẽ giúp bạn chơi nhanh hơn nhưng khó điều khiển hơn",
+ "Tao vừa mới thấy Back-to-Back-to-Back hả?",
+ "B2B2B2B tồn tại hả?",
+ "Đừng để những thứ nhỏ nhặt làm bạn nản chí!",
+ "Đây không phải là lỗi, đây là tính năng!",
+ "Hệ thống xoay gạch của Techmino rất đẹp trai!",
+ "Em rất tốt nhưng anh rất tiếc…",
+ "Đừng quên xem qua phần cài đặt!",
+ "Nếu bạn thấy có vấn đề gì, hãy lên trang GitHub báo lại cho chúng tôi!",
+ "Game xếp gạch nhưng có thêm chế độ FFA!",
+ "Bạn muốn đóng góp ý tưởng? Hãy vào Discord của chúng tôi!",
+ "Bạn có biết khi gạch xoay thì nó biến thành gì không?",
+ "Khuyến khích đeo tai nghe để có trải nghiệm tốt hơn",
+ "Hello world!",
+ "Chỉ có 2 loại trimino là I3 và L3",
+ "if a==true",
+ "Việc tăng tần số khung hình sẽ mang trải nghiệm tốt hơn cho bạn",
+ "[Hành động] tức thì có thể cứu bạn đấy!",
+ "B2B2B2B là gì? Ăn được không?",
+ "Nó vừa load cutscene, vừa load game đấy!",
+ "Bạn có thể xoá 40 hàng mà không cần dùng nút trái/phải",
+ "Bạn có thể xoá 40 hàng mà không cần dùng nút xoay",
+ "Hãy tham gia Discord của chúng tôi!",
+ "l-=-1",
+ "Nổi lửa lên em, NỔI LỬA LÊN EM!",
+ "Việc giảm tần số khung hình sẽ mang trải nghiệm tệ hơn cho bạn",
+ "LrL RlR LLr RRl RRR LLL FFF RfR RRf rFF",
+ "Mix clear sắp ra mắt!",
+ "Hầu hết các biểu tượng của các nút được vẽ tay vào trong bảng Unicode Private Use Area",
+ "Hầu hết nhạc trong game được tạo bằng Beepbox",
+ "Nghe nhạc làm bạn phân tâm? Tắt nó đi",
+ "Nếu mà Chế độ đơn giản được bật thì bạn sẽ không thấy điều đặc biệt nào đâu!",
+ "Thương cho tấm thân cơ hàn, ngậm ngùi lặng nhìn con đò sang ngang",
+ "Chơi game một tay chưa?",
+ "Có công mài sắt, có ngày nên kim!",
+ "Chạy bằng LÖVE",
+ "Chạy bằng Un..LÖVE",
+ "pps-0.01",
+ "Dit me VNPT",
+ "Một số yêu cầu để đạt được rank X là rất khó, kể cả đối với những người giỏi nhất",
+ "Bạn sẽ sớm được chơi với mọi người trên thế giới thôi",
+ "Split clear sắp ra mắt!",
+ "Techmino là sự kết hợp giữa “technique” và “tetromino”",
+ "Hình như mình nghiện Techmino rồi!",
+ "Techmino trên Nspire-CX ư? Có thật đấy! Mà khoan đã, hai game này không giống nhau chút nào cả!",
+ "TetroDictionary đã ra mắt (có bản tiếng Việt rồi, nhưng mà hơi bruh, thôi vẫn đủ xài!)",
+ "Những cái tên xuất hiện ở phần nền trong trang Đội Ngũ là danh sách các nhà tài trợ của chúng tôi",
+ "Toàn bộ nhạc game này đã có mặt trên Soundcloud rồi đấy!",
+ "The stacker future is yours in Techmino!",
+ "Bạn có biết: Có một số chế độ đã bị ẩn khỏi map không?",
+ "Có tất cả 18 miếng pentomino khác nhau",
+ "Có tất cả 7 miếng tetromino khác nhau",
+ "Chế độ nhiều người đã ra mắt rồi, hãy thử nó đi!",
+ "Thử sử dụng nhiều ô Hold đi!",
+ "Thử dùng 2 nút xoay đi. Dùng cả 3 thì càng tốt",
+ {C.R,"CẢNH BÁO! ",C.Z,"Cấu trúc dữ liệu và Giải thuật"},
+ "20 PC thì sao?",
+ "Thế còn 23 PC trong 100 hàng?",
+ "26 TSD có nổi không thế?",
+ "Game rác v*i c*t",
+ "while (false)",
+ "Bạn là Nhất!",
+ "Bạn có thể giúp chúng tôi viết BGM và SFX!",
+ "Bạn có thể cắm bàn phím vào điện thoại hoặc máy tính bảng (đối với iOS thì không)",
+ "Bạn có thể cài đặt bố cục phím trong phần cài đặt!",
+ "Bạn có thể mở thư mục chứa dữ liệu từ trang Thống kê",
+ "Bạn có thể thực hiện Spin với tất cả cả miếng gạch trong game này",
+ "Bạn có thể đặt hướng xuất hiện cho từng miếng gạch",
+ "ZS JL T O I",
+ {C.C,"Also try 15puzzle!"},
+ {C.C,"Also try Ballance!"},
+ {C.C,"Also try Minecraft!"},
+ {C.C,"Also try Minesweeper!"},
+ {C.C,"Also try Orzmic!"},
+ {C.C,"Also try osu!"},
+ {C.C,"Also try Phigros!"},
+ {C.C,"Also try Puyo Puyo!"},
+ {C.C,"Also try Quatrack"},
+ {C.C,"Also try Rubik’s cube!"},
+ {C.C,"Also try Terraria!"},
+ {C.C,"Also try Touhou Project!"},
+ {C.C,"Also try VVVVVV!"},
+ {C.C,"Also try World of goo!"},
+ {C.C,"Also try Zuma!"},
+ {C.H,"MÓM RỒI ANH EM ƠI!!!!!"},
+ {C.lP,"Con số bí mật: 626"},
+ {C.lR,"Z ",C.lG,"S ",C.lS,"J ",C.lO,"L ",C.lP,"T ",C.lY,"O ",C.lC,"I"},
+ {C.lY,"MÁT QUÁ!!"},
+ {C.N,"Lua",C.Z," No.1"},
+ {C.P,"T-spin!"},
+ {C.R,"DMCA là gì?"},
+ {C.R,"“Luật sở hữu trí tuệ”"},
+ {C.R,"DD",C.Z," Cannon=",C.P,"TS",C.R,"D",C.Z,"+",C.P,"TS",C.R,"D",C.Z," Cannon"},
+ {C.R,"DT",C.Z," Cannon=",C.P,"TS",C.R,"D",C.Z,"+",C.P,"TS",C.R,"T",C.Z," Cannon"},
+ {C.R,"LrL ",C.G,"RlR ",C.B,"LLr ",C.O,"RRl ",C.P,"RRR ",C.P,"LLL ",C.C,"FFF ",C.Y,"RfR ",C.Y,"RRf ",C.Y,"rFF"},
+ {C.Y,"O-Spin Triple!"},
+ {C.Z,"Gì? ",C.lC,"Xspin?"},
+
+
+
+ -- TECHMINO FUN FACT
+ -- How do you pronounce Techmino?
+ "Phát âm từ Techmino như thế nào mới đúng?",
+ -- English UK: /'tɛkminəʊ/; English US: /tɛkminoʊ/
+ "Techmino phát âm trong tiếng Anh là /'tɛkminəʊ/; còn tiếng Mỹ là /tɛkminoʊ/.",
+ --
+ "Ủa Techmino phải đọc là “Tét-mai-nô” hay là “Tét-mi-nô” vậy?",
+ -- Where to download Techmino?
+ "Tải Techmino ở đâu vậy? Trên GitHub đấy!",
+ -- 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 (ĐÙA ĐẤY ĐỪNG TIN!)",
+ -- Hope you all like Z... Oh no, like Techmino
+ {"Mình mong các bạn sẽ thích ",C.W,"Z",C.Z,"… Ối! Không phải, thích ",C.G,"Techmino",C.Z," cơ! Nhầm nhầm nhầm!"},
+ -- 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'.
+ "Tên chính thức của game là “方块研究所” (Block Research Institute).",
+ "Một tên khác của game này là “Tiehu Minuo”",
+ -- 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!",
+ --
+ "Trừ khi bạn đang chơi Techmino: “O-spin is a lie!”)",
+ -- 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!",
+ -- Warning: No pretending to be weak.
+ {C.R,"CẢNH BÁO! ",C.Z,"Đừng giả vờ yếu đuối"},
+ -- "Meow!"
+ "Meow!",
+ -- Getting popup messages in the middle of a game? Go to settings and disable them.
+ "Thông báo tự dưng hiện lên giữa game? Vào cài đặt của app tạo ra popup và tắt nó đi.",
+ "Do Not Distrub (Không làm phiền) sẽ là cứu tinh của bạn khi có quá nhiều thông báo cùng làm phiền.",
+ -- 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 điện thoại có thể khiến máy giật lag.",
+ -- 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? Giỡn à? Xem lại replay để chắc rằng ông đã nhấn và xem thử mất bao nhiêu thời gian để ông nhấn phím đó.",
+ -- Probably someone will read the tip
+ "Chắc chắn có người đang đọc cái dòng chữ nhỏ đang chạy ở dưới này.",
+ -- 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ì toeng! Nhớ quản lý thời gian 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
+ "Xếp gạch cổ điển cũng không đơn giản gì như xếp gạch hiện đại đâu. Đừng có mà xem thường những người chơi hệ cổ điển!",
+ -- 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 không có nghĩa là bạn giỏi cả bên còn lại đâu. Bạn phải học từ đầu đấy! Không đơn giản đâu.",
+ -- 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 hoặc 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!)"},
+ -- Even if you're topped out, don't give up; every line of garbage can potentially become your weapon.
+ "Ngay cả khi bạn sắp bị top out, đừng bỏ cuộc; vì từng hàng rác có tiềm năng trở thành vũ khí của bạn!",
+ -- The video shown above is not a recording; it's the robot playing in real-time.
+ "Cái ở trên là replay 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~
+ "Những lần chơi game kéo dài thường xuyên dần dần làm giảm hiệu suất chơi game (trong trường hợp tệ nhất bạn có thể bị stall). Nhớ nghỉ ngơi khi chơi lâu",
+ -- 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 concise 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!",
+ -- 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.",
+ --
+ "Hãy ra ngoài và chạm cỏ đi!",
+--
+ -- MrZ
+ {C.W,"uid:225238922"},
+ {"Ai là ",C.W,"MrZ",C.Z," vậy?"},
+--
+ -- Z SAID
+ -- I can't write cool music (crying)
+ {C.W,"Z: ",C.Z,"Tôi không thể nào viết một bản nhạc nào trông ngầu 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?
+ {C.W,"Z: ",C.Z,"Còn mẹo nào tôi có thể viết ra nhỉ?"},
+ -- I hope Minimalistic Mode is fine.
+ {C.W,"Z: ",C.Z,"Tôi mong là Chế độ Đơn giản đủ tốt"},
+ -- I wonder how many people playing games actually care about who made the game.",
+ {C.W,"Z: ",C.Z,"Tôi tự hỏi là có bao nhiêu người chơi game thực sự quan tâm ai viết ra nó."},
+--
+ -- IT JOKES
+ "git clone --recursive https://github.com/26F-Studio/Techmino.git",
+ "git merge --rebase",
+ "git stash",
+ "git stash apply",
+ "git submodule update",
+ "git commit -m \".\"",
+ "git push -f",
+ "Lua No.1",
+ "sudo rm -rf /*",
+ "shutdown /s /t 0", -- Turn off computer completely (no Fast Boot)
+ "shutdown /s /t 0 /hybrid", -- Turn off computer with Fast Boot still activated
+ -- Techmino has reached the limit.
+ "Không thể mở Techmino vì bạn đã quá nghiện game này rồi :>",
+ -- Techmino.exe has stopped working.
+ "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."},
+ -- COLD CLEAR PATH
+ "Đường dẫn của Cold Clear: "..(
+ SYSTEM=='Windows' and "\\CCloader.dll" or
+ SYSTEM=='Linux' and "/CCloader.so" or
+ SYSTEM=='Android' and "/libAndroid/arm64-v8a (hoặc armeabi-v7a)/CCloader.so" or
+ SYSTEM=='OS X' and "",
"0next 0hold.",
"11renPC!",
"1next 0hold",
@@ -774,7 +968,7 @@ return{
"1next 6hold!",
"3.1415926535897932384(\\d{3})",
"3next 1hold?",
- "40行世界纪录:14.915s by Reset_",
+ "40行世界纪录:14.708s by hiryu",
"6236326236327175",
"626in1",
"6next 1hold!",
@@ -783,25 +977,18 @@ return{
"本游戏还在测试中,出各种问题都是有可能的哦",
"本游戏使用精简版字体,可能有些特殊字符不能正确显示",
"别催了,在做了!",
- "不要大力拍打或滑动哦",
"不要卖弱不要卖弱不要卖弱",
"不知道有多少人玩游戏的时候会关心游戏是谁做的",
"部分手机系统开启震动会导致严重卡顿",
"彩色消除即将到来!",
- "草(日本语)",
- "车万方块是一家(暴论",
+ "草(日本语)",
"吃键?真的吗?建议回放看看到底按没按到,按了多久",
- "凑数tip什么时候能站起来!",
- "打铁.png",
- "打铁",
+ "打铁.mp4",
"大概还是有人会看tip的",
"大家认为的俄罗斯方块很可能不是你以为的俄罗斯方块,场合合适的时候可以适当提醒一下哦",
"大满贯10连击消四全清!",
"戴上耳机以获得最佳体验",
- "单手也能玩!",
- "点击添加标题",
- "对编程有真·兴趣推荐Lua,安装无脑 语法简单 执行速度快 远离枯燥学校编程(雾",
- "多年小游戏玩家表示痛恨故意拖时间的假加载",
+ "多年小游戏玩家表示痛恨拖时间的假加载",
"多hold现代块又回来了!",
"俄罗斯方块完全可以作为电竞游戏",
"发现有个“隐形”皮肤了吗",
@@ -809,23 +996,16 @@ return{
"方块能吃吗",
"感觉明明按键了但是没反应?你真的按到了吗?",
"感谢群友帮忙想tip",
- "感谢Orzmic为这个tip框提供修改意见",
- "感谢Phigros提供(确信)部分tip模板",
- "隔壁不在乎玩家意见但是我们在乎,没人提过的合理建议一定会回应",
"隔断消除即将到来!",
"还能写些什么tip呢",
"好像还没人能用脚打块打到一定水平",
- "很有精神!",
"欢迎来帮忙制作音乐或音效!",
"欢迎提供更多游戏创意!",
"混合消除即将到来!",
"架空消除即将到来!",
"建议使用双手游玩",
- "绝大多数按钮上的图标是调用Unicode私用区里的自制字符实现的",
- "科技骨牌 你的创新式块堆栈业务技术管理器",
"块东V共荣",
"快去打一把100%极简看看会怎样",
- "锟斤拷锟斤拷锟斤拷",
"来学编程,好玩的",
"老牌益智游戏了",
"论如何正确使用Unicode私用区定制字体",
@@ -834,59 +1014,42 @@ return{
"免费吃鸡方块",
"喵!",
"魔方也是方块(确信",
- "你的双手是为了你的一生服务的,而不是Techmino",
"你今天的人品值是(满分100):"..math.random(100),
"你们考虑过Z酱的感受吗?没有!你们只考虑你自己。",
- "你有一个好",
- "你这块是金子做的还是垃圾行是金子做的",
- "你准备好了吗?",
"配乐是有考虑到模式氛围的哦",
- "请谨慎向没有方块经验的玩家推荐,会对本游戏的生存环境造成影响,感谢配合。",
- "请勿大力敲打设备!敲坏了就没有Techmino玩了",
+ "拼图与趣味",
"请勿使用三只手游玩",
"全球目前应该没人能全X评价(大爆炸不算)",
"如何O-spin: 一秒转626圈(误",
"三岁通关困难马拉松",
- "少女祈祷中",
"深降了解一下",
"试试用跳舞毯打块",
"适度游戏益脑,沉迷游戏伤身,合理安排时间,享受健康生活",
- "烫烫烫烫烫烫",
- "天哪,我竟然是一条凑数tip",
"挖掘能力在对战里非常非常非常重要!!!!",
"玩到一半弹出消息框?快去设置禁止弹窗",
"玩得开心的话游戏作者也会很开心哦",
"我曾经在极度愤怒的时候15秒消了40行",
- "我们联合!",
"我们是不是第一个在方块游戏做tip的?",
- "我是一条凑数tip",
- "我也是一条凑数tip",
"我一个滑铲就挖了个11renPC",
- "我永远喜……",
- "无法打开“Techmino.app”,因为无法验证开发者。",
"物理hold了解一下",
"希望极简率没事",
"希望你们都能喜欢Z……哦不是,喜欢Techmino",
"享受Tech的特色旋转系统!",
"写不出那种很酷的音乐(哭",
- "要盯着bug不放",
"音乐风格是什么,能吃吗",
"音乐使用beepbox制作",
"音游方块是一家(暴论",
"游戏使用LÖVE引擎制作",
"游戏使用un……LÖVE引擎制作",
+ "游戏原声已上架网易云音乐",
"有建议的话可以反馈给作者~",
- "有两个模式是以东方Project里的角色为主题的",
"这不是休闲游戏……别怪关卡要求太高,多练吧",
- "震惊,我只是一条凑数tip吗",
"中文方块百科全书:tetris.huijiwiki.com",
- "众所周知俄罗斯方块是经典编程练手游戏(?",
"众所周知mac不能拿来玩游戏",
"作业没做完别玩手机",
"作者40行sub26了",
- "作者电脑上装了11个方块",
- "作者浏览器收藏夹里有6个方块",
- "做,做碌鸠啊做,打块先啦!",
+ "作者电脑上装了16个方块",
+ "作者浏览器收藏夹里有7个方块",
"ALLSPIN!",
"Am G F G",
"B2B2B???",
@@ -895,40 +1058,99 @@ return{
"c4w人竟是我自己",
"c4w人竟在我身边",
"fin neo iso 是满足tspin条件的特殊t2的名字",
- "git commit",
- "git push -f",
- "hello world",
- "if a==true",
"iOS设备使用键盘控制可能会有问题,还是先只用触屏吧",
- "l-=-1",
"Let-The-Bass-Kick!",
"MrZ是谁啊",
"pps-0.01",
- "shutdown -h now",
"sofunhowtoget",
"STSD必死",
- "sudo rm -rf /*",
- "Techmino /'tɛkmɪnoʊ/ n.铁壳米诺(游戏名)",
+ "Techmino 英/'tɛkminəʊ/ 美/'tɛkminoʊ/ n.铁壳米诺 (游戏名)",
"Techmino = Technique + Tetromino",
"Techmino 好玩!",
- "Techmino 濂界帺锛",
- "Techmino console了解一下",
- "Techmino: App意外退出。",
- "Techmino.exe 已停止工作",
"Techmino安卓下载",
"Techmino没有氪金没有逼肝,良不良心~",
"Techmino在哪里下载",
"Techmino怎么念啊",
"techminohaowan",
"techminoisfun",
- "TechminOS coming s∞n",
- "viod main[]",
- "while(false)",
"Z酱竟是我自己",
"Z酱累了,Z酱不想更新",
"Z酱是谁",
"Z酱只是个写代码的,懂什么方块",
"Z块等身抱枕来一个(x",
+
+ -- 计算机技术梗
+ "点击添加标题",
+ "对编程有真·兴趣推荐Lua,安装无脑 语法简单 执行速度快 远离枯燥学校编程(雾",
+ "绝大多数按钮上的图标是调用Unicode私用区里的自制字符实现的",
+ "科技骨牌 你的创新式块堆栈业务技术管理器",
+ "锟斤拷锟斤拷锟斤拷",
+ "烫烫烫烫烫烫",
+ "“Techmino.app”将对您的电脑造成伤害。您应该将它移到废纸篓。",
+ "$include",
+ "无法打开“Techmino.app”,因为无法验证开发者。",
+ "众所周知俄罗斯方块是经典编程练手游戏(?",
+ "git commit",
+ "git push -f",
+ "hello world",
+ " if a==true",
+ "l-=-1",
+ "shutdown -h now",
+ "sudo rm -rf /*",
+ "Techmino 濂界帺锛",
+ "Techmino console了解一下",
+ "Techmino: App意外退出。",
+ "Techmino: 耗电异常 ——在后台阻止系统休眠",
+ "Techmino.exe 已停止工作",
+ "TechminOS coming s∞n",
+ "viod main[]",
+ " while (false)",
+
+ -- 其他乱七八糟梗
+ "啊哈哈哈哈哈,T块来咯",
+ "不轻不重,手感真是好极了",
+ "不要大力拍打或滑动哦",
+ "车万方块是一家(暴论",
+ "单手也能玩!",
+ "感谢Orzmic为这个tip框提供修改意见",
+ "感谢Phigros提供(确信)部分tip模板",
+ "科目三:(见词典\"新人练习路线\")",
+ "你的双手是为了你的一生服务的,而不是Techmino",
+ "你有一个好",
+ "你这块是金子做的还是垃圾行是金子做的",
+ "你准备好了吗?",
+ "请勿大力敲打设备!敲坏了就没有Techmino玩了",
+ "少女祈祷中",
+ "他奶奶的,为什么转不进去",
+ "我们联合!",
+ "要盯着bug不放",
+ "这打块,多是一件美事",
+ "做,做碌鸠啊做,打块先啦!",
+ {C.Z,"1,2,",C.C,"⑨",C.Z,"!!!!!"},
+ {C.C,""},
+ {C.H,"暂定段位:9"},
+ {C.lY,"COOL!!"},
+ {C.H,"REGRET!!"},
+ {C.Y,"<φ> 10000"},
+ {C.Y,"10000 φ"},
+ {C.Y,"暂定段位:GM"},
+ {C.Y,"暂定段位:M"},
+ {C.Y,"暂定段位:MK"},
+ {C.Y,"暂定段位:MM"},
+ {C.Y,"暂定段位:MO"},
+ {C.Y,"暂定段位:MV"},
+ {C.Y,"O-spin!"},
+ {C.lY,"Xspin",C.Z,"是啥"},
+ {C.Z,"堆叠药水",C.H," 堆叠提升 (3:00)"},
+ {C.Z,"挖掘药水",C.H," 挖掘提升 (8:00)"},
+ {C.Z,"效率药水",C.H," 效率提升 (3:00)"},
+ {C.Z,"协调药水",C.H," MD减少 II(1:30)"},
+ {C.P,"T-spin!"},
+ {C.R,"DD",C.Z,"炮=",C.P,"TS",C.R,"D",C.Z,"+",C.P,"TS",C.R,"D",C.Z,"炮"},
+ {C.R,"DT",C.Z,"炮=",C.P,"TS",C.R,"D",C.Z,"+",C.P,"TS",C.R,"T",C.Z,"炮"},
+ {C.R,"LrL ",C.G,"RlR ",C.B,"LLr ",C.O,"RRl ",C.P,"RRR LLL ",C.C,"FFF ",C.Y,"RfR RRf rFF"},
+
+ -- 时间碎片
"时间碎片[000] 2021/11/21加入这个版块",
"时间碎片[001] V0.0.091726加入TRS旋转系统",
"时间碎片[002] V0.7.9加入O-spin",
@@ -943,15 +1165,17 @@ return{
"时间碎片[011] V0.13.0联网对战测试",
"时间碎片[012] V0.13.2加入任意场地高度",
"时间碎片[013] V0.13.3加入控制台",
- "时间碎片[014] V0.14.4加入第一首非Beepbox制作的BGM",
- "时间碎片[015] V0.14.5加入第一首社区玩家自制BGM",
- "时间碎片[016] V0.15.5加入录像回放菜单",
- "时间碎片[017] V0.16.0加入BIRS",
- "时间碎片[018] V0.16.2加入打击垫样式的音效室",
- "时间碎片[019] V0.17.0加入手柄的摇杆和扳机支持",
+ "时间碎片[014] V0.14.5加入第一首社区玩家自制BGM",
+ "时间碎片[015] V0.15.5加入录像回放菜单",
+ "时间碎片[016] V0.16.0加入BIRS",
+ "时间碎片[017] V0.16.2加入打击垫样式的音效室",
+ "时间碎片[018] V0.17.0加入手柄的摇杆和扳机支持",
+ "时间碎片[019] V0.17.3准备停止开发老Techmino,进入维护期",
+
+ -- 豆知识
"豆知识[001]总共有400多条tip哦",
"豆知识[002]背景影响游玩?可以去设置关闭",
- "豆知识[003]方块默认出现的方向都是重心在下哦(如果你没乱动设置",
+ "豆知识[003]方块默认出现的方向都是重心在下哦(如果你没乱动设置",
"豆知识[004]各种画面细节选项都可以在设置里找到哦",
"豆知识[005]觉得移动速度太慢或太快,手感不好?快去设置调整DAS/ARR",
"豆知识[006]无聊翻翻设置是好习惯",
@@ -973,7 +1197,7 @@ return{
"豆知识[022]不同人打40行最合适的方式不一样,s1w/63/散消/s2w……",
"豆知识[023]不同游戏(甚至不同模式)中不同战术的强度都不一样,并不能简单的按顺序排名",
"豆知识[024]除了雨宫太阳还有很多高手玩家,尤其是不在PPT里,甚至强出不少",
- "豆知识[025]触发游戏报错后日志文件会越来越大(不过顶多几百K)",
+ "豆知识[025]触发游戏报错后日志文件会越来越大(不过顶多几百K)",
"豆知识[026]打好块跟学习一样没有捷径,多练!",
"豆知识[027]打网络对战前请确认自己有一定的水平,不然会毫无游戏体验的",
"豆知识[028]大量使用开局定式的数据是不准的",
@@ -1016,7 +1240,7 @@ return{
"豆知识[065]三连块只有2种",
"豆知识[066]四连块总共7种",
"豆知识[067]五连块总共18种",
- "豆知识[068]六连块总共有……?那不重要,不会做的(大概",
+ "豆知识[068]六连块总共有……?那不重要,不会做的(大概",
"豆知识[069]上面这个不是录像,是机器人实时在玩",
"豆知识[070]使用固定堆叠方法达成20TSD难度很低",
"豆知识[071]手机玩也可以外接键盘哦(iOS除外)",
@@ -1054,16 +1278,25 @@ return{
"豆知识[103]请在有一定基础之后再学Tspin!不然副作用非常大!",
"豆知识[104]新人请千万记住,打好基础,不要太早学那些花里胡哨的。",
"豆知识[105]长时间游戏状态会越来越差!玩久了记得放松一下~",
+
+ -- 健康小贴士
"健康小贴士[01]玩游戏多眨眼,不然会干眼病",
"健康小贴士[02]少玩点游戏,多注意眨眼和休息",
"健康小贴士[03]戴耳机(尤其是半入耳式)时音量千万别拉满,不然真的会影响听力(虽然很慢)",
"健康小贴士[04]不要熬夜,真的会猝死",
"健康小贴士[05]长期睡眠不足会引起不可逆的脑损伤(变傻)",
+
+ -- 群友名言
"群友名言[001]“玩了Techmino之后发现打字速度变快了”",
"群友名言[002]“我要陪伴着tech一步步成长,然后就可以疯狂的享受他”",
+ "群友名言[003]“太super啦,不愧是guideline”",
+ "群友名言[004]“憋惦记你那*26了(”",
+ "群友名言[005]“如果bug有颜色,那一定是___”",
+
+ -- Frt评
"Frt评[01]“成天被夸赞‘好玩’的”",
"Frt评[02]“可以形成方块圈子小中心话题,同作者一起衍生一些概念与梗的”",
- "Frt评[03]“论方块的软工意义(就算这么小个范围内,各种取舍蒙混翻车现象都总会以很易懂的方式出现(”",
+ "Frt评[03]“论方块的软工意义(就算这么小个范围内,各种取舍蒙混翻车现象都总会以很易懂的方式出现(”",
"Frt评[04]“民间微创新”",
"Frt评[05]“民间音lè与图案”",
"Frt评[06]“民间游戏设计”",
@@ -1073,6 +1306,8 @@ return{
"Frt评[10]“是民间UI动效艺术作品”",
"Frt评[11]“是一滩散乱的代码组成的蜜汁结构”",
"Frt评[12]“它是现在的techmino已发布版本”",
+
+ -- 今日数学
"今日数学[01](a+b)³=a³+3a²b+3ab²+b³",
"今日数学[02]∫u dv=uv-∫v du",
"今日数学[03]cos(α+β)=CαCβ-SβSα",
@@ -1088,10 +1323,12 @@ return{
"今日数学[13]sin²α-cos²β=-C(α+β)C(α-β)",
"今日数学[14]sin²α-sin²β=S(α+β)S(α-β)",
"今日数学[15]sin2α=2SαCα",
+
+ -- Z
"Z哲[01]方块教会我们,合群了就会消失,……",
- "Z哲[02]假如生活欺骗了你,不要悲伤,不要心急,还有块陪着你",
- "Z哲[03]……,合群了就会消失,不合群世界毁灭(指game over",
- "Z哲[04]……,合群了就会消失,但消失不代表没有意义",
+ "Z哲[02]……,合群了就会消失,不合群世界毁灭(指game over",
+ "Z哲[03]……,合群了就会消失,但消失不代表没有意义",
+ "Z哲[04]假如生活欺骗了你,不要悲伤,不要心急,还有块陪着你",
"Z哲[05]没有量化就没有对比,……",
"Z哲[06]……,没有对比就没有伤害",
"Z哲[07]方块不是你生活的全部,适当走出去看看",
@@ -1124,45 +1361,27 @@ return{
"Z推[10]Phigros好玩!",
"Z推[11]VVVVVV好玩!",
"Z推[12]Ballance好玩!",
- "Z推[13]Zuma好玩!",
- "Z推[14]魔方好玩!",
- "Z推[15]15puzzle好玩!",
- "Z推[16]扫雷好玩!",
- {C.C,""},
- {C.H,"暂定段位:9"},
- {C.H,"REGRET!!"},
- {C.lC,"Xspin",C.Z,"是啥"},
+ "Z推[13]Bejeweled3好玩!",
+ "Z推[14]Zuma好玩!",
+ "Z推[15]魔方好玩!",
+ "Z推[16]15puzzle好玩!",
+ "Z推[17]扫雷好玩!",
+
+ -- 可爱!
{C.lP,"口〇口",C.Z," 可爱!"},
- {C.lP,"秘密数字:626"},
- {C.lR,"Z ",C.lG,"S ",C.lS,"J ",C.lO,"L ",C.lP,"T ",C.lY,"O ",C.lC,"I"},
+ {C.Y,"Miya",C.Z," 可爱!"},
{C.lS,"茶娘",C.Z," 可爱!"},
- {C.lY,"COOL!!"},
+ -- "Z酱 可爱!",
+
+ {C.lP,"秘密数字:626"},
{C.N,"Lua",C.Z,"天下第一"},
- {C.P,"T-spin!"},
+ {C.lR,"Z ",C.lG,"S ",C.lS,"J ",C.lO,"L ",C.lP,"T ",C.lY,"O ",C.lC,"I"},
{C.R,"《滥用DMCA》"},
{C.R,"《知识产权法》"},
{C.R,"本游戏难度上限很高,做好心理准备。"},
{C.R,"上班时间不许摸鱼打块!"},
{C.R,"上课时间不许摸鱼打块!"},
- {C.R,"DD",C.Z,"炮=",C.P,"TS",C.R,"D",C.Z,"+",C.P,"TS",C.R,"D",C.Z,"炮"},
- {C.R,"DT",C.Z,"炮=",C.P,"TS",C.R,"D",C.Z,"+",C.P,"TS",C.R,"T",C.Z,"炮"},
- {C.R,"LrL ",C.G,"RlR ",C.B,"LLr ",C.O,"RRl ",C.P,"RRR LLL ",C.C,"FFF ",C.Y,"RfR RRf rFF"},
{C.W,"uid:225238922"},
- {C.Y,"<φ> 10000"},
- {C.Y,"10000 φ"},
- {C.Y,"暂定段位:GM"},
- {C.Y,"暂定段位:M"},
- {C.Y,"暂定段位:MK"},
- {C.Y,"暂定段位:MM"},
- {C.Y,"暂定段位:MO"},
- {C.Y,"暂定段位:MV"},
- {C.Y,"Miya",C.Z," 可爱!"},
- {C.Y,"O-spin!"},
- {C.Z,"1,2,",C.C,"⑨",C.Z,"!!!!!"},
- {C.Z,"堆叠药水",C.H," 堆叠提升 (3:00)"},
- {C.Z,"挖掘药水",C.H," 挖掘提升 (8:00)"},
- {C.Z,"效率药水",C.H," 效率提升 (3:00)"},
- {C.Z,"协调药水",C.H," MD减少 II(1:30)"},
- -- "Z酱 可爱!",
- }
+ },
+ pumpkin="我是南瓜",
}
diff --git a/parts/language/lang_zh_code.lua b/parts/language/lang_zh_code.lua
new file mode 100644
index 000000000..0e95a486a
--- /dev/null
+++ b/parts/language/lang_zh_code.lua
@@ -0,0 +1,875 @@
+return {
+ loadText={
+ loadSFX="Load(SFX);",
+ loadSample="Load(Sample);",
+ loadVoice="Load(Voice);",
+ loadFont="Load(Font);",
+ loadModeIcon="Load(ModeIcon);",
+ loadMode="Load(Mode);",
+ loadOther="Load(Other);",
+ finish="PressStart();",
+ },
+ sureQuit="SureQuit();",
+ sureReset="SureReset();",
+ sureDelete="SureDelete();",
+ newDay="NewDay=true",
+ playedLong="PlayedLong=true",
+ playedTooMuch="PlayedTooMuch=true",
+ settingWarn="SettingWarn();",
+ settingWarn2="SettingWarn2();",
+
+ atkModeName={"Random();","Badges();","Kills();","Back();"},
+ royale_remain="LeftPlayers=$1",
+ powerUp={[0]="UP=.0","UP=.25","UP=.5","UP=.75","UP=1"},
+ cmb={"Combo=0","Combo=1","Combo=2","Combo=3","Combo=4","Combo=5","Combo=6","Combo=7","Combo=8","Combo=9","Combo=10","Combo=11","Combo=12","Combo=13","Combo=14","Combo=15","Combo=16","Combo=17","Combo=18","Combo=19","Combo>=20"},
+ spin="_Spin.",
+ spinNC="_Spin();",
+ clear={"Clear(1);","Clear(2);","Clear(3);","Clear(4);","Clear(5);","Clear(6);","Clear(7);","Clear(8);","Clear(9);","Clear(10);","Clear(11);","Clear(12);","Clear(13);","Clear(14);","Clear(15);","Clear(16);","Clear(17);","Clear(18);","Clear(19);","Clear(20);","Clear(20+)"},
+ cleared="",
+ mini="Mini=true",b2b="B2B.",b3b="B2B2B.",
+ PC="PC(All);",HPC="PC(Half);",
+ replaying="Replay=true",
+ tasUsing="TAS=true",
+
+ stage="StrgePass=$1",
+ great="Great();",
+ awesome="Awesome();",
+ almost="Almost();",
+ continue="Continue();",
+ maxspeed="Speed(Max);",
+ speedup="Speed(Up);",
+ missionFailed="Clear.Wrong();",
+
+ speedLV="P.SpeedLV",
+ piece="P.Piece",line="P.Line",atk="P.ATK",eff="P.EFF",
+ rpm="P.RPM",tsd="P.TSD",
+ grade="P.Grade",techrash="P.Techrash",
+ wave="P.Wave",nextWave="P.Next",
+ combo="P.Combo",maxcmb="P.MaxCombo",
+ pc="P.PC",ko="P.KO",
+
+ win="Win();",
+ lose="Lose();",
+
+ finish="Result=Finish",
+ gamewin="Result=Win",
+ gameover="Result=GameOver",
+
+ pause="Pause=true",
+ pauseCount="PauseCount",
+ finesse_ap="All.Perfect();",
+ finesse_fc="Full.Combo();",
+
+ page="Page=",
+
+ cc_fixed=" if (AI==CC and Sequence==Fixed) then Error(); end",
+ cc_swap=" if (AI==CC and Hold.Mode==Swap) then Error(); end",
+ ai_prebag=" if (AI==true and Ctm.Seq~=Tetromino) then Error(); end",
+ ai_mission=" if (AI==true and Ctm.Mission~=true) then Error(); end",
+ switchSpawnSFX="SpawnSFX=false",
+ needRestart="NeedRestart=true",
+
+ loadError_errorMode="Error(Load.$1); Error.NoMode.$2();",
+ loadError_read="Error(Load.$1); Error.ReadFailed();",
+ loadError_noFile="Error(Load.$1); Error.NoFile();",
+ loadError_other="Error(Load.$1); Error.LoadingFailed.$2();",
+ loadError_unknown="Error(Load.$1); Error.Unknown();",
+
+ saveError_duplicate="Error(Save.$1); Error.FileDuplicated();",
+ saveError_encode="Error(Save.$1); Error.Encode();",
+ saveError_other="Error(Save.$1); Error.$2();",
+ saveError_unknown="SaveError($1); Error.Unknown();",
+
+ copyDone="Copy(Done);",
+ saveDone="Save(Done);",
+ exportSuccess="Export(Success);",
+ importSuccess="Import(Success);",
+ dataCorrupted="Error.DataCorrupted();",
+ pasteWrongPlace="Error.PasteWrongPlace();",
+ noFile="Error.NoFile();",
+
+ nowPlaying="NowPlaying=",
+
+ VKTchW="VK.Weight.Touch",
+ VKOrgW="VK.Weight.Origin",
+ VKCurW="VK.Weight.CurrentPosition",
+
+ noScore="NoScore=true",
+ modeLocked="Locked=true",
+ unlockHint=" if (PreviousMode<=B) then Unlock();",
+ highScore="HighScore",
+ newRecord="NewRecord=true",
+
+ replayBroken="Error.ReplayBroken();",
+
+ dictNote="#!CopySource=Zictionary",
+
+
+
+ -- Server's warn/error messages
+ Techrater={},
+
+ tooFrequent="Error.requesttooFrequent();",
+ roomPasswordChanged="Info.roomPwChanged();",
+ oldVersion="Version.New($1);",
+ versionNotMatch="Version.NotMatch();",
+ notFinished="ComingSoon();",
+
+ noUsername="Error.NoUsername();",
+ wrongEmail="Error.WrongEmail();",
+ wrongCode="Error.WrongVerificationCode();",
+ diffPassword="Error.DiffPassword();",
+ checkEmail="register.RequestSent=true",
+
+ wsFailed="Error.Websocket.Failed=$1",
+ wsClose="Error.Websocket.Close=$1",
+ netTimeout="Error.ConnectTimeOut();",
+ serverDown="Error.ServerDown();",
+ requestFailed="Error.RequestFailed();",
+
+ onlinePlayerCount="OnlinePlayerCount=$1",
+ createRoomSuccessed="CreateRoom.Successs=true",
+ playerKicked="[$1]: roomKick([$2])",
+ -- becomeHost="$1 become host",
+ started="Room.Playing();",
+ joinRoom="Room.Join($1);",
+ leaveRoom="Room.Leave($1);",
+ roomRemoved="Room.Removed();",
+ ready="Ready();",
+ spectating="Room.Spectating();",
+
+
+
+ keySettingInstruction="Key.Bind(Press);\nKey.Bind.Cancel(Escspe);\nKey.Bind.Delete(Backspace);",
+ customBGhelp="Ctm.BG(DropHere);",
+ customBGloadFailed="Error.Ctm.BG(UnsupportFormat);",
+
+ errorMsg="Error.Fatal();\n//请检查语法错误或向作者进行反馈。",
+ tryAnotherBuild="Error.DecodeUTF8(); //如果你现在用的是Windows系统,请重新下载 Techmino-32/64位 (和现在运行的不一样的那个)。",
+
+ modInstruction="Mod.Instruction();\n/*选择你要使用的Mod\n不同Mod会用不同的方式改变初始游戏规则(可能导致不能正常游玩)\n提醒:开启一些Mod会让成绩无效,你也可以用键盘开关Mod,按住shift反向*/",
+ modInfo={
+ next="Mod.Next();\n//强制使用Next的个数",
+ hold="Mod.Hold\n//强制使用Hold的个数",
+ hideNext="Mod.HideNext();\n//隐藏前几个Next",
+ infHold="Mod.InfHold();\n//可以无限制使用Hold",
+ hideBlock="Mod.HideBlock();\n//使当前方块不可见",
+ hideGhost="Mod.HideGhost();\n//使提示阴影不可见",
+ hidden="Mod.Hidden();\n//方块将会在锁定之后隐形",
+ hideBoard="Mod.HideBoard();\n//遮挡部分或者全部场地",
+ flipBoard="Mod.FlipBoard();\n//将场地以一定方式翻转显示",
+ dropDelay="Mod.DropDelay();\n//强制使用下落速度(单位:帧/格)",
+ lockDelay="Mod.LockDelay();\n//强制使用锁定延迟(单位:帧)",
+ waitDelay="Mod.WaitDelay();\n//出块后的等待时间(单位:帧)",
+ fallDelay="Mod.FallDelay();\n//消行后的等待时间(单位:帧)",
+ life="Mod.Life();\n//修改初始生命数量",
+ forceB2B="Mod.ForceB2B();\n//B2B条掉到启动线以下就会结束游戏",
+ forceFinesse="Mod.ForceFinesse();\n//非极简操作将强制结束游戏",
+ tele="Mod.Tele();\n//强制启用0移动延迟",
+ noRotation="Mod.NoRot();\n//禁用旋转按键",
+ noMove="Mod.NoMove();\n//禁用移动按键",
+ customSeq="Mod.CtmSeq\n//强制使用某种序列",
+ pushSpeed="Mod.PushSpeed();\n//改变垃圾行升起的速度(单位:格/帧)",
+ boneBlock="Mod.Bone();\n//使用骨块进行游戏",
+ },
+ pauseStat={
+ "P.Time",
+ "P.Key/Rot/Hold",
+ "P.Pieces",
+ "P.Row/Dig",
+ "P.Atk/DAtk",
+ "P.Receive",
+ "P.Clear",
+ "P.Spin",
+ "P.B2B/B3B;P.PC/HPC",
+ "P.Finesse",
+ },
+ radar={"DEF","OFF","ATK","SEND","SPD","DIG"},
+ radarData={"D'PM","ADPM","APM","SPM","L'PM","DPM"},
+ stat={
+ "Stat.Launch = ",
+ "Stat.Count = ",
+ "Stat.Time = ",
+ "Stat.Key/Rot/Hold = ",
+ "Stat.Block/Row/Atk = ",
+ "Stat.Recv/Res/Asc = ",
+ "Stat.Dig/DAtk = ",
+ "Stat.Eff/DEff = ",
+ "Stat.B2B/B3B = ",
+ "Stat.PC/HPC = ",
+ "Stat.FErr/FRate = ",
+ },
+ aboutTexts={
+ "/*这只是一个普通的*方块游戏*",
+ "从C2/IO/JS/WWC/KOS等方块获得过灵感",
+ "",
+ "使用LÖVE引擎",
+ "错误或者建议请附带截图发送到内测群或者作者邮箱~",
+ "仅通过官网/*见主菜单词典*/ 免费下载/更新",
+ "其他渠道获得游戏皆有被修改/加广告/植入病毒的风险,程序只申请了振动&联网权限!",
+ "若由于被修改的本游戏产生的各种损失作者不负责(怎么负责啊我又没法管)",
+ FNNS and "/" or "请从正规途径获得最新版,游戏现为免费,不过有打赏当然感谢啦~",
+ FNNS and "/" or "更多信息见小z词典*/",
+ },
+ staff={
+ "原作者 MrZ",
+ "邮箱: 1046101471@qq.com",
+ "",
+ "程序, 开发和设计",
+ "MrZ",
+ "",
+ "音乐制作使用",
+ "Beepbox",
+ "FL Studio",
+ "FL Mobile",
+ "Logic Pro X",
+ "",
+ "[POWERED BY LÖVE]",
+ "",
+ "程序",
+ "MrZ",
+ "ParticleG",
+ "Gompyn",
+ "Trebor",
+ "(scdhh)",
+ "(FinnTenzor)",
+ "(NOT_A_ROBOT)",
+ "(user670)",
+ "",
+ "GitHub CI、封装和后端",
+ "ParticleG",
+ "Trebor",
+ "LawrenceLiu",
+ "Gompyn",
+ "flaribbit",
+ "schh",
+ "",
+ "视觉设计、UI和UX",
+ "MrZ",
+ "Gnyar",
+ "C₂₉H₂₅N₃O₅",
+ "ScF",
+ "(旋律星萤)",
+ "(T0722)",
+ "",
+ "插图",
+ "Miya",
+ "Mono",
+ "Xiaoya",
+ "葉枭",
+ "",
+ "音乐设计",
+ "MrZ",
+ "柒栎流星",
+ "ERM",
+ "Trebor",
+ "C₂₉H₂₅N₃O₅",
+ "(T0722)",
+ "(Aether)",
+ "(Hailey)",
+ "",
+ "音效和语音包",
+ "Miya",
+ "Xiaoya",
+ "Mono",
+ "MrZ",
+ "Trebor",
+ "",
+ "翻译和本地化",
+ "User670",
+ "MattMayuga",
+ "Mizu",
+ "Mr.Faq",
+ "ScF",
+ "C₂₉H₂₅N₃O₅",
+ "NOT_A_ROBOT",
+ "XMiao",
+ "sakurw, Airun, 幽灵3383",
+ "Shard Nguyễn, Squishy and TVN community",
+ "",
+ "演出",
+ "Electric283",
+ "Hebomai",
+ "",
+ "特别感谢",
+ "Flyz",
+ "Big_True",
+ "NOT_A_ROBOT",
+ "思竣",
+ "yuhao7370",
+ "Farter",
+ "Teatube",
+ "蕴空之灵",
+ "T9972",
+ "No-Usernam8",
+ "andrew4043",
+ "smdbs-smdbs",
+ "paoho",
+ "Allustrate",
+ "Haoran SUN",
+ "Tianling Lyu",
+ "huaji2369",
+ "Lexitik",
+ "Tourahi Anime",
+ "[All other test staff]",
+ "…And You!",
+ },
+ used=[[
+ Used.Tools=
+ Beepbox
+ Goldwave
+ GFIE
+ FL Mobile
+ Used.Libs=
+ Cold_Clear [MinusKelvin]
+ json.lua [rxi]
+ profile.lua [itraykov]
+ sha2 [Egor Skriptunoff]
+ ]],
+ support="支持作者",
+ WidgetText={
+ main={
+ offline="PlaySingle();",
+ qplay="QPlay.",
+ online="PlayMulti();",
+ custom="PlayCtm();",
+ setting="GameSettings();",
+ stat="GameStat();",
+ dict="Zictionary();",
+ replays="GameReplay();",
+ },
+ main_simple={
+ sprint="Play.Sprint(40L);",
+ marathon="Play.Marathon();",
+ },
+ mode={
+ mod="Mod(); (F1)",
+ start="Play();",
+ },
+ mod={
+ title="GameMod.UI",
+ reset="Mod.Reset();",
+ unranked="unranked=true",
+ },
+ pause={
+ setting="Settings(); (S)",
+ replay="Replay(Play); (P)",
+ save="Replay(Save); (O)",
+ resume="Resume(); (Esc)",
+ restart="Restart(); (R)",
+ quit="Return 0; (Q)",
+ tas="TAS(); (T)",
+ },
+ net_menu={
+ league="M.TechLeague();",
+ ffa="M.FFA",
+ rooms="M.Rooms();",
+ resetPW="M.ResetPW",
+ logout="M.Logout();",
+ },
+ net_league={
+ match="TL.Match();",
+ },
+ net_rooms={
+ password="Password=",
+ refreshing="Refrishing();",
+ noRoom="NoRoom=true",
+ refresh="Refresh();",
+ new="NewRoom();",
+ join="Join();",
+ },
+ net_newRoom={
+ title="NewRoom.UI",
+ roomName="RoomName //Default = [username]'s room",
+ password="Password",
+ description="Description",
+
+ life="Life",
+ pushSpeed="PushSpeed",
+ garbageSpeed="GarbageSpeed",
+ visible="Visiblity",
+ freshLimit="FreshLimit",
+
+ fieldH="FieldHeight",
+ bufferLimit="BufferLimit",
+ heightLimit="HeightLimit",
+
+ drop="DropDelay",
+ lock="LockDelay",
+ wait="EntryDelay",
+ fall="LineDelay",
+ hang="DeathDelay",
+ hurry="AREInterruption",
+
+ capacity="Capacity",
+ create="Create();",
+
+ ospin="OSpin",
+ fineKill="FineKill",
+ b2bKill="B2BKill",
+ lockout="Lockout",
+ easyFresh="EZFresh",
+ deepDrop="DeepDrop",
+ bone="Bone",
+
+ eventSet="EventSet",
+
+ holdMode="HoldMode",
+ nextCount="Next=",
+ holdCount="Hold=",
+ infHold="InfHold",
+ phyHold="PhyHold",
+ },
+ net_game={
+ ready="Ready();",
+ spectate="Spectate();",
+ cancel="Cancel();",
+ },
+ setting_game={
+ title="GameSettings.UI",
+ graphic="←Set.Video();",
+ sound="Set.Sound();→",
+ style="Style();",
+
+ ctrl="Set.Ctrl();",
+ key="Set.Key();",
+ touch="Set.Touch();",
+ showVK="Set.ShowVK",
+ reTime="Set.ReTime=",
+ RS="Set.RS",
+ menuPos="Set.MenuPos",
+ sysCursor="Set.SysCursor",
+ autoPause="Set.AutoPause",
+ autoSave="Set.AutoSave",
+ simpMode="Set.SimpMode",
+ },
+ setting_video={
+ title="VideoSettings.UI",
+ sound="←Set.Sound();",
+ game="Set.Game();→",
+
+ block="Set.DrawBlock",
+ smooth="Set.SmoothFall",
+ upEdge="Set.UpEdge",
+ bagLine="Set.BagLine",
+
+ ghostType="Set.GhostType",
+ ghost="Set.Ghost=",
+ center="Set.Center=",
+ grid="Set.Grid=",
+ lineNum="Set.LineNum=",
+
+ lockFX="Set.LockFX=",
+ dropFX="Set.DropFX=",
+ moveFX="Set.MoveFX=",
+ clearFX="Set.ClearFX=",
+ splashFX="Set.SplashFX=",
+ shakeFX="Set.ShakeFX=",
+ atkFX="Set.AtkFX=",
+
+ frame="Set.Frame //\"%\"",
+
+ text="Set.TextPU",
+ score="Set.ScorePU",
+ bufferWarn="Set.BufferWarn",
+ showSpike="Set.ShowSpike",
+ nextPos="Set.NextPos",
+ highCam="Set.HighCam",
+ warn="Set.Warn",
+
+ clickFX="Set.ClickFX",
+ power="Set.Battery",
+ clean="Set.QuickDraw",
+ fullscreen="Set.Fullscreen",
+ portrait="Set.Portrait",
+ msaa="Set.MSAA",
+
+ bg_on="Set.BG(Normal);",
+ bg_off="Set.BG(Off);",
+ bg_custom="Set.BG(Ctm);",
+
+ blockSatur="Set.BlockSatur",
+ fieldSatur="Set.FieldSatur",
+ },
+ setting_sound={
+ title="MusicSettings.UI",
+ game="←Set.Game();",
+ graphic="Set.Video();→",
+
+ mainVol="Set.MainVol=",
+ bgm="Set.BGM=",
+ sfx="Set.SFX=",
+ stereo="Set.Stereo=",
+ spawn="Set.SpawnSFX=",
+ warn="Set.WarnSFX=",
+ vib="Set.VIB=",
+ voc="Set.VOC=",
+
+ autoMute="Set.AutoMute",
+ fine="Set.FineErrSFX",
+ sfxPack="Set.SFXPack",
+ vocPack="Set.VOCPack",
+ apply="Set.Apply();",
+ },
+ setting_control={
+ title="CtrlSettings.UI",
+ preview="Set.Preview();",
+
+ das="Set.DAS=",arr="Set.SRR=",
+ dascut="Set.DASCut=",
+ dropcut="Set.DropCut=",
+ sddas="Set.SDDAS=",sdarr="Set.SDARR=",
+ ihs="Set.IHS",
+ irs="Set.IRS",
+ ims="Set.IMS",
+ reset="Set.Reset();",
+ },
+ setting_key={
+ a1="SK.MLeft();",
+ a2="SK.MRight();",
+ a3="SK.RRight();",
+ a4="SK.RLeft();",
+ a5="SK.R180();",
+ a6="SK.HDrop();",
+ a7="SK.SDrop();",
+ a8="SK.Hold();",
+ a9="SK.Function1();",
+ a10="SK.Function2();",
+ a11="SK.ILeft();",
+ a12="SK.IRight();",
+ a13="SK.SonicDrop();",
+ a14="SK.Down1();",
+ a15="SK.Down4();",
+ a16="SK.Down10();",
+ a17="SK.LDrop();",
+ a18="SK.RDrop();",
+ a19="SK.LZangi();",
+ a20="SK.RZangi();",
+ restart="SK.Restart();",
+ },
+ setting_skin={
+ skinSet="Set.SkinSet",
+ title="StyleSettings.UI",
+ skinR="Set.RColor();",
+ faceR="Set.RDir();",
+ },
+ setting_touch={
+ default="Set.Default();",
+ snap="Set.Snap();",
+ size="Set.Size=",
+ shape="Set.Shape();",
+ },
+ setting_touchSwitch={
+ b1="ST.MLeft", b2="ST.MRight", b3="ST.RRight", b4="ST.RLeft",
+ b5="ST.R180", b6="ST.HDrop", b7="ST.SDrop", b8="ST.Hold",
+ b9="ST.Function1", b10="ST.Function2", b11="ST.ILeft", b12="ST.IRight",
+ b13="ST.SonicDrop", b14="ST.Down1", b15="ST.Down4", b16="ST.Down10",
+ b17="ST.LDrop", b18="ST.RDrop", b19="ST.LZangi", b20="ST.RZangi",
+
+ norm="Set.Norm();",
+ pro="Set.Pro();",
+ icon="Set.Icon",
+ sfx="Set.SFX=",
+ vib="Set.VIB=",
+ alpha="Set.Alpha=",
+
+ track="Set.AutoTrack",
+ dodge="Set.AutoDodge",
+ },
+ customGame={
+ title="CtmGame.UI",
+ defSeq="DefSeq=true",
+ noMsn="NoMsn=true",
+
+ drop="DropDelay",
+ lock="LockDelay",
+ wait="EntryDelay",
+ fall="LineDelay",
+ hang="DeathDelay",
+ hurry="AREInterruption",
+
+ bg="BG",
+ bgm="BGM",
+
+ copy="Copy.All();",
+ paste="Paste.All();",
+ play_clear="Play.Ctm(Clear);",
+ play_puzzle="Play.Ctm(Puzzle);",
+
+ reset="Reset(); (del)",
+ advance="Advance(); (A)",
+ mod="Mod(); (F1)",
+ field="Edit.Field(); (F)",
+ sequence="Edit.Seq(); (S)",
+ mission="Edit.Mission(); (M)",
+
+ eventSet="EventSet",
+
+ holdMode="HoldMode",
+ nextCount="Next=",
+ holdCount="Hold=",
+ infHold="InfHold",
+ phyHold="PhyHold",
+
+ fieldH="FieldHeight",
+ visible="Visiblity",
+ freshLimit="FreshLimit",
+ opponent="Bot",
+ life="Life",
+ pushSpeed="PushSpeed",
+ garbageSpeed="GarbargeSpeed",
+
+ bufferLimit="BufferLimit",
+ heightLimit="HeightLimit",
+ ospin="Ospin",
+ fineKill="FineKill",
+ b2bKill="B2BKill",
+ lockout="Lockout",
+ easyFresh="EZFresh",
+ deepDrop="DeepDrop",
+ bone="Bone",
+ },
+ custom_field={
+ title="CtmGame.Field.UI",
+ subTitle="",
+
+ any="Erase();",
+ smart="Smart();",
+
+ push="Add(); (K)",
+ del="Del(); (L)",
+
+ demo="Show\"×\"",
+
+ newPg="NewPG(); (N)",
+ delPg="DelPG(); (M)",
+ prevPg="PrevPG();",
+ nextPg="NextPG();",
+ },
+ custom_sequence={
+ title="CtmGame.Seq.UI",
+ subTitle="",
+ sequence="Sequence",
+ },
+ custom_mission={
+ title="CtmGame.Mission.UI",
+ subTitle="",
+
+ _1="1",_2="2",_3="3",_4="4",
+ any1="any1",any2="any2",any3="any3",any4="any4",
+ PC="PC",
+ Z1="Z1",S1="S1",J1="J1",L1="L1",T1="T1",O1="O1",I1="I1",
+ Z2="Z2",S2="S2",J2="J2",L2="L2",T2="T2",O2="O2",I2="I2",
+ Z3="Z3",S3="S3",J3="J3",L3="L3",T3="T3",O3="O3",I3="I3",
+ O4="O4",I4="I4",
+ mission="Force",
+ },
+ music={
+ title="Music.UI",
+ arrow="→",
+ now="NowPlaying=",
+
+ bgm="BGM",
+ sound="SFX();",
+ },
+ launchpad={
+ title="SFX.UI",
+ bgm="BGM",
+ sfx="SFX",
+ voc="VOC",
+ music="Music();",
+ label="Label",
+ },
+ about={
+ staff="Staff();",
+ his="History();",
+ legals="Leagls();",
+ },
+ dict={
+ title="Zictionary.UI",
+ },
+ stat={
+ path="OpenPath();",
+ save="DataManagement();",
+ },
+ login={
+ title="SignIn.UI",
+ ticket="Ticket=",
+ authorize="Authorize();",
+ paste="Paste();",
+ submit="Submit();",
+ },
+ reset_password={
+ title="Reset_Password.UI",
+ send="Send();",
+ code="V-code=",
+ password="Password=",
+ password2="RePassword=",
+ setPW="SetPassword();",
+ },
+ account={
+ title="Account.UI",
+ },
+ app_15p={
+ color="Color",
+ invis="Invis",
+ slide="Slide",
+ pathVis="PathVis",
+ revKB="PrvKB",
+ },
+ app_schulteG={
+ rank="Rank=",
+ invis="Invis",
+ disappear="Disappsar",
+ tapFX="TapFX",
+ },
+ app_AtoZ={
+ level="Level",
+ keyboard="Keyboard();",
+ },
+ app_2048={
+ invis="Invis",
+ tapControl="TapCtrl",
+
+ skip="Skip();",
+ },
+ app_ten={
+ next="Next",
+ invis="Invis",
+ fast="Fast",
+ },
+ app_dtw={
+ color="Color",
+ mode="Mode",
+ bgm="BGM",
+ arcade="Arcade",
+ },
+ app_link={
+ invis="Invis",
+ },
+ savedata={
+ export="Data.Export",
+ import="Data.Import",
+ unlock="Progress();",
+ data="Stat();",
+ setting="Setting();",
+ vk="VK();",
+
+ couldSave="Data.Cloud //Testing",
+ notLogin="NotLogin=true",
+ upload="UpLoad();",
+ download="DownLoad();",
+ },
+ },
+ modes={
+ ['sprint_10l']= {"Sprint(10L);", "", "消除10行"},
+ ['sprint_20l']= {"Sprint(20L);", "", "消除20行"},
+ ['sprint_40l']= {"Sprint(40L);", "", "消除40行"},
+ ['sprint_100l']= {"Sprint(100L);", "", "消除100行"},
+ ['sprint_400l']= {"Sprint(400L);", "", "消除400行"},
+ ['sprint_1000l']= {"Sprint(1000L);", "", "消除1000行"},
+ ['secret_grade']= {"SecretGrade();", "", "按照提示完成经典的“大于号”拼图"},
+ ['sprintPenta']= {"Sprint(Penta);", "", "伤脑筋十八块"},
+ ['sprintMPH']= {"Sprint(MPH);", "", "纯随机\n无预览\n无暂存"},
+ ['sprint123']= {"Sprint(M123);", "", "40L,但只有1~3连块"},
+ ['dig_10l']= {"Dig(10L);", "", "挖掘10行"},
+ ['dig_40l']= {"Dig(40L);", "", "挖掘40行"},
+ ['dig_100l']= {"Dig(100L);", "", "挖掘100行"},
+ ['dig_400l']= {"Dig(400L);", "", "挖掘400行"},
+ ['dig_eff_10l']= {"DigEff(10L);", "", "用尽量少的块数挖掘10行"},
+ ['dig_eff_40l']= {"DigEff(40L);", "", "用尽量少的块数挖掘40行"},
+ ['dig_eff_100l']= {"DigEff(100L);", "", "用尽量少的块数挖掘100行"},
+ ['dig_eff_400l']= {"DigEff(400L);", "", "用尽量少的块数挖掘400行"},
+ ['dig_quad_10l']= {"DigQuad(10L);", "", "挖掘10行,但只能消四"},
+ ['drought_n']= {"Drought(100L);", "", "你I没了"},
+ ['drought_l']= {"DroughtP(100L);", "", "后 妈 发 牌"},
+ ['marathon_n']= {"Marathon(Normal);", "", "200行加速马拉松"},
+ ['marathon_h']= {"Marathon(Hard);", "", "200行高速马拉松"},
+ ['solo_e']= {"Solo(Easy);", "", "打败AI"},
+ ['solo_n']= {"Solo(Normal);", "", "打败AI"},
+ ['solo_h']= {"Solo(Hard);", "", "打败AI"},
+ ['solo_l']= {"Solo(Lunatic);", "", "打败AI"},
+ ['solo_u']= {"Solo(Ultimate);", "", "打败AI"},
+ ['techmino49_e']= {"Tech49(Easy);", "", "49人混战,活到最后"},
+ ['techmino49_h']= {"Tech49(Hard);", "", "49人混战,活到最后"},
+ ['techmino49_u']= {"Tech49(Ultimate);", "", "49人混战,活到最后"},
+ ['techmino99_e']= {"Tech99(Easy);", "", "99人混战,活到最后"},
+ ['techmino99_h']= {"Tech99(Hard);", "", "99人混战,活到最后"},
+ ['techmino99_u']= {"Tech99(Ultimate);", "", "99人混战,活到最后"},
+ ['round_e']= {"Round(Easy);", "", "下棋模式"},
+ ['round_n']= {"Round(Normal);", "", "下棋模式"},
+ ['round_h']= {"Round(Hard);", "", "下棋模式"},
+ ['round_l']= {"Round(Lunatic);", "", "下棋模式"},
+ ['round_u']= {"Round(Ultimate);", "", "下棋模式"},
+ ['big_n']= {"Big(Normal);", "", "模拟10*5场地的玩法(标准尺寸的一半)"},
+ ['big_h']= {"Big(Hard);", "", "模拟10*5场地的玩法(标准尺寸的一半)"},
+ ['master_n']= {"Master(Normal);", "", "20G初心者练习"},
+ ['master_h']= {"Master(Hard);", "", "上级者20G挑战"},
+ ['master_m']= {"Master(M21);", "", "大师20G"},
+ ['master_final']= {"Master(Final);", "", "究极20G:无法触及的终点"},
+ ['master_ph']= {"Master(Phantasm);", "", "虚幻20G:???"},
+ ['master_g']= {"Master(Graded);", "", "20G段位考试"},
+ ['master_ex']= {"Master(EX);", "", "成为方块大师"},
+ ['master_instinct']={"Master(Instinct);", "", "当前块在出现后一小会后会隐形"},
+ ['strategy_e']= {"Strategy(Easy);", "", "20G堆叠中速决策练习"},
+ ['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(Half);", "", "不强大脑"},
+ ['blind_n']= {"Blind(All);", "", "挺强大脑"},
+ ['blind_h']= {"Blind(Sudden);", "", "很强大脑"},
+ ['blind_l']= {"Blind(SuddenP);", "", "最强大脑"},
+ ['blind_u']= {"Blind(What);", "", "你准备好了吗"},
+ ['blind_wtf']= {"Blind(WTF);" , "", "还没准备好"},
+ ['classic_e']= {"Classic(Easy);", "", "高速经典"},
+ ['classic_h']= {"Classic(Hard);", "", "飞速经典"},
+ ['classic_l']= {"Classic(Lunatic);", "", "极速经典"},
+ ['classic_u']= {"Classic(Ultimate);", "", "光速经典"},
+ ['survivor_e']= {"Surviver(Easy);", "", "你能存活多久?"},
+ ['survivor_n']= {"Surviver(Normal);", "", "你能存活多久?"},
+ ['survivor_h']= {"Surviver(Hard);", "", "你能存活多久?"},
+ ['survivor_l']= {"Surviver(Lunatic);", "", "你能存活多久?"},
+ ['survivor_u']= {"Surviver(Ultimate);", "", "你能存活多久?"},
+ ['attacker_h']= {"Attacker(Hard);", "", "进攻练习"},
+ ['attacker_u']= {"Attacker(Ultimate);", "", "进攻练习"},
+ ['defender_n']= {"Defender(Normal);", "", "防守练习"},
+ ['defender_l']= {"Defender(Lunatic);", "", "防守练习"},
+ ['dig_h']= {"Dig(Hard);", "", "挖掘练习"},
+ ['dig_u']= {"Dig(Ultimate);", "", "挖掘练习"},
+ ['c4wtrain_n']= {"C4WTrain(Normal);", "", "无 限 连 击"},
+ ['c4wtrain_l']= {"C4WTrain(Lunatic);", "", "无 限 连 击"},
+ ['pctrain_n']= {"PCTrain(Normal);", "", "简易PC题库,熟悉全清定式的组合"},
+ ['pctrain_l']= {"PCTrain(Lunatic);", "", "困难PC题库,强算力者进"},
+ ['pc_n']= {"PC(Normal);", "", "100行内刷PC"},
+ ['pc_h']= {"PC(Hard);", "", "100行内刷PC"},
+ ['pc_l']= {"PC(Lunatic);", "", "100行内刷PC"},
+ ['pc_inf']= {"PC(Inf);", "", "你能连续做多少PC?"},
+ ['tech_n']= {"Tech(Normal);", "", "禁止断B2B"},
+ ['tech_n_plus']= {"Tech(NormalP);", "", "仅允许spin与PC"},
+ ['tech_h']= {"Tech(Hard);", "", "禁止断B2B"},
+ ['tech_h_plus']= {"Tech(HardP);", "", "仅允许spin与PC"},
+ ['tech_l']= {"Tech(Lunatic);", "", "禁止断B2B"},
+ ['tech_l_plus']= {"Tech(LunaticP);", "", "仅允许spin与PC"},
+ ['tech_finesse']= {"Tech(Finesse);", "", "强制最简操作"},
+ ['tech_finesse_f']= {"Tech(FinesseF);", "", "禁止普通消除,强制最简操作"},
+ ['tsd_e']= {"TSD(Easy);", "", "你能连续做几个TSD?"},
+ ['tsd_h']= {"TSD(Hard);", "", "你能连续做几个TSD?"},
+ ['tsd_u']= {"TSD(Ultimate);", "", "你能连续做几个TSD?"},
+ ['backfire_n']= {"Backfire(Normal);", "", "打出100攻击"},
+ ['backfire_h']= {"Backfire(Hard);", "", "打出100攻击"},
+ ['backfire_l']= {"Backfire(Lunatic);", "", "打出100攻击"},
+ ['backfire_u']= {"Backfire(Ultimate);", "", "打出100攻击"},
+ ['sprintAtk']= {"Sprint(100ATK);", "", "打出100攻击"},
+ ['sprintEff']= {"Sprint(EFF);", "", "40行内打出更高的攻击"},
+ ['zen']= {"Zen(200L);", "", "不限时200行"},
+ ['ultra']= {"Ultra(EXTRA);", "", "在两分钟内尽可能拿到最多的分数"},
+ ['infinite']= {"Infinite();", "", "沙盒"},
+ ['infinite_dig']= {"InfDig();", "", "挖呀挖呀挖"},
+ ['marathon_inf']= {"Marathon(Inf);", "", "无尽马拉松"},
+
+ ['custom_clear']= {"Ctm(Clear);", ""},
+ ['custom_puzzle']= {"Ctm(Puzzle);", ""},
+ },
+}
diff --git a/parts/language/lang_zh_full.lua b/parts/language/lang_zh_full.lua
deleted file mode 100644
index a6a856a1a..000000000
--- a/parts/language/lang_zh_full.lua
+++ /dev/null
@@ -1,184 +0,0 @@
-return{
- cmb={nil,"1连击","2连击","3连击","4连击","5连击","6连击","7连击","8连击","9连击","10连击!","11连击!","12连击!","13连击!","14连击!","15连击!","16连击!","17连击!","18连击!","19连击!","巨型连击"},
- spin="型回旋",
- clear={"单清","双清","三清","四清","五清","六清","七清","八清","九清","十清","十一清","十二清","十三清","十四清","十五清","十六清","十七清","十八清","十九清","二十清","超二十清"},
- cleared="",
- mini="迷你",b2b="满贯",b3b="大满贯",
- PC="场地全清",HPC="场地半清",
-
- great="不错!",
- awesome="精彩。",
- almost="差一点!",
- continue="继续。",
-
- speedLV="速度等级",
- piece="块数",line="行数",atk="攻击",eff="效率",
- rpm="收每分",tsd="T2",
- grade="段位",techrash="消四",
- wave="波数",nextWave="下一波",
- combo="连击",maxcmb="最大连击",
- pc="全清",ko="淘汰",
-
- finesse_ap="完美极简",
- finesse_fc="全连击",
-
- cc_fixed="不能同时开启CC和固定序列",
- cc_swap="不能同时开启CC和swap的暂存模式",
- ai_prebag="不能同时开启电脑玩家和含有非四连块的自定义序列",
- ai_mission="不能同时开启电脑玩家和自定义任务",
-
- modInstruction="选择你要使用的模组!\n不同的模组会用不同的方式改变游戏规则,来开发新玩法挑战自我吧!\n提醒:开启一些模组会让成绩无效 你可以用键盘开关模组,按tab重置",
- modInfo={
- next="预览数量:\n强制使用预览的个数",
- hold="暂存数量:\n强制使用暂存的个数",
- hideNext="隐藏预览:\n隐藏前几个预览",
- infHold="无限暂存:\n可以无限制使用暂存",
- forceB2B="强制满贯:\n满贯点数条掉到启动线以下就会结束游戏",
- },
- pauseStat={
- "时间:",
- "按键/旋转/暂存:",
- "落块:",
- "消行/挖掘:",
- "攻击/挖掘攻击:",
- "上涨/接收/抵消:",
- "消除:",
- "回旋:",
- "(大)满贯/全(半)清:",
- "非极简操作:",
- },
- radar={"防","守","攻","送","速","挖"},
- radarData={"防/分","守/分","攻/分","送/分","行/分","挖/分"},
- WidgetText={
- mode={
- mod="模组(F1)",
- },
- mod={
- title="模组",
- },
- net_newRoom={
- ospin="O旋",
- holdMode="暂存模式",
- nextCount="预览个数",
- holdCount="暂存个数",
- infHold="无限暂存",
- phyHold="物理暂存",
- },
- setting_control={
- das="首次移动延迟",arr="移动重复延迟",
- sddas="首次软降延迟",sdarr="软降重复延迟",
- ihs="提前暂存",
- },
- customGame={
- mod="模组(F1)",
-
- ospin="O旋",
- holdMode="暂存模式",
- nextCount="预览个数",
- holdCount="暂存个数",
- infHold="无限暂存",
- phyHold="物理暂存",
- },
- },
- modes={
- ['sprint_10l']= {"竞速", "10行", "消除10行"},
- ['sprint_20l']= {"竞速", "20行", "消除20行"},
- ['sprint_40l']= {"竞速", "40行", "消除40行"},
- ['sprint_100l']= {"竞速", "100行", "消除100行"},
- ['sprint_400l']= {"竞速", "400行", "消除400行"},
- ['sprint_1000l']= {"竞速", "1000行", "消除1000行"},
- ['sprintPenta']= {"竞速", "五连块", "伤脑筋十八块"},
- ['sprintMPH']= {"竞速", "纯净", "纯随机\n无预览\n无暂存"},
- ['dig_10l']= {"挖掘", "10L", "挖掘10行"},
- ['dig_40l']= {"挖掘", "40L", "挖掘40行"},
- ['dig_100l']= {"挖掘", "100L", "挖掘100行"},
- ['dig_400l']= {"挖掘", "400L", "挖掘400行"},
- ['drought_n']= {"干旱", "100行", "你I没了"},
- ['drought_l']= {"干旱+", "100行", "后 妈 发 牌"},
- ['marathon_n']= {"马拉松", "普通", "200行加速马拉松"},
- ['marathon_h']= {"马拉松", "困难", "200行高速马拉松"},
- ['solo_e']= {"单挑", "简单", "打败机器人"},
- ['solo_n']= {"单挑", "普通", "打败机器人"},
- ['solo_h']= {"单挑", "困难", "打败机器人"},
- ['solo_l']= {"单挑", "疯狂", "打败机器人"},
- ['solo_u']= {"单挑", "极限", "打败机器人"},
- ['techmino49_e']= {"49人混战", "简单", "49人混战,活到最后"},
- ['techmino49_h']= {"49人混战", "困难", "49人混战,活到最后"},
- ['techmino49_u']= {"49人混战", "极限", "49人混战,活到最后"},
- ['techmino99_e']= {"99人混战", "简单", "99人混战,活到最后"},
- ['techmino99_h']= {"99人混战", "困难", "99人混战,活到最后"},
- ['techmino99_u']= {"99人混战", "极限", "99人混战,活到最后"},
- ['round_e']= {"回合制", "简单", "下棋模式"},
- ['round_n']= {"回合制", "普通", "下棋模式"},
- ['round_h']= {"回合制", "困难", "下棋模式"},
- ['round_l']= {"回合制", "疯狂", "下棋模式"},
- ['round_u']= {"回合制", "极限", "下棋模式"},
- ['master_n']= {"大师", "普通", "20G初心者练习"},
- ['master_h']= {"大师", "困难", "上级者20G挑战"},
- ['master_m']= {"大师", "大师", "大师20G"},
- ['master_final']= {"大师", "终点", "究极20G:无法触及的终点"},
- ['master_ph']= {"大师", "虚幻", "虚幻20G:???"},
- ['master_ex']= {"宗师", "EX", "成为方块大师"},
- ['master_instinct']={"大师", "本能", "隐藏当前块"},
- ['strategy_e']= {"策略堆叠", "简单", "20G堆叠中速决策练习"},
- ['strategy_h']= {"策略堆叠", "困难", "20G堆叠快速决策练习"},
- ['strategy_u']= {"策略堆叠", "极限", "20G堆叠极速决策练习"},
- ['strategy_e_plus']={"策略堆叠", "简单+", "20G堆叠中速决策练习"},
- ['strategy_h_plus']={"策略堆叠", "困难+", "20G堆叠快速决策练习"},
- ['strategy_u_plus']={"策略堆叠", "极限+", "20G堆叠极速决策练习"},
- ['blind_e']= {"隐形", "半隐", "不强大脑"},
- ['blind_n']= {"隐形", "全隐", "挺强大脑"},
- ['blind_h']= {"隐形", "瞬隐", "很强大脑"},
- ['blind_l']= {"隐形", "瞬隐+", "超强大脑"},
- ['blind_u']= {"隐形", "啊这", "你准备好了吗"},
- ['blind_wtf']= {"隐形", "不会吧", "还没准备好"},
- ['classic_e']= {"高速经典", "简单", "高速经典"},
- ['classic_h']= {"高速经典", "困难", "飞速经典"},
- ['classic_u']= {"高速经典", "极限", "极速经典"},
- ['survivor_e']= {"生存", "简单", "你能存活多久?"},
- ['survivor_n']= {"生存", "普通", "你能存活多久?"},
- ['survivor_h']= {"生存", "困难", "你能存活多久?"},
- ['survivor_l']= {"生存", "疯狂", "你能存活多久?"},
- ['survivor_u']= {"生存", "极限", "你能存活多久?"},
- ['attacker_h']= {"进攻", "困难", "进攻练习"},
- ['attacker_u']= {"进攻", "极限", "进攻练习"},
- ['defender_n']= {"防守", "普通", "防守练习"},
- ['defender_l']= {"防守", "疯狂", "防守练习"},
- ['dig_h']= {"挖掘", "困难", "挖掘练习"},
- ['dig_u']= {"挖掘", "极限", "挖掘练习"},
- ['clearRush']= {"清版竞速", "普通", "所有块的回旋入门\n还没做好"},
- ['c4wtrain_n']= {"中四宽练习", "普通", "无 限 连 击"},
- ['c4wtrain_l']= {"中四宽练习", "疯狂", "无 限 连 击"},
- ['pctrain_n']= {"全清训练", "普通", "简易全清题库,熟悉全清定式的组合"},
- ['pctrain_l']= {"全清训练", "疯狂", "困难全清题库,强算力者进"},
- ['pc_n']= {"全清挑战", "普通", "100行内刷全清"},
- ['pc_h']= {"全清挑战", "困难", "100行内刷全清"},
- ['pc_l']= {"全清挑战", "疯狂", "100行内刷全清"},
- ['pc_inf']= {"无尽全清挑战", "", "你能连续做多少全清?"},
- ['tech_n']= {"科研", "普通", "禁止断满贯"},
- ['tech_n_plus']= {"科研", "普通+", "仅允许回旋与全清"},
- ['tech_h']= {"科研", "困难", "禁止断满贯"},
- ['tech_h_plus']= {"科研", "困难+", "仅允许回旋与全清"},
- ['tech_l']= {"科研", "疯狂", "禁止断满贯"},
- ['tech_l_plus']= {"科研", "疯狂+", "仅允许回旋与全清"},
- ['tech_finesse']= {"科研", "极简", "强制最简操作"},
- ['tech_finesse_f']= {"科研", "极简+", "禁止普通消除,强制最简操作"},
- ['tsd_e']= {"T2挑战", "简单", "你能连续做几个T旋双清?"},
- ['tsd_h']= {"T2挑战", "困难", "你能连续做几个T旋双清?"},
- ['tsd_u']= {"T2挑战", "极限", "你能连续做几个T旋双清?"},
- ['backfire_n']= {"自攻自防", "普通", "打出100攻击"},
- ['backfire_h']= {"自攻自防", "困难", "打出100攻击"},
- ['backfire_l']= {"自攻自防", "疯狂", "打出100攻击"},
- ['backfire_u']= {"自攻自防", "极限", "打出100攻击"},
- ['sprintAtk']= {"竞速", "100攻击", "打出100攻击"},
- ['sprintEff']= {"竞速", "效率", "40行内打出更高的攻击"},
- ['zen']= {"禅", "200", "不限时200行"},
- ['ultra']= {"限时打分", "挑战", "在两分钟内尽可能拿到最多的分数"},
- ['infinite']= {"无尽", "", "沙盒"},
- ['infinite_dig']= {"无尽:挖掘", "", "挖呀挖呀挖"},
- ['marathon_inf']= {"马拉松", "无尽", "无尽马拉松"},
-
- ['custom_clear']= {"自定义", "普通"},
- ['custom_puzzle']= {"自定义", "拼图"},
- },
-}
diff --git a/parts/language/lang_zh_grass.lua b/parts/language/lang_zh_grass.lua
deleted file mode 100644
index d3a9ad27e..000000000
--- a/parts/language/lang_zh_grass.lua
+++ /dev/null
@@ -1,854 +0,0 @@
-return{
- fallback='zh',
- loadText={
- loadSFX="加载音效",
- loadSample="装载仪器样品",
- loadVoice="加载语音包",
- loadFont="加载字体",
- loadModeIcon="加载模式图标",
- loadMode="加载方式",
- loadOther="加载其他资产",
- finish="按任意按钮开始!",
- },
- sureQuit="再次按退出",
- sureReset="再次按下可重置",
- sureDelete="再次按可删除",
- newDay="新的一天,新的开始!",
- playedLong="你已经玩了很长时间了。一定要好好休息!",
- playedTooMuch="你玩得太久了!玩方块游戏很有趣,但现在是休息的时候了。",
- settingWarn="修改设置时,请小心!",
-
- atkModeName={"随机的","徽章","击败","攻击者"},
- royale_remain="剩余$1球员",
- powerUp={[0]="+000%","+025%","+050%","+075%","+100%"},
- cmb={nil,"1连击","2连击","3连击","4连击","5连击","6连击","7连击","8连击","9连击","10连击!","11连击!","12连击!","13连击!","14连击!","15连击!","16连击!","17连击!","18连击!","19连击!","巨大连击"},
- spin="-旋转",
- clear={"单身的","双重的","三倍的","技术崩溃","五角碰撞","六面体碎裂","七冲击","八度碰撞","非碰撞","十点崩溃","不祥","十二面体碰撞","三十年代的崩溃","十四烷","十五烷碰撞","十六进制","七烷酸","十八进制崩溃","非十进制碰撞","超级崩溃","冒牌货"},
- cleared="$1 线",
- mini="迷你",b2b="背靠背",b3b="背靠背靠背",
- PC="清清楚楚",HPC="半完美清晰",
- replaying="[重播]",
- tasUsing="[TAS]",
-
- stage="第$1阶段已完成",
- great="伟大的",
- awesome="令人惊叹的!",
- almost="几乎!",
- continue="继续前进!",
- maxspeed="最高速度!",
- speedup="加快",
- missionFailed="错误清除",
-
- speedLV="速度水平",
- piece="块",line="线",atk="攻击",eff="效率",
- rpm="转速",tsd="热关断",
- grade="等级",techrash="技术崩溃",
- wave="波动",nextWave="下一个",
- combo="联合体",maxcmb="最大连击",
- pc="清清楚楚",ko="击倒对手",
-
- win="赢",
- lose="失去",
-
- finish="完成",
- gamewin="你赢了",
- gameover="游戏结束",
-
- pause="暂停",
- pauseCount="暂停计数",
- finesse_ap="完美无缺",
- finesse_fc="全组合",
-
- page="页:",
-
- cc_fixed="CC与固定序列不兼容",
- cc_swap="CC与交换保持模式不兼容",
- ai_prebag="AI与具有非四格拼板的自定义序列不兼容",
- ai_mission="AI与自定义使命不兼容",
- switchSpawnSFX="请打开繁殖特技效果",
- needRestart="请重试以使更改生效",
-
- loadError_errorMode="'$1' 加载失败:无加载模式 '$2'",
- loadError_read="'$1' 加载失败:读取失败",
- loadError_noFile="'$1' 加载失败:没有文件",
- loadError_other="'$1' 加载失败:$2",
- loadError_unknown="'$1' 加载失败:原因未知",
-
- saveError_duplicate="'$1' 保存失败:文件名重复",
- saveError_encode="'$1' 保存失败:编码失败",
- saveError_other="'$1' 保存失败:$2",
- saveError_unknown="'$1' 保存失败:原因未知",
-
- copyDone="收到了!",
- saveDone="保存的数据",
- exportSuccess="成功导出",
- importSuccess="导入成功",
- dataCorrupted="数据损坏",
- pasteWrongPlace="贴错地方了?",
- noFile="找不到文件",
-
- nowPlaying="现在播放:",
-
- VKTchW="触重",
- VKOrgW="起始重量",
- VKCurW="现在的位置重量",
-
- noScore="还没有分数",
- modeLocked="锁定",
- unlockHint="在先决条件模式下达到B级或更高级别以解锁",
- highScore="个人最好成绩",
- newRecord="新纪录!",
-
- replayBroken="无法加载重播",
-
- getNoticeFail="获取通知失败",
- oldVersion="版本$1现已推出!",
- needUpdate="需要更新版本!",
- versionNotMatch="版本不匹配!",
- notFinished="马上就来!",
-
- jsonError="JSON错误",
-
- noUsername="请指定用户名",
- wrongEmail="无效电邮地址",
- noPassword="输入您的密码",
- diffPassword="密码不匹配",
- registerRequestSent="已发送注册请求",
- registerSuccessed="注册成功!",
- loginSuccessed="您现在已登录!",
- accessSuccessed="允许访问",
-
- wsConnecting="双向通信连接",
- wsFailed="双向通信连接失败",
- wsClose="双向通信已关闭:",
- netTimeout="网络连接超时",
-
- onlinePlayerCount="在线的",
- createRoomSuccessed="房间成功创建!",
- started="玩",
- joinRoom="加入了房间",
- leaveRoom="离开了房间",
- ready="准备好的",
- connStream="连接",
- waitStream="等待",
- spectating="观赛",
- chatRemain="在线的",
- chatStart="------日志开始------",
- chatHistory="------下面是新消息------",
-
- keySettingInstruction="按绑定键\n退出:取消\n退格:删除",
- customBGhelp="将图像文件拖放到此处以应用自定义背景",
- customBGloadFailed="不支持自定义背景的图像格式",
-
- errorMsg="技术米诺遇到问题,需要重新启动。\n您可以将错误日志发送给开发人员。",
- tryAnotherBuild="[无效UTF-8]如果您在Windows上,请尝试下载Techmino-win32或Techmino-win64(与您现在使用的不同)",
-
- modInstruction="选择你的修改器\n多重器官衰竭允许您更改游戏。\n它们也可能以奇怪的方式破坏游戏。\n请注意,多重器官衰竭将导致您的游戏取消排名!",
- modInfo={
- next="下一步\n减少下一步的数量",
- hold="保持\n减少保持件的数量",
- hideNext="隐藏的下一个\n在下一个队列中包含特定数量的碎片",
- infHold="无限持有\n允许您无限地持有碎片",
- hideBlock="隐藏当前工件:\n使您控制的工件不可见",
- hideGhost="无重影\n使鬼魂片段不可见",
- hidden="隐藏锁定的片段\n使锁定的片段褪色",
- hideBoard="隐藏板\n局部或完全隐藏字段",
- flipBoard="翻转板\n翻转或旋转场",
- dropDelay="重力\n以帧/块为单位降低下降速度",
- lockDelay="锁定延迟\n以帧为单位减少锁定延迟",
- waitDelay="繁殖延迟\n以帧为单位减少繁殖延迟",
- fallDelay="线路清除延迟\n以帧为单位减少线路清除延迟",
- life="寿命\n更改附加寿命的初始数量",
- forceB2B="仅背靠背\n当背靠背仪表下降到初始线以下时,停止游戏",
- forceFinesse="仅使用技巧\n在出现任何技巧错误的情况下使用该游戏",
- tele="远程传送\n强制0直连式存储和0抗共振环",
- noRotation="无旋转\n不允许工件旋转",
- noMove="无移动\n禁止左右移动",
- customSeq="随机发生器\n为块序列生成随机发生器",
- pushSpeed="垃圾速度\n降低垃圾线(块/帧)的上升速度",
- boneBlock="[]\n使用[]块播放",
- },
- pauseStat={
- "时间:",
- "按键/旋转/保持:",
- "块:",
- "行/挖掘:",
- "攻击/数字攻击:",
- "收到:",
- "清除:",
- "旋转:",
- "背靠背/背靠背靠背/个人电脑/高性能计算机:",
- "技巧:",
- },
- radar={"很棒","对象文件格式","攻击","发送","自给能探测器","挖掘"},
- radarData={"下午","认证确定包标记","高级电源管理","冲击脉冲","下午好","每分钟衰变"},
- stat={
- "时代启动:",
- "播放计数:",
- "播放时间:",
- "按键/旋转/保持:",
- "块/行/攻击.:",
- "记录/记录/分类:",
- "挖掘/挖掘:",
- "效率/挖掘效率:",
- "背靠背/背靠背靠背:",
- "个人电脑/高性能计算机:",
- "技巧错误/技巧率:",
- },
- aboutTexts={
- "这只是一个*普通的*积木堆垛机。真的,就这样",
- "灵感来自C2/IO/JS/WWC/KOS等",
- "",
- "由LÖVE提供动力",
- "任何建议或错误报告都将不胜感激!",
- "确保只从官方渠道获得游戏,",
- "因为如果你在别处找到它,我们无法确保你的安全",
- "作者不对任何修改负责",
- FNNS and"/"or"虽然游戏是免费的,但我们感谢捐款。",
- FNNS and"/"or"查看Zictionary以了解更多信息",
- },
- staff={
- "最初由Z先生",
- "电子邮件: 1046101471@qq.com",
- "",
- "编程、开发和设计的",
- "Z先生",
- "",
- "使用了音乐",
- "蜂鸣器",
- "FL工作室",
- "FL移动",
- "逻辑专业X",
- "",
- "[POWERED BY LÖVE]",
- "",
- "程序",
- "Z先生",
- "粒子G",
- "皮恩",
- "特雷伯尔",
- "(呵呵)",
- "(芬恩·坦佐)",
- "(不是机器人)",
- "(用户670)",
- "",
- "集线器CI,外包装及后端",
- "粒子G",
- "特雷伯尔",
- "劳伦斯刘",
- "尼亚尔",
- "废话",
- "呵呵",
- "",
- "视觉设计,用户界面及用户体验",
- "Z先生",
- "尼亚尔",
- "蛋白激酶G抑制剂",
- "氟化钪",
- "(旋律星萤)",
- "(T0722)",
- "",
- "音乐设计",
- "Z先生",
- "柒栎流星",
- "ERM",
- "特雷伯尔",
- "蛋白激酶G抑制剂",
- "(T0722)",
- "(以太)",
- "(黑利)",
- "",
- "音效和语音包",
- "米娅",
- "小亚",
- "东西",
- "Z先生",
- "特雷伯尔",
- "",
- "翻译和本土化",
- "用户670",
- "马特·马尤加",
- "水",
- "法克先生",
- "氟化钪",
- "蛋白激酶G抑制剂",
- "不是机器人",
- "",
- "性能",
- "电动283",
- "河北麦",
- "",
- "特别鸣谢",
- "飞天",
- "大真",
- "不是机器人",
- "思竣",
- "余浩7370",
- "放屁者",
- "茶管",
- "蕴空之灵",
- "T9972",
- "无用户名8",
- "安德鲁4043",
- "中小型银行-中小型银行",
- "泡霍",
- "暗示",
- "浩然太阳",
- "天灵刘",
- "滑稽2369",
- "伊提克",
- "拉希动漫",
- "[所有其他的测试人员]",
- "…和你!",
- },
- used=[[
- 使用工具:
- Beepbox
- Goldwave
- GFIE
- FL Mobile
- 使用库:
- Cold_Clear [MinusKelvin]
- json.lua [rxi]
- profile.lua [itraykov]
- simple-love-lights [dylhunn]
- ]],
- support="供养作者!",
- WidgetText={
- main={
- offline="单人",
- qplay="最后玩",
- online="多人游戏",
- custom="海关",
- setting="设置",
- stat="统计",
- dict="四联词典",
- replays="重播",
- },
- main_simple={
- sprint="冲刺",
- marathon="马拉松赛跑",
- },
- mode={
- mod="多重器官衰竭(F1)",
- start="开始",
- },
- mod={
- title="多重器官衰竭",
- reset="重置(制表)",
- unranked="未分级",
- },
- pause={
- setting="设置(S)",
- replay="重播(P)",
- save="保存(O)",
- resume="恢复(esc)",
- restart="重试(R)",
- quit="退出(Q)",
- tas="TAS(T)",
- },
- net_menu={
- league="技术联盟",
- ffa="游离脂肪酸",
- rooms="房间",
- logout="注销",
- },
- net_league={
- match="找到匹配项",
- },
- net_rooms={
- password="密码",
- refreshing="清新的房间",
- noRoom="现在没有房间了...",
- refresh="刷新",
- new="新房间",
- join="参加",
- },
- net_newRoom={
- title="房间配置",
- roomName="房间名称(默认为用户名的房间)",
- password="密码",
- description="房间描述",
-
- life="生活",
- pushSpeed="推进速度",
- garbageSpeed="垃圾速度",
- visible="可见度",
- freshLimit="锁定重置限制",
-
- fieldH="田间高度",
- bufferLimit="缓冲区限制",
- heightLimit="高度限制",
-
- drop="下降延迟",
- lock="锁定延迟",
- wait="进入延迟",
- fall="线路延迟",
- hang="毁灭延迟",
- hurry="是打扰吗",
-
- capacity="容量",
- create="创造",
-
- ospin="O型自旋",
- fineKill="100%精巧",
- b2bKill="没有背靠背中断",
- lockout="锁定时失败",
- easyFresh="正常锁复位",
- deepDrop="深滴",
- bone="骨块",
-
- eventSet="规则集",
-
- holdMode="持有模式",
- nextCount="下一个",
- holdCount="持有",
- infHold="无限持有",
- phyHold="原地等待",
- },
- net_game={
- ready="准备好的",
- spectate="凝视",
- cancel="取消准备",
- },
- setting_game={
- title="游戏设置",
- graphic="←视频",
- sound="声音→",
- style="风格",
-
- ctrl="控制设置",
- key="键映射",
- touch="触摸设置",
- showVK="显示虚拟密钥",
- reTime="启动延迟",
- RS="轮换制",
- menuPos="菜单按钮位置",
- sysCursor="使用系统游标",
- autoPause="心不在焉",
- autoSave="自动保存新的最佳",
- autoLogin="启动时自动登录",
- simpMode="简单化风格",
- },
- setting_video={
- title="视频设置",
- sound="←声音",
- game="游戏→",
-
- block="绘图块",
- smooth="光滑下降",
- upEdge="三维积木",
- bagLine="袋式分离器",
-
- ghostType="鬼型",
- ghost="鬼魂",
- center="居中",
- grid="网格",
- lineNum="线路号",
-
- lockFX="锁定外汇",
- dropFX="下降外汇",
- moveFX="移动外汇",
- clearFX="外汇结算",
- splashFX="飞溅外汇",
- shakeFX="磁场摆动",
- atkFX="攻击外汇",
-
- frame="渲染帧率(%)",
- FTlock="逻辑追帧",
-
- text="行清除弹出窗口",
- score="分数弹出",
- bufferWarn="缓冲区警报",
- showSpike="尖峰计数器",
- nextPos="繁殖预览",
- highCam="屏幕滚动",
- warn="危险警报",
-
- clickFX="单击外汇",
- power="蓄电池信息",
- clean="快速绘制",
- fullscreen="全屏",
-
- bg_on="正常背景",
- bg_off="没有背景",
- bg_custom="应用自定义背景",
-
- blockSatur="块饱和",
- fieldSatur="场饱和",
- },
- setting_sound={
- title="声音设置",
-
- game="←游戏",
- graphic="视频→",
-
- mainVol="主卷",
- bgm="血糖监测",
- sfx="特技效果",
- stereo="立体声",
- spawn="发出声音",
- warn="警告",
- vib="振动",
- voc="声音",
-
- autoMute="不聚焦时保持沉默",
- fine="精细度误差",
- sfxPack="特技效果包",
- vocPack="语音包",
- apply="申请",
- },
- setting_control={
- title="控制设置",
- preview="预览",
-
- das="直连式存储",arr="抗共振环",
- dascut="直连式存储切",
- dropcut="自动锁定切割",
- sddas="软滴直连式存储",sdarr="软降抗共振环",
- ihs="初始持有",
- irs="初始旋转",
- ims="初始运动",
- },
- setting_key={
- a1="向左移动",
- a2="向右方移动",
- a3="右转",
- a4="向左旋转",
- a5="旋转180°",
- a6="硬滴",
- a7="软滴",
- a8="持有",
- a9="功能1",
- a10="功能2",
- a11="立即离开",
- a12="即时权利",
- a13="声波滴",
- a14="向下1",
- a15="下降4",
- a16="下降10",
- a17="左撇子",
- a18="右转",
- a19="左桑吉",
- a20="右桑吉",
- restart="重试",
- },
- setting_skin={
- skinSet="块状表皮",
- title="布局设置",
- skinR="重置颜色",
- faceR="重置目录",
- },
- setting_touch={
- default="违约",
- snap="捕捉到网格",
- size="尺寸",
- shape="形状",
- },
- setting_touchSwitch={
- b1= "向左移动:", b2="右移:", b3="右转:", b4="向左旋转:",
- b5= "旋转180°:", b6="硬滴:", b7="软跌落:", b8="持有:",
- b9= "职能1:", b10="职能2:", b11="立即离开:",b12="即时权利:",
- b13="声波滴:", b14="下降1:", b15="下降4:", b16="下降10:",
- b17="左下降:", b18="右下角:",b19="左桑吉:", b20="右桑吉:",
-
- norm="正常",
- pro="专业的",
- icon="偶像",
- sfx="特技效果",
- vib="振动",
- alpha="阿尔法",
-
- track="自动跟踪",
- dodge="自动闪避",
- },
- customGame={
- title="定制游戏",
- defSeq="默认顺序",
- noMsn="无使命",
-
- drop="下降延迟",
- lock="锁定延迟",
- wait="进入延迟",
- fall="线路延迟",
- hang="毁灭延迟",
- hurry="是打扰吗",
-
- bg="背景",
- bgm="音乐",
-
- copy="复制字段+序号+使命",
- paste="粘贴字段+序号+使命",
- play_clear="清场",
- play_puzzle="开始拼图",
-
- reset="复位(del)",
- advance="更多(A)",
- mod="多重器官衰竭(F1)",
- field="编辑字段(F)",
- sequence="编辑序列(S)",
- mission="编辑使命(M)",
-
- eventSet="规则集",
-
- holdMode="持有模式",
- nextCount="下一个",
- holdCount="持有",
- infHold="无限持有",
- phyHold="原地等待",
-
- fieldH="田间高度",
- visible="可见度",
- freshLimit="锁定重置限制",
- opponent="对手",
- life="生活",
- pushSpeed="推进速度",
- garbageSpeed="垃圾速度",
-
- bufferLimit="缓冲区限制",
- heightLimit="高度限制",
- ospin="O型自旋",
- fineKill="100%精巧",
- b2bKill="没有背靠背中断",
- lockout="锁定时失败",
- easyFresh="正常锁复位",
- deepDrop="深滴",
- bone="骨块",
- },
- custom_field={
- title="定制游戏",
- subTitle="领域",
-
- any="擦除",
- smart="聪明的",
-
- push="添加行(K)",
- del="中线(L)",
-
- demo="不要展示×",
-
- newPg="新页(N)",
- delPg="德尔佩奇(M)",
- prevPg="前页",
- nextPg="下一页",
- },
- custom_sequence={
- title="定制游戏",
- subTitle="序列",
- sequence="序列",
- },
- custom_mission={
- title="定制游戏",
- subTitle="使命",
-
- _1="1.",_2="2.",_3="3.",_4="4.",
- any1="any1",any2="any2",any3="any3",any4="任何4",
- PC="个人电脑",
- Z1="Z1",S1="S1",J1="J1",L1="L1",T1="T1",O1="O1",I1="I1",
- Z2="Z2",S2="S2",J2="J2",L2="L2",T2="T2",O2="氧气",I2="I2",
- Z3="Z3",S3="S3",J3="J3",L3="L3",T3="T3",O3="臭氧",I3="I3",
- O4="O4",I4="I4",
- mission="使命",
- },
- about={
- staff="工作人员",
- his="历史",
- legals="法律",
- },
- dict={
- title="四联词典",
- },
- stat={
- path="打开数据文件夹",
- save="数据管理",
- },
- music={
- title="音乐培训室",
- arrow="→",
- now="现在播放:",
-
- bgm="血糖监测",
- sound="特技效果",
- },
- launchpad={
- title="特技效果",
- bgm="血糖监测",
- sfx="特技效果",
- voc="声音",
- music="音乐培训室",
- label="标签",
- },
- login={
- title="登录",
- register="登记",
- email="电子邮件地址",
- password="密码",
- keepPW="记得我吗",
- login="登录",
- },
- register={
- title="登记",
- login="登录",
- username="用户名",
- email="电子邮件地址",
- password="密码",
- password2="重新输入密码",
- register="登记",
- registering="等待回应...",
- },
- account={
- title="帐户",
- },
- app_15p={
- color="颜色",
- invis="英维斯",
- slide="滑动",
- pathVis="显示路径",
- revKB="逆转",
- },
- app_schulteG={
- rank="大小",
- invis="英维斯",
- disappear="隐藏",
- tapFX="Tap外汇",
- },
- app_AtoZ={
- level="水平仪",
- keyboard="键盘",
- },
- app_2048={
- invis="英维斯",
- tapControl="抽头控制",
-
- skip="跳转",
- },
- app_ten={
- next="下一个",
- invis="英维斯",
- fast="快速的",
- },
- app_dtw={
- color="颜色",
- mode="模式",
- bgm="血糖监测",
- arcade="游乐中心",
- },
- app_link={
- invis="英维斯",
- },
- savedata={
- export="导出到剪贴板",
- import="从剪贴板导入",
- unlock="进展",
- data="统计数据",
- setting="设置",
- vk="虚拟密钥布局",
-
- couldSave="云存储(注意:测试)",
- notLogin="[登录访问云保存]",
- upload="上传到云",
- download="从云端下载",
- },
- },
- modes={
- ['sprint_10l']= {"冲刺", "10升", "清除10行!"},
- ['sprint_20l']= {"冲刺", "20升", "清除20行!"},
- ['sprint_40l']= {"冲刺", "40升", "清除40行!"},
- ['sprint_100l']= {"冲刺", "100升", "清除100行!"},
- ['sprint_400l']= {"冲刺", "400升", "清除400行!"},
- ['sprint_1000l']= {"冲刺", "1000升", "清除1000行!"},
- ['sprintPenta']= {"冲刺", "五联骨牌", "40升,配18个五分钟"},
- ['sprintMPH']= {"冲刺", "每小时英里数", "无记忆\n无先前\n无记忆"},
- ['dig_10l']= {"挖掘", "10升", "挖10条垃圾线"},
- ['dig_40l']= {"挖掘", "40升", "挖40条垃圾线"},
- ['dig_100l']= {"挖掘", "100升", "挖100条垃圾线"},
- ['dig_400l']= {"挖掘", "400升", "挖400条垃圾线"},
- ['drought_n']= {"干旱", "100升", "没有工装"},
- ['drought_l']= {"干旱+", "100升", "搞什么呀"},
- ['marathon_n']= {"马拉松赛跑", "正常", "200线加速马拉松"},
- ['marathon_h']= {"马拉松赛跑", "硬的", "200线高速马拉松"},
- ['solo_e']= {"战争", "容易", "打败AI!"},
- ['solo_n']= {"战争", "正常", "打败AI!"},
- ['solo_h']= {"战争", "硬的", "打败AI!"},
- ['solo_l']= {"战争", "疯子", "打败AI!"},
- ['solo_u']= {"战争", "终极", "打败AI!"},
- ['techmino49_e']= {"技术49", "容易", "49人战斗\n最后一个站着的人获胜"},
- ['techmino49_h']= {"技术49", "硬的", "49人战斗\n最后一个站着的人获胜"},
- ['techmino49_u']= {"技术49", "终极", "49人战斗\n最后一个站着的人获胜"},
- ['techmino99_e']= {"科技99", "容易", "99人战斗\n最后一个站着的人获胜"},
- ['techmino99_h']= {"科技99", "硬的", "99人战斗\n最后一个站着的人获胜"},
- ['techmino99_u']= {"科技99", "终极", "99人战斗\n最后一个站着的人获胜"},
- ['round_e']= {"回合制", "容易", "轮流玩AI!"},
- ['round_n']= {"回合制", "正常", "轮流玩AI!"},
- ['round_h']= {"回合制", "硬的", "轮流玩AI!"},
- ['round_l']= {"回合制", "疯子", "轮流玩AI!"},
- ['round_u']= {"回合制", "终极", "轮流玩AI!"},
- ['master_n']= {"主人", "正常", "适合20G初学者"},
- ['master_h']= {"主人", "硬的", "20克的职业选手"},
- ['master_m']= {"主人", "M21", "20克大师赛"},
- ['master_final']= {"主人", "最终", "20G及以上"},
- ['master_ph']= {"主人", "幻觉", "???"},
- ['master_ex']= {"主人", "额外的", "比瞬间还短的永恒"},
- ['master_instinct']={"主人", "情绪", "步行的秘密部分"},
- ['strategy_e']= {"策略堆叠", "简单", "20G堆叠中速决策练习"},
- ['strategy_h']= {"策略堆叠", "困难", "20G堆叠快速决策练习"},
- ['strategy_u']= {"策略堆叠", "极限", "20G堆叠极速决策练习"},
- ['strategy_e_plus']={"策略堆叠", "简单", "20G堆叠中速决策练习"},
- ['strategy_h_plus']={"策略堆叠", "困难", "20G堆叠快速决策练习"},
- ['strategy_u_plus']={"策略堆叠", "极限", "20G堆叠极速决策练习"},
- ['blind_e']= {"看不见的", "一半", "对于新手来说"},
- ['blind_n']= {"看不见的", "全部", "对于中间产品"},
- ['blind_h']= {"看不见的", "突然", "对于有经验的人"},
- ['blind_l']= {"看不见的", "突然+", "对于专业人士"},
- ['blind_u']= {"看不见的", "?", "你准备好了吗?"},
- ['blind_wtf']= {"看不见的", "世界跆拳道联盟", "你还没准备好"},
- ['classic_e']= {"经典", "容易", "80年代的低速娱乐"},
- ['classic_h']= {"经典", "困难", "80年代的中速娱乐"},
- ['classic_u']= {"经典", "终极", "80年代的高速娱乐"},
- ['survivor_e']= {"幸存者", "容易", "你能活多久?"},
- ['survivor_n']= {"幸存者", "正常", "你能活多久?"},
- ['survivor_h']= {"幸存者", "硬的", "你能活多久?"},
- ['survivor_l']= {"幸存者", "疯子", "你能活多久?"},
- ['survivor_u']= {"幸存者", "终极", "你能活多久?"},
- ['attacker_h']= {"攻击者", "硬的", "练习你的进攻技巧!"},
- ['attacker_u']= {"攻击者", "终极", "练习你的进攻技巧!"},
- ['defender_n']= {"防守者", "正常", "练习你的防守技巧!"},
- ['defender_l']= {"防守者", "疯子", "练习你的防守技巧!"},
- ['dig_h']= {"钻机", "硬的", "挖掘练习!"},
- ['dig_u']= {"钻机", "终极", "挖掘练习!"},
- ['clearRush']= {"清晰的冲", "普通", "所有旋转教程\n[在建]"},
- ['c4wtrain_n']= {"C4W训练", "正常", "无限组合"},
- ['c4wtrain_l']= {"C4W训练", "疯子", "无限组合"},
- ['pctrain_n']= {"电脑培训", "正常", "完美清晰的实践"},
- ['pctrain_l']= {"电脑培训", "疯子", "更难的完美清晰的练习"},
- ['pc_n']= {"电脑挑战", "正常", "让电脑在100线以内!"},
- ['pc_h']= {"电脑挑战", "硬的", "让电脑在100线以内!"},
- ['pc_l']= {"电脑挑战", "疯子", "让电脑在100线以内!"},
- ['pc_inf']= {"无尽个人电脑挑战", "", "尽可能多地获取个人电脑"},
- ['tech_n']= {"技术人员", "正常", "试着保持背靠背的链条!"},
- ['tech_n_plus']= {"技术人员", "正常+", "仅限旋转和个人电脑"},
- ['tech_h']= {"技术人员", "硬的", "试着保持背靠背的链条!"},
- ['tech_h_plus']= {"技术人员", "硬的+", "仅限旋转和个人电脑"},
- ['tech_l']= {"技术人员", "疯子", "试着保持背靠背的链条!"},
- ['tech_l_plus']= {"技术人员", "疯子+", "仅限旋转和个人电脑"},
- ['tech_finesse']= {"技术人员", "手腕", "没有技巧错误!"},
- ['tech_finesse_f']= {"技术人员", "技巧+", "没有正常的清除和技巧错误!"},
- ['tsd_e']= {"热关断挑战赛", "容易", "只有T-Spin双打!"},
- ['tsd_h']= {"热关断挑战赛", "硬的", "只有T-Spin双打!"},
- ['tsd_u']= {"热关断挑战赛", "终极", "只有T-Spin双打!"},
- ['backfire_n']= {"适得其反", "正常", "挡住回火的垃圾管道"},
- ['backfire_h']= {"适得其反", "硬的", "挡住回火的垃圾管道"},
- ['backfire_l']= {"适得其反", "疯子", "挡住回火的垃圾管道"},
- ['backfire_u']= {"适得其反", "终极", "挡住回火的垃圾管道"},
- ['sprintAtk']= {"冲刺", "100次攻击", "发送100行!"},
- ['sprintEff']= {"竞速", "效率", "在40行内发动更多攻击!"},
- ['zen']= {"禅宗", "200", "没有时间限制的200线跑步"},
- ['ultra']= {"Ultra", "额外", "2分钟的得分进攻"},
- ['infinite']= {"无限", "", "这只是一个沙箱"},
- ['infinite_dig']= {"无限:挖掘", "", "挖,挖,挖"},
- ['marathon_inf']= {"马拉松", "无尽", "无尽马拉松"},
-
- ['custom_clear']= {"习俗", "正常"},
- ['custom_puzzle']= {"习俗", "令人费解的"},
- },
-}
diff --git a/parts/language/lang_zh_trad.lua b/parts/language/lang_zh_trad.lua
index 7a279d12a..ad3690174 100644
--- a/parts/language/lang_zh_trad.lua
+++ b/parts/language/lang_zh_trad.lua
@@ -1,4 +1,4 @@
-return{
+return {
fallback='zh',
loadText={
loadSFX="加載音效資源",
@@ -17,12 +17,14 @@ return{
playedLong="你玩太久了!注意休息!",
playedTooMuch="今天玩得太久啦!Techmino好玩但也要注意休息哦~",
settingWarn="正在修改不常用設定,小心操作!",
+ settingWarn2="該設定需要重啟後生效",
atkModeName={"隨機","徽章","K.O.","反擊"},
royale_remain="剩下 $1 名玩家",
powerUp={[0]="000%UP","025%UP","050%UP","075%UP","100%UP"},
cmb={nil,"1 Combo","2 Combo","3 Combo","4 Combo","5 Combo","6 Combo","7 Combo","8 Combo","9 Combo","10 Combo!","11 Combo!","12 Combo!","13 Combo!","14 Combo!","15 Combo!","16 Combo!","17 Combo!","18 Combo!","19 Combo!","MEGACMB"},
- spin="-spin",
+ spin="-spin ",
+ spinNC="-spin",
clear={"Single","Double","Triple","Techrash","Pentacrash","Hexacrash","Heptacrash","Octacrash","Nonacrash","Decacrash","Undecacrash","Dodecacrash","Tridecacrash","Tetradecacrash","Pentadecacrash","Hexadecacrash","Heptadecacrash","Octadecacrash","Nonadecacrash","Ultracrash","Impossicrash"},
cleared="$1 lines",
mini="Mini",b2b="B2B ",b3b="B2B2B ",
@@ -103,47 +105,99 @@ return{
dictNote="==拷貝自小z辭典==",
- getNoticeFail="無法獲取公告",
+
+
+ -- Server's warn/error messages
+ Techrater={
+ internalError="內部錯誤",
+ databaseError="資料庫錯誤",
+ invalidFormat="json格式無效",
+ invalidArguments="參數無效",
+ tooFrequent="請求太頻繁",
+ notAvailable="無效請求",
+ noPermission="沒有許可權",
+ roomNotFound="找不到房間",
+
+ -- Controllers
+ WebSocket={
+ invalidConnection="無效連接",
+ invalidAction="無效操作",
+ playerNotFound="找不到玩家",
+ connectionFailed="連接失敗",
+ },
+ -- Filters
+ CheckPermission={
+ playerNotFound="找不到玩家",
+ },
+ -- Plugins
+ ConnectionManager={
+ playerInvalid="無效玩家",
+ playerNotFound="找不到玩家",
+ connectionReplaced="連接已更換",
+ },
+ NoticeManager={
+ noticeNotFound="找不到公告",
+ },
+ PlayerManager={
+ invalidCode="無效驗證碼",
+ invalidEmail="無效郵箱",
+ playerNotFound="找不到玩家",
+ invalidEmailPass="郵箱或密碼無效",
+ emailExists="郵箱存在",
+ emailSendError="郵箱發送錯誤",
+ },
+ -- Strategies
+ PlayerRole={
+ invalidRole="無效角色",
+ invalidTarget="無效目標",
+ },
+ PlayerType={
+ invalidType="無效類型",
+ roomFull="房間已滿",
+ },
+ RoomJoin={
+ wrongPassword="密碼錯誤",
+ },
+ },
+
+ tooFrequent="操作太頻繁",
+ roomPasswordChanged="房間密碼已更改",
oldVersion="版本 $1 現已推出",
- needUpdate="請更新遊戲!",
versionNotMatch="版本不匹配",
notFinished="即將推出!",
- jsonError="JSON錯誤",
-
noUsername="請輸入用戶名",
wrongEmail="無效的電郵地址",
+ wrongCode="無效的驗證碼",
noPassword="請輸入密碼",
diffPassword="密碼不匹配",
- registerRequestSent="已發送註冊請求",
- registerSuccessed="註冊成功!",
- loginSuccessed="登錄成功",
- accessSuccessed="身份認證成功",
-
- wsConnecting="正在連接……",
- wsFailed="連接失敗",
- wsClose="連接斷開:",
+ checkEmail="請查看郵件驗證碼",
+
+ wsFailed="連接失敗: $1",
+ wsClose="連接斷開: $1",
netTimeout="連接超時",
+ serverDown="哎唷!服務器不在线",
+ requestFailed="請求失敗",
- onlinePlayerCount="在線用戶數",
+ onlinePlayerCount="在線用戶數: $1",
createRoomSuccessed="房間已創建!",
+ playerKicked="#$1 把 #$2 移出了房間",
+ becomeHost="$1 成為了房主",
started="遊戲中",
- joinRoom="進入房間",
- leaveRoom="離開房間",
+ joinRoom="$1 進入房間",
+ leaveRoom="$1 離開房間",
+ roomRemoved="房間被解散",
ready="準備!",
- connStream="正在連接……",
- waitStream="等待其他用戶連接……",
spectating="旁觀中",
- chatRemain="用戶數:",
- chatStart="------訊息開始------",
- chatHistory="------以上為歷史訊息------",
+
+
keySettingInstruction="點擊來設置鍵位\n按esc來取消選中\n按退格鍵來清除選中",
customBGhelp="把圖片檔案拖到這個視窗裏使用自定義背景",
customBGloadFailed="自定義背景的圖片檔案格式不支持",
errorMsg="Techmino遇到問題,需要重新啟動。\n我們已經收集了一些錯誤信息,你可以反饋給作者。",
- tryAnotherBuild="[無效的 UTF-8] 如果你使用的是Windows作業系統,請嘗試下載Techmino-win32或Techmino-win64(與你現在使用的不同的版本)。",
+ tryAnotherBuild="[無效的UTF-8] 如果你使用的是Windows作業系統,請嘗試下載Techmino-win32或Techmino-win64(與你現在使用的不同的版本)。",
modInstruction="選擇你想使用的Mod!\n不同的Mod會以不同的方式改變遊戲規則(可能導致遊戲異常)\n快來開發新玩法或挑戰自我吧!\n提醒:開啟Mod會使成績無效,你可以使用鍵盤開關Mod,按下shift反向",
modInfo={
@@ -198,7 +252,7 @@ return{
"多餘操作/finesse率:",
},
aboutTexts={
- "這只是一個普通的方塊遊戲,請勿將此與某帶國家名的事物強行聯繫",
+ "這只是一個普通的*方塊遊戲*",
"從C2/IO/JS/WWC/KOS等方塊獲得過靈感",
"",
"使用LÖVE引擎",
@@ -206,8 +260,8 @@ return{
"僅透過內測QQ群/discord伺服器進行免費下載/更新",
"從其他渠道獲得遊戲皆有被修改/加入廣告/植入病毒的風險,程序只申請了振動&網路權限!",
"若由於被修改的本遊戲產生的各種損失作者概不負責(我怎麼負責啊跟我有什麼關係)",
- FNNS and"/"or"請從正規途徑獲得最新版,遊戲現為免費,不過有打賞當然感謝啦~",
- FNNS and"/"or"更多資訊見小z詞典"
+ FNNS and "/" or "請從正規途徑獲得最新版,遊戲現為免費,不過有打賞當然感謝啦~",
+ FNNS and "/" or "更多資訊見小z詞典"
},
staff={
"原作者 MrZ",
@@ -250,6 +304,12 @@ return{
"(旋律星萤)",
"(T0722)",
"",
+ "插圖",
+ "Miya",
+ "Mono",
+ "Xiaoya",
+ "葉枭",
+ "",
"音樂設計",
"MrZ",
"柒栎流星",
@@ -275,7 +335,9 @@ return{
"ScF",
"C₂₉H₂₅N₃O₅",
"NOT_A_ROBOT",
- "sakurw",
+ "XMiao",
+ "sakurw, Airun, 幽灵3383",
+ "Shard Nguyễn, Squishy, TVN community",
"",
"Performances",
"Electric283",
@@ -314,13 +376,13 @@ return{
Cold_Clear [MinusKelvin]
json.lua [rxi]
profile.lua [itraykov]
- simple-love-lights [dylhunn]
+ sha2 [Egor Skriptunoff]
]],
support="支持作者",
WidgetText={
main={
offline="單人遊戲",
- qplay="快速開始",
+ qplay="快速開始: ",
online="網路遊戲",
custom="自定義",
setting="設置",
@@ -354,6 +416,7 @@ return{
league="Tech League",
ffa="FFA",
rooms="房間列表",
+ resetPW="重設密碼",
logout="登出",
},
net_league={
@@ -430,7 +493,6 @@ return{
sysCursor="使用系統光標",
autoPause="失去焦點時暫停",
autoSave="打破紀錄時自動保存",
- autoLogin="啟動時自動登錄",
simpMode="簡潔模式",
},
setting_video={
@@ -458,7 +520,6 @@ return{
atkFX="攻擊特效",
frame="渲染幀率(%)",
- FTlock="跳幀",
text="清除文本",
score="分數動畫",
@@ -472,6 +533,8 @@ return{
power="電量顯示",
clean="渲染優化",
fullscreen="全屏幕",
+ portrait="豎屏",
+ msaa="抗鋸齒等級",
bg_on="普通背景",
bg_off="無背景",
@@ -683,21 +746,18 @@ return{
},
login={
title="登錄",
- register="註冊",
- email="電郵",
- password="密碼",
- keepPW="保存密碼",
- login="登錄",
- },
- register={
- title="註冊",
- login="登錄",
- username="用戶名",
- email="電郵",
+ ticket="登錄口令",
+ authorize="獲取口令",
+ paste="粘貼口令",
+ submit="登錄",
+ },
+ reset_password={
+ title="重設密碼",
+ send="發送驗證碼",
+ code="驗證碼",
password="密碼",
password2="確認密碼",
- register="註冊",
- registering="等待伺服器響應……",
+ setPW="設置密碼",
},
account={
title="賬戶",
@@ -760,12 +820,19 @@ return{
['sprint_100l']= {"競速", "100L", "清除100行"},
['sprint_400l']= {"競速", "400L", "清除400行"},
['sprint_1000l']= {"競速", "1000L", "清除1000行"},
+ ['secret_grade']= {"秘密段位", "", "按照提示完成經典的“大於號”拼圖"},
['sprintPenta']= {"競速", "五連塊", "傷腦筋十八塊"},
['sprintMPH']= {"競速", "MPH", "純隨機\n無Next\n無Hold"},
+ ['sprint123']= {"競速", "M123", "清除40行,但只有一至三連塊"},
['dig_10l']= {"挖掘", "10L", "挖掘10行"},
['dig_40l']= {"挖掘", "40L", "挖掘40行"},
['dig_100l']= {"挖掘", "100L", "挖掘100行"},
['dig_400l']= {"挖掘", "400L", "挖掘400行"},
+ ['dig_eff_10l']= {"挖掘", "效率 10L", "挖掘10行用最少的件數"},
+ ['dig_eff_40l']= {"挖掘", "效率 40L", "挖掘40行用最少的件數"},
+ ['dig_eff_100l']= {"挖掘", "效率 100L","挖掘100行用最少的件數"},
+ ['dig_eff_400l']= {"挖掘", "效率 400L","挖掘400行用最少的件數"},
+ ['dig_quad_10l']= {"挖掘", "消四10L", "挖掘10行,但只能消四"},
['drought_n']= {"乾旱", "100L", "你I沒了"},
['drought_l']= {"乾旱+", "100L", "後 媽 發 牌"},
['marathon_n']= {"馬拉松", "普通", "200行加速馬拉松"},
@@ -786,19 +853,22 @@ return{
['round_h']= {"回合制", "困難", "下棋模式"},
['round_l']= {"回合制", "瘋狂", "下棋模式"},
['round_u']= {"回合制", "極限", "下棋模式"},
+ ['big_n']= {"大方塊", "普通", "類比10*5場地的玩法(標準尺寸的一半)"},
+ ['big_h']= {"大方塊", "困難", "類比10*5場地的玩法(標準尺寸的一半)"},
['master_n']= {"大師", "普通", "20G初心者練習"},
['master_h']= {"大師", "困難", "上級者20G挑戰"},
['master_m']= {"大師", "大師", "大師20G"},
['master_final']= {"大師", "究極", "究極20G:無法觸及的終點"},
['master_ph']= {"大師", "虛幻", "虛幻20G:???"},
+ ['master_g']= {"大師", "段位考試", "20G段位考試"},
['master_ex']= {"宗師", "EX", "成為方塊大師"},
['master_instinct']={"大師", "本能", "隱藏當前塊"},
['strategy_e']= {"策略堆疊", "簡單", "20G堆疊中速決策練習"},
['strategy_h']= {"策略堆疊", "困難", "20G堆疊快速決策練習"},
['strategy_u']= {"策略堆疊", "極限", "20G堆疊極速決策練習"},
- ['strategy_e_plus']={"策略堆疊", "簡單+", "20G堆疊中速決策練習"},
- ['strategy_h_plus']={"策略堆疊", "困難+", "20G堆疊快速決策練習"},
- ['strategy_u_plus']={"策略堆疊", "極限+", "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']= {"隱形", "瞬隱", "很強大腦"},
@@ -808,7 +878,8 @@ return{
['blind_inv']= {"隱形", "倒置的", "隱形活動件"},
['classic_e']= {"高速經典", "簡單", "高速經典"},
['classic_h']= {"高速經典", "困難", "飛速經典"},
- ['classic_u']= {"高速經典", "極限", "極速經典"},
+ ['classic_l']= {"高速經典", "瘋狂", "極速经典"},
+ ['classic_u']= {"高速經典", "極限", "光速經典"},
['survivor_e']= {"生存", "簡單", "你能存活多久?"},
['survivor_n']= {"生存", "普通", "你能存活多久?"},
['survivor_h']= {"生存", "困難", "你能存活多久?"},
@@ -820,7 +891,6 @@ return{
['defender_l']= {"防守", "瘋狂", "防守練習"},
['dig_h']= {"挖掘", "困難", "挖掘練習"},
['dig_u']= {"挖掘", "極限", "挖掘練習"},
- ['clearRush']= {"清版競速", "普通", "All-spin 入門教程\n施工中"},
['c4wtrain_n']= {"C4W練習", "普通", "無 限 連 擊"},
['c4wtrain_l']= {"C4W練習", "瘋狂", "無 限 連 擊"},
['pctrain_n']= {"全清訓練", "普通", "簡易PC題集,熟悉全清定式的組合"},
@@ -855,4 +925,5 @@ return{
['custom_clear']= {"自定義", "普通"},
['custom_puzzle']= {"自定義", "拼圖"},
},
+ pumpkin="我是南瓜",
}
diff --git a/parts/language/manual_en.txt b/parts/language/manual_en.txt
index 6a9a8c7a4..9b9ae8540 100644
--- a/parts/language/manual_en.txt
+++ b/parts/language/manual_en.txt
@@ -1,46 +1,71 @@
Gameplay:
The system will provide you with tetrominoes (4-block pieces),
with a total of 7 types, and the player needs to control them
- (move left and right, rotate 90, 180 or 270 degrees).
- each row filled with the field will be cleared.
- If there is an opponent, an attack will be sent depending on the line clear type
- Play until the end or achieve the level's goal to win.
+ (move left and right, rotate 90, 180, or 270 degrees).
+ Each row filled with the field will be cleared.
+ If there is an opponent, an attack will be sent depending on the type of line clear.
+ Play until the end or achieve the level’s goal to win.
Rotation system:
- Uses TRS (Techmino Rotation System) by default. The game allows players to choose other commonly used rotation systems (generally unnecessary)
+ Uses TRS (Techmino Rotation System) by default.
+ The game allows players to choose other commonly used rotation systems (generally unnecessary)
Spin detection:
- Satisfies "3 corner" rule +2 points
- Satisfies "immobile" rule +2 points
+ Satisfies “3-corner” rule +2 points
+ Satisfies “immobile” rule +2 points
- As long as one of the above is true, it is a Spin
If the rotation was not using the second check in the kick table, +1 point
- The Spin is a Mini if it only has 2 points; the piece is one of S, Z, J, L, T; AND the line clear did not clear the entire piece.
Attack system:
- Normal line clears (1 to 3 lines):
- Sends (lines cleared -0.5) attack
- Special line clears:
- Spin sends (lines cleared x2) attack,
- - B2B sends extra 1/1/2/4/8 for Spin Single/Double/Triple/Techrash/Techrash+
- - B2B2B sends (lines cleared x0.5), and +1 extra blocking
- - Minis reduces the attack to 25% (x0.25 multiplier)
- Non-Spin Techrash/Techrash+ sends (lines cleared) attack,
- - B2B sends 1 additional line
- - B2B2B will have an attack boost of 50% and +1 extra blocking
-
- Special line clears will the increase B2B gauge, making later special line clears have either a B2B or B2B2B bonus (see below)
-
- Hemi Perfect Clear (a P.C. "with blocks left below". If it's an I clearing 1 line, the remaining blocks must not be player-placed):
- Attack +4, Extra Blocking +2
-
- Perfect Clear (aka All Clear):
- Sends 8 to 16 (increments within a game by 2 for every PC) OR every other damage above, whichever is higher,
- and +2 extra blocking.
-
- Combos: All damage above will be given a (combo x25%) bonus, or (combo x15%) for Single clear (capped at 12 combo),
- +1 more attack for 3 Combo or more.
- After calculating all above, the damage value will be rounded down then sent
+ Special clear:
+ A special clear refers to a situation where you perform a spin, Techrash (or clear more than four lines at a time), PC, or HPC.
+ Special clears can elevate the B2B gauge.
+ Super clear:
+ A super clear refers to a situation where you perform a special clear when the B2B gauge is not empty.
+
+ Special clears (spins):
+ sends (lines cleared ×2) attack,
+ - B2B sends extra 1/1/2/4/8 for Spin Single/Double/Triple/Techrash/Techrash+
+ - B2B2B sends (lines cleared ×0.5) on top of that of B2B, and +1 extra blocking
+ - Minis reduces the attack to 25% (×0.25 multiplier)
+
+ Special clears (Techrash/techrash+ without spins):
+ - B2B sends 1 additional line
+ - B2B2B will have an attack boost of 50% and +1 extra blocking
+
+ Non-special clears:
+ send (lines cleared-0.5) attack.
+
+ Combos (REN):
+ The numbers of the combos are equal to (the numbers you clear lines consecutively –1) (capped at 12 combos).
+ All damage above (except attack from PC/HPC) gets a (combo ×25%) bonus, or (combo ×15%) for Single clear.
+ +1 more attack for 2 Combo or more.
+
+ Hemi Perfect Clear (a P.C. “with blocks left below.” If just one line cleared, the remaining blocks must not be player-placed):
+ - Attack +4, Extra Blocking +2
+
+ Perfect Clear (All Clear):
+ - Sends 8 to 16 (increments within a game by 2 for every PC) OR every other damage above, whichever is higher.
+ - +2 extra blocking.
+
+ After calculating the above, the damage value will be rounded down and sent.
+
+
+Back to Back (B2B) gauge:
+ The B2B gauge ranges from 0 to 1,000. Special line clears are B2B if the gauge is ≥ 50, B2B2B if >800.
+
+ Line cleared:
+ Special clears:
+ - Spin Single/Double/Triple/Techrash/Techrash+ + 50/100/180/800/1000 (×50% if Mini)
+ - Techrash/Techrash+ + 150/200/...
+ - PC when lines cleared in this round >4, +800
+ - HPC, +100
+ - A regular line clear -250
+
+ No lines cleared:
+ - Spin (0 lines) +20. Note that the B2B gauge cannot exceed 800 using this method.
Score system:
The better you play, the higher the score.
@@ -50,40 +75,30 @@ Attack delay:
Followed by Techrash, Spins, which send slower attacks;
High combos are the slowest;
For B2B or B2B2B, they also increase the attack delay while they increase lines sent;
- Minis will greatly increase the delay.
+ Minis will significantly increase the delay.
Countering:
- When you send attacks, if there is garbage in queue,
- extra blocking will be used first, then attack, countering the earliest attack at a 1:1 ratio.
- Any extra blocking you didn't use will be discarded, and finally the remaining attack power will be sent to your opponent.
-
-Back to Back (B2B) gauge:
- The B2B gauge ranges from 0 to 1,000. Special line clears are B2B if the gauge is >=50, B2B2B if >800.
- A regular line clear -250
- Spin Single/Double/Triple/Techrash/Techrash+ + 50/100/180/800/1000 (x50% if Mini)
- Techrash/Techrash+ + 150/200/...
- PC when lines cleared in this round >4, +800
- Hemi-PC, +100
- Spin (0 lines) +20. Do note that the B2B gauge cannot exceed 800 using this method.
- When gauge is above 800, a drop without clearing lines decreases it by 40, but cannot drop below 800
+ When you send attacks, if there is garbage in the queue,
+ extra blocking will be used first, then attack, countering the earliest attack at a 1 : 1 ratio.
+ Any additional blocking you didn’t use will be discarded, and finally, the remaining attack power will be sent to your opponent.
Battle Royale modes:
- Many players play a game at the same time (against AI bots, not real players).
- As players get eliminated, blocks fall faster, and garbage take effect faster, as well as rise faster.
- Eliminate other players to gain a badge and the player's badge to increase your attack power.
+ Many players play a game simultaneously (against AI bots, not actual players).
+ As players get eliminated, blocks fall faster, and garbage takes effect and rises faster.
+ Eliminate other players to gain a badge and the player’s badge to increase your attack power.
Players can choose between four attack modes:
1. Random: Every time you attack, 10% chance to lock onto a random player.
2. Badges: After you attack or when your target dies, lock onto the player with the most badges.
- 3. KOs: After you attack or when your target dies, lock onto the player with the highest field. (Refreshes every second)
+ 3. KOs: Lock onto the player with the highest field after you attack or when your target dies. (Refreshes every second)
4. Attackers: attack all players locking onto yourself.
- Your attack will be sent to all of them. If you are not targetted, you attack a random player (not locking).
+ Your attack will be sent to all of them. If you are not targeted, you attack a random player (not locking).
When all opponents have been eliminated, the last player in the match is the winner.
Custom mode:
You can freely adjust most parameters (not including special effects of other game modes).
You can also draw a field to clear or make a template to build.
In build (puzzle) mode, you can toggle template display with Function key:
- Cells with a X cannot have blocks;
+ Cells with an X cannot have blocks;
empty cells can be in any state;
regular colored cells have to be made of the corresponding block;
garbage-colored cells can be any block but not air.
diff --git a/parts/language/manual_ja.txt b/parts/language/manual_ja.txt
new file mode 100644
index 000000000..1aeaa8093
--- /dev/null
+++ b/parts/language/manual_ja.txt
@@ -0,0 +1,130 @@
+ゲームプレイ:
+ システムから与えられる全7種類のテトロミノ
+ (4ブロックで構成されたピース) をプレイヤーが操作します。
+ (主に左右移動と90°、180°、270°回転)
+ 各ラインがブロックで埋まるとそのラインは消去されます。
+ 相手が居る場合、ラインの消し方等で攻撃と火力が異なります。
+ クリアする為にはそのレベルの目標を達成もしくは、最後までプレイする必要があります。
+
+回転システム:
+ 初期設定はTRS (Techmino Rotation System) で設定されています。
+ プレイヤーは他の一般的な回転システムも使う事ができます。
+ (基本的には変えなくても大丈夫)
+
+スピンの検出:
+ 「3コーナ」ルールを満たした時 +2点
+ 「インモービル (Immobile)」 ルールを満たした時 +2点
+ - 上のどちらかを満たした時、スピンが確定します。
+
+ もし回転システムがキックテーブルから2番目のチェック (2nd check) を採用していなかった場合 +1点
+ - もしスピンの合計点が2点しかない場合は「ミニ」扱いになります。
+ ただしこれは、ミノがS,Z,J,L,Tのいずれかで、line消去の時にそのミノのブロックが全部消せなかった場合のみ。
+
+攻撃システム:
+ Special clear:
+ Special clearとは、spin、techrash(もしくは一度に4段以上のline消去)、PC、HPCのどれかを行うことです。
+ Special clearを行うとB2Bゲージが上昇します。
+ Super clear:
+ Super clearとは、B2Bゲージがある状態でSpecial clearを行うことです。
+ Special clears (spin):
+ 消去line数の2倍の火力を送ります。
+ - B2Bは、spin single/doubleで1line、spin tripleで2line、spin techrashで4line、spin techrash+で8lineを火力に加算します。
+ - B2B2Bは、消去line数の半分を火力に加算し、更に相殺専用火力が1line加算されます。
+ - またspinの場合、B2BとB2B2Bの両方が付与されます。
+ - ミニは、火力を25%に減少させます(倍率0.25倍)。
+
+ Special clears (spin以外のtechrash/techrash+):
+ - B2Bは、火力が1line加算されます。
+ - B2B2Bは、火力を50%上昇させ、更に相殺専用火力が1line加算されます。
+
+ Non-special clears:
+ 消去line数-0.5段を送ります。
+
+ ren:
+ ren数は、連続してline消去した回数-1回です。
+ (上限12ren、13ren以上行っても総ren数12renと処理されます)
+ 1line消しの時に総ren数*15%(1+ren*0.15)、2line以上の時に総ren数*25%(1+ren*0.25)を乗算します。
+ 更に合計2ren以上消していた場合、火力が1line加算されます。
+
+ Half Perfect Clear (下にブロックが残っている状態でのPC、1line消去した場合はプレイヤーが置いたブロックが残ってはいけない):
+ - 火力が4line加算され、更に相殺専用火力が2line加算されます。
+
+ Perfect Clear (全消し):
+ - PCの火力、8~16line(PCを取る度に2ずつ上昇)とそれ以外の火力を比較し、火力の高い方が選択されます。
+ - 更に相殺専用火力が2line加算されます。
+
+ 以上は、計算後小数点以下切り捨てを行い、火力として送られます。
+ 例:2ren目にB2B2B S-spin double(SSD)でHPCを取った場合
+ - SSD =>火力+4line
+ - B2B =>火力+1line
+ - B2B2B=>(double/2)=1で火力+1line、更に相殺専用火力+1line
+ - 2ren =>(1+2ren*25%)=1.5、更に2ren以上消しているので火力+1line、よって{(4+1+1)*1.5+1=10}で火力10line
+ - HPC =>火力+4line、更に相殺専用火力+2line
+ 合計 火力:14line 相殺専用火力:3line
+
+Back to Back (B2B)ゲージ:
+ B2Bゲージは、0~1,000まであります。Special clearをした時にゲージが50以上ならB2B、800以上ならB2B2Bが付与されます。
+
+ ライン消去:
+ Special clears:
+ - spin single/double/triple/techrash/techrash+を行った場合、それぞれ+50/100/180/800/1,000ゲージが上昇します。
+ (ただしミニの場合は、50%減少)
+ - techrash/techrash+の場合は、それぞれ+150/200/...ゲージが上昇します。
+ - 1ゲーム中に4lineより多く消した状態でPCを行った場合、+800ゲージが上昇します。
+ - HPCを行った場合、+100ゲージが上昇します。
+ - 通常のline消去を行った場合、ゲージが250減少します。
+
+ line消去なし:
+ - 空spinの場合+20ゲージが上昇します。
+ (ただしこれでB2Bゲージを800より上昇させることはできません)
+
+スコアシステム:
+ 上手くプレイすれば、 スコアも上がります。
+
+攻撃遅延システム:
+ 2,3line消去の攻撃が一番早く下穴になります。
+ Techrashやスピン等が二番目に早く下穴になります。
+ 高いren数が付くと格段に遅くなります。
+ B2BやB2B2Bは、送るライン数が増えれば増えるほど遅くなります。
+ ミニが付与された場合、大幅に遅くなります。
+
+相殺:
+ 攻撃を送る際、ダメージゲージに火力がある場合、
+ 最初に相殺専用火力が相殺に当てられ、その次に攻撃本体とダメージゲージにある火力を1対1の割合で相殺します。
+ 相殺を終えた後に相殺専用火力が余っていた場合、相殺専用火力は破棄されます。
+ そして攻撃本体の火力が余っていた場合には、余った分が相手に送られます。
+ 例:相手から2line送られ、B2B2B S-spindouble HPCで相殺した場合
+ 火力:10line 相殺専用火力:3line
+ - 相殺専用火力3lineが相手の2lineに当てられる
+ - 残りは火力10line、相殺専用火力1line
+ - 相殺を終えたので相殺専用火力は破棄され、10lineが相手に送られる。
+
+バトルロイヤルモード:
+ 沢山のプレイヤーが同時にゲームをプレイします。
+ (対AIです、本物の人ではありません)
+ 人数が減れば減るほど、ミノの落下速度は加速していき、更に攻撃遅延時間が減少し、せり上がりも速くなります。
+ 他のプレイヤーを倒すとバッジを取得し、自身の火力が上昇します。
+ プレイヤーは4つの攻撃モードから選ぶことができます:
+ 1: ランダム:
+ 攻撃を送る際、 10%の確率で他のプレイヤーに照準を合わせます。
+ 2: バッジ狙い:
+ 攻撃を送った後もしくは標的が倒れた場合、バッジの数が一番多いプレイヤーに照準を合わせます。
+ 3. トドメ撃ち:
+ 攻撃を送った後もしくは標的が倒れた場合、各プレイヤーの中から盤面の高さが一番高いプレイヤーに照準を合わせます。
+ (プレイヤーの盤面の高さは、毎秒更新されます)
+ 4. カウンター:
+ あなたに照準を向けているプレイヤー全員に照準を同時に向けます。
+ あなたの攻撃は照準を向けてるプレイヤー全員に送られます。
+ あなたに向いている標準がない場合、ランダムにプレイヤーを攻撃します。
+ (特定のプレイヤーに標準を固定しません)
+ 最後のプレイヤーが勝者となります。
+
+カスタムモード:
+ 殆どの設定を自由に変えられます。(他のゲームモードの特殊エフェクトを除いて)
+ 更に盤面を自由に設定したり、積み上げる為のガイドも作れます。
+ ビルド(パズル)モードの場合、ガイドの表示をファンクションキーで操作できます:
+ X印の場所には、ブロックを置けない。
+ 無印の場所には、何を置いても構わない。
+ 色付きの場所には、その色に対応したミノブロックを置かなければならない。
+ 下穴の色の場所には、ブロックが既にある判定で何も置けない。
+ ガイド通りに形を作ることでクリアとなります。
diff --git a/parts/language/manual_vi.txt b/parts/language/manual_vi.txt
new file mode 100644
index 000000000..4e3af0fe2
--- /dev/null
+++ b/parts/language/manual_vi.txt
@@ -0,0 +1,119 @@
+Lối chơi:
+ Hệ thống sẽ cung cấp bạn các tetromino (gạch 4 ô),
+ có tổng 7 loại, và người chơi cần điều khiển chúng (di chuyển sang trái và phải; xoay 90, 180, hoặc 270 độ).
+ Cứ mỗi hàng được lấp đầy trong bảng bởi các viên gạch, chúng sẽ bị xóa ra khỏi bảng.
+ Nếu có đối thủ, đối thủ sẽ bị tấn công mạnh hoặc nhẹ tùy theo số hàng bạn gửi.
+ Chơi hết hoặc đạt mục tiêu của cấp độ để thắng.
+
+
+Hệ thống xoay gạch:
+ Mặc định sẽ sử dụng TRS (Techmino Rotation System - Hệ thống xoay gạch Techmino).
+ Game cho phép người chơi chọn các hệ thống xoay gạch phổ biến khác (thường không cần thiết)
+
+
+Cách phát hiện spin:
+ Thỏa mãn quy tắc “3 góc” +2 điểm [*]
+ Thỏa mãn quy tắc “bất động” +2 điểm
+ - Cứ một trong hai điều kiện trên được thỏa mãn, thì sẽ được tính là Spin
+
+ Nếu việc xoay thỏa mãn ngay vị trí đầu tiên trong bảng đá tường, +1 điểm
+
+ - Spin sẽ là Mini nếu:
+ Tổng điểm sau khi kiểm tra các quy tắc chỉ được 2 điểm
+ HOẶC
+ Gạch dùng để làm là S, Z, J, L hoặc T vẫn còn tàn dư của gạch đó sau khi xóa hàng.
+
+ [*] LƯU Ý: quy tắc “góc sau lưng gạch” có thể ảnh hưởng đến kết quả kiểm tra của quy tắc “3 góc”!
+
+Hệ thống tấn công:
+ Kiểu xóa Đặc biệt (Special clear):
+ Kiểu xóa Đặc biệt chỉ trường hợp bạn thực hiện Spin, Techrash/Techrash+, PC/HPC.
+ Kiểu xóa Đặc biệt có thể sạc đầy thanh B2B.
+
+ Kiểu xóa Siêu cấp (Super clear):
+ Kiểu xóa Siêu cấp chỉ trường hợp bạn thực hiện Kiểu xóa Đặc biệt khi thanh B2B không trống.
+
+ Kiểu xóa Đặc biệt (spin): gửi đòn tấn công (số hàng xóa × 2) hàng,
+ - B2B gửi thêm 1/1/2/4/8 cho Spin Đơn/Spin Đôi/Spin Tam/Techrash/Techrash+
+ - B2B2B gửi thêm (số hàng xóa × 0.5) trên B2B và +1 hàng để hủy rác tới
+ - Mini sẽ bị cắt còn 25% (hệ số × 0.25)
+
+ Kiểu xóa Đặc biệt (Techrash/Techrash+ không dùng spin):
+ - B2B gửi thêm 1 hàng
+ - B2B2B sẽ boost 50% tấn công và +1 hàng để hủy rác tới
+
+ Kiểu xóa không Đặc biệt: Single/Double/Triple (Đơn/Đôi/Tam) gửi 1/2/3 hàng
+
+ Combo (REN):
+ Số combo = số lần bạn xóa hàng liên tiếp - 1 (chỉ nhận TỐI ĐA combo 12, từ combo 13 về sau sẽ tính thành combo 12).
+ Toàn bộ sát thương kể trên (trừ tấn công từ PC/HPC) nhận thêm bonus (combo × 25%) HOẶC (combo × 15%) nếu chỉ xóa 1 hàng.
+ +1 hàng để tấn công từ Combo 2 trở đi.
+
+ Hemi Perfect Clear (PC mà “vẫn còn gạch ở dưới”).
+ Nếu chỉ còn 1 hàng xóa, thì toàn bộ gạch còn lại không phải do người chơi đặt:
+ +4 hàng để tấn công, +2 hàng để hủy rác tới
+
+ Perfect Clear (All Clear):
+ - Gửi 8 → 16 hàng rác (6 + 2 * số PC đã làm; tính tối đa 5PC) HOẶC sát thương thường, tùy vào sát thương nào mạnh hơn.
+ - +2 hàng để hủy rác.
+
+ Sau khi tính toán xong, lượng sát thương sẽ bị làm tròn XUỐNG trước khi gửi.
+
+
+Thanh Back to Back (B2B):
+ Thanh B2B có giá trị từ 0 tới 1,000. Kiểu xóa đặc biệt là B2B nếu thanh vượt qua vạch 50, B2B2B nếu qua vạch 800.
+
+ Nếu có hàng được xóa:
+ Kiểu xóa đặc biệt:
+ - Spin Đơn/Đôi/Tam/Techrash/Techrash+ + 50/100/180/800/1000 (×50% nếu là Mini)
+ - Techrash/Techrash+ + 150/200/...
+ - PC nếu số PC làm được trong một ván >4, +800
+ - HPC, +100
+ Kiểu xóa thường -250
+
+ Nếu không: Spin (0 hàng) +20.
+ LƯU Ý! Thanh B2B không thể sạc qua vạch 800 bằng cách này.
+
+
+Hệ thống tính điểm:
+ Cứ chơi càng hay thì điểm càng cao, thế thôi!
+
+
+Khoảng thời gian chờ trước khi tấn công:
+ Sát thường từ Đôi và Tam có hiệu lực nhanh nhất;
+ Theo sau là Techrash và Spin, chúng thường gửi tấn công chậm hơn;
+ Combo dài gửi lâu nhất;
+ Với B2B và B2B2B, có thể kéo dài thời gian chờ cũng như có thể thêm hàng;
+ Minis cũng có thể kéo dài thời gian chờ thêm chút nữa.
+
+
+Phản công:
+ Khi bạn gửi tấn công, nếu có rác trong hàng chờ, thì ưu tiên dùng hàng để hủy rác trước, sau đó mới dùng tới hàng để tấn công sau.
+ Tỉ lệ phản công sẽ là 1:1
+ Bất kỳ hàng nào để phản công không dùng tới sẽ bỏ hết; cuối cùng, số hàng để tấn công còn lại sẽ gửi tới đối thủ.
+
+
+Chế độ Battle Royale:
+ Một chế độ có nhiều người chơi (AI, không phải người thật) cùng đối đầu trong một phòng!
+ Cứ sau một số người chơi bị loại nhất định, gạch sẽ rơi nhanh hơn, và rác cũng sẽ phát tác sớm hơn và dâng nhanh hơn.
+ Đánh bật đối thủ khác để nhận một huy hiệu và toàn bộ huy hiệu của người chơi để tăng sức mạnh tấn công.
+ Người chơi có thể chọn 1 trong 4 chế độ tấn công sau đây:
+ - Ngẫu nhiên: Cứ mỗi lần tấn công, có 10% khả năng nhắm vào một người chơi ngẫu nhiên.
+ - Huy hiệu: Sau khi bạn tấn công/mục tiêu bị chết, tư động ngắm vào người chơi có nhiều huy hiệu nhất.
+ - K.O.: Nhắm vào người chơi “đang thở máy, đang hấp hối”.
+ - Phản công: tấn công tất cả người chơi đang nhắm vào bạn
+ Bạn sẽ gửi tấn công đến tất cả bọn họ.
+ Nếu bạn không nhắm vào mục tiêu nào, thì bạn sẽ tấn công một người chơi ngẫu nhiên (không nhắm)
+ Khi toàn bộ đối thủ đều bị đá bay, người sống sót cuối cùng sẽ chiến thắng.
+
+
+Chế độ Tự do:
+ Bạn có thể tự do tùy chỉnh nhiều thông số (nhưng không bao gồm các hiệu ứng đặc biệt từ các chế độ khác).
+ Bạn có thể vẽ một cái bảng để tập xóa hoặc làm mẫu để tập build.
+ Ở trong chế độ Build (Puzzle):
+ Nhấn phím F1 để hiện/ẩn mẫu
+ ô có X thì không được có gạch;
+ ô trống thì có thể ở bất kỳ tình trạng nào;
+ ô có màu thì gạch đặt vào ô phải khớp màu;
+ ô có màu của hàng rác thì có thể là bất kỳ gạch nào nhưng không thể là không khí.
+ Một khi bạn làm khớp với mẫu ban đầu, bạn thắng.
diff --git a/parts/language/manual_zh.txt b/parts/language/manual_zh.txt
index 7eab09cc6..b4908656d 100644
--- a/parts/language/manual_zh.txt
+++ b/parts/language/manual_zh.txt
@@ -1,57 +1,74 @@
游戏方法:
- 系统会提供的一个个四连骨牌("方块",总共7种)
- 玩家需要控制(左右移动和旋转90,180,270度)这些骨牌直到下落到场地底部,锁定
+ 系统会提供的一个个四连骨牌( “方块”, 总共7种)
+ 玩家需要控制(左右移动和旋转90, 180, 270度)这些骨牌直到下落到场地底部, 锁定
每填满场地的一行就会将其消除(如果有对手的话根据消除方式会给对手攻击)
- 尝试存活更久,或者完成目标即胜利.
+ 尝试存活更久, 或者完成目标即胜利.
旋转系统:
- 默认使用Techmino专属旋转系统TRS,允许玩家自选其他较常用的旋转系统(一般不必要)
+ 默认使用Techmino专属旋转系统TRS, 允许玩家自选其他较常用的旋转系统(一般不必要)
-spin判定:
+Spin判定:
满足三角判定+2分
满足不可移动判定+2分
- --满足以上之一就算是spin
+ --满足以上之一就算是Spin
满足非第二个test+1分
--如果分数只有2,方块是SZJLT之一,并且没有把当前方块整个消除那么就是mini
攻击系统:
- 普通消除:
- 消<4行打出[消行数-0.5]攻击
- 特殊消除:
- 如果是spin,打出[2*消行数]攻击,
- B2B攻击+[1/1/2/4/8(spin1~5)]
- B3B攻击在B2B基础上+消行数*0.5,+1额外抵挡
- mini减至25%
- 不是spin但是单次消>=4行,打出[消行数]攻击,
- B2B攻击+1
- B3B攻击+50%,+1额外抵挡
- 特殊消除会增加B2B点数,让之后的特殊消除获得B2B(B3B)增益(详细说明见下文)
- 半全消("下方有剩余方块"的全消,如果是I消1行则必须不剩余玩家放置的方块):伤害+4,额外抵挡+2
- 全消:全消伤害为8~16(本局内递增2),和上述其他伤害取大,然后+2额外抵挡
- 连击:每次连击给予上述攻击[连击数*25%(上限12连)(如果只消一行就是15%)]的加成,>=3次时再额外加1攻击
- 根据上述规则计算后,向下取整,攻击打出
+ 概念说明[高级消除]:
+ Spin/消四及以上,会受到B2B(点数>=50)或B3B(点数>800)加成
+ 反之称为低级消除
+ 概念说明[特殊消除]:
+ Spin/消四及以上/PC/HPC,可以增加B2B点数
+ 反之称为普通消除
+
+ 高级消除(Spin):
+ 打出[2*消行数]攻击,然后
+ - B2B攻击+[1/1/2/4/8/14(Spin1~6)]
+ - B3B攻击在B2B基础上+消行数*0.5,+1额外抵挡
+ - mini减至25%
+ 高级消除(非Spin但是消四及以上):
+ 打出[消行数]攻击,然后
+ - B2B攻击+1
+ - B3B攻击+50%,+1额外抵挡
+ 低级消除:
+ 打出[消行数-0.5]攻击
+ 连击:
+ (注:连击数为连续消除次数-1)
+ 把上述高级消除/低级消除的攻击直接乘以"连击倍率", 公式为 "连击倍率"=[连击数(上限12)]*[消一行以上25%,只消一行15%]
+ 连击数>=2时再额外加1攻击
+ 半全消("下方有剩余方块"的全消,如果只消了1行则必须不剩余玩家放置的方块):
+ 伤害+4,额外抵挡+2
+ 全消:
+ 伤害为8~16(本局内递增2),和上述其他伤害取大,+2额外抵挡
+ 计算完成后,向下取整,攻击打出
+
+back to back(B2B)点数说明:
+ B2B点数的范围在0~1000
+
+ 落块后消行了:
+ 特殊消除:
+ Spin1~5:+[50/100/180/800/1000](mini变为原来50%)
+ 消四/五/六:+[150/200/...]
+ 本局内消行数>4时全消:+800
+ 半全消:+100
+ 普通消除:
+ -250
+ 落块后没消行:
+ 空Spin:+20
+ 点数在800以上会-40(不低于800)
分数系统:
分数计算系统非常复杂,而且随时可能更改所以不写在这里,并且计算只跟消除方式等信息有关,和模式设定无关
攻击延迟:
- 消2/3的攻击生效最快,消四其次,spin攻击生效较慢,高连击生效最慢
+ 消2/3的攻击生效最快,消四其次,Spin攻击生效较慢,高连击生效最慢
B2B或者B3B增加攻击力的同时也会减缓一点生效速度,mini大幅减缓生效速度
抵消逻辑:
发动攻击时,若缓冲条有攻击则先用额外抵挡再用攻击力1:1抵消最先受到的攻击
没有用上的额外抵挡会被丢弃,最后剩下的攻击力会发送给对手
-back to back(B2B)点数说明:
- B2B点数的范围在0~1000,在点数>=50时进行特殊消除为B2B,>800时特殊消除为B3B
- 普通消除:-250
- spin1~5:+[50/100/180/800/1000](mini变为原来50%)
- 消四/五/六:+[150/200/...]
- 本局内消行数>4时全消:+800
- 半全消:+100
- 空spin:+20,此法得到的点数不能超过800
- 当点数在800以上时空放一块-40(不低于800)
-
混战模式说明:
许多玩家同时进行一局游戏(对手都是AI,不是真人).
随着玩家数量的减少,方块下落/垃圾生效速度/垃圾升起速度都会增加.
diff --git a/parts/line.lua b/parts/line.lua
index 983d22386..84b4de92c 100644
--- a/parts/line.lua
+++ b/parts/line.lua
@@ -1,6 +1,6 @@
local LINE={}
-local L={}--Storage
-local len=0--Length
+local L={}-- Storage
+local len=0-- Length
function LINE.new(val,isGarbage)
if len==0 then
for i=1,10 do
diff --git a/parts/modes.lua b/parts/modes.lua
index c2c9bb951..706dfe194 100644
--- a/parts/modes.lua
+++ b/parts/modes.lua
@@ -1,23 +1,31 @@
-return{
+return {
{name='sprint_10l', x=0, y=0, size=40,shape=1,icon="sprint1", unlock={'sprint_20l','sprint_40l'}},
{name='sprint_20l', x=-200, y=200, size=50,shape=1,icon="sprint1"},
- {name='sprint_40l', x=0, y=-300, size=40,shape=1,icon="sprint2", unlock={'dig_10l','sprint_100l','marathon_n','sprintPenta','sprintMPH'}},
- {name='sprint_100l', x=-200, y=0, size=50,shape=1,icon="sprint2", unlock={'sprint_400l','drought_n'}},
- {name='sprint_400l', x=-400, y=0, size=40,shape=1,icon="sprint3", unlock={'sprint_1000l'}},
- {name='sprint_1000l', x=-600, y=0, size=40,shape=1,icon="sprint3"},
+ {name='sprint_40l', x=0, y=-300, size=40,shape=1,icon="sprint2", unlock={'dig_10l','sprint_100l','marathon_n','sprintPenta','sprintMPH','sprint123','secret_grade'}},
+ {name='sprint_100l', x=-400, y=200, size=50,shape=1,icon="sprint2", unlock={'sprint_400l','drought_n'}},
+ {name='sprint_400l', x=-600, y=200, size=40,shape=1,icon="sprint3", unlock={'sprint_1000l'}},
+ {name='sprint_1000l', x=-800, y=200, size=40,shape=1,icon="sprint3"},
- {name='sprintPenta', x=180, y=-160, size=40,shape=3,icon="sprint2"},
- {name='sprintMPH', x=220, y=-340, size=40,shape=3,icon="sprint2"},
+ {name='sprint123', x=160, y=-400, size=40,shape=1,icon="sprint_tri"},
+ {name='sprintMPH', x=200, y=-260, size=40,shape=3,icon="sprint2"},
+ {name='sprintPenta', x=130, y=-140, size=40,shape=3,icon="sprint_pento"},
- {name='drought_n', x=-400, y=200, size=40,shape=1,icon="drought", unlock={'drought_l'}},
- {name='drought_l', x=-600, y=200, size=40,shape=1,icon="drought"},
+ {name='secret_grade', x=-200, y=-400, size=40,shape=1,icon="secret_grade"},
- {name='dig_10l', x=-200, y=-200, size=40,shape=1,icon="dig_sprint", unlock={'dig_40l'}},
+ {name='drought_n', x=-600, y=400, size=40,shape=1,icon="drought", unlock={'drought_l'}},
+ {name='drought_l', x=-800, y=400, size=40,shape=1,icon="drought"},
+
+ {name='dig_10l', x=-200, y=-200, size=40,shape=1,icon="dig_sprint", unlock={'dig_40l','dig_eff_10l'}},
{name='dig_40l', x=-400, y=-200, size=40,shape=1,icon="dig_sprint", unlock={'dig_100l'}},
{name='dig_100l', x=-600, y=-200, size=40,shape=1,icon="dig_sprint", unlock={'dig_400l'}},
{name='dig_400l', x=-800, y=-200, size=40,shape=1,icon="dig_sprint"},
- {name='marathon_n', x=0, y=-600, size=60,shape=1,icon="marathon", unlock={'marathon_h','solo_e','round_e','blind_e','classic_e','survivor_e','clearRush','zen'}},
+ {name='dig_eff_10l', x=-400, y=0, size=40,shape=1,icon="dig_sprint", unlock={'dig_eff_40l'}},
+ {name='dig_eff_40l', x=-600, y=0, size=40,shape=1,icon="dig_sprint", unlock={'dig_eff_100l'}},
+ {name='dig_eff_100l', x=-800, y=0, size=40,shape=1,icon="dig_sprint", unlock={'dig_eff_400l'}},
+ {name='dig_eff_400l', x=-1000, y=0, size=40,shape=1,icon="dig_sprint"},
+
+ {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'}},
{name='marathon_h', x=0, y=-800, size=50,shape=1,icon="marathon", unlock={'master_n','strategy_e'}},
{name='solo_e', x=-600, y=-1000, size=40,shape=1,icon="solo", unlock={'solo_n'}},
@@ -39,77 +47,85 @@ return{
{name='round_l', x=-1200, y=-800, size=40,shape=1,icon="round", unlock={'round_u'}},
{name='round_u', x=-1400, y=-800, size=40,shape=1,icon="round"},
- {name='master_n', x=0, y=-1000, size=40,shape=1,icon="master", unlock={'master_h','strategy_h'}},
- {name='master_h', x=0, y=-1200, size=40,shape=3,icon="master", unlock={'master_final','master_ex','master_ph','master_m','strategy_u'}},
- {name='master_m', x=150, y=-1320, size=30,shape=3,icon="master"},
- {name='master_final', x=0, y=-1600, size=40,shape=2,icon="master"},
- {name='master_ph', x=-150, y=-1500, size=40,shape=2,icon="master"},
- {name='master_ex', x=150, y=-1500, size=40,shape=2,icon="master_ex"},
+ {name='big_n', x=-400, y=-400, size=40,shape=1,icon="big", unlock={'big_h'}},
+ {name='big_h', x=-600, y=-400, size=40,shape=1,icon="big",},
- {name='strategy_e', x=-150, y=-1030, size=40,shape=3,icon="master"},
- {name='strategy_h', x=-200, y=-1160, size=35,shape=3,icon="master"},
- {name='strategy_u', x=-250, y=-1290, size=30,shape=2,icon="master"},
-
- {name='blind_e', x=150, y=-700, size=40,shape=1,icon="hidden", unlock={'blind_n'}},
+ {name='master_n', x=0, y=-1000, size=40,shape=1,icon="master", unlock={'master_h','strategy_h'}},
+ {name='master_h', x=0, y=-1200, size=40,shape=3,icon="master", unlock={'master_final','master_ex','master_ph','master_m','master_g','strategy_u'}},
+ {name='master_m', x=100, y=-1550, size=40,shape=2,icon="master"},
+ {name='master_final', x=-100, y=-1550, size=40,shape=2,icon="master"},
+ {name='master_ph', x=-170, y=-1450, size=40,shape=2,icon="master"},
+ {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='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="hidden", unlock={'blind_h'}},
{name='blind_h', x=150, y=-900, size=35,shape=1,icon="hidden", unlock={'blind_l'}},
- {name='blind_l', x=150, y=-1000, size=35,shape=3,icon="hidden2", unlock={'blind_u'}},
- {name='blind_u', x=150, y=-1100, size=30,shape=3,icon="hidden2", unlock={'blind_wtf'}},
+ {name='blind_l', x=150, y=-1000, size=35,shape=3,icon="hidden2", unlock={'blind_u'}},
+ {name='blind_u', x=150, y=-1100, size=30,shape=3,icon="hidden2", unlock={'blind_wtf'}},
{name='blind_wtf', x=150, y=-1200, size=25,shape=2,icon="hidden2"},
+ {name='master_instinct',x=285, y=-835, size=40,shape=3,icon="hidden"},
{name='classic_e', x=-200, y=-850, size=40,shape=1,icon="classic", unlock={'classic_h'}},
- {name='classic_h', x=-300, y=-950, size=35,shape=2,icon="classic", unlock={'classic_u'}},
- {name='classic_u', x=-400, y=-1050, size=30,shape=2,icon="classic"},
+ {name='classic_h', x=-300, y=-950, size=40,shape=3,icon="classic", unlock={'classic_l'}},
+ {name='classic_l', x=-400, y=-1050, size=35,shape=3,icon="classic", unlock={'classic_u'}},
+ {name='classic_u', x=-500, y=-1150, size=30,shape=2,icon="classic"},
- {name='survivor_e', x=300, y=-600, size=40,shape=1,icon="survivor", unlock={'survivor_n'}},
- {name='survivor_n', x=500, y=-600, size=40,shape=1,icon="survivor", unlock={'survivor_h','attacker_h','defender_n','dig_h'}},
- {name='survivor_h', x=700, y=-600, size=40,shape=1,icon="survivor", unlock={'survivor_l'}},
- {name='survivor_l', x=900, y=-600, size=40,shape=3,icon="survivor", unlock={'survivor_u'}},
- {name='survivor_u', x=1100, y=-600, size=40,shape=2,icon="survivor"},
+ {name='survivor_e', x=450, y=-600, size=40,shape=1,icon="survivor", unlock={'survivor_n'}},
+ {name='survivor_n', x=650, y=-600, size=40,shape=1,icon="survivor", unlock={'survivor_h','attacker_h','defender_n','dig_h'}},
+ {name='survivor_h', x=850, y=-600, size=40,shape=1,icon="survivor", unlock={'survivor_l'}},
+ {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=300, y=-800, size=40,shape=1,icon="attack", unlock={'attacker_u'}},
- {name='attacker_u', x=300, y=-1000, size=40,shape=1,icon="attack"},
+ {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='defender_n', x=500, y=-800, size=40,shape=1,icon="defend", unlock={'defender_l'}},
- {name='defender_l', x=500, y=-1000, size=40,shape=1,icon="defend"},
+ {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='dig_h', x=700, y=-800, size=40,shape=1,icon="dig", unlock={'dig_u'}},
- {name='dig_u', x=700, y=-1000, size=40,shape=1,icon="dig"},
+ {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='clearRush', x=400, y=-400, size=50,shape=1,icon="bigbang", unlock={'c4wtrain_n','pctrain_n','sprintAtk'}},
- {name='c4wtrain_n', x=700, y=-400, size=40,shape=1,icon="pc", unlock={'c4wtrain_l'}},
- {name='c4wtrain_l', x=900, y=-400, size=40,shape=1,icon="pc"},
+ {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='pctrain_n', x=700, y=-250, size=40,shape=1,icon="pc", unlock={'pctrain_l','pc_n'}},
- {name='pctrain_l', x=900, y=-250, size=40,shape=1,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=-110, size=40,shape=1,icon="pc", unlock={'pc_h'}},
- {name='pc_h', x=950, y=-110, size=40,shape=3,icon="pc", unlock={'pc_l','pc_inf'}},
- {name='pc_l', x=1100, y=-110, size=40,shape=3,icon="pc"},
- {name='pc_inf', x=1100, y=-250, size=40,shape=2,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=530, y=-150, size=40,shape=1,icon="sprint2", unlock={'sprintEff','tech_n','tech_finesse','tsd_e','backfire_n'}},
+ {name='sprintAtk', x=500, y=-280, size=40,shape=1,icon="sprint2", unlock={'sprintEff','tech_n','tech_finesse','tsd_e','backfire_n'}},
{name='sprintEff', x=360, y=-150, size=40,shape=1,icon="sprint2"},
- {name='tech_n', x=400, y=50, size=40,shape=1,icon="tech", unlock={'tech_n_plus','tech_h'}},
- {name='tech_n_plus', x=200, y=20, size=40,shape=3,icon="tech"},
- {name='tech_h', x=400, y=200, size=40,shape=1,icon="tech", unlock={'tech_h_plus','tech_l'}},
- {name='tech_h_plus', x=200, y=170, size=35,shape=3,icon="tech"},
- {name='tech_l', x=400, y=350, size=40,shape=1,icon="tech", unlock={'tech_l_plus'}},
- {name='tech_l_plus', x=200, y=320, size=35,shape=3,icon="tech"},
+ {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"},
+ {name='tech_h', x=400, y=170, size=40,shape=1,icon="tech", unlock={'tech_h_plus','tech_l'}},
+ {name='tech_h_plus', x=200, y=140, size=35,shape=3,icon="tech"},
+ {name='tech_l', x=400, y=320, size=40,shape=1,icon="tech", unlock={'tech_l_plus'}},
+ {name='tech_l_plus', x=200, y=290, size=35,shape=3,icon="tech"},
- {name='tech_finesse', x=800, y=50, size=40,shape=1,icon="tech", unlock={'tech_finesse_f'}},
- {name='tech_finesse_f',x=1000, y=50, size=40,shape=1,icon="tech"},
+ {name='tech_finesse', x=800, y=20, size=40,shape=1,icon="tech", unlock={'tech_finesse_f'}},
+ {name='tech_finesse_f',x=1000, y=20, size=40,shape=1,icon="tech"},
- {name='tsd_e', x=720, y=200, size=40,shape=1,icon="tsd", unlock={'tsd_h'}},
- {name='tsd_h', x=960, y=200, size=40,shape=1,icon="tsd", unlock={'tsd_u'}},
- {name='tsd_u', x=1200, y=200, size=40,shape=1,icon="tsd"},
+ {name='tsd_e', x=720, y=170, size=40,shape=1,icon="tsd", unlock={'tsd_h'}},
+ {name='tsd_h', x=960, y=170, size=40,shape=1,icon="tsd", unlock={'tsd_u'}},
+ {name='tsd_u', x=1200, y=170, size=40,shape=1,icon="tsd"},
- {name='backfire_n', x=650, y=350, size=40,shape=1,icon="backfire", unlock={'backfire_h'}},
- {name='backfire_h', x=850, y=350, size=40,shape=1,icon="backfire", unlock={'backfire_l'}},
- {name='backfire_l', x=1050, y=350, size=40,shape=3,icon="backfire", unlock={'backfire_u'}},
- {name='backfire_u', x=1250, y=350, size=35,shape=2,icon="backfire"},
+ {name='backfire_n', x=650, y=320, size=40,shape=1,icon="backfire", unlock={'backfire_h'}},
+ {name='backfire_h', x=850, y=320, size=40,shape=1,icon="backfire", unlock={'backfire_l'}},
+ {name='backfire_l', x=1050, y=320, size=40,shape=3,icon="backfire", unlock={'backfire_u'}},
+ {name='backfire_u', x=1250, y=320, size=35,shape=2,icon="backfire"},
{name='zen', x=-1000, y=-600, size=40,shape=1,icon="zen", unlock={'ultra','infinite','infinite_dig','marathon_inf'}},
{name='ultra', x=-1200, y=-600, size=40,shape=1,icon="ultra"},
diff --git a/parts/modes/PCbase.lua b/parts/modes/PCbase.lua
index 73b2b7d35..e302db6af 100644
--- a/parts/modes/PCbase.lua
+++ b/parts/modes/PCbase.lua
@@ -1,4 +1,4 @@
-return{
+return {
{
{
{4,4,4,3,3,3,7,0,0,0},
@@ -24,7 +24,7 @@ return{
{3,2,6,6,1,4,0,0,0,7},
{3,3,3,4,4,4,0,0,0,7},
},
- },--3*4 shape
+ },-- 3*4 shape
{
{
{1,1,0,0,0,0,0,3,3,3},
@@ -50,7 +50,7 @@ return{
{3,6,6,5,5,2,2,0,0,0},
{3,3,3,5,2,2,0,0,0,0},
},
- },--7 piece opener(right>)(without i)
+ },-- 7 piece opener(right>)(without i)
{
{
{4,4,4,3,3,3,0,0,0,0},
@@ -64,7 +64,7 @@ return{
{3,2,6,6,1,4,0,0,0,0},
{3,3,3,4,4,4,0,0,0,0},
},
- },--6 piece opener
+ },-- 6 piece opener
{
{
{0,0,0,0,0,1,3,5,6,7},
@@ -84,7 +84,7 @@ return{
{1,3,0,0,0,0,0,5,6,7},
{1,3,0,0,0,0,0,5,6,7},
},
- },--4*5
+ },-- 4*5
{
{
{0,0,0,0,0,0,1,3,5,7},
@@ -104,5 +104,5 @@ return{
{5,7,0,0,0,0,0,0,3,1},
{1,3,0,0,0,0,0,0,7,5},
},
- },--4*6
+ },-- 4*6
}
diff --git a/parts/modes/PClist.lua b/parts/modes/PClist.lua
index 4f7b847b4..49a912b17 100644
--- a/parts/modes/PClist.lua
+++ b/parts/modes/PClist.lua
@@ -1,16 +1,16 @@
-return{
- --3*4 shape
+return {
+ -- 3*4 shape
{{1,3,3},{1,3,4},{1,5,3},{3,1,3},{3,1,4},{3,2,4},{3,3,2},{3,3,5},{3,3,6},{3,3,7},{3,4,1},{3,4,5},{3,4,6},{3,5,3},{3,5,4},{3,5,5},{3,6,3},{3,6,4},{3,7,3},{3,7,4},{5,3,4},{5,3,5},{5,5,1},{5,5,3},{5,7,3},{6,3,3},{6,3,4},{6,6,7},{6,7,6},{7,3,3},{7,3,4},{7,5,3},{7,6,6},{7,7,7}},
- --7 piece opener (right>)
+ -- 7 piece opener (right>)
{{5,3,4,4},{5,3,7,7},{5,7,4,4},{4,2,4,4},{3,5,4,4},{3,4,5,4},{3,3,7,4},{7,5,4,4},{1,5,1,1},{1,5,5,5},{1,5,7,4},{1,2,4,5},{1,4,5,5},{1,4,5,2},{1,4,2,5},{1,4,4,4},{5,1,4,5},{5,5,4,1},{5,5,4,2},{5,5,4,4},{5,4,5,4},{5,4,4,5},{5,4,4,3},{5,7,4,6},{5,7,4,3},{2,5,4,4},{6,4,4,4},{6,7,4,6},{4,1,2,5},{4,1,4,4},{4,5,4,5},{4,5,7,7},{4,6,4,4},{4,4,6,4},{4,4,3,5},{4,4,3,6},{4,3,4,5},{4,3,4,6},{4,7,3,4},{4,7,7,5},{3,1,4,4},{3,1,4,3},{3,1,3,4},{3,5,5,4},{3,5,4,5},{3,5,7,7},{3,2,5,2},{3,2,4,4},{3,6,4,4},{3,6,3,3},{3,4,1,3},{3,4,4,5},{3,4,4,6},{3,4,3,7},{3,3,6,3},{3,7,5,7},{3,7,4,3},{3,7,3,4},{7,5,4,6},{7,5,4,3},{7,5,3,4},{7,5,7,1},{7,6,4,6},{7,4,1,5},{7,4,5,6},{7,4,3,4},{7,4,7,5},{7,3,1,5},{7,3,5,7},{7,3,4,4},{7,3,3,4},{7,3,7,5},{7,7,4,5},{7,7,7,4},{1,1,5,2},{1,1,7,4},{1,5,1,2},{1,5,1,3},{1,5,5,2},{1,5,2,1},{1,5,2,3},{1,5,6,3},{1,5,6,7},{1,5,4,1},{1,5,4,5},{1,5,4,2},{1,5,4,3},{1,5,4,7},{1,5,3,1},{1,5,3,4},{1,5,7,2},{1,5,7,6},{1,5,7,7},{1,2,5,1},{1,2,5,4},{1,2,7,4},{1,4,1,5},{1,4,5,1},{1,4,5,4},{1,4,6,5},{1,4,4,3},{1,4,3,3},{1,3,1,2},{1,3,5,2},{1,3,4,4},{1,3,4,3},{1,3,3,4},{1,7,1,4},{1,7,5,6},{1,7,5,4},{1,7,5,3},{1,7,5,7},{1,7,2,3},{1,7,6,4},{1,7,4,1},{1,7,4,5},{1,7,4,7},{1,7,3,1},{1,7,7,4},{5,1,5,5},{5,1,5,2},{5,1,5,4},{5,1,2,3},{5,1,6,3},{5,1,4,1},{5,1,4,2},{5,1,4,7},{5,1,7,2},{5,1,7,4},{5,5,1,5},{5,5,1,2},{5,5,1,4},{5,5,5,1},{5,5,5,2},{5,5,5,4},{5,5,5,7},{5,5,2,1},{5,5,2,5},{5,5,6,7},{5,5,4,5},{5,5,4,3},{5,5,3,1},{5,5,3,4},{5,5,7,5},{5,5,7,6},{5,2,1,3},{5,2,5,4},{5,2,4,5},{5,2,3,1},{5,2,3,6},{5,2,7,1},{5,6,1,3},{5,6,5,7},{5,6,6,1},{5,4,1,5},{5,4,1,7},{5,4,5,1},{5,4,5,5},{5,4,5,2},{5,4,5,3},{5,4,2,5},{5,4,4,1},{5,4,4,4},{5,4,3,1},{5,4,3,5},{5,4,3,4},{5,4,7,1},{5,3,5,4},{5,3,5,3},{5,3,2,2},{5,3,6,6},{5,3,4,1},{5,3,4,5},{5,3,4,3},{5,3,3,1},{5,3,3,4},{5,3,3,3},{5,7,1,2},{5,7,1,4},{5,7,1,3},{5,7,5,5},{5,7,5,7},{5,7,2,1},{5,7,6,4},{5,7,6,7},{5,7,4,1},{5,7,4,2},{5,7,4,7},{5,7,3,1},{5,7,3,2},{5,7,3,6},{5,7,3,4},{5,7,3,7},{5,7,7,1},{5,7,7,6},{5,7,7,4},{5,7,7,3},{2,1,5,1},{2,1,4,5},{2,1,7,4},{2,5,1,1},{2,5,4,5},{2,5,3,6},{2,4,1,5},{2,4,4,4},{2,4,4,3},{2,3,5,6},{2,7,1,4},{2,7,5,5},{2,7,4,1},{2,7,3,7},{2,7,7,3},{6,5,6,1},{6,5,3,1},{6,6,5,1},{6,6,4,5},{6,6,7,4},{6,4,6,5},{6,4,7,5},{6,3,4,3},{6,3,3,4},{6,7,6,4},{6,7,4,1},{6,7,4,5},{6,7,4,7},{6,7,7,4},{4,1,1,5},{4,1,5,1},{4,1,5,5},{4,1,5,2},{4,1,5,7},{4,1,6,5},{4,1,4,3},{4,1,3,4},{4,1,3,3},{4,1,7,5},{4,5,5,4},{4,5,4,1},{4,5,4,4},{4,5,4,3},{4,5,3,1},{4,5,3,5},{4,2,1,5},{4,2,4,3},{4,2,3,4},{4,6,6,5},{4,6,4,3},{4,6,3,4},{4,4,1,4},{4,4,1,3},{4,4,5,1},{4,4,5,4},{4,4,5,3},{4,4,2,4},{4,4,4,1},{4,4,4,5},{4,4,4,6},{4,4,7,4},{4,4,7,3},{4,3,6,4},{4,3,4,7},{4,3,3,5},{4,3,7,4},{4,7,1,5},{4,7,5,6},{4,7,5,7},{4,7,2,1},{4,7,2,5},{4,7,6,5},{4,7,4,4},{4,7,4,3},{3,1,1,2},{3,1,5,1},{3,1,5,2},{3,1,2,1},{3,1,6,5},{3,1,6,7},{3,1,7,6},{3,5,1,2},{3,5,5,1},{3,5,5,6},{3,5,5,3},{3,5,2,1},{3,5,2,2},{3,5,6,5},{3,5,6,6},{3,5,4,1},{3,5,4,3},{3,5,3,1},{3,5,3,5},{3,5,3,4},{3,5,3,3},{3,2,1,5},{3,2,5,1},{3,2,2,5},{3,6,1,5},{3,6,1,7},{3,6,5,5},{3,6,5,6},{3,6,6,5},{3,6,4,3},{3,6,3,4},{3,4,5,3},{3,4,2,4},{3,4,6,4},{3,4,6,3},{3,4,3,1},{3,4,3,5},{3,4,3,2},{3,4,3,6},{3,4,7,3},{3,3,1,4},{3,3,5,1},{3,3,5,4},{3,3,5,3},{3,3,6,4},{3,3,4,1},{3,3,4,5},{3,3,4,2},{3,3,4,6},{3,3,4,7},{3,3,3,1},{3,3,3,5},{3,3,3,6},{3,7,1,5},{3,7,5,1},{3,7,5,2},{3,7,2,5},{3,7,6,5},{3,7,7,5},{7,1,1,4},{7,1,5,6},{7,1,5,4},{7,1,5,3},{7,1,5,7},{7,1,2,3},{7,1,6,4},{7,1,4,1},{7,1,4,5},{7,1,4,7},{7,1,3,1},{7,1,7,4},{7,5,1,2},{7,5,1,6},{7,5,1,4},{7,5,1,3},{7,5,1,7},{7,5,5,5},{7,5,5,7},{7,5,2,1},{7,5,6,4},{7,5,6,7},{7,5,4,1},{7,5,4,2},{7,5,4,7},{7,5,3,1},{7,5,3,2},{7,5,3,6},{7,5,3,7},{7,5,7,6},{7,5,7,4},{7,5,7,3},{7,2,1,4},{7,2,1,3},{7,2,5,5},{7,2,4,1},{7,2,3,7},{7,2,7,3},{7,6,1,4},{7,6,5,4},{7,6,6,4},{7,6,4,1},{7,6,4,5},{7,6,4,7},{7,6,7,4},{7,4,5,1},{7,4,5,2},{7,4,5,7},{7,4,2,1},{7,4,2,5},{7,4,6,5},{7,4,4,4},{7,4,4,3},{7,3,5,1},{7,3,5,2},{7,3,5,6},{7,3,5,4},{7,3,2,5},{7,3,2,7},{7,3,6,1},{7,3,6,5},{7,3,4,3},{7,3,7,2},{7,3,7,6},{7,7,1,4},{7,7,5,1},{7,7,5,6},{7,7,5,4},{7,7,5,3},{7,7,2,3},{7,7,6,4},{7,7,6,3},{7,7,4,7},{7,7,3,6}},
- --6 piece opener
+ -- 6 piece opener
{{1,1,3,4},{1,1,4,3},{1,2,5,3},{1,2,5,4},{1,3,4,7},{1,3,5,5},{1,3,7,3},{1,3,7,4},{1,4,1,4},{1,4,4,6},{1,5,2,3},{1,5,3,2},{1,5,3,5},{1,5,4,7},{1,5,5,2},{1,5,5,4},{1,5,5,5},{1,5,7,3},{1,5,7,4},{1,6,3,3},{1,6,5,3},{1,7,3,3},{1,7,3,4},{1,7,5,3},{1,7,5,4},{3,1,3,7},{3,1,4,7},{3,1,5,5},{3,1,6,3},{3,1,7,3},{3,1,7,4},{3,2,2,3},{3,2,3,2},{3,2,3,6},{3,2,4,5},{3,2,4,7},{3,2,5,5},{3,2,6,3},{3,2,6,4},{3,2,7,4},{3,3,1,5},{3,3,2,6},{3,3,2,7},{3,3,3,3},{3,3,3,4},{3,3,4,3},{3,3,4,4},{3,3,5,3},{3,3,5,4},{3,3,6,1},{3,3,6,6},{3,3,6,7},{3,3,7,2},{3,3,7,5},{3,3,7,6},{3,3,7,7},{3,4,1,2},{3,4,1,5},{3,4,1,7},{3,4,2,1},{3,4,2,5},{3,4,2,7},{3,4,3,3},{3,4,3,4},{3,4,4,3},{3,4,4,4},{3,4,5,3},{3,4,5,4},{3,4,5,7},{3,4,6,1},{3,4,6,2},{3,4,6,7},{3,4,7,1},{3,4,7,2},{3,4,7,5},{3,4,7,6},{3,5,1,2},{3,5,2,3},{3,5,2,5},{3,5,3,2},{3,5,3,3},{3,5,3,4},{3,5,4,3},{3,5,4,6},{3,5,4,7},{3,5,5,5},{3,5,5,7},{3,5,6,4},{3,5,7,3},{3,5,7,4},{3,5,7,5},{3,6,1,3},{3,6,2,3},{3,6,2,4},{3,6,3,1},{3,6,3,5},{3,6,3,6},{3,6,3,7},{3,6,4,2},{3,6,4,7},{3,6,5,4},{3,6,6,3},{3,6,6,4},{3,6,7,3},{3,6,7,4},{3,7,1,3},{3,7,1,4},{3,7,2,4},{3,7,3,2},{3,7,3,5},{3,7,3,6},{3,7,3,7},{3,7,4,1},{3,7,4,2},{3,7,4,5},{3,7,4,6},{3,7,5,3},{3,7,5,4},{3,7,5,5},{3,7,6,3},{3,7,6,4},{3,7,7,3},{3,7,7,4},{5,1,2,3},{5,1,3,2},{5,1,3,4},{5,1,4,1},{5,1,4,7},{5,1,5,4},{5,1,5,5},{5,1,7,4},{5,3,1,2},{5,3,1,4},{5,3,2,5},{5,3,3,3},{5,3,3,4},{5,3,3,6},{5,3,4,3},{5,3,5,2},{5,3,5,4},{5,3,5,5},{5,3,5,7},{5,3,7,4},{5,3,7,5},{5,5,1,2},{5,5,1,4},{5,5,3,2},{5,5,3,3},{5,5,3,4},{5,5,3,5},{5,5,3,7},{5,5,5,1},{5,5,5,5},{5,5,6,3},{5,5,6,7},{5,5,7,1},{5,5,7,3},{5,5,7,6},{5,6,3,5},{5,6,3,6},{5,6,3,7},{5,6,5,3},{5,6,6,3},{5,6,7,3},{5,7,1,4},{5,7,3,4},{5,7,3,5},{5,7,5,1},{5,7,5,3},{5,7,5,6},{5,7,6,3},{5,7,7,3},{6,1,3,3},{6,3,3,5},{6,3,3,6},{6,3,3,7},{6,3,4,7},{6,3,6,3},{6,3,6,4},{6,3,7,3},{6,3,7,4},{6,5,3,5},{6,5,3,6},{6,5,3,7},{6,5,6,3},{6,5,7,3},{6,6,3,3},{6,6,3,4},{6,6,5,3},{6,6,6,6},{6,6,7,7},{6,7,3,3},{6,7,3,4},{6,7,5,3},{6,7,6,7},{6,7,7,6},{7,1,3,3},{7,1,3,4},{7,1,5,3},{7,1,5,4},{7,3,1,3},{7,3,1,4},{7,3,2,4},{7,3,3,2},{7,3,3,5},{7,3,3,6},{7,3,3,7},{7,3,4,1},{7,3,4,2},{7,3,4,5},{7,3,4,6},{7,3,5,3},{7,3,5,4},{7,3,5,5},{7,3,6,3},{7,3,6,4},{7,3,7,3},{7,3,7,4},{7,5,1,4},{7,5,3,4},{7,5,3,5},{7,5,5,1},{7,5,5,3},{7,5,5,6},{7,5,6,3},{7,5,7,3},{7,6,3,3},{7,6,3,4},{7,6,5,3},{7,6,6,7},{7,6,7,6},{7,7,3,3},{7,7,3,4},{7,7,5,3},{7,7,6,6},{7,7,7,7}},
- --4*5
+ -- 4*5
{{7,3,5,1,2},{7,3,1,5,5},{7,3,1,5,4},{7,3,1,5,3},{2,3,7,6,4},{2,3,7,6,3},{3,2,7,6,4},{3,2,7,6,3},{3,2,6,7,4},{3,2,6,7,3},{7,1,3,5,5},{7,1,3,5,4},{7,1,3,5,3},{5,7,1,2,4},{5,7,1,2,3},{1,7,3,5,5},{5,1,7,2,3},{1,7,5,3,5},{1,7,5,3,2},{1,5,7,2,3},{7,1,5,3,5},{7,1,5,3,4},{7,1,5,3,3},{7,1,5,3,2},{1,5,2,7,3},{7,5,1,3,4},{5,1,2,7,4},{7,5,1,3,3},{5,1,2,7,3},{7,5,1,3,2},{7,5,3,1,5},{7,5,3,1,4},{7,5,3,1,3},{7,5,3,1,2},{5,7,3,2,5},{5,7,3,2,7},{5,7,3,2,4},{5,7,2,3,5},{5,7,2,3,7},{5,7,2,3,2},{5,2,7,3,5},{5,2,7,3,7},{5,2,7,3,3},{5,2,7,3,2},{2,1,5,7,4},{2,5,7,3,7},{2,5,7,3,3},{3,6,2,7,4},{3,6,2,7,3},{6,3,2,7,4},{6,3,2,7,3},{6,3,7,2,3},{3,6,7,2,4},{3,6,7,2,3},{3,7,6,2,4},{3,7,6,2,3},{1,2,7,5,4},{1,2,7,5,3},{2,7,1,5,4},{2,7,1,5,3},{2,7,5,1,4},{7,2,5,1,4},{7,2,5,1,3},{7,2,1,5,4},{7,2,1,5,3},{3,7,2,6,4},{3,7,2,6,3},{7,5,1,2,4},{7,3,2,1,3},{7,5,1,2,3},{7,3,1,2,4},{7,3,1,2,3},{7,1,3,2,4},{2,5,3,7,5},{2,5,3,7,3},{5,2,3,7,3},{5,3,2,7,5},{5,3,2,7,3},{5,3,7,2,5},{5,3,7,2,4},{5,3,7,2,3},{3,5,7,2,5},{3,5,7,2,4},{3,5,7,2,3},{3,5,2,7,5},{3,5,2,7,3},{3,2,5,7,5},{3,2,5,7,3},{2,3,5,7,5},{2,3,5,7,3},{2,3,5,7,2},{2,3,7,5,5},{2,3,7,5,4},{2,3,7,5,3},{2,3,7,5,6},{3,2,7,5,5},{3,2,7,5,7},{3,2,7,5,4},{3,2,7,5,3},{3,2,7,5,6},{3,7,2,5,5},{3,7,2,5,7},{3,7,2,5,4},{3,7,2,5,3},{3,7,2,5,6},{3,7,5,2,5},{3,7,5,2,7},{3,7,5,2,4},{3,7,5,2,3},{3,7,5,2,6},{7,3,5,2,5},{7,3,5,2,3},{7,3,2,5,5},{2,7,3,5,4},{2,7,3,5,3},{2,7,3,5,6},{2,7,5,3,7},{7,2,5,3,7},{7,2,5,3,3},{7,5,2,3,5},{7,5,2,3,7},{7,5,2,3,4},{7,5,2,3,3},{7,5,2,3,2},{7,5,3,2,5},{7,5,3,2,3},{5,7,4,6,5},{5,7,4,6,3},{5,7,4,6,2},{5,7,6,4,5},{5,7,6,4,7},{5,7,6,4,1},{5,7,6,4,6},{5,6,7,4,5},{5,6,7,4,7},{5,6,7,4,3},{5,6,7,4,1},{5,6,7,4,6},{6,5,7,4,5},{6,5,7,4,7},{6,5,7,4,3},{6,5,7,4,1},{6,5,7,4,6},{6,5,4,7,5},{6,5,4,7,3},{5,6,4,7,5},{5,6,4,7,3},{5,4,6,7,3},{5,4,7,6,5},{5,4,7,6,3},{4,5,7,6,5},{4,5,7,6,4},{4,5,7,6,3},{4,5,6,7,3},{4,6,5,7,3},{6,4,5,7,5},{6,4,7,5,4},{4,6,7,5,4},{4,6,7,5,3},{4,7,6,5,4},{4,7,6,5,3},{4,7,5,6,4},{4,7,5,6,3},{7,4,5,6,5},{7,4,5,6,4},{7,4,5,6,3},{7,4,6,5,5},{7,4,6,5,7},{7,4,6,5,4},{7,4,6,5,3},{7,6,4,5,5},{7,6,4,5,7},{7,6,4,5,3},{6,7,5,4,5},{6,7,5,4,7},{6,7,5,4,6},{7,6,5,4,5},{7,6,5,4,7},{7,6,5,4,3},{7,6,5,4,6},{7,5,6,4,5},{7,5,6,4,7},{7,5,6,4,3},{7,5,6,4,6},{7,5,4,6,5},{7,5,4,6,4},{7,5,4,6,3},{5,3,1,6,5},{5,3,1,6,7},{5,3,6,1,5},{5,3,6,1,7},{1,5,6,3,5},{1,5,6,3,7},{1,5,6,3,6},{1,6,5,3,5},{1,6,5,3,7},{1,6,5,3,3},{1,6,5,3,6},{6,1,5,3,5},{6,1,5,3,7},{6,1,5,3,3},{6,1,5,3,6},{6,1,3,5,5},{1,6,3,5,5},{1,3,6,5,7},{1,3,5,6,7},{3,1,6,5,7},{3,6,1,5,7},{6,3,1,5,5},{3,6,5,1,5},{3,5,6,1,5},{3,5,6,1,7},{3,5,1,6,5},{3,5,1,6,7},{5,3,2,6,5},{5,6,2,3,3},{5,2,6,3,3},{5,2,3,6,5},{6,2,3,5,7},{6,2,3,5,3},{6,2,3,5,6},{2,6,3,5,7},{2,6,3,5,3},{2,6,3,5,6},{2,3,6,5,3},{2,3,6,5,6},{7,1,2,3,4},{5,7,3,1,5},{6,3,2,5,7},{5,7,3,1,4},{5,7,3,1,3},{5,7,3,1,2},{5,7,1,3,4},{5,7,1,3,2},{5,7,1,3,1},{5,1,7,3,4},{5,1,7,3,3},{5,1,7,3,2},{5,1,7,3,1},{3,5,2,6,5},{1,5,7,3,5},{1,5,7,3,3},{1,5,7,3,2},{5,3,2,1,5},{1,5,7,3,1},{5,3,2,1,4},{1,5,3,7,5},{1,5,3,7,3},{5,3,1,2,5},{5,3,1,2,1},{5,1,3,7,4},{5,1,3,7,3},{5,1,3,2,5},{5,3,1,7,4},{1,5,3,2,5},{5,3,1,7,3},{5,3,1,7,6},{5,3,7,1,5},{5,3,7,1,4},{1,5,2,3,5},{5,3,7,1,3},{1,5,2,3,7},{5,3,7,1,2},{1,5,2,3,2},{3,5,7,1,5},{5,1,2,3,5},{3,5,7,1,2},{5,2,1,3,5},{5,2,1,3,3},{3,5,1,7,6},{4,3,1,7,7},{4,3,1,7,2},{4,3,1,7,6},{4,1,3,7,5},{4,1,3,7,7},{4,1,3,7,2},{4,1,3,7,6},{1,4,3,7,5},{1,4,3,7,7},{3,1,5,7,5},{1,4,7,3,5},{1,4,7,3,7},{1,3,5,7,5},{1,4,7,3,2},{1,4,7,3,1},{1,3,5,7,6},{1,3,7,5,5},{3,1,7,5,5},{1,4,7,3,6},{4,1,7,3,5},{4,1,7,3,7},{3,7,1,5,5},{4,1,7,3,2},{4,1,7,3,1},{4,1,7,3,6},{4,7,1,3,5},{4,7,1,3,7},{3,7,5,1,3},{3,7,5,1,2},{7,3,5,1,5},{7,3,5,1,4},{7,3,5,1,3},{3,5,2,4,4},{7,2,1,3,4},{3,5,2,4,3},{3,5,2,4,1},{3,2,5,4,4},{3,2,5,4,3},{3,2,5,4,1},{7,2,3,1,3},{2,3,5,4,6},{2,3,4,5,4},{2,3,4,5,3},{2,3,4,5,6},{3,2,4,5,5},{2,7,3,1,4},{2,7,3,1,3},{3,2,4,5,4},{3,2,4,5,3},{3,4,2,5,5},{3,4,2,5,3},{3,4,5,2,5},{4,3,5,2,5},{4,3,2,5,5},{4,3,2,5,4},{4,2,3,5,4},{4,2,3,5,3},{2,4,3,5,4},{2,4,3,5,3},{2,4,5,3,5},{2,4,5,3,4},{2,4,5,3,3},{4,2,5,3,5},{4,2,5,3,4},{4,2,5,3,3},{4,5,2,3,4},{4,5,2,3,3},{4,5,3,2,5},{4,5,3,2,7},{4,5,3,2,4},{5,7,1,6,4},{5,7,6,1,4},{5,1,7,6,4},{1,5,7,6,3},{1,5,6,7,3},{1,6,5,7,3},{6,1,5,7,3},{1,6,7,5,3},{1,7,6,5,3},{7,1,6,5,3},{7,6,5,1,4},{7,5,6,1,4},{7,5,1,6,4},{2,3,7,1,4},{3,2,7,1,4},{3,2,7,1,3},{3,2,1,7,3},{3,1,2,7,3},{1,3,2,7,3},{1,3,7,2,4},{3,1,7,2,4},{3,7,1,2,4},{3,7,2,1,4},{7,4,1,6,4},{7,4,1,6,3},{7,4,6,1,4},{7,4,6,1,3},{7,6,4,1,4},{7,6,4,1,3},{7,6,3,1,4},{7,6,3,1,3},{6,7,1,3,3},{7,6,1,3,3},{7,1,6,3,3},{7,1,3,6,4},{7,1,3,6,3},{1,7,3,6,4},{1,7,3,6,3},{1,7,6,3,3},{1,6,7,3,3},{6,1,7,3,3},{6,1,3,7,3},{1,6,3,7,3},{1,3,7,6,3},{3,1,7,6,3},{3,1,6,7,4},{3,1,6,7,3},{3,6,1,7,4},{3,6,1,7,3},{6,3,1,7,4},{6,3,1,7,3},{3,6,7,1,3},{3,7,6,1,3},{3,7,1,6,3},{7,6,2,3,4},{7,6,2,3,3},{7,2,6,3,4},{7,2,6,3,3},{7,2,3,6,4},{7,2,3,6,3},{2,7,3,6,4},{2,7,3,6,3},{2,7,6,3,3},{2,6,7,3,4},{6,2,7,3,4},{6,2,3,7,4},{2,6,3,7,4},{2,3,6,7,4},{5,7,4,3,4},{5,7,4,3,3},{5,7,4,3,2},{5,7,4,3,6},{5,3,7,4,7},{5,3,7,4,3},{5,3,7,4,2},{5,3,7,4,1},{5,3,7,4,6},{3,5,7,4,7},{3,5,7,4,4},{3,5,7,4,3},{3,5,7,4,2},{3,5,7,4,1},{3,5,7,4,6},{3,5,4,7,4},{3,5,4,7,3},{5,3,4,7,3},{4,3,5,7,4},{4,3,5,7,3},{4,7,1,3,2},{4,7,1,3,6},{4,7,3,1,5},{4,7,3,1,7},{3,4,7,5,7},{4,7,3,1,2},{3,4,7,5,4},{3,4,7,5,3},{3,4,7,5,2},{3,4,7,5,1},{3,4,7,5,6},{7,4,3,2,5},{7,4,3,2,7},{7,4,3,2,1},{7,4,2,3,5},{4,7,3,5,7},{4,7,3,5,4},{7,4,2,3,7},{4,7,3,5,3},{4,7,3,5,2},{4,7,3,5,6},{7,4,2,3,1},{4,7,5,3,7},{7,4,2,3,6},{4,7,5,3,4},{7,2,4,3,5},{4,7,5,3,3},{4,7,5,3,2},{7,2,4,3,7},{4,7,5,3,1},{4,7,5,3,6},{7,4,5,3,7},{7,2,4,3,1},{7,4,5,3,4},{7,2,4,3,6},{7,4,5,3,3},{2,7,4,3,7},{7,4,5,3,6},{7,4,3,5,7},{7,4,3,5,4},{2,7,4,3,1},{7,4,3,5,3},{2,7,4,3,6},{2,7,3,4,5},{7,4,3,5,6},{2,7,3,4,2},{2,7,3,4,1},{2,7,3,4,6},{7,2,3,4,7},{7,2,3,4,2},{7,2,3,4,1},{7,2,3,4,6},{7,3,2,4,5},{7,3,2,4,7},{7,3,2,4,1},{7,3,2,4,6},{7,3,4,2,5},{7,3,4,2,7},{7,5,3,4,4},{7,5,3,4,3},{7,3,4,2,1},{4,6,3,2,7},{4,6,3,2,1},{4,6,3,2,6},{6,4,3,2,5},{6,4,3,2,7},{6,4,3,2,1},{6,4,3,2,6},{6,4,2,3,7},{6,4,2,3,6},{4,6,2,3,7},{3,4,2,7,5},{4,6,2,3,6},{4,2,6,3,7},{4,2,6,3,6},{3,4,7,2,5},{3,4,7,2,7},{4,2,3,6,6},{3,4,7,2,1},{4,3,7,2,5},{4,3,7,2,7},{2,4,3,6,6},{4,3,7,2,1},{4,3,2,7,5},{4,3,2,7,7},{4,3,2,7,1},{2,4,6,3,6},{4,2,3,7,5},{4,2,3,7,7},{4,2,3,7,6},{2,4,3,7,5},{2,4,3,7,7},{2,4,7,3,5},{2,4,7,3,7},{4,2,7,3,5},{2,6,3,4,6},{4,2,7,3,7},{4,2,7,3,6},{2,3,6,4,6},{4,7,2,3,7},{2,3,4,6,6},{3,2,4,6,7},{4,7,3,2,5},{4,7,3,2,7},{3,2,4,6,6},{3,2,6,4,5},{3,2,6,4,7},{4,7,3,2,1},{3,2,6,4,6},{3,6,2,4,5},{3,6,2,4,7},{3,6,2,4,6},{6,3,2,4,5},{6,3,2,4,7},{6,3,2,4,6},{6,3,4,2,5},{6,3,4,2,7},{6,3,4,2,1},{6,3,4,2,6},{3,6,4,2,5},{3,6,4,2,7},{3,6,4,2,1},{3,4,2,6,7},{6,7,3,4,1},{4,3,1,2,7},{6,7,3,4,6},{7,6,3,4,5},{7,6,3,4,7},{7,6,3,4,2},{7,6,3,4,1},{7,3,6,4,5},{7,3,6,4,7},{7,3,6,4,2},{4,3,1,2,6},{7,3,6,4,1},{7,3,6,4,6},{4,1,3,2,7},{7,3,4,6,5},{7,3,4,6,7},{7,3,4,6,2},{7,3,4,6,1},{4,1,3,2,6},{7,3,4,6,6},{3,7,4,6,5},{3,7,4,6,7},{3,7,4,6,2},{3,7,4,6,1},{3,7,4,6,6},{3,7,6,4,5},{3,7,6,4,7},{3,7,6,4,2},{3,7,6,4,1},{3,7,6,4,6},{3,6,7,4,5},{3,6,7,4,7},{3,6,7,4,2},{3,6,7,4,1},{3,6,7,4,6},{6,3,7,4,7},{6,3,7,4,2},{6,3,7,4,1},{6,3,7,4,6},{6,3,4,7,7},{6,3,4,7,2},{6,3,4,7,1},{6,3,4,7,6},{3,6,4,7,7},{3,6,4,7,2},{3,6,4,7,1},{3,6,4,7,6},{3,4,6,7,7},{3,4,6,7,2},{3,4,6,7,1},{3,4,6,7,6},{3,4,7,6,5},{3,4,7,6,7},{3,4,7,6,2},{3,4,7,6,1},{2,1,5,4,7},{2,1,5,4,1},{1,2,4,5,7},{1,2,4,5,4},{2,1,4,5,7},{2,1,4,5,4},{2,4,1,5,5},{2,4,1,5,7},{2,4,5,1,5},{4,2,5,1,5},{4,2,1,5,5},{4,2,1,5,7},{4,1,2,5,5},{1,4,2,5,4},{1,4,5,2,5},{4,1,5,2,5},{4,1,5,2,3},{4,5,1,2,5},{4,5,1,2,3},{4,5,2,1,5},{4,5,2,1,2},{5,4,3,6,4},{5,4,3,6,3},{7,4,2,6,4},{7,4,2,6,3},{5,4,6,3,4},{5,4,6,3,3},{7,4,6,2,4},{7,4,6,2,3},{5,6,4,3,4},{6,5,4,3,4},{3,5,4,6,5},{3,5,4,6,4},{3,5,4,6,3},{3,5,6,4,5},{3,5,6,4,7},{3,5,6,4,4},{3,5,6,4,3},{3,6,5,4,5},{3,6,5,4,7},{3,6,5,4,4},{3,6,5,4,3},{6,3,5,4,4},{6,3,5,4,3},{2,1,4,6,4},{6,7,4,3,7},{3,2,1,6,4},{2,4,1,6,4},{6,3,2,1,3},{3,1,2,6,3},{6,2,1,3,3},{6,2,3,1,3},{2,3,1,6,4},{2,1,3,4,6},{2,3,1,4,6},{2,3,4,1,2},{2,3,4,1,1},{3,2,1,4,2},{3,2,1,4,1},{3,2,1,4,6},{3,1,2,4,2},{3,1,2,4,1},{1,3,2,4,2},{1,3,2,4,1},{1,3,4,2,2},{1,3,4,2,1},{3,1,4,2,2},{3,1,4,2,1},{5,1,4,2,5},{5,1,4,2,4},{1,5,4,2,5},{1,5,4,2,4},{1,5,2,4,4},{2,1,4,3,6},{5,4,3,1,5},{5,4,3,1,7},{5,4,3,1,3},{5,4,1,3,5},{5,4,1,3,4},{5,4,1,3,3},{5,4,1,3,2},{5,1,4,3,5},{5,1,4,3,3},{1,5,4,3,6},{1,5,3,4,5},{1,5,3,4,4},{1,5,3,4,3},{5,1,3,4,5},{5,1,3,4,4},{5,1,3,4,3},{5,3,1,4,5},{5,3,1,4,4},{5,3,1,4,3},{5,3,4,1,5},{5,3,4,1,7},{5,3,4,1,3},{4,5,1,3,5},{4,5,3,1,5},{4,5,3,1,3},{6,3,4,5,4},{6,3,4,5,3},{3,6,4,5,7},{3,6,4,5,4},{3,6,4,5,3},{3,4,6,5,7},{3,4,6,5,4},{3,4,6,5,3}},
- --4*6
+ -- 4*6
{{1,6,5,3,7,5},{1,6,5,3,7,3},{1,6,5,3,7,2},{5,1,6,3,2,5},{5,1,6,3,2,7},{5,1,6,3,2,6},{5,6,1,3,2,5},{5,6,1,3,2,7},{5,6,1,3,2,6},{6,5,1,3,2,5},{6,1,5,3,7,5},{6,5,1,3,2,7},{6,1,5,3,7,3},{6,1,5,3,7,2},{6,5,1,3,2,6},{6,1,5,3,2,5},{3,4,7,1,5,5},{6,1,5,3,2,7},{5,7,2,1,4,5},{3,4,7,1,5,3},{3,4,7,1,5,2},{3,4,7,1,5,1},{3,4,7,1,5,6},{3,4,1,7,5,5},{3,4,1,7,5,4},{3,4,1,7,5,3},{6,1,5,3,2,6},{1,6,5,3,2,5},{1,6,5,3,2,7},{3,4,1,7,5,2},{3,4,1,7,5,1},{5,7,2,1,4,3},{1,6,5,3,2,6},{1,5,6,3,2,5},{5,7,2,4,1,5},{1,5,6,3,2,7},{1,5,6,3,2,6},{5,2,7,4,1,5},{3,4,1,7,5,6},{3,1,4,7,5,5},{1,5,3,2,6,5},{5,2,7,4,1,4},{1,5,2,3,6,5},{3,1,4,7,5,4},{5,2,7,1,4,5},{5,2,7,1,4,3},{5,2,7,1,4,2},{5,2,1,7,4,5},{3,1,4,7,5,3},{5,2,1,7,4,4},{1,3,4,7,5,5},{5,2,1,7,4,3},{1,3,4,7,5,4},{1,3,4,7,5,3},{1,5,2,6,3,5},{1,5,2,6,3,7},{5,1,2,7,4,5},{5,1,2,7,4,4},{1,5,2,7,4,4},{6,5,1,3,7,4},{1,5,2,7,4,2},{6,5,1,3,7,3},{1,2,5,7,4,3},{6,5,1,3,7,2},{1,2,5,7,4,2},{2,1,5,7,4,7},{2,1,5,7,4,3},{2,1,5,7,4,2},{2,1,5,7,4,1},{5,6,1,3,7,4},{2,5,1,7,4,5},{2,5,1,7,4,7},{2,5,1,7,4,4},{2,5,1,7,4,3},{2,5,1,7,4,1},{2,5,7,1,4,5},{2,5,7,1,4,7},{5,6,1,3,7,2},{2,5,7,1,4,4},{2,5,7,1,4,3},{2,5,7,1,4,2},{2,5,7,1,4,1},{2,5,7,4,1,5},{2,5,7,4,1,4},{5,1,6,3,7,4},{5,1,6,3,7,2},{5,1,3,6,7,4},{5,1,3,7,6,5},{2,5,7,4,1,6},{5,1,3,7,6,4},{2,5,4,7,1,5},{2,5,4,7,1,4},{2,5,4,1,7,5},{5,3,1,7,6,5},{2,5,4,1,7,4},{2,5,4,1,7,3},{5,3,1,7,6,4},{5,3,1,6,7,5},{5,3,1,6,7,4},{5,3,6,1,7,5},{5,3,6,1,7,4},{5,3,6,1,7,3},{5,6,3,1,7,4},{2,5,1,4,7,5},{2,5,1,4,7,4},{2,5,1,4,7,3},{6,5,3,1,7,4},{6,5,3,1,7,3},{2,5,1,4,7,1},{6,5,3,7,1,4},{2,1,5,4,7,3},{2,1,5,4,7,1},{1,2,5,4,7,3},{1,5,2,4,7,5},{5,6,3,7,1,4},{1,5,2,4,7,4},{1,5,2,4,7,3},{1,5,2,4,7,2},{5,1,2,4,7,5},{5,1,2,4,7,4},{5,1,2,4,7,2},{5,3,6,7,1,5},{5,3,7,6,1,5},{5,3,7,6,1,7},{5,3,7,1,6,5},{5,3,7,1,6,7},{1,4,3,7,5,5},{1,4,3,7,5,4},{3,5,7,1,6,5},{1,4,3,7,5,3},{3,5,7,1,6,7},{3,5,7,1,6,3},{3,5,7,6,1,5},{3,5,7,6,1,7},{3,5,7,6,1,4},{3,5,6,7,1,5},{3,5,6,7,1,4},{3,6,5,7,1,5},{3,6,5,7,1,4},{4,1,3,7,5,5},{1,5,2,6,3,6},{1,5,6,2,3,5},{4,1,3,7,5,4},{4,1,3,7,5,3},{1,5,6,2,3,7},{4,1,3,7,5,2},{4,1,3,7,5,1},{4,1,3,7,5,6},{4,3,1,7,5,5},{1,5,6,2,3,6},{4,3,1,7,5,4},{4,3,1,7,5,3},{4,3,1,7,5,2},{5,2,1,4,7,5},{4,3,1,7,5,1},{4,3,1,7,5,6},{4,3,7,1,5,5},{4,3,7,1,5,4},{4,3,7,1,5,3},{4,3,7,1,5,2},{4,3,7,1,5,1},{5,2,1,4,7,4},{4,3,7,1,5,6},{5,2,1,4,7,3},{4,3,7,5,1,5},{5,2,1,4,7,2},{5,2,1,4,7,1},{4,3,7,5,1,4},{4,3,7,5,1,3},{5,2,4,1,7,5},{4,7,3,5,1,5},{5,2,4,1,7,4},{5,2,4,1,7,3},{4,7,3,5,1,4},{4,7,3,5,1,3},{4,7,3,1,5,5},{4,7,3,1,5,7},{4,7,3,1,5,4},{4,7,3,1,5,3},{4,7,3,1,5,2},{4,7,3,1,5,1},{5,2,4,7,1,5},{4,7,1,3,5,5},{5,2,4,7,1,4},{4,7,1,3,5,4},{4,7,1,3,5,3},{4,7,1,3,5,2},{4,7,1,3,5,1},{5,4,2,7,1,5},{4,7,1,3,5,6},{4,1,7,3,5,5},{5,4,2,7,1,4},{4,1,7,3,5,4},{4,1,7,3,5,3},{4,1,7,3,5,2},{4,1,7,3,5,1},{4,1,7,3,5,6},{1,4,7,3,5,5},{5,4,2,7,1,3},{1,4,7,3,5,4},{1,4,7,3,5,3},{1,4,7,3,5,6},{1,4,7,5,3,5},{1,4,7,5,3,4},{1,4,7,5,3,1},{5,4,2,1,7,5},{1,4,7,5,3,6},{4,1,7,5,3,5},{5,4,2,1,7,4},{5,4,2,1,7,3},{4,1,7,5,3,4},{4,1,7,5,3,3},{4,1,7,5,3,2},{4,1,7,5,3,1},{4,1,7,5,3,6},{4,7,1,5,3,5},{4,7,1,5,3,7},{4,7,1,5,3,4},{4,7,1,5,3,3},{4,7,1,5,3,2},{4,7,1,5,3,1},{4,7,1,5,3,6},{1,6,5,2,3,5},{4,7,5,1,3,5},{1,6,5,2,3,7},{4,7,5,1,3,7},{4,7,5,1,3,4},{4,7,5,1,3,3},{4,7,5,1,3,2},{4,7,5,3,1,5},{4,7,5,3,1,7},{4,7,5,3,1,4},{4,7,5,3,1,3},{7,4,5,3,1,5},{7,4,5,3,1,7},{7,4,5,3,1,4},{7,4,5,3,1,3},{5,4,1,2,7,5},{7,4,5,1,3,5},{7,4,5,1,3,7},{5,4,1,2,7,4},{7,4,5,1,3,4},{7,4,5,1,3,3},{7,4,5,1,3,2},{7,4,1,5,3,5},{7,4,1,5,3,7},{7,4,1,5,3,4},{7,4,1,5,3,3},{7,4,1,5,3,2},{7,1,4,5,3,5},{7,1,4,5,3,7},{7,1,4,5,3,4},{7,1,4,5,3,3},{7,1,4,5,3,6},{1,7,4,5,3,5},{1,7,4,5,3,4},{1,7,4,5,3,1},{1,7,4,5,3,6},{1,7,4,3,5,5},{1,7,4,3,5,4},{1,7,4,3,5,3},{5,4,1,2,7,3},{1,7,4,3,5,6},{7,1,4,3,5,5},{7,1,4,3,5,4},{5,1,4,2,7,5},{7,1,4,3,5,3},{5,1,4,2,7,7},{7,1,4,3,5,2},{5,1,4,2,7,4},{7,1,4,3,5,6},{7,4,1,3,5,5},{7,4,1,3,5,4},{7,4,1,3,5,3},{7,4,1,3,5,2},{1,5,4,2,7,5},{7,4,1,3,5,6},{7,4,3,1,5,5},{1,5,4,2,7,4},{7,4,3,1,5,7},{7,4,3,1,5,4},{7,4,3,1,5,3},{7,4,3,1,5,2},{1,5,4,2,7,3},{7,4,3,1,5,6},{1,6,5,2,3,6},{1,5,4,2,7,6},{6,1,5,2,3,5},{6,1,5,2,3,7},{1,5,4,7,2,5},{1,5,4,7,2,4},{6,1,5,2,3,6},{1,5,4,7,2,3},{6,5,1,2,3,5},{6,5,1,2,3,7},{6,5,1,2,3,6},{5,6,1,2,3,5},{5,6,1,2,3,7},{5,1,4,7,2,5},{5,6,1,2,3,6},{5,1,4,7,2,4},{5,1,6,2,3,5},{5,1,6,2,3,7},{5,1,6,2,3,6},{5,1,2,6,3,5},{5,1,2,6,3,7},{5,1,2,6,3,6},{5,4,1,7,2,5},{5,4,1,7,2,4},{5,2,1,6,3,5},{5,4,1,7,2,3},{5,2,1,6,3,7},{5,4,7,1,2,5},{5,4,7,1,2,4},{5,4,7,1,2,3},{5,2,1,6,3,6},{5,6,2,1,3,5},{5,4,7,2,1,5},{5,4,7,2,1,3},{5,4,7,2,1,2},{6,5,2,1,3,5},{4,5,7,2,1,5},{4,5,7,2,1,4},{4,5,7,2,1,3},{4,5,7,2,1,2},{6,5,2,3,1,5},{4,5,7,1,2,5},{6,3,5,7,1,4},{4,5,7,1,2,4},{4,5,7,1,2,3},{6,3,5,1,7,4},{4,5,1,7,2,5},{6,3,5,1,7,3},{4,5,1,7,2,4},{4,5,1,7,2,3},{3,6,5,1,7,5},{3,6,5,1,7,4},{3,6,5,1,7,3},{4,1,5,7,2,5},{4,1,5,7,2,7},{4,1,5,7,2,4},{3,5,6,1,7,5},{3,5,6,1,7,4},{3,5,6,1,7,3},{4,1,5,7,2,3},{3,5,1,6,7,5},{1,4,5,7,2,5},{3,5,1,6,7,4},{1,4,5,7,2,4},{1,4,5,7,2,3},{3,5,1,7,6,5},{1,4,5,2,7,5},{3,5,1,7,6,4},{1,4,5,2,7,4},{3,5,1,7,6,3},{1,4,5,2,7,3},{1,4,5,2,7,6},{4,1,5,2,7,5},{4,1,5,2,7,7},{4,1,5,2,7,3},{4,1,5,2,7,6},{4,5,1,2,7,5},{4,5,1,2,7,3},{4,5,2,1,7,5},{4,5,2,1,7,4},{4,5,2,1,7,3},{4,5,2,7,1,5},{4,5,2,7,1,4},{4,5,2,7,1,3},{4,2,5,7,1,5},{4,2,5,7,1,4},{4,2,5,1,7,5},{4,2,5,1,7,4},{4,2,5,1,7,3},{3,1,5,7,6,5},{4,2,1,5,7,5},{4,2,1,5,7,4},{4,2,1,5,7,3},{5,6,2,3,1,5},{3,1,5,7,6,3},{4,1,2,5,7,5},{3,1,5,6,7,5},{4,1,2,5,7,3},{3,1,5,6,7,3},{1,4,2,5,7,3},{3,1,6,5,7,5},{3,1,6,5,7,3},{1,2,4,5,7,3},{3,6,1,5,7,5},{3,6,1,5,7,3},{2,1,4,5,7,3},{2,4,1,5,7,5},{6,3,1,5,7,5},{2,4,5,1,7,5},{6,1,3,5,7,5},{5,2,6,3,1,5},{1,6,3,5,7,5},{1,3,6,5,7,3},{2,5,3,1,6,5},{1,3,5,6,7,3},{2,5,3,1,6,7},{2,5,3,1,6,4},{1,3,5,7,6,5},{2,5,3,6,1,5},{2,5,3,6,1,7},{2,5,3,6,1,4},{1,3,7,5,6,5},{1,3,7,5,6,7},{1,3,7,6,5,7},{7,4,3,5,1,5},{1,3,7,6,5,3},{7,4,3,5,1,7},{7,4,3,5,1,4},{7,4,3,5,1,3},{1,3,6,7,5,7},{1,3,6,7,5,3},{1,6,3,7,5,5},{7,3,4,5,1,5},{1,6,3,7,5,7},{7,3,4,5,1,7},{1,6,3,7,5,3},{7,3,4,5,1,4},{6,1,3,7,5,5},{7,3,4,5,1,3},{7,3,4,1,5,5},{6,3,1,7,5,5},{7,3,4,1,5,7},{7,3,4,1,5,4},{7,3,4,1,5,3},{7,3,4,1,5,2},{7,3,4,1,5,6},{3,6,1,7,5,5},{3,6,1,7,5,7},{7,3,1,4,5,5},{7,3,1,4,5,7},{7,3,1,4,5,4},{7,3,1,4,5,3},{7,3,1,4,5,2},{3,1,6,7,5,5},{3,1,6,7,5,7},{3,1,6,7,5,3},{3,1,7,6,5,5},{3,1,7,6,5,7},{3,1,7,6,5,3},{3,1,7,5,6,5},{3,1,7,5,6,3},{3,7,1,5,6,5},{3,7,1,5,6,3},{7,3,1,4,5,6},{3,7,1,6,5,5},{3,7,1,6,5,7},{7,1,3,4,5,5},{3,7,1,6,5,3},{7,1,3,4,5,4},{7,1,3,4,5,3},{3,7,6,1,5,5},{7,1,3,4,5,2},{3,7,6,1,5,7},{7,1,3,4,5,6},{3,7,6,1,5,3},{1,7,3,4,5,5},{1,7,3,4,5,4},{3,6,7,1,5,5},{3,6,7,1,5,7},{1,7,3,4,5,3},{1,7,3,4,5,1},{1,3,7,4,5,5},{6,3,7,1,5,5},{1,3,7,4,5,4},{1,3,7,4,5,3},{1,3,7,4,5,1},{6,3,7,5,1,4},{3,1,7,4,5,5},{6,3,7,5,1,3},{3,1,7,4,5,4},{3,1,7,4,5,3},{3,6,7,5,1,5},{3,1,7,4,5,1},{3,7,1,4,5,5},{3,7,6,5,1,5},{3,7,1,4,5,4},{3,7,1,4,5,3},{3,7,1,4,5,2},{3,7,5,6,1,5},{3,7,5,6,1,7},{3,7,4,1,5,5},{3,7,4,1,5,3},{3,7,4,1,5,2},{3,7,5,1,6,5},{3,7,4,1,5,1},{3,7,5,1,6,7},{3,7,4,1,5,6},{3,7,4,5,1,5},{3,7,5,1,6,3},{3,7,4,5,1,7},{3,7,4,5,1,4},{7,3,5,1,6,5},{7,3,5,1,6,7},{7,3,5,1,6,3},{3,7,5,4,1,5},{3,7,5,4,1,7},{3,7,5,4,1,4},{3,7,5,4,1,3},{7,3,5,6,1,5},{7,3,5,6,1,7},{3,7,5,4,1,2},{7,3,6,5,1,5},{7,3,6,5,1,4},{3,7,5,1,4,5},{3,7,5,1,4,7},{3,7,5,1,4,4},{3,7,5,1,4,3},{3,7,5,1,4,2},{3,7,1,5,4,5},{3,7,1,5,4,4},{3,7,1,5,4,3},{3,7,1,5,4,2},{6,2,5,3,1,5},{3,1,7,5,4,5},{3,1,7,5,4,4},{3,1,7,5,4,3},{6,2,5,1,3,5},{3,1,7,5,4,2},{1,3,7,5,4,5},{1,3,7,5,4,4},{1,3,7,5,4,3},{1,3,7,5,4,2},{1,7,3,5,4,5},{1,7,3,5,4,4},{1,7,3,5,4,3},{7,1,3,5,4,5},{7,1,3,5,4,4},{7,1,3,5,4,3},{2,5,1,3,6,4},{7,1,3,5,4,2},{7,3,1,5,4,5},{7,3,1,5,4,7},{7,3,1,5,4,4},{2,1,5,3,6,4},{7,3,1,5,4,3},{7,3,1,5,4,2},{7,3,1,5,4,1},{7,3,5,1,4,5},{7,3,5,1,4,7},{7,3,5,1,4,4},{7,3,5,1,4,3},{7,3,5,1,4,2},{2,1,6,5,3,7},{7,3,5,1,4,1},{7,3,5,1,4,6},{2,1,6,5,3,4},{7,3,5,4,1,5},{7,3,5,4,1,7},{7,3,5,4,1,4},{2,1,6,5,3,6},{7,3,5,4,1,3},{7,3,5,4,1,2},{7,3,5,4,1,1},{2,6,1,5,3,7},{2,6,1,5,3,4},{7,5,3,4,1,5},{7,5,3,4,1,7},{7,5,3,4,1,4},{7,5,3,4,1,3},{2,6,1,5,3,6},{7,5,3,4,1,2},{7,5,3,4,1,1},{6,2,1,5,3,7},{6,2,1,5,3,4},{7,5,3,1,4,5},{7,5,3,1,4,7},{7,5,3,1,4,4},{7,5,3,1,4,3},{6,2,1,5,3,6},{7,5,3,1,4,2},{7,5,3,1,4,1},{2,4,5,1,7,4},{7,5,3,1,4,6},{6,1,2,5,3,7},{6,1,2,5,3,4},{2,4,5,1,7,3},{7,5,1,3,4,5},{7,5,1,3,4,7},{7,5,1,3,4,4},{7,5,1,3,4,3},{7,5,1,3,4,1},{2,4,5,7,1,5},{7,5,1,3,4,6},{7,1,5,3,4,5},{7,1,5,3,4,7},{2,4,5,7,1,4},{7,1,5,3,4,4},{7,1,5,3,4,3},{7,1,5,3,4,6},{1,7,5,3,4,5},{2,4,7,5,1,5},{1,7,5,3,4,4},{2,4,7,5,1,4},{1,7,5,3,4,3},{1,7,5,4,3,5},{2,4,7,1,5,5},{1,7,5,4,3,4},{2,4,7,1,5,7},{1,7,5,4,3,3},{1,7,5,4,3,6},{7,1,5,4,3,5},{7,1,5,4,3,7},{7,1,5,4,3,4},{2,4,1,7,5,5},{2,4,1,7,5,7},{7,1,5,4,3,6},{7,5,1,4,3,5},{7,5,1,4,3,7},{7,5,1,4,3,4},{7,5,1,4,3,3},{7,5,1,4,3,6},{2,1,4,7,5,7},{7,5,4,1,3,5},{2,1,4,7,5,4},{7,5,4,1,3,7},{7,5,4,1,3,4},{7,5,4,1,3,3},{2,1,4,7,5,3},{7,5,4,1,3,2},{2,1,4,7,5,6},{7,5,4,3,1,5},{7,5,4,3,1,7},{7,5,4,3,1,4},{7,5,4,3,1,3},{7,5,4,3,1,2},{1,2,4,7,5,7},{1,2,4,7,5,4},{5,7,4,3,2,5},{1,2,4,7,5,3},{5,7,4,3,2,7},{5,7,4,3,2,4},{1,2,4,7,5,6},{5,7,4,3,2,3},{5,7,4,3,2,2},{1,4,2,7,5,4},{5,7,4,2,3,5},{1,4,2,7,5,3},{5,7,4,2,3,7},{5,7,4,2,3,4},{5,7,4,2,3,3},{5,7,4,2,3,2},{1,4,2,7,5,6},{5,7,4,2,3,1},{4,1,2,7,5,5},{5,7,2,4,3,5},{4,1,2,7,5,7},{4,1,2,7,5,4},{5,7,2,4,3,4},{4,1,2,7,5,3},{5,7,2,4,3,3},{5,7,2,4,3,2},{4,1,2,7,5,6},{5,2,7,4,3,5},{4,2,1,7,5,5},{4,2,1,7,5,7},{5,2,7,4,3,4},{5,2,7,4,3,3},{5,2,7,4,3,2},{2,5,7,4,3,5},{4,2,7,1,5,5},{2,5,7,4,3,4},{2,5,7,4,3,3},{4,2,7,1,5,7},{4,2,7,1,5,4},{2,5,7,3,4,5},{2,5,7,3,4,4},{2,5,7,3,4,3},{4,2,7,5,1,5},{2,5,7,3,4,1},{4,2,7,5,1,4},{2,5,7,3,4,6},{5,2,7,3,4,5},{5,2,7,3,4,4},{5,2,7,3,4,3},{5,2,7,3,4,2},{5,2,7,3,4,1},{5,2,7,3,4,6},{4,7,2,5,1,5},{5,7,2,3,4,5},{4,7,2,5,1,4},{5,7,2,3,4,4},{4,7,2,5,1,3},{5,7,2,3,4,2},{6,1,2,5,3,6},{1,6,2,5,3,7},{1,6,2,5,3,4},{4,7,2,1,5,5},{4,7,2,1,5,7},{4,7,2,1,5,4},{4,7,2,1,5,3},{7,6,3,5,1,4},{7,6,3,5,1,3},{4,7,1,2,5,5},{4,7,1,2,5,7},{4,7,1,2,5,4},{4,7,1,2,5,3},{4,7,1,2,5,6},{6,7,3,5,1,4},{4,1,7,2,5,5},{4,1,7,2,5,7},{6,7,3,5,1,3},{4,1,7,2,5,4},{4,1,7,2,5,3},{4,1,7,2,5,6},{6,7,3,1,5,5},{1,4,7,2,5,4},{1,4,7,2,5,3},{1,4,7,5,2,5},{7,6,3,1,5,5},{1,4,7,5,2,4},{1,4,7,5,2,3},{7,6,3,1,5,3},{4,1,7,5,2,5},{4,1,7,5,2,7},{4,1,7,5,2,4},{4,1,7,5,2,3},{7,3,6,1,5,5},{7,3,6,1,5,7},{4,1,7,5,2,6},{4,7,1,5,2,5},{7,3,6,1,5,3},{4,7,1,5,2,7},{4,7,1,5,2,4},{4,7,1,5,2,3},{7,3,1,6,5,5},{7,3,1,6,5,7},{7,3,1,6,5,3},{4,7,1,5,2,6},{4,7,5,1,2,5},{4,7,5,1,2,7},{7,3,1,5,6,5},{7,3,1,5,6,3},{4,7,5,1,2,3},{7,1,3,5,6,5},{7,1,3,5,6,7},{4,7,5,2,1,5},{4,7,5,2,1,4},{7,1,3,6,5,5},{4,7,5,2,1,3},{4,7,5,2,1,2},{7,1,3,6,5,7},{7,4,5,2,1,5},{7,4,5,2,1,4},{7,1,6,3,5,5},{7,4,5,2,1,3},{7,4,5,2,1,2},{7,4,5,1,2,5},{7,6,1,3,5,5},{7,4,5,1,2,7},{7,4,5,1,2,3},{7,4,1,5,2,5},{6,7,1,3,5,5},{7,4,1,5,2,7},{7,4,1,5,2,3},{6,1,7,3,5,5},{7,1,4,5,2,5},{7,1,4,5,2,7},{7,1,4,5,2,3},{1,6,7,3,5,5},{1,6,7,3,5,3},{1,7,4,5,2,5},{1,7,4,5,2,4},{1,7,6,3,5,5},{1,7,4,5,2,3},{1,7,6,3,5,4},{1,7,6,3,5,3},{1,7,4,2,5,5},{1,7,3,6,5,5},{1,7,4,2,5,4},{1,7,3,6,5,7},{1,7,3,6,5,4},{1,7,4,2,5,3},{1,7,3,5,6,5},{7,1,4,2,5,5},{1,7,3,5,6,7},{1,7,3,5,6,4},{7,1,4,2,5,4},{7,1,4,2,5,3},{1,7,5,3,6,5},{1,7,5,3,6,4},{7,4,1,2,5,5},{1,7,5,3,6,2},{1,7,5,6,3,5},{7,4,1,2,5,3},{1,7,5,6,3,7},{1,7,5,6,3,4},{1,7,5,6,3,3},{1,7,5,6,3,2},{7,4,2,1,5,5},{7,4,2,1,5,7},{1,7,5,6,3,6},{7,4,2,1,5,4},{1,7,6,5,3,5},{7,4,2,1,5,3},{1,7,6,5,3,7},{1,7,6,5,3,4},{1,7,6,5,3,3},{7,4,2,5,1,5},{1,7,6,5,3,6},{1,6,7,5,3,5},{7,4,2,5,1,4},{1,6,7,5,3,7},{7,4,2,5,1,3},{1,6,7,5,3,3},{1,6,7,5,3,2},{1,6,7,5,3,6},{7,2,4,5,1,5},{6,1,7,5,3,5},{6,1,7,5,3,7},{7,2,4,5,1,3},{6,1,7,5,3,3},{6,1,7,5,3,2},{6,1,7,5,3,6},{7,2,4,1,5,5},{6,7,1,5,3,5},{7,2,4,1,5,7},{6,7,1,5,3,7},{6,7,1,5,3,4},{6,7,1,5,3,3},{7,2,4,1,5,3},{6,7,1,5,3,2},{6,7,1,5,3,6},{7,6,1,5,3,5},{7,6,1,5,3,7},{7,2,1,4,5,7},{7,6,1,5,3,4},{7,6,1,5,3,3},{7,2,1,4,5,4},{7,2,1,4,5,3},{7,6,1,5,3,1},{7,6,1,5,3,6},{7,1,6,5,3,5},{7,1,6,5,3,7},{7,1,2,4,5,7},{7,1,6,5,3,4},{7,1,2,4,5,4},{7,1,6,5,3,3},{7,1,2,4,5,3},{7,1,6,5,3,1},{7,1,6,5,3,6},{7,1,5,6,3,5},{7,1,5,6,3,7},{7,1,5,6,3,3},{1,7,2,4,5,7},{7,1,5,6,3,1},{1,7,2,4,5,4},{7,1,5,6,3,6},{1,7,2,4,5,3},{7,1,5,3,6,5},{1,2,7,4,5,7},{1,2,7,4,5,4},{7,5,1,3,6,5},{1,2,7,4,5,3},{1,2,7,4,5,6},{2,1,7,4,5,7},{2,1,7,4,5,4},{7,5,1,6,3,4},{2,1,7,4,5,3},{2,1,7,4,5,6},{2,7,1,4,5,7},{2,7,1,4,5,4},{7,5,6,1,3,4},{2,7,1,4,5,3},{2,7,1,4,5,6},{2,7,4,1,5,5},{7,6,5,1,3,4},{2,7,4,1,5,7},{6,7,5,1,3,4},{2,7,4,5,1,5},{2,7,4,5,1,4},{6,7,5,3,1,4},{6,7,5,3,1,3},{2,7,5,4,1,5},{7,6,5,3,1,4},{5,7,2,3,4,1},{7,6,5,3,1,3},{5,7,2,3,4,6},{5,7,3,2,4,5},{5,7,3,2,4,4},{7,5,6,3,1,4},{5,7,3,2,4,3},{7,5,6,3,1,3},{5,7,3,2,4,2},{7,5,3,6,1,5},{7,5,3,6,1,7},{5,7,3,2,4,1},{7,5,3,1,6,5},{7,5,3,1,6,7},{5,7,3,2,4,6},{5,7,3,4,2,5},{1,6,2,5,3,6},{1,2,6,5,3,7},{5,7,3,4,2,7},{5,7,3,2,6,5},{5,7,3,4,2,4},{5,7,3,2,6,4},{5,7,3,2,6,3},{5,7,3,4,2,3},{5,7,3,4,2,2},{5,7,3,4,2,6},{5,7,3,6,2,4},{5,3,7,4,2,5},{5,7,3,6,2,3},{5,3,7,4,2,7},{5,3,7,4,2,4},{5,3,7,4,2,2},{5,7,6,3,2,3},{5,3,7,4,2,6},{5,3,7,2,4,5},{1,2,6,5,3,4},{5,6,7,3,2,3},{5,6,7,3,2,1},{1,2,6,5,3,6},{6,5,7,3,2,3},{6,5,7,3,2,1},{1,2,5,6,3,6},{1,2,5,3,6,5},{6,5,7,2,3,3},{1,2,3,5,6,5},{5,6,7,2,3,3},{5,3,7,2,4,4},{5,3,7,2,4,3},{5,3,7,2,4,2},{5,3,7,2,4,1},{5,3,7,2,4,6},{5,3,2,7,4,5},{1,2,3,6,5,5},{5,3,2,7,4,4},{1,2,3,6,5,4},{5,3,2,7,4,3},{5,3,2,7,4,2},{5,3,2,7,4,1},{5,3,2,7,4,6},{1,2,3,6,5,6},{5,2,3,7,4,5},{1,2,6,3,5,7},{5,2,3,7,4,4},{1,2,6,3,5,4},{5,2,3,7,4,3},{5,2,3,7,4,2},{5,2,3,7,4,1},{1,2,6,3,5,6},{5,2,3,7,4,6},{1,6,2,3,5,7},{2,5,3,7,4,5},{1,6,2,3,5,4},{2,5,3,7,4,4},{2,5,3,7,4,3},{1,6,2,3,5,6},{6,1,2,3,5,7},{2,5,3,7,4,1},{6,1,2,3,5,4},{2,5,3,7,4,6},{2,3,5,7,4,5},{6,1,2,3,5,6},{2,3,5,7,4,4},{2,3,5,7,4,3},{2,3,5,7,4,2},{6,2,1,3,5,7},{2,3,5,7,4,1},{6,2,1,3,5,4},{2,3,5,7,4,6},{3,2,5,7,4,5},{3,2,5,7,4,4},{6,2,1,3,5,6},{3,2,5,7,4,3},{3,2,5,7,4,2},{2,6,1,3,5,7},{3,2,5,7,4,1},{3,2,5,7,4,6},{2,6,1,3,5,4},{3,5,2,7,4,5},{3,5,2,7,4,4},{2,6,1,3,5,6},{3,5,2,7,4,3},{3,5,2,7,4,2},{3,5,2,7,4,1},{2,1,6,3,5,7},{3,5,2,7,4,6},{2,1,6,3,5,4},{3,5,7,2,4,5},{3,5,7,2,4,4},{3,5,7,2,4,3},{2,1,6,3,5,6},{3,5,7,2,4,1},{3,5,7,4,2,5},{2,1,3,6,5,4},{3,5,7,4,2,7},{3,5,7,4,2,4},{3,5,7,4,2,3},{2,1,3,6,5,6},{3,5,4,7,2,5},{3,5,4,7,2,3},{3,5,4,2,7,5},{3,5,4,2,7,4},{3,5,4,2,7,3},{3,5,2,4,7,5},{2,3,1,6,5,4},{3,5,2,4,7,4},{3,5,2,4,7,3},{2,3,1,6,5,6},{3,5,2,4,7,2},{2,3,6,1,5,4},{3,2,5,4,7,5},{2,3,6,1,5,6},{3,2,5,4,7,4},{3,2,5,4,7,3},{3,2,5,4,7,2},{2,6,3,1,5,4},{3,2,5,4,7,6},{2,3,5,4,7,5},{2,6,3,1,5,6},{2,3,5,4,7,4},{6,2,3,1,5,4},{2,3,5,4,7,3},{2,3,5,4,7,6},{6,2,3,1,5,6},{2,5,3,4,7,5},{6,2,3,5,1,5},{2,5,3,4,7,4},{2,5,3,4,7,3},{2,5,3,4,7,6},{5,2,3,4,7,5},{5,2,3,4,7,4},{5,2,3,4,7,6},{5,3,2,4,7,5},{2,3,6,5,1,5},{5,3,2,4,7,4},{5,3,2,4,7,3},{5,3,2,4,7,2},{2,3,5,6,1,5},{2,3,5,6,1,7},{5,3,4,2,7,5},{2,3,5,6,1,4},{5,3,4,2,7,4},{5,3,4,2,7,3},{2,3,5,1,6,5},{2,3,5,1,6,7},{2,3,5,1,6,4},{5,3,4,7,2,5},{5,3,4,7,2,7},{3,2,5,1,6,5},{3,2,5,1,6,7},{3,2,5,1,6,4},{3,2,5,6,1,5},{3,2,5,6,1,7},{3,2,5,6,1,4},{5,3,4,7,2,3},{3,2,6,5,1,5},{5,4,3,7,2,5},{5,4,3,7,2,7},{5,4,3,7,2,3},{5,4,3,2,7,5},{5,4,3,2,7,4},{5,4,3,2,7,3},{3,6,2,5,1,5},{5,4,2,3,7,5},{5,4,2,3,7,4},{5,4,2,3,7,3},{5,4,2,3,7,1},{6,3,2,5,1,5},{5,4,2,3,7,6},{5,2,4,3,7,5},{5,2,4,3,7,4},{5,2,4,3,7,3},{5,2,4,3,7,1},{5,2,4,3,7,6},{2,5,4,3,7,5},{3,6,2,1,5,5},{2,5,4,3,7,4},{2,5,4,3,7,3},{2,5,4,3,7,1},{2,5,4,3,7,6},{3,2,6,1,5,5},{2,5,4,7,3,5},{2,5,4,7,3,4},{2,5,4,7,3,3},{3,2,1,6,5,5},{2,5,4,7,3,1},{5,2,4,7,3,5},{5,2,4,7,3,4},{3,2,1,5,6,5},{5,2,4,7,3,3},{5,2,4,7,3,1},{5,4,2,7,3,5},{5,4,2,7,3,4},{3,1,2,5,6,5},{5,4,2,7,3,3},{5,4,2,7,3,1},{5,4,7,2,3,5},{3,1,2,6,5,5},{5,4,7,2,3,4},{5,4,7,2,3,3},{5,4,7,2,3,1},{5,4,7,3,2,5},{5,4,7,3,2,7},{5,4,7,3,2,4},{4,5,7,3,2,5},{4,5,7,3,2,7},{4,5,7,3,2,4},{6,3,1,2,5,7},{4,5,7,2,3,5},{4,5,7,2,3,4},{4,5,7,2,3,3},{4,5,7,2,3,1},{6,1,3,2,5,7},{4,5,2,7,3,5},{4,5,2,7,3,4},{4,5,2,7,3,3},{4,5,2,7,3,1},{1,6,3,2,5,7},{4,2,5,7,3,5},{4,2,5,7,3,4},{4,2,5,7,3,3},{4,2,5,7,3,1},{2,4,5,7,3,5},{2,4,5,7,3,4},{2,4,5,7,3,3},{1,3,2,6,5,5},{2,4,5,7,3,1},{2,4,5,3,7,4},{2,4,5,3,7,3},{1,3,2,5,6,5},{2,4,5,3,7,1},{4,2,5,3,7,5},{4,2,5,3,7,4},{4,2,5,3,7,3},{1,3,5,2,6,5},{4,2,5,3,7,1},{4,5,2,3,7,5},{4,5,2,3,7,4},{4,5,2,3,7,3},{4,5,2,3,7,1},{4,5,2,3,7,6},{2,7,5,4,1,4},{2,7,5,4,1,6},{2,7,5,1,4,5},{2,7,5,1,4,7},{2,7,5,1,4,4},{2,7,5,1,4,1},{5,7,6,2,3,5},{2,7,1,5,4,7},{2,7,1,5,4,4},{5,7,6,2,3,3},{2,7,1,5,4,2},{2,7,1,5,4,1},{5,7,2,6,3,5},{2,1,7,5,4,7},{2,1,7,5,4,2},{2,1,7,5,4,1},{5,7,2,6,3,4},{1,2,7,5,4,3},{5,7,2,6,3,3},{1,2,7,5,4,2},{5,7,2,3,6,5},{5,7,2,3,6,4},{5,7,2,3,6,3},{1,7,2,5,4,3},{5,2,7,3,6,5},{5,2,7,3,6,4},{7,1,2,5,4,3},{5,2,7,3,6,3},{5,2,7,6,3,5},{7,2,1,5,4,7},{5,2,7,6,3,4},{5,2,7,6,3,3},{7,2,1,5,4,2},{7,2,1,5,4,1},{7,2,5,1,4,5},{7,2,5,1,4,7},{7,2,5,1,4,4},{5,2,6,7,3,4},{5,2,6,7,3,3},{7,2,5,1,4,2},{7,2,5,1,4,1},{5,6,2,7,3,3},{6,5,2,7,3,3},{7,2,5,4,1,5},{6,2,5,7,3,3},{6,2,5,7,3,1},{7,5,2,4,1,5},{2,6,5,7,3,4},{2,6,5,7,3,3},{2,6,5,7,3,1},{7,5,2,1,4,5},{2,5,6,7,3,4},{2,5,6,7,3,3},{2,5,6,7,3,1},{7,5,1,2,4,5},{2,5,7,6,3,4},{7,5,1,2,4,4},{7,5,1,2,4,3},{2,5,7,6,3,1},{2,5,7,3,6,5},{2,5,7,3,6,4},{2,5,7,3,6,3},{7,1,5,2,4,4},{7,1,5,2,4,3},{2,5,7,3,6,1},{2,5,3,7,6,5},{2,5,3,7,6,4},{2,5,3,7,6,3},{1,7,5,2,4,4},{1,7,5,2,4,3},{1,7,5,2,4,2},{2,5,3,6,7,4},{1,7,5,4,2,5},{2,5,3,6,7,3},{1,7,5,4,2,4},{1,7,5,4,2,3},{1,7,5,4,2,1},{2,5,6,3,7,4},{7,1,5,4,2,5},{2,5,6,3,7,3},{7,1,5,4,2,7},{7,1,5,4,2,4},{7,1,5,4,2,3},{2,5,6,3,7,6},{2,6,5,3,7,4},{7,5,1,4,2,5},{2,6,5,3,7,3},{7,5,1,4,2,7},{7,5,1,4,2,4},{2,6,5,3,7,6},{6,2,5,3,7,4},{7,5,4,1,2,5},{6,2,5,3,7,3},{7,5,4,1,2,7},{7,5,4,1,2,3},{7,5,4,2,1,5},{7,5,4,2,1,4},{7,5,4,2,1,3},{7,5,4,2,1,2},{5,7,4,3,6,7},{5,7,4,3,6,4},{5,7,4,3,6,3},{6,2,5,3,7,6},{5,7,4,6,3,5},{5,7,4,6,3,7},{6,5,2,3,7,3},{6,5,2,3,7,2},{5,7,4,6,3,4},{5,7,4,6,3,3},{6,5,2,3,7,6},{5,7,4,6,3,1},{5,7,6,4,3,5},{5,6,2,3,7,3},{5,6,2,3,7,2},{5,7,6,4,3,4},{5,6,2,3,7,6},{5,7,6,4,3,3},{5,7,6,4,3,2},{5,2,6,3,7,3},{5,7,6,4,3,6},{5,2,6,3,7,2},{5,6,7,4,3,5},{5,2,6,3,7,6},{5,2,3,6,7,5},{5,2,3,6,7,3},{5,6,7,4,3,4},{5,2,3,7,6,5},{5,6,7,4,3,6},{6,5,7,4,3,5},{5,2,3,7,6,4},{5,2,3,7,6,3},{6,5,7,4,3,4},{5,3,2,7,6,5},{5,3,2,7,6,4},{5,3,2,6,7,5},{5,3,2,6,7,3},{5,3,6,2,7,3},{5,6,3,2,7,4},{5,3,7,4,6,7},{6,5,3,2,7,4},{6,5,3,2,7,3},{5,3,7,4,6,4},{5,3,7,4,6,3},{5,3,7,6,4,5},{6,5,3,7,2,3},{5,3,7,6,4,4},{5,3,7,6,4,3},{6,5,3,7,2,1},{5,3,7,6,4,2},{5,3,6,7,4,5},{5,3,6,7,4,4},{5,6,3,7,2,1},{5,3,6,7,4,3},{5,6,3,7,4,5},{5,3,6,7,2,3},{5,6,3,7,4,4},{5,6,3,7,4,3},{5,6,3,7,4,2},{5,3,7,6,2,4},{6,5,3,7,4,5},{5,3,7,2,6,5},{5,3,7,2,6,4},{6,5,3,7,4,4},{3,5,7,2,6,5},{6,5,3,7,4,3},{6,5,3,7,4,2},{6,3,5,7,4,5},{6,3,5,7,4,7},{6,3,5,7,4,4},{6,3,5,7,4,3},{6,3,5,7,4,2},{3,5,7,6,2,3},{3,6,5,7,4,5},{3,6,5,7,4,7},{3,6,5,7,4,4},{3,6,5,7,4,3},{3,5,6,7,2,3},{3,5,6,7,4,5},{3,5,6,7,4,7},{3,5,6,7,4,4},{3,5,6,7,4,3},{3,6,5,7,2,3},{6,3,5,7,2,3},{6,3,5,7,2,1},{3,5,7,6,4,5},{3,5,7,6,4,7},{3,5,7,6,4,4},{6,3,5,2,7,4},{6,3,5,2,7,3},{3,5,7,6,4,3},{3,5,7,4,6,5},{3,5,7,4,6,7},{3,5,7,4,6,4},{3,6,5,2,7,3},{3,5,7,4,6,3},{3,5,4,7,6,5},{3,5,4,7,6,3},{3,5,4,6,7,5},{3,5,4,6,7,4},{3,5,6,2,7,3},{3,5,2,6,7,5},{3,5,2,6,7,3},{3,5,2,7,6,5},{4,5,3,2,7,5},{4,5,3,2,7,4},{4,5,3,2,7,3},{4,5,3,7,2,5},{4,5,3,7,2,7},{4,5,3,7,2,3},{1,6,3,5,2,5},{4,3,5,7,2,5},{4,3,5,7,2,3},{6,1,3,5,2,5},{4,3,5,2,7,5},{4,3,5,2,7,4},{4,3,5,2,7,3},{6,3,1,5,2,5},{4,3,2,5,7,5},{4,3,2,5,7,4},{4,3,2,5,7,3},{4,3,2,5,7,2},{4,2,3,5,7,4},{4,2,3,5,7,3},{4,2,3,5,7,6},{3,1,5,2,6,5},{2,4,3,5,7,4},{2,4,3,5,7,3},{2,4,3,5,7,6},{2,3,4,5,7,4},{2,3,4,5,7,3},{2,3,4,5,7,6},{3,2,4,5,7,5},{3,2,4,5,7,4},{3,2,4,5,7,3},{3,2,4,5,7,2},{3,4,2,5,7,5},{3,5,6,1,2,4},{3,4,2,5,7,4},{3,4,2,5,7,3},{3,4,2,5,7,2},{3,4,5,2,7,5},{6,3,5,1,2,5},{3,4,5,2,7,4},{6,3,5,2,1,5},{3,4,5,2,7,3},{3,4,5,7,2,5},{3,6,5,2,1,4},{3,4,5,7,2,3},{3,5,6,2,1,4},{3,5,2,6,1,4},{3,5,2,1,6,4},{5,4,6,2,1,3},{5,6,4,2,1,5},{5,6,4,2,1,3},{6,5,4,2,1,5},{6,5,4,1,2,5},{5,6,4,1,2,5},{4,3,7,5,2,5},{4,3,7,5,2,4},{4,3,7,5,2,3},{3,5,4,6,7,3},{3,5,6,4,7,5},{3,5,6,4,7,7},{3,5,6,4,7,4},{3,5,2,7,6,3},{3,5,6,4,7,3},{3,5,6,4,7,6},{3,2,5,7,6,5},{3,6,5,4,7,5},{3,6,5,4,7,7},{3,2,5,7,6,4},{3,2,5,7,6,3},{3,6,5,4,7,4},{3,6,5,4,7,3},{3,6,5,4,7,6},{3,2,5,6,7,5},{6,3,5,4,7,5},{6,3,5,4,7,7},{3,2,5,6,7,4},{3,2,5,6,7,3},{6,3,5,4,7,4},{6,3,5,4,7,3},{6,3,5,4,7,2},{6,3,5,4,7,6},{6,5,3,4,7,5},{6,5,3,4,7,4},{6,5,3,4,7,3},{6,5,3,4,7,2},{5,6,3,4,7,5},{5,6,3,4,7,4},{5,6,3,4,7,3},{5,6,3,4,7,2},{3,2,6,5,7,5},{5,3,6,4,7,5},{3,2,6,5,7,3},{3,6,2,5,7,5},{3,6,2,5,7,4},{3,6,2,5,7,3},{5,3,6,4,7,4},{6,3,2,5,7,4},{5,3,6,4,7,3},{6,3,2,5,7,3},{5,3,6,4,7,6},{5,3,4,6,7,5},{5,3,4,6,7,4},{6,2,3,5,7,4},{5,3,4,6,7,3},{6,2,3,5,7,3},{2,6,3,5,7,4},{2,6,3,5,7,3},{2,3,6,5,7,3},{2,3,5,6,7,4},{2,3,5,6,7,3},{2,3,5,7,6,5},{2,3,5,7,6,4},{2,3,5,7,6,3},{2,3,7,5,6,5},{2,3,7,5,6,4},{2,3,7,6,5,5},{2,3,7,6,5,4},{2,3,7,6,5,3},{2,3,7,6,5,6},{2,3,6,7,5,4},{2,3,6,7,5,3},{2,3,6,7,5,6},{2,6,3,7,5,7},{2,6,3,7,5,4},{2,6,3,7,5,3},{2,6,3,7,5,6},{6,2,3,7,5,7},{6,2,3,7,5,4},{6,2,3,7,5,3},{6,2,3,7,5,6},{6,3,2,7,5,7},{6,3,2,7,5,4},{6,3,2,7,5,3},{3,6,2,7,5,4},{3,6,2,7,5,3},{3,2,6,7,5,4},{3,2,6,7,5,3},{3,2,7,6,5,4},{3,2,7,5,6,5},{3,2,7,5,6,4},{3,2,7,5,6,3},{3,7,2,5,6,5},{3,7,2,5,6,4},{3,7,2,6,5,4},{3,7,6,2,5,3},{3,6,7,2,5,4},{6,3,7,2,5,7},{6,3,7,2,5,4},{6,3,7,5,2,3},{3,6,7,5,2,3},{4,3,5,7,6,5},{3,6,7,5,2,1},{4,3,5,7,6,4},{4,3,5,7,6,3},{3,7,6,5,2,3},{4,3,5,6,7,5},{3,7,6,5,2,1},{4,3,5,6,7,4},{4,3,5,6,7,3},{3,7,5,6,2,1},{4,3,6,5,7,5},{3,7,5,2,6,5},{4,3,6,5,7,4},{4,3,6,5,7,3},{4,3,6,5,7,6},{3,7,5,2,6,1},{4,6,3,5,7,5},{7,3,5,2,6,5},{4,6,3,5,7,4},{4,6,3,5,7,3},{7,3,5,2,6,3},{4,6,3,5,7,6},{6,4,3,5,7,4},{6,4,3,5,7,3},{6,4,3,5,7,6},{7,3,5,6,2,3},{7,3,6,5,2,3},{7,6,3,5,2,3},{6,7,3,5,2,3},{6,7,3,2,5,7},{6,7,3,2,5,4},{7,6,3,2,5,7},{7,6,3,2,5,4},{7,3,6,2,5,5},{7,3,2,6,5,5},{7,3,2,5,6,5},{6,4,2,7,3,7},{6,4,2,7,3,1},{6,4,2,7,3,6},{4,6,2,7,3,5},{4,6,2,7,3,7},{4,6,2,7,3,1},{4,6,2,7,3,6},{4,2,6,7,3,5},{4,2,6,7,3,7},{4,2,6,7,3,6},{4,2,7,6,3,5},{4,2,7,6,3,7},{4,2,7,6,3,6},{4,2,7,3,6,7},{4,2,7,3,6,2},{4,2,7,3,6,1},{4,2,7,3,6,6},{4,7,2,3,6,1},{4,7,2,3,6,6},{4,7,2,6,3,7},{4,7,2,6,3,6},{4,7,6,2,3,5},{4,7,6,2,3,7},{4,7,6,2,3,1},{4,7,6,2,3,6},{4,6,7,2,3,5},{4,6,7,2,3,7},{4,6,7,2,3,1},{4,6,7,2,3,6},{6,4,7,2,3,5},{6,4,7,2,3,7},{6,4,7,2,3,1},{6,4,7,2,3,6},{6,4,7,3,2,5},{6,4,7,3,2,7},{6,4,7,3,2,1},{6,4,7,3,2,6},{4,6,7,3,2,5},{4,6,7,3,2,7},{4,6,7,3,2,2},{4,6,7,3,2,1},{4,6,7,3,2,6},{4,7,6,3,2,7},{4,7,6,3,2,2},{4,7,6,3,2,1},{4,7,6,3,2,6},{4,7,3,6,2,5},{4,7,3,6,2,7},{4,7,3,6,2,2},{4,7,3,6,2,1},{4,7,3,6,2,6},{4,7,3,2,6,5},{4,7,3,2,6,7},{4,7,3,2,6,2},{4,7,3,2,6,1},{4,7,3,2,6,6},{7,4,3,2,1,5},{7,4,3,2,1,2},{7,4,3,2,1,1},{7,4,3,1,2,5},{7,4,3,1,2,7},{7,4,3,1,2,2},{7,4,3,1,2,1},{7,4,3,1,2,6},{7,4,1,3,2,5},{7,4,1,3,2,7},{7,4,1,3,2,2},{7,4,1,3,2,6},{7,1,4,3,2,5},{7,1,4,3,2,7},{7,1,4,3,2,2},{7,1,4,3,2,1},{1,7,4,3,2,7},{1,7,4,3,2,2},{2,6,1,7,4,4},{2,6,1,7,4,3},{6,2,1,7,4,4},{1,7,4,3,2,1},{6,2,1,7,4,3},{1,7,4,3,2,6},{1,7,4,2,3,7},{1,7,4,2,3,2},{6,1,2,7,4,4},{1,7,4,2,3,6},{6,1,2,7,4,3},{7,1,4,2,3,5},{7,1,4,2,3,7},{1,6,2,7,4,4},{1,6,2,7,4,3},{7,1,4,2,3,6},{7,4,1,2,3,5},{7,4,1,2,3,7},{7,4,1,2,3,2},{7,4,1,2,3,1},{7,4,1,2,3,6},{7,4,2,1,3,5},{7,4,2,1,3,7},{7,4,2,1,3,2},{7,4,2,1,3,1},{7,4,2,3,1,5},{7,4,2,3,1,2},{7,4,2,3,1,1},{7,2,4,3,1,5},{7,2,4,3,1,7},{7,2,3,5,6,5},{3,4,7,5,6,4},{7,2,3,5,6,4},{3,4,7,5,6,3},{3,4,7,6,5,5},{7,2,3,6,5,5},{3,4,7,6,5,7},{3,4,7,6,5,4},{7,2,3,6,5,4},{3,4,7,6,5,3},{7,2,3,6,5,3},{7,2,3,6,5,6},{3,4,6,7,5,5},{7,2,6,3,5,5},{3,4,6,7,5,7},{7,2,6,3,5,7},{3,4,6,7,5,4},{7,2,6,3,5,4},{3,4,6,7,5,3},{7,2,6,3,5,3},{3,6,4,7,5,5},{7,2,6,3,5,6},{3,6,4,7,5,7},{7,6,2,3,5,5},{7,6,2,3,5,7},{3,6,4,7,5,4},{7,6,2,3,5,4},{3,6,4,7,5,3},{7,6,2,3,5,3},{7,6,2,3,5,6},{6,7,2,3,5,7},{3,6,4,7,5,6},{6,3,4,7,5,5},{6,7,2,3,5,4},{6,7,2,3,5,3},{6,3,4,7,5,4},{6,3,4,7,5,3},{6,7,2,3,5,6},{6,2,7,3,5,7},{6,3,4,7,5,6},{6,2,7,3,5,4},{6,2,7,3,5,3},{6,2,7,3,5,6},{2,6,7,3,5,7},{2,6,7,3,5,4},{2,6,7,3,5,3},{2,6,7,3,5,6},{2,7,6,3,5,5},{2,7,6,3,5,7},{2,7,6,3,5,4},{2,7,6,3,5,3},{2,7,6,3,5,6},{2,7,3,6,5,5},{2,7,3,6,5,4},{2,7,3,6,5,3},{2,7,3,6,5,6},{2,7,3,5,6,5},{2,7,3,5,6,4},{2,7,5,3,6,5},{2,7,5,3,6,4},{4,7,3,5,6,5},{4,7,3,5,6,7},{2,7,5,3,6,1},{4,7,3,5,6,4},{4,7,3,5,6,3},{2,7,5,6,3,5},{2,7,5,6,3,4},{4,7,3,6,5,5},{4,7,3,6,5,7},{2,7,5,6,3,1},{4,7,3,6,5,4},{4,7,3,6,5,3},{2,7,6,5,3,5},{2,7,6,5,3,4},{4,7,6,3,5,5},{4,7,6,3,5,7},{4,7,6,3,5,4},{4,7,6,3,5,3},{2,6,7,5,3,4},{4,6,7,3,5,5},{2,6,7,5,3,1},{4,6,7,3,5,7},{4,6,7,3,5,4},{4,6,7,3,5,3},{6,2,7,5,3,4},{4,6,7,3,5,6},{6,2,7,5,3,1},{6,4,7,3,5,5},{6,4,7,3,5,4},{6,7,2,5,3,4},{6,4,7,3,5,3},{6,7,2,5,3,1},{6,4,7,3,5,6},{6,4,7,5,3,5},{7,6,2,5,3,5},{6,4,7,5,3,7},{6,4,7,5,3,4},{7,6,2,5,3,4},{6,4,7,5,3,3},{7,6,2,5,3,3},{6,4,7,5,3,1},{4,6,7,5,3,5},{7,2,6,5,3,5},{4,6,7,5,3,7},{4,6,7,5,3,4},{7,2,6,5,3,4},{4,6,7,5,3,3},{7,2,6,5,3,3},{4,7,6,5,3,5},{7,2,5,6,3,5},{4,7,6,5,3,7},{7,2,5,6,3,4},{4,7,6,5,3,4},{7,2,5,6,3,3},{4,7,6,5,3,3},{7,2,5,3,6,5},{4,7,5,6,3,5},{7,2,5,3,6,4},{4,7,5,6,3,7},{4,7,5,6,3,4},{4,7,5,6,3,3},{7,5,2,3,6,5},{4,7,5,3,6,5},{4,7,5,3,6,7},{7,5,2,3,6,3},{4,7,5,3,6,4},{4,7,5,3,6,3},{7,5,2,6,3,5},{7,4,5,3,6,5},{7,4,5,3,6,7},{7,5,2,6,3,3},{7,4,5,3,6,4},{7,5,6,2,3,5},{7,5,6,2,3,4},{7,5,6,2,3,3},{7,6,5,2,3,5},{7,6,5,2,3,4},{7,6,5,2,3,3},{6,7,5,2,3,4},{7,4,5,3,6,3},{6,7,5,2,3,3},{7,4,5,6,3,5},{7,4,5,6,3,7},{7,4,5,6,3,4},{7,4,5,6,3,3},{6,7,5,3,2,3},{7,4,5,6,3,6},{7,4,6,5,3,5},{7,4,6,5,3,7},{7,4,6,5,3,4},{7,6,5,3,2,3},{7,4,6,5,3,3},{7,4,6,5,3,2},{7,4,6,5,3,6},{7,6,4,5,3,5},{7,6,4,5,3,4},{7,6,4,5,3,3},{7,6,4,5,3,2},{7,6,4,5,3,6},{6,7,4,5,3,5},{6,7,4,5,3,7},{6,7,4,5,3,4},{6,7,4,5,3,3},{7,5,3,6,2,3},{6,7,4,3,5,5},{7,5,3,2,6,5},{6,7,4,3,5,4},{6,7,4,3,5,3},{7,5,3,2,6,3},{6,7,4,3,5,6},{7,6,4,3,5,5},{5,7,3,2,1,5},{7,6,4,3,5,4},{7,6,4,3,5,3},{5,7,3,2,1,4},{5,7,3,2,1,3},{7,6,4,3,5,6},{7,4,6,3,5,5},{7,4,6,3,5,7},{5,7,3,1,2,5},{7,4,6,3,5,4},{5,7,3,1,2,4},{7,4,6,3,5,3},{5,7,3,1,2,3},{5,7,3,1,2,1},{7,4,6,3,5,6},{7,4,3,6,5,5},{7,4,3,6,5,7},{7,4,3,6,5,4},{7,4,3,6,5,3},{7,4,3,5,6,5},{7,4,3,5,6,7},{7,4,3,5,6,4},{7,4,3,5,6,3},{5,7,2,1,3,5},{5,7,2,1,3,3},{5,7,2,3,1,5},{5,7,2,3,1,3},{5,2,7,3,1,5},{5,2,7,3,1,3},{5,2,7,1,3,5},{5,2,7,1,3,3},{1,2,6,7,4,4},{1,2,6,7,4,3},{1,2,7,6,4,3},{1,2,7,4,6,4},{1,2,7,4,6,3},{1,2,4,7,6,4},{1,2,4,7,6,3},{1,2,4,6,7,4},{7,2,4,3,1,2},{7,2,4,3,1,1},{1,2,6,4,7,4},{7,2,4,1,3,5},{7,2,4,1,3,2},{7,2,4,1,3,1},{1,6,2,4,7,4},{7,2,1,4,3,5},{7,2,1,4,3,6},{6,1,2,4,7,4},{7,1,2,4,3,5},{6,2,1,4,7,4},{7,1,2,4,3,6},{6,2,1,4,7,3},{1,7,2,4,3,2},{2,6,1,4,7,4},{1,7,2,4,3,6},{2,1,6,4,7,4},{1,2,7,4,3,2},{1,2,7,4,3,6},{2,1,4,6,7,4},{2,1,7,4,3,1},{2,1,7,4,3,6},{2,1,4,7,6,4},{2,7,1,4,3,1},{2,7,1,4,3,6},{2,7,4,1,3,5},{2,7,4,1,3,2},{2,7,4,1,3,1},{2,7,4,1,3,6},{2,7,4,3,1,7},{2,7,4,3,1,2},{2,4,1,7,6,4},{2,7,4,3,1,1},{2,7,4,3,1,6},{2,4,1,6,7,4},{6,2,4,1,7,3},{6,2,4,7,1,3},{2,4,7,1,6,4},{4,2,7,1,6,4},{4,6,2,7,1,3},{6,4,2,7,1,3},{6,4,2,1,7,3},{4,6,2,1,7,3},{4,2,1,6,7,4},{4,2,1,6,7,3},{4,2,1,7,6,4},{4,1,2,7,6,4},{4,1,2,7,6,3},{3,7,4,2,1,5},{3,7,4,2,1,7},{3,7,4,2,1,2},{4,1,2,6,7,4},{3,7,4,2,1,1},{3,7,4,2,1,6},{3,7,4,1,2,5},{3,7,4,1,2,7},{4,1,6,2,7,4},{3,7,4,1,2,1},{3,7,4,1,2,6},{3,7,1,4,2,5},{3,7,1,4,2,2},{4,6,1,2,7,4},{3,7,1,4,2,1},{3,7,1,4,2,6},{3,1,7,4,2,7},{3,1,7,4,2,2},{3,1,7,4,2,1},{6,4,1,2,7,4},{3,1,7,4,2,6},{1,3,7,4,2,7},{1,3,7,4,2,2},{1,3,7,4,2,1},{6,1,4,2,7,4},{1,3,7,2,4,5},{1,3,7,2,4,2},{1,6,4,2,7,4},{1,3,7,2,4,1},{3,1,7,2,4,5},{3,1,7,2,4,2},{1,4,6,2,7,4},{3,1,7,2,4,1},{3,7,1,2,4,5},{3,7,1,2,4,2},{1,4,2,6,7,4},{3,7,1,2,4,1},{3,7,2,1,4,5},{3,7,2,1,4,2},{1,4,2,7,6,4},{3,7,2,1,4,1},{3,7,2,1,4,6},{3,7,2,4,1,5},{3,7,2,4,1,7},{1,4,7,2,6,3},{3,7,2,4,1,1},{3,7,2,4,1,6},{3,2,7,4,1,5},{3,2,7,4,1,7},{3,2,7,4,1,1},{3,2,7,4,1,6},{3,2,7,1,4,5},{3,2,7,1,4,2},{2,5,7,1,3,4},{2,5,7,1,3,3},{2,5,7,1,3,1},{2,5,7,3,1,5},{2,5,7,3,1,4},{2,5,7,3,1,3},{2,5,7,3,1,2},{7,5,3,4,6,7},{7,5,3,4,6,4},{7,5,3,4,6,3},{7,5,3,6,4,5},{7,5,3,6,4,7},{7,5,3,6,4,4},{7,5,3,6,4,3},{7,5,6,3,4,5},{7,5,6,3,4,4},{7,5,6,3,4,3},{7,5,6,3,4,1},{7,6,5,3,4,5},{7,6,5,3,4,4},{7,6,5,3,4,3},{7,6,5,3,4,1},{6,7,5,3,4,5},{6,7,5,3,4,3},{3,2,7,1,4,1},{3,2,7,1,4,6},{1,4,7,6,2,3},{3,2,1,7,4,5},{3,2,1,7,4,2},{3,2,1,7,4,1},{3,2,1,7,4,6},{3,1,2,7,4,2},{3,1,2,7,4,1},{1,3,2,7,4,2},{1,3,2,7,4,1},{6,1,4,7,2,4},{1,2,3,7,4,2},{1,2,3,7,4,6},{6,4,1,7,2,4},{6,4,1,7,2,3},{2,1,3,7,4,2},{4,6,1,7,2,4},{4,6,1,7,2,3},{2,1,3,7,4,6},{4,1,6,7,2,4},{4,1,6,7,2,3},{2,3,1,7,4,2},{2,3,1,7,4,6},{2,3,7,1,4,2},{4,1,7,6,2,3},{2,3,7,1,4,6},{2,3,7,4,1,7},{4,1,7,2,6,3},{2,3,7,4,1,2},{2,3,7,4,1,1},{4,7,1,2,6,3},{2,3,4,7,1,2},{2,3,4,7,1,1},{4,7,1,6,2,4},{2,3,4,1,7,2},{4,7,1,6,2,3},{2,3,4,1,7,1},{4,7,6,1,2,4},{2,3,1,4,7,2},{2,3,1,4,7,1},{2,3,1,4,7,6},{2,1,3,4,7,2},{4,6,7,1,2,4},{2,1,3,4,7,1},{4,6,7,1,2,3},{2,1,3,4,7,6},{6,4,7,1,2,4},{1,2,3,4,7,2},{6,4,7,1,2,3},{1,2,3,4,7,1},{1,2,3,4,7,6},{1,3,2,4,7,2},{6,4,7,2,1,3},{1,3,2,4,7,1},{3,1,2,4,7,2},{4,6,7,2,1,3},{3,1,2,4,7,1},{4,7,6,2,1,3},{3,2,1,4,7,2},{3,2,1,4,7,1},{3,2,1,4,7,6},{3,2,4,1,7,6},{3,2,4,7,1,5},{4,7,2,1,6,4},{3,2,4,7,1,7},{7,4,3,1,6,5},{7,4,3,1,6,7},{3,2,4,7,1,6},{3,4,2,7,1,5},{3,4,2,7,1,7},{3,4,2,7,1,6},{7,4,3,1,6,2},{7,4,3,1,6,6},{7,4,3,6,1,5},{7,4,3,6,1,7},{3,4,2,1,7,6},{7,4,3,6,1,2},{7,4,3,6,1,6},{7,4,6,3,1,5},{7,4,6,3,1,7},{3,4,1,2,7,6},{7,4,6,3,1,2},{7,4,6,3,1,6},{7,6,4,3,1,5},{7,6,4,3,1,7},{3,1,4,2,7,2},{3,1,4,2,7,1},{7,6,4,3,1,2},{3,1,4,2,7,6},{7,6,4,3,1,6},{6,7,4,3,1,5},{6,7,4,3,1,7},{1,3,4,2,7,2},{6,7,4,3,1,2},{1,3,4,2,7,1},{6,7,4,3,1,6},{6,7,4,1,3,5},{6,7,4,1,3,7},{6,7,4,1,3,2},{1,3,4,7,2,2},{6,7,4,1,3,1},{1,3,4,7,2,1},{6,7,4,1,3,6},{7,6,4,1,3,5},{7,6,4,1,3,7},{3,1,4,7,2,7},{7,6,4,1,3,2},{7,6,4,1,3,1},{3,1,4,7,2,2},{7,6,4,1,3,6},{3,1,4,7,2,1},{3,1,4,7,2,6},{7,4,6,1,3,5},{3,4,1,7,2,5},{7,4,6,1,3,7},{3,4,1,7,2,7},{3,4,1,7,2,6},{7,4,6,1,3,6},{3,4,7,1,2,5},{7,4,1,6,3,5},{3,4,7,1,2,7},{7,4,1,6,3,7},{3,4,7,1,2,2},{3,4,7,1,2,1},{7,4,1,6,3,2},{3,4,7,1,2,6},{3,4,7,2,1,5},{7,4,1,6,3,6},{3,4,7,2,1,7},{7,4,1,3,6,5},{3,4,7,2,1,2},{7,4,1,3,6,7},{3,4,7,2,1,1},{3,4,7,2,1,6},{7,4,1,3,6,2},{7,4,1,3,6,6},{7,1,4,3,6,7},{7,1,4,3,6,6},{7,1,4,6,3,5},{7,1,4,6,3,7},{7,1,4,6,3,2},{7,1,4,6,3,1},{7,1,4,6,3,6},{7,1,6,4,3,5},{7,1,6,4,3,7},{7,1,6,4,3,2},{7,1,6,4,3,1},{7,1,6,4,3,6},{7,6,1,4,3,5},{7,6,1,4,3,7},{7,6,1,4,3,2},{7,6,1,4,3,1},{7,6,1,4,3,6},{6,7,1,4,3,5},{6,7,1,4,3,2},{6,7,1,4,3,1},{6,7,1,4,3,6},{6,1,7,4,3,5},{6,1,7,4,3,6},{1,6,7,4,3,6},{1,7,6,4,3,7},{1,7,6,4,3,2},{1,7,6,4,3,1},{1,7,6,4,3,6},{1,7,4,6,3,7},{1,7,4,6,3,1},{1,7,4,6,3,6},{1,7,4,3,6,7},{1,7,4,3,6,6},{1,7,3,4,6,7},{1,7,3,4,6,6},{1,7,3,6,4,5},{1,7,3,6,4,7},{1,7,3,6,4,2},{1,7,3,6,4,6},{1,7,6,3,4,7},{1,7,6,3,4,2},{1,7,6,3,4,1},{1,6,7,3,4,5},{6,1,7,3,4,5},{4,1,5,3,2,2},{4,1,5,3,2,6},{4,5,1,3,2,5},{4,5,1,3,2,6},{4,5,3,1,2,5},{4,5,3,2,1,5},{5,1,7,2,6,4},{1,5,7,6,2,3},{1,5,7,2,6,3},{1,5,2,7,6,3},{1,5,2,6,7,3},{1,5,6,2,7,3},{1,6,5,2,7,3},{6,1,5,2,7,3},{6,5,1,2,7,3},{6,1,7,3,4,6},{6,7,1,3,4,5},{6,7,1,3,4,2},{6,7,1,3,4,1},{6,7,1,3,4,6},{7,6,1,3,4,5},{7,6,1,3,4,7},{7,6,1,3,4,2},{7,6,1,3,4,1},{7,6,1,3,4,6},{7,1,6,3,4,7},{7,1,6,3,4,2},{7,1,6,3,4,1},{7,1,3,6,4,7},{7,1,3,6,4,2},{7,1,3,6,4,1},{7,1,3,6,4,6},{7,1,3,4,6,7},{7,1,3,4,6,6},{7,3,1,4,6,7},{7,3,1,4,6,1},{7,3,1,4,6,6},{7,3,1,6,4,5},{7,3,1,6,4,7},{7,3,1,6,4,2},{7,3,1,6,4,6},{7,3,6,1,4,5},{7,3,6,1,4,7},{7,3,6,1,4,2},{7,3,6,1,4,1},{7,3,6,1,4,6},{7,6,3,1,4,5},{7,6,3,1,4,7},{7,6,3,1,4,2},{7,6,3,1,4,1},{7,6,3,1,4,6},{6,7,3,1,4,5},{6,7,3,1,4,7},{6,7,3,1,4,2},{6,7,3,1,4,6},{6,7,3,4,1,5},{6,7,3,4,1,7},{6,7,3,4,1,2},{6,7,3,4,1,6},{7,6,3,4,1,5},{7,6,3,4,1,7},{7,6,3,4,1,2},{7,6,3,4,1,6},{7,3,6,4,1,5},{7,3,6,4,1,7},{7,3,6,4,1,2},{7,3,6,4,1,6},{7,3,4,6,1,5},{7,3,4,6,1,7},{7,3,4,6,1,2},{7,3,4,6,1,6},{7,3,4,1,6,5},{7,3,4,1,6,7},{7,3,4,1,6,2},{7,3,4,1,6,6},{6,3,1,7,4,5},{6,1,3,7,4,5},{6,1,3,7,4,2},{6,1,3,7,4,6},{6,1,3,4,5,5},{1,6,3,7,4,5},{6,1,3,4,5,7},{6,1,3,4,5,4},{6,1,3,4,5,3},{1,6,3,7,4,2},{1,6,3,7,4,6},{1,3,6,7,4,5},{6,3,1,4,5,5},{6,3,1,4,5,7},{6,3,1,4,5,3},{1,3,6,7,4,6},{1,3,7,6,4,5},{3,6,1,4,5,7},{1,3,7,6,4,7},{3,6,1,4,5,3},{1,3,7,6,4,6},{1,3,7,4,6,7},{3,1,6,4,5,3},{1,3,7,4,6,6},{3,1,4,6,5,7},{3,1,4,6,5,4},{3,1,4,6,5,3},{1,3,4,7,6,6},{1,3,4,6,7,5},{3,1,4,5,6,5},{3,1,4,5,6,7},{3,1,4,5,6,4},{3,1,4,5,6,3},{1,3,4,6,7,6},{3,4,1,5,6,5},{3,4,1,5,6,4},{1,3,6,4,7,6},{1,6,3,4,7,5},{3,4,1,6,5,5},{3,4,1,6,5,4},{1,6,3,4,7,2},{1,6,3,4,7,6},{6,1,3,4,7,5},{3,4,6,1,5,5},{3,4,6,1,5,3},{6,1,3,4,7,2},{6,1,3,4,7,6},{3,4,6,1,5,6},{6,3,1,4,7,5},{3,6,4,1,5,5},{6,3,1,4,7,7},{3,6,4,1,5,3},{6,3,1,4,7,2},{6,3,1,4,7,6},{6,3,4,1,5,5},{3,6,1,4,7,5},{3,6,1,4,7,7},{3,6,1,4,7,2},{3,6,1,4,7,6},{6,3,4,5,1,5},{3,1,6,4,7,7},{3,6,4,5,1,5},{3,1,6,4,7,6},{3,1,4,6,7,5},{3,1,4,6,7,2},{3,1,4,6,7,1},{3,4,6,5,1,5},{3,1,4,6,7,6},{3,1,4,7,6,7},{3,1,4,7,6,2},{3,1,4,7,6,1},{3,4,5,6,1,5},{3,1,4,7,6,6},{3,4,1,7,6,7},{3,4,1,7,6,2},{3,4,5,1,6,5},{3,4,1,7,6,1},{3,4,1,7,6,6},{3,4,1,6,7,2},{4,3,5,1,6,5},{3,4,1,6,7,1},{3,4,1,6,7,6},{3,4,6,1,7,2},{3,4,6,1,7,1},{3,4,6,1,7,6},{3,6,4,1,7,7},{3,6,4,1,7,2},{3,6,4,1,7,1},{3,6,4,1,7,6},{6,3,4,1,7,5},{6,3,4,1,7,7},{6,3,4,1,7,2},{5,6,1,2,7,3},{5,1,6,2,7,3},{5,1,2,6,7,4},{5,1,2,6,7,3},{5,1,2,7,6,4},{5,1,2,7,6,3},{5,7,4,2,6,5},{5,7,4,2,6,7},{5,7,4,6,2,5},{5,7,4,6,2,7},{5,7,6,4,2,3},{6,5,7,4,2,3},{6,5,7,2,4,3},{5,6,7,2,4,4},{5,6,7,2,4,3},{5,7,6,2,4,4},{5,7,6,2,4,3},{5,7,2,6,4,3},{5,7,2,4,6,5},{5,2,7,4,6,5},{5,2,7,4,6,3},{5,2,7,6,4,5},{5,2,7,6,4,3},{5,2,6,7,4,5},{5,2,6,7,4,3},{5,6,2,7,4,5},{5,6,2,7,4,3},{6,5,2,7,4,5},{6,5,2,7,4,4},{6,5,2,7,4,3},{6,2,5,7,4,5},{6,2,5,7,4,7},{6,2,5,7,4,4},{6,2,5,7,4,1},{6,2,5,7,4,6},{2,6,5,7,4,5},{2,1,6,5,7,4},{2,6,5,7,4,7},{2,1,6,5,7,3},{2,6,5,7,4,4},{2,6,5,7,4,1},{2,6,5,7,4,6},{2,5,6,7,4,5},{2,6,1,5,7,4},{2,5,6,7,4,7},{2,6,1,5,7,3},{2,5,6,7,4,4},{2,5,6,7,4,3},{2,5,6,7,4,1},{2,5,6,7,4,6},{2,5,7,6,4,5},{6,2,1,5,7,4},{2,5,7,6,4,7},{6,2,1,5,7,3},{2,5,7,6,4,4},{2,5,7,6,4,3},{2,5,7,6,4,1},{2,5,7,6,4,6},{2,5,7,4,6,5},{2,5,7,4,6,3},{2,5,7,4,6,1},{2,5,4,7,6,5},{2,5,4,6,7,4},{2,5,6,4,7,5},{2,5,6,4,7,4},{2,5,6,4,7,1},{4,3,5,6,1,5},{6,3,4,1,7,6},{6,3,4,7,1,5},{6,3,4,7,1,7},{4,3,6,5,1,5},{6,3,4,7,1,2},{6,3,4,7,1,6},{4,6,3,5,1,5},{3,6,4,7,1,7},{3,6,4,7,1,2},{3,6,4,7,1,1},{3,6,4,7,1,6},{3,4,6,7,1,5},{6,4,3,5,1,5},{3,4,6,7,1,7},{3,4,6,7,1,2},{3,4,6,7,1,1},{3,4,6,7,1,6},{6,4,3,1,5,5},{3,4,7,6,1,5},{3,4,7,6,1,7},{3,4,7,6,1,2},{6,4,3,1,5,6},{3,4,7,6,1,1},{4,6,3,1,5,5},{3,4,7,6,1,6},{3,4,7,1,6,5},{3,4,7,1,6,7},{4,6,3,1,5,3},{3,4,7,1,6,2},{4,6,3,1,5,6},{4,3,6,1,5,5},{3,4,7,1,6,1},{3,4,7,1,6,6},{4,3,7,1,6,5},{4,3,6,1,5,3},{4,3,7,1,6,7},{4,3,6,1,5,6},{4,3,1,6,5,5},{4,3,7,1,6,2},{4,3,7,1,6,1},{4,3,1,6,5,4},{4,3,7,1,6,6},{4,3,1,6,5,3},{4,3,7,6,1,5},{4,3,7,6,1,7},{4,3,1,5,6,5},{4,3,7,6,1,2},{4,3,1,5,6,4},{4,3,7,6,1,1},{4,3,7,6,1,6},{4,3,1,5,6,3},{4,3,6,7,1,5},{4,3,6,7,1,7},{4,1,3,5,6,5},{4,1,3,5,6,4},{4,3,6,7,1,2},{4,1,3,5,6,3},{4,3,6,7,1,1},{4,3,6,7,1,6},{4,6,3,7,1,5},{4,6,3,7,1,7},{4,1,3,6,5,5},{4,1,3,6,5,4},{4,1,3,6,5,3},{4,6,3,7,1,2},{4,6,3,7,1,1},{4,6,3,7,1,6},{4,1,6,3,5,5},{6,4,3,7,1,5},{6,4,3,7,1,7},{4,1,6,3,5,4},{4,1,6,3,5,3},{6,4,3,7,1,2},{6,4,3,7,1,6},{6,4,3,1,7,5},{4,6,1,3,5,5},{6,4,3,1,7,7},{4,6,1,3,5,4},{6,4,3,1,7,2},{4,6,1,3,5,3},{6,4,3,1,7,6},{4,6,3,1,7,5},{6,4,1,3,5,5},{4,6,3,1,7,7},{6,4,1,3,5,7},{6,4,1,3,5,4},{4,6,3,1,7,2},{4,6,3,1,7,1},{4,6,3,1,7,6},{6,1,4,3,5,5},{6,1,4,3,5,7},{6,1,4,3,5,4},{6,1,4,3,5,3},{4,3,6,1,7,2},{4,3,6,1,7,1},{1,6,4,3,5,5},{4,3,6,1,7,6},{1,6,4,3,5,7},{1,6,4,3,5,3},{4,3,1,6,7,2},{1,4,6,3,5,5},{4,3,1,6,7,1},{1,4,6,3,5,7},{4,3,1,6,7,6},{1,4,6,3,5,3},{4,3,1,7,6,7},{4,3,1,7,6,2},{1,4,3,6,5,7},{4,3,1,7,6,1},{1,4,3,6,5,3},{4,3,1,7,6,6},{4,1,3,7,6,7},{1,4,3,5,6,5},{1,4,3,5,6,7},{1,4,3,5,6,3},{4,1,3,7,6,1},{4,1,3,7,6,6},{1,4,5,3,6,5},{1,4,5,3,6,7},{4,1,3,6,7,7},{1,4,5,3,6,4},{1,4,5,3,6,3},{1,4,5,3,6,2},{4,1,3,6,7,1},{4,1,3,6,7,6},{4,1,6,3,7,5},{1,4,5,6,3,5},{4,1,6,3,7,7},{1,4,5,6,3,7},{1,4,5,6,3,4},{1,4,5,6,3,3},{4,1,6,3,7,1},{1,4,5,6,3,2},{4,1,6,3,7,6},{4,6,1,3,7,5},{4,6,1,3,7,7},{1,4,6,5,3,5},{4,6,1,3,7,2},{4,6,1,3,7,1},{1,4,6,5,3,3},{4,6,1,3,7,6},{6,4,1,3,7,5},{6,4,1,3,7,7},{1,6,4,5,3,5},{1,6,4,5,3,7},{6,4,1,3,7,2},{1,6,4,5,3,4},{6,4,1,3,7,6},{6,1,4,3,7,5},{6,1,4,5,3,5},{6,1,4,3,7,2},{6,1,4,5,3,7},{6,1,4,5,3,4},{6,1,4,3,7,6},{6,1,4,5,3,3},{1,6,4,3,7,5},{6,4,1,5,3,5},{1,6,4,3,7,2},{6,4,1,5,3,7},{1,6,4,3,7,6},{6,4,1,5,3,4},{1,4,6,3,7,5},{6,4,1,5,3,3},{1,4,6,3,7,2},{4,6,1,5,3,5},{1,4,6,3,7,6},{4,6,1,5,3,7},{1,4,3,6,7,5},{4,6,1,5,3,4},{4,6,1,5,3,3},{4,1,6,5,3,5},{1,4,3,6,7,6},{4,1,6,5,3,4},{4,1,6,5,3,3},{4,1,5,6,3,5},{1,4,3,7,6,6},{4,1,5,6,3,7},{1,4,7,3,6,7},{4,1,5,6,3,4},{4,1,5,6,3,3},{4,1,5,6,3,2},{4,1,5,3,6,5},{1,4,7,3,6,6},{4,1,5,3,6,7},{4,1,5,3,6,4},{4,1,5,3,6,3},{4,1,5,3,6,2},{1,4,7,6,3,1},{1,4,7,6,3,6},{4,5,1,3,6,5},{4,5,1,3,6,2},{1,4,6,7,3,6},{4,5,1,6,3,5},{4,5,1,6,3,4},{4,5,1,6,3,2},{1,6,4,7,3,6},{6,1,4,7,3,5},{4,5,6,1,3,5},{4,5,6,1,3,4},{4,5,6,1,3,2},{6,1,4,7,3,6},{6,4,1,7,3,5},{4,6,5,1,3,5},{6,4,1,7,3,7},{4,6,5,1,3,4},{4,6,5,1,3,2},{6,4,1,7,3,6},{4,6,1,7,3,5},{4,6,1,7,3,7},{6,4,5,1,3,5},{6,4,5,1,3,7},{6,4,5,1,3,3},{4,6,1,7,3,1},{4,6,1,7,3,6},{4,1,6,7,3,5},{4,1,6,7,3,7},{6,4,5,3,1,5},{6,4,5,3,1,7},{4,1,6,7,3,1},{4,1,6,7,3,6},{6,4,5,3,1,2},{4,1,7,6,3,5},{4,1,7,6,3,7},{4,6,5,3,1,5},{4,1,7,6,3,1},{4,6,5,3,1,2},{4,1,7,6,3,6},{4,1,7,3,6,7},{4,5,6,3,1,5},{4,1,7,3,6,2},{4,5,6,3,1,2},{4,1,7,3,6,1},{4,1,7,3,6,6},{4,7,1,3,6,5},{4,5,3,6,1,5},{4,7,1,3,6,7},{4,5,3,6,1,2},{4,7,1,3,6,2},{4,5,3,1,6,5},{4,7,1,3,6,6},{4,7,1,6,3,5},{4,7,1,6,3,7},{4,7,1,6,3,2},{4,7,1,6,3,6},{4,7,6,1,3,5},{4,7,6,1,3,7},{4,7,6,1,3,6},{4,6,7,1,3,5},{4,6,7,1,3,7},{5,4,6,3,2,5},{4,6,7,1,3,2},{4,6,7,1,3,6},{6,4,7,1,3,5},{6,4,7,1,3,7},{6,4,7,1,3,2},{5,6,4,3,2,5},{6,4,7,1,3,1},{6,4,7,1,3,6},{6,4,7,3,1,5},{6,4,7,3,1,7},{6,5,4,3,2,5},{6,4,7,3,1,2},{6,4,7,3,1,6},{4,6,7,3,1,5},{6,5,4,3,2,1},{4,6,7,3,1,7},{6,5,4,2,3,5},{6,5,4,2,3,7},{4,6,7,3,1,2},{4,6,7,3,1,6},{6,5,4,2,3,1},{6,5,4,2,3,6},{4,7,6,3,1,5},{5,6,4,2,3,5},{4,7,6,3,1,7},{5,6,4,2,3,7},{4,7,6,3,1,2},{5,6,4,2,3,6},{4,7,3,6,1,5},{5,4,6,2,3,5},{4,7,3,6,1,7},{5,4,6,2,3,7},{5,4,6,2,3,4},{4,7,3,6,1,2},{4,7,3,6,1,1},{4,7,3,1,6,5},{4,7,3,1,6,7},{4,7,3,1,6,2},{5,4,6,2,3,6},{4,7,3,1,6,6},{5,4,2,6,3,5},{5,4,2,6,3,7},{5,4,2,6,3,4},{5,4,2,6,3,6},{5,4,2,3,6,7},{5,4,2,3,6,4},{5,2,4,3,6,7},{5,2,4,6,3,5},{5,2,4,6,3,7},{5,2,4,6,3,6},{5,2,6,4,3,5},{5,2,6,4,3,7},{5,2,6,4,3,4},{5,2,6,4,3,6},{5,6,2,4,3,5},{5,6,2,4,3,7},{5,6,2,4,3,4},{2,7,6,5,1,4},{2,7,5,6,1,4},{2,7,5,1,6,4},{7,2,5,1,6,4},{7,2,5,6,1,4},{7,2,6,5,1,4},{7,6,2,5,1,4},{5,6,2,4,3,6},{6,5,2,4,3,5},{6,5,2,4,3,7},{6,5,2,4,3,4},{6,5,2,4,3,6},{6,2,5,4,3,5},{6,2,5,4,3,4},{2,6,5,4,3,5},{2,6,5,4,3,4},{2,5,6,4,3,5},{2,5,6,4,3,4},{2,5,4,6,3,4},{2,5,4,3,6,5},{2,5,4,3,6,7},{2,5,4,3,6,4},{2,5,3,4,6,5},{2,5,3,4,6,7},{2,5,3,4,6,4},{2,5,3,4,6,3},{2,5,3,4,6,1},{2,5,3,6,4,5},{2,5,3,6,4,7},{2,5,3,6,4,4},{2,5,3,6,4,3},{2,5,3,6,4,1},{2,5,6,3,4,5},{2,5,6,3,4,7},{2,5,6,3,4,4},{2,5,6,3,4,3},{2,6,5,3,4,5},{2,6,5,3,4,7},{2,6,5,3,4,4},{2,6,5,3,4,3},{6,2,5,3,4,5},{6,2,5,3,4,7},{6,2,5,3,4,4},{6,2,5,3,4,3},{6,5,2,3,4,5},{6,5,2,3,4,4},{5,6,2,3,4,5},{5,6,2,3,4,4},{5,2,6,3,4,5},{5,2,6,3,4,4},{5,2,3,6,4,5},{5,2,3,4,6,7},{5,3,2,6,4,3},{5,3,6,2,4,3},{5,6,3,2,4,5},{5,6,3,2,4,7},{5,6,3,2,4,4},{6,5,3,2,4,5},{6,5,3,2,4,7},{6,5,3,2,4,4},{6,5,3,4,2,5},{6,5,3,4,2,7},{6,5,3,4,2,1},{5,6,3,4,2,5},{5,6,3,4,2,7},{2,6,4,3,5,5},{2,6,4,3,5,7},{2,6,4,3,5,4},{2,4,6,3,5,4},{2,4,3,6,5,7},{2,4,3,6,5,4},{2,4,3,5,6,5},{2,4,3,5,6,7},{2,4,3,5,6,4},{2,4,5,3,6,5},{2,4,5,3,6,4},{2,4,5,6,3,4},{2,4,6,5,3,4},{2,6,4,5,3,5},{2,6,4,5,3,4},{6,2,4,5,3,5},{6,2,4,5,3,4},{6,4,2,5,3,5},{6,4,2,5,3,4},{4,6,2,5,3,4},{4,2,6,5,3,4},{4,2,5,6,3,4},{4,2,5,3,6,5},{4,2,5,3,6,4},{4,5,2,3,6,7},{4,5,2,3,6,4},{4,5,2,3,6,2},{4,5,2,6,3,7},{4,5,2,6,3,4},{4,5,2,6,3,2},{4,5,6,2,3,5},{4,5,6,2,3,7},{4,5,6,2,3,4},{4,5,6,2,3,2},{4,6,5,2,3,5},{4,6,5,2,3,7},{4,6,5,2,3,4},{4,6,5,2,3,2},{4,6,5,2,3,1},{6,4,5,2,3,5},{6,4,5,2,3,7},{6,4,5,2,3,1},{6,4,5,3,2,1},{4,6,5,3,2,5},{4,6,5,3,2,1},{4,5,6,3,2,5},{4,5,3,6,2,5},{4,5,3,2,6,5},{5,4,3,2,1,5},{5,4,3,1,2,5},{5,4,1,3,2,5},{5,1,4,3,2,2},{5,1,4,3,2,1},{1,5,4,3,2,4},{1,5,4,3,2,3},{1,5,4,3,2,2},{1,5,4,3,2,6},{1,5,4,2,3,7},{1,5,4,2,3,4},{1,5,4,2,3,3},{1,5,4,2,3,2},{1,5,4,2,3,1},{1,5,4,2,3,6},{5,1,4,2,3,4},{5,1,4,2,3,2},{5,1,4,2,3,1},{5,4,1,2,3,5},{5,4,1,2,3,2},{5,4,1,2,3,6},{5,4,2,1,3,7},{5,4,2,1,3,2},{5,4,2,1,3,6},{5,4,2,3,1,7},{5,4,2,3,1,2},{5,4,2,3,1,6},{5,2,4,3,1,7},{5,2,4,3,1,2},{5,2,4,3,1,6},{5,2,4,1,3,7},{5,2,4,1,3,4},{5,2,4,1,3,2},{5,2,4,1,3,6},{5,2,1,4,3,4},{5,2,1,4,3,3},{5,2,1,4,3,2},{5,2,1,4,3,1},{5,2,1,4,3,6},{5,1,2,4,3,4},{5,1,2,4,3,3},{5,1,2,4,3,2},{5,1,2,4,3,1},{1,5,2,4,3,4},{1,5,2,4,3,3},{1,5,2,4,3,2},{1,5,2,4,3,1},{1,5,2,4,3,6},{1,2,5,4,3,7},{1,2,5,4,3,4},{1,2,5,4,3,3},{1,2,5,4,3,2},{1,2,5,4,3,6},{2,1,5,4,3,4},{2,1,5,4,3,3},{2,5,1,4,3,4},{2,5,1,4,3,3},{2,5,4,1,3,7},{2,5,4,1,3,4},{2,5,4,1,3,3},{2,5,4,3,1,7},{3,5,1,4,2,7},{3,5,1,4,2,3},{3,5,1,4,2,1},{3,1,5,4,2,7},{3,1,5,4,2,3},{7,6,1,2,3,4},{3,1,5,4,2,1},{7,6,1,2,3,3},{1,3,5,4,2,7},{1,3,5,4,2,3},{7,1,6,2,3,4},{7,1,6,2,3,3},{1,3,5,2,4,5},{1,3,5,2,4,7},{1,3,5,2,4,4},{1,3,5,2,4,3},{7,1,2,6,3,4},{7,1,2,6,3,3},{3,1,5,2,4,5},{3,1,5,2,4,7},{3,1,5,2,4,4},{3,1,5,2,4,3},{7,1,2,3,6,3},{3,5,1,2,4,5},{3,5,1,2,4,7},{7,2,1,3,6,4},{3,5,2,1,4,5},{3,5,2,1,4,7},{7,2,1,6,3,4},{3,5,2,1,4,6},{7,2,1,6,3,3},{3,2,5,4,1,5},{7,2,6,1,3,4},{7,2,6,1,3,3},{7,6,2,1,3,4},{7,6,2,1,3,3},{6,7,2,1,3,3},{6,7,2,3,1,3},{7,6,2,3,1,4},{7,6,2,3,1,3},{7,2,6,3,1,4},{7,2,6,3,1,3},{7,2,3,6,1,4},{7,2,3,6,1,3},{7,2,3,1,6,4},{2,7,3,1,6,4},{2,7,3,6,1,4},{2,7,6,3,1,4},{6,2,7,3,1,3},{6,2,7,1,3,3},{2,7,6,1,3,4},{2,7,1,6,3,4},{2,7,1,3,6,4},{1,2,6,7,3,4},{1,2,6,7,3,3},{1,2,7,6,3,4},{1,2,7,6,3,3},{1,2,7,3,6,4},{1,2,7,3,6,3},{3,2,5,4,1,3},{3,2,5,1,4,5},{3,2,5,1,4,7},{3,2,5,1,4,4},{3,2,5,1,4,3},{3,2,5,1,4,2},{3,2,5,1,4,1},{3,2,5,1,4,6},{3,2,1,5,4,5},{3,2,1,5,4,7},{3,2,1,5,4,4},{3,2,1,5,4,3},{3,1,2,5,4,7},{3,1,2,5,4,4},{3,1,2,5,4,3},{1,3,2,5,4,4},{1,3,2,5,4,3},{1,2,3,5,4,4},{1,2,3,5,4,3},{2,1,3,5,4,7},{2,1,3,5,4,4},{2,1,3,5,4,3},{2,3,1,5,4,7},{2,3,1,5,4,4},{2,3,1,5,4,3},{2,3,5,1,4,7},{2,3,5,1,4,4},{2,3,5,1,4,3},{2,3,5,1,4,2},{2,3,5,1,4,1},{2,3,5,1,4,6},{2,3,5,4,1,4},{2,3,5,4,1,3},{2,3,5,4,1,1},{2,3,5,4,1,6},{2,3,4,5,1,3},{2,3,4,1,5,3},{2,3,1,4,5,4},{1,3,2,4,5,4},{1,3,2,4,5,3},{3,1,2,4,5,4},{3,1,2,4,5,3},{3,2,1,4,5,5},{3,2,1,4,5,4},{3,2,1,4,5,3},{3,2,1,4,5,2},{3,2,1,4,5,1},{3,2,4,1,5,5},{3,2,4,1,5,3},{3,2,4,1,5,2},{3,2,4,1,5,1},{3,2,4,5,1,5},{3,4,2,5,1,5},{3,4,2,5,1,3},{3,4,2,5,1,2},{3,4,2,1,5,5},{3,4,2,1,5,3},{3,4,2,1,5,2},{3,4,2,1,5,1},{3,4,1,2,5,5},{3,4,1,2,5,4},{3,4,1,2,5,2},{3,4,1,2,5,1},{3,1,4,2,5,4},{3,1,4,2,5,1},{1,3,4,2,5,4},{1,3,4,5,2,4},{3,1,4,5,2,4},{3,1,4,5,2,1},{3,4,1,5,2,5},{3,4,1,5,2,4},{3,4,1,5,2,1},{3,4,5,1,2,5},{3,4,5,2,1,5},{7,4,2,1,6,4},{4,3,2,1,6,5},{4,3,2,1,6,7},{4,3,2,6,1,5},{4,3,2,6,1,7},{4,3,2,6,1,2},{4,3,6,2,1,5},{4,3,6,2,1,7},{4,3,6,2,1,2},{4,6,3,2,1,5},{4,6,3,2,1,7},{6,4,3,2,1,7},{6,4,3,1,2,7},{4,6,3,1,2,5},{4,6,3,1,2,7},{4,6,3,1,2,1},{4,3,6,1,2,5},{4,3,6,1,2,7},{4,3,6,1,2,1},{4,3,1,6,2,5},{4,3,1,6,2,7},{4,3,1,6,2,1},{4,3,1,2,6,5},{4,3,1,2,6,7},{6,7,4,1,2,4},{6,7,4,1,2,3},{4,1,3,2,6,5},{4,1,3,2,6,7},{7,6,4,1,2,4},{4,1,3,6,2,5},{4,1,3,6,2,7},{4,1,3,6,2,1},{7,4,6,1,2,4},{4,1,6,3,2,5},{4,1,6,3,2,7},{4,1,6,3,2,1},{4,6,1,3,2,5},{4,6,1,3,2,7},{7,4,1,6,2,4},{7,4,1,6,2,3},{4,6,1,3,2,1},{6,4,1,3,2,7},{7,4,1,2,6,3},{6,1,4,3,2,5},{6,1,4,3,2,7},{1,6,4,3,2,5},{1,6,4,3,2,7},{1,4,6,3,2,5},{1,4,6,3,2,7},{1,4,2,6,3,5},{1,4,6,2,3,5},{1,6,4,2,3,5},{6,1,4,2,3,5},{6,4,1,2,3,5},{6,7,2,1,4,4},{7,2,4,1,6,4},{2,7,4,1,6,4},{2,7,4,1,6,3},{2,7,4,6,1,4},{2,7,4,6,1,3},{2,7,6,4,1,3},{4,2,1,6,3,7},{4,6,2,1,3,7},{6,4,2,1,3,7},{6,2,7,1,4,4},{6,4,2,3,1,5},{6,4,2,3,1,7},{2,6,7,1,4,4},{4,6,2,3,1,7},{2,7,6,1,4,4},{2,7,6,1,4,3},{2,7,1,6,4,4},{2,7,1,6,4,3},{4,2,3,6,1,7},{2,7,1,4,6,4},{2,7,1,4,6,3},{4,2,3,1,6,7},{2,6,4,3,1,5},{2,6,4,3,1,7},{6,2,4,3,1,5},{6,2,4,3,1,7},{6,2,4,1,3,7},{2,1,4,6,3,5},{2,1,6,4,3,5},{2,6,1,4,3,5},{6,2,1,4,3,5},{6,2,1,4,3,7},{6,1,2,4,3,5},{1,6,2,4,3,5},{1,2,6,4,3,5},{1,2,4,6,3,5}},
}
diff --git a/parts/modes/attacker_h.lua b/parts/modes/attacker_h.lua
index f3a375c3a..a66f3ea20 100644
--- a/parts/modes/attacker_h.lua
+++ b/parts/modes/attacker_h.lua
@@ -1,4 +1,4 @@
-return{
+return {
env={
drop=30,lock=60,
fall=12,
@@ -7,9 +7,9 @@ return{
eventSet='attacker_h',
bg='rainbow2',bgm='shining terminal',
},
- score=function(P)return{P.modeData.wave,P.stat.time}end,
- scoreDisp=function(D)return D[1].." Waves "..STRING.time(D[2])end,
- comp=function(a,b)return a[1]>b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]=100 then
diff --git a/parts/modes/backfire_l.lua b/parts/modes/backfire_l.lua
index 72b810be7..4da3dce1b 100644
--- a/parts/modes/backfire_l.lua
+++ b/parts/modes/backfire_l.lua
@@ -1,4 +1,4 @@
-return{
+return {
env={
drop=5,lock=45,
freshLimit=15,
@@ -8,14 +8,14 @@ return{
},
mesDisp=function(P)
setFont(60)
- mStr(P.stat.atk,63,280)
+ GC.mStr(P.stat.atk,63,280)
mText(TEXTOBJ.atk,63,350)
end,
bg='blockhole',bgm='echo',
},
- score=function(P)return{math.min(math.floor(P.stat.atk),100),P.stat.time}end,
- scoreDisp=function(D)return D[1].." Attack "..STRING.time(D[2])end,
- comp=function(a,b)return a[1]>b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]=100 then
diff --git a/parts/modes/backfire_n.lua b/parts/modes/backfire_n.lua
index 957762651..96adcf20b 100644
--- a/parts/modes/backfire_n.lua
+++ b/parts/modes/backfire_n.lua
@@ -1,4 +1,4 @@
-return{
+return {
env={
drop=30,lock=60,
hook_drop={
@@ -7,14 +7,14 @@ return{
},
mesDisp=function(P)
setFont(60)
- mStr(P.stat.atk,63,280)
+ GC.mStr(P.stat.atk,63,280)
mText(TEXTOBJ.atk,63,350)
end,
bg='tunnel',bgm='echo',
},
- score=function(P)return{math.min(math.floor(P.stat.atk),100),P.stat.time}end,
- scoreDisp=function(D)return D[1].." Attack "..STRING.time(D[2])end,
- comp=function(a,b)return a[1]>b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]=100 then
diff --git a/parts/modes/backfire_u.lua b/parts/modes/backfire_u.lua
index 97e8651a3..bf08d84e9 100644
--- a/parts/modes/backfire_u.lua
+++ b/parts/modes/backfire_u.lua
@@ -1,4 +1,4 @@
-return{
+return {
env={
drop=2,lock=30,
freshLimit=10,
@@ -8,14 +8,14 @@ return{
},
mesDisp=function(P)
setFont(60)
- mStr(P.stat.atk,63,280)
+ GC.mStr(P.stat.atk,63,280)
mText(TEXTOBJ.atk,63,350)
end,
bg='blockhole',bgm='echo',
},
- score=function(P)return{math.min(math.floor(P.stat.atk),100),P.stat.time}end,
- scoreDisp=function(D)return D[1].." Attack "..STRING.time(D[2])end,
- comp=function(a,b)return a[1]>b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]=100 then
diff --git a/parts/modes/big_h.lua b/parts/modes/big_h.lua
index c1b4d0cfc..c7428572a 100644
--- a/parts/modes/big_h.lua
+++ b/parts/modes/big_h.lua
@@ -1,4 +1,4 @@
-return{
+return {
env={
noTele=true,
mindas=7,minarr=1,minsdarr=1,
@@ -7,16 +7,16 @@ return{
eventSet='big_h',
bg='cubes',bgm='push',
},
- score=function(P)return{math.min(P.modeData.maxCombo,100),P.stat.time}end,
- scoreDisp=function(D)return D[1].." Combo "..STRING.time(D[2])end,
- comp=function(a,b)return a[1]>b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]=200 then
local T=P.stat.time
return
- T<=160 and 5 or
- T<=280 and 4 or
+ T<=120 and 5 or
+ T<=180 and 4 or
3
else
return
diff --git a/parts/modes/big_n.lua b/parts/modes/big_n.lua
index 2bf31c135..8a3e95c69 100644
--- a/parts/modes/big_n.lua
+++ b/parts/modes/big_n.lua
@@ -1,4 +1,4 @@
-return{
+return {
env={
noTele=true,
mindas=7,minarr=1,minsdarr=1,
@@ -7,16 +7,16 @@ return{
eventSet='big_n',
bg='bg2',bgm='push',
},
- score=function(P)return{math.min(P.modeData.maxCombo,100),P.stat.time}end,
- scoreDisp=function(D)return D[1].." Combo "..STRING.time(D[2])end,
- comp=function(a,b)return a[1]>b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]=200 then
local T=P.stat.time
return
- T<=180 and 5 or
- T<=300 and 4 or
+ T<=120 and 5 or
+ T<=180 and 4 or
3
else
return
diff --git a/parts/modes/blind_e.lua b/parts/modes/blind_e.lua
index 694521083..bfeb49063 100644
--- a/parts/modes/blind_e.lua
+++ b/parts/modes/blind_e.lua
@@ -1,4 +1,4 @@
-return{
+return {
env={
drop=30,lock=45,
freshLimit=10,
@@ -7,9 +7,9 @@ return{
eventSet='checkLine_200',
bg='glow',bgm='sugar fairy',
},
- score=function(P)return{math.min(P.stat.row,200),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]b[1] or a[1]==b[1] and a[2]=200 then
diff --git a/parts/modes/blind_h.lua b/parts/modes/blind_h.lua
index 46fb8ec19..528c6c676 100644
--- a/parts/modes/blind_h.lua
+++ b/parts/modes/blind_h.lua
@@ -1,4 +1,4 @@
-return{
+return {
env={
drop=15,lock=45,
fall=10,
@@ -10,9 +10,9 @@ return{
eventSet='checkLine_200',
bg='rgb',bgm='sugar fairy',
},
- score=function(P)return{math.min(P.stat.row,200),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]b[1] or a[1]==b[1] and a[2]=200 then
diff --git a/parts/modes/blind_l.lua b/parts/modes/blind_l.lua
index 0f0e97b22..06aa6d9d8 100644
--- a/parts/modes/blind_l.lua
+++ b/parts/modes/blind_l.lua
@@ -1,4 +1,4 @@
-return{
+return {
env={
drop=10,lock=60,
fall=5,
@@ -11,9 +11,9 @@ return{
eventSet='checkLine_200',
bg='rgb',bgm='sugar fairy',
},
- score=function(P)return{math.min(P.stat.row,200),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]b[1] or a[1]==b[1] and a[2]=200 then
diff --git a/parts/modes/blind_n.lua b/parts/modes/blind_n.lua
index 81a38011f..1afb4e2ca 100644
--- a/parts/modes/blind_n.lua
+++ b/parts/modes/blind_n.lua
@@ -1,4 +1,4 @@
-return{
+return {
env={
drop=15,lock=45,
freshLimit=10,
@@ -7,9 +7,9 @@ return{
eventSet='checkLine_200',
bg='glow',bgm='sugar fairy',
},
- score=function(P)return{math.min(P.stat.row,200),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]b[1] or a[1]==b[1] and a[2]=200 then
diff --git a/parts/modes/blind_u.lua b/parts/modes/blind_u.lua
index dfe246289..42a01e919 100644
--- a/parts/modes/blind_u.lua
+++ b/parts/modes/blind_u.lua
@@ -1,4 +1,4 @@
-return{
+return {
env={
drop=30,lock=60,
block=false,center=0,ghost=0,
@@ -10,9 +10,9 @@ return{
eventSet='checkLine_100',
bg='rgb',bgm='far',
},
- 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]b[1] or a[1]==b[1] and a[2]b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]=100 then
local T=P.stat.time
return
T<=32 and 5 or
diff --git a/parts/modes/classic_e.lua b/parts/modes/classic_e.lua
index 1caf50c56..4503bdbad 100644
--- a/parts/modes/classic_e.lua
+++ b/parts/modes/classic_e.lua
@@ -1,4 +1,4 @@
-return{
+return {
env={
center=0,ghost=0,
smooth=false,
@@ -7,9 +7,9 @@ return{
bg='rgb',bgm='1980s',
},
slowMark=true,
- score=function(P)return{P.stat.score,P.stat.row}end,
- scoreDisp=function(D)return D[1].." "..D[2].." Lines"end,
- comp=function(a,b)return a[1]>b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1] or a[1]==b[1] and a[2]=200 and 5 or
+ L>=140 and 4 or
+ L>=100 and 3 or
+ L>=60 and 2 or
+ L>=30 and 1 or
+ L>=1 and 0
+ end,
+}
\ No newline at end of file
diff --git a/parts/modes/classic_u.lua b/parts/modes/classic_u.lua
index 4ece901a7..ab89b63c9 100644
--- a/parts/modes/classic_u.lua
+++ b/parts/modes/classic_u.lua
@@ -1,4 +1,4 @@
-return{
+return {
env={
center=0,ghost=0,
smooth=false,
@@ -7,9 +7,9 @@ return{
bg='rgb',bgm='1980s',
},
slowMark=true,
- score=function(P)return{P.stat.score,P.stat.row}end,
- scoreDisp=function(D)return D[1].." "..D[2].." Lines"end,
- comp=function(a,b)return a[1]>b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1]or a[1]==b[1]and a[2]=100 and 5 or
- L>=70 and 4 or
- L>=40 and 3 or
- L>=20 and 2 or
- L>=10 and 1 or
- L>=3 and 0
- end,
-}
diff --git a/parts/modes/custom_clear.lua b/parts/modes/custom_clear.lua
index 5d0ff9846..07422dee4 100644
--- a/parts/modes/custom_clear.lua
+++ b/parts/modes/custom_clear.lua
@@ -1,9 +1,9 @@
-return{
+return {
env={},
load=function()
applyCustomGame()
- --Switch clear sprint mode on
+ -- Switch clear sprint mode on
if #FIELD[1]>0 then
GAME.modeEnv.hook_drop=require'parts.eventsets.checkClearBoard'.hook_drop
else
@@ -12,9 +12,9 @@ return{
PLY.newPlayer(1)
local AItype=GAME.modeEnv.opponent:sub(1,2)
local AIlevel=tonumber(GAME.modeEnv.opponent:sub(-1))
- if AItype=='9S'then
+ if AItype=='9S' then
PLY.newAIPlayer(2,BOT.template{type='9S',speedLV=2*AIlevel,hold=true})
- elseif AItype=='CC'then
+ elseif AItype=='CC' then
PLY.newAIPlayer(2,BOT.template{type='CC',speedLV=2*AIlevel-1,next=math.floor(AIlevel*.5+1),hold=true,node=20000+5000*AIlevel})
end
diff --git a/parts/modes/custom_puzzle.lua b/parts/modes/custom_puzzle.lua
index 8eba6be95..3a82dfea1 100644
--- a/parts/modes/custom_puzzle.lua
+++ b/parts/modes/custom_puzzle.lua
@@ -1,16 +1,16 @@
local gc_setColor,gc_draw=love.graphics.setColor,love.graphics.draw
local ply_applyField=PLY.draw.applyField
-return{
+return {
env={
- fkey1=function(P)P.modeData.showMark=1-P.modeData.showMark end,
+ fkey1=function(P) P.modeData.showMark=1-P.modeData.showMark end,
hook_drop=function(P)
local D=P.modeData
local F=FIELD[D.finished+1]
for y=1,#F do
local L=P.field[y]
for x=1,10 do
- local a,b=F[y][x],L and L[x]or 0
+ local a,b=F[y][x],L and L[x] or 0
if a~=0 then
if a==-1 then if b>0 then return end
elseif a<12 then if a~=b then return end
@@ -20,7 +20,7 @@ return{
end
end
D.finished=D.finished+1
- if FIELD[D.finished+1]then
+ if FIELD[D.finished+1] then
P.waiting=26
for _=#P.field,1,-1 do
P.field[_],P.visTime[_]=nil
@@ -46,7 +46,7 @@ return{
end
end end
end
- PLY.draw.cancelField(P)
+ PLY.draw.cancelField()
end,
},
load=function()
@@ -54,9 +54,9 @@ return{
local AItype=GAME.modeEnv.opponent:sub(1,2)
local AIlevel=tonumber(GAME.modeEnv.opponent:sub(-1))
PLY.newPlayer(1)
- if AItype=='9S'then
+ if AItype=='9S' then
PLY.newAIPlayer(2,BOT.template{type='9S',speedLV=2*AIlevel,hold=true})
- elseif AItype=='CC'then
+ elseif AItype=='CC' then
PLY.newAIPlayer(2,BOT.template{type='CC',speedLV=2*AIlevel-1,next=math.floor(AIlevel*.5+1),hold=true,node=20000+5000*AIlevel})
end
end,
diff --git a/parts/modes/defender_l.lua b/parts/modes/defender_l.lua
index 318e6270f..d8603247b 100644
--- a/parts/modes/defender_l.lua
+++ b/parts/modes/defender_l.lua
@@ -1,4 +1,4 @@
-return{
+return {
env={
nextCount=3,
freshLimit=15,
@@ -6,9 +6,9 @@ return{
eventSet='defender_l',
bg='rainbow2',bgm='storm',
},
- score=function(P)return{P.modeData.wave,P.stat.time}end,
- scoreDisp=function(D)return D[1].." Waves "..STRING.time(D[2])end,
- comp=function(a,b)return a[1]>b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]0 and P.lastPiece.row<4 then
+ P:lose()
+ else
+ P.stat.dig_quad = P.stat.dig
+ end
+ if P.stat.dig==10 then
+ P:win('finish')
+ end
+ end,
+ task=function(P)
+ local last = -1
+ for _=1,10 do
+ local garbage = last
+ repeat
+ garbage = P:getHolePos()
+ until garbage ~= last
+ last = garbage
+ P:garbageRise(21,1,garbage)
+ end
+ P.fieldBeneath=0
+ P.stat.dig_quad = 0
+ end,
+ },
+ score=function(P) return {P.stat.dig_quad,P.stat.piece} end,
+ scoreDisp=function(D) return D[1].." Techrash "..D[2].." Pieces" end,
+ comp=function(a,b) return a[1]>b[1] or a[1]==b[1] and a[2] 103 and 2 or
+ piece > 92 and 3 or
+ piece > 81 and 4 or
+ 5
+ end,
+}
diff --git a/parts/modes/dig_u.lua b/parts/modes/dig_u.lua
index 60c525617..3040eee45 100644
--- a/parts/modes/dig_u.lua
+++ b/parts/modes/dig_u.lua
@@ -1,13 +1,13 @@
-return{
+return {
env={
drop=10,lock=30,
freshLimit=15,
eventSet='dig_u',
bg='bg2',bgm='shift',
},
- score=function(P)return{P.modeData.wave,P.stat.row}end,
- scoreDisp=function(D)return D[1].." Waves "..D[2].." Lines"end,
- comp=function(a,b)return a[1]>b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]0 then
- --Get heights
- for x=1,10 do
- local h=max
- while P.field[h][x]==0 and h>1 do
- h=h-1
- end
- height[x]=h
- end
- else
- for x=1,10 do
- height[x]=0
+ local height=TABLE.new(0,10)
+ local max=#field
+ if max>0 then
+ -- Get heights
+ for x=1,10 do
+ local h=max
+ while field[h][x]==0 and h>1 do
+ h=h-1
end
+ height[x]=h
+ end
+ else
+ for x=1,10 do
+ height[x]=0
end
- height[11]=999
+ end
+ height[11]=999
- local wei={1,1,2,2,3,4}
- local d=0
- for i=1,10 do
- d=d+height[i]
+ local wei={1,1,2,2,3,4}
+ local d=0
+ for i=1,10 do
+ d=d+height[i]
+ end
+ if d<40 or stat.row>2*42 then-- Low field or almost win, give SZO
+ for _=1,4 do
+ ins(wei,1)
+ ins(wei,2)
+ ins(wei,6)
end
- if d<40 or P.stat.row>2*42 then--Low field or almost win, give SZO
- for _=1,4 do
- ins(wei,1)
- ins(wei,2)
- ins(wei,6)
- end
- else
- --Give I when no hole
- local tempDeltaHei=-999--Height difference
- for x=2,11 do
- local deltaHei=height[x]-height[x-1]
- if tempDeltaHei<-2 and deltaHei>2 then
- break
- elseif x==11 then
- for _=1,3 do ins(wei,7)end
- else
- tempDeltaHei=deltaHei
- end
+ else
+ -- Give I when no hole
+ local tempDeltaHei=-999-- Height difference
+ for x=2,11 do
+ local deltaHei=height[x]-height[x-1]
+ if tempDeltaHei<-2 and deltaHei>2 then
+ break
+ elseif x==11 then
+ for _=1,3 do ins(wei,7) end
+ else
+ tempDeltaHei=deltaHei
end
+ end
- --Give O when no d=0/give T when no d=1
- local flatCount=0--d=0 count
- local stairCount=0--d=1 count
- for x=2,10 do
- local _=height[x]-height[x-1]
- if _==0 then
- flatCount=flatCount+1
- elseif _==1 or _==-1 then
- stairCount=stairCount+1
- end
- end
- if flatCount<3 then
- for _=1,3 do ins(wei,6)end
- end
- if stairCount<3 then
- for _=1,4 do ins(wei,5)end
+ -- Give O when no d=0/give T when no d=1
+ local flatCount=0-- d=0 count
+ local stairCount=0-- d=1 count
+ for x=2,10 do
+ local _=height[x]-height[x-1]
+ if _==0 then
+ flatCount=flatCount+1
+ elseif _==1 or _==-1 then
+ stairCount=stairCount+1
end
end
- P:getNext(wei[P.seqRND:random(#wei)])
+ if flatCount<3 then
+ for _=1,3 do ins(wei,6) end
+ end
+ if stairCount<3 then
+ for _=1,4 do ins(wei,5) end
+ end
end
+ field,stat=yield(wei[seqRND:random(#wei)])
end
end,
- nextCount=1,holdCount=0,
+ trueNextCount=1,nextCount=1,holdCount=0,
ospin=false,
freshLimit=15,
eventSet='checkLine_100',
bg='blockfall',bgm='reason',
},
- 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]b[1] or a[1]==b[1] and a[2]=100 then
diff --git a/parts/modes/drought_n.lua b/parts/modes/drought_n.lua
index 9f3b4798f..5b2be90e4 100644
--- a/parts/modes/drought_n.lua
+++ b/parts/modes/drought_n.lua
@@ -1,4 +1,4 @@
-return{
+return {
env={
drop=20,lock=60,
sequence='bag',
@@ -9,9 +9,9 @@ return{
eventSet='checkLine_100',
bg='blockfall',bgm='reason',
},
- 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]b[1] or a[1]==b[1] and a[2]=100 then
diff --git a/parts/modes/infinite.lua b/parts/modes/infinite.lua
index 7fec0ed09..aabeca896 100644
--- a/parts/modes/infinite.lua
+++ b/parts/modes/infinite.lua
@@ -1,11 +1,11 @@
-return{
+return {
env={
drop=1e99,lock=1e99,
infHold=true,
mesDisp=function(P)
setFont(45)
- mStr(("%.1f"):format(P.stat.atk),63,190)
- mStr(("%.2f"):format(P.stat.atk/P.stat.row),63,310)
+ GC.mStr(("%d"):format(P.stat.atk),63,190)
+ GC.mStr(("%.2f"):format(P.stat.atk/P.stat.row),63,310)
mText(TEXTOBJ.atk,63,243)
mText(TEXTOBJ.eff,63,363)
end,
diff --git a/parts/modes/infinite_dig.lua b/parts/modes/infinite_dig.lua
index 0a545812a..9a96a6619 100644
--- a/parts/modes/infinite_dig.lua
+++ b/parts/modes/infinite_dig.lua
@@ -15,17 +15,17 @@ local function check_rise(P)
if L==0 then
P:_showText(text.awesome,0,-120,80,'beat',.6)
SFX.play('pc')
- if BG.cur=='wing'then BG.send(26)end
+ if BG.cur=='wing' then BG.send(26) end
for _=1,8 do
P:garbageRise(13,1,generateLine(P.holeRND:random(10)))
end
else
- if BG.cur=='wing'then BG.send(#P.clearedRow)end
+ if BG.cur=='wing' then BG.send(#P.clearedRow) end
end
end
end
-return{
+return {
env={
drop=1e99,lock=1e99,
infHold=true,
@@ -33,9 +33,9 @@ return{
hook_drop=check_rise,
mesDisp=function(P)
setFont(45)
- mStr(P.stat.dig,63,190)
- mStr(P.stat.atk,63,310)
- mStr(("%.2f"):format(P.stat.atk/P.stat.row),63,420)
+ GC.mStr(P.stat.dig,63,190)
+ GC.mStr(P.stat.atk,63,310)
+ GC.mStr(("%.2f"):format(P.stat.atk/P.stat.row),63,420)
mText(TEXTOBJ.line,63,243)
mText(TEXTOBJ.atk,63,363)
mText(TEXTOBJ.eff,63,475)
diff --git a/parts/modes/marathon_bfmax.lua b/parts/modes/marathon_bfmax.lua
index d9e207c1c..1408600a8 100644
--- a/parts/modes/marathon_bfmax.lua
+++ b/parts/modes/marathon_bfmax.lua
@@ -1,4 +1,4 @@
-return{
+return {
env={
noTele=true,
mindas=7,minarr=1,minsdarr=1,
diff --git a/parts/modes/marathon_h.lua b/parts/modes/marathon_h.lua
index 2d707a841..5cee731b1 100644
--- a/parts/modes/marathon_h.lua
+++ b/parts/modes/marathon_h.lua
@@ -1,4 +1,4 @@
-return{
+return {
env={
noTele=true,
mindas=7,minarr=1,minsdarr=1,
@@ -7,9 +7,9 @@ return{
bg='cubes',bgm='push',
},
slowMark=true,
- score=function(P)return{math.min(P.stat.row,200),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]b[1] or a[1]==b[1] and a[2]=200 then
diff --git a/parts/modes/marathon_inf.lua b/parts/modes/marathon_inf.lua
index 9f8ef6675..f00e674d4 100644
--- a/parts/modes/marathon_inf.lua
+++ b/parts/modes/marathon_inf.lua
@@ -1,4 +1,4 @@
-return{
+return {
env={
noTele=true,
mindas=7,minarr=1,minsdarr=1,
@@ -7,9 +7,9 @@ return{
bg='bg2',bgm='push',
},
slowMark=true,
- score=function(P)return{P.stat.score,P.stat.row,P.stat.time}end,
- scoreDisp=function(D)return D[1].."P "..D[2].."L "..STRING.time(D[3])end,
- comp=function(a,b)return a[1]>b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]=26 and 0
end,
diff --git a/parts/modes/marathon_n.lua b/parts/modes/marathon_n.lua
index ee3d10098..5184e53f3 100644
--- a/parts/modes/marathon_n.lua
+++ b/parts/modes/marathon_n.lua
@@ -1,4 +1,4 @@
-return{
+return {
env={
noTele=true,
mindas=7,minarr=1,minsdarr=1,
@@ -7,9 +7,9 @@ return{
bg='bg2',bgm='push',
},
slowMark=true,
- score=function(P)return{math.min(P.stat.row,200),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]b[1] or a[1]==b[1] and a[2]=200 then
diff --git a/parts/modes/master_ex.lua b/parts/modes/master_ex.lua
index c9055c4f5..7aa16a1e5 100644
--- a/parts/modes/master_ex.lua
+++ b/parts/modes/master_ex.lua
@@ -1,14 +1,14 @@
local sectionName={"D","C","B","A","A+","S-","S","S+","S+","SS","SS","U","U","X","X+"}
-return{
+return {
env={
eventSet='master_ex',
bg='blockspace',bgm='hope',
},
slowMark=true,
- score=function(P)return{P.modeData.rankPoint,P.stat.score}end,
- scoreDisp=function(D)return sectionName[math.floor(D[1]/10)+1].." "..D[2]end,
- comp=function(a,b)return a[1]>b[1]or a[1]==b[1]and a[2]>b[2]end,
+ score=function(P) return {P.modeData.rankPoint,P.stat.score} end,
+ scoreDisp=function(D) return sectionName[math.floor(D[1]/10)+1].." "..D[2] end,
+ comp=function(a,b) return a[1]>b[1] or a[1]==b[1] and a[2]>b[2] end,
getRank=function(P)
P=P.modeData.rankPoint
return
diff --git a/parts/modes/master_final.lua b/parts/modes/master_final.lua
index d1608960b..3b17d0171 100644
--- a/parts/modes/master_final.lua
+++ b/parts/modes/master_final.lua
@@ -1,13 +1,13 @@
-return{
+return {
env={
sequence="bagES",
eventSet='master_final',
bg='lightning',bgm='rectification',
},
slowMark=true,
- score=function(P)return{P.modeData.pt,P.stat.time}end,
- scoreDisp=function(D)return D[1].."P "..STRING.time(D[2])end,
- comp=function(a,b)return a[1]>b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1] or (a[1]==b[1] and a[2]=40 and 5 or -- TM+
+ G>=32 and 4 or -- MM- - TM
+ G>=26 and 3 or -- m8 - MO
+ G>=19 and 2 or -- m1 - m7
+ G>=10 and 1 or -- S1 - S9
+ 0
+
+ -- Table of grades vs values
+ -- 9 8 7 6 5 4 3 2 1 S1 S2 S3 S4 S5 S6 S7 S8 S9 m1 m2 m3 m4 m5 m6 m7 m8 m9 M MK MV MO MM- MM MM+ GM- GM GM+ TM- TM TM+
+ -- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
+ end,
+}
diff --git a/parts/modes/master_h.lua b/parts/modes/master_h.lua
index f58b91561..1b8ecc22f 100644
--- a/parts/modes/master_h.lua
+++ b/parts/modes/master_h.lua
@@ -1,4 +1,4 @@
-return{
+return {
env={
freshLimit=15,
sequence="bagES",
@@ -6,10 +6,10 @@ return{
bg='bg2',bgm='secret7th',
},
slowMark=true,
- score=function(P)return{P.modeData.pt,P.stat.time}end,
- scoreDisp=function(D)return D[1].."P "..STRING.time(D[2])end,
+ score=function(P) return {P.modeData.pt,P.stat.time} end,
+ scoreDisp=function(D) return D[1].."P "..STRING.time(D[2]) end,
comp=function(a,b)
- return a[1]>b[1]or(a[1]==b[1]and a[2]b[1] or (a[1]==b[1] and a[2]b[1]or(a[1]==b[1]and a[2]b[1] or (a[1]==b[1] and a[2]b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1]or(a[1]==b[1]and a[2]b[1] or (a[1]==b[1] and a[2]b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]=226 and 4 or
p>=162 and 3 or
p>=62 and 2 or
diff --git a/parts/modes/netBattle.lua b/parts/modes/netBattle.lua
index 2238a5aba..2e9f26e4d 100644
--- a/parts/modes/netBattle.lua
+++ b/parts/modes/netBattle.lua
@@ -1,30 +1,37 @@
-local yield=YIELD
+local yield=coroutine.yield
local function marginTask(P)
local S=P.stat
- while true do yield()if S.frame>90*60 then P.strength=1;P:setFrameColor(1)break end end
- while true do yield()if S.frame>135*60 then P.strength=2;P:setFrameColor(2)break end end
- while true do yield()if S.frame>180*60 then P.strength=3;P:setFrameColor(3)break end end
- while true do yield()if S.frame>260*60 then P.strength=4;P:setFrameColor(4)break end end
+ while true do yield() if S.frame>90*60 then P.strength=1;P:setFrameColor(1)break end end
+ while true do yield() if S.frame>135*60 then P.strength=2;P:setFrameColor(2)break end end
+ while true do yield() if S.frame>180*60 then P.strength=3;P:setFrameColor(3)break end end
+ while true do yield() if S.frame>260*60 then P.strength=4;P:setFrameColor(4)break end end
end
-return{
+return {
env={
bg={'bg1','bg2','blockhole','blockfall','blockrain','blockspace','cubes','fan','flink','glow','matrix','rainbow','rainbow2','tunnel'},
bgm={'battle','beat5th','cruelty','distortion','echo','far','final','here','hope','memory','moonbeam','push','rectification','secret7th remix','secret7th','secret8th remix','secret8th','shift','shining terminal','storm','super7th','there','truth','vapor','waterfall'},
},
load=function()
- for k,v in next,NET.roomState.roomData do
+ for k,v in next,NET.roomState.data do
GAME.modeEnv[k]=v
end
GAME.modeEnv.allowMod=false
GAME.modeEnv.task=marginTask
- local L=TABLE.copy(NETPLY.list)
+ local L=TABLE.shift(NETPLY.list,0)
+ table.sort(L,function(a,b) return a.uidb[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1] or a[1]==b[1] and a[2]=23 and 5 or
+ G>=21 and 4 or
+ G>=19 and 3 or
+ G>=15 and 2 or
+ G>=11 and 1 or
+ G>=7 and 0
+ end,
+}
diff --git a/parts/modes/solo_e.lua b/parts/modes/solo_e.lua
index 4178e46b3..20bed375e 100644
--- a/parts/modes/solo_e.lua
+++ b/parts/modes/solo_e.lua
@@ -1,19 +1,19 @@
-return{
+return {
env={
life=2,
drop=60,lock=60,
freshLimit=15,
- bg='bg2',bgm='battle',
+ bg='quarks',bgm='battle',
},
load=function()
PLY.newPlayer(1)
PLY.newAIPlayer(2,BOT.template{type='9S',speedLV=3,hold=true})
end,
- score=function(P)return{P.stat.time}end,
- scoreDisp=function(D)return STRING.time(D[1])end,
- comp=function(a,b)return a[1]=2 and 5 or
diff --git a/parts/modes/solo_n.lua b/parts/modes/solo_n.lua
index 068508741..796c839c4 100644
--- a/parts/modes/solo_n.lua
+++ b/parts/modes/solo_n.lua
@@ -1,19 +1,19 @@
-return{
+return {
env={
life=2,
drop=60,lock=60,
freshLimit=15,
- bg='bg2',bgm='battle',
+ bg='quarks',bgm='battle',
},
load=function()
PLY.newPlayer(1)
PLY.newAIPlayer(2,BOT.template{type='9S',speedLV=5,hold=true})
end,
- score=function(P)return{P.stat.time}end,
- scoreDisp=function(D)return STRING.time(D[1])end,
- comp=function(a,b)return a[1]=2 and 5 or
diff --git a/parts/modes/sprint123.lua b/parts/modes/sprint123.lua
new file mode 100644
index 000000000..83a7d1da3
--- /dev/null
+++ b/parts/modes/sprint123.lua
@@ -0,0 +1,22 @@
+return {
+ env={
+ drop=60,lock=60,
+ sequence='bag',seqData={26,27,28,29},
+ eventSet='checkLine_40',
+ bg='bg2',bgm='race',
+ },
+ score=function(P) return {P.stat.time,P.stat.piece} end,
+ scoreDisp=function(D) return STRING.time(D[1]).." "..D[2].." Pieces" end,
+ comp=function(a,b) return a[1]b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1]or a[1]==b[1]and a[2]b[1] or a[1]==b[1] and a[2]b[1]or a[1]==b[1]and a[2]