Compare commits
395 Commits
v0.17.7
...
0e8ddee6c5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e8ddee6c5 | ||
|
|
bf0bb1d47b | ||
|
|
bce60ee6c7 | ||
|
|
b0a47f5222 | ||
|
|
58bac2e290 | ||
|
|
84361c3c31 | ||
|
|
d0a7a28349 | ||
|
|
10b8891cf0 | ||
|
|
3a4fcf6d7b | ||
|
|
19ea76dc4c | ||
|
|
42942d1ac4 | ||
|
|
43215dfc4b | ||
|
|
5728194085 | ||
|
|
1501ebd92a | ||
|
|
0299fde47b | ||
|
|
11680aedbb | ||
|
|
ad0b73ff62 | ||
|
|
f38746ff96 | ||
|
|
8ee7a90eca | ||
|
|
d06d8ebfff | ||
|
|
d3e4d7e62c | ||
|
|
80ff30401a | ||
|
|
4657515b61 | ||
|
|
90dcb9ee1a | ||
|
|
4e606f4e91 | ||
|
|
9c0dc60746 | ||
|
|
58a5749d67 | ||
|
|
7d0d89f1a6 | ||
|
|
f92121f093 | ||
|
|
2604d034fe | ||
|
|
3219da77e9 | ||
|
|
ea3fb8d09e | ||
|
|
074cefed5d | ||
|
|
7070e620c8 | ||
|
|
1cd62bb163 | ||
|
|
529b8d453d | ||
|
|
486eaeae52 | ||
|
|
a2931ea290 | ||
|
|
edb79e8156 | ||
|
|
ed5abe0350 | ||
|
|
3806f02fa5 | ||
|
|
7d23fe4acb | ||
|
|
c650f268f6 | ||
|
|
55800e307f | ||
|
|
2671306688 | ||
|
|
20e9d085c0 | ||
|
|
1c1a006723 | ||
|
|
a0fd8ff8b6 | ||
|
|
720325fcb9 | ||
|
|
fcc1cba0cf | ||
|
|
8ca17ba3ff | ||
|
|
942a789b9e | ||
|
|
293e687077 | ||
|
|
9929b888c5 | ||
|
|
e66e30c14a | ||
|
|
adf225e192 | ||
|
|
4c2dc5e8df | ||
|
|
e1a9222b1f | ||
|
|
86c673ee51 | ||
|
|
6aefa078da | ||
|
|
dd743035f5 | ||
|
|
045deb6954 | ||
|
|
8e169dbde8 | ||
|
|
90c428cf44 | ||
|
|
7ac2c282f6 | ||
|
|
ad58d38ab1 | ||
|
|
5ea940d8c4 | ||
|
|
c0dca683b5 | ||
|
|
35635e10ea | ||
|
|
dfda067c08 | ||
|
|
09117c4704 | ||
|
|
6083fd5097 | ||
|
|
e104297b13 | ||
|
|
ed3927a8c3 | ||
|
|
b62b907dc8 | ||
|
|
769125a894 | ||
|
|
6ccebcfe17 | ||
|
|
8894701806 | ||
|
|
012e0f76a9 | ||
|
|
d58f41b999 | ||
|
|
95916a8736 | ||
|
|
69a288db8f | ||
|
|
bb8a436604 | ||
|
|
b58f266561 | ||
|
|
4e41024ba8 | ||
|
|
323f8a72aa | ||
|
|
bb4d3023c6 | ||
|
|
2208a0fca0 | ||
|
|
3cd6f3d726 | ||
|
|
8b1d72fb54 | ||
|
|
73480d4a53 | ||
|
|
120dc453d7 | ||
|
|
eae441b18b | ||
|
|
4f411ef78e | ||
|
|
35ec325990 | ||
|
|
54758fd705 | ||
|
|
e7183025cf | ||
|
|
03a2e9356c | ||
|
|
0eb4212e40 | ||
|
|
22ca0a7c96 | ||
|
|
33fc59bd5c | ||
|
|
2f6a3392e6 | ||
|
|
75f3efc6a0 | ||
|
|
19e4185668 | ||
|
|
bbb5fd7832 | ||
|
|
8806ef602e | ||
|
|
6f5ebb1a4d | ||
|
|
7cd03d0ec0 | ||
|
|
00c5233f3b | ||
|
|
a08328ae02 | ||
|
|
a6a20b4332 | ||
|
|
732e2aee79 | ||
|
|
74c3d3a313 | ||
|
|
3ebc93e65c | ||
|
|
7e8e67694d | ||
|
|
00f63a2ec5 | ||
|
|
5a30e4aec9 | ||
|
|
43aecd2467 | ||
|
|
622ae07b32 | ||
|
|
63f443d4e4 | ||
|
|
688328e6b0 | ||
|
|
0fc4957b21 | ||
|
|
5e88b23980 | ||
|
|
986f0dcdc8 | ||
|
|
48f2ee9252 | ||
|
|
73d6eaaffc | ||
|
|
b1dbc4fa87 | ||
|
|
2e9ea4a783 | ||
|
|
86654689da | ||
|
|
b4901add94 | ||
|
|
8df321b84d | ||
|
|
6a4dfb47bb | ||
|
|
dd8a810591 | ||
|
|
009858e2f8 | ||
|
|
a475232432 | ||
|
|
bc99af5b1b | ||
|
|
337293dbe1 | ||
|
|
5e0be0d463 | ||
|
|
cf147be119 | ||
|
|
c695596285 | ||
|
|
7b97aefa0a | ||
|
|
a3e5ccffa4 | ||
|
|
452fa65748 | ||
|
|
7141f46948 | ||
|
|
481ea06e61 | ||
|
|
3aa60d3488 | ||
|
|
e152e147e2 | ||
|
|
c7b8dd24c7 | ||
|
|
9e384f80cb | ||
|
|
06dc22544f | ||
|
|
70c1b04bf6 | ||
|
|
7f8e3e647a | ||
|
|
df79e99fa5 | ||
|
|
03eafb4881 | ||
|
|
e795604721 | ||
|
|
9769b33deb | ||
|
|
51968741ea | ||
|
|
41c957cd8f | ||
|
|
e3a0eacf1d | ||
|
|
29a5cc63df | ||
|
|
3f0bf28fbe | ||
|
|
2321176712 | ||
|
|
974308c843 | ||
|
|
1d59cba316 | ||
|
|
f3e1e9b4b2 | ||
|
|
5c38bb64a0 | ||
|
|
3fbff37095 | ||
|
|
540099a944 | ||
|
|
cd0b276885 | ||
|
|
519f84a804 | ||
|
|
e44462bb78 | ||
|
|
9da2300194 | ||
|
|
91c39ee7ef | ||
|
|
58ea85e6b9 | ||
|
|
7be2aa50dd | ||
|
|
ed9417dcdf | ||
|
|
36522c7146 | ||
|
|
20b74ea78a | ||
|
|
0ae9cbcdaa | ||
|
|
c9cbb0e363 | ||
|
|
0595ce4ea6 | ||
|
|
2e2427f942 | ||
|
|
aeddee2f03 | ||
|
|
43037f8043 | ||
|
|
0c3d552d08 | ||
|
|
a1b6b8a434 | ||
|
|
5061cad389 | ||
|
|
9d3fb33d10 | ||
|
|
4d82b182a6 | ||
|
|
78ac05efba | ||
|
|
02cf7b71c1 | ||
|
|
091bb23488 | ||
|
|
0ec0d80e9c | ||
|
|
d4d87ccb5c | ||
|
|
c782c1fcdd | ||
|
|
f7cdae8677 | ||
|
|
f41a68de0d | ||
|
|
aefde7a777 | ||
|
|
3dc61688c4 | ||
|
|
7e00a7d764 | ||
|
|
8304cf655b | ||
|
|
c25e7a3d5b | ||
|
|
b7b02ab5bc | ||
|
|
b3a8724538 | ||
|
|
ed11faf909 | ||
|
|
b5cd0be057 | ||
|
|
d31954d1e2 | ||
|
|
96bf30fcab | ||
|
|
e7fc5a676e | ||
|
|
4a81d8beb0 | ||
|
|
c583769cf3 | ||
|
|
2ff2fd1940 | ||
|
|
6d45cf978a | ||
|
|
4c3b80a1fb | ||
|
|
d22aa81fa0 | ||
|
|
1e76b8e533 | ||
|
|
886adc3534 | ||
|
|
aff7ffb2c4 | ||
|
|
4ec1f7c5c8 | ||
|
|
7772c9b424 | ||
|
|
514f0a17b5 | ||
|
|
91adc0d153 | ||
|
|
48425f5549 | ||
|
|
fd36562a7d | ||
|
|
4b36442170 | ||
|
|
dad6beca05 | ||
|
|
ee61c5aa8d | ||
|
|
1001588f97 | ||
|
|
25df3d819b | ||
|
|
a2e5656747 | ||
|
|
65fc0339b9 | ||
|
|
0421654c50 | ||
|
|
bdaa42f6df | ||
|
|
9984c3ecb5 | ||
|
|
5e7c2309ac | ||
|
|
9dda8555a0 | ||
|
|
43046a3cf3 | ||
|
|
fe29cc532d | ||
|
|
7dd73ef8d3 | ||
|
|
ad6bd7be4b | ||
|
|
c276b700fa | ||
|
|
98f73aa4c0 | ||
|
|
1db854618e | ||
|
|
940a1bc3f8 | ||
|
|
7463dd96dc | ||
|
|
48e96998a9 | ||
|
|
95a1b03cc5 | ||
|
|
ee4dfa7f51 | ||
|
|
06f403e9d7 | ||
|
|
c03f3f727c | ||
|
|
ed4ba1dc38 | ||
|
|
9663f8c316 | ||
|
|
2478df1242 | ||
|
|
1b54dd3b90 | ||
|
|
001014c70e | ||
|
|
1a444a9e98 | ||
|
|
d5397333d5 | ||
|
|
e1001c74c5 | ||
|
|
5f664c04d6 | ||
|
|
525fa4c25e | ||
|
|
f513760153 | ||
|
|
5faa929bb0 | ||
|
|
5c4557a7b7 | ||
|
|
69a84c035e | ||
|
|
f8277e1c8a | ||
|
|
48f3d293bd | ||
|
|
00bf828ef4 | ||
|
|
d1cef7ed84 | ||
|
|
17bb8dbe6d | ||
|
|
6166c03eab | ||
|
|
303f32f5b2 | ||
|
|
f7e4d7b30d | ||
|
|
f2957dff7b | ||
|
|
cadbe38a8f | ||
|
|
e55d117371 | ||
|
|
1f3d8a212b | ||
|
|
035f30d7e1 | ||
|
|
3202aa18b1 | ||
|
|
0c5d2bdf1a | ||
|
|
db25475c21 | ||
|
|
11b1c23be0 | ||
|
|
5b1eef890d | ||
|
|
3a3d062e5c | ||
|
|
2ee9ed237f | ||
|
|
9159661945 | ||
|
|
0efd2c8044 | ||
|
|
0aaa5822fb | ||
|
|
2b258aeaed | ||
|
|
0d7a80f2b5 | ||
|
|
d433d98c04 | ||
|
|
180dc12460 | ||
|
|
dd1d0b4126 | ||
|
|
f1517fad1a | ||
|
|
62ed279f07 | ||
|
|
6925d59f87 | ||
|
|
848cc41c72 | ||
|
|
f212076604 | ||
|
|
ee4fd51e0f | ||
|
|
f96b4f6724 | ||
|
|
7b6f2f826a | ||
|
|
8ed4fd6cba | ||
|
|
b914cb26be | ||
|
|
97472e9a17 | ||
|
|
dece8c0daa | ||
|
|
5796d1af32 | ||
|
|
06d7a1df6b | ||
|
|
ed293ddad8 | ||
|
|
d7a92344e5 | ||
|
|
3fa020fe91 | ||
|
|
ce19af7da0 | ||
|
|
e558a9fc9d | ||
|
|
fb5544ce0f | ||
|
|
051f0d484c | ||
|
|
108cbea686 | ||
|
|
8b61bd7d8a | ||
|
|
1699a2b68a | ||
|
|
2fca95e81b | ||
|
|
969aa87a10 | ||
|
|
b3dfa7d7ce | ||
|
|
483de50169 | ||
|
|
96762ffa5c | ||
|
|
88d05c2354 | ||
|
|
8aac152ee6 | ||
|
|
d83779662a | ||
|
|
c19e656d46 | ||
|
|
4631a2f440 | ||
|
|
338f5811a1 | ||
|
|
bc634b2eeb | ||
|
|
23cbb9e261 | ||
|
|
fbfbf3c32b | ||
|
|
3073a2e90d | ||
|
|
29e4dc93ab | ||
|
|
2b16a20032 | ||
|
|
59b412899d | ||
|
|
e656ab5e1d | ||
|
|
b90c06da72 | ||
|
|
f62f3652e2 | ||
|
|
dbbec9d2bd | ||
|
|
1be8189058 | ||
|
|
b8b3160ccd | ||
|
|
54fd3995e6 | ||
|
|
e506190c7f | ||
|
|
8f418a0da9 | ||
|
|
0403ee91ea | ||
|
|
47d1856143 | ||
|
|
e521f0fea0 | ||
|
|
eb1e7fd15a | ||
|
|
c9e0a58232 | ||
|
|
9acd8b54e3 | ||
|
|
acd66b1634 | ||
|
|
3820855812 | ||
|
|
056abe7b68 | ||
|
|
bf05b1bda2 | ||
|
|
77a3c146c0 | ||
|
|
5761f7f543 | ||
|
|
5ed5b543ce | ||
|
|
98ae0f2762 | ||
|
|
963bc80439 | ||
|
|
4106dc454e | ||
|
|
0ba26aa836 | ||
|
|
a4c775174b | ||
|
|
29c40c34fe | ||
|
|
44cb889b91 | ||
|
|
915d65d2f4 | ||
|
|
8b7c270cf6 | ||
|
|
a3f07f8ce4 | ||
|
|
91d3252685 | ||
|
|
f9d9112651 | ||
|
|
477a1acc61 | ||
|
|
4770366f74 | ||
|
|
1c66b4dce1 | ||
|
|
3a19bb534a | ||
|
|
f39b3cfd4a | ||
|
|
f0410243c4 | ||
|
|
8abc40707a | ||
|
|
f91fe34a12 | ||
|
|
e9bf6c3b58 | ||
|
|
17c660b5a2 | ||
|
|
ed46f73987 | ||
|
|
e1200b5038 | ||
|
|
7f7ea6ac97 | ||
|
|
f70edaac83 | ||
|
|
d932febe89 | ||
|
|
945a63c51d | ||
|
|
da716ea5c5 | ||
|
|
c6f92a3030 | ||
|
|
267e2dc544 | ||
|
|
cb7d3afdfb | ||
|
|
b57e863c28 | ||
|
|
7aed15fd4f | ||
|
|
6d71b26595 | ||
|
|
1df5406cb3 | ||
|
|
a2b762dcbc | ||
|
|
c2d29c3d6a | ||
|
|
da602eb693 |
31
.editorconfig
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# EmmyLuaCodeStyle
|
||||||
|
[*.lua]
|
||||||
|
max_line_length = 26000
|
||||||
|
indent_style = space
|
||||||
|
insert_final_newline = true
|
||||||
|
space_around_table_field_list = false
|
||||||
|
space_before_attribute = false
|
||||||
|
space_before_function_call_open_parenthesis = false
|
||||||
|
space_before_closure_open_parenthesis = false
|
||||||
|
space_before_function_call_single_arg = false
|
||||||
|
space_before_open_square_bracket = false
|
||||||
|
space_inside_function_call_parentheses = false
|
||||||
|
space_inside_function_param_list_parentheses = false
|
||||||
|
space_inside_square_brackets = false
|
||||||
|
space_around_table_append_operator = false
|
||||||
|
space_before_inline_comment = false
|
||||||
|
space_around_math_operator = false
|
||||||
|
space_around_logical_operator = false
|
||||||
|
space_around_assign_operator = false
|
||||||
|
space_after_comma = false
|
||||||
|
space_after_comma_in_for_statement = false
|
||||||
|
space_around_concat_operator = false
|
||||||
|
align_call_args = false
|
||||||
|
align_function_params = false
|
||||||
|
align_continuous_assign_statement = true
|
||||||
|
align_continuous_rect_table_field = true
|
||||||
|
align_if_branch = false
|
||||||
|
align_array_table = true
|
||||||
|
ignore_spaces_inside_function_call = true
|
||||||
|
line_space_after_function_statement = keep
|
||||||
|
trailing_table_separator = smart
|
||||||
2
.github/actions/get-cc/action.yml
vendored
@@ -3,7 +3,7 @@ description: 'download cc into specific dir'
|
|||||||
inputs:
|
inputs:
|
||||||
tag:
|
tag:
|
||||||
required: false
|
required: false
|
||||||
default: "11.4"
|
default: "11.4.2"
|
||||||
platform:
|
platform:
|
||||||
required: true
|
required: true
|
||||||
dir:
|
dir:
|
||||||
|
|||||||
12
.github/build/iOS/love.patch
vendored
@@ -8,7 +8,7 @@ index c1932555..552e432e 100644
|
|||||||
**/
|
**/
|
||||||
-void vibrate();
|
-void vibrate();
|
||||||
+void vibrate(const double seconds);
|
+void vibrate(const double seconds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable mix mode (e.g. with background music apps) and playback with a muted device.
|
* Enable mix mode (e.g. with background music apps) and playback with a muted device.
|
||||||
diff --git a/src/common/ios.mm b/src/common/ios.mm
|
diff --git a/src/common/ios.mm b/src/common/ios.mm
|
||||||
@@ -18,16 +18,16 @@ index 7730991e..4ba8e708 100644
|
|||||||
@@ -36,6 +36,8 @@
|
@@ -36,6 +36,8 @@
|
||||||
#include <SDL_video.h>
|
#include <SDL_video.h>
|
||||||
#include <SDL_syswm.h>
|
#include <SDL_syswm.h>
|
||||||
|
|
||||||
+#include <sys/utsname.h>
|
+#include <sys/utsname.h>
|
||||||
+
|
+
|
||||||
static NSArray *getLovesInDocuments();
|
static NSArray *getLovesInDocuments();
|
||||||
static bool deleteFileInDocuments(NSString *filename);
|
static bool deleteFileInDocuments(NSString *filename);
|
||||||
|
|
||||||
@@ -391,10 +393,40 @@ std::string getExecutablePath()
|
@@ -391,10 +393,40 @@ std::string getExecutablePath()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
-void vibrate()
|
-void vibrate()
|
||||||
+void vibrate(const double seconds)
|
+void vibrate(const double seconds)
|
||||||
{
|
{
|
||||||
@@ -73,7 +73,7 @@ index c8af8596..ae7a5e32 100644
|
|||||||
@@ -140,6 +140,10 @@ enum DoneAction
|
@@ -140,6 +140,10 @@ enum DoneAction
|
||||||
DONE_RESTART,
|
DONE_RESTART,
|
||||||
};
|
};
|
||||||
|
|
||||||
+extern "C" {
|
+extern "C" {
|
||||||
+ int luaopen_CCloader(lua_State *L);
|
+ int luaopen_CCloader(lua_State *L);
|
||||||
+}
|
+}
|
||||||
@@ -84,7 +84,7 @@ index c8af8596..ae7a5e32 100644
|
|||||||
@@ -158,6 +162,9 @@ static DoneAction runlove(int argc, char **argv, int &retval)
|
@@ -158,6 +162,9 @@ static DoneAction runlove(int argc, char **argv, int &retval)
|
||||||
lua_State *L = luaL_newstate();
|
lua_State *L = luaL_newstate();
|
||||||
luaL_openlibs(L);
|
luaL_openlibs(L);
|
||||||
|
|
||||||
+ // Init CCloader
|
+ // Init CCloader
|
||||||
+ luaopen_CCloader(L);
|
+ luaopen_CCloader(L);
|
||||||
+
|
+
|
||||||
|
|||||||
10
.github/build/linux/dev/template.desktop
vendored
@@ -1,10 +0,0 @@
|
|||||||
[Desktop Entry]
|
|
||||||
Name=Techmino Development
|
|
||||||
Comment=Techmino is fun!
|
|
||||||
MimeType=application/x-love-game;
|
|
||||||
Exec=app %f
|
|
||||||
Type=Application
|
|
||||||
Categories=Game;
|
|
||||||
Terminal=false
|
|
||||||
Icon=icon
|
|
||||||
NoDisplay=false
|
|
||||||
1
.github/build/linux/release/.gitattributes
vendored
@@ -1 +0,0 @@
|
|||||||
*.template text eol=lf
|
|
||||||
10
.github/build/linux/release/template.desktop
vendored
@@ -1,10 +0,0 @@
|
|||||||
[Desktop Entry]
|
|
||||||
Name=Techmino
|
|
||||||
Comment=Techmino is fun!
|
|
||||||
MimeType=application/x-love-game;
|
|
||||||
Exec=app %f
|
|
||||||
Type=Application
|
|
||||||
Categories=Game;
|
|
||||||
Terminal=false
|
|
||||||
Icon=icon
|
|
||||||
NoDisplay=false
|
|
||||||
BIN
.github/build/web/favicon.ico
vendored
Normal file
|
After Width: | Height: | Size: 305 KiB |
288
.github/build/web/game.js
vendored
Normal file
@@ -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}]});
|
||||||
|
|
||||||
|
})();
|
||||||
111
.github/build/web/index.html
vendored
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en-us">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, minimum-scale=1, maximum-scale=1">
|
||||||
|
<title>Techmino</title>
|
||||||
|
|
||||||
|
<!-- Load custom style sheet -->
|
||||||
|
<link rel="stylesheet" type="text/css" href="theme/love.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<center>
|
||||||
|
<div>
|
||||||
|
<h1>Techmino</h1>
|
||||||
|
<canvas id="loadingCanvas" oncontextmenu="event.preventDefault()" width="800" height="600"></canvas>
|
||||||
|
<canvas id="canvas" oncontextmenu="event.preventDefault()"></canvas>
|
||||||
|
</div>
|
||||||
|
</center>
|
||||||
|
|
||||||
|
<script type='text/javascript'>
|
||||||
|
function goFullScreen(){
|
||||||
|
var canvas = document.getElementById("canvas");
|
||||||
|
if(canvas.requestFullScreen)
|
||||||
|
canvas.requestFullScreen();
|
||||||
|
else if(canvas.webkitRequestFullScreen)
|
||||||
|
canvas.webkitRequestFullScreen();
|
||||||
|
else if(canvas.mozRequestFullScreen)
|
||||||
|
canvas.mozRequestFullScreen();
|
||||||
|
}
|
||||||
|
function FullScreenHook(){
|
||||||
|
var canvas = document.getElementById("canvas");
|
||||||
|
canvas.width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
|
||||||
|
canvas.height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
|
||||||
|
}
|
||||||
|
var loadingContext = document.getElementById('loadingCanvas').getContext('2d');
|
||||||
|
function drawLoadingText(text) {
|
||||||
|
var canvas = loadingContext.canvas;
|
||||||
|
|
||||||
|
loadingContext.fillStyle = "rgb(142, 195, 227)";
|
||||||
|
loadingContext.fillRect(0, 0, canvas.scrollWidth, canvas.scrollHeight);
|
||||||
|
|
||||||
|
loadingContext.font = '2em arial';
|
||||||
|
loadingContext.textAlign = 'center'
|
||||||
|
loadingContext.fillStyle = "rgb( 11, 86, 117 )";
|
||||||
|
loadingContext.fillText(text, canvas.scrollWidth / 2, canvas.scrollHeight / 2);
|
||||||
|
|
||||||
|
loadingContext.fillText("Powered By Emscripten.", canvas.scrollWidth / 2, canvas.scrollHeight / 4);
|
||||||
|
loadingContext.fillText("Powered By LÖVE.", canvas.scrollWidth / 2, canvas.scrollHeight / 4 * 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onload = function () { window.focus(); };
|
||||||
|
window.onclick = function () { window.focus(); };
|
||||||
|
|
||||||
|
window.addEventListener("keydown", function(e) {
|
||||||
|
// space and arrow keys
|
||||||
|
if([32, 37, 38, 39, 40].indexOf(e.keyCode) > -1) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
var Module = {
|
||||||
|
arguments: ["./game.love"],
|
||||||
|
INITIAL_MEMORY: 536870912,
|
||||||
|
printErr: console.error.bind(console),
|
||||||
|
canvas: (function() {
|
||||||
|
var canvas = document.getElementById('canvas');
|
||||||
|
|
||||||
|
// As a default initial behavior, pop up an alert when webgl context is lost. To make your
|
||||||
|
// application robust, you may want to override this behavior before shipping!
|
||||||
|
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
|
||||||
|
canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
|
||||||
|
|
||||||
|
return canvas;
|
||||||
|
})(),
|
||||||
|
setStatus: function(text) {
|
||||||
|
if (text) {
|
||||||
|
drawLoadingText(text);
|
||||||
|
} else if (Module.remainingDependencies === 0) {
|
||||||
|
document.getElementById('loadingCanvas').style.display = 'none';
|
||||||
|
document.getElementById('canvas').style.visibility = 'visible';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
totalDependencies: 0,
|
||||||
|
remainingDependencies: 0,
|
||||||
|
monitorRunDependencies: function(left) {
|
||||||
|
this.remainingDependencies = left;
|
||||||
|
this.totalDependencies = Math.max(this.totalDependencies, left);
|
||||||
|
Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Module.setStatus('Downloading...');
|
||||||
|
window.onerror = function(event) {
|
||||||
|
// TODO: do not warn on ok events like simulating an infinite loop or exitStatus
|
||||||
|
Module.setStatus('Exception thrown, see JavaScript console');
|
||||||
|
Module.setStatus = function(text) {
|
||||||
|
if (text) Module.printErr('[post-exception status] ' + text);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var applicationLoad = function(e) {
|
||||||
|
Love(Module);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script type="text/javascript" src="game.js"></script>
|
||||||
|
<script async type="text/javascript" src="love.js" onload="applicationLoad(this)"></script>
|
||||||
|
<footer>
|
||||||
|
<p>Built with <a href="https://github.com/Davidobot/love.js">love.js</a> <button onclick="goFullScreen();">Go Fullscreen</button><br>Hint: Reload the page if screen is blank</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
22
.github/build/web/love.js
vendored
Normal file
BIN
.github/build/web/love.wasm
vendored
Normal file
BIN
.github/build/web/theme/bg.png
vendored
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
49
.github/build/web/theme/love.css
vendored
Normal file
@@ -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;
|
||||||
|
}
|
||||||
7
.github/build/windows/dev/template.rc
vendored
@@ -8,9 +8,12 @@ FILETYPE 0x1
|
|||||||
{
|
{
|
||||||
BLOCK "040904B0"
|
BLOCK "040904B0"
|
||||||
{
|
{
|
||||||
VALUE "FileDescription", "Techmino Development"
|
|
||||||
VALUE "CompanyName", "26F Studio"
|
VALUE "CompanyName", "26F Studio"
|
||||||
VALUE "LegalCopyright", "Copyright @ 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 "ProductName", "Techmino"
|
||||||
VALUE "ProductVersion", "@Version"
|
VALUE "ProductVersion", "@Version"
|
||||||
}
|
}
|
||||||
|
|||||||
7
.github/build/windows/release/template.rc
vendored
@@ -8,9 +8,12 @@ FILETYPE 0x1
|
|||||||
{
|
{
|
||||||
BLOCK "040904B0"
|
BLOCK "040904B0"
|
||||||
{
|
{
|
||||||
VALUE "FileDescription", "Techmino"
|
|
||||||
VALUE "CompanyName", "26F Studio"
|
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 "ProductName", "Techmino"
|
||||||
VALUE "ProductVersion", "@Version"
|
VALUE "ProductVersion", "@Version"
|
||||||
}
|
}
|
||||||
|
|||||||
393
.github/workflows/main.yml
vendored
@@ -39,7 +39,9 @@ jobs:
|
|||||||
os.execute('echo "version-string=' .. version.string:gsub("%a", "") .. '" >> $GITHUB_OUTPUT')
|
os.execute('echo "version-string=' .. version.string:gsub("%a", "") .. '" >> $GITHUB_OUTPUT')
|
||||||
os.execute('echo "version-code=' .. tostring(version.code) .. '" >> $GITHUB_OUTPUT')
|
os.execute('echo "version-code=' .. tostring(version.code) .. '" >> $GITHUB_OUTPUT')
|
||||||
|
|
||||||
local note = require 'parts.updateLog'
|
local f = io.open("updateLog.txt", 'r')
|
||||||
|
local note = f:read("*a")
|
||||||
|
f:close()
|
||||||
local p1 = note:find("\n%d") + 1
|
local p1 = note:find("\n%d") + 1
|
||||||
local p2 = note:find("\n", p1) - 1
|
local p2 = note:find("\n", p1) - 1
|
||||||
os.execute('echo "update-title=' .. note:sub(p1, p2) .. '" >> $GITHUB_OUTPUT')
|
os.execute('echo "update-title=' .. note:sub(p1, p2) .. '" >> $GITHUB_OUTPUT')
|
||||||
@@ -70,8 +72,6 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
OUTPUT_FOLDER: ./build
|
OUTPUT_FOLDER: ./build
|
||||||
RELEASE_FOLDER: ./release
|
RELEASE_FOLDER: ./release
|
||||||
outputs:
|
|
||||||
download-url: ${{ steps.transfer.outputs.download-url }}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
@@ -92,13 +92,18 @@ jobs:
|
|||||||
- name: Build core love package
|
- name: Build core love package
|
||||||
uses: love-actions/love-actions-core@v1
|
uses: love-actions/love-actions-core@v1
|
||||||
with:
|
with:
|
||||||
build-list: ./media/ ./parts/ ./Zframework/ ./conf.lua ./main.lua ./version.lua
|
build-list: ./media/ ./parts/ ./Zframework/ ./conf.lua ./main.lua ./version.lua ./legals.md ./license.txt
|
||||||
package-path: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
package-path: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
||||||
- name: Upload core love package
|
- name: Upload core love package
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
||||||
path: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
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
|
- name: Rename love package
|
||||||
run: |
|
run: |
|
||||||
mkdir -p ${{ env.OUTPUT_FOLDER }}
|
mkdir -p ${{ env.OUTPUT_FOLDER }}
|
||||||
@@ -123,12 +128,6 @@ jobs:
|
|||||||
body: ${{ needs.get-info.outputs.update-note }}
|
body: ${{ needs.get-info.outputs.update-note }}
|
||||||
name: ${{ needs.get-info.outputs.update-title }}
|
name: ${{ needs.get-info.outputs.update-title }}
|
||||||
prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
|
prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
|
||||||
- name: Upload to WeTransfer
|
|
||||||
id: transfer
|
|
||||||
run: |
|
|
||||||
curl -sL https://git.io/file-transfer | sh
|
|
||||||
./transfer wet -s -p 16 --no-progress ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.love 2>&1>./wetransfer.log
|
|
||||||
echo "download-url=$(cat ./wetransfer.log | grep https | cut -f3 -d" ")" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
auto-test:
|
auto-test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -146,11 +145,10 @@ jobs:
|
|||||||
build-android:
|
build-android:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [get-info, build-core, auto-test]
|
needs: [get-info, build-core, auto-test]
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
env:
|
env:
|
||||||
OUTPUT_FOLDER: ./build
|
OUTPUT_FOLDER: ./build
|
||||||
RELEASE_FOLDER: ./release
|
RELEASE_FOLDER: ./release
|
||||||
outputs:
|
|
||||||
download-url: ${{ steps.transfer.outputs.download-url }}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
@@ -162,12 +160,12 @@ jobs:
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
with open(os.getenv('GITHUB_OUTPUT'), 'a') as f:
|
with open(os.getenv('GITHUB_OUTPUT'), 'a') as f:
|
||||||
if "${{ env.BUILD_TYPE }}" == "dev":
|
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('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')
|
f.write('product-name=' + re.sub(r'[^A-Za-z0-9]+', '-', '${{ needs.get-info.outputs.app-name }}') + '_Snapshot\n')
|
||||||
else:
|
else:
|
||||||
f.write('bundle-id=org.f26_studio.' + re.sub(r'[^A-Za-z0-9]+', '_', '${{ needs.get-info.outputs.app-name }}') + '\n')
|
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')
|
f.write('product-name=' + re.sub(r'[^A-Za-z0-9]+', '-', '${{ needs.get-info.outputs.app-name }}') + '\n')
|
||||||
- name: Download core love package
|
- name: Download core love package
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
@@ -176,17 +174,10 @@ jobs:
|
|||||||
uses: ./.github/actions/get-cc
|
uses: ./.github/actions/get-cc
|
||||||
with:
|
with:
|
||||||
platform: Android
|
platform: Android
|
||||||
dir: ./ColdClear
|
dir: ./libAndroid
|
||||||
- name: Process ColdClear
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
mkdir -p ./libAndroid/armeabi-v7a/
|
|
||||||
mkdir -p ./libAndroid/arm64-v8a/
|
|
||||||
mv ./ColdClear/armeabi-v7a/libCCloader.so ./libAndroid/armeabi-v7a/
|
|
||||||
mv ./ColdClear/arm64-v8a/libCCloader.so ./libAndroid/arm64-v8a/
|
|
||||||
- name: Build Android packages
|
- name: Build Android packages
|
||||||
id: build-packages
|
id: build-packages
|
||||||
uses: love-actions/love-actions-android@v1
|
uses: love-actions/love-actions-android@main
|
||||||
with:
|
with:
|
||||||
app-name: ${{ needs.get-info.outputs.app-name }}
|
app-name: ${{ needs.get-info.outputs.app-name }}
|
||||||
bundle-id: ${{ steps.process-app-name.outputs.bundle-id }}
|
bundle-id: ${{ steps.process-app-name.outputs.bundle-id }}
|
||||||
@@ -197,8 +188,8 @@ jobs:
|
|||||||
keystore-store-password: ${{ secrets.ANDROID_KEYSTORE_STOREPASSWORD }}
|
keystore-store-password: ${{ secrets.ANDROID_KEYSTORE_STOREPASSWORD }}
|
||||||
love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
||||||
resource-path: ./.github/build/android/${{ env.BUILD_TYPE }}/res
|
resource-path: ./.github/build/android/${{ env.BUILD_TYPE }}/res
|
||||||
libs-path: ./ColdClear/
|
|
||||||
extra-assets: ./libAndroid/
|
extra-assets: ./libAndroid/
|
||||||
|
custom-scheme: studio26f://oauth
|
||||||
product-name: ${{ steps.process-app-name.outputs.product-name }}
|
product-name: ${{ steps.process-app-name.outputs.product-name }}
|
||||||
version-string: ${{ needs.get-info.outputs.version-string }}
|
version-string: ${{ needs.get-info.outputs.version-string }}
|
||||||
version-code: ${{ needs.get-info.outputs.version-code }}
|
version-code: ${{ needs.get-info.outputs.version-code }}
|
||||||
@@ -223,101 +214,6 @@ jobs:
|
|||||||
body: ${{ needs.get-info.outputs.update-note }}
|
body: ${{ needs.get-info.outputs.update-note }}
|
||||||
name: ${{ needs.get-info.outputs.update-title }}
|
name: ${{ needs.get-info.outputs.update-title }}
|
||||||
prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
|
prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
|
||||||
- name: Upload to WeTransfer
|
|
||||||
id: transfer
|
|
||||||
run: |
|
|
||||||
curl -sL https://git.io/file-transfer | sh
|
|
||||||
./transfer wet -s -p 16 --no-progress ${{ steps.build-packages.outputs.package-paths }} 2>&1>./wetransfer.log
|
|
||||||
echo "download-url=$(cat ./wetransfer.log | grep https | cut -f3 -d" ")" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
build-ios:
|
|
||||||
runs-on: macos-latest
|
|
||||||
if: github.event_name != 'pull_request'
|
|
||||||
needs: [get-info, build-core, auto-test]
|
|
||||||
env:
|
|
||||||
OUTPUT_FOLDER: ./build
|
|
||||||
RELEASE_FOLDER: ./release
|
|
||||||
outputs:
|
|
||||||
download-url: ${{ steps.transfer.outputs.download-url }}
|
|
||||||
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-2022 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') }}
|
|
||||||
- name: Upload to WeTransfer
|
|
||||||
id: transfer
|
|
||||||
run: |
|
|
||||||
wget -qO- https://github.com/Mikubill/transfer/releases/download/v0.4.17/transfer_0.4.17_darwin_amd64.tar.gz | tar xvz
|
|
||||||
./transfer wet -s -p 16 --no-progress ${{ steps.build-packages.outputs.package-paths }} 2>&1>./wetransfer.log
|
|
||||||
echo "download-url=$(cat ./wetransfer.log | grep https | cut -f3 -d" ")" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
build-linux:
|
build-linux:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -325,8 +221,6 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
OUTPUT_FOLDER: ./build
|
OUTPUT_FOLDER: ./build
|
||||||
RELEASE_FOLDER: ./release
|
RELEASE_FOLDER: ./release
|
||||||
outputs:
|
|
||||||
download-url: ${{ steps.transfer.outputs.download-url }}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
@@ -337,12 +231,20 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
import os
|
import os
|
||||||
import re
|
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:
|
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')
|
f.write('bundle-id=org.26f-studio.' + product_name + '\n')
|
||||||
|
f.write('product-name=' + product_name + '\n')
|
||||||
- name: Download core love package
|
- name: Download core love package
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
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
|
- name: Download ColdClear
|
||||||
uses: ./.github/actions/get-cc
|
uses: ./.github/actions/get-cc
|
||||||
with:
|
with:
|
||||||
@@ -352,20 +254,19 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
cd ./ColdClear
|
cd ./ColdClear
|
||||||
mkdir ./libs
|
mkdir -p ./lib/lua/5.1
|
||||||
mv ./x64/libcold_clear.so ./libs
|
mv ./x64/CCloader.so ./lib/lua/5.1
|
||||||
mkdir ./shared
|
|
||||||
mv ./x64/CCloader.so ./shared
|
|
||||||
- name: Build Linux packages
|
- name: Build Linux packages
|
||||||
id: build-packages
|
id: build-packages
|
||||||
uses: love-actions/love-actions-linux@v1
|
uses: love-actions/love-actions-linux@v1
|
||||||
with:
|
with:
|
||||||
desktop-file-path: ./.github/build/linux/${{ env.BUILD_TYPE }}/template.desktop
|
app-name: ${{ needs.get-info.outputs.app-name }}
|
||||||
executable-name: app
|
bundle-id: ${{ steps.process-app-name.outputs.bundle-id }}
|
||||||
|
description: Techmino is fun!
|
||||||
|
version-string: ${{ needs.get-info.outputs.version-string }}
|
||||||
icon-path: ./.github/build/linux/${{ env.BUILD_TYPE }}/icon.png
|
icon-path: ./.github/build/linux/${{ env.BUILD_TYPE }}/icon.png
|
||||||
love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
||||||
libs-path: ./ColdClear/libs/
|
lib-path: ./ColdClear/lib
|
||||||
shared-path: ./ColdClear/shared/
|
|
||||||
product-name: ${{ steps.process-app-name.outputs.product-name }}
|
product-name: ${{ steps.process-app-name.outputs.product-name }}
|
||||||
output-folder: ${{ env.OUTPUT_FOLDER }}
|
output-folder: ${{ env.OUTPUT_FOLDER }}
|
||||||
- name: Upload AppImage artifact
|
- name: Upload AppImage artifact
|
||||||
@@ -373,129 +274,37 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: ${{ needs.get-info.outputs.base-name }}_Linux_AppImage
|
name: ${{ needs.get-info.outputs.base-name }}_Linux_AppImage
|
||||||
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}.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
|
- name: Prepare for release
|
||||||
if: ${{ startsWith(github.ref, 'refs/tags/pre') || startsWith(github.ref, 'refs/tags/v') }}
|
if: ${{ startsWith(github.ref, 'refs/tags/pre') || startsWith(github.ref, 'refs/tags/v') }}
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
mkdir -p ${{ env.RELEASE_FOLDER }}
|
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 }}.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
|
- name: Upload release
|
||||||
if: ${{ startsWith(github.ref, 'refs/tags/pre') || startsWith(github.ref, 'refs/tags/v') }}
|
if: ${{ startsWith(github.ref, 'refs/tags/pre') || startsWith(github.ref, 'refs/tags/v') }}
|
||||||
uses: ncipollo/release-action@v1
|
uses: ncipollo/release-action@v1
|
||||||
with:
|
with:
|
||||||
allowUpdates: true
|
allowUpdates: true
|
||||||
artifacts: ${{ env.RELEASE_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_Linux.AppImage
|
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 }}
|
body: ${{ needs.get-info.outputs.update-note }}
|
||||||
name: ${{ needs.get-info.outputs.update-title }}
|
name: ${{ needs.get-info.outputs.update-title }}
|
||||||
prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
|
prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
|
||||||
- name: Upload to WeTransfer
|
|
||||||
id: transfer
|
|
||||||
run: |
|
|
||||||
curl -sL https://git.io/file-transfer | sh
|
|
||||||
./transfer wet -s -p 16 --no-progress ${{ steps.build-packages.outputs.package-paths }} 2>&1>./wetransfer.log
|
|
||||||
echo "download-url=$(cat ./wetransfer.log | grep https | cut -f3 -d" ")" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
build-macos-appstore:
|
|
||||||
runs-on: macos-latest
|
|
||||||
if: github.event_name != 'pull_request'
|
|
||||||
needs: [get-info, build-core, auto-test]
|
|
||||||
env:
|
|
||||||
OUTPUT_FOLDER: ./build
|
|
||||||
RELEASE_FOLDER: ./release
|
|
||||||
outputs:
|
|
||||||
download-url: ${{ steps.transfer.outputs.download-url }}
|
|
||||||
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-2022 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') }}
|
|
||||||
- name: Upload to WeTransfer
|
|
||||||
id: transfer
|
|
||||||
run: |
|
|
||||||
wget -qO- https://github.com/Mikubill/transfer/releases/download/v0.4.17/transfer_0.4.17_darwin_amd64.tar.gz | tar xvz
|
|
||||||
./transfer wet -s -p 16 --no-progress ${{ steps.build-packages.outputs.package-paths }} 2>&1>./wetransfer.log
|
|
||||||
echo "download-url=$(cat ./wetransfer.log | grep https | cut -f3 -d" ")" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
build-macos-portable:
|
build-macos-portable:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
if: github.event_name != 'pull_request'
|
|
||||||
needs: [get-info, build-core, auto-test]
|
needs: [get-info, build-core, auto-test]
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
env:
|
env:
|
||||||
OUTPUT_FOLDER: ./build
|
OUTPUT_FOLDER: ./build
|
||||||
RELEASE_FOLDER: ./release
|
RELEASE_FOLDER: ./release
|
||||||
outputs:
|
|
||||||
download-url: ${{ steps.transfer.outputs.download-url }}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
@@ -528,7 +337,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
app-name: ${{ needs.get-info.outputs.app-name }}
|
app-name: ${{ needs.get-info.outputs.app-name }}
|
||||||
bundle-id: ${{ steps.process-app-name.outputs.bundle-id }}
|
bundle-id: ${{ steps.process-app-name.outputs.bundle-id }}
|
||||||
copyright: "Copyright © 2019-2022 26F-Studio. Some Rights Reserved."
|
copyright: "Copyright © 2019-2023 26F-Studio. Some Rights Reserved."
|
||||||
icon-path: ./.github/build/macOS/${{ env.BUILD_TYPE }}/icon.icns
|
icon-path: ./.github/build/macOS/${{ env.BUILD_TYPE }}/icon.icns
|
||||||
love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
||||||
libs-path: ./ColdClear/universal/
|
libs-path: ./ColdClear/universal/
|
||||||
@@ -578,16 +387,40 @@ jobs:
|
|||||||
uses: ncipollo/release-action@v1
|
uses: ncipollo/release-action@v1
|
||||||
with:
|
with:
|
||||||
allowUpdates: true
|
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
|
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 }}
|
body: ${{ needs.get-info.outputs.update-note }}
|
||||||
name: ${{ needs.get-info.outputs.update-title }}
|
name: ${{ needs.get-info.outputs.update-title }}
|
||||||
prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
|
prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
|
||||||
- name: Upload to WeTransfer
|
|
||||||
id: transfer
|
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: |
|
run: |
|
||||||
wget -qO- https://github.com/Mikubill/transfer/releases/download/v0.4.17/transfer_0.4.17_darwin_amd64.tar.gz | tar xvz
|
mv ${{ env.CORE_LOVE_PACKAGE_PATH }} ./.github/build/web/game.data
|
||||||
./transfer wet -s -p 16 --no-progress ${{ steps.build-packages.outputs.package-paths }} 2>&1>./wetransfer.log
|
- name: Deploy to GitHub Pages
|
||||||
echo "download-url=$(cat ./wetransfer.log | grep https | cut -f3 -d" ")" >> $GITHUB_OUTPUT
|
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:
|
build-windows:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
@@ -595,8 +428,6 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
OUTPUT_FOLDER: ./build
|
OUTPUT_FOLDER: ./build
|
||||||
RELEASE_FOLDER: ./release
|
RELEASE_FOLDER: ./release
|
||||||
outputs:
|
|
||||||
download-url: ${{ steps.transfer.outputs.download-url }}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
@@ -618,6 +449,19 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
platform: Windows
|
platform: Windows
|
||||||
dir: ./ColdClear
|
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
|
- name: Build Windows packages
|
||||||
id: build-packages
|
id: build-packages
|
||||||
uses: love-actions/love-actions-windows@v1
|
uses: love-actions/love-actions-windows@v1
|
||||||
@@ -628,7 +472,9 @@ jobs:
|
|||||||
extra-assets-x86: ./ColdClear/x86/CCloader.dll ./ColdClear/x86/cold_clear.dll
|
extra-assets-x86: ./ColdClear/x86/CCloader.dll ./ColdClear/x86/cold_clear.dll
|
||||||
extra-assets-x64: ./ColdClear/x64/CCloader.dll ./ColdClear/x64/cold_clear.dll
|
extra-assets-x64: ./ColdClear/x64/CCloader.dll ./ColdClear/x64/cold_clear.dll
|
||||||
product-name: ${{ steps.process-app-name.outputs.product-name }}
|
product-name: ${{ steps.process-app-name.outputs.product-name }}
|
||||||
version-string: ${{ needs.get-info.outputs.version-string }}
|
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 }}
|
output-folder: ${{ env.OUTPUT_FOLDER }}
|
||||||
- name: Upload 32-bit artifact
|
- name: Upload 32-bit artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
@@ -640,6 +486,11 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: ${{ needs.get-info.outputs.base-name }}_Windows_x64
|
name: ${{ needs.get-info.outputs.base-name }}_Windows_x64
|
||||||
path: ${{ env.OUTPUT_FOLDER }}/${{ steps.process-app-name.outputs.product-name }}_x64.zip
|
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
|
- name: Prepare for release
|
||||||
if: ${{ startsWith(github.ref, 'refs/tags/pre') || startsWith(github.ref, 'refs/tags/v') }}
|
if: ${{ startsWith(github.ref, 'refs/tags/pre') || startsWith(github.ref, 'refs/tags/v') }}
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -647,29 +498,19 @@ jobs:
|
|||||||
mkdir -p ${{ env.RELEASE_FOLDER }}
|
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 }}_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 }}_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
|
- name: Upload release
|
||||||
if: ${{ startsWith(github.ref, 'refs/tags/pre') || startsWith(github.ref, 'refs/tags/v') }}
|
if: ${{ startsWith(github.ref, 'refs/tags/pre') || startsWith(github.ref, 'refs/tags/v') }}
|
||||||
uses: ncipollo/release-action@v1
|
uses: ncipollo/release-action@v1
|
||||||
with:
|
with:
|
||||||
allowUpdates: true
|
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
|
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 }}
|
body: ${{ needs.get-info.outputs.update-note }}
|
||||||
name: ${{ needs.get-info.outputs.update-title }}
|
name: ${{ needs.get-info.outputs.update-title }}
|
||||||
prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
|
prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
|
||||||
- name: Get transfer
|
|
||||||
env:
|
|
||||||
TEMP_PATH: ./temp.zip
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
curl -L --retry 5 https://github.com/Mikubill/transfer/releases/download/v0.4.17/transfer_0.4.17_windows_amd64.zip -o ${{ env.TEMP_PATH }}
|
|
||||||
7z x ${{ env.TEMP_PATH }} -o./
|
|
||||||
rm ${{ env.TEMP_PATH }}
|
|
||||||
- name: Upload to WeTransfer
|
|
||||||
id: transfer
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
./transfer.exe wet -s -p 16 --no-progress ${{ steps.build-packages.outputs.package-paths }} 2>&1>./wetransfer.log
|
|
||||||
"download-url=$(cat ./wetransfer.log | grep https | cut -f3 -d" ")" >> $env:GITHUB_OUTPUT
|
|
||||||
|
|
||||||
post-build:
|
post-build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -680,48 +521,21 @@ jobs:
|
|||||||
auto-test,
|
auto-test,
|
||||||
build-core,
|
build-core,
|
||||||
build-android,
|
build-android,
|
||||||
build-ios,
|
|
||||||
build-linux,
|
build-linux,
|
||||||
build-macos-appstore,
|
|
||||||
build-macos-portable,
|
build-macos-portable,
|
||||||
|
build-web,
|
||||||
build-windows,
|
build-windows,
|
||||||
]
|
]
|
||||||
env:
|
env:
|
||||||
ACTION_TYPE: ${{ fromJSON('[["Development", "Pre-release"], ["Release", "Release"]]')[startsWith(github.ref, 'refs/tags/v')][startsWith(github.ref, 'refs/tags/pre')] }}
|
ACTION_TYPE: ${{ fromJSON('[["Development", "Pre-release"], ["Release", "Release"]]')[startsWith(github.ref, 'refs/tags/v')][startsWith(github.ref, 'refs/tags/pre')] }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Cleanup
|
- name: Cleanup
|
||||||
uses: geekyeggo/delete-artifact@v2
|
uses: geekyeggo/delete-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
||||||
- name: Display summary
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "# Summary" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "## Version: ${{ needs.get-info.outputs.version-string }}" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "## Package Name: ${{ needs.get-info.outputs.base-name }}" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "## Download links: " >> $GITHUB_STEP_SUMMARY
|
|
||||||
- name: Display download links
|
|
||||||
shell: python3 {0}
|
|
||||||
run: |
|
|
||||||
import os
|
|
||||||
with open(os.getenv('GITHUB_STEP_SUMMARY'), 'a') as f:
|
|
||||||
if "${{ needs.build-core.result }}" == "success":
|
|
||||||
f.write("- Bare love packages: [WeTransfer](${{ needs.build-core.outputs.download-url }})\n")
|
|
||||||
if "${{ needs.build-android.result }}" == "success":
|
|
||||||
f.write("- Android packages: [WeTransfer](${{ needs.build-android.outputs.download-url }})\n")
|
|
||||||
if "${{ needs.build-ios.result }}" == "success":
|
|
||||||
f.write("- iOS packages: [WeTransfer](${{ needs.build-ios.outputs.download-url }})\n")
|
|
||||||
if "${{ needs.build-linux.result }}" == "success":
|
|
||||||
f.write("- Linux packages: [WeTransfer](${{ needs.build-linux.outputs.download-url }})\n")
|
|
||||||
if "${{ needs.build-macos-appstore.result }}" == "success":
|
|
||||||
f.write("- macOS packages(App Store version): [WeTransfer](${{ needs.build-macos-appstore.outputs.download-url }})\n")
|
|
||||||
if "${{ needs.build-macos-portable.result }}" == "success":
|
|
||||||
f.write("- macOS packages(Portable version): [WeTransfer](${{ needs.build-macos-portable.outputs.download-url }})\n")
|
|
||||||
if "${{ needs.build-windows.result }}" == "success":
|
|
||||||
f.write("- Windows packages: [WeTransfer](${{ needs.build-windows.outputs.download-url }})\n")
|
|
||||||
- name: Send Discord message
|
- name: Send Discord message
|
||||||
uses: Sniddl/discord-commits@v1.5
|
if: github.event_name != 'pull_request'
|
||||||
|
uses: Sniddl/discord-commits@v1.6
|
||||||
with:
|
with:
|
||||||
webhook: ${{ secrets.DISCORD_WEBHOOK }}
|
webhook: ${{ secrets.DISCORD_WEBHOOK }}
|
||||||
message: "Github Actions for **${{ github.repository }}**."
|
message: "Github Actions for **${{ github.repository }}**."
|
||||||
@@ -740,7 +554,6 @@ jobs:
|
|||||||
"fields":[
|
"fields":[
|
||||||
{"name":"Version","value":"${{ needs.get-info.outputs.version-string }}","inline": true},
|
{"name":"Version","value":"${{ needs.get-info.outputs.version-string }}","inline": true},
|
||||||
{"name":"Package Name","value":"${{ needs.get-info.outputs.base-name }}","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 }}"},
|
{"name":"Status","value":"**Automatic Test:** ${{ needs.auto-test.result }}\n**Core:** ${{ needs.build-core.result }}\n**Android:** ${{ needs.build-android.result }}\n**Linux:** ${{ needs.build-linux.result }}\n**macOS portable:** ${{ needs.build-macos-portable.result }}\n**Windows:** ${{ needs.build-windows.result }}"}
|
||||||
{"name":"Download Links","value":"**Core:** ${{ needs.build-core.outputs.download-url}}\n**Android:** ${{ needs.build-android.outputs.download-url }}\n**iOS:** ${{ needs.build-ios.outputs.download-url }}\n**Linux:** ${{ needs.build-linux.outputs.download-url }}\n**macOS App Store:** ${{ needs.build-macos-appstore.outputs.download-url }}\n**macOS portable:** ${{ needs.build-macos-portable.outputs.download-url }}\n**Windows:** ${{ needs.build-windows.outputs.download-url}}"}
|
|
||||||
]
|
]
|
||||||
}'
|
}'
|
||||||
|
|||||||
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
|||||||
[submodule "Zframework"]
|
|
||||||
path = Zframework
|
|
||||||
url = https://github.com/26F-Studio/Zframework.git
|
|
||||||
57
Zframework/background.lua
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
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()
|
||||||
|
if ... then BG.send(...) end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return BG
|
||||||
350
Zframework/bgm.lua
Normal file
@@ -0,0 +1,350 @@
|
|||||||
|
local audio=love.audio
|
||||||
|
local effectsSupported=audio.isEffectsSupported()
|
||||||
|
|
||||||
|
local nameList={}
|
||||||
|
local srcLib={}-- Stored bgm objects: {name='foo', source=bar, ...}, more info at function _addFile()
|
||||||
|
local lastLoadNames={}
|
||||||
|
local nowPlay={}
|
||||||
|
local lastPlay=NONE-- Directly stored last played bgm name(s)
|
||||||
|
|
||||||
|
local defaultBGM=false
|
||||||
|
local maxLoadedCount=3
|
||||||
|
local volume=1
|
||||||
|
|
||||||
|
local function task_setVolume(obj,ve,time,stop)
|
||||||
|
local vs=obj.vol
|
||||||
|
local t=0
|
||||||
|
while true do
|
||||||
|
t=time~=0 and math.min(t+coroutine.yield()/time,1) or 1
|
||||||
|
local v=MATH.mix(vs,ve,t)
|
||||||
|
obj.vol=v
|
||||||
|
obj.source:setVolume(v*volume)
|
||||||
|
if t==1 then
|
||||||
|
obj.volChanging=false
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if stop then
|
||||||
|
obj.source:stop()
|
||||||
|
end
|
||||||
|
obj.volChanging=false
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
local function task_setPitch(obj,pe,time)
|
||||||
|
local ps=obj.pitch
|
||||||
|
local t=0
|
||||||
|
while true do
|
||||||
|
t=time~=0 and math.min(t+coroutine.yield()/time,1) or 1
|
||||||
|
local p=MATH.mix(ps,pe,t)
|
||||||
|
obj.pitch=p
|
||||||
|
obj.source:setPitch(p)
|
||||||
|
if t==1 then
|
||||||
|
obj.pitchChanging=false
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local function task_setLowgain(obj,pe,time)
|
||||||
|
local ps=obj.lowgain
|
||||||
|
local t=0
|
||||||
|
while true do
|
||||||
|
t=time~=0 and math.min(t+coroutine.yield()/time,1) or 1
|
||||||
|
local p=MATH.mix(ps,pe,t)
|
||||||
|
obj.lowgain=p
|
||||||
|
obj.source:setFilter{type='bandpass',lowgain=obj.lowgain^9.42,highgain=obj.highgain^9.42,volume=1}
|
||||||
|
if t==1 then
|
||||||
|
obj.lowgainChanging=false
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local function task_setHighgain(obj,pe,time)
|
||||||
|
local ps=obj.highgain
|
||||||
|
local t=0
|
||||||
|
while true do
|
||||||
|
t=time~=0 and math.min(t+coroutine.yield()/time,1) or 1
|
||||||
|
local p=MATH.mix(ps,pe,t)
|
||||||
|
obj.highgain=p
|
||||||
|
obj.source:setFilter{type='bandpass',lowgain=obj.lowgain^9.42,highgain=obj.highgain^9.42,volume=1}
|
||||||
|
if t==1 then
|
||||||
|
obj.highgainChanging=false
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local function _clearTask(obj,mode)
|
||||||
|
local taskFunc=
|
||||||
|
mode=='volume' and task_setVolume or
|
||||||
|
mode=='pitch' and task_setPitch or
|
||||||
|
mode=='lowgain' and task_setLowgain or
|
||||||
|
mode=='highgain' and task_setHighgain or
|
||||||
|
'any'
|
||||||
|
TASK.removeTask_iterate(function(task)
|
||||||
|
return task.args[1]==obj and (taskFunc=='any' or task.code==taskFunc)
|
||||||
|
end,obj)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function _updateSources()
|
||||||
|
local n=#lastLoadNames
|
||||||
|
while #lastLoadNames>maxLoadedCount and n>0 do
|
||||||
|
local name=lastLoadNames[n]
|
||||||
|
if srcLib[name].source and not srcLib[name].source:isPlaying() then
|
||||||
|
srcLib[name].source=srcLib[name].source:release() and nil
|
||||||
|
_clearTask(srcLib[name],'any')
|
||||||
|
end
|
||||||
|
n=n-1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local function _addFile(name,path)
|
||||||
|
if not srcLib[name] then
|
||||||
|
table.insert(nameList,name)
|
||||||
|
srcLib[name]={
|
||||||
|
name=name,path=path,source=false,
|
||||||
|
vol=0,volChanging=false,
|
||||||
|
pitch=1,pitchChanging=false,
|
||||||
|
lowgain=1,lowgainChanging=false,
|
||||||
|
highgain=1,highgainChanging=false,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local function _tryLoad(name)
|
||||||
|
if srcLib[name] then
|
||||||
|
local obj=srcLib[name]
|
||||||
|
if obj.source then
|
||||||
|
return true
|
||||||
|
elseif love.filesystem.getInfo(obj.path) then
|
||||||
|
obj.source=audio.newSource(obj.path,'stream')
|
||||||
|
obj.source:setLooping(true)
|
||||||
|
table.insert(lastLoadNames,1,name)
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
LOG(STRING.repD("Wrong path for BGM '$1': $2",obj.name,obj.path),5)
|
||||||
|
end
|
||||||
|
elseif name then
|
||||||
|
LOG("No BGM: "..name,5)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local BGM={}
|
||||||
|
|
||||||
|
function BGM.getList() return nameList end
|
||||||
|
function BGM.getCount() return #nameList end
|
||||||
|
|
||||||
|
function BGM.setDefault(bgms)
|
||||||
|
if type(bgms)=='string' then
|
||||||
|
bgms={bgms}
|
||||||
|
elseif type(bgms)=='table' then
|
||||||
|
for i=1,#bgms do assert(type(bgms[i])=='string',"BGM list must be list of strings") end
|
||||||
|
else
|
||||||
|
error("BGM.setDefault(bgms): bgms must be string or table")
|
||||||
|
end
|
||||||
|
defaultBGM=bgms
|
||||||
|
end
|
||||||
|
function BGM.setMaxSources(count)
|
||||||
|
assert(type(count)=='number' and count>0 and count%1==0,"BGM.setMaxSources(count): count must be positive integer")
|
||||||
|
maxLoadedCount=count
|
||||||
|
_updateSources()
|
||||||
|
end
|
||||||
|
function BGM.setVol(vol)
|
||||||
|
assert(type(vol)=='number' and vol>=0 and vol<=1,"BGM.setVol(vol): count must be in range 0~1")
|
||||||
|
volume=vol
|
||||||
|
for i=1,#nowPlay do
|
||||||
|
local bgm=nowPlay[i]
|
||||||
|
if not bgm.volChanging then
|
||||||
|
bgm.source:setVolume(bgm.vol*vol)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function BGM.init(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.play(bgms,args)
|
||||||
|
if not args then args='' end
|
||||||
|
if not bgms then bgms=defaultBGM end
|
||||||
|
if not bgms then return end
|
||||||
|
|
||||||
|
if type(bgms)=='string' then bgms={bgms} end
|
||||||
|
assert(type(bgms)=='table',"BGM.play(name,args): name must be string or table")
|
||||||
|
|
||||||
|
if
|
||||||
|
TABLE.compare(lastPlay,bgms) and
|
||||||
|
srcLib[lastPlay[1]] and srcLib[lastPlay[1]].source and
|
||||||
|
srcLib[lastPlay[1]].source:isPlaying()
|
||||||
|
then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
BGM.stop()
|
||||||
|
|
||||||
|
if not STRING.sArg(args,'-preLoad') then
|
||||||
|
lastPlay=bgms
|
||||||
|
end
|
||||||
|
|
||||||
|
for i=1,#bgms do
|
||||||
|
local bgm=bgms[i]
|
||||||
|
assert(type(bgm)=='string',"BGM list can only be list of string")
|
||||||
|
if _tryLoad(bgm) and not STRING.sArg(args,'-preLoad') then
|
||||||
|
local obj=srcLib[bgms[i]]
|
||||||
|
obj.vol=0
|
||||||
|
obj.pitch=1
|
||||||
|
obj.lowgain=1
|
||||||
|
obj.highgain=1
|
||||||
|
obj.volChanging=false
|
||||||
|
obj.pitchChanging=false
|
||||||
|
obj.lowgainChanging=false
|
||||||
|
obj.highgainChanging=false
|
||||||
|
|
||||||
|
_clearTask(obj)
|
||||||
|
|
||||||
|
local source=obj.source
|
||||||
|
source:setLooping(not STRING.sArg(args,'-noloop'))
|
||||||
|
source:setPitch(1)
|
||||||
|
source:seek(0)
|
||||||
|
source:setFilter()
|
||||||
|
if STRING.sArg(args,'-sdin') then
|
||||||
|
obj.vol=1
|
||||||
|
source:setVolume(volume)
|
||||||
|
BGM.set(bgm,'volume',1,0)
|
||||||
|
else
|
||||||
|
source:setVolume(0)
|
||||||
|
BGM.set(bgm,'volume',1,.626)
|
||||||
|
end
|
||||||
|
source:play()
|
||||||
|
|
||||||
|
table.insert(nowPlay,obj)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
_updateSources()
|
||||||
|
end
|
||||||
|
function BGM.stop(time)
|
||||||
|
if #nowPlay>0 then
|
||||||
|
for i=1,#nowPlay do
|
||||||
|
local obj=nowPlay[i]
|
||||||
|
_clearTask(obj,'volume')
|
||||||
|
if time==0 then
|
||||||
|
obj.source:stop()
|
||||||
|
obj.volChanging=false
|
||||||
|
else
|
||||||
|
TASK.new(task_setVolume,obj,0,time or .626,true)
|
||||||
|
obj.volChanging=true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
TABLE.cut(nowPlay)
|
||||||
|
lastPlay=NONE
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param mode
|
||||||
|
---| 'volume'
|
||||||
|
---| 'lowgain'
|
||||||
|
---| 'highgain'
|
||||||
|
---| 'volume'
|
||||||
|
---| 'pitch'
|
||||||
|
---| 'seek'
|
||||||
|
function BGM.set(bgms,mode,...)
|
||||||
|
if type(bgms)=='string' then
|
||||||
|
if bgms=='all' then
|
||||||
|
bgms=nowPlay
|
||||||
|
else
|
||||||
|
bgms={srcLib[bgms]}
|
||||||
|
end
|
||||||
|
elseif type(bgms)=='table' then
|
||||||
|
bgms=TABLE.shift(bgms)
|
||||||
|
for i=1,#bgms do
|
||||||
|
assert(type(bgms[i])=='string',"BGM list must be list of strings")
|
||||||
|
bgms[i]=srcLib[bgms[i]]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
error("BGM.play(name,args): name must be string or table")
|
||||||
|
end
|
||||||
|
for i=1,#bgms do
|
||||||
|
local obj=bgms[i]
|
||||||
|
if obj.source then
|
||||||
|
if mode=='volume' then
|
||||||
|
_clearTask(obj,'volume')
|
||||||
|
|
||||||
|
local vol,time=...
|
||||||
|
if not time then time=1 end
|
||||||
|
|
||||||
|
assert(type(vol)=='number' and vol>=0 and vol<=1,"BGM.set(...,volume): volume must be in range 0~1")
|
||||||
|
assert(type(time)=='number' and time>=0,"BGM.set(...,time): time must be positive number")
|
||||||
|
|
||||||
|
TASK.new(task_setVolume,obj,vol,time)
|
||||||
|
elseif mode=='pitch' then
|
||||||
|
_clearTask(obj,'pitch')
|
||||||
|
|
||||||
|
local pitch,changeTime=...
|
||||||
|
if not pitch then pitch=1 end
|
||||||
|
if not changeTime then changeTime=1 end
|
||||||
|
|
||||||
|
assert(type(pitch)=='number' and pitch>0 and pitch<=32,"BGM.set(...,pitch): pitch must be in range 0~32")
|
||||||
|
assert(type(changeTime)=='number' and changeTime>=0,"BGM.set(...,time): time must be positive number")
|
||||||
|
|
||||||
|
TASK.new(task_setPitch,obj,pitch,changeTime)
|
||||||
|
elseif mode=='seek' then
|
||||||
|
local time=...
|
||||||
|
assert(type(time)=='number',"BGM.set(...,time): time must be number")
|
||||||
|
obj.source:seek(MATH.clamp(time,0,obj.source:getDuration()))
|
||||||
|
elseif mode=='lowgain' then
|
||||||
|
if effectsSupported then
|
||||||
|
_clearTask(obj,'lowgain')
|
||||||
|
local lowgain,changeTime=...
|
||||||
|
if not lowgain then lowgain=1 end
|
||||||
|
if not changeTime then changeTime=1 end
|
||||||
|
|
||||||
|
assert(type(lowgain)=='number' and lowgain>=0 and lowgain<=1,"BGM.set(...,lowgain,highgain): lowgain must be in range 0~1")
|
||||||
|
assert(type(changeTime)=='number' and changeTime>=0,"BGM.set(...,time): time must be positive number")
|
||||||
|
|
||||||
|
TASK.new(task_setLowgain,obj,lowgain,changeTime)
|
||||||
|
obj.lowgain=lowgain
|
||||||
|
obj.source:setFilter{type='bandpass',lowgain=obj.lowgain,highgain=obj.highgain,volume=1}
|
||||||
|
end
|
||||||
|
elseif mode=='highgain' then
|
||||||
|
if effectsSupported then
|
||||||
|
_clearTask(obj,'highgain')
|
||||||
|
local highgain,changeTime=...
|
||||||
|
if not highgain then highgain=1 end
|
||||||
|
if not changeTime then changeTime=1 end
|
||||||
|
|
||||||
|
assert(type(highgain)=='number' and highgain>=0 and highgain<=1,"BGM.set(...,lowgain,highgain): highgain must be in range 0~1")
|
||||||
|
assert(type(changeTime)=='number' and changeTime>=0,"BGM.set(...,time): time must be positive number")
|
||||||
|
|
||||||
|
TASK.new(task_setHighgain,obj,highgain,changeTime)
|
||||||
|
obj.highgain=highgain
|
||||||
|
obj.source:setFilter{type='bandpass',lowgain=obj.lowgain,highgain=obj.highgain,volume=1}
|
||||||
|
end
|
||||||
|
else
|
||||||
|
error("BGM.set(...,mode): mode must be 'volume', 'pitch', or 'seek'")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function BGM.getPlaying()
|
||||||
|
return TABLE.shift(lastPlay)
|
||||||
|
end
|
||||||
|
function BGM.isPlaying()
|
||||||
|
return #nowPlay>0 and nowPlay[1].source:isPlaying()
|
||||||
|
end
|
||||||
|
function BGM.tell()
|
||||||
|
if nowPlay[1] then
|
||||||
|
return nowPlay[1].source:tell()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function BGM.getDuration()
|
||||||
|
if nowPlay[1] then
|
||||||
|
return nowPlay[1].source:getDuration()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return BGM
|
||||||
366
Zframework/bitop.lua
Normal file
@@ -0,0 +1,366 @@
|
|||||||
|
local M = {_TYPE='module', _NAME='bitop.funcs', _VERSION='1.0-0'}
|
||||||
|
|
||||||
|
local floor = math.floor
|
||||||
|
|
||||||
|
local MOD = 2 ^ 32
|
||||||
|
local MODM = MOD - 1
|
||||||
|
|
||||||
|
local function memoize(f)
|
||||||
|
|
||||||
|
local mt = {}
|
||||||
|
local t = setmetatable({}, mt)
|
||||||
|
|
||||||
|
function mt:__index(k)
|
||||||
|
local v = f(k)
|
||||||
|
t[k] = v
|
||||||
|
return v
|
||||||
|
end
|
||||||
|
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
|
local function make_bitop_uncached(t, m)
|
||||||
|
local function bitop(a, b)
|
||||||
|
local res, p = 0, 1
|
||||||
|
while a ~= 0 and b ~= 0 do
|
||||||
|
local am, bm = a % m, b % m
|
||||||
|
res = res + t[am][bm] * p
|
||||||
|
a = (a - am) / m
|
||||||
|
b = (b - bm) / m
|
||||||
|
p = p * m
|
||||||
|
end
|
||||||
|
res = res + (a + b) * p
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
return bitop
|
||||||
|
end
|
||||||
|
|
||||||
|
local function make_bitop(t)
|
||||||
|
local op1 = make_bitop_uncached(t, 2 ^ 1)
|
||||||
|
local op2 = memoize(function(a)
|
||||||
|
return memoize(function(b)
|
||||||
|
return op1(a, b)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
return make_bitop_uncached(op2, 2 ^ (t.n or 1))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ok? probably not if running on a 32-bit int Lua number type platform
|
||||||
|
function M.tobit(x)
|
||||||
|
return x % 2 ^ 32
|
||||||
|
end
|
||||||
|
|
||||||
|
M.bxor = make_bitop{[0]={[0]=0, [1]=1}, [1]={[0]=1, [1]=0}, n=4}
|
||||||
|
local bxor = M.bxor
|
||||||
|
|
||||||
|
function M.bnot(a)
|
||||||
|
return MODM - a
|
||||||
|
end
|
||||||
|
local bnot = M.bnot
|
||||||
|
|
||||||
|
function M.band(a, b)
|
||||||
|
return ((a + b) - bxor(a, b)) / 2
|
||||||
|
end
|
||||||
|
local band = M.band
|
||||||
|
|
||||||
|
function M.bor(a, b)
|
||||||
|
return MODM - band(MODM - a, MODM - b)
|
||||||
|
end
|
||||||
|
local bor = M.bor
|
||||||
|
|
||||||
|
local lshift, rshift -- forward declare
|
||||||
|
|
||||||
|
function M.rshift(a, disp) -- Lua5.2 insipred
|
||||||
|
if disp < 0 then
|
||||||
|
return lshift(a, -disp)
|
||||||
|
end
|
||||||
|
return floor(a % 2 ^ 32 / 2 ^ disp)
|
||||||
|
end
|
||||||
|
rshift = M.rshift
|
||||||
|
|
||||||
|
function M.lshift(a, disp) -- Lua5.2 inspired
|
||||||
|
if disp < 0 then
|
||||||
|
return rshift(a, -disp)
|
||||||
|
end
|
||||||
|
return (a * 2 ^ disp) % 2 ^ 32
|
||||||
|
end
|
||||||
|
lshift = M.lshift
|
||||||
|
|
||||||
|
function M.tohex(x, n) -- BitOp style
|
||||||
|
n = n or 8
|
||||||
|
local up
|
||||||
|
if n <= 0 then
|
||||||
|
if n == 0 then
|
||||||
|
return ''
|
||||||
|
end
|
||||||
|
up = true
|
||||||
|
n = -n
|
||||||
|
end
|
||||||
|
x = band(x, 16 ^ n - 1)
|
||||||
|
return ('%0' .. n .. (up and 'X' or 'x')):format(x)
|
||||||
|
end
|
||||||
|
local tohex = M.tohex
|
||||||
|
|
||||||
|
function M.extract(n, field, width) -- Lua5.2 inspired
|
||||||
|
width = width or 1
|
||||||
|
return band(rshift(n, field), 2 ^ width - 1)
|
||||||
|
end
|
||||||
|
local extract = M.extract
|
||||||
|
|
||||||
|
function M.replace(n, v, field, width) -- Lua5.2 inspired
|
||||||
|
width = width or 1
|
||||||
|
local mask1 = 2 ^ width - 1
|
||||||
|
v = band(v, mask1) -- required by spec?
|
||||||
|
local mask = bnot(lshift(mask1, field))
|
||||||
|
return band(n, mask) + lshift(v, field)
|
||||||
|
end
|
||||||
|
local replace = M.replace
|
||||||
|
|
||||||
|
function M.bswap(x) -- BitOp style
|
||||||
|
local a = band(x, 0xff);
|
||||||
|
x = rshift(x, 8)
|
||||||
|
local b = band(x, 0xff);
|
||||||
|
x = rshift(x, 8)
|
||||||
|
local c = band(x, 0xff);
|
||||||
|
x = rshift(x, 8)
|
||||||
|
local d = band(x, 0xff)
|
||||||
|
return lshift(lshift(lshift(a, 8) + b, 8) + c, 8) + d
|
||||||
|
end
|
||||||
|
local bswap = M.bswap
|
||||||
|
|
||||||
|
function M.rrotate(x, disp) -- Lua5.2 inspired
|
||||||
|
disp = disp % 32
|
||||||
|
local low = band(x, 2 ^ disp - 1)
|
||||||
|
return rshift(x, disp) + lshift(low, 32 - disp)
|
||||||
|
end
|
||||||
|
local rrotate = M.rrotate
|
||||||
|
|
||||||
|
function M.lrotate(x, disp) -- Lua5.2 inspired
|
||||||
|
return rrotate(x, -disp)
|
||||||
|
end
|
||||||
|
local lrotate = M.lrotate
|
||||||
|
|
||||||
|
M.rol = M.lrotate -- LuaOp inspired
|
||||||
|
M.ror = M.rrotate -- LuaOp insipred
|
||||||
|
|
||||||
|
function M.arshift(x, disp) -- Lua5.2 inspired
|
||||||
|
local z = rshift(x, disp)
|
||||||
|
if x >= 0x80000000 then
|
||||||
|
z = z + lshift(2 ^ disp - 1, 32 - disp)
|
||||||
|
end
|
||||||
|
return z
|
||||||
|
end
|
||||||
|
local arshift = M.arshift
|
||||||
|
|
||||||
|
function M.btest(x, y) -- Lua5.2 inspired
|
||||||
|
return band(x, y) ~= 0
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Start Lua 5.2 "bit32" compat section.
|
||||||
|
--
|
||||||
|
|
||||||
|
M.bit32 = {} -- Lua 5.2 'bit32' compatibility
|
||||||
|
|
||||||
|
local function bit32_bnot(x)
|
||||||
|
return (-1 - x) % MOD
|
||||||
|
end
|
||||||
|
M.bit32.bnot = bit32_bnot
|
||||||
|
|
||||||
|
local function bit32_bxor(a, b, c, ...)
|
||||||
|
local z
|
||||||
|
if b then
|
||||||
|
a = a % MOD
|
||||||
|
b = b % MOD
|
||||||
|
z = bxor(a, b)
|
||||||
|
if c then
|
||||||
|
z = bit32_bxor(z, c, ...)
|
||||||
|
end
|
||||||
|
return z
|
||||||
|
elseif a then
|
||||||
|
return a % MOD
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
M.bit32.bxor = bit32_bxor
|
||||||
|
|
||||||
|
local function bit32_band(a, b, c, ...)
|
||||||
|
local z
|
||||||
|
if b then
|
||||||
|
a = a % MOD
|
||||||
|
b = b % MOD
|
||||||
|
z = ((a + b) - bxor(a, b)) / 2
|
||||||
|
if c then
|
||||||
|
z = bit32_band(z, c, ...)
|
||||||
|
end
|
||||||
|
return z
|
||||||
|
elseif a then
|
||||||
|
return a % MOD
|
||||||
|
else
|
||||||
|
return MODM
|
||||||
|
end
|
||||||
|
end
|
||||||
|
M.bit32.band = bit32_band
|
||||||
|
|
||||||
|
local function bit32_bor(a, b, c, ...)
|
||||||
|
local z
|
||||||
|
if b then
|
||||||
|
a = a % MOD
|
||||||
|
b = b % MOD
|
||||||
|
z = MODM - band(MODM - a, MODM - b)
|
||||||
|
if c then
|
||||||
|
z = bit32_bor(z, c, ...)
|
||||||
|
end
|
||||||
|
return z
|
||||||
|
elseif a then
|
||||||
|
return a % MOD
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
M.bit32.bor = bit32_bor
|
||||||
|
|
||||||
|
function M.bit32.btest(...)
|
||||||
|
return bit32_band(...) ~= 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit32.lrotate(x, disp)
|
||||||
|
return lrotate(x % MOD, disp)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit32.rrotate(x, disp)
|
||||||
|
return rrotate(x % MOD, disp)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit32.lshift(x, disp)
|
||||||
|
if disp > 31 or disp < -31 then
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
return lshift(x % MOD, disp)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit32.rshift(x, disp)
|
||||||
|
if disp > 31 or disp < -31 then
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
return rshift(x % MOD, disp)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit32.arshift(x, disp)
|
||||||
|
x = x % MOD
|
||||||
|
if disp >= 0 then
|
||||||
|
if disp > 31 then
|
||||||
|
return (x >= 0x80000000) and MODM or 0
|
||||||
|
else
|
||||||
|
local z = rshift(x, disp)
|
||||||
|
if x >= 0x80000000 then
|
||||||
|
z = z + lshift(2 ^ disp - 1, 32 - disp)
|
||||||
|
end
|
||||||
|
return z
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return lshift(x, -disp)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit32.extract(x, field, ...)
|
||||||
|
local width = ... or 1
|
||||||
|
if field < 0 or field > 31 or width < 0 or field + width > 32 then
|
||||||
|
error'out of range'
|
||||||
|
end
|
||||||
|
x = x % MOD
|
||||||
|
return extract(x, field, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit32.replace(x, v, field, ...)
|
||||||
|
local width = ... or 1
|
||||||
|
if field < 0 or field > 31 or width < 0 or field + width > 32 then
|
||||||
|
error'out of range'
|
||||||
|
end
|
||||||
|
x = x % MOD
|
||||||
|
v = v % MOD
|
||||||
|
return replace(x, v, field, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Start LuaBitOp "bit" compat section.
|
||||||
|
--
|
||||||
|
|
||||||
|
M.bit = {} -- LuaBitOp "bit" compatibility
|
||||||
|
|
||||||
|
function M.bit.tobit(x)
|
||||||
|
x = x % MOD
|
||||||
|
if x >= 0x80000000 then
|
||||||
|
x = x - MOD
|
||||||
|
end
|
||||||
|
return x
|
||||||
|
end
|
||||||
|
local bit_tobit = M.bit.tobit
|
||||||
|
|
||||||
|
function M.bit.tohex(x, ...)
|
||||||
|
return tohex(x % MOD, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit.bnot(x)
|
||||||
|
return bit_tobit(bnot(x % MOD))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function bit_bor(a, b, c, ...)
|
||||||
|
if c then
|
||||||
|
return bit_bor(bit_bor(a, b), c, ...)
|
||||||
|
elseif b then
|
||||||
|
return bit_tobit(bor(a % MOD, b % MOD))
|
||||||
|
else
|
||||||
|
return bit_tobit(a)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
M.bit.bor = bit_bor
|
||||||
|
|
||||||
|
local function bit_band(a, b, c, ...)
|
||||||
|
if c then
|
||||||
|
return bit_band(bit_band(a, b), c, ...)
|
||||||
|
elseif b then
|
||||||
|
return bit_tobit(band(a % MOD, b % MOD))
|
||||||
|
else
|
||||||
|
return bit_tobit(a)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
M.bit.band = bit_band
|
||||||
|
|
||||||
|
local function bit_bxor(a, b, c, ...)
|
||||||
|
if c then
|
||||||
|
return bit_bxor(bit_bxor(a, b), c, ...)
|
||||||
|
elseif b then
|
||||||
|
return bit_tobit(bxor(a % MOD, b % MOD))
|
||||||
|
else
|
||||||
|
return bit_tobit(a)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
M.bit.bxor = bit_bxor
|
||||||
|
|
||||||
|
function M.bit.lshift(x, n)
|
||||||
|
return bit_tobit(lshift(x % MOD, n % 32))
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit.rshift(x, n)
|
||||||
|
return bit_tobit(rshift(x % MOD, n % 32))
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit.arshift(x, n)
|
||||||
|
return bit_tobit(arshift(x % MOD, n % 32))
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit.rol(x, n)
|
||||||
|
return bit_tobit(lrotate(x % MOD, n % 32))
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit.ror(x, n)
|
||||||
|
return bit_tobit(rrotate(x % MOD, n % 32))
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.bit.bswap(x)
|
||||||
|
return bit_tobit(bswap(x % MOD))
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
||||||
235
Zframework/color.lua
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
local abs=math.abs
|
||||||
|
|
||||||
|
-- Converts from HSV to RGB color. All arguments should be between 0 and 1, inclusively.
|
||||||
|
local function HSVToRGB(h,s,v,a)
|
||||||
|
if s<=0 then return v,v,v,a end
|
||||||
|
h=h%1*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 function RGBToHSV(r,g,b,a)
|
||||||
|
local max=math.max(r,g,b) -- = value
|
||||||
|
local min=math.min(r,g,b)
|
||||||
|
local chroma=max-min
|
||||||
|
local hue=(
|
||||||
|
max==min and 0 or
|
||||||
|
max==r and (g-b)/chroma%6/6 or
|
||||||
|
max==g and (2+(b-r)/chroma)/6 or
|
||||||
|
(4+(r-g)/chroma)/6
|
||||||
|
)
|
||||||
|
local saturation=max==0 and 0 or chroma/max
|
||||||
|
return hue,saturation,max,a
|
||||||
|
end
|
||||||
|
|
||||||
|
local COLOR={
|
||||||
|
hsv=HSVToRGB, -- backwards compatibility
|
||||||
|
HSVToRGB=HSVToRGB,
|
||||||
|
RGBToHSV=RGBToHSV,
|
||||||
|
|
||||||
|
|
||||||
|
red= {HSVToRGB(0.00, 0.89, 0.91)},
|
||||||
|
fire= {HSVToRGB(0.04, 0.93, 0.94)},
|
||||||
|
orange= {HSVToRGB(0.09, 0.99, 0.96)},
|
||||||
|
yellow= {HSVToRGB(0.15, 0.82, 0.90)},
|
||||||
|
lime= {HSVToRGB(0.20, 0.89, 0.88)},
|
||||||
|
jade= {HSVToRGB(0.25, 1.00, 0.82)},
|
||||||
|
green= {HSVToRGB(0.33, 1.00, 0.81)},
|
||||||
|
aqua= {HSVToRGB(0.47, 1.00, 0.76)},
|
||||||
|
cyan= {HSVToRGB(0.53, 1.00, 0.88)},
|
||||||
|
navy= {HSVToRGB(0.56, 1.00, 1.00)},
|
||||||
|
sea= {HSVToRGB(0.61, 1.00, 1.00)},
|
||||||
|
blue= {HSVToRGB(0.64, 1.00, 0.95)},
|
||||||
|
violet= {HSVToRGB(0.74, 1.00, 0.91)},
|
||||||
|
purple= {HSVToRGB(0.80, 1.00, 0.81)},
|
||||||
|
magenta= {HSVToRGB(0.86, 1.00, 0.78)},
|
||||||
|
wine= {HSVToRGB(0.92, 0.98, 0.91)},
|
||||||
|
|
||||||
|
lRed= {HSVToRGB(0.00, 0.38, 0.93)},
|
||||||
|
lFire= {HSVToRGB(0.04, 0.45, 0.91)},
|
||||||
|
lOrange= {HSVToRGB(0.10, 0.53, 0.92)},
|
||||||
|
lYellow= {HSVToRGB(0.14, 0.61, 0.95)},
|
||||||
|
lLime= {HSVToRGB(0.20, 0.66, 0.92)},
|
||||||
|
lJade= {HSVToRGB(0.26, 0.56, 0.90)},
|
||||||
|
lGreen= {HSVToRGB(0.34, 0.49, 0.89)},
|
||||||
|
lAqua= {HSVToRGB(0.47, 0.59, 0.86)},
|
||||||
|
lCyan= {HSVToRGB(0.51, 0.77, 0.88)},
|
||||||
|
lNavy= {HSVToRGB(0.54, 0.80, 0.95)},
|
||||||
|
lSea= {HSVToRGB(0.57, 0.72, 0.97)},
|
||||||
|
lBlue= {HSVToRGB(0.64, 0.44, 0.96)},
|
||||||
|
lViolet= {HSVToRGB(0.72, 0.47, 0.95)},
|
||||||
|
lPurple= {HSVToRGB(0.80, 0.62, 0.89)},
|
||||||
|
lMagenta= {HSVToRGB(0.86, 0.61, 0.89)},
|
||||||
|
lWine= {HSVToRGB(0.93, 0.57, 0.92)},
|
||||||
|
|
||||||
|
dRed= {HSVToRGB(0.00, 0.80, 0.48)},
|
||||||
|
dFire= {HSVToRGB(0.04, 0.80, 0.34)},
|
||||||
|
dOrange= {HSVToRGB(0.07, 0.80, 0.39)},
|
||||||
|
dYellow= {HSVToRGB(0.12, 0.80, 0.37)},
|
||||||
|
dLime= {HSVToRGB(0.20, 0.80, 0.26)},
|
||||||
|
dJade= {HSVToRGB(0.29, 0.80, 0.27)},
|
||||||
|
dGreen= {HSVToRGB(0.33, 0.80, 0.26)},
|
||||||
|
dAqua= {HSVToRGB(0.46, 0.80, 0.24)},
|
||||||
|
dCyan= {HSVToRGB(0.50, 0.80, 0.30)},
|
||||||
|
dNavy= {HSVToRGB(0.58, 0.80, 0.42)},
|
||||||
|
dSea= {HSVToRGB(0.64, 0.80, 0.40)},
|
||||||
|
dBlue= {HSVToRGB(0.67, 0.80, 0.34)},
|
||||||
|
dViolet= {HSVToRGB(0.71, 0.80, 0.35)},
|
||||||
|
dPurple= {HSVToRGB(0.76, 0.80, 0.32)},
|
||||||
|
dMagenta= {HSVToRGB(0.87, 0.80, 0.28)},
|
||||||
|
dWine= {HSVToRGB(0.92, 0.80, 0.28)},
|
||||||
|
|
||||||
|
black= {HSVToRGB(0.04, 0.04, 0.14)},
|
||||||
|
dGray= {HSVToRGB(0.02, 0.05, 0.44)},
|
||||||
|
gray= {HSVToRGB(0.02, 0.05, 0.65)},
|
||||||
|
lGray= {HSVToRGB(0.02, 0.06, 0.86)},
|
||||||
|
white= {HSVToRGB(0.01, 0.02, 0.99)},
|
||||||
|
|
||||||
|
xGray= {HSVToRGB(0.00, 0.00, 0.35,.8)},
|
||||||
|
lxGray= {HSVToRGB(0.00, 0.00, 0.62,.8)},
|
||||||
|
dxGray= {HSVToRGB(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: EIKQTU
|
||||||
|
} 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 twoThirdsOfPi=2*math.pi/3
|
||||||
|
local sin=math.sin
|
||||||
|
function COLOR.rainbow(phase,alpha)
|
||||||
|
return
|
||||||
|
sin(phase)*.4+.6,
|
||||||
|
sin(phase+twoThirdsOfPi)*.4+.6,
|
||||||
|
sin(phase-twoThirdsOfPi)*.4+.6,
|
||||||
|
alpha
|
||||||
|
end
|
||||||
|
function COLOR.rainbow_light(phase,alpha)
|
||||||
|
return
|
||||||
|
sin(phase)*.2+.7,
|
||||||
|
sin(phase+twoThirdsOfPi)*.2+.7,
|
||||||
|
sin(phase-twoThirdsOfPi)*.2+.7,
|
||||||
|
alpha
|
||||||
|
end
|
||||||
|
function COLOR.rainbow_dark(phase,alpha)
|
||||||
|
return
|
||||||
|
sin(phase)*.2+.4,
|
||||||
|
sin(phase+twoThirdsOfPi)*.2+.4,
|
||||||
|
sin(phase-twoThirdsOfPi)*.2+.4,
|
||||||
|
alpha
|
||||||
|
end
|
||||||
|
function COLOR.rainbow_gray(phase,alpha)
|
||||||
|
return
|
||||||
|
sin(phase)*.16+.5,
|
||||||
|
sin(phase+twoThirdsOfPi)*.16+.5,
|
||||||
|
sin(phase-twoThirdsOfPi)*.16+.5,
|
||||||
|
alpha
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
do -- Color interpolation https://www.alanzucconi.com/2016/01/06/colour-interpolation/
|
||||||
|
local lerp=MATH.mix
|
||||||
|
function COLOR.interpolateRGB(rgba1,rgba2,t)
|
||||||
|
return
|
||||||
|
lerp(rgba1[1],rgba2[1],t),
|
||||||
|
lerp(rgba1[2],rgba2[2],t),
|
||||||
|
lerp(rgba1[3],rgba2[3],t),
|
||||||
|
((rgba1[4] and rgba2[4]) and lerp(rgba1[4],rgba1[4],t) or nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
function COLOR.interpolateHSV(hsv1,hsv2,t)
|
||||||
|
local hue1,hue2=hsv1[1],hsv2[1]
|
||||||
|
if hue1>hue2 then
|
||||||
|
hue1,hue2=hue2,hue1
|
||||||
|
t=1-t
|
||||||
|
end
|
||||||
|
|
||||||
|
local hueDiff=hue2-hue1
|
||||||
|
local finalHue=.0
|
||||||
|
if hueDiff>.5 then
|
||||||
|
hue1=hue1+1
|
||||||
|
finalHue=(hue1+t*(hue2-hue1))%1;
|
||||||
|
else
|
||||||
|
finalHue=hue1+t*hueDiff
|
||||||
|
end
|
||||||
|
|
||||||
|
return finalHue,
|
||||||
|
lerp(hsv1[2],hsv2[2],t),
|
||||||
|
lerp(hsv1[3],hsv2[3],t),
|
||||||
|
((hsv1[4] and hsv2[4]) and lerp(hsv1[4],hsv1[4],t) or nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Returns either color1 or color2 based on time.
|
||||||
|
Args:
|
||||||
|
- color1, color2: colors to switch between
|
||||||
|
- period: the length of time in a cycle in seconds. ("wavelength")
|
||||||
|
- percentage [optional]: percentage of time in the color1 phase (default: 50%)
|
||||||
|
]]
|
||||||
|
function COLOR.flicker(color1,color2,period,percentage)
|
||||||
|
percentage=percentage or .5
|
||||||
|
return TIME()%period>percentage*period and color1 or color2
|
||||||
|
end
|
||||||
|
|
||||||
|
local lerpRGB,lerpHSV=COLOR.interpolateRGB,COLOR.interpolateHSV
|
||||||
|
local tau=MATH.tau
|
||||||
|
--[[
|
||||||
|
Oscillates between color1 and color2 over time in a sinusoidal fashion.
|
||||||
|
Args:
|
||||||
|
- color1, color2: colors to switch between.
|
||||||
|
[FORMAT IS BASED ON TYPE, WHICH DEFAULTS TO HSV]
|
||||||
|
Use COLOR.HSVtoRGB() and/or COLOR.RGBtoHSV to convert between color formats.
|
||||||
|
- period: the length of time in a cycle in seconds. (wavelength)
|
||||||
|
- type [optional]: the type of interpolation, defaulting to 'hsv'.
|
||||||
|
Supported values: nil, 'hsv', 'rgb'
|
||||||
|
]]
|
||||||
|
function COLOR.sine(color1,color2,period,type)
|
||||||
|
type=type or 'hsv'
|
||||||
|
local t=math.sin(tau*TIME()/period)
|
||||||
|
if type=='hsv' then
|
||||||
|
return lerpHSV(color1, color2, t)
|
||||||
|
elseif type=='rgb' then
|
||||||
|
return lerpRGB(color1, color2, t)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return COLOR
|
||||||
48
Zframework/diacritics.txt
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
Á=A,Ă=A,Ắ=A,Ặ=A,Ằ=A,Ẳ=A,Ẵ=A,Ǎ=A,Â=A,Ấ=A,Ậ=A,Ầ=A,Ẩ=A,Ẫ=A,Ä=A,Ạ=A,À=A,Ả=A,Ā=A,Ą=A,Å=A,Ǻ=A,Ã=A,Æ=AE,Ǽ=AE
|
||||||
|
Ḅ=B,Ɓ=B,ʚ=B,ɞ=B
|
||||||
|
Ć=C,Č=C,Ç=C,Ĉ=C,Ċ=C,Ɔ=C,ʗ=C
|
||||||
|
Ď=D,Ḓ=D,Ḍ=D,Ɗ=D,Ḏ=D,Dz=DZ,Dž=DZ,Đ=D,Ð=D,DZ=DZ,DŽ=DZ
|
||||||
|
É=E,Ĕ=E,Ě=E,Ê=E,Ế=E,Ệ=E,Ề=E,Ể=E,Ễ=E,Ë=E,Ė=E,Ẹ=E,È=E,Ẻ=E,Ē=E,Ę=E,Ẽ=E,Ɛ=E,Ə=E
|
||||||
|
Ƒ=F
|
||||||
|
Ǵ=G,Ğ=G,Ǧ=G,Ģ=G,Ĝ=G,Ġ=G,Ḡ=G,ʛ=G
|
||||||
|
Ḫ=H,Ĥ=H,Ḥ=H,Ħ=H
|
||||||
|
Í=I,Ĭ=I,Ǐ=I,Î=I,Ï=I,İ=I,Ị=I,Ì=I,Ỉ=I,Ī=I,Į=I,Ĩ=I,IJ=IJ
|
||||||
|
Ĵ=J
|
||||||
|
Ķ=K,Ḳ=K,Ƙ=K,Ḵ=K
|
||||||
|
Ĺ=L,Ƚ=L,Ľ=L,Ļ=L,Ḽ=L,Ḷ=L,Ḹ=L,Ḻ=L,Ŀ=L,Lj=Lj,Ł=L,LJ=LJ
|
||||||
|
Ḿ=M,Ṁ=M,Ṃ=M
|
||||||
|
Ń=N,Ň=N,Ņ=N,Ṋ=N,Ṅ=N,Ṇ=N,Ǹ=N,Ɲ=N,Ṉ=N,Nj=Nj,Ñ=N,NJ=NJ
|
||||||
|
Ó=O,Ŏ=O,Ǒ=O,Ô=O,Ố=O,Ộ=O,Ồ=O,Ổ=O,Ỗ=O,Ö=O,Ọ=O,Ő=O,Ò=O,Ỏ=O,Ơ=O,Ớ=O,Ợ=O,Ờ=O,Ở=O,Ỡ=O,Ō=O,Ɵ=O,Ǫ=O,Ø=O,Ǿ=O,Õ=O,Œ=OE,ɶ=Oe
|
||||||
|
Þ=P
|
||||||
|
Ŕ=R,Ř=R,Ŗ=R,Ṙ=R,Ṛ=R,Ṝ=R,Ṟ=R,ʁ=R
|
||||||
|
Ś=S,Š=S,Ş=S,Ŝ=S,Ș=S,Ṡ=S,Ṣ=S,ẞ=S
|
||||||
|
Ť=T,Ţ=T,Ṱ=T,Ț=T,Ṭ=T,Ṯ=T,Ŧ=T,Þ=T,Ð=T
|
||||||
|
Ú=U,Ŭ=U,Ǔ=U,Û=U,Ü=U,Ǘ=U,Ǚ=U,Ǜ=U,Ǖ=U,Ụ=U,Ű=U,Ù=U,Ủ=U,Ư=U,Ứ=U,Ự=U,Ừ=U,Ử=U,Ữ=U,Ū=U,Ų=U,Ů=U,Ũ=U
|
||||||
|
Ẃ=W,Ŵ=W,Ẅ=W,Ẁ=W,ʬ=W
|
||||||
|
Ý=Y,Ŷ=Y,Ÿ=Y,Ẏ=Y,Ỵ=Y,Ỳ=Y,Ƴ=Y,Ỷ=Y,Ȳ=Y,Ỹ=Y
|
||||||
|
Ź=Z,Ž=Z,Ż=Z,Ẓ=Z,Ẕ=Z,Ƶ=Z
|
||||||
|
á=a,ă=a,ắ=a,ặ=a,ằ=a,ẳ=a,ẵ=a,ǎ=a,â=a,ấ=a,ậ=a,ầ=a,ẩ=a,ẫ=a,ä=a,ạ=a,à=a,ả=a,ā=a,ą=a,å=a,ǻ=a,ã=a,æ=a,ǽ=a,ɑ=a,ɐ=a,ɒ=a
|
||||||
|
ḅ=b,ɓ=b,ß=b
|
||||||
|
ć=c,č=c,ç=c,ĉ=c,ɕ=c,ċ=c
|
||||||
|
ď=d,ḓ=d,ḍ=d,ɗ=d,ḏ=d,đ=d,ɖ=d,ʤ=d,dz=d,ʣ=d,ʥ=d,dž=d,ð=d
|
||||||
|
é=e,ĕ=e,ě=e,ê=e,ế=e,ệ=e,ề=e,ể=e,ễ=e,ë=e,ė=e,ẹ=e,è=e,ẻ=e,ē=e,ę=e,ẽ=e,ʒ=e,ǯ=e,ʓ=e,ɘ=e,ɜ=e,ɝ=e,ə=e,ɚ=e,ʚ=e,ɞ=e
|
||||||
|
ƒ=f,ſ=f,ʩ=f,fi=f,fl=f,ʃ=f,ʆ=f,ʅ=f,ɟ=f,ʄ=f
|
||||||
|
ǵ=g,ğ=g,ǧ=g,ģ=g,ĝ=g,ġ=g,ɠ=g,ḡ=g,ɡ=g,ɣ=g
|
||||||
|
ḫ=h,ĥ=h,ḥ=h,ɦ=h,ẖ=h,ħ=h,ɧ=h,ɥ=h,ʮ=h,ʯ=h,ų=h
|
||||||
|
í=i,ĭ=i,ǐ=i,î=i,ï=i,ị=i,ì=i,ỉ=i,ī=i,į=i,ɨ=i,ĩ=i,ɩ=i,ı=i,ij=ij,ɟ=i
|
||||||
|
ǰ=j,ĵ=j,ʝ=j,ȷ=j,ɟ=j,ʄ=j
|
||||||
|
ķ=k,ḳ=k,ƙ=k,ḵ=k,ĸ=k,ʞ=k
|
||||||
|
ĺ=l,ƚ=l,ɬ=l,ľ=l,ļ=l,ḽ=l,ḷ=l,ḹ=l,ḻ=l,ŀ=l,ɫ=l,ɭ=l,ł=l,ƛ=l,ɮ=lz,lj=lj,ʪ=ls,ʫ=lz
|
||||||
|
ḿ=m,ṁ=m,ṃ=m,ɱ=m,ɯ=m,ɰ=m
|
||||||
|
ʼn=n,ń=n,ň=n,ņ=n,ṋ=n,ṅ=n,ṇ=n,ǹ=n,ɲ=n,ṉ=n,ɳ=n,ñ=n,nj=nj,ŋ=n,Ŋ=n
|
||||||
|
ó=o,ŏ=o,ǒ=o,ô=o,ố=o,ộ=o,ồ=o,ổ=o,ỗ=o,ö=o,ọ=o,ő=o,ò=o,ỏ=o,ơ=o,ớ=o,ợ=o,ờ=o,ở=o,ỡ=o,ō=o,ǫ=o,ø=o,ǿ=o,õ=o,ɛ=o,ɔ=o,ɵ=o,ʘ=o,œ=oe
|
||||||
|
ɸ=p,þ=p
|
||||||
|
ʠ=q
|
||||||
|
ŕ=r,ř=r,ŗ=r,ṙ=r,ṛ=r,ṝ=r,ɾ=r,ṟ=r,ɼ=r,ɽ=r,ɿ=r,ɹ=r,ɻ=r,ɺ=r
|
||||||
|
ś=s,š=s,ş=s,ŝ=s,ș=s,ṡ=s,ṣ=s,ʂ=s,ſ=s,ʃ=s,ʆ=s,ß=s,ʅ=s
|
||||||
|
ť=t,ţ=t,ṱ=t,ț=t,ẗ=t,ṭ=t,ṯ=t,ʈ=t,ŧ=t,ʨ=t,ʧ=t,þ=t,ð=t,ʦ=t,ʇ=t
|
||||||
|
ʉ=u,ú=u,ŭ=u,ǔ=u,û=u,ü=u,ǘ=u,ǚ=u,ǜ=u,ǖ=u,ụ=u,ű=u,ù=u,ủ=u,ư=u,ứ=u,ự=u,ừ=u,ử=u,ữ=u,ū=u,ų=u,ů=u,ũ=u,ʊ=u
|
||||||
|
ʋ=v,ʌ=v
|
||||||
|
ẃ=w,ŵ=w,ẅ=w,ẁ=w,ʍ=w
|
||||||
|
ý=y,ŷ=y,ÿ=y,ẏ=y,ỵ=y,ỳ=y,ƴ=y,ỷ=y,ȳ=y,ỹ=y,ʎ=y
|
||||||
|
ź=z,ž=z,ʑ=z,ż=z,ẓ=z,ẕ=z,ʐ=z,ƶ=z
|
||||||
112
Zframework/file.lua
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
local fs=love.filesystem
|
||||||
|
local FILE={}
|
||||||
|
function FILE.isSafe(file)
|
||||||
|
return SYSTEM=='Web' or fs.getRealDirectory(file)~=fs.getSaveDirectory()
|
||||||
|
end
|
||||||
|
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,9):find('return%s*%{') 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
|
||||||
|
elseif not STRING.sArg(args,'-canskip') then
|
||||||
|
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
|
||||||
|
if STRING.sArg(args,'-expand') then
|
||||||
|
data=TABLE.dump(data)
|
||||||
|
else
|
||||||
|
data='return'..TABLE.dumpDeflate(data)
|
||||||
|
end
|
||||||
|
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 not FILE.isSafe(path) and fs.getInfo(path).type=='directory' then
|
||||||
|
for _,name in next,fs.getDirectoryItems(path) do
|
||||||
|
name=path..'/'..name
|
||||||
|
if not FILE.isSafe(name) 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 (not FILE.isSafe(path) and fs.getInfo(path).type=='directory') then
|
||||||
|
for _,name in next,fs.getDirectoryItems(path) do
|
||||||
|
name=path..'/'..name
|
||||||
|
if not FILE.isSafe(name) 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
|
||||||
59
Zframework/font.lua
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
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
|
||||||
184
Zframework/gcExtend.lua
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
local gc=love.graphics
|
||||||
|
local setColor,printf,draw=gc.setColor,gc.printf,gc.draw
|
||||||
|
local sin,cos=math.sin,math.cos
|
||||||
|
|
||||||
|
local GC=setmetatable({},{
|
||||||
|
__index=gc,
|
||||||
|
__metatable=true
|
||||||
|
})
|
||||||
|
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.mDraw(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.regPolygon(mode,x,y,R,segments,phase)
|
||||||
|
local l={}
|
||||||
|
local ang=phase or 0
|
||||||
|
local angStep=6.283185307179586/segments
|
||||||
|
for i=1,segments do
|
||||||
|
l[2*i-1]=x+R*cos(ang)
|
||||||
|
l[2*i]=y+R*sin(ang)
|
||||||
|
ang=ang+angStep
|
||||||
|
end
|
||||||
|
gc.polygon(mode,l)
|
||||||
|
end
|
||||||
|
function GC.regRoundPolygon(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*cos(ang)
|
||||||
|
Y[i]=y+R*sin(ang)
|
||||||
|
ang=ang+angStep
|
||||||
|
end
|
||||||
|
X[segments+1]=x+R*cos(ang)
|
||||||
|
Y[segments+1]=y+R*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*cos(dir),y1+erasedLen*sin(dir),x2-erasedLen*cos(dir),y2-erasedLen*sin(dir))
|
||||||
|
|
||||||
|
-- Arc
|
||||||
|
ang=ang+angStep
|
||||||
|
local R2=R-r/cos(halfAng)
|
||||||
|
local arcCX,arcCY=x+R2*cos(ang),y+R2*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)
|
||||||
|
L[4*i-3]=x1+erasedLen*cos(dir)
|
||||||
|
L[4*i-2]=y1+erasedLen*sin(dir)
|
||||||
|
L[4*i-1]=x2-erasedLen*cos(dir)
|
||||||
|
L[4*i]=y2-erasedLen*sin(dir)
|
||||||
|
|
||||||
|
-- Arc
|
||||||
|
ang=ang+angStep
|
||||||
|
local R2=R-r/cos(halfAng)
|
||||||
|
local arcCX,arcCY=x+R2*cos(ang),y+R2*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",
|
||||||
|
setBM="setBlendMode",
|
||||||
|
|
||||||
|
print="print",
|
||||||
|
rawFT=function(...)FONT.rawset(...) end,
|
||||||
|
setFT=function(...)FONT.set(...) end,
|
||||||
|
mText=GC.mStr,
|
||||||
|
mDraw=GC.mDraw,
|
||||||
|
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.regPolygon('fill',...) end,
|
||||||
|
dRPol=function(...)GC.regPolygon('line',...) end,
|
||||||
|
fRRPol=function(...)GC.regRoundPolygon('fill',...) end,
|
||||||
|
dRRPol=function(...)GC.regRoundPolygon('line',...) end,
|
||||||
|
}
|
||||||
|
local sizeLimit=gc.getSystemLimits().texturesize
|
||||||
|
function GC.DO(L)
|
||||||
|
gc.push()
|
||||||
|
local success,canvas
|
||||||
|
repeat
|
||||||
|
success,canvas=pcall(gc.newCanvas,math.min(L[1],sizeLimit),math.min(L[2],sizeLimit))
|
||||||
|
if not success then
|
||||||
|
sizeLimit=math.floor(sizeLimit*.8)
|
||||||
|
end
|
||||||
|
until success
|
||||||
|
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] or gc[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
|
||||||
191
Zframework/http.lua
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
local sendCHN=love.thread.getChannel('inputChannel')
|
||||||
|
local recvCHN=love.thread.getChannel('outputChannel')
|
||||||
|
|
||||||
|
local threads={}
|
||||||
|
local threadCount=0
|
||||||
|
local threadCode=[[
|
||||||
|
local id=...
|
||||||
|
|
||||||
|
local http=require'socket.http'
|
||||||
|
local ltn12=require'ltn12'
|
||||||
|
|
||||||
|
local sendCHN=love.thread.getChannel('inputChannel')
|
||||||
|
local recvCHN=love.thread.getChannel('outputChannel')
|
||||||
|
|
||||||
|
while true do
|
||||||
|
local arg=sendCHN:demand()
|
||||||
|
|
||||||
|
if arg._destroy then
|
||||||
|
recvCHN:push{
|
||||||
|
destroy=true,
|
||||||
|
id=id,
|
||||||
|
}
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
-- print("\n------SEND------") for k,v in next,arg do print(k,v) end
|
||||||
|
local data={}
|
||||||
|
local _,code,detail=http.request{
|
||||||
|
method=arg.method,
|
||||||
|
url=arg.url,
|
||||||
|
headers=arg.headers,
|
||||||
|
source=ltn12.source.string(arg.body),
|
||||||
|
|
||||||
|
sink=ltn12.sink.table(data),
|
||||||
|
}
|
||||||
|
|
||||||
|
local result={
|
||||||
|
pool=arg.pool,
|
||||||
|
poolPtr=arg.poolPtr,
|
||||||
|
code=code,
|
||||||
|
body=table.concat(data),
|
||||||
|
detail=detail,
|
||||||
|
}
|
||||||
|
-- print("\n------RECV------") for k,v in next,result do print(k,v) end
|
||||||
|
recvCHN:push(result)
|
||||||
|
end
|
||||||
|
]]
|
||||||
|
|
||||||
|
local msgPool=setmetatable({},{
|
||||||
|
__index=function(self,k)
|
||||||
|
self[k]={}
|
||||||
|
return self[k]
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
local HTTP={
|
||||||
|
_msgCount=0,
|
||||||
|
_trigTime=0,
|
||||||
|
_trigInterval=.26,
|
||||||
|
_host=false,
|
||||||
|
}
|
||||||
|
|
||||||
|
local function addThread(num)
|
||||||
|
for i=1,26 do
|
||||||
|
if num<=0 then break end
|
||||||
|
if not threads[i] then
|
||||||
|
threads[i]=love.thread.newThread(threadCode)
|
||||||
|
threads[i]:start(i)
|
||||||
|
threadCount=threadCount+1
|
||||||
|
num=num-1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function HTTP.request(arg)
|
||||||
|
arg.method=arg.method or arg.body and 'POST' or 'GET'
|
||||||
|
if arg.url then
|
||||||
|
assert(type(arg.url)=='string',"Field 'url' need string, get "..type(arg.url))
|
||||||
|
if arg.url:sub(1,7)~='http://' then arg.url='http://'..arg.url end
|
||||||
|
else
|
||||||
|
arg.url=HTTP._host or error("Need url=<string> or set default host with HTTP.setHost")
|
||||||
|
end
|
||||||
|
if arg.path then
|
||||||
|
assert(type(arg.path)=='string',"Field 'path' need string, get "..type(arg.path))
|
||||||
|
arg.url=arg.url..arg.path
|
||||||
|
end
|
||||||
|
assert(arg.headers==nil or type(arg.headers)=='table',"Field 'headers' need table, get "..type(arg.headers))
|
||||||
|
|
||||||
|
if arg.body~=nil then
|
||||||
|
assert(type(arg.body)=='table',"Field 'body' need table, get "..type(arg.body))
|
||||||
|
arg.body=JSON.encode(arg.body)
|
||||||
|
if not arg.headers then arg.headers={} end
|
||||||
|
TABLE.cover({
|
||||||
|
['Content-Type']="application/json",
|
||||||
|
['Content-Length']=#arg.body,
|
||||||
|
},arg.headers)
|
||||||
|
end
|
||||||
|
|
||||||
|
if arg.pool==nil then arg.pool='_default' end
|
||||||
|
arg.poolPtr=tostring(msgPool[arg.pool])
|
||||||
|
|
||||||
|
sendCHN:push(arg)
|
||||||
|
end
|
||||||
|
|
||||||
|
function HTTP.reset()
|
||||||
|
for i=1,#threads do
|
||||||
|
threads[i]:release()
|
||||||
|
threads[i]=false
|
||||||
|
end
|
||||||
|
TABLE.clear(msgPool)
|
||||||
|
sendCHN:clear()
|
||||||
|
recvCHN:clear()
|
||||||
|
addThread(threadCount)
|
||||||
|
end
|
||||||
|
function HTTP.setThreadCount(n)
|
||||||
|
assert(type(n)=='number' and n>=1 and n<=26 and n%1==0,"function HTTP.setThreadCount(n): n must be integer from 1 to 26")
|
||||||
|
if n>threadCount then
|
||||||
|
addThread(n-threadCount)
|
||||||
|
else
|
||||||
|
for _=n+1,threadCount do
|
||||||
|
sendCHN:push{_destroy=true}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function HTTP.getThreadCount()
|
||||||
|
return threadCount
|
||||||
|
end
|
||||||
|
function HTTP.setInterval(interval)
|
||||||
|
if interval<=0 then interval=1e99 end
|
||||||
|
assert(type(interval)=='number',"Interval must be number")
|
||||||
|
HTTP._trigInterval=interval
|
||||||
|
end
|
||||||
|
function HTTP.clearPool(pool)
|
||||||
|
if pool==nil then pool='_default' end
|
||||||
|
assert(type(pool)=='string',"Pool must be nil or string")
|
||||||
|
HTTP._msgCount=HTTP._msgCount-#msgPool[pool]
|
||||||
|
msgPool[pool]={}
|
||||||
|
end
|
||||||
|
function HTTP.deletePool(pool)
|
||||||
|
assert(type(pool)=='string',"Pool must be nil or string")
|
||||||
|
assert(pool~='_default',"Cannot delete _default pool. What are you doing?")
|
||||||
|
HTTP._msgCount=HTTP._msgCount-#msgPool[pool]
|
||||||
|
msgPool[pool]=nil
|
||||||
|
end
|
||||||
|
function HTTP.pollMsg(pool)
|
||||||
|
if not (type(pool)=='nil' or type(pool)=='string') then error("Pool must be nil or string") end
|
||||||
|
HTTP.update()
|
||||||
|
local p=msgPool[pool or '_default']
|
||||||
|
if #p>0 then
|
||||||
|
HTTP._msgCount=HTTP._msgCount-1
|
||||||
|
return table.remove(p)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function HTTP.setHost(host)
|
||||||
|
assert(type(host)=='string',"Host must be string")
|
||||||
|
if host:sub(1,7)~='http://' then host='http://'..host end
|
||||||
|
HTTP._host=host
|
||||||
|
end
|
||||||
|
|
||||||
|
function HTTP.update(dt)
|
||||||
|
if dt then
|
||||||
|
HTTP._trigTime=HTTP._trigTime+dt
|
||||||
|
if HTTP._trigTime>HTTP._trigInterval then
|
||||||
|
HTTP._trigTime=HTTP._trigTime%HTTP._trigInterval
|
||||||
|
else
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
while recvCHN:getCount()>0 do
|
||||||
|
local m=recvCHN:pop()
|
||||||
|
if m.destroy then
|
||||||
|
threads[m.id]:release()
|
||||||
|
threads[m.id]=false
|
||||||
|
elseif tostring(msgPool[m.pool])==m.poolPtr then -- If pool were cleared, discard this datapack
|
||||||
|
table.insert(msgPool[m.pool],{
|
||||||
|
code=m.code,
|
||||||
|
body=m.body,
|
||||||
|
detail=m.detail,
|
||||||
|
})
|
||||||
|
HTTP._msgCount=HTTP._msgCount+1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
setmetatable(HTTP,{__call=function(self,arg)
|
||||||
|
return self.request(arg)
|
||||||
|
end,__metatable=true})
|
||||||
|
|
||||||
|
HTTP.reset()
|
||||||
|
|
||||||
|
return HTTP
|
||||||
25
Zframework/image.lua
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
local IMG={}
|
||||||
|
function IMG.init(list)
|
||||||
|
IMG.init=nil
|
||||||
|
|
||||||
|
setmetatable(IMG,{__index=function(self,name)
|
||||||
|
if type(list[name])=='table' then
|
||||||
|
self[name]={}
|
||||||
|
for k,v in next,list[name] do
|
||||||
|
self[name][k]=love.graphics.newImage(v)
|
||||||
|
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
|
||||||
932
Zframework/init.lua
Normal file
@@ -0,0 +1,932 @@
|
|||||||
|
NONE={}function NULL() end PAPER=love.graphics.newCanvas(1,1)
|
||||||
|
EDITING=""
|
||||||
|
LOADED=false
|
||||||
|
SYSTEM=love.system.getOS()
|
||||||
|
if SYSTEM=='OS X' then SYSTEM='macOS' end
|
||||||
|
|
||||||
|
-- Bit module
|
||||||
|
local success
|
||||||
|
success,bit=pcall(require,"bit")
|
||||||
|
if not success then
|
||||||
|
bit=require"Zframework.bitop".bit
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 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'
|
||||||
|
LANG= require'Zframework.languages'
|
||||||
|
HASH= require'Zframework.sha2'
|
||||||
|
do
|
||||||
|
local bxor=bit.bxor
|
||||||
|
local char=string.char
|
||||||
|
local function sxor(s1, s2)
|
||||||
|
local b3=""
|
||||||
|
for i=1,#s1 do
|
||||||
|
b3=b3..char(bxor(s1:byte(i),s2:byte(i)))
|
||||||
|
end
|
||||||
|
return b3
|
||||||
|
end
|
||||||
|
function HASH.pbkdf2(hashFunc, pw, salt, n)
|
||||||
|
local u=HASH.hex2bin(HASH.hmac(hashFunc, pw, salt.."\0\0\0\1"))
|
||||||
|
local t=u
|
||||||
|
|
||||||
|
for _=2,n do
|
||||||
|
u=HASH.hex2bin(HASH.hmac(hashFunc, pw, u))
|
||||||
|
t=sxor(t, u)
|
||||||
|
end
|
||||||
|
|
||||||
|
return HASH.bin2hex(t):upper()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Love-based modules (basic)
|
||||||
|
HTTP= require'Zframework.http'
|
||||||
|
WS= require'Zframework.websocket'
|
||||||
|
FILE= require'Zframework.file'
|
||||||
|
WHEELMOV= require'Zframework.wheelScroll'
|
||||||
|
SCR= require'Zframework.screen'
|
||||||
|
SCN= require'Zframework.scene'
|
||||||
|
|
||||||
|
-- Love-based modules (complex)
|
||||||
|
GC= require'Zframework.gcExtend'
|
||||||
|
FONT= require'Zframework.font'
|
||||||
|
TEXT= require'Zframework.text'
|
||||||
|
SYSFX= require'Zframework.sysFX'
|
||||||
|
WAIT= require'Zframework.wait'
|
||||||
|
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 BG,WIDGET,SCR,SCN,WAIT=BG,WIDGET,SCR,SCN,WAIT
|
||||||
|
local xOy=SCR.xOy
|
||||||
|
local ITP=xOy.inverseTransformPoint
|
||||||
|
|
||||||
|
local max,min=math.max,math.min
|
||||||
|
|
||||||
|
local debugMode
|
||||||
|
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 onBeforeQuit=false
|
||||||
|
local versionText=""
|
||||||
|
|
||||||
|
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 or WAIT.state 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 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 or WAIT.state then return end
|
||||||
|
mouseShow=true
|
||||||
|
mx,my=ITP(xOy,x,y)
|
||||||
|
if debugMode==1 then
|
||||||
|
print(("(%d,%d)<-%d,%d ~~(%d,%d)<-%d,%d"):format(
|
||||||
|
mx,my,
|
||||||
|
mx-lastX,my-lastY,
|
||||||
|
math.floor(mx/10)*10,math.floor(my/10)*10,
|
||||||
|
math.floor((mx-lastX)/10)*10,math.floor((my-lastY)/10)*10
|
||||||
|
))
|
||||||
|
end
|
||||||
|
if SCN.swapping then return end
|
||||||
|
if SCN.mouseDown then SCN.mouseDown(mx,my,k) end
|
||||||
|
WIDGET.press(mx,my,k)
|
||||||
|
lastX,lastY=mx,my
|
||||||
|
if showClickFX then SYSFX.newTap(3,mx,my) end
|
||||||
|
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 WAIT.state 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,k)
|
||||||
|
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 math.abs(x)>=100 then x=x/100 end
|
||||||
|
if math.abs(y)>=100 then y=y/100 end
|
||||||
|
if WAIT.state or 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 WAIT.state or 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
|
||||||
|
if SCN.touchDown then SCN.touchDown(x,y,id) end
|
||||||
|
if kb.hasTextInput() then kb.setTextInput(false) end
|
||||||
|
WIDGET.cursorMove(x,y)
|
||||||
|
WIDGET.press(x,y,1)
|
||||||
|
end
|
||||||
|
function love.touchmoved(id,x,y,dx,dy)
|
||||||
|
if WAIT.state or 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 WAIT.state or SCN.swapping then return end
|
||||||
|
x,y=ITP(xOy,x,y)
|
||||||
|
if id==SCN.mainTouchID then
|
||||||
|
WIDGET.release(x,y,1)
|
||||||
|
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
|
||||||
|
-- function love.mousepressed(x,y,k) love.touchpressed(1,x,y) end
|
||||||
|
-- function love.mousemoved(x,y,dx,dy,touch) love.touchmoved(1,x,y,dx,dy) end
|
||||||
|
-- function love.mousereleased(x,y,k) love.touchreleased(1,x,y) end
|
||||||
|
|
||||||
|
local globalKey={
|
||||||
|
f8=function()
|
||||||
|
debugMode=1
|
||||||
|
MES.new('info',"DEBUG ON",.2)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
local fnKey={NULL,NULL,NULL,NULL,NULL,NULL,NULL}
|
||||||
|
local function debugKeyPressed(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 debugMode=nil MES.new('info',"DEBUG OFF",.2)
|
||||||
|
elseif key=='f9' then debugMode=1 MES.new('info',"DEBUG 1")
|
||||||
|
elseif key=='f10' then debugMode=2 MES.new('info',"DEBUG 2")
|
||||||
|
elseif key=='f11' then debugMode=3 MES.new('info',"DEBUG 3")
|
||||||
|
elseif key=='f12' then debugMode=4 MES.new('info',"DEBUG 4")
|
||||||
|
elseif debugMode==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
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
function love.keypressed(key,_,isRep)
|
||||||
|
mouseShow=false
|
||||||
|
if debugMode and debugKeyPressed(key) then
|
||||||
|
-- Do nothing
|
||||||
|
elseif globalKey[key] then
|
||||||
|
globalKey[key]()
|
||||||
|
else
|
||||||
|
if SCN.swapping then return end
|
||||||
|
if WAIT.state then
|
||||||
|
if key=='escape' and WAIT.arg.escapable then WAIT.interrupt() end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
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
|
||||||
|
love.mousepressed(mx,my,1)
|
||||||
|
love.mousereleased(mx,my,1)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if W and W.keypress then
|
||||||
|
W:keypress(key)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function love.keyreleased(i)
|
||||||
|
if WAIT.state or 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
|
||||||
|
love.mousepressed(mx,my,1)
|
||||||
|
love.mousereleased(mx,my,1)
|
||||||
|
else
|
||||||
|
if W and W.keypress then
|
||||||
|
W:keypress(key)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function love.gamepadreleased(_,i)
|
||||||
|
if WAIT.state or SCN.swapping then return end
|
||||||
|
if SCN.gamepadUp then SCN.gamepadUp(i) end
|
||||||
|
end
|
||||||
|
|
||||||
|
function love.filedropped(file)
|
||||||
|
if WAIT.state or SCN.swapping then return end
|
||||||
|
if SCN.fileDropped then SCN.fileDropped(file) end
|
||||||
|
end
|
||||||
|
function love.directorydropped(dir)
|
||||||
|
if WAIT.state or SCN.swapping then return end
|
||||||
|
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()
|
||||||
|
|
||||||
|
local sceneStack=SCN and table.concat(SCN.stack,"/") or "NULL"
|
||||||
|
if LOADED and #errData<3 then
|
||||||
|
BG.set('none')
|
||||||
|
table.insert(errData,{mes=err,scene=sceneStack})
|
||||||
|
|
||||||
|
-- Write messages to log file
|
||||||
|
love.filesystem.append('conf/error.log',
|
||||||
|
os.date("%Y/%m/%d %A %H:%M:%S\n")..
|
||||||
|
#errData.." crash(es) "..SYSTEM.."-"..VERSION.string.." scene: "..sceneStack.."\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(SYSTEM.."-"..VERSION.string.." scene:"..sceneStack,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 debugColor={
|
||||||
|
COLOR.Z,
|
||||||
|
COLOR.lM,
|
||||||
|
COLOR.lG,
|
||||||
|
COLOR.lB,
|
||||||
|
}
|
||||||
|
|
||||||
|
local debugInfos={
|
||||||
|
{"Cache",gcinfo},
|
||||||
|
}
|
||||||
|
function love.run()
|
||||||
|
local love=love
|
||||||
|
|
||||||
|
local TEXT_update,TEXT_draw=TEXT.update,TEXT.draw
|
||||||
|
local MES_update,MES_draw=MES.update,MES.draw
|
||||||
|
local HTTP_update,WS_update=HTTP.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,SLEEP=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=love.timer.getTime
|
||||||
|
|
||||||
|
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
|
||||||
|
if #errData>0 then
|
||||||
|
SCN.cur='error'
|
||||||
|
SCN.init('error')
|
||||||
|
else
|
||||||
|
SCN.init('load')
|
||||||
|
end
|
||||||
|
|
||||||
|
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
|
||||||
|
if onBeforeQuit then
|
||||||
|
onBeforeQuit()
|
||||||
|
onBeforeQuit=false
|
||||||
|
else
|
||||||
|
onQuit()
|
||||||
|
return a or true
|
||||||
|
end
|
||||||
|
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)
|
||||||
|
WAIT.update(dt)
|
||||||
|
MES_update(dt)
|
||||||
|
HTTP_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)
|
||||||
|
if showPowerInfo then
|
||||||
|
gc.translate(0,27)
|
||||||
|
end
|
||||||
|
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.state
|
||||||
|
_.draw(_.time)
|
||||||
|
end
|
||||||
|
gc_replaceTransform(SCR.xOy_d)
|
||||||
|
-- Draw Version string
|
||||||
|
gc_setColor(.9,.9,.9,.42)
|
||||||
|
FONT.set(20)
|
||||||
|
GC.mStr(versionText,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 debugMode then
|
||||||
|
-- Debug infos at left-down
|
||||||
|
gc_setColor(debugColor[debugMode])
|
||||||
|
|
||||||
|
-- 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
|
||||||
|
local status=WS.status('game')
|
||||||
|
if status=='dead' then
|
||||||
|
gc_setColor(COLOR.R)
|
||||||
|
elseif status=='connecting' then
|
||||||
|
gc_setColor(1,1,1,.5+.3*math.sin(time*6.26))
|
||||||
|
elseif status=='running' then
|
||||||
|
gc_setColor(COLOR.lG)
|
||||||
|
end
|
||||||
|
gc.rectangle('fill',-16,-16,12,12)
|
||||||
|
local t1,t2,t3=WS.getTimers('game')
|
||||||
|
if t1>0 then gc_setColor(.9,.9,.9,t1)gc.rectangle('fill',-60,-2,-16,-16) end
|
||||||
|
if t2>0 then gc_setColor(.3,1,.3,t2)gc.rectangle('fill',-42,-2,-16,-16) end
|
||||||
|
if t3>0 then gc_setColor(1,.2,.2,t3)gc.rectangle('fill',-24,-2,-16,-16) end
|
||||||
|
end
|
||||||
|
gc_replaceTransform(SCR.origin)
|
||||||
|
WAIT.draw()
|
||||||
|
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 debugmode
|
||||||
|
if debugMode then
|
||||||
|
if debugMode==3 then
|
||||||
|
SLEEP(.1)
|
||||||
|
elseif debugMode==4 then
|
||||||
|
SLEEP(.5)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
_=timer()-lastFrame
|
||||||
|
if _<sleepInterval*.9626 then SLEEP(sleepInterval*.9626-_) end
|
||||||
|
while timer()-lastFrame<sleepInterval do end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local Z={}
|
||||||
|
|
||||||
|
function Z.getJsState() return jsState end
|
||||||
|
function Z.getErr(i)
|
||||||
|
if i=='#' then
|
||||||
|
return errData[#errData]
|
||||||
|
elseif i then
|
||||||
|
return errData[i]
|
||||||
|
else
|
||||||
|
return errData
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Z.setPowerInfo(bool) showPowerInfo=bool end
|
||||||
|
function Z.setCleanCanvas(bool) discardCanvas=bool end
|
||||||
|
function Z.setFrameMul(n) frameMul=n end
|
||||||
|
function Z.setMaxFPS(fps) sleepInterval=1/fps end
|
||||||
|
function Z.setClickFX(bool) showClickFX=bool end
|
||||||
|
|
||||||
|
--[Warning] Color and line width is uncertain value, set it in the function.
|
||||||
|
function Z.setCursor(func) drawCursor=func end
|
||||||
|
|
||||||
|
function Z.setVersionText(str) versionText=str end
|
||||||
|
|
||||||
|
function Z.setDebugInfo(list)
|
||||||
|
assert(type(list)=='table',"Z.setDebugInfo(list): list must be table")
|
||||||
|
for i=1,#list do
|
||||||
|
assert(type(list[i][1])=='string',"Z.setDebugInfo(list): list[i][1] must be string")
|
||||||
|
assert(type(list[i][2])=='function',"Z.setDebugInfo(list): list[i][2] must be function")
|
||||||
|
end
|
||||||
|
debugInfos=list
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Change F1~F7 events of debugmode (F8 mode)
|
||||||
|
function Z.setOnFnKeys(list)
|
||||||
|
assert(type(list)=='table',"Z.setOnFnKeys(list): list must be table")
|
||||||
|
for i=1,7 do fnKey[i]=assert(type(list[i])=='function' and list[i]) end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Z.setOnGlobalKey(key,func)
|
||||||
|
assert(type(key)=='string',"Z.setOnFnKeys(key,func): key must be string")
|
||||||
|
if not func then
|
||||||
|
globalKey[key]=nil
|
||||||
|
else
|
||||||
|
assert(type(func)=='function',"Z.setOnFnKeys(key,func): func must be function")
|
||||||
|
globalKey[key]=func
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Z.setOnFocus(func)
|
||||||
|
onFocus=assert(type(func)=='function' and func,"Z.setOnFocus(func): func must be function")
|
||||||
|
end
|
||||||
|
|
||||||
|
function Z.setOnResize(func)
|
||||||
|
onResize=assert(type(func)=='function' and func,"Z.setOnResize(func): func must be function")
|
||||||
|
end
|
||||||
|
|
||||||
|
function Z.setOnQuit(func)
|
||||||
|
onQuit=assert(type(func)=='function' and func,"Z.setOnQuit(func): func must be function")
|
||||||
|
end
|
||||||
|
|
||||||
|
function Z.setOnBeforeQuit(func)
|
||||||
|
onBeforeQuit=assert(type(func)=='function' and func,"Z.setOnBeforeQuit(func): func must be function")
|
||||||
|
end
|
||||||
|
|
||||||
|
return Z
|
||||||
340
Zframework/json.lua
Normal file
@@ -0,0 +1,340 @@
|
|||||||
|
-- json.lua
|
||||||
|
|
||||||
|
-- Copyright (c) 2020 rxi
|
||||||
|
|
||||||
|
-- Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
-- this software and associated documentation files (the "Software"), to deal in
|
||||||
|
-- the Software without restriction, including without limitation the rights to
|
||||||
|
-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
-- of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
-- so, subject to the following conditions:
|
||||||
|
|
||||||
|
-- The above copyright notice and this permission notice shall be included in all
|
||||||
|
-- copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
-- SOFTWARE.
|
||||||
|
|
||||||
|
-- Editted by MrZ
|
||||||
|
|
||||||
|
local ins,char=table.insert,string.char
|
||||||
|
local json = {}
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Encode
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
local _encode
|
||||||
|
|
||||||
|
local escape_char_map = {
|
||||||
|
["\\"] = "\\",
|
||||||
|
["\""] = "\"",
|
||||||
|
["\b"] = "b",
|
||||||
|
["\f"] = "f",
|
||||||
|
["\n"] = "n",
|
||||||
|
["\r"] = "r",
|
||||||
|
["\t"] = "t"
|
||||||
|
}
|
||||||
|
|
||||||
|
local escape_char_map_inv = {["/"] = "/"}
|
||||||
|
for k, v in pairs(escape_char_map) do escape_char_map_inv[v] = k end
|
||||||
|
|
||||||
|
local function escape_char(c)
|
||||||
|
return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte()))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function encode_nil() return "null" end
|
||||||
|
|
||||||
|
local function encode_table(val, stack)
|
||||||
|
local res = {}
|
||||||
|
stack = stack or {}
|
||||||
|
|
||||||
|
-- Circular reference?
|
||||||
|
if stack[val] then error("circular reference") end
|
||||||
|
|
||||||
|
stack[val] = true
|
||||||
|
|
||||||
|
if rawget(val, 1) ~= nil or next(val) == nil then
|
||||||
|
-- Treat as array -- check keys are valid and it is not sparse
|
||||||
|
local n = 0
|
||||||
|
for k in pairs(val) do
|
||||||
|
if type(k) ~= 'number' then
|
||||||
|
error("invalid table: mixed or invalid key types")
|
||||||
|
end
|
||||||
|
n = n + 1
|
||||||
|
end
|
||||||
|
if n ~= #val then error("invalid table: sparse array") end
|
||||||
|
-- Encode
|
||||||
|
for _, v in ipairs(val) do ins(res, _encode(v, stack)) end
|
||||||
|
stack[val] = nil
|
||||||
|
return "[" .. table.concat(res, ",") .. "]"
|
||||||
|
|
||||||
|
else
|
||||||
|
-- Treat as an object
|
||||||
|
for k, v in pairs(val) do
|
||||||
|
if type(k) ~= 'string' then
|
||||||
|
error("invalid table: mixed or invalid key types")
|
||||||
|
end
|
||||||
|
ins(res, _encode(k, stack) .. ":" .. _encode(v, stack))
|
||||||
|
end
|
||||||
|
stack[val] = nil
|
||||||
|
return "{" .. table.concat(res, ",") .. "}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function encode_string(val)
|
||||||
|
return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
|
||||||
|
end
|
||||||
|
|
||||||
|
local function encode_number(val)
|
||||||
|
-- Check for NaN, -inf and inf
|
||||||
|
if val ~= val or val <= -math.huge or val >= 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
|
||||||
57
Zframework/languages.lua
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
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
|
||||||
20
Zframework/log.lua
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
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
|
||||||
26
Zframework/lowcaser.txt
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
A=a,B=b,C=c,D=d,E=e,F=f,G=g,H=h,I=i,J=j,K=k,L=l,M=m,N=n,O=o,P=p,Q=q,R=r,S=s,T=t,U=u,V=v,W=w,X=x,Y=y,Z=z
|
||||||
|
Μ=µ,ẞ=ß,À=à,Á=á,Â=â,Ã=ã,Ä=ä,Å=å,Æ=æ,Ç=ç,È=è,É=é,Ê=ê,Ë=ë,Ì=ì,Í=í,Î=î,Ï=ï,Ð=ð,Ñ=ñ,Ò=ò,Ó=ó,Ô=ô,Õ=õ,Ö=ö,Ø=ø,Ù=ù,Ú=ú,Û=û,Ü=ü,Ý=ý,Þ=þ,Ÿ=ÿ,Ā=ā,Ă=ă,Ą=ą,Ć=ć,Ĉ=ĉ,Ċ=ċ,Č=č,Ď=ď,Đ=đ,Ē=ē,Ĕ=ĕ,Ė=ė,Ę=ę,Ě=ě,Ĝ=ĝ,Ğ=ğ,Ġ=ġ,Ģ=ģ,Ĥ=ĥ,Ħ=ħ,Ĩ=ĩ,Ī=ī,Ĭ=ĭ,Į=į,IJ=ij,Ĵ=ĵ,Ķ=ķ,Ĺ=ĺ,Ļ=ļ,Ľ=ľ,Ŀ=ŀ,Ł=ł,Ń=ń,Ņ=ņ,Ň=ň,Ŋ=ŋ,Ō=ō,Ŏ=ŏ,Ő=ő,Œ=œ,Ŕ=ŕ,Ŗ=ŗ,Ř=ř,Ś=ś,Ŝ=ŝ,Ş=ş,Š=š,Ţ=ţ,Ť=ť,Ŧ=ŧ,Ũ=ũ,Ū=ū,Ŭ=ŭ,Ů=ů,Ű=ű,Ų=ų,Ŵ=ŵ,Ŷ=ŷ,Ź=ź,Ż=ż,Ž=ž
|
||||||
|
Ƀ=ƀ,Ƃ=ƃ,Ƅ=ƅ,Ƈ=ƈ,Ƌ=ƌ,Ƒ=ƒ,Ƕ=ƕ,Ƙ=ƙ,Ƚ=ƚ,Ƞ=ƞ,Ơ=ơ,Ƣ=ƣ,Ƥ=ƥ,Ƨ=ƨ,Ƭ=ƭ,Ư=ư,Ƴ=ƴ,Ƶ=ƶ,Ƹ=ƹ,Ƽ=ƽ,Ƿ=ƿ,DŽ=dž,LJ=lj,NJ=nj,Ǎ=ǎ,Ǐ=ǐ,Ǒ=ǒ,Ǔ=ǔ,Ǖ=ǖ,Ǘ=ǘ,Ǚ=ǚ,Ǜ=ǜ,Ǝ=ǝ,Ǟ=ǟ,Ǡ=ǡ,Ǣ=ǣ,Ǥ=ǥ,Ǧ=ǧ,Ǩ=ǩ,Ǫ=ǫ,Ǭ=ǭ,Ǯ=ǯ,DZ=dz,Ǵ=ǵ,Ǹ=ǹ,Ǻ=ǻ,Ǽ=ǽ,Ǿ=ǿ,Ȁ=ȁ,Ȃ=ȃ,Ȅ=ȅ,Ȇ=ȇ,Ȉ=ȉ,Ȋ=ȋ,Ȍ=ȍ,Ȏ=ȏ,Ȑ=ȑ,Ȓ=ȓ,Ȕ=ȕ,Ȗ=ȗ,Ș=ș,Ț=ț,Ȝ=ȝ,Ȟ=ȟ,Ȣ=ȣ,Ȥ=ȥ,Ȧ=ȧ,Ȩ=ȩ,Ȫ=ȫ,Ȭ=ȭ,Ȯ=ȯ,Ȱ=ȱ,Ȳ=ȳ,Ȼ=ȼ,Ȿ=ȿ,Ɀ=ɀ,Ɂ=ɂ,Ɇ=ɇ,Ɉ=ɉ,Ɋ=ɋ,Ɍ=ɍ,Ɏ=ɏ
|
||||||
|
Ɐ=ɐ,Ɑ=ɑ,Ɒ=ɒ,Ɓ=ɓ,Ɔ=ɔ,Ɖ=ɖ,Ɗ=ɗ,Ə=ə,Ɛ=ɛ,Ɜ=ɜ,Ɠ=ɠ,Ɡ=ɡ,Ɣ=ɣ,Ɥ=ɥ,Ɦ=ɦ,Ɨ=ɨ,Ɩ=ɩ,Ɪ=ɪ,Ɫ=ɫ,Ɬ=ɬ,Ɯ=ɯ,Ɱ=ɱ,Ɲ=ɲ,Ɵ=ɵ,Ɽ=ɽ,Ʀ=ʀ,Ʂ=ʂ,Ʃ=ʃ,Ʇ=ʇ,Ʈ=ʈ,Ʉ=ʉ,Ʊ=ʊ,Ʋ=ʋ,Ʌ=ʌ,Ʒ=ʒ,Ʝ=ʝ,Ʞ=ʞ
|
||||||
|
Ͱ=ͱ,Ͳ=ͳ,Ͷ=ͷ,Ͻ=ͻ,Ͼ=ͼ,Ͽ=ͽ,Ά=ά,Έ=έ,Ή=ή,Ί=ί,Α=α,Β=β,Γ=γ,Δ=δ,Ε=ε,Ζ=ζ,Η=η,Θ=θ,Κ=κ,Λ=λ,Ν=ν,Ξ=ξ,Ο=ο,Π=π,Ρ=ρ,Σ=σ,Τ=τ,Υ=υ,Φ=φ,Χ=χ,Ψ=ψ,Ω=ω,Ϊ=ϊ,Ϋ=ϋ,Ό=ό,Ύ=ύ,Ώ=ώ,Ϗ=ϗ,Ϙ=ϙ,Ϛ=ϛ,Ϝ=ϝ,Ϟ=ϟ,Ϡ=ϡ,Ϣ=ϣ,Ϥ=ϥ,Ϧ=ϧ,Ϩ=ϩ,Ϫ=ϫ,Ϭ=ϭ,Ϯ=ϯ,Ϲ=ϲ,Ϳ=ϳ,Ϸ=ϸ,Ϻ=ϻ
|
||||||
|
А=а,Б=б,В=в,Г=г,Д=д,Е=е,Ж=ж,З=з,И=и,Й=й,К=к,Л=л,М=м,Н=н,О=о,П=п,Р=р,С=с,Т=т,У=у,Ф=ф,Х=х,Ц=ц,Ч=ч,Ш=ш,Щ=щ,Ъ=ъ,Ы=ы,Ь=ь,Э=э,Ю=ю,Я=я,Ѐ=ѐ,Ё=ё,Ђ=ђ,Ѓ=ѓ,Є=є,Ѕ=ѕ,І=і,Ї=ї,Ј=ј,Љ=љ,Њ=њ,Ћ=ћ,Ќ=ќ,Ѝ=ѝ,Ў=ў,Џ=џ,Ѡ=ѡ,Ѣ=ѣ,Ѥ=ѥ,Ѧ=ѧ,Ѩ=ѩ,Ѫ=ѫ,Ѭ=ѭ,Ѯ=ѯ,Ѱ=ѱ,Ѳ=ѳ,Ѵ=ѵ,Ѷ=ѷ,Ѹ=ѹ,Ѻ=ѻ,Ѽ=ѽ,Ѿ=ѿ,Ҁ=ҁ,Ҋ=ҋ,Ҍ=ҍ,Ҏ=ҏ,Ґ=ґ,Ғ=ғ,Ҕ=ҕ,Җ=җ,Ҙ=ҙ,Қ=қ,Ҝ=ҝ,Ҟ=ҟ,Ҡ=ҡ,Ң=ң,Ҥ=ҥ,Ҧ=ҧ,Ҩ=ҩ,Ҫ=ҫ,Ҭ=ҭ,Ү=ү,Ұ=ұ,Ҳ=ҳ,Ҵ=ҵ,Ҷ=ҷ,Ҹ=ҹ,Һ=һ,Ҽ=ҽ,Ҿ=ҿ,Ӂ=ӂ,Ӄ=ӄ,Ӆ=ӆ,Ӈ=ӈ,Ӊ=ӊ,Ӌ=ӌ,Ӎ=ӎ,Ӏ=ӏ,Ӑ=ӑ,Ӓ=ӓ,Ӕ=ӕ,Ӗ=ӗ,Ә=ә,Ӛ=ӛ,Ӝ=ӝ,Ӟ=ӟ,Ӡ=ӡ,Ӣ=ӣ,Ӥ=ӥ,Ӧ=ӧ,Ө=ө,Ӫ=ӫ,Ӭ=ӭ,Ӯ=ӯ,Ӱ=ӱ,Ӳ=ӳ,Ӵ=ӵ,Ӷ=ӷ,Ӹ=ӹ,Ӻ=ӻ,Ӽ=ӽ,Ӿ=ӿ,Ԁ=ԁ,Ԃ=ԃ,Ԅ=ԅ,Ԇ=ԇ,Ԉ=ԉ,Ԋ=ԋ,Ԍ=ԍ,Ԏ=ԏ,Ԑ=ԑ,Ԓ=ԓ,Ԕ=ԕ,Ԗ=ԗ,Ԙ=ԙ,Ԛ=ԛ,Ԝ=ԝ,Ԟ=ԟ,Ԡ=ԡ,Ԣ=ԣ,Ԥ=ԥ,Ԧ=ԧ,Ԩ=ԩ,Ԫ=ԫ,Ԭ=ԭ,Ԯ=ԯ
|
||||||
|
Ա=ա,Բ=բ,Գ=գ,Դ=դ,Ե=ե,Զ=զ,Է=է,Ը=ը,Թ=թ,Ժ=ժ,Ի=ի,Լ=լ,Խ=խ,Ծ=ծ,Կ=կ,Հ=հ,Ձ=ձ,Ղ=ղ,Ճ=ճ,Մ=մ,Յ=յ,Ն=ն,Շ=շ,Ո=ո,Չ=չ,Պ=պ,Ջ=ջ,Ռ=ռ,Ս=ս,Վ=վ,Տ=տ,Ր=ր,Ց=ց,Ւ=ւ,Փ=փ,Ք=ք,Օ=օ,Ֆ=ֆ
|
||||||
|
Ა=ა,Ბ=ბ,Გ=გ,Დ=დ,Ე=ე,Ვ=ვ,Ზ=ზ,Თ=თ,Ი=ი,Კ=კ,Ლ=ლ,Მ=მ,Ნ=ნ,Ო=ო,Პ=პ,Ჟ=ჟ,Რ=რ,Ს=ს,Ტ=ტ,Უ=უ,Ფ=ფ,Ქ=ქ,Ღ=ღ,Ყ=ყ,Შ=შ,Ჩ=ჩ,Ც=ც,Ძ=ძ,Წ=წ,Ჭ=ჭ,Ხ=ხ,Ჯ=ჯ,Ჰ=ჰ,Ჱ=ჱ,Ჲ=ჲ,Ჳ=ჳ,Ჴ=ჴ,Ჵ=ჵ,Ჶ=ჶ,Ჷ=ჷ,Ჸ=ჸ,Ჹ=ჹ,Ჺ=ჺ,Ჽ=ჽ,Ჾ=ჾ,Ჿ=ჿ
|
||||||
|
Ᏸ=ᏸ,Ᏹ=ᏹ,Ᏺ=ᏺ,Ᏻ=ᏻ,Ᏼ=ᏼ,Ᏽ=ᏽ
|
||||||
|
Ꙋ=ᲈ,Ᵹ=ᵹ,Ᵽ=ᵽ,Ᶎ=ᶎ,Ḁ=ḁ,Ḃ=ḃ,Ḅ=ḅ,Ḇ=ḇ,Ḉ=ḉ,Ḋ=ḋ,Ḍ=ḍ,Ḏ=ḏ,Ḑ=ḑ,Ḓ=ḓ,Ḕ=ḕ,Ḗ=ḗ,Ḙ=ḙ,Ḛ=ḛ,Ḝ=ḝ,Ḟ=ḟ,Ḡ=ḡ,Ḣ=ḣ,Ḥ=ḥ,Ḧ=ḧ,Ḩ=ḩ,Ḫ=ḫ,Ḭ=ḭ,Ḯ=ḯ,Ḱ=ḱ,Ḳ=ḳ,Ḵ=ḵ,Ḷ=ḷ,Ḹ=ḹ,Ḻ=ḻ,Ḽ=ḽ,Ḿ=ḿ,Ṁ=ṁ,Ṃ=ṃ,Ṅ=ṅ,Ṇ=ṇ,Ṉ=ṉ,Ṋ=ṋ,Ṍ=ṍ,Ṏ=ṏ,Ṑ=ṑ,Ṓ=ṓ,Ṕ=ṕ,Ṗ=ṗ,Ṙ=ṙ,Ṛ=ṛ,Ṝ=ṝ,Ṟ=ṟ,Ṡ=ṡ,Ṣ=ṣ,Ṥ=ṥ,Ṧ=ṧ,Ṩ=ṩ,Ṫ=ṫ,Ṭ=ṭ,Ṯ=ṯ,Ṱ=ṱ,Ṳ=ṳ,Ṵ=ṵ,Ṷ=ṷ,Ṹ=ṹ,Ṻ=ṻ,Ṽ=ṽ,Ṿ=ṿ,Ẁ=ẁ,Ẃ=ẃ,Ẅ=ẅ,Ẇ=ẇ,Ẉ=ẉ,Ẋ=ẋ,Ẍ=ẍ,Ẏ=ẏ,Ẑ=ẑ,Ẓ=ẓ,Ẕ=ẕ,Ạ=ạ,Ả=ả,Ấ=ấ,Ầ=ầ,Ẩ=ẩ,Ẫ=ẫ,Ậ=ậ,Ắ=ắ,Ằ=ằ,Ẳ=ẳ,Ẵ=ẵ,Ặ=ặ,Ẹ=ẹ,Ẻ=ẻ,Ẽ=ẽ,Ế=ế,Ề=ề,Ể=ể,Ễ=ễ,Ệ=ệ,Ỉ=ỉ,Ị=ị,Ọ=ọ,Ỏ=ỏ,Ố=ố,Ồ=ồ,Ổ=ổ,Ỗ=ỗ,Ộ=ộ,Ớ=ớ,Ờ=ờ,Ở=ở,Ỡ=ỡ,Ợ=ợ,Ụ=ụ,Ủ=ủ,Ứ=ứ,Ừ=ừ,Ử=ử,Ữ=ữ,Ự=ự,Ỳ=ỳ,Ỵ=ỵ,Ỷ=ỷ,Ỹ=ỹ,Ỻ=ỻ,Ỽ=ỽ,Ỿ=ỿ,Ἀ=ἀ,Ἁ=ἁ,Ἂ=ἂ,Ἃ=ἃ,Ἄ=ἄ,Ἅ=ἅ,Ἆ=ἆ,Ἇ=ἇ,Ἐ=ἐ,Ἑ=ἑ,Ἒ=ἒ,Ἓ=ἓ,Ἔ=ἔ,Ἕ=ἕ,Ἠ=ἠ,Ἡ=ἡ,Ἢ=ἢ,Ἣ=ἣ,Ἤ=ἤ,Ἥ=ἥ,Ἦ=ἦ,Ἧ=ἧ,Ἰ=ἰ,Ἱ=ἱ,Ἲ=ἲ,Ἳ=ἳ,Ἴ=ἴ,Ἵ=ἵ,Ἶ=ἶ,Ἷ=ἷ,Ὀ=ὀ,Ὁ=ὁ,Ὂ=ὂ,Ὃ=ὃ,Ὄ=ὄ,Ὅ=ὅ,Ὑ=ὑ,Ὓ=ὓ,Ὕ=ὕ,Ὗ=ὗ,Ὠ=ὠ,Ὡ=ὡ,Ὢ=ὢ,Ὣ=ὣ,Ὤ=ὤ,Ὥ=ὥ,Ὦ=ὦ,Ὧ=ὧ,Ὰ=ὰ,Ά=ά,Ὲ=ὲ,Έ=έ,Ὴ=ὴ,Ή=ή,Ὶ=ὶ,Ί=ί,Ὸ=ὸ,Ό=ό,Ὺ=ὺ,Ύ=ύ,Ὼ=ὼ,Ώ=ώ,Ᾰ=ᾰ,Ᾱ=ᾱ,Ῐ=ῐ,Ῑ=ῑ,Ῠ=ῠ,Ῡ=ῡ,Ῥ=ῥ,Ⅎ=ⅎ
|
||||||
|
Ⅰ=ⅰ,Ⅱ=ⅱ,Ⅲ=ⅲ,Ⅳ=ⅳ,Ⅴ=ⅴ,Ⅵ=ⅵ,Ⅶ=ⅶ,Ⅷ=ⅷ,Ⅸ=ⅸ,Ⅹ=ⅹ,Ⅺ=ⅺ,Ⅻ=ⅻ,Ⅼ=ⅼ,Ⅽ=ⅽ,Ⅾ=ⅾ,Ⅿ=ⅿ,Ↄ=ↄ
|
||||||
|
Ⓐ=ⓐ,Ⓑ=ⓑ,Ⓒ=ⓒ,Ⓓ=ⓓ,Ⓔ=ⓔ,Ⓕ=ⓕ,Ⓖ=ⓖ,Ⓗ=ⓗ,Ⓘ=ⓘ,Ⓙ=ⓙ,Ⓚ=ⓚ,Ⓛ=ⓛ,Ⓜ=ⓜ,Ⓝ=ⓝ,Ⓞ=ⓞ,Ⓟ=ⓟ,Ⓠ=ⓠ,Ⓡ=ⓡ,Ⓢ=ⓢ,Ⓣ=ⓣ,Ⓤ=ⓤ,Ⓥ=ⓥ,Ⓦ=ⓦ,Ⓧ=ⓧ,Ⓨ=ⓨ,Ⓩ=ⓩ
|
||||||
|
Ⰰ=ⰰ,Ⰱ=ⰱ,Ⰲ=ⰲ,Ⰳ=ⰳ,Ⰴ=ⰴ,Ⰵ=ⰵ,Ⰶ=ⰶ,Ⰷ=ⰷ,Ⰸ=ⰸ,Ⰹ=ⰹ,Ⰺ=ⰺ,Ⰻ=ⰻ,Ⰼ=ⰼ,Ⰽ=ⰽ,Ⰾ=ⰾ,Ⰿ=ⰿ,Ⱀ=ⱀ,Ⱁ=ⱁ,Ⱂ=ⱂ,Ⱃ=ⱃ,Ⱄ=ⱄ,Ⱅ=ⱅ,Ⱆ=ⱆ,Ⱇ=ⱇ,Ⱈ=ⱈ,Ⱉ=ⱉ,Ⱊ=ⱊ,Ⱋ=ⱋ,Ⱌ=ⱌ,Ⱍ=ⱍ,Ⱎ=ⱎ,Ⱏ=ⱏ,Ⱐ=ⱐ,Ⱑ=ⱑ,Ⱒ=ⱒ,Ⱓ=ⱓ,Ⱔ=ⱔ,Ⱕ=ⱕ,Ⱖ=ⱖ,Ⱗ=ⱗ,Ⱘ=ⱘ,Ⱙ=ⱙ,Ⱚ=ⱚ,Ⱛ=ⱛ,Ⱜ=ⱜ,Ⱝ=ⱝ,Ⱞ=ⱞ,Ⱟ=ⱟ
|
||||||
|
Ⱡ=ⱡ,Ⱥ=ⱥ,Ⱦ=ⱦ,Ⱨ=ⱨ,Ⱪ=ⱪ,Ⱬ=ⱬ,Ⱳ=ⱳ,Ⱶ=ⱶ
|
||||||
|
Ⲁ=ⲁ,Ⲃ=ⲃ,Ⲅ=ⲅ,Ⲇ=ⲇ,Ⲉ=ⲉ,Ⲋ=ⲋ,Ⲍ=ⲍ,Ⲏ=ⲏ,Ⲑ=ⲑ,Ⲓ=ⲓ,Ⲕ=ⲕ,Ⲗ=ⲗ,Ⲙ=ⲙ,Ⲛ=ⲛ,Ⲝ=ⲝ,Ⲟ=ⲟ,Ⲡ=ⲡ,Ⲣ=ⲣ,Ⲥ=ⲥ,Ⲧ=ⲧ,Ⲩ=ⲩ,Ⲫ=ⲫ,Ⲭ=ⲭ,Ⲯ=ⲯ,Ⲱ=ⲱ,Ⲳ=ⲳ,Ⲵ=ⲵ,Ⲷ=ⲷ,Ⲹ=ⲹ,Ⲻ=ⲻ,Ⲽ=ⲽ,Ⲿ=ⲿ,Ⳁ=ⳁ,Ⳃ=ⳃ,Ⳅ=ⳅ,Ⳇ=ⳇ,Ⳉ=ⳉ,Ⳋ=ⳋ,Ⳍ=ⳍ,Ⳏ=ⳏ,Ⳑ=ⳑ,Ⳓ=ⳓ,Ⳕ=ⳕ,Ⳗ=ⳗ,Ⳙ=ⳙ,Ⳛ=ⳛ,Ⳝ=ⳝ,Ⳟ=ⳟ,Ⳡ=ⳡ,Ⳣ=ⳣ,Ⳬ=ⳬ,Ⳮ=ⳮ,Ⳳ=ⳳ
|
||||||
|
Ⴀ=ⴀ,Ⴁ=ⴁ,Ⴂ=ⴂ,Ⴃ=ⴃ,Ⴄ=ⴄ,Ⴅ=ⴅ,Ⴆ=ⴆ,Ⴇ=ⴇ,Ⴈ=ⴈ,Ⴉ=ⴉ,Ⴊ=ⴊ,Ⴋ=ⴋ,Ⴌ=ⴌ,Ⴍ=ⴍ,Ⴎ=ⴎ,Ⴏ=ⴏ,Ⴐ=ⴐ,Ⴑ=ⴑ,Ⴒ=ⴒ,Ⴓ=ⴓ,Ⴔ=ⴔ,Ⴕ=ⴕ,Ⴖ=ⴖ,Ⴗ=ⴗ,Ⴘ=ⴘ,Ⴙ=ⴙ,Ⴚ=ⴚ,Ⴛ=ⴛ,Ⴜ=ⴜ,Ⴝ=ⴝ,Ⴞ=ⴞ,Ⴟ=ⴟ,Ⴠ=ⴠ,Ⴡ=ⴡ,Ⴢ=ⴢ,Ⴣ=ⴣ,Ⴤ=ⴤ,Ⴥ=ⴥ,Ⴧ=ⴧ
|
||||||
|
Ⴭ=ⴭ,Ꙁ=ꙁ,Ꙃ=ꙃ,Ꙅ=ꙅ,Ꙇ=ꙇ,Ꙉ=ꙉ,Ꙍ=ꙍ,Ꙏ=ꙏ,Ꙑ=ꙑ,Ꙓ=ꙓ,Ꙕ=ꙕ,Ꙗ=ꙗ,Ꙙ=ꙙ,Ꙛ=ꙛ,Ꙝ=ꙝ,Ꙟ=ꙟ,Ꙡ=ꙡ,Ꙣ=ꙣ,Ꙥ=ꙥ,Ꙧ=ꙧ,Ꙩ=ꙩ,Ꙫ=ꙫ,Ꙭ=ꙭ,Ꚁ=ꚁ,Ꚃ=ꚃ,Ꚅ=ꚅ,Ꚇ=ꚇ,Ꚉ=ꚉ,Ꚋ=ꚋ,Ꚍ=ꚍ,Ꚏ=ꚏ,Ꚑ=ꚑ,Ꚓ=ꚓ,Ꚕ=ꚕ,Ꚗ=ꚗ,Ꚙ=ꚙ,Ꚛ=ꚛ,Ꜣ=ꜣ,Ꜥ=ꜥ,Ꜧ=ꜧ,Ꜩ=ꜩ,Ꜫ=ꜫ,Ꜭ=ꜭ,Ꜯ=ꜯ,Ꜳ=ꜳ,Ꜵ=ꜵ,Ꜷ=ꜷ,Ꜹ=ꜹ,Ꜻ=ꜻ,Ꜽ=ꜽ,Ꜿ=ꜿ,Ꝁ=ꝁ,Ꝃ=ꝃ,Ꝅ=ꝅ,Ꝇ=ꝇ,Ꝉ=ꝉ,Ꝋ=ꝋ,Ꝍ=ꝍ,Ꝏ=ꝏ,Ꝑ=ꝑ,Ꝓ=ꝓ,Ꝕ=ꝕ,Ꝗ=ꝗ,Ꝙ=ꝙ,Ꝛ=ꝛ,Ꝝ=ꝝ,Ꝟ=ꝟ,Ꝡ=ꝡ,Ꝣ=ꝣ,Ꝥ=ꝥ,Ꝧ=ꝧ,Ꝩ=ꝩ,Ꝫ=ꝫ,Ꝭ=ꝭ,Ꝯ=ꝯ,Ꝺ=ꝺ,Ꝼ=ꝼ,Ꝿ=ꝿ,Ꞁ=ꞁ,Ꞃ=ꞃ,Ꞅ=ꞅ,Ꞇ=ꞇ,Ꞌ=ꞌ,Ꞑ=ꞑ,Ꞓ=ꞓ,Ꞔ=ꞔ,Ꞗ=ꞗ,Ꞙ=ꞙ,Ꞛ=ꞛ,Ꞝ=ꞝ,Ꞟ=ꞟ,Ꞡ=ꞡ,Ꞣ=ꞣ,Ꞥ=ꞥ,Ꞧ=ꞧ,Ꞩ=ꞩ,Ꞵ=ꞵ,Ꞷ=ꞷ,Ꞹ=ꞹ,Ꞻ=ꞻ,Ꞽ=ꞽ,Ꞿ=ꞿ,Ꟁ=ꟁ,Ꟃ=ꟃ,Ꟈ=ꟈ,Ꟊ=ꟊ,Ꟑ=ꟑ,Ꟗ=ꟗ,Ꟙ=ꟙ,Ꟶ=ꟶ,Ꭓ=ꭓ
|
||||||
|
Ꭰ=ꭰ,Ꭱ=ꭱ,Ꭲ=ꭲ,Ꭳ=ꭳ,Ꭴ=ꭴ,Ꭵ=ꭵ,Ꭶ=ꭶ,Ꭷ=ꭷ,Ꭸ=ꭸ,Ꭹ=ꭹ,Ꭺ=ꭺ,Ꭻ=ꭻ,Ꭼ=ꭼ,Ꭽ=ꭽ,Ꭾ=ꭾ,Ꭿ=ꭿ,Ꮀ=ꮀ,Ꮁ=ꮁ,Ꮂ=ꮂ,Ꮃ=ꮃ,Ꮄ=ꮄ,Ꮅ=ꮅ,Ꮆ=ꮆ,Ꮇ=ꮇ,Ꮈ=ꮈ,Ꮉ=ꮉ,Ꮊ=ꮊ,Ꮋ=ꮋ,Ꮌ=ꮌ,Ꮍ=ꮍ,Ꮎ=ꮎ,Ꮏ=ꮏ,Ꮐ=ꮐ,Ꮑ=ꮑ,Ꮒ=ꮒ,Ꮓ=ꮓ,Ꮔ=ꮔ,Ꮕ=ꮕ,Ꮖ=ꮖ,Ꮗ=ꮗ,Ꮘ=ꮘ,Ꮙ=ꮙ,Ꮚ=ꮚ,Ꮛ=ꮛ,Ꮜ=ꮜ,Ꮝ=ꮝ,Ꮞ=ꮞ,Ꮟ=ꮟ,Ꮠ=ꮠ,Ꮡ=ꮡ,Ꮢ=ꮢ,Ꮣ=ꮣ,Ꮤ=ꮤ,Ꮥ=ꮥ,Ꮦ=ꮦ,Ꮧ=ꮧ,Ꮨ=ꮨ,Ꮩ=ꮩ,Ꮪ=ꮪ,Ꮫ=ꮫ,Ꮬ=ꮬ,Ꮭ=ꮭ,Ꮮ=ꮮ,Ꮯ=ꮯ,Ꮰ=ꮰ,Ꮱ=ꮱ,Ꮲ=ꮲ,Ꮳ=ꮳ,Ꮴ=ꮴ,Ꮵ=ꮵ,Ꮶ=ꮶ,Ꮷ=ꮷ,Ꮸ=ꮸ,Ꮹ=ꮹ,Ꮺ=ꮺ,Ꮻ=ꮻ,Ꮼ=ꮼ,Ꮽ=ꮽ,Ꮾ=ꮾ,Ꮿ=ꮿ
|
||||||
|
A=a,B=b,C=c,D=d,E=e,F=f,G=g,H=h,I=i,J=j,K=k,L=l,M=m,N=n,O=o,P=p,Q=q,R=r,S=s,T=t,U=u,V=v,W=w,X=x,Y=y,Z=z
|
||||||
|
𐐀=𐐨,𐐁=𐐩,𐐂=𐐪,𐐃=𐐫,𐐄=𐐬,𐐅=𐐭,𐐆=𐐮,𐐇=𐐯,𐐈=𐐰,𐐉=𐐱,𐐊=𐐲,𐐋=𐐳,𐐌=𐐴,𐐍=𐐵,𐐎=𐐶,𐐏=𐐷,𐐐=𐐸,𐐑=𐐹,𐐒=𐐺,𐐓=𐐻,𐐔=𐐼,𐐕=𐐽,𐐖=𐐾,𐐗=𐐿,𐐘=𐑀,𐐙=𐑁,𐐚=𐑂,𐐛=𐑃,𐐜=𐑄,𐐝=𐑅,𐐞=𐑆,𐐟=𐑇,𐐠=𐑈,𐐡=𐑉,𐐢=𐑊,𐐣=𐑋,𐐤=𐑌,𐐥=𐑍,𐐦=𐑎,𐐧=𐑏
|
||||||
|
𐒰=𐓘,𐒱=𐓙,𐒲=𐓚,𐒳=𐓛,𐒴=𐓜,𐒵=𐓝,𐒶=𐓞,𐒷=𐓟,𐒸=𐓠,𐒹=𐓡,𐒺=𐓢,𐒻=𐓣,𐒼=𐓤,𐒽=𐓥,𐒾=𐓦,𐒿=𐓧,𐓀=𐓨,𐓁=𐓩,𐓂=𐓪,𐓃=𐓫,𐓄=𐓬,𐓅=𐓭,𐓆=𐓮,𐓇=𐓯,𐓈=𐓰,𐓉=𐓱,𐓊=𐓲,𐓋=𐓳,𐓌=𐓴,𐓍=𐓵,𐓎=𐓶,𐓏=𐓷,𐓐=𐓸,𐓑=𐓹,𐓒=𐓺,𐓓=𐓻
|
||||||
|
𐲀=𐳀,𐲁=𐳁,𐲂=𐳂,𐲃=𐳃,𐲄=𐳄,𐲅=𐳅,𐲆=𐳆,𐲇=𐳇,𐲈=𐳈,𐲉=𐳉,𐲊=𐳊,𐲋=𐳋,𐲌=𐳌,𐲍=𐳍,𐲎=𐳎,𐲏=𐳏,𐲐=𐳐,𐲑=𐳑,𐲒=𐳒,𐲓=𐳓,𐲔=𐳔,𐲕=𐳕,𐲖=𐳖,𐲗=𐳗,𐲘=𐳘,𐲙=𐳙,𐲚=𐳚,𐲛=𐳛,𐲜=𐳜,𐲝=𐳝,𐲞=𐳞,𐲟=𐳟,𐲠=𐳠,𐲡=𐳡,𐲢=𐳢,𐲣=𐳣,𐲤=𐳤,𐲥=𐳥,𐲦=𐳦,𐲧=𐳧,𐲨=𐳨,𐲩=𐳩,𐲪=𐳪,𐲫=𐳫,𐲬=𐳬,𐲭=𐳭,𐲮=𐳮,𐲯=𐳯,𐲰=𐳰,𐲱=𐳱,𐲲=𐳲
|
||||||
|
𑢠=𑣀,𑢡=𑣁,𑢢=𑣂,𑢣=𑣃,𑢤=𑣄,𑢥=𑣅,𑢦=𑣆,𑢧=𑣇,𑢨=𑣈,𑢩=𑣉,𑢪=𑣊,𑢫=𑣋,𑢬=𑣌,𑢭=𑣍,𑢮=𑣎,𑢯=𑣏,𑢰=𑣐,𑢱=𑣑,𑢲=𑣒,𑢳=𑣓,𑢴=𑣔,𑢵=𑣕,𑢶=𑣖,𑢷=𑣗,𑢸=𑣘,𑢹=𑣙,𑢺=𑣚,𑢻=𑣛,𑢼=𑣜,𑢽=𑣝,𑢾=𑣞,𑢿=𑣟
|
||||||
|
𖹀=𖹠,𖹁=𖹡,𖹂=𖹢,𖹃=𖹣,𖹄=𖹤,𖹅=𖹥,𖹆=𖹦,𖹇=𖹧,𖹈=𖹨,𖹉=𖹩,𖹊=𖹪,𖹋=𖹫,𖹌=𖹬,𖹍=𖹭,𖹎=𖹮,𖹏=𖹯,𖹐=𖹰,𖹑=𖹱,𖹒=𖹲,𖹓=𖹳,𖹔=𖹴,𖹕=𖹵,𖹖=𖹶,𖹗=𖹷,𖹘=𖹸,𖹙=𖹹,𖹚=𖹺,𖹛=𖹻,𖹜=𖹼,𖹝=𖹽,𖹞=𖹾,𖹟=𖹿
|
||||||
|
𞤀=𞤢,𞤁=𞤣,𞤂=𞤤,𞤃=𞤥,𞤄=𞤦,𞤅=𞤧,𞤆=𞤨,𞤇=𞤩,𞤈=𞤪,𞤉=𞤫,𞤊=𞤬,𞤋=𞤭,𞤌=𞤮,𞤍=𞤯,𞤎=𞤰,𞤏=𞤱,𞤐=𞤲,𞤑=𞤳,𞤒=𞤴,𞤓=𞤵,𞤔=𞤶,𞤕=𞤷,𞤖=𞤸,𞤗=𞤹,𞤘=𞤺,𞤙=𞤻,𞤚=𞤼,𞤛=𞤽,𞤜=𞤾,𞤝=𞤿,𞤞=𞥀,𞤟=𞥁,𞤠=𞥂,𞤡=𞥃
|
||||||
|
İ=i̇,ʼN=ʼn,J̌=ǰ,Ϊ́=ΐ,Ϋ́=ΰ,ԵՒ=և,H̱=ẖ,T̈=ẗ,W̊=ẘ,Y̊=ẙ,Aʾ=ẚ,Υ̓=ὐ,Υ̓̀=ὒ,Υ̓́=ὔ,Υ̓͂=ὖ,ἈΙ=ᾀ,ἉΙ=ᾁ,ἊΙ=ᾂ,ἋΙ=ᾃ,ἌΙ=ᾄ,ἍΙ=ᾅ,ἎΙ=ᾆ,ἏΙ=ᾇ,ἨΙ=ᾐ,ἩΙ=ᾑ,ἪΙ=ᾒ,ἫΙ=ᾓ,ἬΙ=ᾔ,ἭΙ=ᾕ,ἮΙ=ᾖ,ἯΙ=ᾗ,ὨΙ=ᾠ,ὩΙ=ᾡ,ὪΙ=ᾢ,ὫΙ=ᾣ,ὬΙ=ᾤ,ὭΙ=ᾥ,ὮΙ=ᾦ,ὯΙ=ᾧ,ᾺΙ=ᾲ,ΑΙ=ᾳ,ΆΙ=ᾴ,Α͂=ᾶ,Α͂Ι=ᾷ,ῊΙ=ῂ,ΗΙ=ῃ,ΉΙ=ῄ,Η͂=ῆ,Η͂Ι=ῇ,Ϊ̀=ῒ,Ι͂=ῖ,Ϊ͂=ῗ,Ϋ̀=ῢ,Ρ̓=ῤ,Υ͂=ῦ,Ϋ͂=ῧ,ῺΙ=ῲ,ΩΙ=ῳ,ΏΙ=ῴ,Ω͂=ῶ,Ω͂Ι=ῷ,ՄՆ=ﬓ,ՄԵ=ﬔ,ՄԻ=ﬕ,ՎՆ=ﬖ,ՄԽ=ﬗ
|
||||||
88
Zframework/mathExtend.lua
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
local MATH={} for k,v in next,math do MATH[k]=v end
|
||||||
|
|
||||||
|
local floor,ceil=math.floor,math.ceil
|
||||||
|
local rnd=math.random
|
||||||
|
local exp=math.exp
|
||||||
|
|
||||||
|
MATH.tau=2*math.pi
|
||||||
|
MATH.phi=(1+math.sqrt(5))/2
|
||||||
|
MATH.inf=1/0
|
||||||
|
MATH.nan=0/0
|
||||||
|
|
||||||
|
function MATH.isnan(n)
|
||||||
|
return n~=n
|
||||||
|
end
|
||||||
|
|
||||||
|
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.clamp(v,low,high)
|
||||||
|
if v<=low then
|
||||||
|
return low
|
||||||
|
elseif v>=high then
|
||||||
|
return high
|
||||||
|
else
|
||||||
|
return v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function MATH.mix(s,e,t)
|
||||||
|
return s+(e-s)*t
|
||||||
|
end
|
||||||
|
|
||||||
|
do-- function MATH.listMix(list,t)
|
||||||
|
local clamp,mix=MATH.clamp,MATH.mix
|
||||||
|
function MATH.listMix(list,t)
|
||||||
|
local t2=(#list-1)*clamp(t,0,1)+1
|
||||||
|
return mix(list[floor(t2)],list[ceil(t2)],t2%1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function MATH.expApproach(a,b,k)
|
||||||
|
return b+(a-b)*exp(-k)
|
||||||
|
end
|
||||||
|
|
||||||
|
function MATH.distance(x1,y1,x2,y2)
|
||||||
|
return ((x1-x2)^2+(y1-y2)^2)^.5
|
||||||
|
end
|
||||||
|
|
||||||
|
-- By Pedro Gimeno,donated to the public domain
|
||||||
|
function MATH.pointInPolygon(x,y,poly,evenOddRule)
|
||||||
|
local x1,y1,x2,y2
|
||||||
|
local len=#poly
|
||||||
|
x2,y2=poly[len-1],poly[len]
|
||||||
|
local wn=0
|
||||||
|
for idx=1,len,2 do
|
||||||
|
x1,y1=x2,y2
|
||||||
|
x2,y2=poly[idx],poly[idx+1]
|
||||||
|
if y1>y then
|
||||||
|
if y2<=y and (x1-x)*(y2-y)<(x2-x)*(y1-y) then
|
||||||
|
wn=wn+1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if y2>y and (x1-x)*(y2-y)>(x2-x)*(y1-y) then
|
||||||
|
wn=wn-1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if evenOddRule then
|
||||||
|
return wn%2~=0
|
||||||
|
else-- non-zero winding rule
|
||||||
|
return wn~=0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return MATH
|
||||||
153
Zframework/message.lua
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
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},
|
||||||
|
other={.5,.5,.5,.7},
|
||||||
|
}
|
||||||
|
function MES.new(icon,str,time)
|
||||||
|
local color=backColors.other
|
||||||
|
if type(icon)=='string' then
|
||||||
|
color=TABLE.shift(backColors[icon] or color)
|
||||||
|
icon=mesIcon[icon]
|
||||||
|
end
|
||||||
|
local text=GC.newText(FONT.get(30),str)
|
||||||
|
local w=math.max(text:getWidth()+(icon and 45 or 5),200)+15
|
||||||
|
local h=math.max(text:getHeight(),46)+2
|
||||||
|
local k=h>400 and 1/math.min(h/400,2.6) or 1
|
||||||
|
|
||||||
|
ins(mesList,1,{
|
||||||
|
startTime=.26,
|
||||||
|
endTime=.26,
|
||||||
|
time=time or 3,
|
||||||
|
|
||||||
|
color=color,
|
||||||
|
text=text,icon=icon,
|
||||||
|
w=w,h=h,k=k,
|
||||||
|
y=-h,
|
||||||
|
})
|
||||||
|
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
|
||||||
|
if i>1 then
|
||||||
|
local _m=mesList[i-1]
|
||||||
|
m.y=MATH.expApproach(m.y,_m.y+_m.h*_m.k+3,dt*26)
|
||||||
|
else
|
||||||
|
m.y=MATH.expApproach(m.y,3,dt*26)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function MES.draw()
|
||||||
|
if #mesList>0 then
|
||||||
|
GC.setLineWidth(2)
|
||||||
|
for i=1,#mesList do
|
||||||
|
local m=mesList[i]
|
||||||
|
local a=3.846*(m.endTime-m.startTime)
|
||||||
|
GC.push('transform')
|
||||||
|
GC.translate(3+SCR.safeX,m.y)
|
||||||
|
GC.scale(m.k)
|
||||||
|
|
||||||
|
GC.setColor(m.color[1],m.color[2],m.color[3],m.color[4]*a)
|
||||||
|
GC.rectangle('fill',0,0,m.w,m.h,8)
|
||||||
|
GC.setColor(.62,.62,.62,a*.626)
|
||||||
|
GC.rectangle('line',1,1,m.w-2,m.h-2,4)
|
||||||
|
GC.setColor(1,1,1,a)
|
||||||
|
if m.icon then
|
||||||
|
GC.draw(m.icon,4,4,nil,40/m.icon:getWidth(),40/m.icon:getHeight())
|
||||||
|
end
|
||||||
|
GC.simpY(m.text,m.icon and 50 or 10,m.h/2)
|
||||||
|
GC.pop()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
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
|
||||||
157
Zframework/profile.lua
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
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 l1<l2 then
|
||||||
|
s=s..(" "):rep(l2-l1)
|
||||||
|
elseif l1>l2 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
|
||||||
47
Zframework/require.lua
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
package.cpath=package.cpath..';'..love.filesystem.getSaveDirectory()..'/lib/?.so;'..'?.dylib'
|
||||||
|
local loaded={}
|
||||||
|
local errorCount={}
|
||||||
|
return function(libName)
|
||||||
|
local require=require
|
||||||
|
local arch='unknown'
|
||||||
|
local success,res
|
||||||
|
if SYSTEM=='Web' then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if SYSTEM=='macOS' then
|
||||||
|
require=package.loadlib(libName..'.dylib','luaopen_'..libName)
|
||||||
|
success,res=pcall(require)
|
||||||
|
else
|
||||||
|
if SYSTEM=='Android' and not loaded[libName] then
|
||||||
|
local platform=(function()
|
||||||
|
local p=io.popen('uname -m')
|
||||||
|
arch=p:read('*a'):lower()
|
||||||
|
p:close()
|
||||||
|
if arch:find('v8') and not arch:find('v8l') or arch:find('64') then
|
||||||
|
return 'arm64-v8a'
|
||||||
|
else
|
||||||
|
return 'armeabi-v7a'
|
||||||
|
end
|
||||||
|
end)()
|
||||||
|
local data=love.filesystem.read('data','libAndroid/'..platform..'/'..libName..'.so')
|
||||||
|
if data then
|
||||||
|
love.filesystem.write('lib/'..libName..'.so',data)
|
||||||
|
end
|
||||||
|
loaded[libName]=true
|
||||||
|
end
|
||||||
|
success,res=pcall(require,libName)
|
||||||
|
end
|
||||||
|
if success and res then
|
||||||
|
return res
|
||||||
|
else
|
||||||
|
if not next(errorCount) then
|
||||||
|
MES.new('info',"Architecture: "..arch)
|
||||||
|
end
|
||||||
|
errorCount[libName]=(errorCount[libName] or 0)+1
|
||||||
|
if errorCount[libName]==1 then
|
||||||
|
MES.new('error',"Cannot load "..libName..": "..tostring(res):gsub('[\128-\255]+','??'))
|
||||||
|
else
|
||||||
|
MES.new('error',("Cannot load %s (x%d)"):format(libName,errorCount[libName]))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
223
Zframework/scene.lua
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
local scenes={}
|
||||||
|
|
||||||
|
local SCN={
|
||||||
|
mainTouchID=nil, -- First touching ID(userdata)
|
||||||
|
swapping=false, -- If Swapping
|
||||||
|
state={
|
||||||
|
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,
|
||||||
|
cur=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,
|
||||||
|
}-- 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.state
|
||||||
|
S.time=S.time-dt
|
||||||
|
if S.time<S.changeTime and S.time+dt>=S.changeTime then
|
||||||
|
-- Scene swapped this frame
|
||||||
|
SCN.stack[#SCN.stack]=S.tar
|
||||||
|
SCN.cur=S.tar
|
||||||
|
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]
|
||||||
|
|
||||||
|
WIDGET.setScrollHeight(S.widgetScrollHeight)
|
||||||
|
WIDGET.setWidgetList(S.widgetList)
|
||||||
|
SCN.enter=S.enter
|
||||||
|
SCN.leave=S.leave
|
||||||
|
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.update=S.update
|
||||||
|
SCN.draw=S.draw
|
||||||
|
if S.enter then
|
||||||
|
S.enter()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function SCN.push(tar)
|
||||||
|
table.insert(SCN.stack,tar or SCN.stack[#SCN.stack])
|
||||||
|
end
|
||||||
|
function SCN.pop()
|
||||||
|
table.remove(SCN.stack)
|
||||||
|
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-math.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-math.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-math.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 then
|
||||||
|
SCN.prev=SCN.stack[#SCN.stack]
|
||||||
|
|
||||||
|
style=style or 'fade'
|
||||||
|
SCN.swapping=true
|
||||||
|
SCN.args={...}
|
||||||
|
local S=SCN.state
|
||||||
|
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: "..tostring(tar))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function SCN.go(tar,style,...)-- Normal scene swapping, can back
|
||||||
|
if scenes[tar] then
|
||||||
|
if not SCN.swapping then
|
||||||
|
SCN.push(SCN.stack[#SCN.stack] or '_')
|
||||||
|
SCN.swapTo(tar,style,...)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
MES.new('warn',"No Scene: "..tar)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function SCN.back(style,...)
|
||||||
|
if SCN.swapping then return end
|
||||||
|
|
||||||
|
-- Leave scene
|
||||||
|
if SCN.leave then
|
||||||
|
SCN.leave()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Poll&Back to previous Scene
|
||||||
|
if #SCN.stack>1 then
|
||||||
|
SCN.pop()
|
||||||
|
SCN.swapTo(SCN.stack[#SCN.stack],style,...)
|
||||||
|
else
|
||||||
|
SCN.swapTo('quit','slowFade')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function SCN.backTo(tar,style,...)
|
||||||
|
if SCN.swapping then return end
|
||||||
|
|
||||||
|
-- Leave scene
|
||||||
|
if SCN.leave then
|
||||||
|
SCN.leave()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Poll&Back to previous Scene
|
||||||
|
while SCN.stack[#SCN.stack]~=tar and #SCN.stack>1 do
|
||||||
|
SCN.pop()
|
||||||
|
end
|
||||||
|
SCN.swapTo(SCN.stack[#SCN.stack],style,...)
|
||||||
|
end
|
||||||
|
function SCN.printStack()
|
||||||
|
for i=0,#SCN.stack+1 do print(SCN.stack[i] or "-------") end
|
||||||
|
end
|
||||||
|
|
||||||
|
return SCN
|
||||||
73
Zframework/screen.lua
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
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
|
||||||
169
Zframework/sfx.lua
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
local type,rem=type,table.remove
|
||||||
|
local floor,rnd=math.floor,math.random
|
||||||
|
|
||||||
|
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=floor(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=MATH.clamp(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
|
||||||
5675
Zframework/sha2.lua
Normal file
428
Zframework/stringExtend.lua
Normal file
@@ -0,0 +1,428 @@
|
|||||||
|
local data=love.data
|
||||||
|
local STRING={}
|
||||||
|
local assert,tostring,tonumber=assert,tostring,tonumber
|
||||||
|
local floorint,format=math.floor,string.format
|
||||||
|
local find,sub,gsub=string.find,string.sub,string.gsub
|
||||||
|
local rep,upper=string.rep,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
|
||||||
|
|
||||||
|
-- [LOW PERFORMANCE!]
|
||||||
|
local upperData,lowerData,diaData
|
||||||
|
function STRING.upperUTF8(str)
|
||||||
|
for _,pair in next,upperData do
|
||||||
|
str=str:gsub(pair[1],pair[2])
|
||||||
|
end
|
||||||
|
return str
|
||||||
|
end
|
||||||
|
function STRING.lowerUTF8(str)
|
||||||
|
for _,pair in next,lowerData do
|
||||||
|
str=str:gsub(pair[1],pair[2])
|
||||||
|
end
|
||||||
|
return str
|
||||||
|
end
|
||||||
|
function STRING.remDiacritics(str)
|
||||||
|
for _,pair in next,diaData do
|
||||||
|
str=str:gsub(pair[1],pair[2])
|
||||||
|
end
|
||||||
|
return str
|
||||||
|
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
|
||||||
|
|
||||||
|
local MINUTE=60
|
||||||
|
local HOUR=3600
|
||||||
|
local DAY=86400
|
||||||
|
local YEAR=31536000 -- 365 days
|
||||||
|
local function convertSecondsToUnits(t) -- convert seconds to {seconds, minutes, hours, days, years}
|
||||||
|
local years=floorint(t/YEAR)
|
||||||
|
local remainder=t%YEAR
|
||||||
|
|
||||||
|
local days=floorint(remainder/DAY)
|
||||||
|
remainder=remainder%DAY
|
||||||
|
|
||||||
|
local hours=floorint(remainder/HOUR)
|
||||||
|
remainder=remainder%HOUR
|
||||||
|
|
||||||
|
local minutes=floorint(remainder/MINUTE)
|
||||||
|
local seconds=remainder%MINUTE
|
||||||
|
return seconds,minutes,hours,days,years
|
||||||
|
end
|
||||||
|
|
||||||
|
-- MM:SS
|
||||||
|
function STRING.time_simp(t)
|
||||||
|
return format("%02d:%02d",floorint(t/MINUTE),floorint(t%MINUTE))
|
||||||
|
end
|
||||||
|
|
||||||
|
local timeLetters={' y',' d',' h',' m',' s',' ms'}
|
||||||
|
-- Display 2 largest units of time.
|
||||||
|
function STRING.time_short(t)
|
||||||
|
-- Early returns to prevent nil values
|
||||||
|
if t<0 then return '-'..STRING.time_short(-t) end -- negative time
|
||||||
|
if t<1 then return math.floor(t*1000)..timeLetters[6] end -- 123 ms
|
||||||
|
if t<MINUTE then return math.floor(t)..timeLetters[5]..' '..math.floor((t%1)*1000)..timeLetters[6] end -- 12s 345ms
|
||||||
|
|
||||||
|
local timeUnits=TABLE.reverse({convertSecondsToUnits(t)})
|
||||||
|
|
||||||
|
-- floor seconds
|
||||||
|
timeUnits[#timeUnits]=floorint(timeUnits[#timeUnits])
|
||||||
|
|
||||||
|
local outputStr=''
|
||||||
|
for i=1,#timeUnits do
|
||||||
|
if timeUnits>0 then
|
||||||
|
return timeUnits[i]..timeLetters[i]..' '..timeUnits[i+1]..timeLetters[i+1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function STRING.time(t)
|
||||||
|
local s,m,h,d,y=convertSecondsToUnits(t)
|
||||||
|
if t<MINUTE then
|
||||||
|
return format("%.3f″",t) -- example: 12.345″
|
||||||
|
elseif t<HOUR then
|
||||||
|
return format("%d′%05.2f″",m,s) -- 1′23.45″
|
||||||
|
elseif t<DAY then
|
||||||
|
return format("%d:%.2d′%04.1f″",h,m,s) -- 12:34′56.7″
|
||||||
|
elseif t<YEAR then
|
||||||
|
return format("%dd %d:%.2d′%.2d″",d,h,m,s) -- 123d 12:34′56″
|
||||||
|
else
|
||||||
|
return format("%dy %dd %d:%.2d′",y,d,h,m) -- 1y 234d 12:34′
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function STRING.time_ext(t)
|
||||||
|
local s,m,h,d,y=convertSecondsToUnits(t)
|
||||||
|
if t<MINUTE then
|
||||||
|
return format("%.5f″",t) -- 12.34567″
|
||||||
|
elseif t<HOUR then
|
||||||
|
return format("%d′%06.3f″",m,s) -- 1′23.456″
|
||||||
|
elseif t<DAY then
|
||||||
|
return format("%d:%.2d′%05.2f″",h,m,s) -- 12:34′56.78″
|
||||||
|
elseif t<YEAR then
|
||||||
|
return format("%dd %d:%.2d′%04.1f″",d,h,m,s) -- 123d 12:34′56.7″
|
||||||
|
else
|
||||||
|
return format("%dy %dd %d:%.2d′%.2d″",y,d,h,m,s) -- 1y 234d 12:34′56″
|
||||||
|
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+floorint(n/2^06),128+n%2^6)
|
||||||
|
elseif n<2^16 then return char(224+floorint(n/2^12),128+floorint(n/2^06)%2^6,128+n%2^6)
|
||||||
|
elseif n<2^21 then return char(240+floorint(n/2^18),128+floorint(n/2^12)%2^6,128+floorint(n/2^06)%2^6,128+n%2^6)
|
||||||
|
elseif n<2^26 then return char(248+floorint(n/2^24),128+floorint(n/2^18)%2^6,128+floorint(n/2^12)%2^6,128+floorint(n/2^06)%2^6,128+n%2^6)
|
||||||
|
elseif n<2^31 then return char(252+floorint(n/2^30),128+floorint(n/2^24)%2^6,128+floorint(n/2^18)%2^6,128+floorint(n/2^12)%2^6,128+floorint(n/2^06)%2^6,128+n%2^6)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
do-- functions to shorted big numbers
|
||||||
|
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=floorint(lg(t)/3)
|
||||||
|
return(t/10^(e*3))..units[e+1]
|
||||||
|
else
|
||||||
|
return "INF"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local MIN_SI=-30 -- current lowest order of magnitude for SI units (quecto-; 10^-30)
|
||||||
|
local MAX_SI=30 -- current highest order of magnitude for SI units (quetta-; 10^30)
|
||||||
|
local SI_SHORT={
|
||||||
|
[-30]='q',[-27]='r',[-24]='y',[-21]='z',[-18]='a',[-15]='f',[-12]='p',
|
||||||
|
[-9]='n',[-6]='μ',[-3]='m',[0]='',[3]='k',[6]='M',[9]='G',
|
||||||
|
[12]='T',[15]='P',[18]='E',[21]='Z',[24]='Y',[27]='R',[30]='Q'
|
||||||
|
}
|
||||||
|
local SI_LONG={
|
||||||
|
[-30]='quecto',[-27]='ronto',[-24]='yocto',[-21]='zepto',[-18]='atto',[-15]='femto',[-12]='pico',
|
||||||
|
[-9]='nano',[-6]='micro',[-3]='milli',[0]='',[3]='kilo',[6]='mega',[9]='giga',
|
||||||
|
[12]='tera',[15]='peta',[18]='exa',[21]='zetta',[24]='yotta',[27]='ronna',[30]='quetta'
|
||||||
|
}
|
||||||
|
--[[
|
||||||
|
Converts a number into SI notation with letter prefixes.
|
||||||
|
NOTE: Only power-of-thousand prefixes; no deci-/centi-.
|
||||||
|
Arguments:
|
||||||
|
- num: The number to be converted to SI notation.
|
||||||
|
- unit: [optional] The unit to be concatenated at the end.
|
||||||
|
Example: STRING.SI(10^-9,"m") --> "1 nm"
|
||||||
|
]]
|
||||||
|
function STRING.SI(num, unit)
|
||||||
|
unit=unit or ''
|
||||||
|
local order=MATH.clamp(3*math.floor(math.log10(num)/3),MIN_SI,MAX_SI)
|
||||||
|
local prefix=SI_SHORT[order]
|
||||||
|
local scaledNum=num/10^order
|
||||||
|
local formattedNum=string.format('%.3f', scaledNum):gsub('%.?0+$','')
|
||||||
|
return formattedNum.." "..prefix..unit
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Converts a number into SI notation with word prefixes.
|
||||||
|
NOTE: Only power-of-thousand prefixes; no deci-/centi-.
|
||||||
|
Arguments:
|
||||||
|
- num: The number to be converted to SI notation.
|
||||||
|
- unit: [optional] The unit to be concatenated at the end.
|
||||||
|
Example: STRING.SI(10^9,"hertz") --> "1 megahertz"
|
||||||
|
]]
|
||||||
|
function STRING.SILong(num, unit)
|
||||||
|
unit=unit or ''
|
||||||
|
local order=MATH.clamp(3*math.floor(math.log10(num)/3),MIN_SI,MAX_SI)
|
||||||
|
local prefix=SI_LONG[order]
|
||||||
|
local scaledNum=num/10^order
|
||||||
|
local formattedNum=string.format('%.3f', scaledNum):gsub('%.?0+$','')
|
||||||
|
return formattedNum.." "..prefix..unit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
do-- function STRING.toBin, STRING.toOct, STRING.toHex(n,len)
|
||||||
|
function STRING.toBin(n,len)
|
||||||
|
local s=""
|
||||||
|
while n>0 do
|
||||||
|
s=(n%2)..s
|
||||||
|
n=floorint(n/2)
|
||||||
|
end
|
||||||
|
if len then
|
||||||
|
return rep("0",len-#s)..s
|
||||||
|
else
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function STRING.toOct(n,len)
|
||||||
|
local s=""
|
||||||
|
while n>0 do
|
||||||
|
s=(n%8)..s
|
||||||
|
n=floorint(n/8)
|
||||||
|
end
|
||||||
|
if len then
|
||||||
|
return rep("0",len-#s)..s
|
||||||
|
else
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local b16={[0]='0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}
|
||||||
|
function STRING.toHex(n,len)
|
||||||
|
local s=""
|
||||||
|
while n>0 do
|
||||||
|
s=b16[n%16]..s
|
||||||
|
n=floorint(n/16)
|
||||||
|
end
|
||||||
|
if len then
|
||||||
|
return rep("0",len-#s)..s
|
||||||
|
else
|
||||||
|
return s
|
||||||
|
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
|
||||||
|
|
||||||
|
do
|
||||||
|
local function parseFile(fname)
|
||||||
|
local d
|
||||||
|
if love and love.filesystem and type(love.filesystem.read)=='function' then
|
||||||
|
d=love.filesystem.read(fname)
|
||||||
|
else
|
||||||
|
local f=io.open(fname,'r')
|
||||||
|
if f then
|
||||||
|
d=f:read('a')
|
||||||
|
f:close()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not d then
|
||||||
|
print("ERROR: Failed to read the data from "..fname)
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
d=STRING.split(gsub(d,'\n',','),',')
|
||||||
|
for i=1,#d do
|
||||||
|
d[i]=STRING.split(d[i],'=')
|
||||||
|
end
|
||||||
|
return d
|
||||||
|
end
|
||||||
|
upperData=parseFile('Zframework/upcaser.txt')
|
||||||
|
lowerData=parseFile('Zframework/lowcaser.txt')
|
||||||
|
diaData=parseFile('Zframework/diacritics.txt')
|
||||||
|
end
|
||||||
|
|
||||||
|
return STRING
|
||||||
205
Zframework/sysFX.lua
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
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
|
||||||
463
Zframework/tableExtend.lua
Normal file
@@ -0,0 +1,463 @@
|
|||||||
|
local rnd=math.random
|
||||||
|
local min,max=math.min,math.max
|
||||||
|
local find=string.find
|
||||||
|
local ins,rem=table.insert,table.remove
|
||||||
|
local next,type=next,type
|
||||||
|
local TABLE={}
|
||||||
|
|
||||||
|
-----------------------[Making Tables]------------------------
|
||||||
|
-- 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
|
||||||
|
|
||||||
|
-- Connect [1~#] elements of new to the end of org
|
||||||
|
function TABLE.connect(org,new)
|
||||||
|
local l0=#org
|
||||||
|
for i=1,#new do
|
||||||
|
org[l0+i]=new[i]
|
||||||
|
end
|
||||||
|
return org
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get a table of two lists connected
|
||||||
|
function TABLE.combine(L1,L2)
|
||||||
|
local l={}
|
||||||
|
local l0=#L1
|
||||||
|
for i=1,l0 do l[i]=L1[i] end
|
||||||
|
for i=1,#L2 do l[l0+i]=L2[i] end
|
||||||
|
return l
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------[Modifying Tables]----------------------
|
||||||
|
|
||||||
|
-- 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 org, delete them if it's in sub
|
||||||
|
function TABLE.subtract(org,sub)
|
||||||
|
for _,v in next,sub do
|
||||||
|
while true do
|
||||||
|
local p=TABLE.search(org,v)
|
||||||
|
if p then
|
||||||
|
rem(org,p)
|
||||||
|
else
|
||||||
|
break
|
||||||
|
end
|
||||||
|
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
|
||||||
|
|
||||||
|
-------------------[Removing Table Values]--------------------
|
||||||
|
|
||||||
|
-- Pop & return random [1~#] of table
|
||||||
|
function TABLE.popRandom(t)
|
||||||
|
local l=#t
|
||||||
|
if l>0 then
|
||||||
|
local r=rnd(l)
|
||||||
|
r,t[r]=t[r],t[l]
|
||||||
|
t[l]=nil
|
||||||
|
return r
|
||||||
|
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
|
||||||
|
|
||||||
|
--------------------[Handling duplicates]---------------------
|
||||||
|
|
||||||
|
-- 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
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Run length encoder. Input must be a list containing non-nil value(s).
|
||||||
|
Example:
|
||||||
|
- Input: {1, 1, 2, 2, 2, 1}
|
||||||
|
- Output: {{1, 2}, {2, 3}, {1, 1}}
|
||||||
|
- This means: "Two 1's in a row", "Three 2's in a row", "One 1 in a row"
|
||||||
|
]]
|
||||||
|
function TABLE.RLE(org)
|
||||||
|
local output={}
|
||||||
|
local cur=nil
|
||||||
|
local count=0
|
||||||
|
|
||||||
|
for i=1,#org do
|
||||||
|
local item=org[i]
|
||||||
|
|
||||||
|
if item==cur then
|
||||||
|
count=count+1
|
||||||
|
else
|
||||||
|
if cur then
|
||||||
|
ins(output,{cur,count})
|
||||||
|
end
|
||||||
|
cur=item
|
||||||
|
count=1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if cur then
|
||||||
|
ins(output,{cur,count})
|
||||||
|
end
|
||||||
|
|
||||||
|
return output
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------[Reversing Tables]----------------------
|
||||||
|
|
||||||
|
-- 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
|
||||||
|
|
||||||
|
----------------------[Table Comparison]----------------------
|
||||||
|
|
||||||
|
-- Check if tow list have same elements
|
||||||
|
function TABLE.compare(a,b)
|
||||||
|
if #a~=#b then return false end
|
||||||
|
if a==b then return true end
|
||||||
|
for i=1,#a do
|
||||||
|
if a[i]~=b[i] then return false end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if tow table have same elements
|
||||||
|
function TABLE.equal(a,b)
|
||||||
|
if #a~=#b then return false end
|
||||||
|
if a==b then return true end
|
||||||
|
for k,v in next,a do
|
||||||
|
if b[k]~=v then return false end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------[Table Operations]----------------------
|
||||||
|
|
||||||
|
-- Find value in [1~#], like string.find
|
||||||
|
function TABLE.find(t,val,start)
|
||||||
|
for i=start or 1,#t do if t[i]==val then return i end end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get subset of table, like string.sub
|
||||||
|
function TABLE.sub(t,i,j)
|
||||||
|
local subTable={}
|
||||||
|
for k=max(i,1),(j and min(j,#t) or #t) do
|
||||||
|
subTable[k-i+1]=t[k]
|
||||||
|
end
|
||||||
|
return subTable
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Replace value in [1~#], like string.gsub
|
||||||
|
function TABLE.gsub(t,v_old,v_new,count,start)
|
||||||
|
if not start then start=1 end
|
||||||
|
if not count then count=1e99 end
|
||||||
|
while t[start] and count>0 do
|
||||||
|
if t[start]==v_old then
|
||||||
|
t[start]=v_new
|
||||||
|
count=count-1
|
||||||
|
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
|
||||||
|
|
||||||
|
-- Replace all value in t
|
||||||
|
function TABLE.replace(t,v_old,v_new)
|
||||||
|
for k,v in next,t do
|
||||||
|
if v==v_old then
|
||||||
|
t[k]=v_new
|
||||||
|
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
|
||||||
|
|
||||||
|
-- Return table where keys and values are swapped (useful for hashmap)
|
||||||
|
function TABLE.kvSwap(t)
|
||||||
|
local output={}
|
||||||
|
for k,v in next,t do output[v]=k end
|
||||||
|
return output
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Extracts a value from each sub-table in table.
|
||||||
|
Example input: ({{name='A'},{name='B'},{name='C'}}, 'name')
|
||||||
|
Output: {'A','B'}
|
||||||
|
]]
|
||||||
|
function TABLE.extract(t,keyName)
|
||||||
|
local output={}
|
||||||
|
for k,v in next,t do output[k]=v[keyName] end
|
||||||
|
return output
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get element count of table
|
||||||
|
function TABLE.getSize(t)
|
||||||
|
local size=0
|
||||||
|
for _ in next,t do size=size+1 end
|
||||||
|
return size
|
||||||
|
end
|
||||||
|
|
||||||
|
-----------------------[Table Rotation]-----------------------
|
||||||
|
|
||||||
|
-- Copy a rotated matrix table
|
||||||
|
function TABLE.rotate(cb,dir)
|
||||||
|
local icb={}
|
||||||
|
if dir=='R' then-- Rotate CW
|
||||||
|
for y=1,#cb[1] do
|
||||||
|
icb[y]={}
|
||||||
|
for x=1,#cb do
|
||||||
|
icb[y][x]=cb[x][#cb[1]-y+1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif dir=='L' then-- Rotate CCW
|
||||||
|
for y=1,#cb[1] do
|
||||||
|
icb[y]={}
|
||||||
|
for x=1,#cb do
|
||||||
|
icb[y][x]=cb[#cb-x+1][y]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif dir=='F' then-- Rotate 180 degree
|
||||||
|
for y=1,#cb do
|
||||||
|
icb[y]={}
|
||||||
|
for x=1,#cb[1] do
|
||||||
|
icb[y][x]=cb[#cb-y+1][#cb[1]-x+1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return icb
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------[Table Functions]-----------------------
|
||||||
|
|
||||||
|
-- Return a function that return a value of table
|
||||||
|
function TABLE.func_getVal(t,k)
|
||||||
|
return function() return t[k] end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Return a function that reverse a value of table
|
||||||
|
function TABLE.func_revVal(t,k)
|
||||||
|
return function() t[k]=not t[k] end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Return a function that set a value of table
|
||||||
|
function TABLE.func_setVal(t,k)
|
||||||
|
return function(v) t[k]=v end
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------[Table Dump]-------------------------
|
||||||
|
|
||||||
|
-- Dump a simple lua table (no whitespaces)
|
||||||
|
do-- function TABLE.dumpDeflate(L,t)
|
||||||
|
local function dump(L)
|
||||||
|
if type(L)~='table' then return end
|
||||||
|
local s='{'
|
||||||
|
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 v='*'..tostring(v)
|
||||||
|
end
|
||||||
|
s=s..k..v..','
|
||||||
|
end
|
||||||
|
return s..'}'
|
||||||
|
end
|
||||||
|
TABLE.dumpDeflate=dump
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Dump a simple lua table
|
||||||
|
do-- function TABLE.dump(L,t)
|
||||||
|
local tabs=setmetatable({
|
||||||
|
[0]='',
|
||||||
|
'\t',
|
||||||
|
},{__index=function(self,k)
|
||||||
|
if k>=626 then error("Too many tabs!") end
|
||||||
|
for i=#self+1,k do
|
||||||
|
self[i]=self[i-1]..'\t'
|
||||||
|
end
|
||||||
|
return self[k]
|
||||||
|
end})
|
||||||
|
local function dump(L,t)
|
||||||
|
local s='{\n'
|
||||||
|
if not t then
|
||||||
|
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 k='[\'*'..tostring(k)..'\']='
|
||||||
|
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 v='*'..tostring(v)
|
||||||
|
end
|
||||||
|
s=s..tabs[t]..k..v..',\n'
|
||||||
|
end
|
||||||
|
return s..tabs[t-1]..'}'
|
||||||
|
end
|
||||||
|
TABLE.dump=dump
|
||||||
|
end
|
||||||
|
|
||||||
|
return TABLE
|
||||||
83
Zframework/task.lua
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
local rem=table.remove
|
||||||
|
local assert,resume,status=assert,coroutine.resume,coroutine.status
|
||||||
|
local rawset=rawset
|
||||||
|
local timer=love.timer.getTime
|
||||||
|
|
||||||
|
local TASK={}
|
||||||
|
|
||||||
|
-- Locks
|
||||||
|
local locks=setmetatable({},{
|
||||||
|
__index=function(self,k) rawset(self,k,-1e99)return -1e99 end,
|
||||||
|
__newindex=function(self,k) rawset(self,k,-1e99) end,
|
||||||
|
})
|
||||||
|
function TASK.lock(name,T)
|
||||||
|
if timer()>=locks[name] then
|
||||||
|
locks[name]=timer()+(T or 1e99)
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function TASK.unlock(name)
|
||||||
|
locks[name]=-1e99
|
||||||
|
end
|
||||||
|
function TASK.getLock(name)
|
||||||
|
local v=locks[name]-timer()
|
||||||
|
return v>0 and v
|
||||||
|
end
|
||||||
|
function TASK.clearLock()
|
||||||
|
for k in next,locks do
|
||||||
|
locks[k]=nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local tasks={}
|
||||||
|
|
||||||
|
function TASK.getCount()
|
||||||
|
return #tasks
|
||||||
|
end
|
||||||
|
local trigFrame=0
|
||||||
|
function TASK.update(dt)
|
||||||
|
trigFrame=trigFrame+dt*60
|
||||||
|
for _=1,trigFrame 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,dt/trigFrame))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
trigFrame=1
|
||||||
|
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()
|
||||||
|
TABLE.cut(tasks)
|
||||||
|
end
|
||||||
|
|
||||||
|
return TASK
|
||||||
18
Zframework/test.lua
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
local yield=coroutine.yield
|
||||||
|
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
|
||||||
|
|
||||||
|
function TEST.yieldT(timeout)
|
||||||
|
local t=0
|
||||||
|
repeat t=t+yield() until t>=timeout
|
||||||
|
end
|
||||||
|
|
||||||
|
return TEST
|
||||||
152
Zframework/text.lua
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
local getColor,setColor=GC.getColor,GC.setColor
|
||||||
|
|
||||||
|
local floor,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(floor(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(floor(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
|
||||||
26
Zframework/upcaser.txt
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
a=A,b=B,c=C,d=D,e=E,f=F,g=G,h=H,i=I,j=J,k=K,l=L,m=M,n=N,o=O,p=P,q=Q,r=R,s=S,t=T,u=U,v=V,w=W,x=X,y=Y,z=Z
|
||||||
|
µ=Μ,ß=SS,à=À,á=Á,â=Â,ã=Ã,ä=Ä,å=Å,æ=Æ,ç=Ç,è=È,é=É,ê=Ê,ë=Ë,ì=Ì,í=Í,î=Î,ï=Ï,ð=Ð,ñ=Ñ,ò=Ò,ó=Ó,ô=Ô,õ=Õ,ö=Ö,ø=Ø,ù=Ù,ú=Ú,û=Û,ü=Ü,ý=Ý,þ=Þ,ÿ=Ÿ,ā=Ā,ă=Ă,ą=Ą,ć=Ć,ĉ=Ĉ,ċ=Ċ,č=Č,ď=Ď,đ=Đ,ē=Ē,ĕ=Ĕ,ė=Ė,ę=Ę,ě=Ě,ĝ=Ĝ,ğ=Ğ,ġ=Ġ,ģ=Ģ,ĥ=Ĥ,ħ=Ħ,ĩ=Ĩ,ī=Ī,ĭ=Ĭ,į=Į,ij=IJ,ĵ=Ĵ,ķ=Ķ,ĺ=Ĺ,ļ=Ļ,ľ=Ľ,ŀ=Ŀ,ł=Ł,ń=Ń,ņ=Ņ,ň=Ň,ŋ=Ŋ,ō=Ō,ŏ=Ŏ,ő=Ő,œ=Œ,ŕ=Ŕ,ŗ=Ŗ,ř=Ř,ś=Ś,ŝ=Ŝ,ş=Ş,š=Š,ţ=Ţ,ť=Ť,ŧ=Ŧ,ũ=Ũ,ū=Ū,ŭ=Ŭ,ů=Ů,ű=Ű,ų=Ų,ŵ=Ŵ,ŷ=Ŷ,ź=Ź,ż=Ż,ž=Ž
|
||||||
|
ƀ=Ƀ,ƃ=Ƃ,ƅ=Ƅ,ƈ=Ƈ,ƌ=Ƌ,ƒ=Ƒ,ƕ=Ƕ,ƙ=Ƙ,ƚ=Ƚ,ƞ=Ƞ,ơ=Ơ,ƣ=Ƣ,ƥ=Ƥ,ƨ=Ƨ,ƭ=Ƭ,ư=Ư,ƴ=Ƴ,ƶ=Ƶ,ƹ=Ƹ,ƽ=Ƽ,ƿ=Ƿ,dž=DŽ,lj=LJ,nj=NJ,ǎ=Ǎ,ǐ=Ǐ,ǒ=Ǒ,ǔ=Ǔ,ǖ=Ǖ,ǘ=Ǘ,ǚ=Ǚ,ǜ=Ǜ,ǝ=Ǝ,ǟ=Ǟ,ǡ=Ǡ,ǣ=Ǣ,ǥ=Ǥ,ǧ=Ǧ,ǩ=Ǩ,ǫ=Ǫ,ǭ=Ǭ,ǯ=Ǯ,dz=DZ,ǵ=Ǵ,ǹ=Ǹ,ǻ=Ǻ,ǽ=Ǽ,ǿ=Ǿ,ȁ=Ȁ,ȃ=Ȃ,ȅ=Ȅ,ȇ=Ȇ,ȉ=Ȉ,ȋ=Ȋ,ȍ=Ȍ,ȏ=Ȏ,ȑ=Ȑ,ȓ=Ȓ,ȕ=Ȕ,ȗ=Ȗ,ș=Ș,ț=Ț,ȝ=Ȝ,ȟ=Ȟ,ȣ=Ȣ,ȥ=Ȥ,ȧ=Ȧ,ȩ=Ȩ,ȫ=Ȫ,ȭ=Ȭ,ȯ=Ȯ,ȱ=Ȱ,ȳ=Ȳ,ȼ=Ȼ,ȿ=Ȿ,ɀ=Ɀ,ɂ=Ɂ,ɇ=Ɇ,ɉ=Ɉ,ɋ=Ɋ,ɍ=Ɍ,ɏ=Ɏ
|
||||||
|
ɐ=Ɐ,ɑ=Ɑ,ɒ=Ɒ,ɓ=Ɓ,ɔ=Ɔ,ɖ=Ɖ,ɗ=Ɗ,ə=Ə,ɛ=Ɛ,ɜ=Ɜ,ɠ=Ɠ,ɡ=Ɡ,ɣ=Ɣ,ɥ=Ɥ,ɦ=Ɦ,ɨ=Ɨ,ɩ=Ɩ,ɪ=Ɪ,ɫ=Ɫ,ɬ=Ɬ,ɯ=Ɯ,ɱ=Ɱ,ɲ=Ɲ,ɵ=Ɵ,ɽ=Ɽ,ʀ=Ʀ,ʂ=Ʂ,ʃ=Ʃ,ʇ=Ʇ,ʈ=Ʈ,ʉ=Ʉ,ʊ=Ʊ,ʋ=Ʋ,ʌ=Ʌ,ʒ=Ʒ,ʝ=Ʝ,ʞ=Ʞ
|
||||||
|
ͱ=Ͱ,ͳ=Ͳ,ͷ=Ͷ,ͻ=Ͻ,ͼ=Ͼ,ͽ=Ͽ,ά=Ά,έ=Έ,ή=Ή,ί=Ί,α=Α,β=Β,γ=Γ,δ=Δ,ε=Ε,ζ=Ζ,η=Η,θ=Θ,κ=Κ,λ=Λ,ν=Ν,ξ=Ξ,ο=Ο,π=Π,ρ=Ρ,σ=Σ,τ=Τ,υ=Υ,φ=Φ,χ=Χ,ψ=Ψ,ω=Ω,ϊ=Ϊ,ϋ=Ϋ,ό=Ό,ύ=Ύ,ώ=Ώ,ϗ=Ϗ,ϙ=Ϙ,ϛ=Ϛ,ϝ=Ϝ,ϟ=Ϟ,ϡ=Ϡ,ϣ=Ϣ,ϥ=Ϥ,ϧ=Ϧ,ϩ=Ϩ,ϫ=Ϫ,ϭ=Ϭ,ϯ=Ϯ,ϲ=Ϲ,ϳ=Ϳ,ϸ=Ϸ,ϻ=Ϻ
|
||||||
|
а=А,б=Б,в=В,г=Г,д=Д,е=Е,ж=Ж,з=З,и=И,й=Й,к=К,л=Л,м=М,н=Н,о=О,п=П,р=Р,с=С,т=Т,у=У,ф=Ф,х=Х,ц=Ц,ч=Ч,ш=Ш,щ=Щ,ъ=Ъ,ы=Ы,ь=Ь,э=Э,ю=Ю,я=Я,ѐ=Ѐ,ё=Ё,ђ=Ђ,ѓ=Ѓ,є=Є,ѕ=Ѕ,і=І,ї=Ї,ј=Ј,љ=Љ,њ=Њ,ћ=Ћ,ќ=Ќ,ѝ=Ѝ,ў=Ў,џ=Џ,ѡ=Ѡ,ѣ=Ѣ,ѥ=Ѥ,ѧ=Ѧ,ѩ=Ѩ,ѫ=Ѫ,ѭ=Ѭ,ѯ=Ѯ,ѱ=Ѱ,ѳ=Ѳ,ѵ=Ѵ,ѷ=Ѷ,ѹ=Ѹ,ѻ=Ѻ,ѽ=Ѽ,ѿ=Ѿ,ҁ=Ҁ,ҋ=Ҋ,ҍ=Ҍ,ҏ=Ҏ,ґ=Ґ,ғ=Ғ,ҕ=Ҕ,җ=Җ,ҙ=Ҙ,қ=Қ,ҝ=Ҝ,ҟ=Ҟ,ҡ=Ҡ,ң=Ң,ҥ=Ҥ,ҧ=Ҧ,ҩ=Ҩ,ҫ=Ҫ,ҭ=Ҭ,ү=Ү,ұ=Ұ,ҳ=Ҳ,ҵ=Ҵ,ҷ=Ҷ,ҹ=Ҹ,һ=Һ,ҽ=Ҽ,ҿ=Ҿ,ӂ=Ӂ,ӄ=Ӄ,ӆ=Ӆ,ӈ=Ӈ,ӊ=Ӊ,ӌ=Ӌ,ӎ=Ӎ,ӏ=Ӏ,ӑ=Ӑ,ӓ=Ӓ,ӕ=Ӕ,ӗ=Ӗ,ә=Ә,ӛ=Ӛ,ӝ=Ӝ,ӟ=Ӟ,ӡ=Ӡ,ӣ=Ӣ,ӥ=Ӥ,ӧ=Ӧ,ө=Ө,ӫ=Ӫ,ӭ=Ӭ,ӯ=Ӯ,ӱ=Ӱ,ӳ=Ӳ,ӵ=Ӵ,ӷ=Ӷ,ӹ=Ӹ,ӻ=Ӻ,ӽ=Ӽ,ӿ=Ӿ,ԁ=Ԁ,ԃ=Ԃ,ԅ=Ԅ,ԇ=Ԇ,ԉ=Ԉ,ԋ=Ԋ,ԍ=Ԍ,ԏ=Ԏ,ԑ=Ԑ,ԓ=Ԓ,ԕ=Ԕ,ԗ=Ԗ,ԙ=Ԙ,ԛ=Ԛ,ԝ=Ԝ,ԟ=Ԟ,ԡ=Ԡ,ԣ=Ԣ,ԥ=Ԥ,ԧ=Ԧ,ԩ=Ԩ,ԫ=Ԫ,ԭ=Ԭ,ԯ=Ԯ
|
||||||
|
ա=Ա,բ=Բ,գ=Գ,դ=Դ,ե=Ե,զ=Զ,է=Է,ը=Ը,թ=Թ,ժ=Ժ,ի=Ի,լ=Լ,խ=Խ,ծ=Ծ,կ=Կ,հ=Հ,ձ=Ձ,ղ=Ղ,ճ=Ճ,մ=Մ,յ=Յ,ն=Ն,շ=Շ,ո=Ո,չ=Չ,պ=Պ,ջ=Ջ,ռ=Ռ,ս=Ս,վ=Վ,տ=Տ,ր=Ր,ց=Ց,ւ=Ւ,փ=Փ,ք=Ք,օ=Օ,ֆ=Ֆ
|
||||||
|
ა=Ა,ბ=Ბ,გ=Გ,დ=Დ,ე=Ე,ვ=Ვ,ზ=Ზ,თ=Თ,ი=Ი,კ=Კ,ლ=Ლ,მ=Მ,ნ=Ნ,ო=Ო,პ=Პ,ჟ=Ჟ,რ=Რ,ს=Ს,ტ=Ტ,უ=Უ,ფ=Ფ,ქ=Ქ,ღ=Ღ,ყ=Ყ,შ=Შ,ჩ=Ჩ,ც=Ც,ძ=Ძ,წ=Წ,ჭ=Ჭ,ხ=Ხ,ჯ=Ჯ,ჰ=Ჰ,ჱ=Ჱ,ჲ=Ჲ,ჳ=Ჳ,ჴ=Ჴ,ჵ=Ჵ,ჶ=Ჶ,ჷ=Ჷ,ჸ=Ჸ,ჹ=Ჹ,ჺ=Ჺ,ჽ=Ჽ,ჾ=Ჾ,ჿ=Ჿ
|
||||||
|
ᏸ=Ᏸ,ᏹ=Ᏹ,ᏺ=Ᏺ,ᏻ=Ᏻ,ᏼ=Ᏼ,ᏽ=Ᏽ
|
||||||
|
ᲈ=Ꙋ,ᵹ=Ᵹ,ᵽ=Ᵽ,ᶎ=Ᶎ,ḁ=Ḁ,ḃ=Ḃ,ḅ=Ḅ,ḇ=Ḇ,ḉ=Ḉ,ḋ=Ḋ,ḍ=Ḍ,ḏ=Ḏ,ḑ=Ḑ,ḓ=Ḓ,ḕ=Ḕ,ḗ=Ḗ,ḙ=Ḙ,ḛ=Ḛ,ḝ=Ḝ,ḟ=Ḟ,ḡ=Ḡ,ḣ=Ḣ,ḥ=Ḥ,ḧ=Ḧ,ḩ=Ḩ,ḫ=Ḫ,ḭ=Ḭ,ḯ=Ḯ,ḱ=Ḱ,ḳ=Ḳ,ḵ=Ḵ,ḷ=Ḷ,ḹ=Ḹ,ḻ=Ḻ,ḽ=Ḽ,ḿ=Ḿ,ṁ=Ṁ,ṃ=Ṃ,ṅ=Ṅ,ṇ=Ṇ,ṉ=Ṉ,ṋ=Ṋ,ṍ=Ṍ,ṏ=Ṏ,ṑ=Ṑ,ṓ=Ṓ,ṕ=Ṕ,ṗ=Ṗ,ṙ=Ṙ,ṛ=Ṛ,ṝ=Ṝ,ṟ=Ṟ,ṡ=Ṡ,ṣ=Ṣ,ṥ=Ṥ,ṧ=Ṧ,ṩ=Ṩ,ṫ=Ṫ,ṭ=Ṭ,ṯ=Ṯ,ṱ=Ṱ,ṳ=Ṳ,ṵ=Ṵ,ṷ=Ṷ,ṹ=Ṹ,ṻ=Ṻ,ṽ=Ṽ,ṿ=Ṿ,ẁ=Ẁ,ẃ=Ẃ,ẅ=Ẅ,ẇ=Ẇ,ẉ=Ẉ,ẋ=Ẋ,ẍ=Ẍ,ẏ=Ẏ,ẑ=Ẑ,ẓ=Ẓ,ẕ=Ẕ,ạ=Ạ,ả=Ả,ấ=Ấ,ầ=Ầ,ẩ=Ẩ,ẫ=Ẫ,ậ=Ậ,ắ=Ắ,ằ=Ằ,ẳ=Ẳ,ẵ=Ẵ,ặ=Ặ,ẹ=Ẹ,ẻ=Ẻ,ẽ=Ẽ,ế=Ế,ề=Ề,ể=Ể,ễ=Ễ,ệ=Ệ,ỉ=Ỉ,ị=Ị,ọ=Ọ,ỏ=Ỏ,ố=Ố,ồ=Ồ,ổ=Ổ,ỗ=Ỗ,ộ=Ộ,ớ=Ớ,ờ=Ờ,ở=Ở,ỡ=Ỡ,ợ=Ợ,ụ=Ụ,ủ=Ủ,ứ=Ứ,ừ=Ừ,ử=Ử,ữ=Ữ,ự=Ự,ỳ=Ỳ,ỵ=Ỵ,ỷ=Ỷ,ỹ=Ỹ,ỻ=Ỻ,ỽ=Ỽ,ỿ=Ỿ,ἀ=Ἀ,ἁ=Ἁ,ἂ=Ἂ,ἃ=Ἃ,ἄ=Ἄ,ἅ=Ἅ,ἆ=Ἆ,ἇ=Ἇ,ἐ=Ἐ,ἑ=Ἑ,ἒ=Ἒ,ἓ=Ἓ,ἔ=Ἔ,ἕ=Ἕ,ἠ=Ἠ,ἡ=Ἡ,ἢ=Ἢ,ἣ=Ἣ,ἤ=Ἤ,ἥ=Ἥ,ἦ=Ἦ,ἧ=Ἧ,ἰ=Ἰ,ἱ=Ἱ,ἲ=Ἲ,ἳ=Ἳ,ἴ=Ἴ,ἵ=Ἵ,ἶ=Ἶ,ἷ=Ἷ,ὀ=Ὀ,ὁ=Ὁ,ὂ=Ὂ,ὃ=Ὃ,ὄ=Ὄ,ὅ=Ὅ,ὑ=Ὑ,ὓ=Ὓ,ὕ=Ὕ,ὗ=Ὗ,ὠ=Ὠ,ὡ=Ὡ,ὢ=Ὢ,ὣ=Ὣ,ὤ=Ὤ,ὥ=Ὥ,ὦ=Ὦ,ὧ=Ὧ,ὰ=Ὰ,ά=Ά,ὲ=Ὲ,έ=Έ,ὴ=Ὴ,ή=Ή,ὶ=Ὶ,ί=Ί,ὸ=Ὸ,ό=Ό,ὺ=Ὺ,ύ=Ύ,ὼ=Ὼ,ώ=Ώ,ᾰ=Ᾰ,ᾱ=Ᾱ,ῐ=Ῐ,ῑ=Ῑ,ῠ=Ῠ,ῡ=Ῡ,ῥ=Ῥ,ⅎ=Ⅎ
|
||||||
|
ⅰ=Ⅰ,ⅱ=Ⅱ,ⅲ=Ⅲ,ⅳ=Ⅳ,ⅴ=Ⅴ,ⅵ=Ⅵ,ⅶ=Ⅶ,ⅷ=Ⅷ,ⅸ=Ⅸ,ⅹ=Ⅹ,ⅺ=Ⅺ,ⅻ=Ⅻ,ⅼ=Ⅼ,ⅽ=Ⅽ,ⅾ=Ⅾ,ⅿ=Ⅿ,ↄ=Ↄ
|
||||||
|
ⓐ=Ⓐ,ⓑ=Ⓑ,ⓒ=Ⓒ,ⓓ=Ⓓ,ⓔ=Ⓔ,ⓕ=Ⓕ,ⓖ=Ⓖ,ⓗ=Ⓗ,ⓘ=Ⓘ,ⓙ=Ⓙ,ⓚ=Ⓚ,ⓛ=Ⓛ,ⓜ=Ⓜ,ⓝ=Ⓝ,ⓞ=Ⓞ,ⓟ=Ⓟ,ⓠ=Ⓠ,ⓡ=Ⓡ,ⓢ=Ⓢ,ⓣ=Ⓣ,ⓤ=Ⓤ,ⓥ=Ⓥ,ⓦ=Ⓦ,ⓧ=Ⓧ,ⓨ=Ⓨ,ⓩ=Ⓩ
|
||||||
|
ⰰ=Ⰰ,ⰱ=Ⰱ,ⰲ=Ⰲ,ⰳ=Ⰳ,ⰴ=Ⰴ,ⰵ=Ⰵ,ⰶ=Ⰶ,ⰷ=Ⰷ,ⰸ=Ⰸ,ⰹ=Ⰹ,ⰺ=Ⰺ,ⰻ=Ⰻ,ⰼ=Ⰼ,ⰽ=Ⰽ,ⰾ=Ⰾ,ⰿ=Ⰿ,ⱀ=Ⱀ,ⱁ=Ⱁ,ⱂ=Ⱂ,ⱃ=Ⱃ,ⱄ=Ⱄ,ⱅ=Ⱅ,ⱆ=Ⱆ,ⱇ=Ⱇ,ⱈ=Ⱈ,ⱉ=Ⱉ,ⱊ=Ⱊ,ⱋ=Ⱋ,ⱌ=Ⱌ,ⱍ=Ⱍ,ⱎ=Ⱎ,ⱏ=Ⱏ,ⱐ=Ⱐ,ⱑ=Ⱑ,ⱒ=Ⱒ,ⱓ=Ⱓ,ⱔ=Ⱔ,ⱕ=Ⱕ,ⱖ=Ⱖ,ⱗ=Ⱗ,ⱘ=Ⱘ,ⱙ=Ⱙ,ⱚ=Ⱚ,ⱛ=Ⱛ,ⱜ=Ⱜ,ⱝ=Ⱝ,ⱞ=Ⱞ,ⱟ=Ⱟ
|
||||||
|
ⱡ=Ⱡ,ⱥ=Ⱥ,ⱦ=Ⱦ,ⱨ=Ⱨ,ⱪ=Ⱪ,ⱬ=Ⱬ,ⱳ=Ⱳ,ⱶ=Ⱶ
|
||||||
|
ⲁ=Ⲁ,ⲃ=Ⲃ,ⲅ=Ⲅ,ⲇ=Ⲇ,ⲉ=Ⲉ,ⲋ=Ⲋ,ⲍ=Ⲍ,ⲏ=Ⲏ,ⲑ=Ⲑ,ⲓ=Ⲓ,ⲕ=Ⲕ,ⲗ=Ⲗ,ⲙ=Ⲙ,ⲛ=Ⲛ,ⲝ=Ⲝ,ⲟ=Ⲟ,ⲡ=Ⲡ,ⲣ=Ⲣ,ⲥ=Ⲥ,ⲧ=Ⲧ,ⲩ=Ⲩ,ⲫ=Ⲫ,ⲭ=Ⲭ,ⲯ=Ⲯ,ⲱ=Ⲱ,ⲳ=Ⲳ,ⲵ=Ⲵ,ⲷ=Ⲷ,ⲹ=Ⲹ,ⲻ=Ⲻ,ⲽ=Ⲽ,ⲿ=Ⲿ,ⳁ=Ⳁ,ⳃ=Ⳃ,ⳅ=Ⳅ,ⳇ=Ⳇ,ⳉ=Ⳉ,ⳋ=Ⳋ,ⳍ=Ⳍ,ⳏ=Ⳏ,ⳑ=Ⳑ,ⳓ=Ⳓ,ⳕ=Ⳕ,ⳗ=Ⳗ,ⳙ=Ⳙ,ⳛ=Ⳛ,ⳝ=Ⳝ,ⳟ=Ⳟ,ⳡ=Ⳡ,ⳣ=Ⳣ,ⳬ=Ⳬ,ⳮ=Ⳮ,ⳳ=Ⳳ
|
||||||
|
ⴀ=Ⴀ,ⴁ=Ⴁ,ⴂ=Ⴂ,ⴃ=Ⴃ,ⴄ=Ⴄ,ⴅ=Ⴅ,ⴆ=Ⴆ,ⴇ=Ⴇ,ⴈ=Ⴈ,ⴉ=Ⴉ,ⴊ=Ⴊ,ⴋ=Ⴋ,ⴌ=Ⴌ,ⴍ=Ⴍ,ⴎ=Ⴎ,ⴏ=Ⴏ,ⴐ=Ⴐ,ⴑ=Ⴑ,ⴒ=Ⴒ,ⴓ=Ⴓ,ⴔ=Ⴔ,ⴕ=Ⴕ,ⴖ=Ⴖ,ⴗ=Ⴗ,ⴘ=Ⴘ,ⴙ=Ⴙ,ⴚ=Ⴚ,ⴛ=Ⴛ,ⴜ=Ⴜ,ⴝ=Ⴝ,ⴞ=Ⴞ,ⴟ=Ⴟ,ⴠ=Ⴠ,ⴡ=Ⴡ,ⴢ=Ⴢ,ⴣ=Ⴣ,ⴤ=Ⴤ,ⴥ=Ⴥ,ⴧ=Ⴧ
|
||||||
|
ⴭ=Ⴭ,ꙁ=Ꙁ,ꙃ=Ꙃ,ꙅ=Ꙅ,ꙇ=Ꙇ,ꙉ=Ꙉ,ꙍ=Ꙍ,ꙏ=Ꙏ,ꙑ=Ꙑ,ꙓ=Ꙓ,ꙕ=Ꙕ,ꙗ=Ꙗ,ꙙ=Ꙙ,ꙛ=Ꙛ,ꙝ=Ꙝ,ꙟ=Ꙟ,ꙡ=Ꙡ,ꙣ=Ꙣ,ꙥ=Ꙥ,ꙧ=Ꙧ,ꙩ=Ꙩ,ꙫ=Ꙫ,ꙭ=Ꙭ,ꚁ=Ꚁ,ꚃ=Ꚃ,ꚅ=Ꚅ,ꚇ=Ꚇ,ꚉ=Ꚉ,ꚋ=Ꚋ,ꚍ=Ꚍ,ꚏ=Ꚏ,ꚑ=Ꚑ,ꚓ=Ꚓ,ꚕ=Ꚕ,ꚗ=Ꚗ,ꚙ=Ꚙ,ꚛ=Ꚛ,ꜣ=Ꜣ,ꜥ=Ꜥ,ꜧ=Ꜧ,ꜩ=Ꜩ,ꜫ=Ꜫ,ꜭ=Ꜭ,ꜯ=Ꜯ,ꜳ=Ꜳ,ꜵ=Ꜵ,ꜷ=Ꜷ,ꜹ=Ꜹ,ꜻ=Ꜻ,ꜽ=Ꜽ,ꜿ=Ꜿ,ꝁ=Ꝁ,ꝃ=Ꝃ,ꝅ=Ꝅ,ꝇ=Ꝇ,ꝉ=Ꝉ,ꝋ=Ꝋ,ꝍ=Ꝍ,ꝏ=Ꝏ,ꝑ=Ꝑ,ꝓ=Ꝓ,ꝕ=Ꝕ,ꝗ=Ꝗ,ꝙ=Ꝙ,ꝛ=Ꝛ,ꝝ=Ꝝ,ꝟ=Ꝟ,ꝡ=Ꝡ,ꝣ=Ꝣ,ꝥ=Ꝥ,ꝧ=Ꝧ,ꝩ=Ꝩ,ꝫ=Ꝫ,ꝭ=Ꝭ,ꝯ=Ꝯ,ꝺ=Ꝺ,ꝼ=Ꝼ,ꝿ=Ꝿ,ꞁ=Ꞁ,ꞃ=Ꞃ,ꞅ=Ꞅ,ꞇ=Ꞇ,ꞌ=Ꞌ,ꞑ=Ꞑ,ꞓ=Ꞓ,ꞔ=Ꞔ,ꞗ=Ꞗ,ꞙ=Ꞙ,ꞛ=Ꞛ,ꞝ=Ꞝ,ꞟ=Ꞟ,ꞡ=Ꞡ,ꞣ=Ꞣ,ꞥ=Ꞥ,ꞧ=Ꞧ,ꞩ=Ꞩ,ꞵ=Ꞵ,ꞷ=Ꞷ,ꞹ=Ꞹ,ꞻ=Ꞻ,ꞽ=Ꞽ,ꞿ=Ꞿ,ꟁ=Ꟁ,ꟃ=Ꟃ,ꟈ=Ꟈ,ꟊ=Ꟊ,ꟑ=Ꟑ,ꟗ=Ꟗ,ꟙ=Ꟙ,ꟶ=Ꟶ,ꭓ=Ꭓ
|
||||||
|
ꭰ=Ꭰ,ꭱ=Ꭱ,ꭲ=Ꭲ,ꭳ=Ꭳ,ꭴ=Ꭴ,ꭵ=Ꭵ,ꭶ=Ꭶ,ꭷ=Ꭷ,ꭸ=Ꭸ,ꭹ=Ꭹ,ꭺ=Ꭺ,ꭻ=Ꭻ,ꭼ=Ꭼ,ꭽ=Ꭽ,ꭾ=Ꭾ,ꭿ=Ꭿ,ꮀ=Ꮀ,ꮁ=Ꮁ,ꮂ=Ꮂ,ꮃ=Ꮃ,ꮄ=Ꮄ,ꮅ=Ꮅ,ꮆ=Ꮆ,ꮇ=Ꮇ,ꮈ=Ꮈ,ꮉ=Ꮉ,ꮊ=Ꮊ,ꮋ=Ꮋ,ꮌ=Ꮌ,ꮍ=Ꮍ,ꮎ=Ꮎ,ꮏ=Ꮏ,ꮐ=Ꮐ,ꮑ=Ꮑ,ꮒ=Ꮒ,ꮓ=Ꮓ,ꮔ=Ꮔ,ꮕ=Ꮕ,ꮖ=Ꮖ,ꮗ=Ꮗ,ꮘ=Ꮘ,ꮙ=Ꮙ,ꮚ=Ꮚ,ꮛ=Ꮛ,ꮜ=Ꮜ,ꮝ=Ꮝ,ꮞ=Ꮞ,ꮟ=Ꮟ,ꮠ=Ꮠ,ꮡ=Ꮡ,ꮢ=Ꮢ,ꮣ=Ꮣ,ꮤ=Ꮤ,ꮥ=Ꮥ,ꮦ=Ꮦ,ꮧ=Ꮧ,ꮨ=Ꮨ,ꮩ=Ꮩ,ꮪ=Ꮪ,ꮫ=Ꮫ,ꮬ=Ꮬ,ꮭ=Ꮭ,ꮮ=Ꮮ,ꮯ=Ꮯ,ꮰ=Ꮰ,ꮱ=Ꮱ,ꮲ=Ꮲ,ꮳ=Ꮳ,ꮴ=Ꮴ,ꮵ=Ꮵ,ꮶ=Ꮶ,ꮷ=Ꮷ,ꮸ=Ꮸ,ꮹ=Ꮹ,ꮺ=Ꮺ,ꮻ=Ꮻ,ꮼ=Ꮼ,ꮽ=Ꮽ,ꮾ=Ꮾ,ꮿ=Ꮿ
|
||||||
|
a=A,b=B,c=C,d=D,e=E,f=F,g=G,h=H,i=I,j=J,k=K,l=L,m=M,n=N,o=O,p=P,q=Q,r=R,s=S,t=T,u=U,v=V,w=W,x=X,y=Y,z=Z
|
||||||
|
𐐨=𐐀,𐐩=𐐁,𐐪=𐐂,𐐫=𐐃,𐐬=𐐄,𐐭=𐐅,𐐮=𐐆,𐐯=𐐇,𐐰=𐐈,𐐱=𐐉,𐐲=𐐊,𐐳=𐐋,𐐴=𐐌,𐐵=𐐍,𐐶=𐐎,𐐷=𐐏,𐐸=𐐐,𐐹=𐐑,𐐺=𐐒,𐐻=𐐓,𐐼=𐐔,𐐽=𐐕,𐐾=𐐖,𐐿=𐐗,𐑀=𐐘,𐑁=𐐙,𐑂=𐐚,𐑃=𐐛,𐑄=𐐜,𐑅=𐐝,𐑆=𐐞,𐑇=𐐟,𐑈=𐐠,𐑉=𐐡,𐑊=𐐢,𐑋=𐐣,𐑌=𐐤,𐑍=𐐥,𐑎=𐐦,𐑏=𐐧
|
||||||
|
𐓘=𐒰,𐓙=𐒱,𐓚=𐒲,𐓛=𐒳,𐓜=𐒴,𐓝=𐒵,𐓞=𐒶,𐓟=𐒷,𐓠=𐒸,𐓡=𐒹,𐓢=𐒺,𐓣=𐒻,𐓤=𐒼,𐓥=𐒽,𐓦=𐒾,𐓧=𐒿,𐓨=𐓀,𐓩=𐓁,𐓪=𐓂,𐓫=𐓃,𐓬=𐓄,𐓭=𐓅,𐓮=𐓆,𐓯=𐓇,𐓰=𐓈,𐓱=𐓉,𐓲=𐓊,𐓳=𐓋,𐓴=𐓌,𐓵=𐓍,𐓶=𐓎,𐓷=𐓏,𐓸=𐓐,𐓹=𐓑,𐓺=𐓒,𐓻=𐓓
|
||||||
|
𐳀=𐲀,𐳁=𐲁,𐳂=𐲂,𐳃=𐲃,𐳄=𐲄,𐳅=𐲅,𐳆=𐲆,𐳇=𐲇,𐳈=𐲈,𐳉=𐲉,𐳊=𐲊,𐳋=𐲋,𐳌=𐲌,𐳍=𐲍,𐳎=𐲎,𐳏=𐲏,𐳐=𐲐,𐳑=𐲑,𐳒=𐲒,𐳓=𐲓,𐳔=𐲔,𐳕=𐲕,𐳖=𐲖,𐳗=𐲗,𐳘=𐲘,𐳙=𐲙,𐳚=𐲚,𐳛=𐲛,𐳜=𐲜,𐳝=𐲝,𐳞=𐲞,𐳟=𐲟,𐳠=𐲠,𐳡=𐲡,𐳢=𐲢,𐳣=𐲣,𐳤=𐲤,𐳥=𐲥,𐳦=𐲦,𐳧=𐲧,𐳨=𐲨,𐳩=𐲩,𐳪=𐲪,𐳫=𐲫,𐳬=𐲬,𐳭=𐲭,𐳮=𐲮,𐳯=𐲯,𐳰=𐲰,𐳱=𐲱,𐳲=𐲲
|
||||||
|
𑣀=𑢠,𑣁=𑢡,𑣂=𑢢,𑣃=𑢣,𑣄=𑢤,𑣅=𑢥,𑣆=𑢦,𑣇=𑢧,𑣈=𑢨,𑣉=𑢩,𑣊=𑢪,𑣋=𑢫,𑣌=𑢬,𑣍=𑢭,𑣎=𑢮,𑣏=𑢯,𑣐=𑢰,𑣑=𑢱,𑣒=𑢲,𑣓=𑢳,𑣔=𑢴,𑣕=𑢵,𑣖=𑢶,𑣗=𑢷,𑣘=𑢸,𑣙=𑢹,𑣚=𑢺,𑣛=𑢻,𑣜=𑢼,𑣝=𑢽,𑣞=𑢾,𑣟=𑢿
|
||||||
|
𖹠=𖹀,𖹡=𖹁,𖹢=𖹂,𖹣=𖹃,𖹤=𖹄,𖹥=𖹅,𖹦=𖹆,𖹧=𖹇,𖹨=𖹈,𖹩=𖹉,𖹪=𖹊,𖹫=𖹋,𖹬=𖹌,𖹭=𖹍,𖹮=𖹎,𖹯=𖹏,𖹰=𖹐,𖹱=𖹑,𖹲=𖹒,𖹳=𖹓,𖹴=𖹔,𖹵=𖹕,𖹶=𖹖,𖹷=𖹗,𖹸=𖹘,𖹹=𖹙,𖹺=𖹚,𖹻=𖹛,𖹼=𖹜,𖹽=𖹝,𖹾=𖹞,𖹿=𖹟
|
||||||
|
𞤢=𞤀,𞤣=𞤁,𞤤=𞤂,𞤥=𞤃,𞤦=𞤄,𞤧=𞤅,𞤨=𞤆,𞤩=𞤇,𞤪=𞤈,𞤫=𞤉,𞤬=𞤊,𞤭=𞤋,𞤮=𞤌,𞤯=𞤍,𞤰=𞤎,𞤱=𞤏,𞤲=𞤐,𞤳=𞤑,𞤴=𞤒,𞤵=𞤓,𞤶=𞤔,𞤷=𞤕,𞤸=𞤖,𞤹=𞤗,𞤺=𞤘,𞤻=𞤙,𞤼=𞤚,𞤽=𞤛,𞤾=𞤜,𞤿=𞤝,𞥀=𞤞,𞥁=𞤟,𞥂=𞤠,𞥃=𞤡
|
||||||
|
i̇=İ,ʼn=ʼN,ǰ=J̌,ΐ=Ϊ́,ΰ=Ϋ́,և=ԵՒ,ẖ=H̱,ẗ=T̈,ẘ=W̊,ẙ=Y̊,ẚ=Aʾ,ὐ=Υ̓,ὒ=Υ̓̀,ὔ=Υ̓́,ὖ=Υ̓͂,ᾀ=ἈΙ,ᾁ=ἉΙ,ᾂ=ἊΙ,ᾃ=ἋΙ,ᾄ=ἌΙ,ᾅ=ἍΙ,ᾆ=ἎΙ,ᾇ=ἏΙ,ᾐ=ἨΙ,ᾑ=ἩΙ,ᾒ=ἪΙ,ᾓ=ἫΙ,ᾔ=ἬΙ,ᾕ=ἭΙ,ᾖ=ἮΙ,ᾗ=ἯΙ,ᾠ=ὨΙ,ᾡ=ὩΙ,ᾢ=ὪΙ,ᾣ=ὫΙ,ᾤ=ὬΙ,ᾥ=ὭΙ,ᾦ=ὮΙ,ᾧ=ὯΙ,ᾲ=ᾺΙ,ᾳ=ΑΙ,ᾴ=ΆΙ,ᾶ=Α͂,ᾷ=Α͂Ι,ῂ=ῊΙ,ῃ=ΗΙ,ῄ=ΉΙ,ῆ=Η͂,ῇ=Η͂Ι,ῒ=Ϊ̀,ῖ=Ι͂,ῗ=Ϊ͂,ῢ=Ϋ̀,ῤ=Ρ̓,ῦ=Υ͂,ῧ=Ϋ͂,ῲ=ῺΙ,ῳ=ΩΙ,ῴ=ΏΙ,ῶ=Ω͂,ῷ=Ω͂Ι,ﬓ=ՄՆ,ﬔ=ՄԵ,ﬕ=ՄԻ,ﬖ=ՎՆ,ﬗ=ՄԽ
|
||||||
12
Zframework/vibrate.lua
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
local level={0,0,.01,.016,.023,.03,.04,.05,.06,.07,.08,.09,.12,.15}
|
||||||
|
local vib=love.system.vibrate
|
||||||
|
return SYSTEM=='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
|
||||||
144
Zframework/voice.lua
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
local rnd=math.random
|
||||||
|
local volume=1
|
||||||
|
local diversion=0
|
||||||
|
local voiceQueue={free=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
|
||||||
|
for i=1,#voiceQueue do
|
||||||
|
local Q=voiceQueue[i]
|
||||||
|
for j=1,#Q do
|
||||||
|
local s=Q[j]
|
||||||
|
if type(s)=='userdata' then
|
||||||
|
s:setVolume(volume)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function VOC.init(list)
|
||||||
|
VOC.init=nil
|
||||||
|
local rem=table.remove
|
||||||
|
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.getQueueLength(chn)
|
||||||
|
return voiceQueue[chn] and #voiceQueue[chn]
|
||||||
|
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
|
||||||
128
Zframework/wait.lua
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
local WAIT={
|
||||||
|
state=false,
|
||||||
|
timer=false,
|
||||||
|
totalTimer=false,
|
||||||
|
|
||||||
|
enterTime=.2,
|
||||||
|
leaveTime=.2,
|
||||||
|
timeout=6,
|
||||||
|
coverColor={.1,.1,.1},
|
||||||
|
coverAlpha=.6,
|
||||||
|
|
||||||
|
arg=false,
|
||||||
|
}
|
||||||
|
|
||||||
|
local arcAlpha={1,.6,.4,.3}
|
||||||
|
local function defaultDraw(a,t)
|
||||||
|
GC.setLineWidth(SCR.h/26)
|
||||||
|
t=t*2.6
|
||||||
|
for i=1,4 do
|
||||||
|
GC.setColor(1,1,1,a*arcAlpha[i])
|
||||||
|
GC.arc('line','open',SCR.w/2,SCR.h/2,SCR.h/5,t+MATH.tau*(i/4),t+MATH.tau*((i+1)/4))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function WAIT.new(arg)
|
||||||
|
if WAIT.state then return end
|
||||||
|
|
||||||
|
assert(type(arg)=='table',"arg must be table")
|
||||||
|
assert(arg.init==nil or type(arg.init) =='function',"Field 'enter' must be function")
|
||||||
|
assert(arg.update==nil or type(arg.update) =='function',"Field 'update' must be function")
|
||||||
|
assert(arg.quit==nil or type(arg.quit) =='function',"Field 'leave' must be function")
|
||||||
|
assert(arg.draw==nil or type(arg.draw) =='function',"Field 'draw' must be function")
|
||||||
|
assert(arg.escapable==nil or type(arg.escapable) =='boolean', "Field 'escapable' must be boolean")
|
||||||
|
if arg.init then arg.init() end
|
||||||
|
|
||||||
|
WAIT.arg=arg
|
||||||
|
WAIT.state='enter'
|
||||||
|
WAIT.timer=0
|
||||||
|
WAIT.totalTimer=0
|
||||||
|
end
|
||||||
|
|
||||||
|
function WAIT.interrupt()
|
||||||
|
if WAIT.state and WAIT.state~='leave' then
|
||||||
|
WAIT.state='leave'
|
||||||
|
WAIT.timer=WAIT.leaveTime*WAIT.timer/WAIT.enterTime
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function WAIT.update(dt)
|
||||||
|
if WAIT.state then
|
||||||
|
WAIT.totalTimer=WAIT.totalTimer+dt
|
||||||
|
if WAIT.arg.update then WAIT.arg.update(dt) end
|
||||||
|
|
||||||
|
if WAIT.state~='leave' and WAIT.totalTimer>=(WAIT.arg.timeout or WAIT.timeout) then
|
||||||
|
WAIT.interrupt()
|
||||||
|
end
|
||||||
|
|
||||||
|
if WAIT.state=='enter' then
|
||||||
|
WAIT.timer=math.min(WAIT.timer+dt,WAIT.enterTime)
|
||||||
|
if WAIT.timer>=WAIT.enterTime then WAIT.state='wait' end
|
||||||
|
elseif WAIT.state=='leave' then
|
||||||
|
WAIT.timer=WAIT.timer-dt
|
||||||
|
if WAIT.timer<=0 then
|
||||||
|
WAIT.state=false
|
||||||
|
if WAIT.arg.quit then WAIT.arg.quit() end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function WAIT.draw()
|
||||||
|
if WAIT.state then
|
||||||
|
local alpha=(
|
||||||
|
WAIT.state=='enter' and WAIT.timer/WAIT.enterTime or
|
||||||
|
WAIT.state=='wait' and 1 or
|
||||||
|
WAIT.state=='leave' and WAIT.timer/WAIT.leaveTime
|
||||||
|
)
|
||||||
|
GC.setColor(
|
||||||
|
WAIT.coverColor[1],
|
||||||
|
WAIT.coverColor[2],
|
||||||
|
WAIT.coverColor[3],
|
||||||
|
alpha*WAIT.coverAlpha
|
||||||
|
)
|
||||||
|
GC.rectangle('fill',0,0,SCR.w,SCR.h);
|
||||||
|
|
||||||
|
(WAIT.arg.draw or defaultDraw)(alpha,WAIT.totalTimer)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function WAIT.setEnterTime(t)
|
||||||
|
assert(type(t)=='number' and t>0,"Arg #1 must be number larger then 0")
|
||||||
|
WAIT.enterTime=t
|
||||||
|
end
|
||||||
|
function WAIT.setLeaveTime(t)
|
||||||
|
assert(type(t)=='number' and t>0,"Arg #1 must be number larger then 0")
|
||||||
|
WAIT.leaveTime=t
|
||||||
|
end
|
||||||
|
function WAIT.setTimeout(t)
|
||||||
|
assert(type(t)=='number' and t>0,"Arg #1 must be number larger then 0")
|
||||||
|
WAIT.timeout=t
|
||||||
|
end
|
||||||
|
function WAIT.setCoverColor(r,g,b)
|
||||||
|
if type(r)=='table' then
|
||||||
|
r,g,b=r[1],r[2],r[3]
|
||||||
|
end
|
||||||
|
if
|
||||||
|
type(r)=='number' and r>=0 and r<=1 and
|
||||||
|
type(g)=='number' and g>=0 and g<=1 and
|
||||||
|
type(b)=='number' and b>=0 and b<=1
|
||||||
|
then
|
||||||
|
WAIT.coverColor[1],WAIT.coverColor[2],WAIT.coverColor[3]=r,g,b
|
||||||
|
else
|
||||||
|
error("Arg must be r,g,b or {r,g,b}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function WAIT.setCoverAlpha(a)
|
||||||
|
assert(type(a)=='number',"Arg #1 must be number between 0~1")
|
||||||
|
end
|
||||||
|
function WAIT.setDefaultDraw(f)
|
||||||
|
assert(type(f)=='function',"Arg #1 must be function")
|
||||||
|
defaultDraw=f
|
||||||
|
end
|
||||||
|
|
||||||
|
setmetatable(WAIT,{__call=function(self,arg)
|
||||||
|
self.new(arg)
|
||||||
|
end,__metatable=true})
|
||||||
|
|
||||||
|
return WAIT
|
||||||
194
Zframework/websocket.lua
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
local host='127.0.0.1'
|
||||||
|
local port='80'
|
||||||
|
local path=''
|
||||||
|
|
||||||
|
-- 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 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,head,timeout)
|
||||||
|
if head then
|
||||||
|
local l=""
|
||||||
|
for k,v in next,head do
|
||||||
|
l=l..(k..": "..v..'\r\n')
|
||||||
|
end
|
||||||
|
head=l
|
||||||
|
else
|
||||||
|
head=""
|
||||||
|
end
|
||||||
|
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)
|
||||||
|
ws.sendCHN:push(host)
|
||||||
|
ws.sendCHN:push(port)
|
||||||
|
ws.sendCHN:push(path..subPath)
|
||||||
|
ws.sendCHN:push(head)
|
||||||
|
ws.sendCHN:push(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
|
||||||
|
ws.sendCHN:push(op and OPcode[op] or 2)-- 2=binary
|
||||||
|
ws.sendCHN:push(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 ws.readCHN:getCount()>=2 then
|
||||||
|
local op,message=ws.readCHN:pop(),ws.readCHN:pop()
|
||||||
|
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
|
||||||
|
ws.sendCHN:push(8)-- 8=close
|
||||||
|
ws.sendCHN:push("")
|
||||||
|
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 ws.triggerCHN:getCount()==0 then
|
||||||
|
ws.triggerCHN:push(0)
|
||||||
|
end
|
||||||
|
if ws.status=='connecting' then
|
||||||
|
local mes=ws.readCHN:pop()
|
||||||
|
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:repD(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
|
||||||
|
MES.new('warn',text.wsClose:repD(err:match(":.-:(.-)\n")))
|
||||||
|
WS.alert(name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return WS
|
||||||
189
Zframework/websocket_thread.lua
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
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 head=CHN_demand(sendCHN)
|
||||||
|
local timeout=CHN_demand(sendCHN)
|
||||||
|
|
||||||
|
SOCK:settimeout(timeout)
|
||||||
|
local res,err=SOCK:connect(host,port)
|
||||||
|
assert(res,err)
|
||||||
|
|
||||||
|
-- WebSocket handshake
|
||||||
|
SOCK:send(
|
||||||
|
'GET '..path..' HTTP/1.1\r\n'..
|
||||||
|
'Host: '..host..':'..port..'\r\n'..
|
||||||
|
'Connection: Upgrade\r\n'..
|
||||||
|
'Upgrade: websocket\r\n'..
|
||||||
|
'Sec-WebSocket-Version: 13\r\n'..
|
||||||
|
'Sec-WebSocket-Key: osT3F7mvlojIvf3/8uIsJQ==\r\n'..-- secKey
|
||||||
|
head..
|
||||||
|
'\r\n'
|
||||||
|
)
|
||||||
|
|
||||||
|
-- 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()
|
||||||
19
Zframework/wheelScroll.lua
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
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
|
||||||
1525
Zframework/widget.lua
Normal file
75
conf.lua
@@ -1,29 +1,42 @@
|
|||||||
|
local OS=love._os
|
||||||
|
if OS=='OS X' then OS='macOS' end
|
||||||
|
MOBILE=OS=='Android' or OS=='iOS'
|
||||||
|
FNNS=OS:find'\79\83' -- What does FNSF stand for? IDK so don't ask me lol
|
||||||
|
|
||||||
|
if OS=='Web' then
|
||||||
|
local oldRead=love.filesystem.read
|
||||||
|
function love.filesystem.read(name,size)
|
||||||
|
if love.filesystem.getInfo(name) then
|
||||||
|
return oldRead(name,size)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function love.conf(t)
|
function love.conf(t)
|
||||||
t.identity='Techmino'-- Saving folder
|
local identity='Techmino'
|
||||||
t.version="11.1"
|
local msaa=0
|
||||||
|
local portrait=false
|
||||||
|
|
||||||
|
local fs=love.filesystem
|
||||||
|
fs.setIdentity(identity)
|
||||||
|
do -- Load grapgic settings from conf/settings
|
||||||
|
local fileData=fs.read('conf/settings')
|
||||||
|
if fileData then
|
||||||
|
msaa=tonumber(fileData:match('"msaa":(%d+)')) or 0;
|
||||||
|
portrait=MOBILE and fileData:find('"portrait":true') and true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
t.identity=identity -- Saving folder
|
||||||
|
t.version="11.4"
|
||||||
t.gammacorrect=false
|
t.gammacorrect=false
|
||||||
t.appendidentity=true-- Search files in source then in save directory
|
t.appendidentity=true -- Search files in source then in save directory
|
||||||
t.accelerometerjoystick=false-- Accelerometer=joystick on ios/android
|
t.accelerometerjoystick=false -- Accelerometer=joystick on ios/android
|
||||||
if t.audio then
|
if t.audio then
|
||||||
t.audio.mic=false
|
t.audio.mic=false
|
||||||
t.audio.mixwithsystem=true
|
t.audio.mixwithsystem=true
|
||||||
end
|
end
|
||||||
|
|
||||||
local W=t.window
|
|
||||||
W.title="Techmino "..require"version".string
|
|
||||||
W.width,W.height=1280,720
|
|
||||||
W.minwidth,W.minheight=640,360
|
|
||||||
W.borderless=false
|
|
||||||
W.resizable=true
|
|
||||||
W.fullscreen=false
|
|
||||||
W.vsync=0-- Unlimited FPS
|
|
||||||
W.msaa=0-- Multi-sampled antialiasing
|
|
||||||
W.depth=0-- Bits/samp of depth buffer
|
|
||||||
W.stencil=1-- Bits/samp of stencil buffer
|
|
||||||
W.display=1-- Monitor ID
|
|
||||||
W.highdpi=true-- High-dpi mode for the window on a Retina display
|
|
||||||
W.x,W.y=nil
|
|
||||||
|
|
||||||
local M=t.modules
|
local M=t.modules
|
||||||
M.window,M.system,M.event,M.thread=true,true,true,true
|
M.window,M.system,M.event,M.thread=true,true,true,true
|
||||||
M.timer,M.math,M.data=true,true,true
|
M.timer,M.math,M.data=true,true,true
|
||||||
@@ -31,4 +44,28 @@ function love.conf(t)
|
|||||||
M.graphics,M.font,M.image=true,true,true
|
M.graphics,M.font,M.image=true,true,true
|
||||||
M.mouse,M.touch,M.keyboard,M.joystick=true,true,true,true
|
M.mouse,M.touch,M.keyboard,M.joystick=true,true,true,true
|
||||||
M.physics=false
|
M.physics=false
|
||||||
|
|
||||||
|
local W=t.window
|
||||||
|
W.vsync=0 -- Unlimited FPS
|
||||||
|
W.msaa=msaa -- Multi-sampled antialiasing
|
||||||
|
W.depth=0 -- Bits/samp of depth buffer
|
||||||
|
W.stencil=1 -- Bits/samp of stencil buffer
|
||||||
|
W.display=1 -- Monitor ID
|
||||||
|
W.highdpi=true -- High-dpi mode for the window on a Retina display
|
||||||
|
W.x,W.y=nil,nil -- Position of the window
|
||||||
|
W.borderless=MOBILE -- Display window frame
|
||||||
|
W.resizable=not MOBILE -- Whether window is resizable
|
||||||
|
|
||||||
|
W.fullscreentype=MOBILE and "exclusive" or "desktop" -- Fullscreen type
|
||||||
|
if portrait then
|
||||||
|
W.width,W.height=720,1280
|
||||||
|
W.minwidth,W.minheight=360,640
|
||||||
|
else
|
||||||
|
W.width,W.height=1280,720
|
||||||
|
W.minwidth,W.minheight=640,360
|
||||||
|
end
|
||||||
|
W.title="Techmino "..require"version".string -- Window title
|
||||||
|
if fs.getInfo('media/image/icon.png') then
|
||||||
|
W.icon='media/image/icon.png'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
569
main.lua
@@ -10,10 +10,8 @@
|
|||||||
Instructions:
|
Instructions:
|
||||||
1. I made a framework called Zframework, *most* code in Zframework are not directly relevant to game;
|
1. I made a framework called Zframework, *most* code in Zframework are not directly relevant to game;
|
||||||
2. "xxx" are texts for reading by player, 'xxx' are string values just used in program;
|
2. "xxx" are texts for reading by player, 'xxx' are string values just used in program;
|
||||||
3. Some goto statement are used for better performance. All goto-labes have detailed names so don't be afraid;
|
3. Except "gcinfo" function of lua itself, other "gc" are short for "graphics";
|
||||||
4. Except "gcinfo" function of lua itself, other "gc" are short for "graphics";
|
]]
|
||||||
]]--
|
|
||||||
|
|
||||||
|
|
||||||
-- Var leak check
|
-- 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})
|
-- setmetatable(_G,{__newindex=function(self,k,v) print('>>'..k..string.rep(" ",26-#k),debug.traceback():match("\n.-\n\t(.-): "))rawset(self,k,v) end})
|
||||||
@@ -22,13 +20,10 @@
|
|||||||
local fs=love.filesystem
|
local fs=love.filesystem
|
||||||
VERSION=require"version"
|
VERSION=require"version"
|
||||||
TIME=love.timer.getTime
|
TIME=love.timer.getTime
|
||||||
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'
|
|
||||||
|
|
||||||
-- Global Vars & Settings
|
-- Global Vars & Settings
|
||||||
SFXPACKS={'chiptune'}
|
SFXPACKS={'chiptune'}
|
||||||
VOCPACKS={'miya','mono','xiaoya','miku'}
|
VOCPACKS={'miya','mono','xiaoya','flore','miku','zundamon'}
|
||||||
FIRSTLAUNCH=false
|
FIRSTLAUNCH=false
|
||||||
DAILYLAUNCH=false
|
DAILYLAUNCH=false
|
||||||
|
|
||||||
@@ -37,11 +32,6 @@ math.randomseed(os.time()*626)
|
|||||||
love.setDeprecationOutput(false)
|
love.setDeprecationOutput(false)
|
||||||
love.keyboard.setKeyRepeat(true)
|
love.keyboard.setKeyRepeat(true)
|
||||||
love.keyboard.setTextInput(false)
|
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 _LOADTIMELIST_={}
|
||||||
local _LOADTIME_=TIME()
|
local _LOADTIME_=TIME()
|
||||||
@@ -55,25 +45,20 @@ FONT.load{
|
|||||||
FONT.setDefault('norm')
|
FONT.setDefault('norm')
|
||||||
FONT.setFallback('norm')
|
FONT.setFallback('norm')
|
||||||
|
|
||||||
SCR.setSize(1280,720)-- Initialize Screen size
|
SCR.setSize(1280,720) -- Initialize Screen size
|
||||||
BGM.setMaxSources(5)
|
BGM.setMaxSources(5)
|
||||||
VOC.setDiversion(.62)
|
VOC.setDiversion(.62)
|
||||||
|
|
||||||
WIDGET.setOnChange(function()
|
WIDGET.setOnChange(function()
|
||||||
if SCN.cur~='custom_field' then
|
if SCN.cur=='net_game' or SCN.cur=='custom_field' then return end
|
||||||
local colorList=THEME.getThemeColor()
|
local colorList=THEME.getThemeColor()
|
||||||
if colorList then
|
if colorList then
|
||||||
for _,W in next,SCN.scenes[SCN.cur].widgetList do
|
for _,W in next,SCN.scenes[SCN.cur].widgetList do
|
||||||
if W.color then
|
W.color=W.color and colorList[math.random(#colorList)]
|
||||||
W.color=colorList[math.random(#colorList)]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
table.insert(_LOADTIMELIST_,("Load Zframework: %.3fs"):format(TIME()-_LOADTIME_))
|
|
||||||
|
|
||||||
-- Create shortcuts
|
-- Create shortcuts
|
||||||
setFont=FONT.set
|
setFont=FONT.set
|
||||||
getFont=FONT.get
|
getFont=FONT.get
|
||||||
@@ -98,10 +83,6 @@ for _,v in next,{'conf','record','replay','cache','lib'} do
|
|||||||
end
|
end
|
||||||
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={}
|
SHADER={}
|
||||||
for _,v in next,fs.getDirectoryItems('parts/shaders') do
|
for _,v in next,fs.getDirectoryItems('parts/shaders') do
|
||||||
@@ -111,31 +92,57 @@ for _,v in next,fs.getDirectoryItems('parts/shaders') do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
THEME= require'parts.theme'
|
-- Load modules
|
||||||
LINE= require'parts.line'
|
CHAR=require'parts.char'
|
||||||
DATA= require'parts.data'
|
require'parts.gameTables'
|
||||||
|
require'parts.gameFuncs'
|
||||||
|
|
||||||
TEXTURE= require'parts.texture'
|
THEME =require'parts.theme'
|
||||||
SKIN= require'parts.skin'
|
LINE =require'parts.line'
|
||||||
USERS= require'parts.users'
|
DATA =require'parts.data'
|
||||||
NET= require'parts.net'
|
|
||||||
VK= require'parts.virtualKey'
|
|
||||||
BOT= require'parts.bot'
|
|
||||||
RSlist= require'parts.RSlist'DSCP=RSlist.TRS.centerPos
|
|
||||||
PLY= require'parts.player'
|
|
||||||
NETPLY= require'parts.netPlayer'
|
|
||||||
MODES= require'parts.modes'
|
|
||||||
|
|
||||||
setmetatable(TEXTURE,{__index=function(self,k)
|
TEXTURE=require'parts.texture'
|
||||||
MES.new('warn',"No texture called: "..k)
|
SKIN =require'parts.skin'
|
||||||
self[k]=PAPER
|
USERS =require'parts.users'
|
||||||
return self[k]
|
NET =require'parts.net'
|
||||||
end})
|
VK =require'parts.virtualKey'
|
||||||
|
BOT =require'parts.bot'
|
||||||
|
RSlist =require'parts.RSlist'; DSCP=RSlist.TRS.centerPos
|
||||||
|
PLY =require'parts.player'
|
||||||
|
NETPLY =require'parts.netPlayer'
|
||||||
|
MODES =require'parts.modes'
|
||||||
|
|
||||||
table.insert(_LOADTIMELIST_,("Load Parts: %.3fs"):format(TIME()-_LOADTIME_))
|
setmetatable(TEXTURE,{
|
||||||
|
__index=function(self,k)
|
||||||
|
MES.new('warn',"No texture called: "..k)
|
||||||
|
self[k]=PAPER
|
||||||
|
return self[k]
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
-- Init Zframework
|
-- Load mode files
|
||||||
do-- Z.setCursor
|
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_))
|
||||||
|
|
||||||
|
-- Initialize Zframework
|
||||||
|
do -- Z.setCursor
|
||||||
local normImg=GC.DO{16,16,
|
local normImg=GC.DO{16,16,
|
||||||
{'fCirc',8,8,4},
|
{'fCirc',8,8,4},
|
||||||
{'setCL',1,1,1,.7},
|
{'setCL',1,1,1,.7},
|
||||||
@@ -165,7 +172,7 @@ Z.setOnFnKeys({
|
|||||||
function() MES.new('error',"挂了") end,
|
function() MES.new('error',"挂了") end,
|
||||||
function()
|
function()
|
||||||
if GAME.playing and not GAME.net then
|
if GAME.playing and not GAME.net then
|
||||||
for _=1,8 do
|
for _=1,1 do
|
||||||
if #PLY_ALIVE>1 then
|
if #PLY_ALIVE>1 then
|
||||||
local P=PLY_ALIVE[math.random(2,#PLY_ALIVE)]
|
local P=PLY_ALIVE[math.random(2,#PLY_ALIVE)]
|
||||||
P.lastRecv=PLAYERS[1]
|
P.lastRecv=PLAYERS[1]
|
||||||
@@ -179,18 +186,20 @@ Z.setOnFnKeys({
|
|||||||
function() if love['_openConsole'] then love['_openConsole']() end end,
|
function() if love['_openConsole'] then love['_openConsole']() end end,
|
||||||
})
|
})
|
||||||
Z.setOnGlobalKey('f11',function()
|
Z.setOnGlobalKey('f11',function()
|
||||||
SETTING.fullscreen=not SETTING.fullscreen
|
if not MOBILE then
|
||||||
applySettings()
|
SETTING.fullscreen=not SETTING.fullscreen
|
||||||
saveSettings()
|
applySettings('fullscreen')
|
||||||
|
saveSettings()
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
Z.setVersionText(VERSION.string)
|
Z.setVersionText(VERSION.string)
|
||||||
Z.setDebugInfo{
|
Z.setDebugInfo{
|
||||||
{"Cache",gcinfo},
|
{"Cache", gcinfo},
|
||||||
{"Tasks",TASK.getCount},
|
{"Tasks", TASK.getCount},
|
||||||
{"Voices",VOC.getQueueCount},
|
{"Voices",VOC.getQueueCount},
|
||||||
{"Audios",love.audio.getSourceCount},
|
{"Audios",love.audio.getSourceCount},
|
||||||
}
|
}
|
||||||
do-- Z.setOnFocus
|
do -- Z.setOnFocus
|
||||||
local function task_autoSoundOff()
|
local function task_autoSoundOff()
|
||||||
while true do
|
while true do
|
||||||
coroutine.yield()
|
coroutine.yield()
|
||||||
@@ -239,45 +248,6 @@ Z.setOnQuit(function()
|
|||||||
destroyPlayers()
|
destroyPlayers()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- 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
|
|
||||||
|
|
||||||
-- 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)
|
|
||||||
|
|
||||||
|
|
||||||
-- Initialize image libs
|
-- Initialize image libs
|
||||||
IMG.init{
|
IMG.init{
|
||||||
lock='media/image/mess/lock.png',
|
lock='media/image/mess/lock.png',
|
||||||
@@ -298,8 +268,9 @@ IMG.init{
|
|||||||
monoCH='media/image/characters/mono.png',
|
monoCH='media/image/characters/mono.png',
|
||||||
xiaoyaCH='media/image/characters/xiaoya.png',
|
xiaoyaCH='media/image/characters/xiaoya.png',
|
||||||
xiaoyaOmino='media/image/characters/xiaoya_Omino.png',
|
xiaoyaOmino='media/image/characters/xiaoya_Omino.png',
|
||||||
|
floreCH='media/image/characters/flore.png',
|
||||||
mikuCH='media/image/characters/miku.png',
|
mikuCH='media/image/characters/miku.png',
|
||||||
rinCH='media/image/characters/rin.png',
|
zundamonCH='media/image/characters/zundamon.png',
|
||||||
z={
|
z={
|
||||||
character='media/image/characters/z_character.png',
|
character='media/image/characters/z_character.png',
|
||||||
screen1='media/image/characters/z_screen1.png',
|
screen1='media/image/characters/z_screen1.png',
|
||||||
@@ -322,46 +293,46 @@ IMG.init{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
SKIN.load{
|
SKIN.load{
|
||||||
{name="crystal_scf",path='media/image/skin/crystal_scf.png'},
|
{name="crystal_scf", path='media/image/skin/crystal_scf.png'},
|
||||||
{name="matte_mrz",path='media/image/skin/matte_mrz.png'},
|
{name="matte_mrz", path='media/image/skin/matte_mrz.png'},
|
||||||
{name="shiny_chno",path='media/image/skin/shiny_chno.png'},
|
{name="shiny_chno", path='media/image/skin/shiny_chno.png'},
|
||||||
{name="contrast_mrz",path='media/image/skin/contrast_mrz.png'},
|
{name="contrast_mrz", path='media/image/skin/contrast_mrz.png'},
|
||||||
{name="polkadots_scf",path='media/image/skin/polkadots_scf.png'},
|
{name="polkadots_scf", path='media/image/skin/polkadots_scf.png'},
|
||||||
{name="toy_scf",path='media/image/skin/toy_scf.png'},
|
{name="toy_scf", path='media/image/skin/toy_scf.png'},
|
||||||
{name="smooth_mrz",path='media/image/skin/smooth_mrz.png'},
|
{name="smooth_mrz", path='media/image/skin/smooth_mrz.png'},
|
||||||
{name="simple_scf",path='media/image/skin/simple_scf.png'},
|
{name="simple_scf", path='media/image/skin/simple_scf.png'},
|
||||||
{name="glass_scf",path='media/image/skin/glass_scf.png'},
|
{name="glass_scf", path='media/image/skin/glass_scf.png'},
|
||||||
{name="penta_scf",path='media/image/skin/penta_scf.png'},
|
{name="penta_scf", path='media/image/skin/penta_scf.png'},
|
||||||
{name="bubble_scf",path='media/image/skin/bubble_scf.png'},
|
{name="bubble_scf", path='media/image/skin/bubble_scf.png'},
|
||||||
{name="minoes_scf",path='media/image/skin/minoes_scf.png'},
|
{name="minoes_scf", path='media/image/skin/minoes_scf.png'},
|
||||||
{name="pure_mrz",path='media/image/skin/pure_mrz.png'},
|
{name="pure_mrz", path='media/image/skin/pure_mrz.png'},
|
||||||
{name="bright_scf",path='media/image/skin/bright_scf.png'},
|
{name="bright_scf", path='media/image/skin/bright_scf.png'},
|
||||||
{name="glow_mrz",path='media/image/skin/glow_mrz.png'},
|
{name="glow_mrz", path='media/image/skin/glow_mrz.png'},
|
||||||
{name="plastic_mrz",path='media/image/skin/plastic_mrz.png'},
|
{name="plastic_mrz", path='media/image/skin/plastic_mrz.png'},
|
||||||
{name="paper_mrz",path='media/image/skin/paper_mrz.png'},
|
{name="paper_mrz", path='media/image/skin/paper_mrz.png'},
|
||||||
{name="yinyang_scf",path='media/image/skin/yinyang_scf.png'},
|
{name="yinyang_scf", path='media/image/skin/yinyang_scf.png'},
|
||||||
{name="cartooncup_earety",path='media/image/skin/cartooncup_earety.png'},
|
{name="cartooncup_earety", path='media/image/skin/cartooncup_earety.png'},
|
||||||
{name="jelly_miya",path='media/image/skin/jelly_miya.png'},
|
{name="jelly_miya", path='media/image/skin/jelly_miya.png'},
|
||||||
{name="guidetris_xmiao_lusisi",path='media/image/skin/guidetris_xmiao_lusisi.png'},
|
{name="guidetris_xmiao_lusisi",path='media/image/skin/guidetris_xmiao_lusisi.png'},
|
||||||
{name="brick_notypey",path='media/image/skin/brick_notypey.png'},
|
{name="brick_notypey", path='media/image/skin/brick_notypey.png'},
|
||||||
{name="gem_notypey",path='media/image/skin/gem_notypey.png'},
|
{name="gem_notypey", path='media/image/skin/gem_notypey.png'},
|
||||||
{name="classic",path='media/image/skin/classic_unknown.png'},
|
{name="classic", path='media/image/skin/classic_unknown.png'},
|
||||||
{name="ball_shaw",path='media/image/skin/ball_shaw.png'},
|
{name="ball_shaw", path='media/image/skin/ball_shaw.png'},
|
||||||
{name="retro_notypey",path='media/image/skin/retro_notypey.png'},
|
{name="retro_notypey", path='media/image/skin/retro_notypey.png'},
|
||||||
{name="pixel_chno",path='media/image/skin/pixel_chno.png'},
|
{name="pixel_chno", path='media/image/skin/pixel_chno.png'},
|
||||||
{name="pastel_chno",path='media/image/skin/pastel_chno.png'},
|
{name="pastel_chno", path='media/image/skin/pastel_chno.png'},
|
||||||
{name="letters_chno",path='media/image/skin/letters_chno.png'},
|
{name="letters_chno", path='media/image/skin/letters_chno.png'},
|
||||||
{name="kanji_chno",path='media/image/skin/kanji_chno.png'},
|
{name="kanji_chno", path='media/image/skin/kanji_chno.png'},
|
||||||
{name="textbone_mrz",path='media/image/skin/textbone_mrz.png'},
|
{name="textbone_mrz", path='media/image/skin/textbone_mrz.png'},
|
||||||
{name="coloredbone_mrz",path='media/image/skin/coloredbone_mrz.png'},
|
{name="coloredbone_mrz", path='media/image/skin/coloredbone_mrz.png'},
|
||||||
{name="wtf",path='media/image/skin/wtf_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
|
SFX.init((function() --[Warning] Not loading files here, just get the list of sound needed
|
||||||
local L={}
|
local L={}
|
||||||
for _,v in next,fs.getDirectoryItems('media/effect/chiptune/') do
|
for _,v in next,fs.getDirectoryItems('media/effect/chiptune/') do
|
||||||
if FILE.isSafe('media/effect/chiptune/'..v,"Dangerous file : %SAVE%/media/effect/chiptune/"..v) then
|
if FILE.isSafe('media/effect/chiptune/'..v) then
|
||||||
table.insert(L,v:sub(1,-5))
|
table.insert(L,v:sub(1,-5))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -370,7 +341,7 @@ end)())
|
|||||||
BGM.init((function()
|
BGM.init((function()
|
||||||
local L={}
|
local L={}
|
||||||
for _,v in next,fs.getDirectoryItems('media/music') do
|
for _,v in next,fs.getDirectoryItems('media/music') do
|
||||||
if FILE.isSafe('media/music/'..v,"Dangerous file : %SAVE%/media/music/"..v) then
|
if FILE.isSafe('media/music/'..v) then
|
||||||
L[v:sub(1,-5)]='media/music/'..v
|
L[v:sub(1,-5)]='media/music/'..v
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -378,7 +349,7 @@ BGM.init((function()
|
|||||||
end)())
|
end)())
|
||||||
VOC.init{
|
VOC.init{
|
||||||
'zspin','sspin','jspin','lspin','tspin','ospin','ispin','pspin','qspin','fspin','espin','uspin','vspin','wspin','xspin','rspin','yspin','nspin','hspin','cspin',
|
'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',
|
'mini','b2b','b3b',
|
||||||
'perfect_clear','half_clear',
|
'perfect_clear','half_clear',
|
||||||
'win','lose','bye',
|
'win','lose','bye',
|
||||||
@@ -386,161 +357,50 @@ VOC.init{
|
|||||||
'welcome',
|
'welcome',
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Initialize language lib
|
table.insert(_LOADTIMELIST_,("Initialize Modules: %.3fs"):format(TIME()-_LOADTIME_))
|
||||||
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',
|
|
||||||
-- 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_))
|
-- Load settings and statistics
|
||||||
|
if
|
||||||
-- Load background files from SOURCE ONLY
|
not (
|
||||||
for _,v in next,fs.getDirectoryItems('parts/backgrounds') do
|
pcall(TABLE.cover, loadFile('conf/user', '-json -canSkip') or loadFile('conf/user', '-luaon -canSkip') or {},USER) and
|
||||||
if FILE.isSafe('parts/backgrounds/'..v) and v:sub(-3)=='lua' then
|
pcall(TABLE.cover, loadFile('conf/unlock', '-json -canSkip') or loadFile('conf/unlock', '-luaon -canSkip') or {},RANKS) and
|
||||||
local name=v:sub(1,-5)
|
pcall(TABLE.update,loadFile('conf/settings', '-json -canSkip') or loadFile('conf/settings', '-luaon -canSkip') or {},SETTING) and
|
||||||
BG.add(name,require('parts.backgrounds.'..name))
|
pcall(TABLE.coverR,loadFile('conf/data', '-json -canSkip') or loadFile('conf/data', '-luaon -canSkip') or {},STAT) and
|
||||||
end
|
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
|
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 FILE.isSafe('parts/scenes/'..v) then
|
|
||||||
local sceneName=v:sub(1,-5)
|
|
||||||
SCN.add(sceneName,require('parts.scenes.'..sceneName))
|
|
||||||
LANG.addScene(sceneName)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- 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 Files: %.3fs"):format(TIME()-_LOADTIME_))
|
|
||||||
|
|
||||||
-- Update data
|
-- Update data
|
||||||
do
|
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
|
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
|
end
|
||||||
if STAT.version<1700 and SETTING.dascut<5 then
|
if STAT.version<1700 and SETTING.dascut<5 then
|
||||||
SETTING.dascut=SETTING.dascut+1
|
SETTING.dascut=SETTING.dascut+1
|
||||||
needSave=true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if RANKS.stack_e then
|
if RANKS.stack_e then
|
||||||
RANKS.stack_e=nil
|
RANKS.stack_e=nil; fs.remove('record/stack_e.rec')
|
||||||
RANKS.stack_h=nil
|
RANKS.stack_h=nil; fs.remove('record/stack_h.rec')
|
||||||
RANKS.stack_u=nil
|
RANKS.stack_u=nil; fs.remove('record/stack_u.rec')
|
||||||
fs.remove('record/stack_e.rec')
|
|
||||||
fs.remove('record/stack_h.rec')
|
|
||||||
fs.remove('record/stack_u.rec')
|
|
||||||
end
|
end
|
||||||
if RANKS.stack_20l then
|
if RANKS.stack_20l then
|
||||||
RANKS.stack_20l=nil
|
RANKS.stack_20l=nil; fs.remove('record/stack_20l.rec')
|
||||||
RANKS.stack_40l=nil
|
RANKS.stack_40l=nil; fs.remove('record/stack_40l.rec')
|
||||||
RANKS.stack_100l=nil
|
RANKS.stack_100l=nil; fs.remove('record/stack_100l.rec')
|
||||||
fs.remove('record/stack_20l.rec')
|
|
||||||
fs.remove('record/stack_40l.rec')
|
|
||||||
fs.remove('record/stack_100l.rec')
|
|
||||||
end
|
end
|
||||||
if RANKS.rhythm_e then
|
if RANKS.rhythm_e then
|
||||||
RANKS.rhythm_e=nil
|
RANKS.rhythm_e=nil; fs.remove('record/rhythm_e.rec')
|
||||||
RANKS.rhythm_h=nil
|
RANKS.rhythm_h=nil; fs.remove('record/rhythm_h.rec')
|
||||||
RANKS.rhythm_u=nil
|
RANKS.rhythm_u=nil; fs.remove('record/rhythm_u.rec')
|
||||||
fs.remove('record/rhythm_e.rec')
|
|
||||||
fs.remove('record/rhythm_h.rec')
|
|
||||||
fs.remove('record/rhythm_u.rec')
|
|
||||||
end
|
|
||||||
if RANKS.bigbang or RANKS.clearRush then
|
|
||||||
fs.remove('record/clearRush.rec')
|
|
||||||
fs.remove('record/bigbang.rec')
|
|
||||||
end
|
end
|
||||||
|
if RANKS.bigbang then fs.remove('record/bigbang.rec') end
|
||||||
|
if RANKS.clearRush then fs.remove('record/clearRush.rec') end
|
||||||
|
if STAT.version<1715 then fs.remove('record/dig_quad_10l.rec') end
|
||||||
|
|
||||||
if STAT.version~=VERSION.code then
|
if STAT.version~=VERSION.code then
|
||||||
for k,v in next,MODE_UPDATE_MAP do
|
for k,v in next,MODE_UPDATE_MAP do
|
||||||
if RANKS[k] then
|
if RANKS[k] then
|
||||||
@@ -558,7 +418,6 @@ do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
STAT.version=VERSION.code
|
STAT.version=VERSION.code
|
||||||
needSave=true
|
|
||||||
end
|
end
|
||||||
SETTING.appLock,SETTING.dataSaving,SETTING.swap,SETTING.autoLogin=nil
|
SETTING.appLock,SETTING.dataSaving,SETTING.swap,SETTING.autoLogin=nil
|
||||||
if not SETTING.VKSkin then SETTING.VKSkin=1 end
|
if not SETTING.VKSkin then SETTING.VKSkin=1 end
|
||||||
@@ -576,41 +435,96 @@ do
|
|||||||
if RANKS.infinite then RANKS.infinite=0 end
|
if RANKS.infinite then RANKS.infinite=0 end
|
||||||
if RANKS.infinite_dig then RANKS.infinite_dig=0 end
|
if RANKS.infinite_dig then RANKS.infinite_dig=0 end
|
||||||
if not RANKS.sprint_10l then RANKS.sprint_10l=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_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 needSave=true end
|
if RANKS.master_u then RANKS.master_h,RANKS.master_u=RANKS.master_u end
|
||||||
|
if RANKS.secret_grade then RANKS.construct_sg,RANKS.secret_grade=RANKS.secret_grade end
|
||||||
for _,v in next,VK_ORG do v.color=nil end
|
for _,v in next,VK_ORG do v.color=nil end
|
||||||
for name,rank in next,RANKS do
|
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
|
RANKS[name]=nil
|
||||||
needSave=true
|
|
||||||
else
|
else
|
||||||
local M=MODES[name]
|
local M=MODES[name]
|
||||||
if M and M.unlock and rank>0 then
|
if M and M.unlock and rank>0 then
|
||||||
for _,unlockName in next,M.unlock do
|
for _,unlockName in next,M.unlock do
|
||||||
if not RANKS[unlockName] then
|
if not RANKS[unlockName] then
|
||||||
RANKS[unlockName]=0
|
RANKS[unlockName]=0
|
||||||
needSave=true
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not (M and M.x) then
|
if not (M and M.x) then
|
||||||
RANKS[name]=nil
|
RANKS[name]=nil
|
||||||
needSave=true
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not MODES[STAT.lastPlay] then
|
if not MODES[STAT.lastPlay] then
|
||||||
STAT.lastPlay='sprint_10l'
|
STAT.lastPlay='sprint_10l'
|
||||||
needSave=true
|
|
||||||
end
|
end
|
||||||
|
fs.remove('conf/account')
|
||||||
|
|
||||||
if needSave then
|
saveStats()
|
||||||
saveStats()
|
saveProgress()
|
||||||
saveProgress()
|
saveSettings()
|
||||||
saveSettings()
|
end
|
||||||
love.event.quit('restart')
|
|
||||||
|
-- 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
|
||||||
end
|
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 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
|
-- First start
|
||||||
FIRSTLAUNCH=STAT.run==0
|
FIRSTLAUNCH=STAT.run==0
|
||||||
@@ -626,50 +540,63 @@ applySettings()
|
|||||||
-- Load replays
|
-- Load replays
|
||||||
for _,fileName in next,fs.getDirectoryItems('replay') do
|
for _,fileName in next,fs.getDirectoryItems('replay') do
|
||||||
if fileName:sub(12,12):match("[a-zA-Z]") then
|
if fileName:sub(12,12):match("[a-zA-Z]") then
|
||||||
local date,mode,version,player,seed,setting,mod
|
repeat
|
||||||
local fileData=fs.read('replay/'..fileName)
|
local date,mode,version,player,seed,setting,mod
|
||||||
date, fileData=STRING.readLine(fileData)date=date:gsub("[a-zA-Z]","")
|
local success,fileData=true,fs.read('replay/'..fileName)
|
||||||
mode, fileData=STRING.readLine(fileData)mode=MODE_UPDATE_MAP[mode] or mode
|
date,fileData=STRING.readLine(fileData)
|
||||||
version,fileData=STRING.readLine(fileData)
|
date=date:gsub("[a-zA-Z]","")
|
||||||
player, fileData=STRING.readLine(fileData) if player=="Local Player" then player="Stacker" end
|
mode,fileData=STRING.readLine(fileData)
|
||||||
local success
|
mode=MODE_UPDATE_MAP[mode] or mode
|
||||||
success,fileData=pcall(love.data.decompress,'string','zlib',fileData)
|
version,fileData=STRING.readLine(fileData)
|
||||||
if not success then goto BREAK_cannotParse end
|
player,fileData=STRING.readLine(fileData)
|
||||||
seed, fileData=STRING.readLine(fileData)
|
if player=="Local Player" then player="Stacker" end
|
||||||
setting,fileData=STRING.readLine(fileData)setting=JSON.decode(setting)
|
success,fileData=pcall(love.data.decompress,'string','zlib',fileData)
|
||||||
mod, fileData=STRING.readLine(fileData)mod=JSON.decode(mod)
|
if not success then break end
|
||||||
if
|
seed,fileData=STRING.readLine(fileData)
|
||||||
not setting or
|
setting,fileData=STRING.readLine(fileData)
|
||||||
not mod or
|
setting=JSON.decode(setting)
|
||||||
not mode or
|
mod,fileData=STRING.readLine(fileData)
|
||||||
#mode==0
|
mod=JSON.decode(mod)
|
||||||
then goto BREAK_cannotParse end
|
if
|
||||||
|
not setting or
|
||||||
|
not mod or
|
||||||
|
not mode or
|
||||||
|
#mode==0
|
||||||
|
then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
fs.remove('replay/'..fileName)
|
fs.remove('replay/'..fileName)
|
||||||
local newName=fileName:sub(1,10)..fileName:sub(15)
|
local newName=fileName:sub(1,10)..fileName:sub(15)
|
||||||
fs.write('replay/'..newName,
|
fs.write('replay/'..newName,
|
||||||
love.data.compress('string','zlib',
|
love.data.compress('string','zlib',
|
||||||
JSON.encode{
|
JSON.encode{
|
||||||
date=date,
|
date=date,
|
||||||
mode=mode,
|
mode=mode,
|
||||||
version=version,
|
version=version,
|
||||||
player=player,
|
player=player,
|
||||||
seed=seed,
|
seed=seed,
|
||||||
setting=setting,
|
setting=setting,
|
||||||
mod=mod,
|
mod=mod,
|
||||||
}.."\n"..
|
}.."\n"..
|
||||||
fileData
|
fileData
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
fileName=newName
|
||||||
fileName=newName
|
until true
|
||||||
end
|
end
|
||||||
::BREAK_cannotParse::
|
|
||||||
local rep=DATA.parseReplay('replay/'..fileName)
|
local rep=DATA.parseReplay('replay/'..fileName)
|
||||||
table.insert(REPLAY,rep)
|
table.insert(REPLAY,rep)
|
||||||
end
|
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)
|
||||||
|
|
||||||
|
table.insert(_LOADTIMELIST_,("Load Resources: %.3fs"):format(TIME()-_LOADTIME_))
|
||||||
|
|
||||||
for i=1,#_LOADTIMELIST_ do LOG(_LOADTIMELIST_[i]) end
|
for i=1,#_LOADTIMELIST_ do LOG(_LOADTIMELIST_[i]) end
|
||||||
|
|
||||||
@@ -679,7 +606,8 @@ if TABLE.find(arg,'-- test') then
|
|||||||
while not LOADED do coroutine.yield() end
|
while not LOADED do coroutine.yield() end
|
||||||
|
|
||||||
LOG("\27[92m\27[1mAutomatic Test Started\27[0m")
|
LOG("\27[92m\27[1mAutomatic Test Started\27[0m")
|
||||||
BGM.setVol(0)SFX.setVol(0)
|
BGM.setVol(0)
|
||||||
|
SFX.setVol(0)
|
||||||
love.keypressed('space')
|
love.keypressed('space')
|
||||||
TEST.yieldUntilNextScene()
|
TEST.yieldUntilNextScene()
|
||||||
|
|
||||||
@@ -706,6 +634,3 @@ if TABLE.find(arg,'-- test') then
|
|||||||
love.event.quit(1)
|
love.event.quit(1)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
WS.switchHost('cafuuchino1.3322.org','10026','/techmino/ws/v1')
|
|
||||||
HTTP.setHost("cafuuchino1.3322.org:10026")
|
|
||||||
HTTP.setThreadCount(1)
|
|
||||||
|
|||||||
BIN
media/effect/chiptune/mod_off.ogg
Normal file
BIN
media/effect/chiptune/mod_on.ogg
Normal file
BIN
media/image/characters/flore.png
Normal file
|
After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 117 KiB |
BIN
media/image/characters/zundamon.png
Normal file
|
After Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 483 B After Width: | Height: | Size: 933 B |
|
Before Width: | Height: | Size: 207 B After Width: | Height: | Size: 1.3 KiB |
BIN
media/image/modeicon/hidden3.png
Normal file
|
After Width: | Height: | Size: 950 B |
BIN
media/image/modeicon/hidden4.png
Normal file
|
After Width: | Height: | Size: 925 B |
BIN
media/image/modeicon/hidden5.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
2
media/image/modeicon/note.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
If the modeicon you're looking for isn't here, try looking in /parts/scenes/load.lua.
|
||||||
|
We vectorized some of them for better scalability.
|
||||||
|
Before Width: | Height: | Size: 489 B |
|
Before Width: | Height: | Size: 488 B |
|
Before Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 395 B |
|
Before Width: | Height: | Size: 457 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 25 KiB |