Compare commits

..

228 Commits

Author SHA1 Message Date
MrZ626
07b47dee3f 版本推进 2021-11-30 01:50:13 +08:00
MrZ626
4431a906b9 整理代码 2021-11-30 01:44:21 +08:00
NOT_A_ROBOT
2bb6852e3e Added multiple bg and bgm to Strategy Mode (#506)
(excluding strategy_e for the bgm)
2021-11-30 01:42:39 +08:00
user670
1948ed3e16 Update gameTables.lua (#508)
On an XBox controller, B is on the right and A is on the bottom (unlike a Nintendo controller), and it makes more sense to default B to rotate right and A to rotate left.
2021-11-30 01:42:02 +08:00
MrZ626
81b5ccae30 修复检测第一次启动失败 2021-11-30 01:40:53 +08:00
MrZ626
5543ff0d29 新小程序:Triple 2021-11-30 01:40:49 +08:00
MrZ626
cd567e9e98 删除添加作者qq按钮 2021-11-30 01:40:01 +08:00
MrZ626
5d86925a8a 大多数菜单的二次确认统一用tryXXX管理 2021-11-30 01:40:01 +08:00
MrZ626
e3db564a4b 整理代码,返回需要二次确认的小程序统一用一个函数 2021-11-30 01:40:01 +08:00
MrZ626
a4293624ab 微调wine颜色 2021-11-29 22:24:17 +08:00
MrZ626
367e2dc81a 新增几个tip 2021-11-29 21:32:09 +08:00
MrZ626
9ec33c6eef 修改BGM: sugar fairy的作者标注 2021-11-29 21:32:08 +08:00
MrZ626
9c9b8d36f2 小程序mem平衡调整 2021-11-29 21:32:08 +08:00
MrZ626
4fc6f335c7 新增小程序:Memorize 2021-11-29 15:40:55 +08:00
MrZ626
d2f4123d08 修改两个有数字键盘的小程序的退格键图标 2021-11-29 15:40:40 +08:00
MrZ626
b29d352a1b 把主菜单快捷键加回来 2021-11-29 12:57:17 +08:00
MrZ626
cd5a71cd12 更新赞助名单 2021-11-29 12:49:58 +08:00
MrZ626
cdd68e985d 修正键位设置菜单里mac的del键符号错误 2021-11-29 11:15:24 +08:00
MrZ626
8cf4d4280c 修正Ospin变O后操作序列不清空
Ospin变远端朝下JL时允许水平可移动
2021-11-29 11:11:54 +08:00
C29H25N3O5
cd29bf8702 调整字体
* Monospaced字体简中字库使用大陆标准字形, 日语部分仍然使用日语字形
* 调整自定义图标手柄和键盘部分的文字字体
* 修复proportional字体a的变音符没对齐的问题
* 修复Monospaced字体ij连字的问题
* 修复Monospaced字体slash还用的是plex字体的问题
2021-11-28 18:24:11 -06:00
MrZ626
13d98be051 版本推进 2021-11-29 04:23:05 +08:00
MrZ626
a350ff3182 微调背景模块,自定义模式设置背景的时候访问不到特殊背景了 2021-11-29 04:22:08 +08:00
MrZ626
e0360cc7eb 修正一处模块更新错误(傻了) 2021-11-29 03:57:18 +08:00
MrZ626
4249a29b63 继续优化键位设置菜单 2021-11-29 03:38:05 +08:00
MrZ626
43b2a0a8c8 优化键位设置菜单各种键的显示 2021-11-29 03:27:57 +08:00
MrZ626
6d6584f99e 修改按钮音效,给复选框和选择器添加新音效 2021-11-29 02:48:41 +08:00
MrZ626
077c651226 微调键位设置菜单 2021-11-29 01:16:22 +08:00
MrZ626
3fc872aa76 微调几个隐藏模式入口点击范围 2021-11-28 22:39:49 +08:00
MrZ626
cb0b347a38 更新赞助名单 2021-11-28 22:21:10 +08:00
MrZ626
d08967c688 整理词典 2021-11-28 22:02:39 +08:00
MrZ626
3666c0caa9 修复更换自定义背景图片时没有更新尺寸 2021-11-28 20:52:12 +08:00
MrZ626
4ef179fccb 控制台场景向全局环境添加一个输出到控制台的函数 close #499 2021-11-28 19:51:46 +08:00
MrZ626
861f9b3caa 继续完善手柄控制 2021-11-28 19:40:26 +08:00
MrZ626
05292df456 模式地图上读取手柄按键时不再报错 2021-11-28 17:43:36 +08:00
MrZ626
9fed692223 控制台help命令输出美化 close #502 2021-11-28 16:53:24 +08:00
MrZ626
b1c04c1fea 修复自定义模式用按钮开始游戏会报错 2021-11-28 16:21:27 +08:00
MrZ626
bc9adc2cd3 调整扳机键的默认触发阈值 2021-11-28 16:16:44 +08:00
MrZ626
cdf149afca 略微优化自定义背景绘制性能 2021-11-28 05:20:29 +08:00
MrZ626
73145b4e5e 自定义背景拖入无法识别的格式时会提示 2021-11-28 05:20:18 +08:00
MrZ626
f8b9f30fd6 修改框架的光标默认位置 2021-11-28 05:02:29 +08:00
MrZ626
e6bc567b12 两种按钮上的文本也会挤压绘制了
优化控件绘制性能
修正两个背景设置按钮位置错误
调整之前忘了同步的语言
2021-11-28 04:56:55 +08:00
MrZ626
fe004a72f0 版本推进 2021-11-28 04:17:44 +08:00
MrZ626
0433fd3d9d 三个高难隐形使用不同模式图标 close #493 2021-11-28 04:10:42 +08:00
MrZ626
1c18060570 尝试修复地图菜单读取手柄摇杆位置错误 2021-11-28 04:06:37 +08:00
MrZ626
be54c0e641 关闭背景时亮度可调
新增自定义图片背景功能(可调透明度,目前仅电脑可用)
2021-11-28 03:56:53 +08:00
MrZ626
0be2eb9107 修正一处可能未改回材质缩放模式 2021-11-28 03:30:34 +08:00
MrZ626
4859faf1e7 创建控件允许留空code域,什么都不会发生 2021-11-28 02:03:52 +08:00
MrZ626
c25d40c67d 启动加载数据文件时允许不存在,不会提醒 close #495 2021-11-28 01:59:24 +08:00
MrZ626
b6c37a5c9f 框架keyDown事件机制微调,重构框架主循环和控件相关代码
可以用键盘和手柄控制光标(手柄不完善)
整理代码和部分语言文件细节
2021-11-27 23:16:21 +08:00
MrZ626
f6b4c1b109 整理代码,表示键盘按键的字符串使用单引号 2021-11-27 19:01:32 +08:00
MrZ626
841faeede4 版本推进 2021-11-27 14:33:38 +08:00
MrZ626
e61b9b23a0 修复右侧c/s/a+方向键不能触发控件功能 close #492 2021-11-27 14:33:36 +08:00
MrZ626
72a826ef0a 微调报错界面,日志使用等宽字体 2021-11-27 14:25:13 +08:00
MrZ626
f070b8f295 修正svg标题的小问题 2021-11-27 14:20:05 +08:00
MrZ626
1646b75520 修正TRS的v块1<->2比0<->3少一个踢墙 2021-11-27 14:20:05 +08:00
C29H25N3O5
241617e31a 微调字体
* Monospaced的CJK字体也调整为思源
* 改动几个新元素汉字
* 精简Monospaced字符集
2021-11-26 22:58:40 -06:00
MrZ626
5de2893e07 帮0.17前的版本自动调大1帧的das打断,尝试维持手感 2021-11-27 05:52:35 +08:00
MrZ626
030e894040 theme移出框架,大改通常bgm的配置 2021-11-27 05:35:55 +08:00
MrZ626
e7b9a4ba87 添加DRS_weak旋转系统 close #441 2021-11-27 05:09:02 +08:00
MrZ626
617bae67c6 修正matt的一些翻译修改和控制台代码 2021-11-27 04:47:48 +08:00
MattMayuga
64d2d08820 Update English translation (#487)
* Update readme.md

* Update lang_en.lua

* Update app_console.lua

* Update error.lua

* Add warnings and extended time to 10s for resetall

When you use the resetall command, you will now get a message that there is no way to recover the saved data when it is deleted.
2021-11-27 04:28:08 +08:00
NOT_A_ROBOT
037b33c99a Update theme list (#489) 2021-11-27 04:26:40 +08:00
MrZ626
afa69ce9a4 版本推进 2021-11-27 04:24:41 +08:00
MrZ626
3226c0c831 重构字体模块,支持多字体
控制台应用等宽字体
2021-11-27 04:24:40 +08:00
MrZ626
4e759cad4c ultra模式重开时会重新播放bgm 2021-11-27 02:05:48 +08:00
MrZ626
291795928d 更多的设置修改的时候会触发警告 2021-11-26 21:52:10 +08:00
MrZ626
a1315e7f7f 修复一处遗留逻辑hold和序列生成相关的错误 2021-11-26 21:24:34 +08:00
MrZ626
657bc2b4e0 修正加载文件的时候会因为没有应用语言没法弹出消息而报错 2021-11-26 14:15:42 +08:00
MrZ626
d8b12fc55d 版本推进 2021-11-26 01:48:23 +08:00
MrZ626
6d11367ea4 新BGM:malate(暂未使用) 2021-11-26 01:47:14 +08:00
MrZ626
eb9e741b4f 关于界面的对称40行入口换成堆积模式 2021-11-26 00:59:23 +08:00
MrZ626
c47546d501 微调一些玩家动作逻辑
修复零ARE+非零lineARE的时候ihs失效
2021-11-26 00:55:29 +08:00
MrZ626
11aa178fc1 ultra模式计时器样式改为数字 2021-11-25 19:58:22 +08:00
MrZ626
f3a88ef269 游戏内再次封装saveFile和loadFile函数
原本的FILE模块更独立,不基于全局text变量和报错信息而是直接报错
2021-11-25 17:38:09 +08:00
MrZ626
720dc2131f 字符串扩展模块给默认string库补充两个方法repD和sArg 2021-11-25 17:37:46 +08:00
MrZ626
701ef17ae1 大爆炸改名清版竞速 2021-11-25 14:03:36 +08:00
MrZ626
1a689a5f07 修正当前方块显示条件 2021-11-25 09:57:45 +08:00
MrZ626
ef12ab0cee 版本推进 2021-11-25 02:43:57 +08:00
MrZ626
3d26db7a01 整理代码,修复消行延迟和出块延迟在极小时的错误行为 2021-11-25 02:42:25 +08:00
MrZ626
dd3df9981b TRS的J/L新增一个踢墙 2021-11-25 02:08:53 +08:00
MrZ626
5d04e83529 修正一个赞助id 2021-11-25 01:13:55 +08:00
MrZ626
7ed4626d71 微调logo 2021-11-24 21:34:26 +08:00
MrZ626
ecf5a29a71 添加一个赞助人 2021-11-24 20:36:52 +08:00
MrZ626
1a24b346a0 修正英文文本缺一个holdMode 2021-11-24 20:36:47 +08:00
MrZ626
72d06c7a02 软降n格的键也可以触发深降 2021-11-24 20:26:24 +08:00
MrZ626
26fde8c694 微调默认摇杆参数 2021-11-24 20:17:53 +08:00
MrZ626
8adeb99be7 修正标题图像素材首字母偏低 close #485 2021-11-24 19:39:38 +08:00
MrZ626
c92f15156b 虚拟按键显示开关移至菜单第一页
修改部分不常用设置时会显示警告
2021-11-24 19:33:08 +08:00
MrZ626
63f69d712b 修复自定义房间改不了锁外即死规则 close #484 2021-11-24 11:20:49 +08:00
MrZ626
55a1bd06f3 版本推进 2021-11-24 06:41:51 +08:00
MrZ626
6a29abf7f0 自定义hold数量为0时不显示hold模式选择器,顺便更新创建房间参数ui遗漏 close #483 2021-11-23 22:30:43 +08:00
MrZ626
83bdd9f2c4 【警告:可能有bug,需要测试】
较大规模整理玩家相关代码
较大规模整理玩家相关代码,重构出块延迟和消行延迟逻辑,现在0是真的无延迟,不再有1帧等待了
添加出块延迟打断(即ARE打断)(不包括消行延迟,默认为打断至无穷大,相当于无此功能)
自定义游戏和自定义房间ui跟进
close #471
2021-11-23 20:26:31 +08:00
MrZ626
95879827c8 调整游戏大logo为正体字 2021-11-23 18:13:45 +08:00
MrZ626
2ade518207 调整tip 2021-11-23 00:48:49 +08:00
MrZ626
36c8449e4d 内存过低的提示每次启动最多出现三次 2021-11-23 00:28:08 +08:00
MrZ626
3c04df69f3 移除手柄时自动松开所有按下了的键,整理代码 2021-11-23 00:27:57 +08:00
MrZ626
1224ee9a67 词典的新人引导条目链接向user670的翻译版本 close #482 2021-11-22 23:45:54 +08:00
MrZ626
fdd1d4463a 版本推进 2021-11-22 21:55:58 +08:00
MrZ626
940ac3736c 整理框架代码
整理手柄的摇杆/扳机支持代码
2021-11-22 15:59:57 +08:00
user670
d38897b54d (Experimental) Support controller axises, closes #466 (#477)
* (Experimental) Support controller axises

* Remove redundant variable; use more readable key event names

* Remove redundant comment; fix typo
2021-11-22 15:52:51 +08:00
MrZ626
90848c6654 全局默认使用5帧窒息延迟 2021-11-22 12:48:02 +08:00
NOT_A_ROBOT
0220d5aefc Make Strategy Ultimate have rhombus outline (#481) 2021-11-22 11:08:13 +08:00
MrZ626
f42032df07 更新赞助名单 2021-11-22 11:04:32 +08:00
MrZ626
05d7eb60bc 修正一处拼写问题导致报错消息识别错误 2021-11-21 21:45:37 +08:00
MrZ626
942416317c 小程序arm添加计时器和重置按钮,删除测试用的跳过按钮 2021-11-21 20:18:42 +08:00
MrZ626
576de945fb 添加一打tip 2021-11-21 05:25:55 +08:00
MrZ626
8b02084428 修复bgm模块清缓存导致报错 2021-11-21 05:11:01 +08:00
MrZ626
9f666d69db 调整大爆炸模式模板 2021-11-21 03:52:13 +08:00
MrZ626
a4c52d9162 修正玩家创建任务第一次初始化运行的时候报错没有任何提示 2021-11-21 03:08:34 +08:00
MrZ626
592b11366e table扩展模块新增两个去重方法和反转方法 2021-11-21 03:06:00 +08:00
MrZ626
07f50b9243 调整一些文本文件 2021-11-20 03:39:05 +08:00
MrZ626
ec74d55686 整理代码 2021-11-20 03:28:58 +08:00
MrZ626
4518513e87 应用1的语音偏移半径 2021-11-20 03:28:19 +08:00
MrZ626
7df4e2144f 语音模块支持设置轻微随机音调偏移半径(默认关闭) 2021-11-20 03:27:53 +08:00
MrZ626
7f9c9248ce 版本推进 2021-11-19 17:36:12 +08:00
MrZ626
9c1db48804 整理代码 2021-11-19 17:35:53 +08:00
C₂₉H₂₅N₃O₅
0628830f0c 继续调词典(嗯) 2021-11-19 01:21:48 -06:00
C₂₉H₂₅N₃O₅
9436f2f5fb 微调词典 大改legals (#472) 2021-11-19 01:17:12 -06:00
MrZ626
c5e1b5617f 再调整词典两个词条 2021-11-19 14:21:42 +08:00
MrZ626
298c417aa3 更新部分词条(英文待翻译) 2021-11-19 02:40:46 +08:00
MrZ626
fc74831700 添加lockout判负规则(默认关闭) 2021-11-19 02:33:21 +08:00
MrZ626
d9db55de44 整理代码,修正一处多余代码忘了删 2021-11-19 02:16:34 +08:00
MrZ626
3fd205e8c2 bgm模块添加可调节的最大加载数限制,更不容易达到引擎加载音频数上限 close #447 2021-11-19 01:47:14 +08:00
MrZ626
5cb828fb92 修改策略堆叠模式的解锁路径 2021-11-19 00:59:16 +08:00
MrZ626
5f7a3fd53f 版本推进 2021-11-18 19:54:31 +08:00
MrZ626
8e3e598753 词典添加cambridge词条(翻译自tetris wiki) 2021-11-18 19:52:42 +08:00
MrZ626
2a0a0f60f8 策略堆叠的das和arr参数移到规则包 2021-11-18 19:43:18 +08:00
MrZ626
6b7d1fdf9f 策略堆叠模式添加到地图 2021-11-18 19:41:27 +08:00
MrZ626
65199a40f7 修复40行效率左侧信息颜色问题 2021-11-18 19:27:27 +08:00
MrZ626
f9082a8800 整理代码 2021-11-18 19:16:06 +08:00
NOT_A_ROBOT
1670c6e7d6 Add strategy modes (#468)
* Add strategy mode
2021-11-18 19:08:46 +08:00
NOT_A_ROBOT
ff2073ed4d fix numpadenter on console (#469)
made numpadenter do the same thing as enter on console
2021-11-18 19:08:46 +08:00
MrZ626
f14aaac635 微调staff页面 close #470 2021-11-18 19:08:46 +08:00
MrZ626
c709fa622f 修正hold模式没有英文文本 2021-11-18 19:08:45 +08:00
MrZ626
c752556bf3 微调pc联系模式左侧信息位置
继续推进大爆炸模式框架
2021-11-18 03:54:42 +08:00
MrZ626
e7d9703fcc 修复向玩家场地里塞入垃圾行时如果不存在当前方块会报错 2021-11-18 03:54:42 +08:00
C29H25N3O5
1ed52a84b0 增加半隐和全隐的英文词条 2021-11-17 11:50:04 -06:00
C29H25N3O5
4fdb278751 微调dmg背景图片 2021-11-17 11:29:41 -06:00
MrZ626
8318803923 修改一首bgm名称和一个赞助id 2021-11-18 01:07:27 +08:00
MrZ626
42de7e3676 纠正一个帮助开发的网友id 2021-11-17 22:14:40 +08:00
MrZ626
3efa646ee3 再增加堆积模式的窒息延迟 2021-11-17 22:11:50 +08:00
MrZ626
b414c2ab42 版本推进 2021-11-17 22:08:00 +08:00
MrZ626
205dea3db7 TRS的S/Z添加四个踢墙防止在一些地方卡死 2021-11-17 21:49:37 +08:00
MrZ626
6cac688555 完善提前移动词条 2021-11-17 20:48:40 +08:00
MrZ626
09b1b08c1e 堆积模式添加8f窒息延迟 2021-11-17 20:29:42 +08:00
MrZ626
b61a1270e9 生成位置预览开启后hold的生成位置也可见 2021-11-17 16:47:25 +08:00
MrZ626
b85cee7e1f 修复机翻语言超级消除没有行数显示 close #462 2021-11-17 16:30:00 +08:00
MrZ626
8e674e3e29 版本推进 2021-11-17 16:25:38 +08:00
MrZ626
aa2812c874 大爆炸模式框架完成,等待具体关卡生成算法 2021-11-17 16:24:18 +08:00
MrZ626
6f282431c4 pc训练的序列模式和旋转系统参数放入规则包 2021-11-17 16:01:09 +08:00
MrZ626
470e54cdd0 两个pc练习模式添加胜利条件,不再无尽
略微降低pc练习-普通的X评级标准
2021-11-17 16:01:08 +08:00
MrZ626
da3ef1c2a6 pc训练代码整理,开局就能看到关卡并且没有提前硬降不会死的bug了 2021-11-17 16:01:08 +08:00
MrZ626
9efe0e62d5 词典添加半隐和全隐词条(英文待翻译) 2021-11-17 16:01:08 +08:00
MrZ626
7038f81b46 调整一些tip
整理代码
2021-11-17 10:59:38 +08:00
MrZ626
de972a60df blackhole背景改名blockhole 2021-11-17 10:59:34 +08:00
MrZ626
6a87787d6f 微调github issue模板 2021-11-17 10:59:30 +08:00
MrZ626
6dc9a4b507 安全,安全!(嗯嗯嗯 2021-11-17 10:59:27 +08:00
MrZ626
5b7c888d57 修正经典模式显示的速度等级 2021-11-17 10:59:01 +08:00
MrZ626
a1f761b83e 修正一处拼写错误 2021-11-17 10:58:51 +08:00
C₂₉H₂₅N₃O₅
c40a6bfaa0 换行 (#463) 2021-11-16 14:28:30 -06:00
MrZ626
441c6f7667 再次修复安全漏洞(嗯 2021-11-17 01:15:03 +08:00
MrZ626
a07d57cf71 版本推进 2021-11-16 20:39:29 +08:00
MrZ626
a467f972f9 调整死亡延迟的称呼 2021-11-16 20:39:19 +08:00
MrZ626
3f455ee360 整理代码 2021-11-16 20:29:55 +08:00
MrZ626
7a0b913768 修复安全漏洞(确信 2021-11-16 14:47:42 +08:00
MrZ626
a7b240ade8 微调符号语言 2021-11-16 14:00:09 +08:00
C₂₉H₂₅N₃O₅
bb64404821 完善字体和符号文本 (#460) 2021-11-15 22:27:40 -06:00
MrZ626
caf92eb3c8 修正几处全半角括号 2021-11-16 11:25:16 +08:00
MrZ626
6a117a0fab 词典添加死亡延迟词条 2021-11-16 11:18:33 +08:00
MrZ626
26682509f7 添加防止死亡延时 close #459 2021-11-16 11:18:32 +08:00
C₂₉H₂₅N₃O₅
d85d92fb43 添加几种语言的赞助说明 (#458) 2021-11-15 17:06:49 -06:00
MrZ626
c412003cb3 调整关于页面信息
词典添加patreon词条
2021-11-16 03:55:57 +08:00
MrZ626
e39b5dbd51 修改中文词典的官网词条 2021-11-16 03:27:46 +08:00
MrZ626
db162ea66f 微调about信息 2021-11-16 03:27:46 +08:00
Not-A-Normal-Robot
f9f9fde368 修改 legals.md 一处拼写错误 (#457) 2021-11-15 10:57:16 -06:00
MrZ626
4b221c2eb5 版本推进 2021-11-15 15:52:16 +08:00
MrZ626
ed45bebfa0 添加转盘模块和实验性每日转盘小程序 2021-11-15 15:47:05 +08:00
MrZ626
fa0bc3805f 整理代码,Zframework添加数学扩展模块 2021-11-15 15:46:57 +08:00
MrZ626
7710f0b70f 修正词典 2021-11-15 02:13:56 +08:00
C₂₉H₂₅N₃O₅
0277ddadb5 微调词典 (#456) 2021-11-14 12:05:00 -06:00
MrZ626
88e23e32f5 piano小程序支持shift/ctrl升降半音,左右alt变调,补充更多键位 2021-11-15 02:00:04 +08:00
MrZ626
8ab5b4a17a SFX模块新增音高获取音名的方法
整理代码
2021-11-15 02:00:04 +08:00
MrZ626
503dfd69ef 再调整SFX.playSample方法,支持用数字代表绝对音高,但是移除最后的音量参数 2021-11-15 01:40:53 +08:00
ParticleG
ae61ec26c0 - Remove upload to server 2021-11-15 01:39:37 +08:00
MrZ626
00bc24bd50 新增piano小程序(目前只支持键盘操作) 2021-11-14 22:19:45 +08:00
MrZ626
abd15d6307 table扩展模块新增一个函数 2021-11-14 22:09:44 +08:00
MrZ626
c01ac546d1 再修正播放采样的超音域问题 2021-11-14 21:48:02 +08:00
MrZ626
af77221ba2 修复换准备音效播放方式后ultra模式倒计时没声 2021-11-14 17:34:41 +08:00
MrZ626
204f0938d3 播放准备音效的函数可调音量 2021-11-14 17:32:10 +08:00
MrZ626
ad39d1408c 音乐室输入首字母自动跳转 2021-11-14 17:31:49 +08:00
MrZ626
ed011173f6 版本推进 2021-11-14 16:53:43 +08:00
MrZ626
491fcb5860 添加缓冲区和消失区两个词条
Co-authored-by: C₂₉H₂₅N₃O₅ <cgu52@wisc.edu>
2021-11-14 16:45:53 +08:00
MrZ626
c2d5537d8d 经典模式添加干旱计数器 close #452 2021-11-14 16:45:50 +08:00
MrZ626
7d5037ae87 竞速-效率显示剩余行数 2021-11-14 12:37:39 +08:00
MrZ626
07d7714317 修正无尽模式标题首字母大小写错误 close #454 2021-11-14 12:19:26 +08:00
MrZ626
2cab97f37d 修复0arr时自动移动时声音特别响 2021-11-14 11:49:41 +08:00
MrZ626
d184778c9a 修正string扩展模块时间转换函数可能出现1分60(截断小数点后两位防止被向上取整) 2021-11-14 11:24:11 +08:00
MrZ626
9fd3b3008d 新增物品数据,每日登录新增加一个zTicket 2021-11-13 22:33:25 +08:00
MrZ626
71aa35b214 修正统计里的日期每次启动都被刷新了导致单日统计时间不对 2021-11-13 17:32:54 +08:00
MrZ626
4443dc9d3e table扩展模块添加一个方法(未来会整理类似数据表更新函数) 2021-11-13 17:29:17 +08:00
MrZ626
839e357301 修改更新历史 2021-11-13 16:31:46 +08:00
MrZ626
ac56c5a415 修改竞速-效率左侧信息栏 2021-11-13 16:23:27 +08:00
MrZ626
36e3343341 TRS的J5和L5新增一个180度踢墙 2021-11-13 16:14:36 +08:00
MrZ626
510f7d7513 版本推进 2021-11-13 05:42:36 +08:00
MrZ626
3128eb38c0 再调整一些模式的bgm 2021-11-13 05:41:27 +08:00
MrZ626
14ef654612 混战模式信息绘制从玩家类移到规则包 2021-11-13 05:21:59 +08:00
MrZ626
bc5193f95e 落块事件改名落块钩子
添加死亡钩子(仅在窒息和超高触发)
堆积模式消行动作挂到死亡钩子上
2021-11-13 05:20:32 +08:00
MrZ626
8cbb4a38bc dropPiece事件改名hook_drop 2021-11-12 23:20:29 +08:00
MrZ626
fce08c83ef 堆积模式移出地图,删除h难度 2021-11-12 21:17:30 +08:00
MrZ626
018e99f9e6 修正改评级文本后tip没改 2021-11-12 16:39:30 +08:00
MrZ626
7fe390b34b 赞助名单添加三位 2021-11-12 16:28:37 +08:00
MrZ626
8c7202c569 版本推进 2021-11-12 03:35:54 +08:00
MrZ626
ab386bb53c 整理代码 2021-11-12 03:30:52 +08:00
MrZ626
87c791b8c7 tips新增几个好玩的游戏 2021-11-12 02:58:17 +08:00
MrZ626
00e3e2d19d 取消准备按钮不再只显示取消两个字 2021-11-12 02:54:14 +08:00
MrZ626
8d7d5c7b04 新BGM:peak(暂未使用) 2021-11-11 19:22:45 +08:00
MrZ626
849a18e159 移除模式的颜色 2021-11-11 19:14:37 +08:00
MrZ626
a4357d0843 移除节奏模式,准备之后添加音游模式 2021-11-11 18:59:04 +08:00
MrZ626
e2b4a78b59 修正超音源音域音符处理方法 2021-11-10 21:15:50 +08:00
MrZ626
01387b5488 版本推进(修改更新历史和build号) 2021-11-10 18:30:34 +08:00
MrZ626
168e2f80b8 SFX.play新增pitch参数,playSample方法允许超过音源范围(差太多了效果不好) 2021-11-10 17:52:48 +08:00
MrZ626
4f79ef8708 改进一处材质缺失后的报错 2021-11-10 16:40:00 +08:00
MrZ626
16497833df 修正COLOR.hsv函数s小于0时漏返回透明度 close #445 2021-11-10 14:35:22 +08:00
MrZ626
cd6a50d5a0 修复词典导出词条保留了替换敏感词的特殊字符 2021-11-10 14:35:22 +08:00
C₂₉H₂₅N₃O₅
4c5a61f2d8 修改License相关内容 (#444) 2021-11-09 21:38:45 -06:00
C29H25N3O5
1fd8d39970 更换中文字形 2021-11-09 18:57:35 -06:00
MrZ626
d133d64890 目标分数显示器分割线长度微调 2021-11-09 23:16:33 +08:00
MrZ626
b27aa8b60d freeRow模块改名line模块并暂时在“行”的管理上不再那么节约地使用内存 2021-11-09 20:14:08 +08:00
297 changed files with 5129 additions and 3943 deletions

View File

@@ -2,8 +2,7 @@
name: Bug report (bluescreen crash) Bug报告 (蓝屏报错)
about: Create a report of problems which made the crash with a bluescreen
---
Screenshot with crash information: (delete this line before submitting)
*Image Here*
Screenshot with crash information (*Image(s) Here*):
If you can reproduce it, write the steps here. If you can't, try to describe the exactly time the game crash, like pressing which key or which button: (delete this line before submitting)
*Details Here*
If you can reproduce it, write the steps here. If you can't, try to describe the exactly time the game crash, like pressing which key or which button (*Details Here*)

View File

@@ -2,8 +2,7 @@
name: Bug report (unintended behaviors) Bug报告 (奇怪的现象)
about: Create a report of unintended behaviors
---
Screenshot with unintended behaviors: (delete this line before submitting)
*Image(s) Here*
Screenshot with unintended behaviors (*Image(s) Here*):
If you can reproduce it, write the steps here. If you can't, try to describe the exactly time the game crash, like pressing which key or which button: (delete this line before submitting)
*Details Here*
If you can reproduce it, write the steps here. If you can't, try to describe the exactly time the game crash, like pressing which key or which button (*Details Here*):

View File

@@ -1,54 +0,0 @@
name: "upload artifact"
description: "upload file with webdav"
inputs:
WEBDAV_USERNAME:
required: true
description: "webdav username"
WEBDAV_PASSWORD:
required: true
description: "webdav password"
ARTIFACT_TYPE:
required: true
description: "file build type"
ARTIFACT_PLATFORM:
required: true
description: "file platform"
ARTIFACT_NAME:
required: true
description: "file name"
runs:
using: "composite"
steps:
- uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install Webdav 4
shell: bash
run: |
pip install webdav4
- name: Update release
shell: python
run: |
import re
from webdav4.client import Client
client = Client(
"http://mc.yuhao7370.top:5212/dav",
auth=("${{ inputs.WEBDAV_USERNAME }}", "${{ inputs.WEBDAV_PASSWORD }}"),
timeout=None,
)
if '${{ inputs.ARTIFACT_TYPE }}' == 'release':
print('Removing previous ${{ inputs.ARTIFACT_PLATFORM }} release file...')
for file in client.ls('Techmino distribution'):
if re.search(r'(Techmino_a[0-9]+\.[0-9]+\.[0-9]_${{ inputs.ARTIFACT_PLATFORM }}.*)', file['name']):
client.remove(file['name'])
print('Uploading new ${{ inputs.ARTIFACT_PLATFORM }} release file...')
client.upload_file("${{ inputs.ARTIFACT_NAME }}", 'Techmino distribution/${{ inputs.ARTIFACT_NAME }}')
if '${{ inputs.ARTIFACT_TYPE }}' == 'test':
print('Removing previous ${{ inputs.ARTIFACT_PLATFORM }} test file...')
for file in client.ls('Techmino Snapshot'):
if re.search(r'(Techmino_pre[0-9]+\.[0-9]+\.[0-9]_[0-9a-z]{7}_${{ inputs.ARTIFACT_PLATFORM }}.*)', file['name']):
client.remove(file['name'])
print('Uploading new ${{ inputs.ARTIFACT_PLATFORM }} test file...')
client.upload_file("${{ inputs.ARTIFACT_NAME }}", 'Techmino Snapshot/${{ inputs.ARTIFACT_NAME }}')

Binary file not shown.

View File

@@ -56,14 +56,6 @@ jobs:
with:
name: ${{ needs.get-info.outputs.updateTitle }}
files: Techmino_a${{ needs.get-info.outputs.release }}_Win64.zip
- name: Upload artifact to server
uses: ./.github/actions/upload-artifact
with:
WEBDAV_USERNAME: ${{ secrets.WEBDAV_USERNAME }}
WEBDAV_PASSWORD: ${{ secrets.WEBDAV_PASSWORD }}
ARTIFACT_TYPE: release
ARTIFACT_PLATFORM: Win64
ARTIFACT_NAME: Techmino_a${{ needs.get-info.outputs.release }}_Win64.zip
build-windows-x86:
runs-on: windows-latest
@@ -85,14 +77,6 @@ jobs:
with:
name: ${{ needs.get-info.outputs.updateTitle }}
files: Techmino_a${{ needs.get-info.outputs.release }}_Win32.zip
- name: Upload artifact to server
uses: ./.github/actions/upload-artifact
with:
WEBDAV_USERNAME: ${{ secrets.WEBDAV_USERNAME }}
WEBDAV_PASSWORD: ${{ secrets.WEBDAV_PASSWORD }}
ARTIFACT_TYPE: release
ARTIFACT_PLATFORM: Win32
ARTIFACT_NAME: Techmino_a${{ needs.get-info.outputs.release }}_Win32.zip
build-linux:
runs-on: ubuntu-20.04
@@ -109,14 +93,6 @@ jobs:
with:
name: ${{ needs.get-info.outputs.updateTitle }}
files: Techmino_a${{ needs.get-info.outputs.release }}_Linux.AppImage
- name: Upload artifact to server
uses: ./.github/actions/upload-artifact
with:
WEBDAV_USERNAME: ${{ secrets.WEBDAV_USERNAME }}
WEBDAV_PASSWORD: ${{ secrets.WEBDAV_PASSWORD }}
ARTIFACT_TYPE: release
ARTIFACT_PLATFORM: Linux
ARTIFACT_NAME: Techmino_a${{ needs.get-info.outputs.release }}_Linux.AppImage
build-android:
runs-on: ubuntu-20.04
@@ -139,14 +115,6 @@ jobs:
with:
name: ${{ needs.get-info.outputs.updateTitle }}
files: Techmino_a${{ needs.get-info.outputs.release }}_Android.apk
- name: Upload artifact to server
uses: ./.github/actions/upload-artifact
with:
WEBDAV_USERNAME: ${{ secrets.WEBDAV_USERNAME }}
WEBDAV_PASSWORD: ${{ secrets.WEBDAV_PASSWORD }}
ARTIFACT_TYPE: release
ARTIFACT_PLATFORM: Android
ARTIFACT_NAME: Techmino_a${{ needs.get-info.outputs.release }}_Android.apk
build-macOS:
runs-on: macos-10.15
@@ -174,14 +142,6 @@ jobs:
with:
name: ${{ needs.get-info.outputs.updateTitle }}
files: Techmino_a${{ needs.get-info.outputs.release }}_MacOS.dmg
- name: Upload artifact to server
uses: ./.github/actions/upload-artifact
with:
WEBDAV_USERNAME: ${{ secrets.WEBDAV_USERNAME }}
WEBDAV_PASSWORD: ${{ secrets.WEBDAV_PASSWORD }}
ARTIFACT_TYPE: release
ARTIFACT_PLATFORM: MacOS
ARTIFACT_NAME: Techmino_a${{ needs.get-info.outputs.release }}_MacOS.dmg
build-iOS:
runs-on: macos-latest
@@ -216,14 +176,6 @@ jobs:
with:
name: ${{ needs.get-info.outputs.updateTitle }}
files: Techmino_a${{ needs.get-info.outputs.release }}_iOS.ipa
- name: Upload artifact to server
uses: ./.github/actions/upload-artifact
with:
WEBDAV_USERNAME: ${{ secrets.WEBDAV_USERNAME }}
WEBDAV_PASSWORD: ${{ secrets.WEBDAV_PASSWORD }}
ARTIFACT_TYPE: release
ARTIFACT_PLATFORM: iOS
ARTIFACT_NAME: Techmino_a${{ needs.get-info.outputs.release }}_iOS.ipa
Add-Release-note:
runs-on: ubuntu-20.04

View File

@@ -49,20 +49,7 @@ jobs:
with:
name: Techmino_pre${{ needs.get-info.outputs.release }}_${{ needs.get-info.outputs.commit }}_Windows
path: love
- name: Pack Techmino
run: 7z a -tzip .\Techmino_pre${{ needs.get-info.outputs.release }}_${{ needs.get-info.outputs.commit }}_Windows.zip .\love
- name: Upload artifact to server
uses: ./.github/actions/upload-artifact
with:
WEBDAV_USERNAME: ${{ secrets.WEBDAV_USERNAME }}
WEBDAV_PASSWORD: ${{ secrets.WEBDAV_PASSWORD }}
ARTIFACT_TYPE: test
ARTIFACT_PLATFORM: Windows
ARTIFACT_NAME: Techmino_pre${{ needs.get-info.outputs.release }}_${{ needs.get-info.outputs.commit }}_Windows.zip
# - name: Upload artifact to server
# run: |
# curl --user "${{ secrets.WEBDAV_USERNAME }}:${{ secrets.WEBDAV_PASSWORD }}" -T Techmino_pre${{ needs.get-info.outputs.release }}_${{ needs.get-info.outputs.commit }}_Windows.zip http://mc.yuhao7370.top:5212/dav/Techmino%20Snapshots/ -v
build-linux:
runs-on: ubuntu-20.04
needs: get-info
@@ -80,16 +67,6 @@ jobs:
with:
name: Techmino_pre${{ needs.get-info.outputs.release }}_${{ needs.get-info.outputs.commit }}_Linux
path: Techmino.AppImage
- name: Pack Techmino
run: mv Techmino.AppImage Techmino_pre${{ needs.get-info.outputs.release }}_${{ needs.get-info.outputs.commit }}_Linux.AppImage
- name: Upload artifact to server
uses: ./.github/actions/upload-artifact
with:
WEBDAV_USERNAME: ${{ secrets.WEBDAV_USERNAME }}
WEBDAV_PASSWORD: ${{ secrets.WEBDAV_PASSWORD }}
ARTIFACT_TYPE: test
ARTIFACT_PLATFORM: Linux
ARTIFACT_NAME: Techmino_pre${{ needs.get-info.outputs.release }}_${{ needs.get-info.outputs.commit }}_Linux.AppImage
build-android:
runs-on: ubuntu-20.04
@@ -115,16 +92,6 @@ jobs:
with:
name: Techmino_pre${{ needs.get-info.outputs.release }}_${{ needs.get-info.outputs.commit }}_Android
path: Techmino_Snapshot.apk
- name: Pack Techmino
run: mv Techmino_Snapshot.apk Techmino_pre${{ needs.get-info.outputs.release }}_${{ needs.get-info.outputs.commit }}_Android.apk
- name: Upload artifact to server
uses: ./.github/actions/upload-artifact
with:
WEBDAV_USERNAME: ${{ secrets.WEBDAV_USERNAME }}
WEBDAV_PASSWORD: ${{ secrets.WEBDAV_PASSWORD }}
ARTIFACT_TYPE: test
ARTIFACT_PLATFORM: Android
ARTIFACT_NAME: Techmino_pre${{ needs.get-info.outputs.release }}_${{ needs.get-info.outputs.commit }}_Android.apk
build-macOS:
runs-on: macos-10.15
@@ -152,16 +119,6 @@ jobs:
with:
name: Techmino_pre${{ needs.get-info.outputs.release }}_${{ needs.get-info.outputs.commit }}_MacOS
path: Techmino.dmg
- name: Pack Techmino
run: mv Techmino.dmg Techmino_pre${{ needs.get-info.outputs.release }}_${{ needs.get-info.outputs.commit }}_MacOS.dmg
- name: Upload artifact to server
uses: ./.github/actions/upload-artifact
with:
WEBDAV_USERNAME: ${{ secrets.WEBDAV_USERNAME }}
WEBDAV_PASSWORD: ${{ secrets.WEBDAV_PASSWORD }}
ARTIFACT_TYPE: test
ARTIFACT_PLATFORM: MacOS
ARTIFACT_NAME: Techmino_pre${{ needs.get-info.outputs.release }}_${{ needs.get-info.outputs.commit }}_MacOS.dmg
build-iOS:
runs-on: macos-latest
@@ -195,13 +152,3 @@ jobs:
with:
name: Techmino_pre${{ needs.get-info.outputs.release }}_${{ needs.get-info.outputs.commit }}_iOS
path: Techmino.ipa
- name: Pack Techmino
run: mv Techmino.ipa Techmino_pre${{ needs.get-info.outputs.release }}_${{ needs.get-info.outputs.commit }}_iOS.ipa
- name: Upload artifact to server
uses: ./.github/actions/upload-artifact
with:
WEBDAV_USERNAME: ${{ secrets.WEBDAV_USERNAME }}
WEBDAV_PASSWORD: ${{ secrets.WEBDAV_PASSWORD }}
ARTIFACT_TYPE: test
ARTIFACT_PLATFORM: iOS
ARTIFACT_NAME: Techmino_pre${{ needs.get-info.outputs.release }}_${{ needs.get-info.outputs.commit }}_iOS.ipa

View File

@@ -4,8 +4,9 @@ local BGs={
}
local BGlist={'none'}
local BG={
cur='none',
default='none',
locked=false,
cur='none',
init=false,
resize=false,
update=NULL,
@@ -14,6 +15,8 @@ local BG={
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
@@ -21,6 +24,9 @@ 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(...)
@@ -29,20 +35,20 @@ end
function BG.setDefault(bg)
BG.default=bg
end
function BG.set(background)
background=background or BG.default
if not BGs[background]or not SETTING.bg then return end
if background~=BG.cur then
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=background
background=BGs[background]
BG.cur=name
local bg=BGs[name]
BG.init= background.init or NULL
BG.resize= background.resize or NULL
BG.update= background.update or NULL
BG.draw= background.draw or NULL
BG.event= background.event or NULL
BG.discard=background.discard or NULL
BG.init= bg.init or NULL
BG.resize= bg.resize or NULL
BG.update= bg.update or NULL
BG.draw= bg.draw or NULL
BG.event= bg.event or NULL
BG.discard=bg.discard or NULL
BG.init()
end
return true

View File

@@ -1,4 +1,6 @@
local Sources={}
local lastLoaded={}
local maxLoadedCount=3
local SourceObjList={}
local volume=1
local BGM={
@@ -37,15 +39,41 @@ end
local function check_curFadeOut(task,code,src)
return task.code==code and task.args[1]==src
end
local function _tryReleaseSources()
local n=#lastLoaded
while #lastLoaded>maxLoadedCount do
local name=lastLoaded[n]
if SourceObjList[name].source:isPlaying()then
n=n-1
if n<=0 then return end
else
SourceObjList[name].source=SourceObjList[name].source:release()and nil
table.remove(lastLoaded,n)
return
end
end
end
function BGM.setDefault(bgm)
BGM.default=bgm
end
function BGM.setMaxSources(count)
maxLoadedCount=count
_tryReleaseSources()
end
function BGM.setChange(func)
BGM.onChange=func
end
function BGM.setVol(v)
assert(type(v)=='number'and v>=0 and v<=1)
assert(type(v)=='number'and v>=0 and v<=1,'Wrong volume')
volume=v
if BGM.playing then
if volume>0 then
BGM.playing:setVolume(volume)
BGM.playing:play()
elseif BGM.nowPlay then
BGM.playing:pause()
end
end
end
function BGM.init(list)
BGM.init=nil
@@ -53,7 +81,7 @@ function BGM.init(list)
local simpList={}
for _,v in next,list do
table.insert(simpList,v.name)
Sources[v.name]=v.path
SourceObjList[v.name]={path=v.path,source=false}
end
table.sort(simpList)
function BGM.getList()return simpList end
@@ -61,58 +89,43 @@ function BGM.init(list)
LOG(count.." BGM files added")
function BGM.getCount()return count end
local function _load(name)
if type(Sources[name])=='string'then
if love.filesystem.getInfo(Sources[name])then
Sources[name]=love.audio.newSource(Sources[name],'stream')
Sources[name]:setLooping(true)
Sources[name]:setVolume(0)
local function _tryLoad(name)
if SourceObjList[name]then
if SourceObjList[name].source then
return true
elseif love.filesystem.getInfo(SourceObjList[name].path)then
SourceObjList[name].source=love.audio.newSource(SourceObjList[name].path,'stream')
SourceObjList[name].source:setLooping(true)
SourceObjList[name].source:setVolume(0)
table.insert(lastLoaded,1,name)
_tryReleaseSources()
return true
else
LOG("No BGM: "..Sources[name],5)
LOG("No BGM: "..SourceObjList[name],5)
end
elseif Sources[name]then
return true
elseif name then
LOG("No BGM: "..name,5)
end
end
function BGM.setVol(v)
assert(type(v)=='number'and v>=0 and v<=1)
volume=v
if BGM.playing then
if volume>0 then
BGM.playing:setVolume(volume)
BGM.playing:play()
elseif BGM.nowPlay then
BGM.playing:pause()
end
end
end
function BGM.loadAll()--Not neccessary, unless you want avoid the lag when playing something for the first time
for name in next,Sources do
_load(name)
end
end
function BGM.play(name)
name=name or BGM.default
if not _load(name)then return end
if not _tryLoad(name)then return end
if volume==0 then
BGM.nowPlay=name
BGM.playing=Sources[name]
BGM.playing=SourceObjList[name].source
return true
end
if name and Sources[name]then
if name and SourceObjList[name].source then
if BGM.nowPlay~=name then
if BGM.nowPlay then
TASK.new(task_fadeOut,BGM.playing)
end
TASK.removeTask_iterate(check_curFadeOut,task_fadeOut,Sources[name])
TASK.removeTask_iterate(check_curFadeOut,task_fadeOut,SourceObjList[name].source)
TASK.removeTask_code(task_fadeIn)
TASK.new(task_fadeIn,Sources[name])
TASK.new(task_fadeIn,SourceObjList[name].source)
BGM.nowPlay=name
BGM.playing=Sources[name]
BGM.playing=SourceObjList[name].source
BGM.lastPlayed=BGM.nowPlay
BGM.playing:seek(0)
BGM.playing:play()
@@ -128,8 +141,8 @@ function BGM.init(list)
end
function BGM.continue()
if BGM.lastPlayed then
BGM.nowPlay,BGM.playing=BGM.lastPlayed,Sources[BGM.lastPlayed]
TASK.removeTask_iterate(check_curFadeOut,task_fadeOut,Sources[BGM.nowPlay])
BGM.nowPlay,BGM.playing=BGM.lastPlayed,SourceObjList[BGM.lastPlayed].source
TASK.removeTask_iterate(check_curFadeOut,task_fadeOut,SourceObjList[BGM.nowPlay].source)
TASK.removeTask_code(task_fadeIn)
TASK.new(task_fadeIn,BGM.playing)
BGM.playing:play()

View File

@@ -1,6 +1,6 @@
local abs=math.abs
local function hsv(h,s,v,a)
if s<=0 then return v,v,v end
if s<=0 then return v,v,v,a end
h=h*6
local c=v*s
local x=abs((h-1)%2-1)*c
@@ -31,7 +31,7 @@ local COLOR={
violet= {hsv(0.73, 1.00, 0.91)},
purple= {hsv(0.80, 1.00, 0.81)},
magenta= {hsv(0.86, 1.00, 0.78)},
wine= {hsv(0.94, 0.96, 0.91)},
wine= {hsv(0.92, 0.98, 0.91)},
lRed= {hsv(0.00, 0.38, 0.93)},
lFire= {hsv(0.04, 0.45, 0.91)},

View File

@@ -1,66 +1,60 @@
local fs=love.filesystem
local FILE={}
function FILE.load(name,mode)
function FILE.load(name,args)
if not args then args=''end
if fs.getInfo(name)then
local F=fs.newFile(name)
if F:open'r'then
local s=F:read()
F:close()
if mode=='luaon'or not mode and s:sub(1,6)=="return{"then
s=loadstring(s)
if s then
setfenv(s,{})
return s()
end
elseif mode=='json'or not mode and s:sub(1,1)=="["and s:sub(-1)=="]"or s:sub(1,1)=="{"and s:sub(-1)=="}"then
local res=JSON.decode(s)
if res then
return res
end
elseif mode=='string'or not mode then
return s
assert(F:open'r','open error')
local s=F:read()F:close()
if args:sArg'-luaon'or args==''and s:sub(1,6)=='return{'then
local func=loadstring(s)
if func then
setfenv(func,{})
local res=func()
return assert(res,'decode error')
else
MES.new("No file loading mode called "..tostring(mode))
error('decode error')
end
elseif args:sArg'-json'or args==''and s:sub(1,1)=='['and s:sub(-1)==']'or s:sub(1,1)=='{'and s:sub(-1)=='}'then
local res=JSON.decode(s)
if res then
return res
end
error('decode error')
elseif args:sArg'-string'or args==''then
return s
else
MES.new('error',name.." "..text.loadError)
error('unknown mode')
end
else
error('no file')
end
end
function FILE.save(data,name,mode)
if not mode then mode=""end
function FILE.save(data,name,args)
if not args then args=''end
if args:sArg'-d'and fs.getInfo(name)then
error('duplicate')
end
if type(data)=='table'then
if mode:find'l'then
if args:sArg'-luaon'then
data=TABLE.dump(data)
if not data then
MES.new('error',name.." "..text.saveError.."dump error")
return
error('encode error')
end
else
data=JSON.encode(data)
if not data then
MES.new('error',name.." "..text.saveError.."json error")
return
error('encode error')
end
end
else
data=tostring(data)
end
if mode:find'd'and fs.getInfo(name)then
MES.new('error',text.saveError_duplicate)
return
end
local F=fs.newFile(name)
F:open'w'
local success,mes=F:write(data)
F:flush()F:close()
if success then
return true
else
MES.new('error',text.saveError..(mes or"unknown error"))
MES.traceback()
end
assert(F:open('w'),'open error')
F:write(data)F:flush()F:close()
end
function FILE.clear(path)
if fs.getRealDirectory(path)==SAVEDIR and fs.getInfo(path).type=='directory'then

View File

@@ -1,67 +1,60 @@
local gc=love.graphics
local set=gc.setFont
local fontCache={}
local currentFontSize
local fontFiles,fontCache={},{}
local defaultFont,defaultFallBack
local curFont=false--Current using font object
local FONT={}
function FONT.set(s)
if s~=currentFontSize then
if not fontCache[s]then
fontCache[s]=gc.setNewFont(s,'light',gc.getDPIScale()*SCR.k*2)
end
set(fontCache[s])
currentFontSize=s
end
end
function FONT.get(s)
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.reset()
for s in next,fontCache do
fontCache[s]=gc.setNewFont(s,'light',gc.getDPIScale()*SCR.k*2)
end
function FONT.rawset(s)
set(fontCache[s]or FONT.rawget(s))
end
function FONT.load(mainFont,secFont)
assert(love.filesystem.getInfo(mainFont),"Font file '"..mainFont.."' not exist!")
mainFont=love.filesystem.newFile(mainFont)
if secFont and love.filesystem.getInfo(secFont)then
secFont=love.filesystem.newFile(secFont)
else
secFont=false
end
function FONT.set(s)
if s~=currentFontSize then
if not fontCache[s]then
fontCache[s]=gc.setNewFont(mainFont,s,'light',gc.getDPIScale()*SCR.k*2)
if secFont then
fontCache[s]:setFallbacks(gc.setNewFont(secFont,s,'light',gc.getDPIScale()*SCR.k*2))
end
end
set(fontCache[s])
currentFontSize=s
end
end
function FONT.get(s)
if not fontCache[s]then
fontCache[s]=gc.setNewFont(mainFont,s,'light',gc.getDPIScale()*SCR.k*2)
if secFont then
fontCache[s]:setFallbacks(gc.setNewFont(secFont,s,'light',gc.getDPIScale()*SCR.k*2))
end
end
return fontCache[s]
end
function FONT.reset()
for s in next,fontCache do
fontCache[s]=gc.setNewFont(mainFont,s,'light',gc.getDPIScale()*SCR.k*2)
if secFont then
fontCache[s]:setFallbacks(gc.setNewFont(secFont,s,'light',gc.getDPIScale()*SCR.k*2))
end
end
function FONT.load(fonts)
for name,path in next,fonts do
assert(love.filesystem.getInfo(path),("Font file $1($2) not exist!"):repD(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

View File

@@ -95,6 +95,7 @@ do--function GC.DO(L)
setLJ="setLineJoin",
print="print",
rawFT=function(...)FONT.rawset(...)end,
setFT=function(...)FONT.set(...)end,
mText=GC.mStr,
mDraw=GC.draw,

View File

@@ -1,9 +1,9 @@
NONE={}function NULL()end
EDITING=""
LOADED=false
ERRDATA={}
--Pure lua modules (basic)
MATH= require'Zframework.mathExtend'
COLOR= require'Zframework.color'
TABLE= require'Zframework.tableExtend'
STRING= require'Zframework.stringExtend'
@@ -37,7 +37,6 @@ REQUIRE= require'Zframework.require'
TASK= require'Zframework.task'
WS= require'Zframework.websocket'
LANG= require'Zframework.languages'
THEME= require'Zframework.theme'
--Love-based modules (basic)
FILE= require'Zframework.file'
@@ -61,6 +60,7 @@ 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
@@ -70,10 +70,13 @@ local gc_draw,gc_line,gc_circle,gc_print=gc.draw,gc.line,gc.circle,gc.print
local WIDGET,SCR,SCN=WIDGET,SCR,SCN
local xOy=SCR.xOy
local ITP=xOy.inverseTransformPoint
local mx,my,mouseShow=-20,-20,false
joysticks={}
local ITP=xOy.inverseTransformPoint
local max,min=math.max,math.min
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 devMode
@@ -126,36 +129,81 @@ local function updatePowerInfo()
end
-------------------------------------------------------------
local lastX,lastY=0,0--Last click pos
local function _updateMousePos(x,y,dx,dy)
if SCN.swapping then return end
dx,dy=dx/SCR.k,dy/SCR.k
if SCN.mouseMove then SCN.mouseMove(x,y,dx,dy)end
if ms.isDown(1)then
WIDGET.drag(x,y,dx,dy)
else
WIDGET.cursorMove(x,y)
end
end
local function _triggerMouseDown(x,y,k)
if devMode==1 then
print(("(%d,%d)<-%d,%d ~~(%d,%d)<-%d,%d"):format(
x,y,
x-lastX,y-lastY,
math.floor(x/10)*10,math.floor(y/10)*10,
math.floor((x-lastX)/10)*10,math.floor((y-lastY)/10)*10
))
end
if SCN.swapping then return end
if SCN.mouseDown then SCN.mouseDown(x,y,k)end
WIDGET.press(x,y,k)
lastX,lastY=x,y
if SETTING.clickFX then SYSFX.newTap(3,x,y)end
end
local function mouse_update(dt)
if not KBisDown('lctrl','rctrl')and KBisDown('up','down','left','right')then
local dx,dy=0,0
if KBisDown('up')then dy=dy-cursorSpd end
if KBisDown('down')then dy=dy+cursorSpd end
if KBisDown('left')then dx=dx-cursorSpd end
if KBisDown('right')then dx=dx+cursorSpd end
mx=max(min(mx+dx,1280),0)
my=max(min(my+dy,720),0)
if my==0 or my==720 then
WIDGET.sel=false
WIDGET.drag(0,0,0,-dy)
end
_updateMousePos(mx,my,dx,dy)
cursorSpd=min(cursorSpd+dt*26,12.6)
else
cursorSpd=6
end
end
local function gp_update(js,dt)
local sx,sy=js._jsObj:getGamepadAxis('leftx'),js._jsObj:getGamepadAxis('lefty')
if math.abs(sx)>.1 or math.abs(sy)>.1 then
local dx,dy=0,0
if sy<-.1 then dy=dy+2*sy*cursorSpd end
if sy>.1 then dy=dy+2*sy*cursorSpd end
if sx<-.1 then dx=dx+2*sx*cursorSpd end
if sx>.1 then dx=dx+2*sx*cursorSpd end
mx=max(min(mx+dx,1280),0)
my=max(min(my+dy,720),0)
if my==0 or my==720 then
WIDGET.sel=false
WIDGET.drag(0,0,0,-dy)
end
_updateMousePos(mx,my,dx,dy)
cursorSpd=min(cursorSpd+dt*26,12.6)
else
cursorSpd=6
end
end
function love.mousepressed(x,y,k,touch)
if touch then return end
mouseShow=true
mx,my=ITP(xOy,x,y)
if devMode==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 SETTING.clickFX then SYSFX.newTap(3,mx,my)end
_triggerMouseDown(mx,my,k)
end
function love.mousemoved(x,y,dx,dy,touch)
if touch then return end
mouseShow=true
mx,my=ITP(xOy,x,y)
if SCN.swapping then return end
dx,dy=dx/SCR.k,dy/SCR.k
if SCN.mouseMove then SCN.mouseMove(mx,my,dx,dy)end
if ms.isDown(1)then
WIDGET.drag(mx,my,dx/SCR.k,dy/SCR.k)
else
WIDGET.cursorMove(mx,my)
end
_updateMousePos(mx,my,dx,dy)
end
function love.mousereleased(x,y,k,touch)
if touch or SCN.swapping then return end
@@ -218,31 +266,31 @@ end
local fnKey={NULL,NULL,NULL,NULL,NULL,NULL,NULL}
local function noDevkeyPressed(key)
if key=="f1"then fnKey[1]()
elseif key=="f2"then fnKey[2]()
elseif key=="f3"then fnKey[3]()
elseif key=="f4"then fnKey[4]()
elseif key=="f5"then fnKey[5]()
elseif key=="f6"then fnKey[6]()
elseif key=="f7"then fnKey[7]()
elseif key=="f8"then devMode=nil MES.new('info',"DEBUG OFF",.2)
elseif key=="f9"then devMode=1 MES.new('info',"DEBUG 1")
elseif key=="f10"then devMode=2 MES.new('info',"DEBUG 2")
elseif key=="f11"then devMode=3 MES.new('info',"DEBUG 3")
elseif key=="f12"then devMode=4 MES.new('info',"DEBUG 4")
if key=='f1'then fnKey[1]()
elseif key=='f2'then fnKey[2]()
elseif key=='f3'then fnKey[3]()
elseif key=='f4'then fnKey[4]()
elseif key=='f5'then fnKey[5]()
elseif key=='f6'then fnKey[6]()
elseif key=='f7'then fnKey[7]()
elseif key=='f8'then devMode=nil MES.new('info',"DEBUG OFF",.2)
elseif key=='f9'then devMode=1 MES.new('info',"DEBUG 1")
elseif key=='f10'then devMode=2 MES.new('info',"DEBUG 2")
elseif key=='f11'then devMode=3 MES.new('info',"DEBUG 3")
elseif key=='f12'then devMode=4 MES.new('info',"DEBUG 4")
elseif devMode==2 then
local W=WIDGET.sel
if W then
if key=="left"then W.x=W.x-10
elseif key=="right"then W.x=W.x+10
elseif key=="up"then W.y=W.y-10
elseif key=="down"then W.y=W.y+10
elseif key==","then W.w=W.w-10
elseif key=="."then W.w=W.w+10
elseif key=="/"then W.h=W.h-10
elseif key=="'"then W.h=W.h+10
elseif key=="["then W.font=W.font-5
elseif key=="]"then W.font=W.font+5
if key=='left'then W.x=W.x-10
elseif key=='right'then W.x=W.x+10
elseif key=='up'then W.y=W.y-10
elseif key=='down'then W.y=W.y+10
elseif key==','then W.w=W.w-10
elseif key=='.'then W.w=W.w+10
elseif key=='/'then W.h=W.h-10
elseif key=='\''then W.h=W.h+10
elseif key=='['then W.font=W.font-5
elseif key==']'then W.font=W.font+5
else return true
end
else
@@ -256,22 +304,34 @@ function love.keypressed(key,_,isRep)
mouseShow=false
if devMode and not noDevkeyPressed(key)then
return
elseif key=="f8"then
elseif key=='f8'then
devMode=1
MES.new('info',"DEBUG ON",.2)
elseif key=="f11"then
elseif key=='f11'then
SETTING.fullscreen=not SETTING.fullscreen
applyFullscreen()
saveSettings()
elseif not SCN.swapping then
if SCN.keyDown then
if EDITING==""then
SCN.keyDown(key,isRep)
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 SETTING.clickFX then SYSFX.newTap(3,mx,my)end
_triggerMouseDown(mx,my,1)
end
else
if W and W.keypress then
W:keypress(key)
end
end
elseif key=="escape"and not isRep then
SCN.back()
else
WIDGET.keyPressed(key,isRep)
end
end
end
@@ -287,18 +347,18 @@ function love.textinput(texts)
WIDGET.textinput(texts)
end
function love.joystickadded(JS)
table.insert(joysticks,JS)
MES.new('info',"Joystick added")
end
function love.joystickremoved(JS)
local i=TABLE.find(joysticks,JS)
if i then
table.remove(joysticks,i)
MES.new('info',"Joystick removed")
end
end
local keyMirror={
--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',
@@ -306,54 +366,118 @@ local keyMirror={
start='return',
back='escape',
}
function love.gamepadpressed(_,i)
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 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 SCN.swapping then return end
if SCN.gamepadDown then SCN.gamepadDown(i)
elseif SCN.keyDown then SCN.keyDown(keyMirror[i]or i)
elseif i=="back"then SCN.back()
else WIDGET.gamepadPressed(keyMirror[i]or i)
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 SETTING.clickFX then SYSFX.newTap(3,mx,my)end
_triggerMouseDown(mx,my,1)
else
if W and W.keypress then
W:keypress(key)
end
end
end
end
end
function love.gamepadreleased(_,i)
if SCN.swapping then return end
if SCN.gamepadUp then SCN.gamepadUp(i)end
end
--[[
function love.joystickpressed(JS,k)
mouseShow=false
if SCN.swapping then return end
if SCN.gamepadDown then SCN.gamepadDown(i)
elseif SCN.keyDown then SCN.keyDown(keyMirror[i]or i)
elseif i=="back"then SCN.back()
else WIDGET.gamepadPressed(i)
end
end
function love.joystickreleased(JS,k)
if SCN.swapping then return end
if SCN.gamepadUp then SCN.gamepadUp(i)
end
end
function love.joystickaxis(JS,axis,val)
end
function love.joystickhat(JS,hat,dir)
end
function love.sendData(data)end
function love.receiveData(id,data)end
]]
function love.filedropped(file)
if SCN.fileDropped then SCN.fileDropped(file)end
end
function love.directorydropped(dir)
if SCN.directoryDropped then SCN.directoryDropped(dir)end
end
local lastGCtime=0
local autoGCcount=0
function love.lowmemory()
if love.timer.getTime()-lastGCtime>6.26 then
collectgarbage()
lastGCtime=love.timer.getTime()
collectgarbage()
if autoGCcount<3 then
autoGCcount=autoGCcount+1
MES.new('check',"[auto GC] low MEM 设备内存过低")
end
end
@@ -378,7 +502,7 @@ end
function love.errorhandler(msg)
if type(msg)~='string'then
msg="Unknown error"
elseif msg:find("Invaild UTF-8")and text then
elseif msg:find("Invalid UTF-8")and text then
msg=text.tryAnotherBuild
end
@@ -402,20 +526,20 @@ function love.errorhandler(msg)
love.audio.stop()
gc.reset()
if LOADED and #ERRDATA<3 then
if LOADED and #errData<3 then
BG.set('none')
local scn=SCN and SCN.cur or"NULL"
table.insert(ERRDATA,{mes=err,scene=scn})
table.insert(errData,{mes=err,scene=scn})
--Write messages to log file
love.filesystem.append('conf/error.log',
os.date("%Y/%m/%d %A %H:%M:%S\n")..
#ERRDATA.." crash(es) "..love.system.getOS().."-"..VERSION.string.." scene: "..scn.."\n"..
#errData.." crash(es) "..love.system.getOS().."-"..VERSION.string.." scene: "..scn.."\n"..
table.concat(err,"\n",1,c-2).."\n\n"
)
--Get screencapture
gc.captureScreenshot(function(_)ERRDATA[#ERRDATA].shot=gc.newImage(_)end)
gc.captureScreenshot(function(_)errData[#errData].shot=gc.newImage(_)end)
gc.present()
--Create a new mainLoop thread to keep game alive
@@ -475,7 +599,7 @@ local devColor={
}
local WS=WS
local WSnames={'app','user','play','stream','chat','manage'}
local wsBottomImage do
local wsImg={}do
local L={78,18,
{'clear',1,1,1,0},
{'setCL',1,1,1,.3},
@@ -485,23 +609,23 @@ local wsBottomImage do
table.insert(L,{'setCL',1,1,1,i*.005})
table.insert(L,{'fRect',i,0,1,18})
end
wsBottomImage=GC.DO(L)
wsImg.bottom=GC.DO(L)
wsImg.dead=GC.DO{20,20,
{'rawFT',20},
{'setCL',1,.3,.3},
{'mText',"X",11,-1},
}
wsImg.connecting=GC.DO{20,20,
{'rawFT',20},
{'setLW',3},
{'mText',"C",11,-1},
}
wsImg.running=GC.DO{20,20,
{'rawFT',20},
{'setCL',.5,1,0},
{'mText',"R",11,-1},
}
end
local ws_deadImg=GC.DO{20,20,
{'setFT',20},
{'setCL',1,.3,.3},
{'mText',"X",11,-1},
}
local ws_connectingImg=GC.DO{20,20,
{'setFT',20},
{'setLW',3},
{'mText',"C",11,-1},
}
local ws_runningImg=GC.DO{20,20,
{'setFT',20},
{'setCL',.5,1,0},
{'mText',"R",11,-1},
}
local function drawCursor(_,x,y)
gc_setColor(1,1,1)
@@ -521,7 +645,6 @@ function love.run()
local TASK_update=TASK.update
local SYSFX_update,SYSFX_draw=SYSFX.update,SYSFX.draw
local WIDGET_update,WIDGET_draw=WIDGET.update,WIDGET.draw
local STEP,WAIT=love.timer.step,love.timer.sleep
local FPS,MINI=love.timer.getFPS,love.window.isMinimized
local PUMP,POLL=love.event.pump,love.event.poll
@@ -538,7 +661,7 @@ function love.run()
--Scene Launch
while #SCN.stack>0 do SCN.pop()end
SCN.push('quit','slowFade')
SCN.init(#ERRDATA==0 and'load'or'error')
SCN.init(#errData==0 and'load'or'error')
return function()
local _
@@ -560,6 +683,8 @@ function love.run()
--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)
@@ -622,9 +747,8 @@ function love.run()
--Left-down infos
gc_setColor(devColor[devMode])
gc_print("MEM "..gcinfo(),safeX+5,-40)
gc_print("Lines "..FREEROW.getCount(),safeX+5,-60)
gc_print("Tasks "..TASK.getCount(),safeX+5,-80)
gc_print("Voices "..VOC.getQueueCount(),safeX+5,-100)
gc_print("Tasks "..TASK.getCount(),safeX+5,-60)
gc_print("Voices "..VOC.getQueueCount(),safeX+5,-80)
--Update & draw frame time
table.insert(frameTimeList,1,dt)table.remove(frameTimeList,126)
@@ -652,14 +776,14 @@ function love.run()
for i=1,6 do
local status=WS.status(WSnames[i])
gc_setColor(1,1,1)
gc.draw(wsBottomImage,-79,20*i-139)
gc.draw(wsImg.bottom,-79,20*i-139)
if status=='dead'then
gc_draw(ws_deadImg,-20,20*i-140)
gc_draw(wsImg.dead,-20,20*i-140)
elseif status=='connecting'then
gc_setColor(1,1,1,.5+.3*math.sin(time*6.26))
gc_draw(ws_connectingImg,-20,20*i-140)
gc_draw(wsImg.connecting,-20,20*i-140)
elseif status=='running'then
gc_draw(ws_runningImg,-20,20*i-140)
gc_draw(wsImg.running,-20,20*i-140)
end
local t1,t2,t3=WS.getTimers(WSnames[i])
gc_setColor(.9,.9,.9,t1)gc.rectangle('fill',-60,20*i-122,-16,-16)
@@ -703,6 +827,9 @@ end
local Z={}
Z.js=jsState
Z.errData=errData
function Z.setIfPowerInfo(func)showPowerInfo=func end
--[Warning] Color and line width is uncertain value, set it in the function.

23
Zframework/mathExtend.lua Normal file
View File

@@ -0,0 +1,23 @@
local MATH={}for k,v in next,math do MATH[k]=v end
local rnd=math.random
MATH.tau=2*math.pi
function MATH.sign(a)
return a>0 and 1 or a<0 and -1 or 0
end
function MATH.roll(chance)
return rnd()<(chance or .5)
end
function MATH.coin(a,b)
if rnd()<.5 then
return a
else
return b
end
end
return MATH

View File

@@ -1,4 +1,5 @@
local type,rem=type,table.remove
local int,rnd=math.floor,math.random
local sfxList={}
local packSetting={}
@@ -6,7 +7,7 @@ local Sources={}
local volume=1
local stereo=1
local noteName={
local noteVal={
C=1,c=1,
D=3,d=3,
E=5,e=5,
@@ -15,10 +16,11 @@ local noteName={
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=noteName[tune:sub(1,1)]
local tuneHeight=noteVal[tune:sub(1,1)]
if tuneHeight then
tuneHeight=tuneHeight+(octave-1)*12
local s=tune:sub(2,2)
@@ -55,14 +57,14 @@ function SFX.loadSample(pack)
assert(type(pack)=='table',"Usage: SFX.loadsample([table])")
assert(pack.name,"No field: name")
assert(pack.path,"No field: path")
packSetting[pack.name]={
base=(_getTuneHeight(pack.base)or 37)-1,
}
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
@@ -70,31 +72,47 @@ function SFX.getCount()
return #sfxList
end
function SFX.setVol(v)
assert(type(v)=='number'and v>=0 and v<=1)
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)
assert(type(v)=='number'and v>=0 and v<=1,'Wrong stereo')
stereo=v
end
function SFX.playSample(pack,...)--vol-2, sampSet1, vol-3, sampSet2, vol-1
function SFX.getNoteName(note)
if note<1 then
return'---'
else
note=note-1
local octave=int(note/12)+1
return noteName[note%12+1]..octave
end
end
function SFX.playSample(pack,...)--vol-1, sampSet1, vol-2, sampSet2
if ... then
local arg={...}
local vol
if type(arg[#arg])=='number'then vol=rem(arg)end
for i=1,#arg do
if type(arg[i])=='number'then
vol=arg[i]
local a=arg[i]
if type(a)=='number'and a<=1 then
vol=a
else
local tune=arg[i]
tune=_getTuneHeight(tune)-packSetting[pack].base
SFX.play(pack..tune,vol)
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
function SFX.play(name,vol,pos)
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
@@ -116,32 +134,13 @@ function SFX.play(name,vol,pos)
S:setPosition(0,0,0)
end
end
S:setVolume(((vol or 1)*volume)^1.626)
S:setVolume(vol^1.626)
S:setPitch(pitch and 1.0594630943592953^pitch or 1)
S:play()
end
function SFX.fplay(name,vol,pos)
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=pos*stereo
S:setPosition(pos,1-pos^2,0)
else
S:setPosition(0,0,0)
end
end
S:setVolume(vol^1.626)
S:play()
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

View File

@@ -2,9 +2,25 @@ local data=love.data
local STRING={}
local assert,tostring,tonumber=assert,tostring,tonumber
local int,format=math.floor,string.format
local find,sub,upper=string.find,string.sub,string.upper
local find,sub,gsub,upper=string.find,string.sub,string.gsub,string.upper
local char,byte=string.char,string.byte
--"Replace dollars", replace all $n with ...
function string.repD(str,...)
local l={...}
for i=#l,1,-1 do
str=gsub(str,'$'..i,l[i])
end
return str
end
--"Scan arg", scan if str has the arg (format of str is like "-json -q", arg is like "-q")
function string.sArg(str,switch)
if find(str.." ",switch.." ")then
return true
end
end
do--function STRING.shiftChar(c)
local shiftMap={
['1']='!',['2']='@',['3']='#',['4']='$',['5']='%',
@@ -63,9 +79,9 @@ function STRING.time(t)
if t<60 then
return format("%.3f\"",t)
elseif t<3600 then
return format("%d'%05.2f\"",int(t/60),t%60)
return format("%d'%05.2f\"",int(t/60),int(t%60*100)/100)
else
return format("%d:%.2d'%05.2f\"",int(t/3600),int(t/60%60),t%60)
return format("%d:%.2d'%05.2f\"",int(t/3600),int(t/60%60),int(t%60*100)/100)
end
end

View File

@@ -1,4 +1,5 @@
local find=string.find
local rem=table.remove
local next,type=next,type
local TABLE={}
@@ -46,6 +47,18 @@ function TABLE.cover(new,old)
end
end
--For all things in new, push to old
function TABLE.coverR(new,old)
for k,v in next,new do
if type(v)=='table'and type(old[k])=='table'then
TABLE.coverR(v,old[k])
else
old[k]=v
end
end
end
--For all things in new if same type in old, push to old
function TABLE.update(new,old)
for k,v in next,new do
@@ -71,7 +84,7 @@ function TABLE.complete(new,old)
end
end
--Remove positive integer index of table
--Remove [1~#] of table
function TABLE.cut(G)
for i=1,#G do
G[i]=nil
@@ -85,11 +98,53 @@ function TABLE.clear(G)
end
end
--Remove duplicated value of [1~#]
function TABLE.trimDuplicate(org)
local cache={}
for i=1,#org,-1 do
if cache[org[i]]then
rem(org,i)
else
cache[org[i]]=true
end
end
end
--Discard duplicated value
function TABLE.remDuplicate(org)
local cache={}
for k,v in next,org do
if cache[v]then
org[k]=nil
else
cache[v]=true
end
end
end
--Reverse [1~#]
function TABLE.reverse(org)
local l=#org
for i=1,math.floor(l/2)do
org[i],org[l+1-i]=org[l+1-i],org[i]
end
end
--------------------------
--Find value in [1~#]
function TABLE.find(t,val)
for i=1,#t do if t[i]==val then return i end end
end
--Return next value of [1~#] (by value)
function TABLE.next(t,val)
for i=1,#t do if t[i]==val then return t[i%#t+1]end end
end
--------------------------
--Find value in whole table
function TABLE.search(t,val)
for k,v in next,t do if v==val then return k end end
@@ -104,6 +159,8 @@ function TABLE.reIndex(org)
end
end
--------------------------
--Dump a simple lua table
do--function TABLE.dump(L,t)
local tabs={

View File

@@ -1,5 +1,7 @@
local rnd=math.random
local volume=1
local diversion=0
local VOC={
vol=1,
getCount=function()return 0 end,
getQueueCount=function()return 0 end,
load=function()error("Cannot load before init!")end,
@@ -7,13 +9,16 @@ local VOC={
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)
VOC.vol=v
assert(type(v)=='number'and v>=0 and v<=1,'Wrong volume')
volume=v
end
function VOC.init(list)
VOC.init=nil
local rnd=math.random
local rem=table.remove
local voiceQueue={free=0}
local bank={}--{vocName1={SRC1s},vocName2={SRC2s},...}
@@ -72,7 +77,7 @@ function VOC.init(list)
end
function VOC.play(s,chn)
if VOC.vol>0 then
if volume>0 then
local _=Source[s]
if not _ then return end
if chn then
@@ -95,13 +100,15 @@ function VOC.init(list)
end
elseif Q.s==1 then--Waiting load source
Q[1]=_getVoice(Q[1])
Q[1]:setVolume(VOC.vol)
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(VOC.vol)
Q[2]:setVolume(volume)
Q[1]:setPitch(1.0594630943592953^(diversion*(rnd()*2-1)))
Q[2]:play()
Q.s=3
end

View File

@@ -9,11 +9,11 @@ return function(y,key1,key2)
trigDist=min(trigDist,0)-(-y)^1.2
end
while trigDist>=1 do
love.keypressed(key1 or"up")
love.keypressed(key1 or'up')
trigDist=trigDist-1
end
while trigDist<=-1 do
love.keypressed(key2 or"down")
love.keypressed(key2 or'down')
trigDist=trigDist+1
end
end

View File

@@ -13,10 +13,9 @@ local kb=love.keyboard
local timer=love.timer.getTime
local next=next
local int,ceil,abs=math.floor,math.ceil,math.abs
local int,ceil=math.floor,math.ceil
local max,min=math.max,math.min
local sub,ins,rem=string.sub,table.insert,table.remove
local mDraw,mDraw_X,mDraw_Y=GC.draw,GC.simpX,GC.simpY
local xOy=SCR.xOy
local FONT=FONT
local mStr=GC.mStr
@@ -29,7 +28,7 @@ local clearIcon=GC.DO{40,40,
{'fRect',11,14,18,21},
}
local sureIcon=GC.DO{40,40,
{'setFT',35},
{'rawFT',35},
{'mText',"?",20,0},
}
local smallerThen=GC.DO{20,20,
@@ -74,7 +73,7 @@ function text:draw()
local c=self.color
gc_setColor(c[1],c[2],c[3],self.alpha)
if self.align=='M'then
mDraw_X(self.obj,self.x,self.y)
gc_draw(self.obj,self.x-self.obj:getWidth()*.5,self.y)
elseif self.align=='L'then
gc_draw(self.obj,self.x,self.y)
elseif self.align=='R'then
@@ -82,7 +81,7 @@ function text:draw()
end
end
end
function WIDGET.newText(D)--name,x,y[,fText][,color][,font=30][,align='M'][,hideF][,hide]
function WIDGET.newText(D)--name,x,y[,fText][,color][,font=30][,fType][,align='M'][,hideF][,hide]
local _={
name= D.name or"_",
x= D.x,
@@ -91,6 +90,7 @@ function WIDGET.newText(D)--name,x,y[,fText][,color][,font=30][,align='M'][,hide
fText=D.fText,
color=D.color and(COLOR[D.color]or D.color)or COLOR.Z,
font= D.font or 30,
fType=D.fType,
align=D.align or'M',
hideF=D.hideF,
}
@@ -139,7 +139,7 @@ function button:reset()
end
function button:setObject(obj)
if type(obj)=='string'or type(obj)=='number'then
self.obj=gc.newText(FONT.get(self.font),obj)
self.obj=gc.newText(FONT.get(self.font,self.fType),obj)
elseif obj then
self.obj=obj
end
@@ -180,36 +180,38 @@ function button:draw()
--Drawable
local obj=self.obj
local ox,oy=obj:getWidth()*.5,obj:getHeight()*.5
local y0=y+h*.5-ATV*.5
gc_setColor(1,1,1,.2+ATV*.05)
if self.align=='M'then
local x0=x+w*.5
mDraw(obj,x0-1,y0-1)
mDraw(obj,x0-1,y0+1)
mDraw(obj,x0+1,y0-1)
mDraw(obj,x0+1,y0+1)
local kx=obj:type()=='Text'and min(w/ox/2,1)or 1
gc_draw(obj,x0-1,y0-1,nil,kx,1,ox,oy)
gc_draw(obj,x0-1,y0+1,nil,kx,1,ox,oy)
gc_draw(obj,x0+1,y0-1,nil,kx,1,ox,oy)
gc_draw(obj,x0+1,y0+1,nil,kx,1,ox,oy)
gc_setColor(r*.55,g*.55,b*.55)
mDraw(obj,x0,y0)
gc_draw(obj,x0,y0,nil,kx,1,ox,oy)
elseif self.align=='L'then
local edge=self.edge
mDraw_Y(obj,x+edge-1,y0-1)
mDraw_Y(obj,x+edge-1,y0+1)
mDraw_Y(obj,x+edge+1,y0-1)
mDraw_Y(obj,x+edge+1,y0+1)
gc_draw(obj,x+edge-1,y0-1-oy)
gc_draw(obj,x+edge-1,y0+1-oy)
gc_draw(obj,x+edge+1,y0-1-oy)
gc_draw(obj,x+edge+1,y0+1-oy)
gc_setColor(r*.55,g*.55,b*.55)
mDraw_Y(obj,x+edge,y0)
gc_draw(obj,x+edge,y0-oy)
elseif self.align=='R'then
local x0=x+w-self.edge-obj:getWidth()
mDraw_Y(obj,x0-1,y0-1)
mDraw_Y(obj,x0-1,y0+1)
mDraw_Y(obj,x0+1,y0-1)
mDraw_Y(obj,x0+1,y0+1)
local x0=x+w-self.edge-ox*2
gc_draw(obj,x0-1,y0-1-oy)
gc_draw(obj,x0-1,y0+1-oy)
gc_draw(obj,x0+1,y0-1-oy)
gc_draw(obj,x0+1,y0+1-oy)
gc_setColor(r*.55,g*.55,b*.55)
mDraw_Y(obj,x0,y0)
gc_draw(obj,x0,y0-oy)
end
end
function button:getInfo()
return("x=%d,y=%d,w=%d,h=%d,font=%d"):format(self.x+self.w*.5,self.y+self.h*.5,self.w,self.h,self.font)
return("x=%d,y=%d,w=%d,h=%d,font=%d"):format(self.x+self.w*.5,self.y+self.h*.5,self.w,self.h,self.font,self.fType)
end
function button:press(_,_,k)
self.code(k)
@@ -225,7 +227,7 @@ function button:press(_,_,k)
SFX.play('button')
end
end
function WIDGET.newButton(D)--name,x,y,w[,h][,fText][,color][,font=30][,sound=true][,align='M'][,edge=0],code[,hideF][,hide]
function WIDGET.newButton(D)--name,x,y,w[,h][,fText][,color][,font=30][,fType][,sound=true][,align='M'][,edge=0][,code][,hideF][,hide]
if not D.h then D.h=D.w end
local _={
name= D.name or"_",
@@ -246,10 +248,11 @@ function WIDGET.newButton(D)--name,x,y,w[,h][,fText][,color][,font=30][,sound=tr
fText=D.fText,
color=D.color and(COLOR[D.color]or D.color)or COLOR.Z,
font= D.font or 30,
fType=D.fType,
align=D.align or'M',
edge= D.edge or 0,
sound=D.sound~=false,
code= D.code,
code= D.code or NULL,
hideF=D.hideF,
hide= D.hide,
}
@@ -268,7 +271,7 @@ function key:reset()
end
function key:setObject(obj)
if type(obj)=='string'or type(obj)=='number'then
self.obj=gc.newText(FONT.get(self.font),obj)
self.obj=gc.newText(FONT.get(self.font,self.fType),obj)
elseif obj then
self.obj=obj
end
@@ -309,11 +312,11 @@ function key:draw()
if self.fShade then
gc_setColor(r,g,b,ATV*.25)
if align=='M'then
mDraw(self.fShade,x+w*.5,y+h*.5)
gc_draw(self.fShade,x+w*.5-self.fShade:getWidth()*.5,y+h*.5-self.fShade:getHeight()*.5)
elseif align=='L'then
mDraw_Y(self.fShade,x+self.edge,y+h*.5)
gc_draw(self.fShade,x+self.edge,y+h*.5-self.fShade:getHeight()*.5)
elseif align=='R'then
mDraw_Y(self.fShade,x+w-self.edge-self.fShade:getWidth(),y+h*.5)
gc_draw(self.fShade,x+w-self.edge-self.fShade:getWidth(),y+h*.5-self.fShade:getHeight()*.5)
end
else
gc_setColor(1,1,1,ATV*.05)
@@ -321,17 +324,20 @@ function key:draw()
end
--Drawable
local obj=self.obj
local ox,oy=obj:getWidth()*.5,obj:getHeight()*.5
gc_setColor(r,g,b)
if align=='M'then
mDraw(self.obj,x+w*.5,y+h*.5)
local kx=obj:type()=='Text'and min(w/ox/2,1)or 1
gc_draw(obj,x+w*.5,y+h*.5,nil,kx,1,ox,oy)
elseif align=='L'then
mDraw_Y(self.obj,x+self.edge,y+h*.5)
gc_draw(obj,x+self.edge,y-oy+h*.5)
elseif align=='R'then
mDraw_Y(self.obj,x+w-self.edge-self.obj:getWidth(),y+h*.5)
gc_draw(obj,x+w-self.edge-ox*2,y-oy+h*.5)
end
end
function key:getInfo()
return("x=%d,y=%d,w=%d,h=%d,font=%d"):format(self.x+self.w*.5,self.y+self.h*.5,self.w,self.h,self.font)
return("x=%d,y=%d,w=%d,h=%d,font=%d"):format(self.x+self.w*.5,self.y+self.h*.5,self.w,self.h,self.font,self.fType)
end
function key:press(_,_,k)
self.code(k)
@@ -339,7 +345,7 @@ function key:press(_,_,k)
SFX.play('key')
end
end
function WIDGET.newKey(D)--name,x,y,w[,h][,fText][,fShade][,noFrame][,color][,font=30][,sound=true][,align='M'][,edge=0],code[,hideF][,hide]
function WIDGET.newKey(D)--name,x,y,w[,h][,fText][,fShade][,noFrame][,color][,font=30][,fType][,sound=true][,align='M'][,edge=0][,code][,hideF][,hide]
if not D.h then D.h=D.w end
local _={
name= D.name or"_",
@@ -362,10 +368,11 @@ function WIDGET.newKey(D)--name,x,y,w[,h][,fText][,fShade][,noFrame][,color][,fo
noFrame=D.noFrame,
color= D.color and(COLOR[D.color]or D.color)or COLOR.Z,
font= D.font or 30,
fType=D.fType,
sound= D.sound~=false,
align= D.align or'M',
edge= D.edge or 0,
code= D.code,
code= D.code or NULL,
hideF= D.hideF,
hide= D.hide,
}
@@ -430,15 +437,15 @@ function switch:draw()
gc_draw(obj,x-12-ATV,y,nil,min(self.lim/obj:getWidth(),1),1,obj:getWidth(),obj:getHeight()*.5)
end
function switch:getInfo()
return("x=%d,y=%d,font=%d"):format(self.x,self.y,self.font)
return("x=%d,y=%d,font=%d"):format(self.x,self.y,self.font,self.fType)
end
function switch:press()
self.code()
if self.sound then
SFX.play('touch')
SFX.play(self.disp()and'check'or'uncheck')
end
end
function WIDGET.newSwitch(D)--name,x,y[,lim][,fText][,color][,font=30][,sound=true][,disp],code[,hideF][,hide]
function WIDGET.newSwitch(D)--name,x,y[,lim][,fText][,color][,font=30][,fType][,sound=true][,disp][,code][,hideF][,hide]
local _={
name= D.name or"_",
@@ -453,9 +460,10 @@ function WIDGET.newSwitch(D)--name,x,y[,lim][,fText][,color][,font=30][,sound=tr
fText=D.fText,
color=D.color and(COLOR[D.color]or D.color)or COLOR.Z,
font= D.font or 30,
fType=D.fType,
sound=D.sound~=false,
disp= D.disp,
code= D.code,
code= D.code or NULL,
hideF=D.hideF,
hide= D.hide,
}
@@ -593,9 +601,9 @@ function slider:scroll(n)
end
end
function slider:arrowKey(k)
self:scroll((k=="left"or k=="up")and -1 or 1)
self:scroll((k=='left'or k=='up')and -1 or 1)
end
function WIDGET.newSlider(D)--name,x,y,w[,lim][,fText][,color][,unit][,smooth][,font=30][,change],disp[,show],code,hide
function WIDGET.newSlider(D)--name,x,y,w[,lim][,fText][,color][,unit][,smooth][,font=30][,fType][,change],disp[,show][,code],hide
local _={
name= D.name or"_",
@@ -617,9 +625,10 @@ function WIDGET.newSlider(D)--name,x,y,w[,lim][,fText][,color][,unit][,smooth][,
unit= D.unit or 1,
smooth=false,
font= D.font or 30,
fType=D.fType,
change=D.change,
disp= D.disp,
code= D.code,
code= D.code or NULL,
hideF= D.hideF,
hide= D.hide,
show= false,
@@ -744,7 +753,7 @@ function selector:press(x)
self.select=s
self.selText=self.list[s]
if self.sound then
SFX.play('prerotate')
SFX.play('selector')
end
end
end
@@ -764,14 +773,14 @@ function selector:scroll(n)
self.select=s
self.selText=self.list[s]
if self.sound then
SFX.play('prerotate')
SFX.play('selector')
end
end
function selector:arrowKey(k)
self:scroll((k=="left"or k=="up")and -1 or 1)
self:scroll((k=='left'or k=='up')and -1 or 1)
end
function WIDGET.newSelector(D)--name,x,y,w[,fText][,color][,sound=true],list,disp,code,hide
function WIDGET.newSelector(D)--name,x,y,w[,fText][,color][,sound=true],list,disp[,code],hide
local _={
name= D.name or"_",
@@ -793,7 +802,7 @@ function WIDGET.newSelector(D)--name,x,y,w[,fText][,color][,sound=true],list,dis
font= 30,
list= D.list,
disp= D.disp,
code= D.code,
code= D.code or NULL,
hideF=D.hideF,
hide= D.hide,
}
@@ -863,9 +872,9 @@ function inputBox:draw()
--Drawable
local f=self.font
FONT.set(f)
FONT.set(f,self.fType)
if self.obj then
mDraw_Y(self.obj,x-12-self.obj:getWidth(),y+h*.5)
gc_draw(self.obj,x-12-self.obj:getWidth(),y+h*.5-self.obj:getHeight()*.5)
end
if self.secret then
y=y+h*.5-f*.2
@@ -892,21 +901,21 @@ end
function inputBox:keypress(k)
local t=self.value
if #t>0 and EDITING==""then
if k=="backspace"then
if k=='backspace'then
local p=#t
while t:byte(p)>=128 and t:byte(p)<192 do
p=p-1
end
t=sub(t,1,p-1)
SFX.play('lock')
elseif k=="delete"then
elseif k=='delete'then
t=""
SFX.play('hold')
end
self.value=t
end
end
function WIDGET.newInputBox(D)--name,x,y,w[,h][,font=30][,secret][,regex][,limit],hide
function WIDGET.newInputBox(D)--name,x,y,w[,h][,font=30][,fType][,secret][,regex][,limit],hide
local _={
name= D.name or"_",
@@ -922,6 +931,7 @@ function WIDGET.newInputBox(D)--name,x,y,w[,h][,font=30][,secret][,regex][,limit
},
font= D.font or int(D.h/7-1)*5,
fType=D.fType,
secret=D.secret==true,
regex= D.regex,
limit= D.limit,
@@ -999,9 +1009,9 @@ function textBox:scroll(dir)
self:drag(nil,nil,nil,-dir*self.lineH)
end
function textBox:arrowKey(k)
if k=="up"then
if k=='up'then
self:scroll(-1)
elseif k=="down"then
elseif k=='down'then
self:scroll(-1)
end
end
@@ -1022,7 +1032,7 @@ function textBox:draw()
gc_rectangle('line',x,y,w,h,3)
--Texts
FONT.set(self.font)
FONT.set(self.font,self.fType)
gc_push('transform')
gc_translate(x,y)
@@ -1054,7 +1064,7 @@ end
function textBox:getInfo()
return("x=%d,y=%d,w=%d,h=%d"):format(self.x+self.w*.5,self.y+self.h*.5,self.w,self.h)
end
function WIDGET.newTextBox(D)--name,x,y,w,h[,font=30][,lineH][,fix],hide
function WIDGET.newTextBox(D)--name,x,y,w,h[,font=30][,fType][,lineH][,fix],hide
local _={
name= D.name or"_",
@@ -1076,6 +1086,7 @@ function WIDGET.newTextBox(D)--name,x,y,w,h[,font=30][,lineH][,fix],hide
h= D.h,
font= D.font or 30,
fType=D.fType,
fix= D.fix,
texts={},
hideF=D.hideF,
@@ -1153,7 +1164,7 @@ function listBox:press(x,y)
if self.list[y]then
if self.selected~=y then
self.selected=y
SFX.play('click',.4)
SFX.play('selector',.8,0,12)
end
end
end
@@ -1373,59 +1384,6 @@ function WIDGET.release(x,y)
W:release(x,y+WIDGET.scrollPos)
end
end
function WIDGET.keyPressed(k,isRep)
local W=WIDGET.sel
if k=="space"or k=="return"then
if not isRep then
WIDGET.press()
end
elseif k=="up"or k=="down"or k=="left"or k=="right"then
if kb.isDown("lshift","lalt","lctrl")then
--Control some widgets with arrowkeys when hold shift/ctrl/alt
if W and W.arrowKey then W:arrowKey(k)end
else
if not W then
for _,w in next,WIDGET.active do
if not w.hide and w.isAbove then
WIDGET.focus(w)
return
end
end
elseif W.getCenter then
local WX,WY=W:getCenter()
local dir=(k=="right"or k=="down")and 1 or -1
local tar
local minDist=1e99
local swap_xy=k=="up"or k=="down"
if swap_xy then WX,WY=WY,WX end--note that we do not swap them back later
for _,W1 in ipairs(WIDGET.active)do
if W~=W1 and W1.resCtr and not W1.hide then
local L=W1.resCtr
for j=1,#L,2 do
local x,y=L[j],L[j+1]
if swap_xy then x,y=y,x end--note that we do not swap them back later
local dist=(x-WX)*dir
if dist>10 then
dist=dist+abs(y-WY)*6.26
if dist<minDist then
minDist=dist
tar=W1
end
end
end
end
end
if tar then
WIDGET.focus(tar)
end
end
end
else
if W and W.keypress then
W:keypress(k)
end
end
end
function WIDGET.textinput(texts)
local W=WIDGET.sel
if W and W.type=='inputBox'then
@@ -1433,41 +1391,10 @@ function WIDGET.textinput(texts)
WIDGET.sel.value=WIDGET.sel.value..texts
SFX.play('touch')
else
SFX.play('finesseError',.3)
SFX.play('drop_cancel')
end
end
end
local keyMirror={
dpup="up",
dpdown="down",
dpleft="left",
dpright="right",
start="return",
back="escape",
}
function WIDGET.gamepadPressed(i)
if i=="start"then
WIDGET.press()
elseif i=="a"or i=="b"then
local W=WIDGET.sel
if W then
if W.type=='button'or W.type=='key'then
WIDGET.press()
elseif W.type=='slider'then
local p=W.disp()
local P=i=="left"and(p>0 and p-1)or p<W.unit and p+1
if p==P or not P then return end
W.code(P)
if W.change and timer()-W.lastTime>.18 then
W.lastTime=timer()
W.change()
end
end
end
elseif i=="dpup"or i=="dpdown"or i=="dpleft"or i=="dpright"then
WIDGET.keyPressed(keyMirror[i])
end
end
function WIDGET.update(dt)
for _,W in next,WIDGET.active do

View File

@@ -1,30 +1,23 @@
**TECHMINO © 2019-2021 26F Studio. Some rights reserved.**
TECHMINO and "26F Studio" are trademarks of 26F Studio.
The TECHMINO game and source code are under a GNU Lesser General Public License Version 3.
TECHMINO © 2019-2021 26F Studio. Some rights reserved.
TECHMINO and "26F Studio" are trademarks of 26F Studio. The TECHMINO game and source code are under a GNU Lesser General Public License Version 3.
TECHMINO is not a fan game of Tetris. TECHMINO and 26F Studio are not affiliated with Tetris Holding, LLC or The Tetris Company, Inc. in any way.
"Tetris" is the registered trademark of The Tetris Holding, LLC, licensed to The Tetris Company, Inc.
"Tetris" is the registered trademark of The Tetris Holding, LLC, licensed to The Tetris Company, Inc. TECHMINO is not a fan game of Tetris. TECHMINO and 26F Studio are not affiliated with Tetris Holding, LLC or The Tetris Company, Inc. in any way.
Powered by LÖVE, © 2006-2021 LÖVE Development Team.
Lua is free software distributed under the terms of the MIT license. Copyright © 1994-2021 by Lua.org, PUC-Rio.
Lua is free software distributed under the terms of the MIT license. Copyright © 1994~2021 by Lua.org, PUC-Rio.
SIMPLE LOVE LIGHTS is under a MIT License. Created by Dylan Hunn.
json.lua is copyrighted by rxi. © 2021 rxi.
IBM Plex is copyrighted by the International Business Machines Corporation. IBM and IBM Plex are trademarks of IBM Corp, registered in many jurisdictions worldwide. IBM Plex is licensed under the SIL Open Font License, Version 1.1.
The Apple logo, "Apple Inc.," iOS, iPadOS, macOS, iPhone, and Mac are registered trademarks of Apple Inc. in the United States of America and other countries or regions.
"Windows", the Windows logo, "Xbox", Xbox logo, and "Microsoft" are registered trademarks of Microsoft Corporation in the United States of America and other countries or regions.
Alibaba Sans is copyrighted by Alibaba Group Holding Limited. Alibaba is a trademark of Alibaba Group Holding Limited in the Peoples Republic of China and other countries or regions.
IBM Plex is copyrighted by the International Business Machines Corporation. IBM and IBM Plex are trademarks of IBM Corp, registered in many jurisdictions worldwide. IBM Plex is licensed under the SIL Open Font License.
Source Han Sans is copyrighted by Adobe Inc. Source Han Sans and Adobe are registered trademarks of Adobe Inc. in United States and other countries or regions. Source Han Sans is licensed under the SIL Open Font License, Version 1.1.
JetBrains Mono is copyrighted by the JetBrains Mono Project authors. JetBrains Mono is a trademark of JetBrains s.r.o. JetBrains Mono is licensed under the SIL Open Font License, Version 1.1.
@@ -33,22 +26,26 @@ JetBrains Mono is copyrighted by the JetBrains Mono Project authors. JetBrains M
"PlayStation", "PS", "PlayStation Family Mark", "PS logo", "DualSense" and "Play Has No Limits" are registered trademarks or trademarks of Sony Interactive Entertainment Inc. "SONY" is a registered trademark of Sony Corporation. © 2021 Sony Interactive Entertainment LLC.
N3TWORK is a registered trademark of N3TWORK Inc. © 2021 N3TWORK Inc.
"Windows", the Windows logo, "Xbox", Xbox logo, and "Microsoft" are registered trademarks of Microsoft Corporation in the United States of America and other countries or regions.
The Apple logo, "Apple Inc.," iOS, iPadOS, macOS, iPhone, and Mac are registered trademarks of Apple Inc. in the United States of America and other countries or regions.
"EA" and "Electronic Arts" are registered trademarks of Electronic Arts Inc. © 2021 Electronic Arts Inc.
SEGA and the SEGA logo are registered trademarks of Sega Corporation. © 2021 Sega Corporation.
Oculus Quest is a registered trademark of Facebook Technologies, LLC. © Facebook, Inc.
Oculus Quest is a registered trademark of Facebook Technologies, LLC. © Meta Platforms, Inc.
"Nintendo" is a registered trademarks of Nintendo Co., Ltd. © 2021 Nintendo Co., Ltd.
N3TWORK is a registered trademark of N3TWORK Inc. © 2021 N3TWORK Inc.
GoldWave is a registered trademark of GoldWave, Inc.
Linux is a registered trademark of Linus Torvalds.
Linux is a registered trademark of Linus Torvalds.
Touhou Project © Team Shanghai Alice 2002-2021.
All other trademarks are the properties of their respective owners.
All other trademarks, logos, and copyrights are the properties of their respective owners.

View File

@@ -24,6 +24,7 @@ VERSION=require"version"
TIME=love.timer.getTime
YIELD=coroutine.yield
SYSTEM=love.system.getOS()
FNSF=SYSTEM:find'\79\83'--What does FNSF stand for? IDK so don't ask me lol
MOBILE=SYSTEM=='Android'or SYSTEM=='iOS'
SAVEDIR=fs.getSaveDirectory()
@@ -49,9 +50,17 @@ local _LOADTIME_=TIME()
--Load modules
Z=require'Zframework'
FONT.load('parts/fonts/proportional.ttf')
FONT.load{
norm='parts/fonts/proportional.ttf',
mono='parts/fonts/monospaced.ttf',
}
FONT.setDefault('norm')
FONT.setFallback('norm')
SCR.setSize(1280,720)--Initialize Screen size
BGM.setMaxSources(5)
BGM.setChange(function(name)MES.new('music',text.nowPlaying..name,5)end)
VOC.setDiversion(1)
table.insert(_LOADTIMELIST_,("Load Zframework: %.3fs"):format(TIME()-_LOADTIME_))
@@ -90,7 +99,8 @@ for _,v in next,fs.getDirectoryItems('parts/shaders')do
end
end
FREEROW= require'parts.freeRow'
THEME= require'parts.theme'
LINE= require'parts.line'
DATA= require'parts.data'
TEXTURE= require'parts.texture'
@@ -104,6 +114,12 @@ PLY= require'parts.player'
NETPLY= require'parts.netPlayer'
MODES= require'parts.modes'
setmetatable(TEXTURE,{__index=function(self,k)
MES.new('warn',"No texture called: "..k)
self[k]=love.graphics.newCanvas(1,1)
return self[k]
end})
table.insert(_LOADTIMELIST_,("Load Parts: %.3fs"):format(TIME()-_LOADTIME_))
--Init Zframework
@@ -196,15 +212,15 @@ end
Z.setOnQuit(destroyPlayers)
--Load settings and statistics
TABLE.cover (FILE.load('conf/user')or{},USER)
TABLE.cover (FILE.load('conf/unlock')or{},RANKS)
TABLE.update(FILE.load('conf/settings')or{},SETTING)
TABLE.update(FILE.load('conf/data')or{},STAT)
TABLE.cover (FILE.load('conf/key')or{},KEY_MAP)
TABLE.cover (FILE.load('conf/virtualkey')or{},VK_ORG)
TABLE.cover (loadFile('conf/user','-canSkip')or{},USER)
TABLE.cover (loadFile('conf/unlock','-canSkip')or{},RANKS)
TABLE.update(loadFile('conf/settings','-canSkip')or{},SETTING)
TABLE.coverR(loadFile('conf/data','-canSkip')or{},STAT)
TABLE.cover (loadFile('conf/key','-canSkip')or{},KEY_MAP)
TABLE.cover (loadFile('conf/virtualkey','-json -canSkip')or{},VK_ORG)
--Initialize fields, sequence, missions, gameEnv for cutsom game
local fieldData=FILE.load('conf/customBoards','string')
local fieldData=loadFile('conf/customBoards','-string -canSkip')
if fieldData then
fieldData=STRING.split(fieldData,"!")
for i=1,#fieldData do
@@ -213,15 +229,15 @@ if fieldData then
else
FIELD[1]=DATA.newBoard()
end
local sequenceData=FILE.load('conf/customSequence','string')
local sequenceData=loadFile('conf/customSequence','-string -canSkip')
if sequenceData then
DATA.pasteSequence(sequenceData)
end
local missionData=FILE.load('conf/customMissions','string')
local missionData=loadFile('conf/customMissions','-string -canSkip')
if missionData then
DATA.pasteMission(missionData)
end
local customData=FILE.load('conf/customEnv')
local customData=loadFile('conf/customEnv','-canSkip')
if customData and customData['version']==VERSION.code then
TABLE.complete(customData,CUSTOMENV)
end
@@ -364,6 +380,7 @@ for _,v in next,fs.getDirectoryItems('parts/backgrounds')do
BG.add(name,require('parts.backgrounds.'..name))
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 isSafeFile('parts/scenes/'..v)then
@@ -398,7 +415,6 @@ do
local needSave
if not fs.getInfo('conf/data')then
FIRSTLAUNCH=true
needSave=true
end
if type(STAT.version)~='number'then
@@ -430,7 +446,6 @@ do
if RANKS.tsd_u then
RANKS.tsd_u=0
end
needSave=true
end
if STAT.version==1601 then
RANKS.round_e=nil
@@ -444,7 +459,11 @@ do
fs.remove('record/round_l.rec')
fs.remove('record/round_u.rec')
end
if STAT.version<1604 then
if STAT.version<1700 and SETTING.dascut<5 then
SETTING.dascut=SETTING.dascut+1
needSave=true
end
if RANKS.stack_e then
RANKS.stack_e=nil
RANKS.stack_h=nil
RANKS.stack_u=nil
@@ -460,6 +479,18 @@ do
fs.remove('record/stack_40l.rec')
fs.remove('record/stack_100l.rec')
end
if RANKS.rhythm_e then
RANKS.rhythm_e=nil
RANKS.rhythm_h=nil
RANKS.rhythm_u=nil
fs.remove('record/rhythm_e.rec')
fs.remove('record/rhythm_h.rec')
fs.remove('record/rhythm_u.rec')
end
if RANKS.bigbang then
RANKS.clearRush,RANKS.bigbang=RANKS.bigbang
fs.remove('record/bigbang.rec')
end
if STAT.version~=VERSION.code then
for k,v in next,MODE_UPDATE_MAP do
if RANKS[k]then
@@ -487,6 +518,7 @@ do
if type(SETTING.skinSet)=='number'then SETTING.skinSet='crystal_scf'end
if not TABLE.find({8,10,13,17,22,29,37,47,62,80,100},SETTING.frameMul)then SETTING.frameMul=100 end
if SETTING.cv then SETTING.vocPack,SETTING.cv=SETTING.cv end
if type(SETTING.bg)~='string'then SETTING.bg='on'end
if RANKS.infinite then RANKS.infinite=0 end
if RANKS.infinite_dig then RANKS.infinite_dig=0 end
if not RANKS.sprint_10l then RANKS.sprint_10l=0 end
@@ -526,7 +558,8 @@ do
end
end
--First start for phones
--First start
FIRSTLAUNCH=STAT.run==0
if FIRSTLAUNCH and MOBILE then
SETTING.VKSwitch=true
SETTING.powerInfo=true
@@ -612,9 +645,9 @@ if TABLE.find(arg,'--test')then
TASK.new(function()
while true do
YIELD()
if ERRDATA[1]then break end
if Z.errData[1]then break end
end
LOG("\27[91m\27[1mAutomatic Test Failed :(\27[0m\nThe error message is:\n"..table.concat(ERRDATA[1].mes,"\n").."\27[91m\nAborting\27[0m")
LOG("\27[91m\27[1mAutomatic Test Failed :(\27[0m\nThe error message is:\n"..table.concat(Z.errData[1].mes,"\n").."\27[91m\nAborting\27[0m")
TEST.yieldN(60)
love.event.quit(1)
end)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 B

BIN
media/music/malate.ogg Normal file

Binary file not shown.

BIN
media/music/peak.ogg Normal file

Binary file not shown.

View File

@@ -97,12 +97,12 @@ do
{131,2,2, 0, 0,0},{131,2,2,-1,-1,0},{131,2,2,-1, 0,0},--S
{131,1,2,-1, 0,0},{131,1,2, 0,-1,0},{131,1,2, 0, 0,0},--Z(misOrder)
{313,2,2, 0, 0,0},{313,2,2,-1,-1,0},{313,2,2,-1, 0,0},--S(misOrder)
{331,3,2, 0,-1,0},--J(farDown)
{113,4,2,-1,-1,0},--L(farDown)
{331,3,2, 0,-1,1},--J(farDown)
{113,4,2,-1,-1,1},--L(farDown)
{113,3,2,-1,-1,0},{113,3,0, 0, 0,0},--J
{331,4,2, 0,-1,0},{331,4,0,-1, 0,0},--L
{222,7,2,-1, 0,2},{222,7,2,-2, 0,2},{222,7,2, 0, 0,2},--I
{222,7,0,-1, 1,1},{222,7,0,-2, 1,1},{222,7,0, 0, 1,1},--I(high)
{222,7,2,-1, 0,2},{222,7,2,-2, 0,2},{222,7,2, 0, 0,2},--I(low)
{121,6,0, 1,-1,2},{112,6,0, 2,-1,2},{122,6,0, 1,-2,2},--O
{323,6,0,-1,-1,2},{332,6,0,-2,-1,2},{322,6,0,-1,-2,2},--O
}--{keys, ID, dir, dx, dy, freeLevel (0=immovable, 1=U/D-immovable, 2=free)}
@@ -129,10 +129,10 @@ do
[10]={'+0+0','+1+0','+1-1','+0+2','+1-2','+1-2'},
[03]={'+0+0','+1+0','+1+1','+0-2','+1-1','+1-2'},
[30]={'+0+0','-1+0','-1-1','+0+2','-1+2','+0-1'},
[12]={'+0+0','+1+0','+1-1','+0+2','+1+2'},
[21]={'+0+0','-1+0','-1+1','+0-2','-1-2'},
[32]={'+0+0','-1+0','-1-1','+0+2','-1+2'},
[23]={'+0+0','+1+0','+1+1','+0-2','+1-2'},
[12]={'+0+0','+1+0','+1-1','+0+2','+1+2','+1+1'},
[21]={'+0+0','-1+0','-1+1','+0-2','-1-2','-1-1'},
[32]={'+0+0','-1+0','-1-1','+0+2','-1+2','+0-1'},
[23]={'+0+0','+1+0','+1+1','+0-2','+1-2','+0+1'},
[02]={'+0+0','+1+0','-1+0','+0-1','+0+1'},
[20]={'+0+0','-1+0','+1+0','+0+1','+0-1'},
[13]={'+0+0','+0-1','+0+1','+0-2'},
@@ -140,8 +140,8 @@ do
},--Z
false,--S
{
[01]={'+0+0','-1+0','-1+1','+0-2','+1+1','+0+1'},
[10]={'+0+0','+1+0','+1-1','+0+2','-1-1','+0-1'},
[01]={'+0+0','-1+0','-1+1','+0-2','+1+1','+0+1','+0-1'},
[10]={'+0+0','+1+0','+1-1','+0+2','-1-1','+0-1','+0+1'},
[03]={'+0+0','+1+0','+1+1','+0-2','+1-2','+1-1','+0+1'},
[30]={'+0+0','-1+0','-1-1','+0+2','-1+2','+0-1','-1+1'},
[12]={'+0+0','+1+0','+1-1','+1+1','-1+0','+0-1','+0+2','+1+2'},
@@ -204,6 +204,7 @@ do
P.spinLast=2
P.stat.rotate=P.stat.rotate+1
P:freshBlock('move')
C.spinSeq=nil
return
end
end
@@ -304,8 +305,8 @@ do
[10]={'+0+0','+0+1','+1+0','+0-2','+1-2'},
[03]={'+0+0','+0-1','+0+1','+0+2'},
[30]={'+0+0','+0-1','+0+1','+0-2'},
[12]={'+0+0','+0-1','+0+1'},
[21]={'+0+0','+0-1','+0-2'},
[12]={'+0+0','+0-1','+0+1','+0+2'},
[21]={'+0+0','+0-1','+0-2','+0-2'},
[32]={'+0+0','+1+0','-1+0'},
[23]={'+0+0','-1+0','+1+0'},
[02]={'+0+0','-1+1','+1-1'},
@@ -353,8 +354,8 @@ do
[21]={'+0+0','-1+0','-1+1','+0+1','-1+2','+0+2','-1-1','+1+0','+0-2','-1-2'},
[32]={'+0+0','-1+0','-1+1','-1-1','+1+0','+0+2','-1+2','+0-2'},
[23]={'+0+0','+1+0','+1-1','+1+1','-1+0','+0-2','+1-2','+0+2'},
[02]={'+0+0','+0-1','+1-1','-1+0','+2-1'},
[20]={'+0+0','+0+1','-1+1','+1+0','-2+1'},
[02]={'+0+0','+0-1','-1-1','+1-1','-1+0','+2-1'},
[20]={'+0+0','+0+1','+1+1','-1+1','+1+0','-2+1'},
[13]={'+0+0','-1+0','-1-1','+0+1','-1-2'},
[31]={'+0+0','+1+0','+1+1','+0-1','+1+2'},
},--J5
@@ -761,6 +762,68 @@ do
ARS_Z.kickTable[25]=upSet
end
local DRS_weak
do
local centerPos=TABLE.copy(defaultCenterPos)
centerPos[1]={[0]={1,1},{1,0},{1,1},{1,1}}--Z
centerPos[2]={[0]={1,1},{1,0},{1,1},{1,1}}--S
centerPos[3]={[0]={1,1},{1,0},{1,1},{1,1}}--L
centerPos[4]={[0]={1,1},{1,0},{1,1},{1,1}}--J
centerPos[5]={[0]={1,1},{1,0},{1,1},{1,1}}--T
centerPos[7]={[0]={.5,1.5},{1.5,-.5},{.5,1.5},{1.5,.5}}--I
centerPos[10]={[0]={1,1},{1,0},{1,1},{1,0}}--P
centerPos[11]={[0]={1,1},{1,1},{1,1},{1,1}}--Q
centerPos[15]={[0]={1,1},{1,0},{1,1},{1,1}}--U
centerPos[16]={[0]={1,1},{1,1},{1,1},{1,1}}--V
centerPos[19]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}--J5
centerPos[20]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}--L5
centerPos[21]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}--R
centerPos[22]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}--Y
centerPos[23]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}--N
centerPos[24]={[0]={1.5,1.5},{1.5,0.5},{1.5,1.5},{1.5,0.5}}--H
centerPos[26]={[0]={0,1},{0,0},{0,1},{0,0}}--I3
centerPos[28]={[0]={0,1},{0,0},{0,1},{0,0}}--I2
local L={'+0+0','-1+0','+1+0','+0-1','-1-1','+1-1'}
local R={'+0+0','+1+0','-1+0','+0-1','+1-1','-1-1'}
local Z={
[01]=R,[10]=L,[03]=L,[30]=R,
[12]=R,[21]=L,[32]=L,[23]=R,
[02]=R,[20]=L,[13]=L,[31]=R,
}
local S=_reflect(Z)
DRS_weak={
centerTex=GC.DO{10,10,
{'setLW',2},
{'dRect',1,1,8,8},
{'fRect',3,3,4,4},
},
centerPos=centerPos,
kickTable={
Z,S,--Z,S
Z,S,--J,L
Z,--T
noKickSet,--O
Z,--I
Z,S,--Z5,S5
Z,S,--P,Q
Z,S,--F,E
Z,Z,Z,Z,--T5,U,V,W
noKickSet,--X
Z,S,--J5,L5
Z,S,--R,Y
Z,S,--N,H
Z,--I5
Z,Z,--I3,C
Z,Z,--I2,O1
}
}
end
local ASC
do
local L={'+0+0','+1+0','+0-1','+1-1','+0-2','+1-2','+2+0','+2-1','+2-2','-1+0','-1-1','+0+1','+1+1','+2+1','-1-2','-2+0','+0+2','+1+2','+2+2','-2-1','-2-2'}
@@ -934,6 +997,7 @@ local RSlist={
SRS_X=SRS_X,
BiRS=BiRS,
ARS_Z=ARS_Z,
DRS_weak=DRS_weak,
ASC=ASC,
ASC_plus=ASC_plus,
C2=C2,

View File

@@ -1,4 +1,4 @@
--Blackhole
--blockhole
local gc=love.graphics
local gc_clear,gc_replaceTransform=gc.clear,gc.replaceTransform
local gc_setColor,gc_setLineWidth=gc.setColor,gc.setLineWidth
@@ -51,7 +51,7 @@ function back.draw()
gc_draw(S.texture,S.d*cos(S.ang),S.d*sin(S.ang),S.rotate,S.size*.026,nil,15,15)
end
--Blackhole
--blockhole
gc_setColor(.07,.07,.07)
gc_circle('fill',0,0,157)
gc_setLineWidth(6)

View File

@@ -0,0 +1,31 @@
--Secret custom background
local gc_clear,gc_setColor=love.graphics.clear,love.graphics.setColor
local back={}
local image=false
local alpha=.26
local mx,my,k
function back.init()
back.resize()
end
function back.resize()
mx,my=SCR.w*.5,SCR.h*.5
if image then
k=math.max(SCR.w/image:getWidth(),SCR.h/image:getHeight())
end
end
function back.draw()
gc_clear(.1,.1,.1)
if image then
gc_setColor(1,1,1,alpha)
mDraw(image,mx,my,nil,k)
end
end
function back.event(a,img)
if a then alpha=a end
if img then image=img end
back.resize()
end
return back

View File

@@ -12,10 +12,9 @@ local ins,rem=table.insert,table.remove
local back={}
local t
local fan,petal
local petal
function back.init()
t=0
fan=SVG_TITLE_FAN
petal={}
end
function back.update()
@@ -62,7 +61,7 @@ function back.draw()
gc_setLineWidth(6)
gc_setColor(.8,.9,1,.3)
for i=1,8 do gc_polygon('line',fan[i])end
for i=1,#SVG_TITLE_FAN do gc_polygon('line',SVG_TITLE_FAN[i])end
gc_setLineWidth(2)
gc_setColor(1,.5,.7,.3)

View File

@@ -0,0 +1,11 @@
--Customizable grey background
local gc=love.graphics
local back={}
local brightness=.26
function back.draw()
gc.clear(brightness,brightness,brightness)
end
function back.event(b)
brightness=b
end
return back

View File

@@ -44,8 +44,7 @@ local function _ifoverlapAI(f,bk,x,y)
end
end end
end
local discardRow=FREEROW.discard
local getRow=FREEROW.get
local getRow,discardRow=LINE.new,LINE.discard
local function _resetField(f0,f,start)
for _=#f,start,-1 do
discardRow(f[_])

View File

@@ -12,7 +12,7 @@ local baseBot={
function baseBot.update(bot)
local P=bot.P
local keys=bot.keys
if P.control and P.waiting==-1 then
if P.control and P.waiting==0 then
bot.delay=bot.delay-1
if not keys[1]then
if bot.runningThread then

View File

@@ -6,6 +6,8 @@ return{
lock=1e99,
wait=0,
fall=0,
hang=5,
hurry=1e99,
--Control
nextCount=6,
@@ -19,6 +21,7 @@ return{
--Rule
sequence='bag',
lockout=false,
fieldH=20,
heightLimit=1e99,
bufferLimit=1e99,

View File

@@ -1,5 +1,5 @@
return{
dropPiece=function(P)
hook_drop=function(P)
if P.lastPiece.atk>0 then
P:receive(nil,P.lastPiece.atk,0,generateLine(P.holeRND:random(10)))
end

View File

@@ -1,5 +1,5 @@
return{
dropPiece=function(P)
hook_drop=function(P)
if P.lastPiece.atk>0 then
P:receive(nil,P.lastPiece.atk,120,generateLine(P.holeRND:random(10)))
end

View File

@@ -1,5 +1,5 @@
return{
dropPiece=function(P)
hook_drop=function(P)
if P.lastPiece.atk>0 then
P:receive(nil,P.lastPiece.atk,30,generateLine(P.holeRND:random(10)))
end

View File

@@ -1,5 +1,5 @@
return{
dropPiece=function(P)
hook_drop=function(P)
if P.lastPiece.atk>0 then
P:receive(nil,P.lastPiece.atk,60,generateLine(P.holeRND:random(10)))
end

View File

@@ -11,8 +11,8 @@ return{
task=function(P)
local F=P.field
for i=1,24 do
F[i]=FREEROW.get(20)
P.visTime[i]=FREEROW.get(20)
F[i]=LINE.new(20)
P.visTime[i]=LINE.new(20)
for x=4,7 do F[i][x]=0 end
end
if P.holeRND:random()<.6 then

View File

@@ -1,10 +1,10 @@
return{
dropPiece=function(P)
hook_drop=function(P)
if P.lastPiece.row>0 then
for _=1,#P.clearedRow do
local h=#P.field
P.field[h+1]=FREEROW.get(20)
P.visTime[h+1]=FREEROW.get(20)
P.field[h+1]=LINE.new(20)
P.visTime[h+1]=LINE.new(20)
for i=4,7 do P.field[h+1][i]=0 end
end
if P.combo>P.modeData.maxCombo then

View File

@@ -1,12 +1,12 @@
return{
dropPiece=function(P)
hook_drop=function(P)
if P.lastPiece.row==0 then
P:lose()
else
for _=1,P.lastPiece.row do
local h=#P.field
P.field[h+1]=FREEROW.get(20)
P.visTime[h+1]=FREEROW.get(20)
P.field[h+1]=LINE.new(20)
P.visTime[h+1]=LINE.new(20)
for i=4,7 do P.field[h+1][i]=0 end
end
if P.combo>P.modeData.maxCombo then

View File

@@ -6,7 +6,7 @@ return{
mText(TEXTOBJ.atk,63,243)
mText(TEXTOBJ.eff,63,363)
end,
dropPiece=function(P)
hook_drop=function(P)
if P.stat.atk>=100 then
P:win('finish')
end

View File

@@ -1,13 +1,11 @@
return{
dropPiece=function(P)
hook_drop=function(P)
if P.garbageBeneath==0 then
local D=P.modeData
D.finished=D.finished+1
if FIELD[D.finished+1]then
P.waiting=26
for i=#P.field,1,-1 do
FREEROW.discard(P.field[i])
FREEROW.discard(P.visTime[i])
P.field[i],P.visTime[i]=nil
end
setField(P,D.finished+1)

View File

@@ -6,7 +6,7 @@ return{
mStr(r,63,265)
PLY.draw.drawTargetLine(P,r)
end,
dropPiece=function(P)
hook_drop=function(P)
if P.stat.row>=10 then
P:win('finish')
end

View File

@@ -6,7 +6,7 @@ return{
mStr(r,63,265)
PLY.draw.drawTargetLine(P,r)
end,
dropPiece=function(P)
hook_drop=function(P)
if P.stat.row>=100 then
P:win('finish')
end

View File

@@ -6,7 +6,7 @@ return{
mStr(r,63,265)
PLY.draw.drawTargetLine(P,r)
end,
dropPiece=function(P)
hook_drop=function(P)
if P.stat.row>=1000 then
P:win('finish')
end

View File

@@ -6,7 +6,7 @@ return{
mStr(r,63,265)
PLY.draw.drawTargetLine(P,r)
end,
dropPiece=function(P)
hook_drop=function(P)
if P.stat.row>=20 then
P:win('finish')
end

View File

@@ -6,7 +6,7 @@ return{
mStr(r,63,265)
PLY.draw.drawTargetLine(P,r)
end,
dropPiece=function(P)
hook_drop=function(P)
if P.stat.row>=200 then
P:win('finish')
end

View File

@@ -6,7 +6,7 @@ return{
mStr(r,63,265)
PLY.draw.drawTargetLine(P,r)
end,
dropPiece=function(P)
hook_drop=function(P)
if P.stat.row>=40 then
P:win('finish')
end

View File

@@ -6,7 +6,7 @@ return{
mStr(r,63,265)
PLY.draw.drawTargetLine(P,r)
end,
dropPiece=function(P)
hook_drop=function(P)
if P.stat.row>=400 then
P:win('finish')
end

View File

@@ -1,5 +1,5 @@
return{
dropPiece=function(P)
hook_drop=function(P)
if #PLY_ALIVE>1 then
P.control=false
local id1=P.sid

View File

@@ -1,5 +1,5 @@
return{
dropPiece=function(P)
hook_drop=function(P)
if P.stat.piece%7==0 and #PLY_ALIVE>1 then
P.control=false
local id1=P.sid

View File

@@ -1,3 +1,4 @@
local gc_setColor=love.graphics.setColor
return{
das=16,arr=6,
sddas=6,sdarr=6,
@@ -18,12 +19,24 @@ return{
mStr(r<10 and 9 or r<30 and r or("%02x"):format(r*10-300),63,210)
mText(TEXTOBJ.speedLV,63,290)
PLY.draw.drawProgress(P.stat.row,P.modeData.target)
if P.modeData.drought>7 then
if P.modeData.drought<=14 then
gc_setColor(1,1,1,P.modeData.drought/7-1)
else
local gb=P.modeData.drought<=21 and 2-P.modeData.drought/14 or .5
gc_setColor(1,gb,gb)
end
setFont(50)
mStr(P.modeData.drought,63,130)
mDraw(MODES.drought_l.icon,63,200,nil,.5)
end
end,
task=function(P)
P.modeData.target=10
end,
dropPiece=function(P)
hook_drop=function(P)
local D=P.modeData
D.drought=P.lastPiece.id==7 and 0 or D.drought+1
if P.stat.row>=D.target then
if D.target==110 then
P.gameEnv.drop,P.gameEnv.lock=5,5

View File

@@ -1,3 +1,4 @@
local gc_setColor=love.graphics.setColor
return{
das=16,arr=6,
sddas=3,sdarr=3,
@@ -18,11 +19,22 @@ return{
mStr(r<11 and 18 or r<22 and r+8 or("%02x"):format(r*10-220),63,210)
mText(TEXTOBJ.speedLV,63,290)
PLY.draw.drawProgress(P.stat.row,P.modeData.target)
if P.modeData.drought>7 then
if P.modeData.drought<=14 then
gc_setColor(1,1,1,P.modeData.drought/7-1)
else
local gb=P.modeData.drought<=21 and 2-P.modeData.drought/14 or .5
gc_setColor(1,gb,gb)
end
setFont(50)
mStr(P.modeData.drought,63,130)
mDraw(MODES.drought_l.icon,63,200,nil,.5)
end
end,
task=function(P)
P.modeData.target=10
end,
dropPiece=function(P)
hook_drop=function(P)
local D=P.modeData
if P.stat.row>=D.target then
if D.target==110 then

View File

@@ -1,3 +1,4 @@
local gc_setColor=love.graphics.setColor
return{
das=16,arr=6,
sddas=1,sdarr=1,
@@ -18,11 +19,22 @@ return{
mStr(r==1 and 29 or("%02x"):format(r*10-20),63,210)
mText(TEXTOBJ.speedLV,63,290)
PLY.draw.drawProgress(P.stat.row,P.modeData.target)
if P.modeData.drought>7 then
if P.modeData.drought<=14 then
gc_setColor(1,1,1,P.modeData.drought/7-1)
else
local gb=P.modeData.drought<=21 and 2-P.modeData.drought/14 or .5
gc_setColor(1,gb,gb)
end
setFont(50)
mStr(P.modeData.drought,63,130)
mDraw(MODES.drought_l.icon,63,200,nil,.5)
end
end,
task=function(P)
P.modeData.target=10
end,
dropPiece=function(P)
hook_drop=function(P)
local D=P.modeData
if P.stat.row>=D.target then
if D.target==100 then

View File

@@ -0,0 +1,36 @@
local function task_newBoard(P,init)
local targetLine
local F,L={},{1}
--TODO
P:pushNextList(L)
P.control=false
if not init then for _=1,26 do YIELD()end end
P.control=true
P.gameEnv.heightLimit=targetLine or #F
P:pushLineList(F)
end
local function _check(P)
P.gameEnv.heightLimit=P.gameEnv.heightLimit-P.lastPiece.row
if P.gameEnv.heightLimit==0 then
P.modeData.stage=P.modeData.stage+1
if P.modeData.stage>=100 then
P:win('finish')
else
P:newTask(task_newBoard)
end
end
end
return{
sequence='none',
RS="TRS",
pushSpeed=5,
mesDisp=function(P)
setFont(60)
mStr(P.modeData.stage,63,280)
mText(TEXTOBJ.wave,63,350)
end,
hook_drop=_check,
task=function(P)task_newBoard(P,true)P.fieldBeneath=0 end,--Just run one time at first to start first level
}

View File

@@ -3,7 +3,7 @@ return{
setFont(55)
mStr(100-P.stat.dig,63,265)
end,
dropPiece=function(P)
hook_drop=function(P)
for _=1,math.min(10,100-P.stat.dig)-P.garbageBeneath do
P:garbageRise(21,1,P:getHolePos())
end

View File

@@ -3,7 +3,7 @@ return{
setFont(55)
mStr(10-P.stat.dig,63,265)
end,
dropPiece=function(P)
hook_drop=function(P)
if P.stat.dig==10 then
P:win('finish')
end

View File

@@ -3,7 +3,7 @@ return{
setFont(55)
mStr(400-P.stat.dig,63,265)
end,
dropPiece=function(P)
hook_drop=function(P)
for _=1,math.min(10,400-P.stat.dig)-P.garbageBeneath do
P:garbageRise(21,1,P:getHolePos())
end

View File

@@ -3,7 +3,7 @@ return{
setFont(55)
mStr(40-P.stat.dig,63,265)
end,
dropPiece=function(P)
hook_drop=function(P)
for _=1,math.min(10,40-P.stat.dig)-P.garbageBeneath do
P:garbageRise(21,1,P:getHolePos())
end

View File

@@ -11,7 +11,7 @@ return{
task=function(P)
P.modeData.target=10
end,
dropPiece=function(P)
hook_drop=function(P)
local flag
local l=P.lastPiece
if P.combo>1 then flag=true;P:showText("2x",0,-220,40,'flicker',.3)end

View File

@@ -10,7 +10,7 @@ return
task=function(P)
P.modeData.target=50
end,
dropPiece=function(P)
hook_drop=function(P)
if P.stat.row>=P.modeData.target then
if P.modeData.target==50 then
P.gameEnv.drop=.25

View File

@@ -30,7 +30,7 @@ return
task=function(P)
P.modeData.target=10
end,
dropPiece=function(P)
hook_drop=function(P)
if P.stat.row>=P.modeData.target then
if P.modeData.target%300==0 then
P.gameEnv.wait=P.gameEnv.wait-1

View File

@@ -12,7 +12,7 @@ return
task=function(P)
P.modeData.target=10
end,
dropPiece=function(P)
hook_drop=function(P)
if P.stat.row>=P.modeData.target then
if P.modeData.target==200 then
P:win('finish')

View File

@@ -30,7 +30,7 @@ return{
mStr(P.stat.row,63,230)
mStr(P.stat.clears[4],63,340)
end,
dropPiece=function(P)
hook_drop=function(P)
if P.modeData.rankPoint<140-passPoint then--If Less then X
local R=#P.clearedRow
if R>0 then

View File

@@ -8,7 +8,7 @@ return{
mesDisp=function(P)
PLY.draw.drawProgress(P.modeData.pt,P.modeData.target)
end,
dropPiece=function(P)
hook_drop=function(P)
local D=P.modeData
local c=#P.clearedRow

View File

@@ -12,7 +12,7 @@ return{
mesDisp=function(P)
PLY.draw.drawProgress(P.modeData.pt,P.modeData.target)
end,
dropPiece=function(P)
hook_drop=function(P)
local D=P.modeData
local c=#P.clearedRow

View File

@@ -14,7 +14,7 @@ return
task=function(P)
P.modeData.target=10
end,
dropPiece=function(P)
hook_drop=function(P)
if P.stat.row>=P.modeData.target then
if P.modeData.target==200 then
P:win('finish')

View File

@@ -12,7 +12,7 @@ return{
mesDisp=function(P)
PLY.draw.drawProgress(P.modeData.pt,P.modeData.target)
end,
dropPiece=function(P)
hook_drop=function(P)
local D=P.modeData
local c=#P.clearedRow

View File

@@ -13,7 +13,7 @@ return
mesDisp=function(P)
PLY.draw.drawProgress(P.modeData.pt,P.modeData.target)
end,
dropPiece=function(P)
hook_drop=function(P)
local p=P.modeData.pt+P.lastPiece.row
if p>=P.modeData.target then
local ENV=P.gameEnv
@@ -55,8 +55,8 @@ return
P.field[i][P.holeRND:random(10)]=0
end
else
P.field[i]=FREEROW.get(0)
P.visTime[i]=FREEROW.get(30)
P.field[i]=LINE.new(0)
P.visTime[i]=LINE.new(30)
for j=1,10 do
if P.holeRND:random()>.9 then
P.field[i][j]=P.holeRND:random(16)

View File

@@ -5,7 +5,7 @@ return{
mStr(P.stat.pc,63,340)
mText(TEXTOBJ.pc,63,410)
end,
dropPiece=function(P)
hook_drop=function(P)
if P.lastPiece.pc and P.stat.row%4==0 then
P.gameEnv.heightLimit=4
if P.stat.pc%5==0 then

View File

@@ -1,51 +1,54 @@
local pc_drop={50,45,40,35,30,26,22,18,15,12}
local pc_lock={55,50,46,42,39,36,33,31,29,27}
local pc_lock={55,50,46,42,40,38,36,34,32,30}
local pc_fall={18,16,14,12,10,9,8,7,6,5}
local PCbase=require"parts.modes.PCbase"
local PClist=require"parts.modes.PClist"
local function task_PC(P)
if P.frameRun>180 then
P.control=false
for _=1,26 do YIELD()end
P.control=true
end
local base=PCbase[P.modeData.type]
P:pushLineList(base[P.holeRND:random(#base)],P.modeData.symmetry)
local difficulty=P.stat.pc<10 and 4 or 5
local L=PClist[difficulty][P.holeRND:random(#PClist[difficulty])]
local symmetry=P.holeRND:random()>.5
P:pushNextList(L,symmetry)
P.control=false
if P.frameRun>180 then for _=1,26 do YIELD()end end
P.control=true
local base=PCbase[difficulty]
P:pushLineList(base[P.holeRND:random(#base)],symmetry)
end
local function check(P)
local f=P.field
if #f>0 then
if #f+P.stat.row%4>4 then
local function _check(P)
if #P.field>0 then
if #P.field+P.stat.row%4>4 then
P:lose()
end
else
local type=P.stat.pc<10 and 4 or 5
local L=PClist[type][P.holeRND:random(#PClist[type])]
local symmetry=P.holeRND:random()>.5
P.modeData.type=type
P.modeData.symmetry=symmetry
P:pushNextList(L,symmetry)
P.modeData.counter=P.stat.piece==0 and 20 or 0
P:newTask(task_PC)
if P.stat.pc>=100 then
P:win('finish')
else
P:newTask(task_PC)
if P.frameRun<180 then P.fieldBeneath=0 end
local s=P.stat.pc*.25
if math.floor(s)==s and s>0 then
P.gameEnv.drop=pc_drop[s]or 10
P.gameEnv.lock=pc_lock[s]or 25
P.gameEnv.fall=pc_fall[s]or 4
if s==10 then
P:_showText(text.maxspeed,0,-140,100,'appear',.6)
if P.stat.pc%4==0 and P.stat.pc>0 and P.stat.pc<=40 then
local s=P.stat.pc/4
P.gameEnv.drop=pc_drop[s]or 10
P.gameEnv.lock=pc_lock[s]or 25
P.gameEnv.fall=pc_fall[s]or 4
if s==10 then
P:_showText(text.maxspeed,0,-140,100,'appear',.6)
end
end
end
end
end
return{
sequence='none',
RS="SRS",
mesDisp=function(P)
setFont(60)
mStr(P.stat.pc,63,340)
mText(TEXTOBJ.pc,63,410)
mStr(P.stat.pc,63,260)
mText(TEXTOBJ.pc,63,330)
end,
dropPiece=check,
task=check,
hook_drop=_check,
task=_check,--Just run one time at first to start first level
}

View File

@@ -8,35 +8,40 @@ local PCtype={
1,2,3,
}
local function task_PC(P)
local difficulty=PCtype[P.stat.pc+1]or 3
local L=PClist[difficulty][P.holeRND:random(#PClist[difficulty])]
local symmetry=P.holeRND:random()>.5
P:pushNextList(L,symmetry)
P.control=false
for _=1,26 do YIELD()end
if P.frameRun>180 then for _=1,26 do YIELD()end end
P.control=true
local base=PCbase[P.modeData.type]
P:pushLineList(base[P.holeRND:random(#base)],P.modeData.symmetry)
local base=PCbase[difficulty]
P:pushLineList(base[P.holeRND:random(#base)],symmetry)
end
local function check(P)
local r=P.field
if #r>0 then
if #r+P.stat.row%4>4 then
local function _check(P)
if #P.field>0 then
if #P.field+P.stat.row%4>4 then
P:lose()
end
else
local type=PCtype[P.stat.pc+1]or 3
local L=PClist[type][P.holeRND:random(#PClist[type])]
local symmetry=P.holeRND:random()>.5
P.modeData.type=type
P.modeData.symmetry=symmetry
P:pushNextList(L,symmetry)
P.modeData.counter=P.stat.piece==0 and 20 or 0
P:newTask(task_PC)
if P.stat.pc>=60 then
P:win('finish')
else
P:newTask(task_PC)
if P.frameRun<180 then P.fieldBeneath=0 end
end
end
end
return{
sequence='none',
RS="SRS",
mesDisp=function(P)
setFont(60)
mStr(P.stat.pc,63,340)
mText(TEXTOBJ.pc,63,410)
mStr(P.stat.pc,63,260)
mText(TEXTOBJ.pc,63,330)
end,
dropPiece=check,
task=check,
hook_drop=_check,
task=_check,--Just run one time at first to start first level
}

View File

@@ -1,53 +0,0 @@
local gc=love.graphics
local dropSpeed={[0]=40,33,27,20,16,12,11,10,9,8,7,6,5,4,3,3,2,2,1,1}
return{
drop=40,
lock=1e99,
wait=20,
fall=90,
mesDisp=function(P)
PLY.draw.drawProgress(P.stat.row,P.modeData.target)
setFont(30)
mStr(P.modeData.bpm,63,178)
gc.setLineWidth(4)
gc.circle('line',63,200,30)
local beat=P.modeData.counter/P.modeData.beatFrame
gc.setColor(1,1,1,1-beat)
gc.setLineWidth(3)
gc.circle('line',63,200,30+45*beat)
end,
dropPiece=function(P)
if P.stat.row>=P.modeData.target then
if P.modeData.target==200 then
P:win('finish')
else
P.modeData.bpm=40+2*P.modeData.target/10
P.modeData.beatFrame=math.floor(3600/P.modeData.bpm)
P.gameEnv.fall=P.modeData.beatFrame
P.gameEnv.wait=math.max(P.gameEnv.wait-2,0)
P.gameEnv.drop=dropSpeed[P.modeData.target/10]
P.modeData.target=P.modeData.target+10
SFX.play('reach')
end
end
end,
task=function(P)
P.modeData.target=10
P.modeData.bpm=40
P.modeData.beatFrame=90
P.modeData.counter=90
while true do
YIELD()
P.modeData.counter=P.modeData.counter-1
if P.modeData.counter==0 then
P.modeData.counter=P.modeData.beatFrame
SFX.play('click',.3)
P:act_hardDrop()
end
end
end,
}

View File

@@ -1,53 +0,0 @@
local gc=love.graphics
local dropSpeed={[0]=30,26,23,20,17,14,12,10,8,6,5,4,3,2,1,1,.5,.5,.25,.25}
return{
drop=30,
lock=1e99,
wait=10,
fall=60,
mesDisp=function(P)
PLY.draw.drawProgress(P.stat.row,P.modeData.target)
setFont(30)
mStr(P.modeData.bpm,63,178)
gc.setLineWidth(4)
gc.circle('line',63,200,30)
local beat=P.modeData.counter/P.modeData.beatFrame
gc.setColor(1,1,1,1-beat)
gc.setLineWidth(3)
gc.circle('line',63,200,30+45*beat)
end,
dropPiece=function(P)
if P.stat.row>=P.modeData.target then
if P.modeData.target==200 then
P:win('finish')
else
P.modeData.bpm=60+3*P.modeData.target/10
P.modeData.beatFrame=math.floor(3600/P.modeData.bpm)
P.gameEnv.fall=P.modeData.beatFrame
P.gameEnv.wait=math.max(P.gameEnv.wait-1,0)
P.gameEnv.drop=dropSpeed[P.modeData.target/10]
P.modeData.target=P.modeData.target+10
SFX.play('reach')
end
end
end,
task=function(P)
P.modeData.target=10
P.modeData.bpm=60
P.modeData.beatFrame=60
P.modeData.counter=60
while true do
YIELD()
P.modeData.counter=P.modeData.counter-1
if P.modeData.counter==0 then
P.modeData.counter=P.modeData.beatFrame
SFX.play('click',.3)
P:act_hardDrop()
end
end
end,
}

View File

@@ -1,58 +0,0 @@
local gc=love.graphics
return{
drop=.5,
lock=1e99,
wait=5,
fall=30,
mesDisp=function(P)
PLY.draw.drawProgress(P.stat.row,P.modeData.target)
setFont(30)
mStr(P.modeData.bpm,63,178)
gc.setLineWidth(4)
gc.circle('line',63,200,30)
local beat=P.modeData.counter/P.modeData.beatFrame
gc.setColor(1,1,1,1-beat)
gc.setLineWidth(3)
gc.circle('line',63,200,30+45*beat)
end,
dropPiece=function(P)
if P.stat.row>=P.modeData.target then
if P.modeData.target==200 then
P:win('finish')
else
P.modeData.bpm=120+2*P.modeData.target/10
P.modeData.beatFrame=math.floor(3600/P.modeData.bpm)
P.gameEnv.fall=P.modeData.beatFrame
P.gameEnv.wait=math.max(P.gameEnv.wait-1,0)
if P.modeData.target==50 then
P.gameEnv.das=5
P.gameEnv.drop=.25
elseif P.modeData.target==100 then
P.gameEnv.das=4
P:set20G(true)
end
P.modeData.target=P.modeData.target+10
SFX.play('reach')
end
end
end,
task=function(P)
P.modeData.target=10
P.modeData.bpm=120
P.modeData.beatFrame=30
P.modeData.counter=30
while true do
YIELD()
P.modeData.counter=P.modeData.counter-1
if P.modeData.counter==0 then
P.modeData.counter=P.modeData.beatFrame
SFX.play('click',.3)
P:act_hardDrop()
end
end
end,
}

View File

@@ -1,5 +1,24 @@
local gc=love.graphics
local gc_draw,gc_print,gc_setColor=gc.draw,gc.print,gc.setColor
local setFont=setFont
local PLAYERS,PLY_ALIVE=PLAYERS,PLY_ALIVE
return{
mesDisp=function(P)
PLY.draw.drawRoyaleInfo(P)
setFont(35)
mStr(#PLY_ALIVE.."/"..#PLAYERS,63,175)
mStr(P.modeData.ko,80,215)
gc_draw(TEXTOBJ.ko,60-TEXTOBJ.ko:getWidth(),222)
setFont(20)
gc_setColor(1,.5,0,.6)
gc_print(P.badge,103,227)
gc_setColor(.97,.97,.97)
setFont(25)
mStr(text.powerUp[P.strength],63,290)
gc_setColor(1,1,1)
for i=1,P.strength do
gc_draw(IMG.badgeIcon,16*i+6,260)
end
end,
}

View File

@@ -0,0 +1,20 @@
return{
mesDisp=function(P)
setFont(45)
mStr(("%.1f"):format(P.stat.atk),63,270)
mText(TEXTOBJ.atk,63,323)
mStr(("%.2f"):format(P.stat.atk/P.stat.row),63,370)
mText(TEXTOBJ.eff,63,423)
setFont(55)
local r=40-P.stat.row
if r<0 then r=0 end
mStr(r,63,170)
PLY.draw.drawTargetLine(P,r)
end,
hook_drop=function(P)
if P.stat.row>=40 then
P:win('finish')
end
end
}

View File

@@ -36,7 +36,7 @@ return{
end
end
end,
dropPiece=function(P)
hook_drop=function(P)
if P.stat.row>=40 then
P:win('finish')
end

View File

@@ -14,7 +14,7 @@ return{
mStr(r,63,265)
PLY.draw.drawTargetLine(P,r)
end,
dropPiece=function(P)
hook_drop=function(P)
local F=P.field
for y=1,#F do
local l=F[y]

View File

@@ -7,9 +7,9 @@ return{
mText(TEXTOBJ.line,63,350)
PLY.draw.drawMarkLine(P,20,.3,1,1,TIME()%.42<.21 and .95 or .6)
end,
dropPiece=function(P)
if #P.field>20 then
local cc=P:clearFilledLines(P.garbageBeneath+1,#P.field-P.garbageBeneath)
hook_die=function(P)
local cc=P:clearFilledLines(P.garbageBeneath+1,#P.field-P.garbageBeneath)
if cc>0 then
local h=20-cc-P.garbageBeneath
if h>0 then
P:garbageRise(21,h,2e10-1)

View File

@@ -1,22 +0,0 @@
return{
fieldH=21,
fillClear=false,
mesDisp=function(P)
setFont(60)
mStr(P.stat.row,63,280)
mText(TEXTOBJ.line,63,350)
PLY.draw.drawMarkLine(P,18,.3,1,1,TIME()%.42<.21 and .95 or .6)
end,
dropPiece=function(P)
if #P.field>20 then
local cc=P:clearFilledLines(P.garbageBeneath+1,#P.field-P.garbageBeneath)
local h=20-cc-P.garbageBeneath-2
if h>0 then
P:garbageRise(21,h,2e10-1)
if P.garbageBeneath>=20 then
P:lose()
end
end
end
end,
}

View File

@@ -7,9 +7,9 @@ return{
mText(TEXTOBJ.line,63,350)
PLY.draw.drawMarkLine(P,17,.3,1,1,TIME()%.42<.21 and .95 or .6)
end,
dropPiece=function(P)
if #P.field>20 then
local cc=P:clearFilledLines(P.garbageBeneath+1,#P.field-P.garbageBeneath)
hook_die=function(P)
local cc=P:clearFilledLines(P.garbageBeneath+1,#P.field-P.garbageBeneath)
if cc>0 then
local h=20-cc-P.garbageBeneath-3
if h>0 then
P:garbageRise(21,h,2e10-1)

View File

@@ -0,0 +1,37 @@
local waitSpeed={60,59,58,57,56,55,54,52,50,48,46,44,42,40,38,36,34,32,30}
return
{
das=5,arr=1,
drop=0,lock=7,
wait=60,fall=0,
freshLimit=12,
mesDisp=function(P)
PLY.draw.drawProgress(P.stat.row,P.modeData.target)
PLY.draw.drawTargetLine(P,200-P.stat.row)
end,
task=function(P)
P.modeData.target=10
end,
hook_drop=function(P)
if P.stat.row>=P.modeData.target then
if P.modeData.target==200 then
P:win('finish')
else
if P.modeData.target==40 then
BG.set('rainbow')
elseif P.modeData.target==80 then
BG.set('rainbow2')
elseif P.modeData.target==100 then
BG.set('glow')
P.modeData.lock=6
elseif P.modeData.target==120 then
BG.set('lightning')
end
P.gameEnv.wait=waitSpeed[P.modeData.target/10]
P.modeData.target=P.modeData.target+10
SFX.play('reach')
end
end
end
}

View File

@@ -0,0 +1,38 @@
local waitSpeed={30,29,28,27,26,25,24,23,22,21,20,19,18,18,17,17,16,16,15}
return
{
das=4,arr=1,
drop=0,lock=6,
wait=30,fall=0,
freshLimit=12,
mesDisp=function(P)
PLY.draw.drawProgress(P.stat.row,P.modeData.target)
PLY.draw.drawTargetLine(P,200-P.stat.row)
end,
task=function(P)
P.modeData.target=10
end,
hook_drop=function(P)
if P.stat.row>=P.modeData.target then
if P.modeData.target==200 then
P:win('finish')
else
if P.modeData.target==40 then
BG.set('rainbow')
elseif P.modeData.target==80 then
BG.set('rainbow2')
elseif P.modeData.target==100 then
BG.set('glow')
P.modeData.lock=5
BGM.play('secret8th remix')
elseif P.modeData.target==120 then
BG.set('lightning')
end
P.gameEnv.wait=waitSpeed[P.modeData.target/10]
P.modeData.target=P.modeData.target+10
SFX.play('reach')
end
end
end
}

View File

@@ -0,0 +1,38 @@
local waitSpeed={15,15,14,14,13,13,12,12,11,11,10,10,9,9,8,8,7,7,7}
return
{
das=3,arr=1,
drop=0,lock=5,
wait=15,fall=0,
freshLimit=12,
mesDisp=function(P)
PLY.draw.drawProgress(P.stat.row,P.modeData.target)
PLY.draw.drawTargetLine(P,200-P.stat.row)
end,
task=function(P)
P.modeData.target=10
end,
hook_drop=function(P)
if P.stat.row>=P.modeData.target then
if P.modeData.target==200 then
P:win('finish')
else
if P.modeData.target==40 then
BG.set('rainbow')
elseif P.modeData.target==80 then
BG.set('rainbow2')
elseif P.modeData.target==100 then
BG.set('glow')
P.modeData.lock=4
BGM.play('secret7th remix')
elseif P.modeData.target==120 then
BG.set('lightning')
end
P.gameEnv.wait=waitSpeed[P.modeData.target/10]
P.modeData.target=P.modeData.target+10
SFX.play('reach')
end
end
end
}

View File

@@ -4,7 +4,7 @@ return{
mStr(P.stat.clear[7][4],63,250)
mText(TEXTOBJ.techrash,63,315)
end,
dropPiece=function(P)
hook_drop=function(P)
if P.lastPiece.row>0 and P.lastPiece.row<4 then
P:lose()
end

View File

@@ -8,12 +8,12 @@ return{
PLY.draw.applyField(P)
local L=P.modeData.history
for i=1,#L do
gc.setColor(1,.3,.3,.45-i*.04)
gc.setColor(1,.3,.3,.5-i*.04)
gc.rectangle('fill',30*L[i]-30,0,30,600)
end
PLY.draw.cancelField(P)
end,
dropPiece=function(P)
hook_drop=function(P)
local C=P.lastPiece
if C.row>0 then
if C.row==4 then

View File

@@ -4,7 +4,7 @@ return{
mStr(P.modeData.tsd,63,250)
mText(TEXTOBJ.tsd,63,315)
end,
dropPiece=function(P)
hook_drop=function(P)
local C=P.lastPiece
if C.row>0 then
if C.id==5 and C.row==2 and C.spin then

View File

@@ -13,7 +13,7 @@ return{
PLY.draw.cancelField(P)
end
end,
dropPiece=function(P)
hook_drop=function(P)
local C=P.lastPiece
if C.row>0 then
if C.id==5 and C.row==2 and C.spin then

View File

@@ -8,12 +8,12 @@ return{
PLY.draw.applyField(P)
local L=P.modeData.history
for i=1,#L do
gc.setColor(1,.3,.3,.3-i*.05)
gc.setColor(1,.3,.3,.4-i*.05)
gc.rectangle('fill',30*L[i]-30,0,30,600)
end
PLY.draw.cancelField(P)
end,
dropPiece=function(P)
hook_drop=function(P)
local C=P.lastPiece
if C.row>0 then
if C.id==5 and C.row==2 and C.spin then

View File

@@ -1,24 +1,34 @@
local gc=love.graphics
local warnTime={60,90,105,115,116,117,118,119,120}
for i=1,#warnTime do warnTime[i]=warnTime[i]*60 end
return{
mesDisp=function(P)
gc.setLineWidth(2)
gc.rectangle('line',55,110,32,402)
local T=P.stat.frame/60/120
gc.setColor(2*T,2-2*T,.2)
gc.rectangle('fill',56,511,30,(T-1)*400)
gc.setColor(.98,.98,.98,.8)
gc.rectangle('line',0,260,126,80,4)
gc.setColor(.98,.98,.98,.4)
gc.rectangle('fill',0+2,260+2,126-4,80-4,2)
setFont(45)
local t=P.stat.frame/60
local T=("%.1f"):format(120-t)
gc.setColor(COLOR.dH)
mStr(T,65,270)
t=t/120
gc.setColor(1.7*t,2.3-2*t,.3)
mStr(T,63,268)
end,
task=function(P)
P.modeData.stage=1
BGM.seek(0)
P.modeData.section=1
while true do
YIELD()
if P.stat.frame/60>=warnTime[P.modeData.stage]then
if P.modeData.stage<9 then
P.modeData.stage=P.modeData.stage+1
SFX.play('ready',.7+P.modeData.stage*.03)
while P.stat.frame>=warnTime[P.modeData.section]do
if P.modeData.section<9 then
P.modeData.section=P.modeData.section+1
playReadySFX(3,.7+P.modeData.section*.03)
else
SFX.play('start')
playReadySFX(0,.7+P.modeData.section*.03)
P:win('finish')
return
end

Binary file not shown.

Binary file not shown.

View File

@@ -1,37 +0,0 @@
local FREEROW={}
local L={}--Storage
local len=0--Length
function FREEROW.reset(num)
if num<len then
for i=len,num+1,-1 do
L[i]=nil
end
elseif num>len then
for i=len+1,num do
L[i]={0,0,0,0,0,0,0,0,0,0,garbage=false}
end
end
len=num
end
function FREEROW.get(val,ifGarbage)
if len==0 then
for i=1,10 do
L[i]={0,0,0,0,0,0,0,0,0,0,garbage=false}
end
len=len+10
end
local t=L[len]
for i=1,10 do t[i]=val end
t.garbage=ifGarbage==true
L[len]=nil
len=len-1
return t
end
function FREEROW.discard(t)
len=len+1
L[len]=t
end
function FREEROW.getCount()
return len
end
return FREEROW

Some files were not shown because too many files have changed in this diff Show More