Compare commits
60 Commits
v0.17.20
...
Vietnamese
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11fba078bb | ||
|
|
8c04139935 | ||
|
|
d38ff06262 | ||
|
|
45a4b10d11 | ||
|
|
fe12f397cc | ||
|
|
801f67b194 | ||
|
|
e331c8f446 | ||
|
|
51897584a7 | ||
|
|
1cf3d101aa | ||
|
|
1830e849d8 | ||
|
|
e3f246aa00 | ||
|
|
1eb679cf24 | ||
|
|
1963dc9fb9 | ||
|
|
396293c8af | ||
|
|
fbf6e910a3 | ||
|
|
9e4e861c32 | ||
|
|
d0b99a16c9 | ||
|
|
347e81c11c | ||
|
|
6b2a376dfe | ||
|
|
51e0ab7c48 | ||
|
|
87fd26ab89 | ||
|
|
0b1cee99bd | ||
|
|
4768df6867 | ||
|
|
423d502aa4 | ||
|
|
a74e9033b3 | ||
|
|
dc6b7de15f | ||
|
|
74f67d0216 | ||
|
|
d47f073d53 | ||
|
|
7407911914 | ||
|
|
9672a4fe57 | ||
|
|
6c6ff26586 | ||
|
|
ca6f701084 | ||
|
|
5793b7ca38 | ||
|
|
dee6ba95f2 | ||
|
|
67aef1dbe3 | ||
|
|
90f41a20a3 | ||
|
|
5f5dd48ee8 | ||
|
|
a8e0574f44 | ||
|
|
40f148b6b3 | ||
|
|
0eb37666f8 | ||
|
|
b73a653332 | ||
|
|
49f1b747b2 | ||
|
|
2c75f0bc9c | ||
|
|
97e17edfae | ||
|
|
f7e4e47466 | ||
|
|
8779abef9a | ||
|
|
4d1caa7fe0 | ||
|
|
78f3c31db1 | ||
|
|
3c852f17a0 | ||
|
|
8737a00b44 | ||
|
|
fff2c49f2e | ||
|
|
35c19a4d50 | ||
|
|
137e707c63 | ||
|
|
d2e9439e38 | ||
|
|
39cd7e4c1a | ||
|
|
57f2b9541d | ||
|
|
9d4065a05a | ||
|
|
424a3b3bee | ||
|
|
de3e1fcdc7 | ||
|
|
59f390de93 |
16
.github/500stars/README.md
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
# Techmino - 500-star Banner
|
||||
Created by NOT_A_ROBOT
|
||||
13 September, 2024
|
||||
|
||||
**Don't forget to attribute me when using this.**
|
||||
The image already includes sufficient attribution, so if you just don't crop that out, you shouldn't need to explicitly mention them.
|
||||
|
||||
## Attribution
|
||||
Created by NOT_A_ROBOT
|
||||
GitHub logo (on Z-character's screen) by GitHub
|
||||
Background (space stars) originally by MrZ, ported to JS by NOT_A_ROBOT for rendering
|
||||
Block skin (featured in the background) by Scf, slightly modified to make it darker
|
||||
Z-character drawn by 葉枭, designed by MrZ
|
||||
Techmino by MrZ and many contributors
|
||||
|
||||
Techmino is fun! https://github.com/26F-Studio/Techmino
|
||||
BIN
.github/500stars/exported.png
vendored
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
.github/build/extraLibs/Windows_x64/discord-rpc.dll
vendored
Normal file
BIN
.github/build/extraLibs/Windows_x86/discord-rpc.dll
vendored
Normal file
BIN
.github/donate/donate.png
vendored
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
32
.github/workflows/main.yml
vendored
@@ -130,7 +130,7 @@ jobs:
|
||||
prerelease: ${{ startsWith(github.ref, 'refs/tags/pre') }}
|
||||
|
||||
auto-test:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04
|
||||
needs: build-core
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -141,6 +141,25 @@ jobs:
|
||||
with:
|
||||
font-path: ./parts/fonts/proportional.otf
|
||||
language-folder: ./parts/language
|
||||
- name: Download core love package
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
|
||||
- name: Download love
|
||||
shell: bash
|
||||
run: |
|
||||
curl -OL --retry 5 https://github.com/love2d/love/releases/download/11.4/love-11.4-x86_64.AppImage
|
||||
chmod +x love-11.4-x86_64.AppImage
|
||||
- name: Prepare PulseAudio and AppImage
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install pulseaudio pulseaudio-utils pavucontrol alsa-oss alsa-utils libfuse2 -y
|
||||
- name: Run automated test
|
||||
uses: coactions/setup-xvfb@v1
|
||||
with:
|
||||
run: |
|
||||
./love-11.4-x86_64.AppImage ${{ env.CORE_LOVE_PACKAGE_PATH }} --test
|
||||
|
||||
build-android:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -331,6 +350,12 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
rm ./ColdClear/universal/libcold_clear.a
|
||||
- name: Use Xcode 15.3
|
||||
# Xcode 15.4 segfaults
|
||||
# see https://forums.developer.apple.com/forums/thread/757398
|
||||
uses: mobiledevops/xcode-select-version-action@v1
|
||||
with:
|
||||
xcode-select-version: 15.3
|
||||
- name: Build macOS packages
|
||||
id: build-packages
|
||||
uses: love-actions/love-actions-macos-portable@v1
|
||||
@@ -339,6 +364,7 @@ jobs:
|
||||
bundle-id: ${{ steps.process-app-name.outputs.bundle-id }}
|
||||
copyright: "Copyright © 2019-2023 26F-Studio. Some Rights Reserved."
|
||||
icon-path: ./.github/build/macOS/${{ env.BUILD_TYPE }}/icon.icns
|
||||
love-ref: "11.5"
|
||||
love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
||||
libs-path: ./ColdClear/universal/
|
||||
product-name: ${{ steps.process-app-name.outputs.product-name }}
|
||||
@@ -469,8 +495,8 @@ jobs:
|
||||
icon-path: ./.github/build/windows/${{ env.BUILD_TYPE }}/icon.ico
|
||||
rc-path: ./.github/build/windows/${{ env.BUILD_TYPE }}/template.rc
|
||||
love-package: ${{ env.CORE_LOVE_PACKAGE_PATH }}
|
||||
extra-assets-x86: ./ColdClear/x86/CCloader.dll ./ColdClear/x86/cold_clear.dll
|
||||
extra-assets-x64: ./ColdClear/x64/CCloader.dll ./ColdClear/x64/cold_clear.dll
|
||||
extra-assets-x86: ./ColdClear/x86/CCloader.dll ./ColdClear/x86/cold_clear.dll ./.github/build/extraLibs/Windows_x64/discord-rpc.dll
|
||||
extra-assets-x64: ./ColdClear/x64/CCloader.dll ./ColdClear/x64/cold_clear.dll ./.github/build/extraLibs/Windows_x86/discord-rpc.dll
|
||||
product-name: ${{ steps.process-app-name.outputs.product-name }}
|
||||
app-id: ${{ secrets.WINDOWS_APP_ID }}
|
||||
project-website: https://www.studio26f.org/
|
||||
|
||||
1
.gitignore
vendored
@@ -1,5 +1,4 @@
|
||||
.vscode
|
||||
libAndroid
|
||||
*.ini
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
@@ -8,8 +8,6 @@ local path=''
|
||||
|
||||
local type=type
|
||||
local timer=love.timer.getTime
|
||||
local TRD=love.thread.newThread("\n")
|
||||
local TRD_isRunning=TRD.isRunning
|
||||
|
||||
local WS={}
|
||||
local wsList=setmetatable({},{
|
||||
@@ -151,7 +149,7 @@ function WS.update(dt)
|
||||
local time=timer()
|
||||
for name,ws in next,wsList do
|
||||
if ws.real and ws.status~='dead' then
|
||||
if TRD_isRunning(ws.thread) then
|
||||
if ws.thread:isRunning() then
|
||||
if ws.triggerCHN:getCount()==0 then
|
||||
ws.triggerCHN:push(0)
|
||||
end
|
||||
|
||||
@@ -15,6 +15,7 @@ do-- Connect
|
||||
|
||||
SOCK:settimeout(timeout)
|
||||
local res,err=SOCK:connect(host,port)
|
||||
-- print('C0',res,err)
|
||||
assert(res,err)
|
||||
|
||||
-- WebSocket handshake
|
||||
@@ -31,6 +32,7 @@ do-- Connect
|
||||
|
||||
-- First line of HTTP
|
||||
res,err=SOCK:receive('*l')
|
||||
-- print('C',res,err)
|
||||
assert(res,err)
|
||||
local code,ctLen
|
||||
code=res:find(' ')
|
||||
@@ -39,6 +41,7 @@ do-- Connect
|
||||
-- Get body length from headers and remove headers
|
||||
repeat
|
||||
res,err=SOCK:receive('*l')
|
||||
-- print('H',res,err)
|
||||
assert(res,err)
|
||||
if not ctLen and res:find('content-length') then
|
||||
ctLen=tonumber(res:match('%d+')) or 0
|
||||
@@ -53,6 +56,7 @@ do-- Connect
|
||||
-- Content(?)
|
||||
if ctLen then
|
||||
res,err=SOCK:receive(ctLen)
|
||||
-- print('R',res,err)
|
||||
if code~='101' then
|
||||
res=JSON.decode(assert(res,err))
|
||||
error((code or "XXX")..":"..(res and res.reason or "Server Error"))
|
||||
@@ -140,10 +144,10 @@ local readThread=coroutine.wrap(function()
|
||||
assert(res,err)
|
||||
length=shl(byte(res,1),8)+byte(res,2)
|
||||
elseif length==127 then
|
||||
local lenData
|
||||
lenData,err=_receive(SOCK,8)
|
||||
-- 'res' is 'lenData' here
|
||||
res,err=_receive(SOCK,8)
|
||||
assert(res,err)
|
||||
local _,_,_,_,_5,_6,_7,_8=byte(lenData,1,8)
|
||||
local _,_,_,_,_5,_6,_7,_8=byte(res,1,8)
|
||||
length=shl(_5,24)+shl(_6,16)+shl(_7,8)+_8
|
||||
end
|
||||
res,err=_receive(SOCK,length)
|
||||
@@ -162,12 +166,14 @@ local readThread=coroutine.wrap(function()
|
||||
lBuffer=lBuffer..res
|
||||
if fin then
|
||||
CHN_push(readCHN,lBuffer)
|
||||
-- print('M',lBuffer)
|
||||
lBuffer=""
|
||||
end
|
||||
else
|
||||
CHN_push(readCHN,op)
|
||||
if fin then
|
||||
CHN_push(readCHN,res)
|
||||
-- print('S',res)
|
||||
lBuffer=""
|
||||
else
|
||||
lBuffer=res
|
||||
|
||||
@@ -15,6 +15,7 @@ local timer=love.timer.getTime
|
||||
local next=next
|
||||
local floor,ceil=math.floor,math.ceil
|
||||
local max,min=math.max,math.min
|
||||
local match=string.match
|
||||
local sub,ins,rem=string.sub,table.insert,table.remove
|
||||
local xOy=SCR.xOy
|
||||
local FONT=FONT
|
||||
@@ -142,13 +143,21 @@ local button={
|
||||
type='button',
|
||||
mustHaveText=true,
|
||||
ATV=0,-- Activating time(0~8)
|
||||
textAlreadyWrapped=false,-- Text already wrapped? (Managed by :setObject, can be override, this will be true if obj has a '\n')
|
||||
}
|
||||
function button:reset()
|
||||
self.ATV=0
|
||||
end
|
||||
function button:setObject(obj)
|
||||
if type(obj)=='string' or type(obj)=='number' then
|
||||
self.obj=gc.newText(FONT.get(self.font,self.fType),obj)
|
||||
if match(obj,"\n") then
|
||||
self.textAlreadyWrapped=true
|
||||
self.obj=gc.newText(FONT.get(self.font,self.fType))
|
||||
self.obj:addf(obj,self.w-self.edge*2,(self.align=='L' and 'left') or (self.align=='R' and 'right') or 'center')
|
||||
else
|
||||
self.textAlreadyWrapped=false
|
||||
self.obj=gc.newText(FONT.get(self.font,self.fType),obj)
|
||||
end
|
||||
elseif obj then
|
||||
self.obj=obj
|
||||
end
|
||||
@@ -194,16 +203,7 @@ function button:draw()
|
||||
local ox,oy=obj:getWidth()*.5,obj:getHeight()*.5
|
||||
local y0=y+h*.5
|
||||
gc_setColor(1,1,1,.2+ATV*.05)
|
||||
if self.align=='M' then
|
||||
local x0=x+w*.5
|
||||
local kx=obj:type()=='Text' and min(w/ox/2,1) or 1
|
||||
gc_draw(obj,x0-1,y0-1,nil,kx,1,ox,oy)
|
||||
gc_draw(obj,x0-1,y0+1,nil,kx,1,ox,oy)
|
||||
gc_draw(obj,x0+1,y0-1,nil,kx,1,ox,oy)
|
||||
gc_draw(obj,x0+1,y0+1,nil,kx,1,ox,oy)
|
||||
gc_setColor(r*.55,g*.55,b*.55)
|
||||
gc_draw(obj,x0,y0,nil,kx,1,ox,oy)
|
||||
elseif self.align=='L' then
|
||||
if self.align=='L' or self.textAlreadyWrapped then
|
||||
local edge=self.edge
|
||||
gc_draw(obj,x+edge-1,y0-1-oy)
|
||||
gc_draw(obj,x+edge-1,y0+1-oy)
|
||||
@@ -219,6 +219,15 @@ function button:draw()
|
||||
gc_draw(obj,x0+1,y0+1-oy)
|
||||
gc_setColor(r*.55,g*.55,b*.55)
|
||||
gc_draw(obj,x0,y0-oy)
|
||||
else--if self.align=='M' then
|
||||
local x0=x+w*.5
|
||||
local kx=obj:type()=='Text' and min(w/ox/2,1) or 1
|
||||
gc_draw(obj,x0-1,y0-1,nil,kx,1,ox,oy)
|
||||
gc_draw(obj,x0-1,y0+1,nil,kx,1,ox,oy)
|
||||
gc_draw(obj,x0+1,y0-1,nil,kx,1,ox,oy)
|
||||
gc_draw(obj,x0+1,y0+1,nil,kx,1,ox,oy)
|
||||
gc_setColor(r*.55,g*.55,b*.55)
|
||||
gc_draw(obj,x0,y0,nil,kx,1,ox,oy)
|
||||
end
|
||||
end
|
||||
function button:getInfo()
|
||||
@@ -290,13 +299,21 @@ local key={
|
||||
type='key',
|
||||
mustHaveText=true,
|
||||
ATV=0,-- Activating time(0~4)
|
||||
textAlreadyWrapped=false,---See button.setObject (line 146)
|
||||
}
|
||||
function key:reset()
|
||||
self.ATV=0
|
||||
end
|
||||
function key:setObject(obj)
|
||||
if type(obj)=='string' or type(obj)=='number' then
|
||||
self.obj=gc.newText(FONT.get(self.font,self.fType),obj)
|
||||
if match(obj,"\n") then
|
||||
self.textAlreadyWrapped=true
|
||||
self.obj=gc.newText(FONT.get(self.font,self.fType))
|
||||
self.obj:addf(obj,self.w-self.edge*2,(self.align=='L' and 'left') or (self.align=='R' and 'right') or 'center')
|
||||
else
|
||||
self.textAlreadyWrapped=false
|
||||
self.obj=gc.newText(FONT.get(self.font,self.fType),obj)
|
||||
end
|
||||
elseif obj then
|
||||
self.obj=obj
|
||||
end
|
||||
@@ -354,14 +371,15 @@ function key:draw()
|
||||
-- Drawable
|
||||
local obj=self.obj
|
||||
local ox,oy=obj:getWidth()*.5,obj:getHeight()*.5
|
||||
|
||||
gc_setColor(r,g,b)
|
||||
if align=='M' then
|
||||
local kx=obj:type()=='Text' and min(w/ox/2,1) or 1
|
||||
gc_draw(obj,x+w*.5,y+h*.5,nil,kx,1,ox,oy)
|
||||
elseif align=='L' then
|
||||
gc_draw(obj,x+self.edge,y-oy+h*.5)
|
||||
if align=='L' or self.textAlreadyWrapped then
|
||||
gc_draw(obj,x+self.edge,y+h*.5-oy)
|
||||
elseif align=='R' then
|
||||
gc_draw(obj,x+w-self.edge-ox*2,y-oy+h*.5)
|
||||
else--if align=='M' then
|
||||
local kx=obj:type()=='Text' and min(w/ox/2,1) or 1
|
||||
gc_draw(obj,x+w*.5,y+h*.5,nil,kx,1,ox,oy)
|
||||
end
|
||||
end
|
||||
function key:getInfo()
|
||||
@@ -1382,10 +1400,13 @@ function WIDGET.setLang(widgetText)
|
||||
t=W.name or "##"
|
||||
W.color=COLOR.dV
|
||||
end
|
||||
if type(t)=='string' and W.font then
|
||||
t=gc.newText(FONT.get(W.font),t)
|
||||
if type(W.setObject)=='function' then
|
||||
W:setObject(t)
|
||||
elseif type(t)=='string' and W.font then
|
||||
W.obj=gc.newText(FONT.get(W.font or 30),t)
|
||||
else
|
||||
W.obj=t
|
||||
end
|
||||
W.obj=t
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -12,6 +12,8 @@ Lua is free software distributed under the terms of the MIT license. Copyright
|
||||
|
||||
json.lua is copyrighted by rxi. © 2022 rxi.
|
||||
|
||||
discord-rpc.dll is copyrighted by Discord, Inc. © 2017 Discord, Inc.
|
||||
|
||||
IBM Plex is copyrighted by the International Business Machines Corporation. IBM and IBM Plex are trademarks of IBM Corp, registered in many jurisdictions worldwide. IBM Plex is licensed under the SIL Open Font License, Version 1.1.
|
||||
|
||||
|
||||
|
||||
83
main.lua
@@ -294,39 +294,41 @@ IMG.init{
|
||||
},
|
||||
}
|
||||
SKIN.load{
|
||||
{name="crystal_scf", path='media/image/skin/crystal_scf.png'},
|
||||
{name="matte_mrz", path='media/image/skin/matte_mrz.png'},
|
||||
{name="shiny_chno", path='media/image/skin/shiny_chno.png'},
|
||||
{name="contrast_mrz", path='media/image/skin/contrast_mrz.png'},
|
||||
{name="polkadots_scf", path='media/image/skin/polkadots_scf.png'},
|
||||
{name="toy_scf", path='media/image/skin/toy_scf.png'},
|
||||
{name="smooth_mrz", path='media/image/skin/smooth_mrz.png'},
|
||||
{name="simple_scf", path='media/image/skin/simple_scf.png'},
|
||||
{name="glass_scf", path='media/image/skin/glass_scf.png'},
|
||||
{name="penta_scf", path='media/image/skin/penta_scf.png'},
|
||||
{name="bubble_scf", path='media/image/skin/bubble_scf.png'},
|
||||
{name="minoes_scf", path='media/image/skin/minoes_scf.png'},
|
||||
{name="pure_mrz", path='media/image/skin/pure_mrz.png'},
|
||||
{name="bright_scf", path='media/image/skin/bright_scf.png'},
|
||||
{name="glow_mrz", path='media/image/skin/glow_mrz.png'},
|
||||
{name="plastic_mrz", path='media/image/skin/plastic_mrz.png'},
|
||||
{name="paper_mrz", path='media/image/skin/paper_mrz.png'},
|
||||
{name="yinyang_scf", path='media/image/skin/yinyang_scf.png'},
|
||||
{name="cartooncup_earety", path='media/image/skin/cartooncup_earety.png'},
|
||||
{name="jelly_miya", path='media/image/skin/jelly_miya.png'},
|
||||
{name="guidetris_xmiao_lusisi",path='media/image/skin/guidetris_xmiao_lusisi.png'},
|
||||
{name="brick_notypey", path='media/image/skin/brick_notypey.png'},
|
||||
{name="gem_notypey", path='media/image/skin/gem_notypey.png'},
|
||||
{name="classic", path='media/image/skin/classic_unknown.png'},
|
||||
{name="ball_shaw", path='media/image/skin/ball_shaw.png'},
|
||||
{name="retro_notypey", path='media/image/skin/retro_notypey.png'},
|
||||
{name="pixel_chno", path='media/image/skin/pixel_chno.png'},
|
||||
{name="pastel_chno", path='media/image/skin/pastel_chno.png'},
|
||||
{name="letters_chno", path='media/image/skin/letters_chno.png'},
|
||||
{name="kanji_chno", path='media/image/skin/kanji_chno.png'},
|
||||
{name="textbone_mrz", path='media/image/skin/textbone_mrz.png'},
|
||||
{name="coloredbone_mrz", path='media/image/skin/coloredbone_mrz.png'},
|
||||
{name="wtf", path='media/image/skin/wtf_mrz.png'},
|
||||
{name="Arcade (Asriel)", path='media/image/skin/asriel/arcade.png'},
|
||||
{name="Cardboard (Asriel, slimenergy)", path='media/image/skin/asriel/cardboard.png'},
|
||||
{name="Crystal (Scf)", path='media/image/skin/scf/crystal.png'},
|
||||
{name="Matte (MrZ)", path='media/image/skin/mrz/matte.png'},
|
||||
{name="Shiny (CHNO)", path='media/image/skin/chno/shiny.png'},
|
||||
{name="Contrast (MrZ)", path='media/image/skin/mrz/contrast.png'},
|
||||
{name="Polkadots (Scf)", path='media/image/skin/scf/polkadots.png'},
|
||||
{name="Toy (Scf)", path='media/image/skin/scf/toy.png'},
|
||||
{name="Smooth (MrZ)", path='media/image/skin/mrz/smooth.png'},
|
||||
{name="Simple (Scf)", path='media/image/skin/scf/simple.png'},
|
||||
{name="Glass (Scf)", path='media/image/skin/scf/glass.png'},
|
||||
{name="Penta (Scf)", path='media/image/skin/scf/penta.png'},
|
||||
{name="Bubble (Scf)", path='media/image/skin/scf/bubble.png'},
|
||||
{name="Minoes (Scf)", path='media/image/skin/scf/minoes.png'},
|
||||
{name="pure (MrZ)", path='media/image/skin/mrz/pure.png'},
|
||||
{name="bright (Scf)", path='media/image/skin/scf/bright.png'},
|
||||
{name="Glow (MrZ)", path='media/image/skin/mrz/glow.png'},
|
||||
{name="Plastic (MrZ)", path='media/image/skin/mrz/plastic.png'},
|
||||
{name="paper (MrZ)", path='media/image/skin/mrz/paper.png'},
|
||||
{name="Yinyang (Scf)", path='media/image/skin/scf/yinyang.png'},
|
||||
{name="Cartooncup (Earety)", path='media/image/skin/earety/cartooncup.png'},
|
||||
{name="Jelly (Miya)", path='media/image/skin/miya/jelly.png'},
|
||||
{name="guidetris (xmiao, lusisi)",path='media/image/skin/guidetris_xmiao_lusisi.png'},
|
||||
{name="brick (Notypey)", path='media/image/skin/notypey/brick.png'},
|
||||
{name="Gem (Notypey)", path='media/image/skin/notypey/gem.png'},
|
||||
{name="Classic", path='media/image/skin/unknown/classic.png'},
|
||||
{name="Ball (Shaw)", path='media/image/skin/shaw/ball.png'},
|
||||
{name="Retro (Notypey)", path='media/image/skin/notypey/retro.png'},
|
||||
{name="Pixel (CHNO)", path='media/image/skin/chno/pixel.png'},
|
||||
{name="Pastel (CHNO)", path='media/image/skin/chno/pastel.png'},
|
||||
{name="Letters (CHNO)", path='media/image/skin/chno/letters.png'},
|
||||
{name="Kanji (CHNO)", path='media/image/skin/chno/kanji.png'},
|
||||
{name="Textbone (MrZ)", path='media/image/skin/mrz/textbone.png'},
|
||||
{name="Coloredbone (MrZ)", path='media/image/skin/mrz/coloredbone.png'},
|
||||
{name="WTF (MrZ)", path='media/image/skin/mrz/wtf.png'},
|
||||
}
|
||||
|
||||
-- Initialize sound libs
|
||||
@@ -425,7 +427,8 @@ do
|
||||
for _,v in next,SETTING.skin do if v<1 or v>17 then v=17 end end
|
||||
if not RSlist[SETTING.RS] then SETTING.RS='TRS' end
|
||||
if SETTING.ghostType=='greyCell' then SETTING.ghostType='grayCell' end
|
||||
if type(SETTING.skinSet)=='number' then SETTING.skinSet='crystal_scf' end
|
||||
if type(SETTING.skinSet)=='number' then SETTING.skinSet='Crystal (Scf)' end
|
||||
if string.find(SETTING.skinSet,"_") then SETTING.skinSet='Crystal (Scf)' end
|
||||
if not TABLE.find({8,10,13,17,22,29,37,47,62,80,100},SETTING.frameMul) then SETTING.frameMul=100 end
|
||||
if SETTING.cv then SETTING.vocPack,SETTING.cv=SETTING.cv end
|
||||
if type(SETTING.bg)~='string' then SETTING.bg='on' end
|
||||
@@ -592,17 +595,21 @@ end
|
||||
table.sort(REPLAY,function(a,b) return a.fileName>b.fileName end)
|
||||
|
||||
AUTHURL="https://www.studio26f.org/oauth?product=techmino"
|
||||
AUTHHOST="www.studio26f.org"
|
||||
WS.switchHost('www.studio26f.org','80','/techmino/ws/v1')
|
||||
HTTP.setHost("www.studio26f.org")
|
||||
AUTHHOST="www.studio26f.org:8080"
|
||||
WS.switchHost('www.studio26f.org','8081','/techmino/ws/v1')
|
||||
HTTP.setHost("www.studio26f.org:8081")
|
||||
HTTP.setThreadCount(1)
|
||||
|
||||
-- Discord RPC
|
||||
DiscordRPC=require'parts.discordRPC'
|
||||
DiscordRPC.update()
|
||||
|
||||
table.insert(_LOADTIMELIST_,("Load Resources: %.3fs"):format(TIME()-_LOADTIME_))
|
||||
|
||||
for i=1,#_LOADTIMELIST_ do LOG(_LOADTIMELIST_[i]) end
|
||||
|
||||
-- Launch testing task if launch param received
|
||||
if TABLE.find(arg,'-- test') then
|
||||
if TABLE.find(arg,'--test') then
|
||||
TASK.new(function()
|
||||
while not LOADED do coroutine.yield() end
|
||||
|
||||
|
||||
BIN
media/image/skin/asriel/arcade.png
Executable file
|
After Width: | Height: | Size: 20 KiB |
BIN
media/image/skin/asriel/cardboard.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 8.0 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 613 B After Width: | Height: | Size: 613 B |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 91 B After Width: | Height: | Size: 91 B |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 837 B After Width: | Height: | Size: 837 B |
|
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |
@@ -256,54 +256,34 @@ end
|
||||
large value will be encoded as 1xxxxxxx(high)-1xxxxxxx-...-0xxxxxxx(low)
|
||||
|
||||
Example (decoded):
|
||||
6,1, 20,-1, 0,2, 26,-2, 872,4, ...
|
||||
26,1, 42,-1, ...
|
||||
This means:
|
||||
Press key1 at 6f
|
||||
Release key1 at 26f (6+20)
|
||||
Press key2 at the same time (26+0)
|
||||
Release key 2 after 26 frame (26+26)
|
||||
Press key 4 after 872 frame (52+872)
|
||||
Press key1 at 26f
|
||||
Release key1 at 42f
|
||||
...
|
||||
]]
|
||||
function DATA.dumpRecording(list,ptr)
|
||||
local out=""
|
||||
local buffer=""
|
||||
if not ptr then ptr=1 end
|
||||
local prevFrm=list[ptr-2] or 0
|
||||
while list[ptr] do
|
||||
-- Flush buffer
|
||||
if #buffer>10 then
|
||||
if #buffer>26 then
|
||||
out=out..buffer
|
||||
buffer=""
|
||||
end
|
||||
|
||||
-- Encode time
|
||||
local t=list[ptr]-prevFrm
|
||||
prevFrm=list[ptr]
|
||||
buffer=buffer.._encode(t)
|
||||
|
||||
-- Encode event
|
||||
buffer=buffer.._encode(list[ptr+1])
|
||||
|
||||
-- Step
|
||||
ptr=ptr+2
|
||||
buffer=buffer.._encode(list[ptr])
|
||||
ptr=ptr+1
|
||||
end
|
||||
return out..buffer,ptr
|
||||
end
|
||||
function DATA.pumpRecording(str,L)
|
||||
local len=#str
|
||||
local p=1
|
||||
local data
|
||||
|
||||
local curFrm=L[#L-1] or 0
|
||||
while p<=len do
|
||||
local code,event
|
||||
-- Read delta time
|
||||
code,p=_decode(str,p)
|
||||
curFrm=curFrm+code
|
||||
ins(L,curFrm)
|
||||
|
||||
event,p=_decode(str,p)
|
||||
ins(L,event)
|
||||
data,p=_decode(str,p)
|
||||
ins(L,data)
|
||||
end
|
||||
end
|
||||
do-- function DATA.saveReplay()
|
||||
|
||||
327
parts/discordRPC.lua
Normal file
@@ -0,0 +1,327 @@
|
||||
local appId='1288557386700951554'
|
||||
|
||||
local ffi=require"ffi"
|
||||
|
||||
local RPC_C
|
||||
if SYSTEM=='Windows' then
|
||||
local suc
|
||||
suc,RPC_C=pcall(ffi.load,"discord-rpc")
|
||||
if not (suc and RPC_C) then
|
||||
print("Failed to load Discord-RPC lib",RPC_C)
|
||||
MES.new('error',"Failed to load Discord-RPC lib")
|
||||
RPC_C=nil
|
||||
end
|
||||
end
|
||||
|
||||
local RPC
|
||||
if RPC_C then
|
||||
RPC={}
|
||||
ffi.cdef[[
|
||||
typedef struct DiscordRichPresence {
|
||||
const char* state; /* max 128 bytes */
|
||||
const char* details; /* max 128 bytes */
|
||||
int64_t startTimestamp;
|
||||
int64_t endTimestamp;
|
||||
const char* largeImageKey; /* max 32 bytes */
|
||||
const char* largeImageText; /* max 128 bytes */
|
||||
const char* smallImageKey; /* max 32 bytes */
|
||||
const char* smallImageText; /* max 128 bytes */
|
||||
const char* partyId; /* max 128 bytes */
|
||||
int partySize;
|
||||
int partyMax;
|
||||
const char* matchSecret; /* max 128 bytes */
|
||||
const char* joinSecret; /* max 128 bytes */
|
||||
const char* spectateSecret; /* max 128 bytes */
|
||||
int8_t instance;
|
||||
} DiscordRichPresence;
|
||||
|
||||
typedef struct DiscordUser {
|
||||
const char* userId;
|
||||
const char* username;
|
||||
const char* discriminator;
|
||||
const char* avatar;
|
||||
} DiscordUser;
|
||||
|
||||
typedef void (*readyPtr)(const DiscordUser* request);
|
||||
typedef void (*disconnectedPtr)(int errorCode, const char* message);
|
||||
typedef void (*erroredPtr)(int errorCode, const char* message);
|
||||
typedef void (*joinGamePtr)(const char* joinSecret);
|
||||
typedef void (*spectateGamePtr)(const char* spectateSecret);
|
||||
typedef void (*joinRequestPtr)(const DiscordUser* request);
|
||||
|
||||
typedef struct DiscordEventHandlers {
|
||||
readyPtr ready;
|
||||
disconnectedPtr disconnected;
|
||||
erroredPtr errored;
|
||||
joinGamePtr joinGame;
|
||||
spectateGamePtr spectateGame;
|
||||
joinRequestPtr joinRequest;
|
||||
} DiscordEventHandlers;
|
||||
|
||||
void Discord_Initialize(const char* applicationId,
|
||||
DiscordEventHandlers* handlers,
|
||||
int autoRegister,
|
||||
const char* optionalSteamId);
|
||||
void Discord_Shutdown(void);
|
||||
void Discord_RunCallbacks(void);
|
||||
void Discord_UpdatePresence(const DiscordRichPresence* presence);
|
||||
void Discord_ClearPresence(void);
|
||||
void Discord_Respond(const char* userid, int reply);
|
||||
void Discord_UpdateHandlers(DiscordEventHandlers* handlers);
|
||||
]]
|
||||
|
||||
local function unpackDiscordUser(request)
|
||||
return ffi.string(request.userId),ffi.string(request.username),
|
||||
ffi.string(request.discriminator),ffi.string(request.avatar)
|
||||
end
|
||||
|
||||
-- callback proxies
|
||||
-- note: callbacks are not JIT compiled (= SLOW), try to avoid doing performance critical tasks in them
|
||||
-- luajit.org/ext_ffi_semantics.html
|
||||
local ready_proxy=ffi.cast("readyPtr",function(request)
|
||||
if RPC.ready then
|
||||
RPC.ready(unpackDiscordUser(request))
|
||||
end
|
||||
end)
|
||||
|
||||
local disconnected_proxy=ffi.cast("disconnectedPtr",function(errorCode,message)
|
||||
if RPC.disconnected then
|
||||
RPC.disconnected(errorCode,ffi.string(message))
|
||||
end
|
||||
end)
|
||||
|
||||
local errored_proxy=ffi.cast("erroredPtr",function(errorCode,message)
|
||||
if RPC.errored then
|
||||
RPC.errored(errorCode,ffi.string(message))
|
||||
end
|
||||
end)
|
||||
|
||||
local joinGame_proxy=ffi.cast("joinGamePtr",function(joinSecret)
|
||||
if RPC.joinGame then
|
||||
RPC.joinGame(ffi.string(joinSecret))
|
||||
end
|
||||
end)
|
||||
|
||||
local spectateGame_proxy=ffi.cast("spectateGamePtr",function(spectateSecret)
|
||||
if RPC.spectateGame then
|
||||
RPC.spectateGame(ffi.string(spectateSecret))
|
||||
end
|
||||
end)
|
||||
|
||||
local joinRequest_proxy=ffi.cast("joinRequestPtr",function(request)
|
||||
if RPC.joinRequest then
|
||||
RPC.joinRequest(unpackDiscordUser(request))
|
||||
end
|
||||
end)
|
||||
|
||||
-- helpers
|
||||
local function checkArg(arg,argType,argName,func,maybeNil)
|
||||
assert(type(arg)==argType or (maybeNil and arg==nil),
|
||||
string.format("Argument \"%s\" to function \"%s\" has to be of type \"%s\"",
|
||||
argName,func,argType))
|
||||
end
|
||||
|
||||
local function checkStrArg(arg,maxLen,argName,func,maybeNil)
|
||||
if maxLen then
|
||||
assert(type(arg)=="string" and arg:len()<=maxLen or (maybeNil and arg==nil),
|
||||
string.format("Argument \"%s\" of function \"%s\" has to be of type string with maximum length %d",
|
||||
argName,func,maxLen))
|
||||
else
|
||||
checkArg(arg,"string",argName,func,true)
|
||||
end
|
||||
end
|
||||
|
||||
local function checkIntArg(arg,maxBits,argName,func,maybeNil)
|
||||
maxBits=math.min(maxBits or 32,52) -- lua number (double) can only store integers < 2^53
|
||||
local maxVal=2^(maxBits-1) -- assuming signed integers, which, for now, are the only ones in use
|
||||
assert(type(arg)=="number" and math.floor(arg)==arg
|
||||
and arg<maxVal and arg>=-maxVal
|
||||
or (maybeNil and arg==nil),
|
||||
string.format("Argument \"%s\" of function \"%s\" has to be a whole number <= %d",
|
||||
argName,func,maxVal))
|
||||
end
|
||||
|
||||
-- function wrappers
|
||||
function RPC.initialize(applicationId,autoRegister,optionalSteamId)
|
||||
local func="discordRPC.Initialize"
|
||||
checkStrArg(applicationId,nil,"applicationId",func)
|
||||
checkArg(autoRegister,"boolean","autoRegister",func)
|
||||
if optionalSteamId~=nil then
|
||||
checkStrArg(optionalSteamId,nil,"optionalSteamId",func)
|
||||
end
|
||||
|
||||
local eventHandlers=ffi.new("struct DiscordEventHandlers")
|
||||
eventHandlers.ready=ready_proxy
|
||||
eventHandlers.disconnected=disconnected_proxy
|
||||
eventHandlers.errored=errored_proxy
|
||||
eventHandlers.joinGame=joinGame_proxy
|
||||
eventHandlers.spectateGame=spectateGame_proxy
|
||||
eventHandlers.joinRequest=joinRequest_proxy
|
||||
|
||||
RPC_C.Discord_Initialize(applicationId,eventHandlers,
|
||||
autoRegister and 1 or 0,optionalSteamId)
|
||||
end
|
||||
|
||||
function RPC.shutdown()
|
||||
RPC_C.Discord_Shutdown()
|
||||
end
|
||||
|
||||
function RPC.runCallbacks()
|
||||
RPC_C.Discord_RunCallbacks()
|
||||
end
|
||||
-- http://luajit.org/ext_ffi_semantics.html#callback :
|
||||
-- It is not allowed, to let an FFI call into a C function (runCallbacks)
|
||||
-- get JIT-compiled, which in turn calls a callback, calling into Lua again (e.g. discordRPC.ready).
|
||||
-- Usually this attempt is caught by the interpreter first and the C function
|
||||
-- is blacklisted for compilation.
|
||||
-- solution:
|
||||
-- "Then you'll need to manually turn off JIT-compilation with jit.off() for
|
||||
-- the surrounding Lua function that invokes such a message polling function."
|
||||
jit.off(RPC.runCallbacks)
|
||||
|
||||
function RPC.updatePresence(presence)
|
||||
local func="discordRPC.updatePresence"
|
||||
checkArg(presence,"table","presence",func)
|
||||
|
||||
-- -1 for string length because of 0-termination
|
||||
checkStrArg(presence.state,127,"presence.state",func,true)
|
||||
checkStrArg(presence.details,127,"presence.details",func,true)
|
||||
|
||||
checkIntArg(presence.startTimestamp,64,"presence.startTimestamp",func,true)
|
||||
checkIntArg(presence.endTimestamp,64,"presence.endTimestamp",func,true)
|
||||
|
||||
checkStrArg(presence.largeImageKey,31,"presence.largeImageKey",func,true)
|
||||
checkStrArg(presence.largeImageText,127,"presence.largeImageText",func,true)
|
||||
checkStrArg(presence.smallImageKey,31,"presence.smallImageKey",func,true)
|
||||
checkStrArg(presence.smallImageText,127,"presence.smallImageText",func,true)
|
||||
checkStrArg(presence.partyId,127,"presence.partyId",func,true)
|
||||
|
||||
checkIntArg(presence.partySize,32,"presence.partySize",func,true)
|
||||
checkIntArg(presence.partyMax,32,"presence.partyMax",func,true)
|
||||
|
||||
checkStrArg(presence.matchSecret,127,"presence.matchSecret",func,true)
|
||||
checkStrArg(presence.joinSecret,127,"presence.joinSecret",func,true)
|
||||
checkStrArg(presence.spectateSecret,127,"presence.spectateSecret",func,true)
|
||||
|
||||
checkIntArg(presence.instance,8,"presence.instance",func,true)
|
||||
|
||||
local cpresence=ffi.new("struct DiscordRichPresence")
|
||||
cpresence.state=presence.state
|
||||
cpresence.details=presence.details
|
||||
cpresence.startTimestamp=presence.startTimestamp or 0
|
||||
cpresence.endTimestamp=presence.endTimestamp or 0
|
||||
cpresence.largeImageKey=presence.largeImageKey
|
||||
cpresence.largeImageText=presence.largeImageText
|
||||
cpresence.smallImageKey=presence.smallImageKey
|
||||
cpresence.smallImageText=presence.smallImageText
|
||||
cpresence.partyId=presence.partyId
|
||||
cpresence.partySize=presence.partySize or 0
|
||||
cpresence.partyMax=presence.partyMax or 0
|
||||
cpresence.matchSecret=presence.matchSecret
|
||||
cpresence.joinSecret=presence.joinSecret
|
||||
cpresence.spectateSecret=presence.spectateSecret
|
||||
cpresence.instance=presence.instance or 0
|
||||
|
||||
RPC_C.Discord_UpdatePresence(cpresence)
|
||||
end
|
||||
|
||||
function RPC.clearPresence()
|
||||
RPC_C.Discord_ClearPresence()
|
||||
end
|
||||
|
||||
local replyMap={
|
||||
no=0,
|
||||
yes=1,
|
||||
ignore=2,
|
||||
}
|
||||
|
||||
-- maybe let reply take ints too (0, 1, 2) and add constants to the module
|
||||
function RPC.respond(userId,reply)
|
||||
checkStrArg(userId,nil,"userId","discordRPC.respond")
|
||||
assert(replyMap[reply],"Argument 'reply' to discordRPC.respond must be 'yes'|'no'|'ignore'")
|
||||
RPC_C.Discord_Respond(userId,replyMap[reply])
|
||||
end
|
||||
|
||||
-- garbage collection callback
|
||||
RPC.gcDummy=newproxy(true)
|
||||
getmetatable(RPC.gcDummy).__gc=function()
|
||||
RPC.shutdown()
|
||||
ready_proxy:free()
|
||||
disconnected_proxy:free()
|
||||
errored_proxy:free()
|
||||
joinGame_proxy:free()
|
||||
spectateGame_proxy:free()
|
||||
joinRequest_proxy:free()
|
||||
end
|
||||
|
||||
function RPC.ready(userId,username,discriminator,avatar)
|
||||
print(string.format("Discord: ready (%s,%s,%s,%s)",userId,username,discriminator,avatar))
|
||||
end
|
||||
function RPC.disconnected(errorCode,message)
|
||||
print(string.format("Discord: disconnected (%d: %s)",errorCode,message))
|
||||
end
|
||||
function RPC.errored(errorCode,message)
|
||||
print(string.format("Discord: error (%d: %s)",errorCode,message))
|
||||
end
|
||||
function RPC.joinGame(joinSecret)
|
||||
print(string.format("Discord: join (%s)",joinSecret))
|
||||
end
|
||||
function RPC.spectateGame(spectateSecret)
|
||||
print(string.format("Discord: spectate (%s)",spectateSecret))
|
||||
end
|
||||
function RPC.joinRequest(userId,username,discriminator,avatar)
|
||||
print(string.format("Discord: join request (%s,%s,%s,%s)",userId,username,discriminator,avatar))
|
||||
RPC.respond(userId,'yes')
|
||||
end
|
||||
RPC.initialize(appId,true)
|
||||
end
|
||||
|
||||
local MyRPC={
|
||||
C=RPC_C,
|
||||
RPC=RPC,
|
||||
presence={
|
||||
startTimestamp=os.time(),
|
||||
state="Loading...",
|
||||
details="",
|
||||
largeImageKey='',
|
||||
largeImageText="Techmino",
|
||||
smallImageKey='',
|
||||
smallImageText="",
|
||||
},
|
||||
}
|
||||
|
||||
---@class DiscordRPC.presence
|
||||
---@field state? string
|
||||
---@field details? string
|
||||
---@field startTimestamp? number
|
||||
---@field endTimestamp? number
|
||||
---@field largeImageKey? string
|
||||
---@field largeImageText? string
|
||||
---@field smallImageKey? string
|
||||
---@field smallImageText? string
|
||||
---@field partyId? string
|
||||
---@field partySize? number
|
||||
---@field partyMax? number
|
||||
---@field matchSecret? string
|
||||
---@field joinSecret? string
|
||||
---@field spectateSecret? string
|
||||
---@field instance? number
|
||||
|
||||
---@overload fun()
|
||||
---@overload fun(state: DiscordRPC.presence)
|
||||
---@param state string
|
||||
---@param details string
|
||||
function MyRPC.update(state,details)
|
||||
if state then
|
||||
for k,v in next,
|
||||
type(state)=='string'
|
||||
and {state=state,details=details}
|
||||
or state
|
||||
do
|
||||
MyRPC.presence[k]=v
|
||||
end
|
||||
end
|
||||
if RPC then RPC.updatePresence(MyRPC.presence) end
|
||||
end
|
||||
|
||||
return MyRPC
|
||||
@@ -26,7 +26,7 @@ end
|
||||
return {
|
||||
das=16,arr=6,
|
||||
sddas=6,sdarr=6,
|
||||
irs=false,ims=false,
|
||||
logicalIRS=false,logicalIMS=false,
|
||||
drop=6,lock=6,
|
||||
wait=10,fall=25,
|
||||
freshLimit=0,
|
||||
|
||||
@@ -26,7 +26,7 @@ end
|
||||
return {
|
||||
das=16,arr=6,
|
||||
sddas=3,sdarr=3,
|
||||
irs=false,ims=false,
|
||||
logicalIRS=false,logicalIMS=false,
|
||||
drop=3,lock=3,
|
||||
wait=10,fall=25,
|
||||
freshLimit=0,
|
||||
|
||||
@@ -26,7 +26,7 @@ end
|
||||
return {
|
||||
das=16,arr=6,
|
||||
sddas=2,sdarr=2,
|
||||
irs=false,ims=false,
|
||||
logicalIRS=false,logicalIMS=false,
|
||||
drop=2,lock=2,
|
||||
wait=10,fall=25,
|
||||
freshLimit=0,
|
||||
|
||||
@@ -7,7 +7,7 @@ end
|
||||
return {
|
||||
das=16,arr=6,
|
||||
sddas=1,sdarr=1,
|
||||
irs=false,ims=false,
|
||||
logicalIRS=false,logicalIMS=false,
|
||||
drop=1,lock=1,
|
||||
wait=10,fall=25,
|
||||
freshLimit=0,
|
||||
|
||||
@@ -149,7 +149,7 @@ return {
|
||||
keyCancel={10,11,12,14,15,16,17,18,19,20},
|
||||
das=16,arr=1,
|
||||
minsdarr=1,
|
||||
ihs=true,irs=true,ims=false,
|
||||
logicalIRS=true,logicalIHS=true,logicalIMS=false,
|
||||
mesDisp=function(P)
|
||||
local D=P.modeData
|
||||
GC.setColor(1,1,1,1)
|
||||
|
||||
@@ -975,7 +975,7 @@ end
|
||||
do-- function dumpBasicConfig()
|
||||
local gameSetting={
|
||||
-- Tuning
|
||||
'das','arr','dascut','dropcut','sddas','sdarr',
|
||||
'das','arr','dascut','irscut','dropcut','sddas','sdarr',
|
||||
'ihs','irs','ims','RS',
|
||||
|
||||
-- System
|
||||
@@ -1021,7 +1021,7 @@ do-- function resetGameData(args)
|
||||
end
|
||||
local gameSetting={
|
||||
-- Tuning
|
||||
'das','arr','dascut','dropcut','sddas','sdarr',
|
||||
'das','arr','dascut','irscut','dropcut','sddas','sdarr',
|
||||
'ihs','irs','ims','RS',
|
||||
|
||||
-- System
|
||||
@@ -1051,6 +1051,8 @@ do-- function resetGameData(args)
|
||||
GAME.rank=0
|
||||
GAME.warnLVL0=0
|
||||
GAME.warnLVL=0
|
||||
GAME.pauseCount=0
|
||||
GAME.pauseTime=0
|
||||
if args:find'r' then
|
||||
GAME.frameStart=0
|
||||
GAME.recording=false
|
||||
@@ -1058,8 +1060,6 @@ do-- function resetGameData(args)
|
||||
else
|
||||
GAME.frameStart=args:find'n' and 0 or 180-SETTING.reTime*60
|
||||
GAME.seed=seed or math.random(1046101471)
|
||||
GAME.pauseTime=0
|
||||
GAME.pauseCount=0
|
||||
GAME.saved=false
|
||||
GAME.setting=_copyGameSetting()
|
||||
GAME.tasUsed=false
|
||||
@@ -1236,7 +1236,7 @@ do-- function pressKey(k)
|
||||
end
|
||||
do-- SETXXX(k) & ROOMXXX(k)
|
||||
local warnList={
|
||||
'das','arr','dascut','dropcut','sddas','sdarr',
|
||||
'das','arr','dascut','irscut','dropcut','sddas','sdarr',
|
||||
'ihs','irs','ims','RS',
|
||||
'frameMul','highCam',
|
||||
'VKSwitch','VKIcon','VKTrack','VKDodge',
|
||||
|
||||
@@ -605,7 +605,7 @@ do-- Userdata tables
|
||||
SETTING={-- Settings
|
||||
-- Tuning
|
||||
das=10,arr=2,
|
||||
dascut=0,dropcut=0,
|
||||
dascut=0,irscut=6,dropcut=0,
|
||||
sddas=0,sdarr=2,
|
||||
ihs=true,irs=true,ims=true,
|
||||
holdMode='hold',
|
||||
@@ -623,7 +623,7 @@ do-- Userdata tables
|
||||
maxFPS=60,
|
||||
frameMul=100,
|
||||
locale='zh',
|
||||
skinSet='crystal_scf',
|
||||
skinSet='Crystal (Scf)',
|
||||
skin={
|
||||
1,7,11,3,14,4,9,
|
||||
1,7,2,6,10,2,13,5,9,15,4,11,3,12,2,16,8,4,
|
||||
|
||||
@@ -865,6 +865,11 @@ FNNS and {"Support 3",
|
||||
"term",
|
||||
"A special delay applied to DAS when a new block is spawned. When this happens, a small delay is added before the DAS starts timing, so that a piece doesn't start moving immediately when a sideways direction key is pressed.\nOther games may have similar mechanisms, but they may work differently.",
|
||||
},
|
||||
{"IRS cut",
|
||||
"irscut icd",
|
||||
"term",
|
||||
"A special delay applied to IRS when a new block is spawned. When entry delay is disabled, this will delay IRS from being applied, allowing you to release the rotation button in the period to avoid a misdrop.",
|
||||
},
|
||||
{"Auto-lock cut",
|
||||
"autolockcut mdcut",
|
||||
"term",
|
||||
|
||||
@@ -961,6 +961,11 @@ FNNS and {"サポート3",
|
||||
"term",
|
||||
"*Techmino用語*通常、ミノが出現する前にDAS時間以上入力をしているとミノが出現した瞬間に動き出します\nDASカットはこのような現象を減らすためにDAS時間以上入力していても出現時にDASカット分減算する機能です\n他のゲームにも似たようなものがありますが恐らく異なるでしょう",
|
||||
},
|
||||
-- {"IRS cut",
|
||||
-- "irscut icd",
|
||||
-- "term",
|
||||
-- "A special delay applied to IRS when a new block is spawned. When entry delay is disabled, this will delay IRS from being applied, allowing you to release the rotation button in the period to avoid a misdrop.",
|
||||
-- },
|
||||
{"Auto-lock cut(自動設置カット)",
|
||||
"autolockcut mdcut 自動 カット",
|
||||
"term",
|
||||
|
||||
@@ -42,7 +42,7 @@ Bạn muốn đóng góp vào bản dịch? Bạn có thể vào trang dự án
|
||||
05B. Hệ thống xoay gạch: ARS, ASC, ASC+, BRS, BiRS, C2RS, C2sym, NRS, SRS, SRS+, TRS, XRS
|
||||
05C. Hệ thống điều khiển: IRS, IHS, IMS
|
||||
05D. Cách kiểu xáo gạch: Túi 7 gạch, His, EZ-Start, Reverb, C2
|
||||
(và vấn đề Drought của một vài kiểu xáo)
|
||||
(và hiện tượng Drought của một vài kiểu xáo)
|
||||
|
||||
05E. Thông số
|
||||
05E1. Thông số của game:
|
||||
@@ -50,7 +50,7 @@ Bạn muốn đóng góp vào bản dịch? Bạn có thể vào trang dự án
|
||||
- ARE, Line ARE, Death ARE
|
||||
- Lockdown Delay, Spawn & Clear delay
|
||||
05E2. Thông số điều khiển:
|
||||
DAS & ARR, DAS cut, Auto-lock cut, SDF
|
||||
DAS & ARR, DAS cut, Auto-lock cut, IRS cut, SDF
|
||||
05F. Điều khiển
|
||||
05F1. Tốc độ: LPM, PPS, BPM, KPM, KPP
|
||||
05F2. Kỹ thuật: Hypertapping, Rolling, Finesse
|
||||
@@ -272,7 +272,7 @@ Khái niệm về trò chơi Tetris hay trò chơi xếp gạch "hiện đại"
|
||||
Nói chung, một game xếp gạch hiện đại thường sẽ bám sát theo Tetris Design Guideline (Bộ nguyên tắc thiết kế cho một game Tetris). Game nào thỏa mãn đa số các tiêu chí dưới đây có thể được coi là game xếp gạch hiện đại.
|
||||
|
||||
1. Phần có thể nhìn thấy được của bảng có kích thước 10 cột × 20 hàng, cùng với 2 - 3 hàng ẩn ở trên cùng. (Kích thước bảng thực tế ở trong mã nguồn game thường cố định ở 10 cột × 40 hàng).
|
||||
2. Gạch mới xuất hiện ở giữa trên cùng của vùng có thể nhìn thấy (thường là ở hàng 21-22). Mỗi gạch đều có màu sắc và hướng xuất hiện mặc định riêng. Với những gạch có chiều dài lẻ có thể lệch sang trái hoặc phải 1 ô.
|
||||
2. Gạch mới xuất hiện ở giữa trên cùng của vùng có thể nhìn thấy (thường là ở hàng 21-22). Mỗi gạch đều có màu sắc và hướng xuất hiện mặc định riêng. Với những gạch có chiều rộng là số lẻ (Z, S, J, L, T) có thể lệch sang trái hoặc phải 1 ô khi xuất hiện.
|
||||
3. Có một bộ xáo gạch như 7-Bag hay His được thiết kế để giảm hoặc tránh tình trạng Flood hay Drought.
|
||||
4. Có một hệ thống xoay, và cho phép xoay theo ít nhất 2 hướng. Ưu tiên hệ thống xoay SRS hoặc các biến thể tương tự.
|
||||
5. Có hệ thống chờ khóa gạch thích hợp.
|
||||
@@ -286,25 +286,25 @@ Nói chung, một game xếp gạch hiện đại thường sẽ bám sát theo
|
||||
{"Next (Kế / Tiếp)",
|
||||
"nhom05 preview",
|
||||
"term",
|
||||
"Là một hàng dùng để hiện chuỗi gạch sẽ lần lượt xuất hiện. Có một kỹ năng cần thiết đó là lên kế hoạch trước cách đặt các gạch từ hàng NEXT. Số lượng gạch bạn muốn lên kế hoạch là tùy thuộc vào bạn và có thể thay đổi tùy theo chế độ chơi và tình trạng bảng chơi hiện tại của bạn.",
|
||||
"Là một hàng dùng để hiện chuỗi gạch sẽ lần lượt xuất hiện.\n\nCó một kỹ năng cần thiết đó là lên kế hoạch trước cách đặt các gạch từ hàng NEXT. Số lượng gạch bạn muốn lên kế hoạch là tùy thuộc vào bạn và có thể thay đổi tùy theo chế độ chơi và tình trạng bảng chơi hiện tại của bạn.",
|
||||
},
|
||||
{"Hold (Giữ/Trữ/Cất)",
|
||||
"nhom05",
|
||||
"term",
|
||||
"Một chức năng cho phép bạn sử dụng gạch ở trong ô HOLD\n(hoặc gạch đầu tiên ở hàng NEXT nếu bạn chưa cất gạch trước đó)\nvà cất gạch đang rơi vào ô HOLD \n\nBình thường, Hold chỉ có thể được sử dụng 1 lần cho mỗi gạch.\n\nTrên thực tế, việc dùng Hold hay không cũng có ưu nhược của nó.\nNếu không dùng Hold:\n\t- Có thể giảm áp lực cho người chơi khi điều khiển gạch.\n\t- Đồng thời có thể giảm số phím cần nhấn trong game → có thể tăng KPS lên.\nTrên thực tế, đã có nhiều kỷ lục 40L được xác lập mà không cần Hold.\n\nNếu dùng Hold:\n\t- Hold có thể có ích trong nhiều trường hợp khác nhau (ví dụ như khi đang chơi ở tốc độ rơi cao).\n\t- Cho phép người chơi có thể làm được nhiều setup phức tạp hơn mà không đẩy thêm áp lực cho người chơi."
|
||||
"Một chức năng cho phép bạn sử dụng gạch ở trong ô HOLD và cất gạch đang rơi vào ô HOLD (hoặc cất gạch hiện tại vào HOLD và sử dụng gạch ở ô đầu tiên trong hàng NEXT, nếu như chưa có gạch nào trong ô HOLD)\n\nBình thường, Hold chỉ có thể được sử dụng 1 lần cho mỗi gạch.\n\nTrên thực tế, việc dùng Hold hay không cũng có ưu nhược của nó.\nNếu không dùng Hold:\n\t- Có thể giảm áp lực cho người chơi khi điều khiển gạch.\n\t- Đồng thời có thể giảm số phím cần nhấn trong game → có thể tăng KPS lên.\nTrên thực tế, đã có nhiều kỷ lục 40L được xác lập mà không cần Hold.\n\nNếu dùng Hold:\n\t- Hold có thể có ích trong nhiều trường hợp khác nhau (ví dụ như khi đang chơi ở tốc độ rơi cao).\n\t- Cho phép người chơi có thể làm được nhiều setup phức tạp hơn mà không đẩy thêm áp lực cho người chơi."
|
||||
},
|
||||
{"Hold tại chỗ",
|
||||
"nhom05 physicalhold physics inplacehold",
|
||||
"term",
|
||||
"*Chỉ có trên Techmino*\n\"Giữ ngay tại chỗ\".\n\nMột kiểu Hold đặc biệt cho phép gạch được lấy ra từ HOLD sẽ xuất hiện ngay tại vị trí mà gạch hiện tại đang rơi (khác với Hold thông thường khi mà gạch sẽ xuất hiện ở trên cùng của bảng).\nBạn có thể bật chức năng này trong Chế độ tự do.\n\nFun fact: người Trung gọi cái này là \"Physical Hold\"",
|
||||
"*Chỉ có trên Techmino*\n\"Giữ ngay tại chỗ\".\n\nMột kiểu Hold đặc biệt cho phép gạch được lấy ra từ ô HOLD sẽ xuất hiện ngay tại vị trí mà gạch hiện tại đang rơi (khác với Hold thông thường khi mà gạch sẽ xuất hiện ở trên cùng của bảng).\nBạn có thể bật chức năng này trong Chế độ tự do.\n\nFun fact: người Trung gọi cái này là \"Physical Hold\"",
|
||||
},
|
||||
{"Swap (Chuyển)",
|
||||
"nhom05 hold",
|
||||
"term",
|
||||
"Một biến thể khác của \"Hold\". Swap sẽ đổi gạch đang rơi với gạch tiếp theo trong NEXT. Bạn có thể bật chức năng này trong Chế độ tự do.",
|
||||
},
|
||||
{"Topping out",
|
||||
"nhom05 topout toppingout game over",
|
||||
{"Game over",
|
||||
"nhom05 topout toppingout",
|
||||
"term",
|
||||
[[
|
||||
Một tựa game xếp gạch hiện đại thường có 3 điều kiện để "game over":
|
||||
@@ -319,7 +319,7 @@ Techmino mặc định sẽ không kiểm tra điều kiện Lock out và Top ou
|
||||
{"Vùng đệm",
|
||||
"nhom05 invisible buffer zone",
|
||||
"term",
|
||||
"Tên tiếng Anh là \"Buffer Zone\". Chỉ bao gồm các hàng từ hàng 21-40 (nằm ở phía trên vùng nhìn thấy).\n\nTồn tại vùng này là vì sẽ có trường hợp hàng rác sẽ đẩy gạch trong bảng ra khỏi vùng nhìn thấy (dễ thấy nhất là Center 4-Wide).\nNhững ô gạch nào đi ra khỏi vùng nhìn thấy được sẽ đi vào vùng đệm và sẽ xuất hiện lại trong vùng nhìn thấy nếu bạn đã xóa đủ hàng.\n\nVùng đệm thường cao 20 ô (thường là do bảng đã bị cố định kích thước ở trong các dòng code), nhưng có game có vùng này cao vô hạn (ví dụ như trong chính Techmino luôn, khi bảng có thể mở rộng kích thước của nó).\n\nCác bạn có thể tìm hiểu thêm ở mục \"Vùng biến mất\".",
|
||||
"Tên tiếng Anh: \"Buffer Zone\". Chỉ bao gồm các hàng từ hàng 21-40 (nằm ở phía trên vùng nhìn thấy).\n\nTồn tại vùng này là vì sẽ có trường hợp hàng rác sẽ đẩy các hàng bên trên trong bảng ra khỏi vùng nhìn thấy (dễ thấy nhất khi dùng Center 4-Wide).\nNhững ô gạch nào đi ra khỏi vùng nhìn thấy được sẽ đi vào vùng đệm và sẽ xuất hiện lại trong vùng nhìn thấy nếu bạn đã xóa đủ hàng.\n\nVùng đệm thường cao 20 ô (thường là do bảng đã bị cố định kích thước ở trong các dòng code), nhưng có game có vùng này cao vô hạn (ví dụ như trong chính Techmino luôn, khi bảng có thể tự mở rộng kích thước của nó).\n\nCác bạn có thể tìm hiểu thêm ở mục \"Vùng biến mất\".",
|
||||
},
|
||||
{"Vùng biến mất",
|
||||
"nhom05 gone vanish zone",
|
||||
@@ -338,7 +338,7 @@ Tuy nhiên, mỗi game sẽ có cách xử lý khác nhau. Ví dụ:
|
||||
{">A|Gạch",
|
||||
"nhom05a",
|
||||
"",
|
||||
"Bạn có biết?\nGame này hỗ trợ và cho phép bạn chơi với 29 loại gạch khác nhau\n\n1 Mino | 1 Domino | 2 Trimino | 7 Tetromino | 18 Pentomino\n\nMino: gạch 1 ô\nDomino: gạch 2 ô\nTrimino: gạch 3 ô\nTetromino: gạch 4 ô\nPentomino: gạch 5 ô\n\nTechmino có Hexomino (gạch 5 ô) không?\nBây giờ thì chưa nhưng tương lai thì có thể có.",
|
||||
"Bạn có biết? Techmino hỗ trợ và cho phép bạn chơi với 29 loại gạch khác nhau, bao gồm: 1 Mino, 1 Domino, 2 Trimino, 7 Tetromino và 18 Pentomino\n\nMino: gạch 1 ô\nDomino: gạch 2 ô\nTrimino: gạch 3 ô\nTetromino: gạch 4 ô\nPentomino: gạch 5 ô\n\nTechmino có Hexomino (gạch 5 ô) không?\nBây giờ thì chưa nhưng tương lai thì có thể có.",
|
||||
},
|
||||
{"Hình dạng",
|
||||
"nhom05a hình dáng"..tetromino,
|
||||
@@ -450,7 +450,7 @@ So với XRS, BiRS dễ nhớ hơn vì chỉ dùng một bảng wall-kick; nhưn
|
||||
{"SRS",
|
||||
"nhom05b superrotationsystem",
|
||||
"term",
|
||||
"Super Rotation System | Hệ thống xoay Siêu Cấp\n\nHệ thống xoay này được sử dụng rất nhiều trong các game xếp gạch hiện đại và có rất nhiều hệ thống xoay do fan làm ra cũng dựa vào hệ thống này.\nCó tất cả 8 bảng wall-kick trong SRS, tương ứng với hai hướng xoay cho tất cả bốn tư thế của tất cả các gạch (không có trường hợp cho 180°). Nếu gạch đụng tường, đụng đáy, hay đè lên gạch khác sau khi xoay, hệ thống sẽ kiểm tra các vị trí xung quanh. Bạn có thể xem đầy đủ các bảng wall-kick của SRS trên Tetris Wiki.",
|
||||
"Super Rotation System | Hệ thống xoay Siêu Cấp\n\nHệ thống xoay này được sử dụng rất nhiều trong các game xếp gạch hiện đại và có rất nhiều hệ thống xoay do fan làm ra cũng dựa vào hệ thống này.\nCó tất cả 8 bảng wall-kick trong SRS, tương ứng với hai hướng xoay cho tất cả bốn tư thế của tất cả các gạch (không có trường hợp cho 180°). Nếu gạch đụng tường, đụng đáy, hay đè lên gạch khác sau khi xoay, hệ thống sẽ kiểm tra các vị trí xung quanh.\n\nBạn có thể xem đầy đủ các bảng wall-kick của SRS trên Tetris Wiki.",
|
||||
},
|
||||
{"SRS+",
|
||||
"nhom05b srsplus superrotationsystemplus",
|
||||
@@ -607,12 +607,12 @@ Xem mục tiếp theo để biết thêm.
|
||||
{"20G",
|
||||
"nhom05e1 trọng lực; ngay lập tức; gravity instantly",
|
||||
"term",
|
||||
"Tốc độ tối đa trong các game xếp gạch hiện đại.\n\nMặc dù nhìn qua thuật ngữ này thể hiện tốc độ rơi là 20 hàng / khung hình, nhưng thật ra chúng được dùng để chỉ tốc độ vô tận.\n\nHơn nữa, trong các chế độ 20G, game sẽ ưu tiên di chuyển gạch xuống đáy hơn là bất cứ thao tác di chuyển nào từ người chơi.\nLấy ví dụ: ngay cả khi ARR được đặt là 0, gạch vẫn cứ di chuyển một mạch xuống phía dưới một cách hồn nhiên giống như người chơi chưa nhấn gì.\nViệc này gây khó cho người chơi khi họ muốn gạch leo ra khỏi hố hoặc nhảy ra khỏi lỗ trong một số tình huống.",
|
||||
"Tốc độ tối đa trong các game xếp gạch hiện đại.\n\nMặc dù nhìn qua thuật ngữ này thể hiện tốc độ rơi là 20 hàng / khung hình, nhưng thật ra chúng được dùng để chỉ tốc độ vô tận.\n\nHơn nữa, trong các chế độ 20G, game sẽ ưu tiên di chuyển gạch xuống đáy hơn là bất cứ thao tác di chuyển nào từ người chơi.\nVà ngay cả khi ARR được đặt là 0, gạch vẫn cứ di chuyển một mạch xuống phía dưới một cách hồn nhiên giống như người chơi chưa nhấn gì, trước khi di chuyển theo thao tác của người chơi.\n\nViệc này gây khó khăn cho người chơi khi họ muốn gạch leo ra khỏi hố hoặc nhảy ra khỏi lỗ trong một số tình huống.",
|
||||
},
|
||||
{"Lockdown Delay",
|
||||
"nhom05e1 lockdelay lockdowndelay lockdowntimer ld; thời gian chờ khóa gạch",
|
||||
"term",
|
||||
"Thời gian chờ khóa gạch, viết tắt là LD.\nĐây là khoảng thời gian ngay sau khi gạch chạm đất và trước khi gạch bị khóa (không thể điều khiển được nữa).\n\nTrong các game xếp gạch cổ điển, khoảng thời gian chờ này = khoảng thời gian gạch cần có để di chuyển xuống 1 ô, và không có cơ chế nào để trì hoãn việc khóa gạch.\n\nTrong các game xếp gạch hiện đại, thời gian chờ được thong thả hơn, và trong game thường có cơ chế trì hoãn việc khóa gạch, trong đó bạn có thể di chuyển hoặc xoay gạch để đặt lại thời gian chờ (tối đa 15 lần trong hầu hết các game).",
|
||||
"Thời gian chờ khóa gạch, viết tắt là LD.\nGame sẽ chờ một khoảng thời gian, trước khi game khóa gạch (tức là gạch không thể điều khiển được nữa), bắt đầu tính từ khi gạch vừa chạm đất.\n\nTrong các game xếp gạch cổ điển, khoảng thời gian chờ này CHÍNH LÀ khoảng thời gian gạch cần có để di chuyển xuống 1 ô, và không có cơ chế nào để trì hoãn việc khóa gạch.\n\nTrong các game xếp gạch hiện đại, thời gian chờ được tính riêng và thoải mái hơn. Đi kèm với thời gian chờ dài hơn là cơ chế hoãn thời điểm khóa gạch, trong đó bạn có thể di chuyển hoặc xoay gạch bắt game chờ thêm một lúc nữa trước khi khóa gạch; nói theo cách khác, là đặt lại thời gian chờ (tối đa 15 lần trong hầu hết các game).",
|
||||
},
|
||||
{"Spawn&ClearDelay",
|
||||
"nhom05e1 spawndelay cleardelay; thời gian chờ gạch sinh ra; thời gian chờ xóa hàng",
|
||||
@@ -622,7 +622,7 @@ Xem mục tiếp theo để biết thêm.
|
||||
{"ARE",
|
||||
"nhom05e1 spawn appearance delay",
|
||||
"term",
|
||||
"Thời gian chờ xuất hiện gạch mới\nHay còn được biết với tên: Appearance Delay và Entry Delay.\n\n\"ARE\" chỉ khoảng thời gian sau khi gạch bị khóa và trước khi gạch mới xuất hiện\n\nP/s: Từ \"ARE\" không phải là từ viết tắt hay hay là một dạng của \"be\" trong tiếng Anh; nó bắt nguồn từ <あれ> (a-re) trong tiếng Nhật, có nghĩa là \"nó\" hoặc \"cái đó\" / \"cái kia\" / \"cái ấy\".",
|
||||
"Thời gian chờ xuất hiện gạch mới\nHay còn được biết với tên: Appearance Delay và Entry Delay.\n\n\"ARE\" chỉ khoảng thời gian sau khi gạch bị khóa và trước khi gạch mới xuất hiện\n\nP/s: Từ \"ARE\" không phải là từ viết tắt hay hay là một dạng của động từ \"be\" trong tiếng Anh; nó bắt nguồn từ <あれ> (a-re) trong tiếng Nhật, có nghĩa là \"nó\" hoặc \"cái đó\" / \"cái kia\" / \"cái ấy\".",
|
||||
},
|
||||
{"Line ARE",
|
||||
"nhom05e1 appearance delay",
|
||||
@@ -632,7 +632,7 @@ Xem mục tiếp theo để biết thêm.
|
||||
{"Death ARE",
|
||||
"nhom05e1 die delay",
|
||||
"term",
|
||||
"Một cơ chế đặc biệt cho phép tránh game over trong một số trường hợp.\n\nDeath ARE sẽ được kích hoạt khi có một viên gạch chặn ngay tại vị trí xuất hiện của gạch mới (dẫn tới hiện tượng block out)\nKhi kích hoạt, spawn ARE sẽ được cộng với một khoảng thời gian bổ sung để cho phép người chơi dùng IRS, IHS hoặc IMS.\n\nÝ tưởng về cơ chế này được đề xuất lần đầu bởi @NOT_A_ROBOT.",
|
||||
"Một cơ chế đặc biệt cho phép tránh game over trong một số trường hợp.\n\nDeath ARE sẽ được kích hoạt khi có một viên gạch chặn ngay tại vị trí xuất hiện của gạch mới (dẫn tới hiện tượng block out)\nKhi kích hoạt, spawn ARE sẽ được cộng với Death ARE để cho phép người chơi dùng IRS, IHS hoặc IMS.\n\nÝ tưởng về cơ chế này được đề xuất lần đầu bởi @NOT_A_ROBOT.",
|
||||
},
|
||||
{">E2|Thg số đ.khiển",
|
||||
"nhom05e2",
|
||||
@@ -647,12 +647,17 @@ Xem mục tiếp theo để biết thêm.
|
||||
{"DAS & ARR",
|
||||
"nhom05e2 das và arr delayedautoshift autorepeatrate",
|
||||
"term",
|
||||
"DAS, hay Delayed Auto-shift, chỉ khoảng thời gian sau khi gạch di chuyển sang một hướng đã chọn 1 ô cho đến truớc khi gạch di chuển một cách tự động.\n\nARR, hay Auto-Repeat Rate, chỉ khoảng cách thời gian giữ 2 lần di chuyển sang 1 ô trong lúc gạch đang tự động di chuyển.\n\nDAS và ARR được tính bằng f (khung hình) (¹/₆₀ ở 60FPS). 1ms = 16²/₃ khung hình.",
|
||||
"DAS, hay Delayed Auto-shift, đây là khoảng thời gian ngay sau khi gạch đã di chuyển sang 1 ô và gạch đang đợi thời điểm gạch có thể bắt đầu quá trình di chuyển tự động.\n\nARR, hay Auto-Repeat Rate, chỉ khoảng cách thời gian giữa 2 lần di chuyển tự động 1 ô khi gạch đang trong quá trình di chuyển tự động.\n\nDAS và ARR được tính bằng f (khung hình) (¹/₆₀ ở 60FPS). 1ms = 16²/₃ khung hình.",
|
||||
},
|
||||
{"DAS cut",
|
||||
"nhom05e2 dascut dcd",
|
||||
"term",
|
||||
"Cơ chế đặc biệt sẽ được kích hoạt khi gạch mới xuất hiện. Khi kích hoạt, cơ chế này sẽ tăng DAS lên một chút để gạch không tự di chuyển ngay khi đang có phím được giữ.\n\nCác game khác có thể có tính năng tương tự nhưng cách hoạt động có thể khác nhau.",
|
||||
"Là cơ chế đặc biệt sẽ được kích hoạt khi gạch mới xuất hiện. Khi kích hoạt, cơ chế này sẽ tăng DAS lên một chút để gạch không tự di chuyển ngay khi đang có phím được giữ.\n\nCác game khác có thể có tính năng tương tự nhưng cách hoạt động có thể khác nhau.",
|
||||
},
|
||||
{"IRS cut",
|
||||
"irscut icd",
|
||||
"term",
|
||||
"Là cơ chế đặc biệt sẽ được kích hoạt khi gạch mới xuất hiện nhưng không có entry delay. Khi kích hoạt, game sẽ hoãn việc kích IRS một lúc để bạn có thời gian nhả phím xoay sau khi thả gạch xong.",
|
||||
},
|
||||
{"Auto-lock cut",
|
||||
"nhom05e2 autolockcut",
|
||||
@@ -697,7 +702,7 @@ Xem mục tiếp theo để biết thêm.
|
||||
{"KPP",
|
||||
"nhom05f1 số lần nhấn mỗi gạch; số phím mỗi gạch",
|
||||
"term",
|
||||
"Keypresses per piece | Số lần nhấn mỗi viên gạch\nPhản ánh mức độ hiệu quả việc điều khiển gạch.\nCó thể giảm con số này bằng cách học Finesse",
|
||||
"Keypresses per piece | Số lần nhấn mỗi viên gạch\nPhản ánh mức độ hiệu quả việc điều khiển gạch.\n\nCó thể giảm con số này bằng cách học Finesse",
|
||||
},
|
||||
{">F2|K.th. đ.khiển",
|
||||
"nhom05f2",
|
||||
@@ -708,9 +713,9 @@ Xem mục tiếp theo để biết thêm.
|
||||
"nhom05f2 finesse lỗi di chuyển",
|
||||
"term",
|
||||
[[
|
||||
Một kỹ thuật di chuyển gạch vào vị trí mong muốn với chuỗi phím ngắn nhất có thể, giúp tiết kiệm thời gian và giảm khả năng misdrop.
|
||||
Là kỹ thuật điều khiển gạch nhanh nhất với chuỗi phím ngắn nhất có thể nhưng vẫn đảm bảo chính xác, giúp tiết kiệm thời gian và giảm khả năng misdrop.
|
||||
|
||||
Đây là một kỹ năng quan trọng nên bạn hãy học Finesse sớm nhất có thể. Bạn có thể thấy khá nhiều video hướng dẫn trên Youtube cũng như các trang hướng dẫn với hình minh họa trên Google. Hãy bắt đầu từ thứ cơ bản nhất, rồi luyện tập dần để tăng độ chính xác lên. Hãy nhớ ưu tiên chính xác hơn là tốc độ nhé.
|
||||
Đây là một kỹ năng quan trọng nên bạn hãy học Finesse sớm nhất có thể. Bạn có thể thấy nhiều video hướng dẫn trên Youtube cũng như các trang hướng dẫn với hình minh họa trên Google. Hãy bắt đầu từ thứ cơ bản nhất, rồi luyện tập dần để tăng độ chính xác lên. Hãy nhớ ưu tiên chính xác hơn là tốc độ nhé.
|
||||
|
||||
Bạn sẽ không bị mất Finesse khi bạn nhét gạch hay thực hiện Spin vì Techmino chỉ kiểm tra những vị trí không yêu cầu soft drop
|
||||
|
||||
@@ -729,7 +734,7 @@ Lưu ý:
|
||||
{"Hypertapping",
|
||||
"nhom05f2 hypertapper nhấn liên tục",
|
||||
"term",
|
||||
"Hypertapping (Nhấn liên tục)\n\nĐề cập tới một kỹ năng là khi bạn rung tay liên tục thay vì giữ phím.\n\nTrong các game xếp gạch cổ điển, thông số DAS rất cao và không thể điều chỉnh được, dẫn tới nhấn nút liên tục sẽ nhanh hơn so với giữ phím.\nBây giờ thì không cần vì các game xếp gạch hiện đại đã có DAS và ARR có thể điều chỉnh được (nếu có chăng không điều chỉnh được thì DAS cũng đã thấp hơn nhiều so với ngày trước)\n\nNhững người dùng kỹ năng này được gọi là \"hypertapper\"",
|
||||
"Hypertapping (Nhấn liên tục)\n\nĐề cập tới một kỹ năng là khi bạn rung tay liên tục thay vì giữ phím.\n\nTrong các game xếp gạch cổ điển, thông số DAS rất cao và không thể điều chỉnh được, dẫn tới nhấn nút liên tục sẽ nhanh hơn so với giữ phím.\nBây giờ thì không cần vì các game xếp gạch hiện đại đã có DAS và ARR có thể điều chỉnh được (nếu có chăng không điều chỉnh được thì DAS cũng đã thấp hơn nhiều so với ngày trước).\n\nNhững người dùng kỹ năng này được gọi là \"hypertapper\"",
|
||||
},
|
||||
{"Rolling",
|
||||
"nhom05f2",
|
||||
@@ -811,7 +816,7 @@ Trong hầu hết các game, tấn công và phòng thủ là tương đương n
|
||||
{"'Debt'",
|
||||
"nhom05g debt owe",
|
||||
"term",
|
||||
"Một thuật ngữ hay được sử dụng trong cộng đồng Tetris Trung Quốc.\n\n\"Debt\" đề cập đến tình huống mà bạn chỉ có thể tấn công KHI và CHỈ KHI setup được hoàn thành. Nên, khi đang làm một hoặc nhiều debt liên tiếp, người chơi bắt buộc phải để ý tới đối thủ để đảm bảo an toàn; còn không, bạn có thể bị bón hành sấp mặt.\n\nThuật ngữ này hay được sử dụng để diễn tả một số setup như TST tower.",
|
||||
"Một thuật ngữ hay được sử dụng trong cộng đồng Tetris Trung Quốc.\n\n\"Debt\" đề cập đến tình huống mà bạn chỉ có thể tấn công KHI và CHỈ KHI setup được hoàn thành. Nên, khi đang làm một hoặc nhiều debt liên tiếp, người chơi bắt buộc phải để ý tới đối thủ để đảm bảo an toàn; còn không, người chơi đó có thể bị bón hành sấp mặt.\n\nThuật ngữ này hay được sử dụng để diễn tả một số setup như TST tower.",
|
||||
},
|
||||
{"Passthrough",
|
||||
"nhom05g pingthrough",
|
||||
@@ -826,17 +831,17 @@ Trong hầu hết các game, tấn công và phòng thủ là tương đương n
|
||||
{">H|Mis-action",
|
||||
"nhom05h misaction misdrop mishold",
|
||||
"",
|
||||
"Misdrop: Vô tình thả rơi / đặt gạch vào nơi không mong muốn.\nMishold: Vô tình nhấn nhầm phím Hold. Việc này có thể dẫn đến việc dùng một viên gạch không mong muốn.\n\nCả misdrop và mishold có thể làm bạn mất cơ hội để làm PC"
|
||||
"Misdrop: Vô tình thả rơi / đặt gạch vào nơi không mong muốn.\nMishold: Vô tình nhấn nhầm phím Hold. Việc này có thể dẫn đến việc dùng một viên gạch không mong muốn.\n\nCả misdrop và mishold có thể làm bạn mất cơ hội để làm PC."
|
||||
},
|
||||
{">I|Spin",
|
||||
"nhom05i",
|
||||
"",
|
||||
"(Ở trong một số game)\n\nXoay gạch để di chuyển tới một vị trí mà bình thường sẽ không tiếp cận được. Ở một số game, thao tác này sẽ gửi thêm hàng rác hoặc là tăng thêm điểm. Mỗi game sẽ có cách kiểm tra Spin khác nhau."
|
||||
"(Ở nhiều game, đa số các game cổ điển không có cái này)\n\nXoay gạch để di chuyển tới một vị trí mà bình thường sẽ không tiếp cận được. Ở một số game, thao tác này sẽ gửi thêm hàng rác hoặc là tăng thêm điểm. Mỗi game sẽ có cách kiểm tra Spin khác nhau."
|
||||
},
|
||||
{"Mini",
|
||||
"nhom05i",
|
||||
"term",
|
||||
"Một kiểu spin (được cho là) dễ làm hơn so với spin thông thường (vì trong một số game cũ, chúng được gọi là \"Ez T-spin\").\nLượng điểm bổ sung và hàng rác đều ít hơn so với spin thông thường.\n\nMỗi game sẽ có các quy tắc khác nhau để kiểm tra và chúng có thể không trực quan.\nNhưng bạn chỉ cần nhớ mấy cái bố cục làm Mini-spin là được!",
|
||||
"Một kiểu spin (được cho là) dễ làm hơn so với spin thông thường (vì trong một số game cũ, chúng được gọi là \"Ez T-spin\").\nLượng điểm bổ sung và hàng rác đều ít hơn so với spin thông thường.\n\nMỗi game sẽ có các quy tắc khác nhau để kiểm tra và chúng có thể không trực quan.\nNhưng bạn chỉ cần nhớ mấy cách làm Mini-spin là được!",
|
||||
},
|
||||
{"All-spin",
|
||||
"nhom05i allspin",
|
||||
@@ -846,12 +851,12 @@ Trong hầu hết các game, tấn công và phòng thủ là tương đương n
|
||||
{"T-spin",
|
||||
"nhom05i tspin",
|
||||
"term",
|
||||
"Spin được thực hiện bởi Tetromino T.\n\nT-spin chủ yếu được phát hiện bởi \"quy luật 3 góc\".\nTức là, nếu 3 trong 4 góc của một hình chữ nhật (có tâm là tâm xoay của gạch T) bị đè bởi bất kỳ gạch nào, thì spin đó được tính là T-spin.\n\nNgoài quy tắc đó ra thì còn có một số quy tắc để phát hiện T-spin và phân biệt giữa T-spin và Mini T-spin.",
|
||||
"Spin được thực hiện bởi Tetromino T.\n\nT-spin chủ yếu được phát hiện bởi \"quy luật 3 góc\": nếu 3 trong 4 góc của hình vuông ngoại tiếp gạch T bị đè bởi bất kỳ gạch nào, thì spin đó được tính là T-spin.\n\nNgoài quy tắc đó ra thì còn có một số quy tắc để phát hiện T-spin và phân biệt giữa T-spin và Mini T-spin.",
|
||||
},
|
||||
{"O-Spin",
|
||||
"nhom05i ospin",
|
||||
"term",
|
||||
"Gạch O vốn dĩ \"tròn\", không đổi hình dạng khi xoay ở bất cứ hướng nào, nên nó không thể \"đá\" được. Do đó gạch O không tài nào leo ra khỏi \"lỗ\" hoặc \"hố\" nếu bị kẹt. Từ việc này, có một người đã làm một cái video fake cách làm O-spin trong Tetris 99 và Tetris Friends\n\nHiện tại có 2 hệ thống xoay hỗ trợ O-spin:\n\tXRS cho phép gạch O có thể \"teleport\" tới một cái lỗ.\n\tTRS cho phép gạch O \"teleport\" và \"biến hình\"",
|
||||
"Gạch O vốn dĩ \"tròn\", không đổi hình dạng khi xoay ở bất cứ hướng nào, nên nó không thể \"đá\" được. Do đó gạch O không tài nào leo ra khỏi \"lỗ\" hoặc \"hố\" nếu bị kẹt. Lợi dụng việc này, có người đã làm video fake cách làm O-spin trong Tetris 99 và Tetris Friends\n\nHiện tại có 2 hệ thống xoay hỗ trợ O-spin:\n\tXRS cho phép gạch O có thể \"teleport\" tới một cái lỗ.\n\tTRS cho phép gạch O \"teleport\" và \"biến hình\"",
|
||||
},
|
||||
{"Fin, Neo, Iso",
|
||||
"nhom05i fin neo iso",
|
||||
@@ -903,7 +908,7 @@ Trong hầu hết các game, tấn công và phòng thủ là tương đương n
|
||||
{"Back to Back",
|
||||
"nhom05j b2b btb backtoback",
|
||||
"term",
|
||||
"Hay còn gọi là B2B. Xóa 2 hoặc nhiều lần xóa theo kiểu nâng cao (như Tetris hay Spin) liên tiếp (nhưng không được kiểu xóa bình thường giữa chừng).\nKhông như combo, Back To Back sẽ không bị mất khi đặt gạch.\n\nỞ Techmino, B2B được tính bằng thanh năng lượng, chứ không tính theo số lần xóa kiểu đặc biệt.\nCũng trong Techmino, nhiều B2B liên tiếp được tính là Back-to-back-to-back (B3B) (xem mục B2B2B để biết thêm).\n\nTechmino cũng tính cả PC và HPC liên tiếp là B2B và B3B",
|
||||
"Hay còn gọi là B2B. Xóa 2 hoặc nhiều lần xóa theo kiểu nâng cao (như Tetris hay Spin) liên tiếp (nhưng không được xóa kiểu bình thường giữa chừng).\nKhông như combo, Back To Back sẽ không bị mất khi đặt gạch.\n\nỞ Techmino, B2B được tính bằng thanh năng lượng, chứ không tính theo số lần xóa kiểu đặc biệt.\nCũng trong Techmino, nhiều B2B liên tiếp được tính là Back-to-back-to-back (B3B) (xem mục B2B2B để biết thêm).\n\nTechmino cũng tính cả PC và HPC liên tiếp là B2B và B3B",
|
||||
},
|
||||
{"B2B2B",
|
||||
"nhom05j b3b backtobacktoback",
|
||||
@@ -913,7 +918,7 @@ Trong hầu hết các game, tấn công và phòng thủ là tương đương n
|
||||
{"All Clear",
|
||||
"nhom05j pc perfectclear ac allclear",
|
||||
"term",
|
||||
"Còn được biết tới là Perfect Clear (PC). Đây là thuật ngữ được dùng nhiều trong cộng đồng và cũng như được dùng trong Techmino\nXóa toàn bộ gạch ra khỏi bảng, không trừ gạch nào\n\n[Sea: còn có một từ ít dùng nữa, đó là \"Bravo\"]",
|
||||
"Còn được biết tới là Perfect Clear (PC). Đây là thuật ngữ được dùng nhiều trong cộng đồng và cũng như được dùng trong Techmino\nXóa toàn bộ gạch ra khỏi bảng, không trừ gạch nào\n\n[Sea: còn có một từ cổ cho thuật ngữ này nữa, đó là \"Bravo\"]",
|
||||
},
|
||||
{"HPC",
|
||||
"nhom05j hc halfperfectclear",
|
||||
@@ -947,7 +952,7 @@ Trông nó nhìn rất giống cục xương, nên đôi khi được gọi là
|
||||
Trong Techmino, bone block được mô tả là "một skin gạch duy nhất, lạ mắt mà tất cả các gạch đều sử dụng".
|
||||
Skin khác nhau sẽ có skin bone block khác nhau.
|
||||
|
||||
Cũng trong Techmino nhưng ở tiếng Việt, từ "gạch ]]..CHAR.icon.bone..[[" được dùng để chỉ bone block.
|
||||
Cũng trong Techmino (khi để ngôn ngữ là tiếng Việt), từ "gạch ]]..CHAR.icon.bone..[[" được dùng để chỉ bone block.
|
||||
]],
|
||||
},
|
||||
{"=[NHÓM 06]=",
|
||||
@@ -1424,7 +1429,7 @@ NHÓM 07: MỘT VÀI CƠ CHẾ VÀ CHẾ ĐỘ CỦA MỘT SỐ GAME
|
||||
{"=[NHÓM 09]=",
|
||||
"nhom09",
|
||||
"",
|
||||
"NHÓM 09: WIKI; CÁC TRANG WEB BÀY SETUP,\nCUNG CẤP CÂU ĐỐ & CHIA SẺ SETUP"
|
||||
"NHÓM 09: WIKI; CÁC TRANG WEB BÀY SETUP, CUNG CẤP CÂU ĐỐ & CHIA SẺ SETUP"
|
||||
},
|
||||
{">A|Wiki",
|
||||
"nhom09a",
|
||||
@@ -1446,7 +1451,7 @@ NHÓM 07: MỘT VÀI CƠ CHẾ VÀ CHẾ ĐỘ CỦA MỘT SỐ GAME
|
||||
{"Tetris.wiki",
|
||||
"nhom09a tetris wiki",
|
||||
"help",
|
||||
"Một wiki tập trung vào các nội dung liên quan đến Tetris. Wiki được tạo ra từ năm 2015 bởi Myndzi. Trong những năm qua, hàng nghìn đóng góp đã được thực hiện để ghi lại các game xếp gạch chính thức và các game do fan làm, các series, những cơ chế của game,… cũng như tạo ra những bài hướng dẫn để cải thiện trải nghiệm chơi.",
|
||||
"Một wiki tập trung vào các nội dung liên quan đến Tetris. Wiki được tạo ra từ năm 2015 bởi Myndzi, hiện đang được quản lý bởi Simon.lc. Trong những năm qua, hàng nghìn đóng góp đã được thực hiện để ghi lại các game xếp gạch chính thức và các game do fan làm, các series, những cơ chế của game,… cũng như tạo ra những bài hướng dẫn để cải thiện trải nghiệm chơi.",
|
||||
"https://tetris.wiki",
|
||||
},
|
||||
{"Tetris Wiki Fandom",
|
||||
@@ -1696,7 +1701,7 @@ Opener phải đạt 2 trong 4 tiêu chí sau
|
||||
{"BTPC",
|
||||
"nhom12a opener btcannon betacannon",
|
||||
"setup",
|
||||
"Phần tiếp theo của DT Cannon kết thúc bằng All Clear.\nĐể có thêm thông tin, bạn có thể nhấn nút hình địa cầu để mở bài ở trên wiki Hard Drop",
|
||||
"Phần tiếp theo của BT Cannon kết thúc bằng All Clear.\nĐể có thêm thông tin, bạn có thể nhấn nút hình địa cầu để mở bài ở trên wiki Hard Drop",
|
||||
"https://harddrop.com/wiki?search=bt_cannon",
|
||||
},
|
||||
{"TKI 3 Perfect Clear",
|
||||
|
||||
@@ -618,17 +618,17 @@ FNNS and {"赞助3",
|
||||
"主流方块游戏中七种块的颜色会使用同一套彩虹配色:\nZ:红 S:绿 J:蓝 L:橙 T:紫 O:黄 I:青\n\nTechmino默认也使用这一套 “标准” 配色。",
|
||||
},
|
||||
{"提前旋转(IRS)",
|
||||
"irs initialrotatesystem",
|
||||
"tiqianxuanzhuan irs initialrotatesystem",
|
||||
"term",
|
||||
"Initial Rotation System 提前旋转系统\n方块出现前提前按下旋转后,出现时就是转好的形状,有时可以避免死亡。",
|
||||
},
|
||||
{"提前暂存(IHS)",
|
||||
"ihs initialholdsystem",
|
||||
"tiqianzancun ihs initialholdsystem",
|
||||
"term",
|
||||
"Initial Hold System 提前Hold系统\n方块出现前提前按下hold后,直接出现hold里的方块,有时可以避免死亡。",
|
||||
},
|
||||
{"提前移动(IMS)",
|
||||
"ims initialmovesystem",
|
||||
"tiqianyidong ims initialmovesystem",
|
||||
"term",
|
||||
"Initial Move System 提前移动系统\n方块出现前提前按住移动后,出现时会朝移动方向偏一格,有时可以避免死亡(Techmino限定)。\n注:需要块出现时das已充满",
|
||||
},
|
||||
@@ -853,6 +853,11 @@ FNNS and {"赞助3",
|
||||
"term",
|
||||
"Techmino中指玩家的操作焦点转移到新方块的瞬间,此时减小(重置)DAS计时器,让自动移动不会立刻生效,减少 “移动键松开晚了导致下一块一出来就立即开始移动” 的情况\n注:其他游戏中的DAS打断机制可能和Techmino的有区别,仅供参考。",
|
||||
},
|
||||
{"IRS打断(ICD)",
|
||||
"irscut icd daduan",
|
||||
"term",
|
||||
"(由Electra设计)新方块生成时触发IRS的特殊延迟。在没有生成延迟时,这会让预输入的旋转动作延迟一段时间再生效,允许晚一点松开旋转键防止md。",
|
||||
},
|
||||
{"误硬降打断(HCD)",
|
||||
"autolockcut mdcut daduan",
|
||||
"term",
|
||||
|
||||
@@ -462,14 +462,13 @@ C. Gamepad
|
||||
tas="TAS (T)",
|
||||
},
|
||||
net_menu={
|
||||
league="Tech League",
|
||||
ffa="FFA",
|
||||
galaxim="Galaxim",
|
||||
rooms="Rooms",
|
||||
resetPW="Reset password",
|
||||
logout="Log out",
|
||||
},
|
||||
net_league={
|
||||
match="Find Match",
|
||||
net_galaxim={
|
||||
match="Enter Sim.",
|
||||
},
|
||||
net_rooms={
|
||||
password="Password",
|
||||
@@ -588,6 +587,7 @@ C. Gamepad
|
||||
bg_on="Normal BG",
|
||||
bg_off="No BG",
|
||||
bg_custom="Custom BG",
|
||||
bg_custom_base64="Paste image as BG\n(PNG/JPG in Base64)",
|
||||
defaultBG="Default BG",
|
||||
resetDbg="Reset to default",
|
||||
lockBG="Lock BG",
|
||||
@@ -623,6 +623,7 @@ C. Gamepad
|
||||
|
||||
das="DAS",arr="ARR",
|
||||
dascut="DAS Cut",
|
||||
irscut="IRS Cut",
|
||||
dropcut="Auto-lock Cut",
|
||||
sddas="Soft Drop DAS",sdarr="Soft Drop ARR",
|
||||
ihs="Initial Hold",
|
||||
@@ -996,7 +997,7 @@ C. Gamepad
|
||||
"1 next 1 hold!",
|
||||
"1 next 6 hold!",
|
||||
"20G is actually a brand new game rule!",
|
||||
"40-line Sprint WR: 13.650s by WestL",
|
||||
"40-line Sprint WR: 13.430s by WestL",
|
||||
"6 next 1 hold!",
|
||||
"6 next 6 hold?!",
|
||||
"A choke a day keeps record away",
|
||||
|
||||
@@ -423,14 +423,13 @@ return {
|
||||
tas="TAS (T)",
|
||||
},
|
||||
net_menu={
|
||||
league="Liga Tech",
|
||||
ffa="FFA",
|
||||
-- galaxim="Galaxim", -- Galaxy+Simulation
|
||||
rooms="Salas",
|
||||
resetPW="Restabl. Contraseña",
|
||||
logout="Desconec.",
|
||||
},
|
||||
net_league={
|
||||
match="Buscar Match",
|
||||
net_galaxim={
|
||||
-- match="Enter Sim.", -- (Actively) Enter (the) (digital) Simulation of (a galaxy)
|
||||
},
|
||||
net_rooms={
|
||||
password="Contraseña",
|
||||
@@ -583,6 +582,7 @@ return {
|
||||
|
||||
das="DAS",arr="ARR",
|
||||
dascut="Intrrp. de DAS",
|
||||
irscut="Intrrp. de IRS",
|
||||
dropcut="Intrrp. de Autocaída",
|
||||
sddas="DAS de C. Ráp.",sdarr="ARR de C. Rápida",
|
||||
ihs="Resv. Inicial",
|
||||
|
||||
@@ -398,14 +398,13 @@ return {
|
||||
-- tas="TAS (T)",
|
||||
},
|
||||
net_menu={
|
||||
-- league="Tech League",
|
||||
ffa="FFA",
|
||||
-- galaxim="Galaxim", -- Galaxy+Simulation
|
||||
rooms="Salons",
|
||||
resetPW="Réinitialiser le mot de passe",
|
||||
logout="Se déconnecter",
|
||||
},
|
||||
net_league={
|
||||
match="Find Match",
|
||||
net_galaxim={
|
||||
-- match="Enter Sim.", -- (Actively) Enter (the) (digital) Simulation of (a galaxy)
|
||||
},
|
||||
net_rooms={
|
||||
password="Mot de passe",
|
||||
@@ -560,6 +559,7 @@ return {
|
||||
|
||||
das="DAS",arr="ARR",
|
||||
dascut="DAS cut",
|
||||
irscut="IRS cut",
|
||||
-- dropcut="Auto-lock cut",
|
||||
sddas="DAS de chute rapide",sdarr="ARR de chute rapide",
|
||||
ihs="Réserve Initiale",
|
||||
|
||||
@@ -424,14 +424,13 @@ return {
|
||||
tas="TAS (T)",
|
||||
},
|
||||
net_menu={
|
||||
league="Tech League",
|
||||
ffa="FFA",
|
||||
-- galaxim="Galaxim", -- Galaxy+Simulation
|
||||
rooms="Ruang-ruang",
|
||||
-- resetPW="Reset password",
|
||||
logout="Log out",
|
||||
},
|
||||
net_league={
|
||||
match="Cari Tandingan",
|
||||
net_galaxim={
|
||||
-- match="Enter Sim.", -- (Actively) Enter (the) (digital) Simulation of (a galaxy)
|
||||
},
|
||||
net_rooms={
|
||||
password="Password",
|
||||
@@ -585,6 +584,7 @@ return {
|
||||
|
||||
das="DAS",arr="ARR",
|
||||
dascut="Gangguan DAS",
|
||||
irscut="Gangguan IRS",
|
||||
dropcut="Gangguan Auto-kunci",
|
||||
sddas="DAS Jatuh",sdarr="ARR Jatuh",
|
||||
ihs="Simpan Saat Tunda",
|
||||
@@ -953,7 +953,7 @@ return {
|
||||
"↑↑↓↓←→←→BA",
|
||||
"$include<studio.h>",
|
||||
"20G sebenarnya peraturan permainan baru!",
|
||||
"Rekor dunia 40L: 13.650s dari WestL",
|
||||
"Rekor dunia 40L: 13.430s dari WestL",
|
||||
"Sistem pencapaian segera akan datang!",
|
||||
"ALL SPIN!",
|
||||
"Am G F G",
|
||||
|
||||
@@ -468,14 +468,13 @@ C. ゲームパッド
|
||||
tas="TAS (T)",
|
||||
},
|
||||
net_menu={
|
||||
league="テクリーグ",
|
||||
ffa="FFA",
|
||||
-- galaxim="Galaxim", -- Galaxy+Simulation
|
||||
rooms="ルーム",
|
||||
resetPW="パスワード再設定",
|
||||
logout="ログアウト",
|
||||
},
|
||||
net_league={
|
||||
match="対戦相手を探す",
|
||||
net_galaxim={
|
||||
-- match="Enter Sim.", -- (Actively) Enter (the) (digital) Simulation of (a galaxy)
|
||||
},
|
||||
net_rooms={
|
||||
password="パスワード",
|
||||
@@ -629,6 +628,7 @@ C. ゲームパッド
|
||||
|
||||
das="DAS",arr="ARR",
|
||||
dascut="DASカット",
|
||||
irscut="IRSカット",
|
||||
dropcut="自動設置カット",
|
||||
sddas="ソフトドロップDAS",sdarr="ソフトドロップARR",
|
||||
ihs="先行ホールド",
|
||||
@@ -1006,7 +1006,7 @@ getTip={refuseCopy=true,
|
||||
"20PCって何?",
|
||||
"26TSDって何?",
|
||||
"2つの回転を使ってみよう、3つ使うとさらにいいです!",
|
||||
"40-line Sprint WR: 13.650s by WestL",
|
||||
"40-line Sprint WR: 13.430s by WestL",
|
||||
"6next 1hold!",
|
||||
"6next 6hold?!",
|
||||
"低音を響かせろ!",
|
||||
|
||||
@@ -412,13 +412,12 @@ return {
|
||||
-- tas="TAS (T)",
|
||||
},
|
||||
net_menu={
|
||||
-- league="Tech League",
|
||||
ffa="FFA",
|
||||
-- galaxim="Galaxim", -- Galaxy+Simulation
|
||||
rooms="Salas",
|
||||
-- resetPW="Reset password",
|
||||
-- logout="Log out",
|
||||
},
|
||||
net_league={
|
||||
net_galaxim={
|
||||
-- match="Find Match",
|
||||
},
|
||||
net_rooms={
|
||||
@@ -573,6 +572,7 @@ return {
|
||||
|
||||
das="DAS",arr="ARR",
|
||||
dascut="DAS cut",
|
||||
irscut="IRS cut",
|
||||
-- dropcut="Auto-lock cut",
|
||||
sddas="Soft Drop DAS",sdarr="Soft Drop ARR",
|
||||
ihs="Segurar Inicial",
|
||||
@@ -948,7 +948,7 @@ return {
|
||||
"1next 1hold!",
|
||||
"1next 6hold!",
|
||||
"Na verdade 20G é uma regra de jogo nova.",
|
||||
"40-line Sprint WR: 13.650s by WestL",
|
||||
"40-line Sprint WR: 13.430s by WestL",
|
||||
"6next 1hold!",
|
||||
"6next 6hold?!",
|
||||
"ALL SPIN!",
|
||||
|
||||
@@ -171,13 +171,12 @@ return {
|
||||
tas="#&; (T)",
|
||||
},
|
||||
net_menu={
|
||||
league="TL",
|
||||
ffa="FFA",
|
||||
-- galaxim="Galaxim", -- Galaxy+Simulation
|
||||
rooms="< >",
|
||||
resetPW="R ***",
|
||||
logout="@_@x",
|
||||
},
|
||||
net_league={
|
||||
net_galaxim={
|
||||
match="!",
|
||||
},
|
||||
net_rooms={
|
||||
@@ -330,6 +329,7 @@ return {
|
||||
|
||||
das="x---x x x",arr="x x-x-x",
|
||||
dascut="x x ↓___x x",
|
||||
irscut="'' !''x",
|
||||
dropcut="↓_ !↓↓x",
|
||||
sddas="↓---↓ ↓ ↓",sdarr="↓ ↓-↓-↓",
|
||||
ihs="![ ]",
|
||||
|
||||
@@ -197,7 +197,7 @@ return {
|
||||
|
||||
|
||||
keySettingInstruction="Nhấn một phím để gán phím đó\nescape (esc): Hủy\nbackspace: Xoá",
|
||||
customBGhelp=not MOBILE and "Kéo một tấm ảnh vào đây để áp dụng ảnh nền tuỳ chỉnh" or "Chưa hỗ trợ ảnh nền cho điện thoại",
|
||||
customBGhelp="Kéo một tấm ảnh vào đây để áp dụng ảnh nền tuỳ chỉnh",
|
||||
customBGloadFailed="Định dạng ảnh không được hỗ trợ",
|
||||
|
||||
errorMsg="Techmino bị lỗi và cần phải được khởi động lại\nBạn có thể gửi error log để giúp dev sửa game nhanh hơn.",
|
||||
@@ -457,14 +457,13 @@ C. Tay cầm chơi game (Gamepad):
|
||||
tas="TAS (T)",
|
||||
},
|
||||
net_menu={
|
||||
league="Tech League",
|
||||
ffa="FFA",
|
||||
galaxim="Galaxim",
|
||||
rooms="Danh sách phòng",
|
||||
resetPW="Đặt lại mật khẩu",
|
||||
logout="Đăng xuất",
|
||||
},
|
||||
net_league={
|
||||
match="Tìm trận",
|
||||
net_galaxim={
|
||||
match="Bước vào mô phỏng",
|
||||
},
|
||||
net_rooms={
|
||||
password="Mật khẩu",
|
||||
@@ -584,6 +583,7 @@ C. Tay cầm chơi game (Gamepad):
|
||||
bg_on="Ảnh nền thường",
|
||||
bg_off="Không ảnh nền",
|
||||
bg_custom="Ảnh nền tự chọn",
|
||||
bg_custom_base64="Dán ảnh và cài thành ảnh nền\n(PNG/JPG ở format Base64)",
|
||||
defaultBG="Nền mặc định",
|
||||
resetDbg='Đặt lại',
|
||||
lockBG="Khóa ảnh nền",
|
||||
@@ -619,6 +619,7 @@ C. Tay cầm chơi game (Gamepad):
|
||||
|
||||
das="DAS",arr="ARR",
|
||||
dascut="DAS cut",
|
||||
irscut="IRS cut",
|
||||
dropcut="Auto-lock cut",
|
||||
sddas="DAS thả nhẹ",sdarr="ARR thả nhẹ",
|
||||
ihs="Giữ tức thì",
|
||||
@@ -964,7 +965,7 @@ C. Tay cầm chơi game (Gamepad):
|
||||
['tech_l']= {"Tech B2B", "RẤT KHÓ", "Cố gắng không phá B2B!"},
|
||||
['tech_l_plus']= {"Tech B2B", "RẤT KHÓ+", "Chỉ được clear Spin hoặc PC"},
|
||||
['tech_finesse']= {"Tech FINESSE", "", "Không được phép có lỗi di chuyển!"},
|
||||
['tech_finesse_f']= {"Tech FINESSE", "KHÔNG ĐƠN/ĐÔI", "Không được phép có lỗi di chuyển hoặc kiểu Xoá hàng thường!"},
|
||||
['tech_finesse_f']= {"Tech FINESSE", "PLUS", "Không được phép có lỗi di chuyển hoặc kiểu Xoá hàng thường!"},
|
||||
['tsd_e']= {"TSD Challenge", "DỄ", "Chỉ được làm T-Spin Double!"},
|
||||
['tsd_h']= {"TSD Challenge", "KHÓ", "Chỉ được làm T-Spin Double!"},
|
||||
['tsd_u']= {"TSD Challenge", "THÁCH ĐẤU", "Chỉ được làm T-Spin Double!"},
|
||||
@@ -1003,7 +1004,7 @@ C. Tay cầm chơi game (Gamepad):
|
||||
"6 next 1 hold!",
|
||||
"6 next 6 hold?!",
|
||||
"20G thực chất là một chế độ mới đấy!",
|
||||
"Kỷ lục Sprint 40 hàng: 13.650s (WestL)",
|
||||
"Kỷ lục Sprint 40 hàng: 13.430s (WestL)",
|
||||
"Rất gần nhưng lại rất xa",
|
||||
"ALL SPIN!",
|
||||
"Am G F G",
|
||||
@@ -1124,7 +1125,7 @@ C. Tay cầm chơi game (Gamepad):
|
||||
-- Techmino's birthday
|
||||
"Ngày sinh nhật của Techmino? Hiện tại (đang giả định) là 26/T6.",
|
||||
-- How to O-spin: Rotate 626 times in one second (mistaken)
|
||||
"Cách O-spin? Nhấn phím xoay 626 lần trong 1 giây (ĐÙA ĐẤY ĐỪNG TIN!)",
|
||||
"Cách làm O-spin? Nhấn phím xoay 626 lần trong 1 giây (ĐÙA ĐẤY ĐỪNG TIN!)",
|
||||
-- 2021 was the year of Techmino's online debut.
|
||||
"2021 là năm ra mắt chế độ trực tuyến của Techmino.",
|
||||
-- The Chinese name of this game is 'Block Research Institute'.
|
||||
@@ -1132,15 +1133,15 @@ C. Tay cầm chơi game (Gamepad):
|
||||
-- This game is not called Teachmino
|
||||
"Tên game không phải là Teachmino!",
|
||||
--
|
||||
"Muốn game có thứ gì đó đặc biệt lúc mở game? Hãy chỉnh đồng hồ trên điện thoại vào một ngày đặc biệt nào đó đi!",
|
||||
"Hãy thử chỉnh đồng hồ trên điện thoại để xem xem, có thứ gì đó đặc biệt hay không?",
|
||||
-- O-spin is a lie!
|
||||
{C.Y,"O-spin",C.Z," is a ",C.R,"lie",C.Z,"!"},
|
||||
{C.Y,"O-spin",C.Z," là ",C.R,"lời nói dối",C.Z,"của em!"},
|
||||
-- techminohaowan
|
||||
"Hảo Techmino",
|
||||
--
|
||||
-- TIPS WHEN PLAYING
|
||||
-- Don't act weak! Don't act weak! Don't act weak!
|
||||
"Đừng tỏ ra yếu đuối! Đừng tỏ ra yếu đuối! ĐỪNG TỎ RA YẾU ĐUỐI!",
|
||||
"Đừng tỏ ra yếu đuối! Và KHÔNG BAO GIỜ tỏ ra yếu đuối!",
|
||||
-- Warning: No pretending to be weak.
|
||||
{C.R,"CẢNH BÁO! ",C.Z,"Đừng giả vờ yếu đuối"},
|
||||
-- "Meow!"
|
||||
@@ -1151,7 +1152,7 @@ C. Tay cầm chơi game (Gamepad):
|
||||
-- Don't play with your phone if your homework isn't finished.
|
||||
"Đừng chơi điện thoại khi bài tập về nhà còn chưa hoàn thành.",
|
||||
-- Enabling vibration on some mobile systems may cause severe lag."
|
||||
"Bật rung trên một số điện thoại có thể làm cho chúng… phải thở oxy!",
|
||||
"Bật rung có thể làm một số điện thoại phải thở oxy!",
|
||||
-- Eat the button? Really? I suggest you play it back to see if you pressed it and how long it took you to press it"
|
||||
"Phím không ăn? Hãy thử kiểm tra lại phím đi!",
|
||||
-- Probably someone will read the tip
|
||||
@@ -1159,31 +1160,43 @@ C. Tay cầm chơi game (Gamepad):
|
||||
-- It seems like no one has reached a high level by playing with their feet yet.
|
||||
"Hình như tới giờ chưa ai chơi xếp gạch giỏi bằng chân…",
|
||||
-- Moderate gaming is good for the brain. Addiction to games is harmful. Plan your time
|
||||
"Chơi game vừa phải có thể tốt cho bộ não. Nhưng nếu nghiện thì toang! Nhớ lập thời gian biểu nhé!",
|
||||
"Chơi game vừa phải có thể tốt cho bộ não. Nhưng nếu nghiện thì toang! Nhớ sắp xếp quỹ thời gian cho hợp lý nhé!",
|
||||
-- The ability to dig is extremely important in battles!!!
|
||||
"Khả năng đào xuống (downstacking) của bạn là RẤT QUAN TRỌNG trong chiến đấu!!!",
|
||||
-- Skilled players of the Classic Tetris game are also formidable; don't underestimate them
|
||||
"Đừng có mà xem thường những người chơi xếp gạch cổ điển! Chơi cái đó cũng khó không khác gì chơi xếp gạch hiện đại đâu.",
|
||||
-- Classic Tetris and Modern Tetris are two different games; being skilled in one doesn't mean you'll be skilled in the other. You have to start from scratch.
|
||||
"Xếp gạch cổ điển và xếp gạch hiện đại là hai thể loại game khác nhau đấy! Giỏi một trong hai chưa chắc bạn giỏi cả bên còn lại đâu. Bạn phải học lại từ đầu đấy",
|
||||
"Xếp gạch cổ điển và xếp gạch hiện đại là hai thể loại game khác nhau đấy! Giỏi một trong hai chưa chắc bạn giỏi cả bên còn lại đâu. Bạn đều phải học lại từ đầu đấy",
|
||||
-- To protect the players' well-being, the game has a temporary and simplified anti-addiction system! (But you probably won't trigger it, haha)
|
||||
"Để tránh việc người chơi nào đó chơi quá lâu, game đã có hệ thống chống nghiện đơn giản tạm thời (Nhưng bạn có lẽ sẽ không bao giờ kích hoạt chúng đâu, haha)",
|
||||
-- Basic stacking and digging skills are crucial; those who neglect these two aspects often regret it (trust me)
|
||||
{"Kỹ năng xếp lên vào đào xuống là 2 kỹ năng RẤT quan trọng; những ai coi thường hay bỏ bê hai khía cạnh này thường hay bị bón hành súp mặt lờ (tin ",C.W,"MrZ",C.Z," đi!)"},
|
||||
{"Kỹ năng xếp lên vào đào xuống là 2 kỹ năng RẤT quan trọng; những người hay bị bón hành hầu hết là những người đếch tôn trọng 2 kỹ năng này (tin lời ",C.W,"MrZ",C.Z," đi!)"},
|
||||
-- Even if you're topped out, don't give up; every line of garbage can potentially become your weapon.
|
||||
"Đừng bỏ cuộc khi đống hàng rác đang làm bạn sắp bị top out, bởi bạn có thể biến chúng trở thành đòn phản công.",
|
||||
-- The video shown above is not a recording; it's the robot playing in real-time.
|
||||
"Cái ở trên là bản ghi sẵn hả? Không, là AI đang chơi trong thời gian thực đấy!",
|
||||
"Cái ở trên là video hả? Không, là AI đang chơi trong thời gian thực đấy!",
|
||||
-- Extended gaming sessions will gradually deteriorate your performance! Remember to take breaks when playing for a long time~
|
||||
"Thường xuyên chơi game lâu có thể khiến bạn có thể bị đuối sức (cả thể chất và tinh thần, tệ nhất có thể bị stall). Hãy nhớ nghỉ giải lao sau khi chơi lâu nhé!",
|
||||
"Thường xuyên chơi game lâu có thể khiến bạn có thể bị đuối sức (cả thể chất và tinh thần, tệ nhất có thể bị stall). Hãy nhớ nghỉ giải lao sau khi chơi lâu nhé! Meow~",
|
||||
-- Be careful of tenosynovitis!
|
||||
{C.R,"CẢNH BÁO! ",C.Z,"Bệnh viêm bao gân cổ tay!"},
|
||||
-- The button with a question mark in the bottom-right corner is the game manual (assuming you haven't enabled the Simple mode).
|
||||
"Cái nút "..CHAR.icon.help.." ở góc phải dưới cùng trong menu (không bật chế độ Đơn giản) đấy hả? Nó là manual (hướng dẫn sử dụng) của game đấy!",
|
||||
"Cái nút "..CHAR.icon.help.." ở màn hình chính (giả sử bạn chưa mở Chế độ đơn giản) là hướng dẫn sử dụng của Techmino đấy!",
|
||||
-- If you're new to blocks, just play more games; there isn't much specific targeted practice beyond 40 lines in two minutes
|
||||
"Bạn mới tập chơi xếp gạch à? Nếu vậy cứ chơi nhiều lên. Không có nhiều mục tiêu luyện tập cụ thể ngoài xóa 40 hàng trong 2 phút đâu!",
|
||||
--
|
||||
"Hãy ra ngoài và chạm cỏ đi!",
|
||||
-- [SELF-MADE]
|
||||
{"Có thuật ngữ nào bạn không hiểu à? Hãy tra ",C.R,"Z",C.Z,"ictionary!"}, -- Have a term you don't understand? Check Zictionary
|
||||
-- Maybe saying this you may not believe, but there are many tips here never appear in English!
|
||||
{"Nói cái này có thể bạn không tin, ",C.lSea,"nhưng có nhiều mẹo trong số này bạn sẽ không bao giờ thấy ở trong Techmino tiếng Anh đâu!"},
|
||||
|
||||
--
|
||||
-- OTHER
|
||||
"\"Zictionary\" có 2 tên gọi khác, đó là: \"TetroDictionary\" và \"Little Z Dictionary\"",
|
||||
"\"Zictionary\" có thể có vài chỗ nghe bất tự nhiên. Cứ thoải mái gửi bản chỉnh sửa lên GitHub đi!",
|
||||
"Làm ơn đừng đánh đồng Korobeiniki với bản nhạc A. Hai nhạc này có sự khác biệt rất rõ trong giai điệu nhé!",
|
||||
"Làm cách nào để mời người khác cùng chơi xếp gạch với mình? Xếp gạch giờ không còn đơn giản như trước đây nữa...",
|
||||
|
||||
--
|
||||
-- MrZ
|
||||
{C.W,"uid:225238922"},
|
||||
@@ -1191,7 +1204,7 @@ C. Tay cầm chơi game (Gamepad):
|
||||
--
|
||||
-- Z SAID
|
||||
-- I can't write cool music (crying)
|
||||
{C.W,"Z: ",C.Z,"Tôi không tài nào viết nổi một bản nhạc nào trông ngầu cả (sadge)."},
|
||||
{C.W,"Z: ",C.Z,"Tôi không tài nào viết nổi một bản nhạc nào ra hồn cả (sadge)."},
|
||||
-- I haven't studied music composition. I just composed it myself. If you really think it's good, that's great!
|
||||
{C.W,"Z: ",C.Z,"Tôi chưa từng học sáng tác nhạc, và tôi chỉ tự sáng tác chúng. Nếu bạn thấy những bản nhạc này hay, thật tuyệt!"},
|
||||
-- What else can I write for tips?
|
||||
@@ -1221,7 +1234,7 @@ C. Tay cầm chơi game (Gamepad):
|
||||
"Techmino.exe hiện không phản hồi",
|
||||
"Techmino đã đột ngột dừng lại",
|
||||
-- If you have a real interest in programming, I recommend Lua. Easy installation, simple syntax, and fast execution speed. Stay away from boring school programming (haha)
|
||||
{"Nếu bạn thực sự có hứng thú trong lập trình, tôi đề xuất sử dụng Lua. Dễ cài đặt, cú pháp đơn giản, tốc độ thực thi nhanh. Hãy tránh xa những tiết học lập trình chán ngắt ở trên trường luôn đi! (haha) - ",C.W,"MrZ",C.Z," said."},
|
||||
{C.W,"MrZ:",C.Z,"Nếu bạn thực sự có hứng thú trong lập trình, tôi đề xuất sử dụng Lua. Dễ cài, cú pháp đơn giản, tốc độ thực thi nhanh. Hãy tránh xa những tiết học lập trình chán ngắt ở trên trường luôn đi! (haha)"},
|
||||
--
|
||||
-- CHANGELOG
|
||||
{C.lW, "V0.0.091726",": ",C.Z, "Thêm hệ thống xoay TRS"},
|
||||
@@ -1268,18 +1281,20 @@ C. Tay cầm chơi game (Gamepad):
|
||||
--
|
||||
-- SEA'S JOKE
|
||||
{C.W,"MrZ",C.Z," còn có một biệt danh dễ thương hơn, đó là ",C.W,"Z-Chan"},
|
||||
{C.W,"Z-Chan",C.Z," cute quá. Tui không cưỡng lại được... HELP!"},
|
||||
|
||||
{C.lSea,"Sea: ",C.Z,"Tui không có đủ mặn để viết joke. Nên một số câu đùa đang chạy ở đây được viết bởi ",C.yellow,"Shard Nguyễn",C.Z,". \"Em cảm ơn anh!\""},
|
||||
{C.lSea,"Sea: ",C.Z,"Tui đang tự hỏi liệu còn bao nhiêu lỗi tui bỏ sót lúc dịch game không? Tính ra tui đã cập nhật đi cập nhật lại cũng 4-5 lần rồi."},
|
||||
|
||||
{"Cộng đồng Tetris ",C.R,"Việt ",C.lY,"Nam ",C.Z,": https://discord.gg/jX7BX9g"}, -- Tetris Vietnam (TVN)
|
||||
{"\"Tetris Việt Nam\"? Không, đó là \"Hội phụ hồ Việt Nam\" (https://discord.gg/hoiphuhovietnam)"},
|
||||
"\"Zictionary\" có 2 tên gọi khác, đó là: \"TetroDictionary\" và \"Little Z Dictionary\"",
|
||||
"Mình xin phép ủng hộ cho player này. Ủng hộ càng nhiều tỉ lệ thắng càng cao!",
|
||||
{"Aiiiii mua cần phô mai ủng hộ ",C.yellow,"Chủ tiệm phô mai",C.Z," không?"}, -- A joke in TVN
|
||||
-- Who will you choose? A girl that can break up to you and make you sad
|
||||
-- Or choose Katyusha that can warm your heart and 40ha land of enemy.
|
||||
"Bạn sẽ chọn ai? Một em gái có thể chia tay và làm bạn buồn? Hay là chọn em Katyusha có thể làm ấm lòng bạn và 40ha đất kẻ thù?", -- Based on a comment in https://www.youtube.com/watch?v=nczdLwTyWmY
|
||||
"Bạn sẽ chọn ai? Một em gái nào đó có thể chia tay và làm bạn buồn? Hay là chọn em gái Katyusha có thể làm ấm lòng bạn và 40ha đất kẻ thù?", -- Based on a comment in https://www.youtube.com/watch?v=nczdLwTyWmY
|
||||
-- What if the ".io" domain disappear? What will happen with TETR.IO?
|
||||
"Nếu tên miền cấp quốc gia '.io' biến mất, chuyện gì sẽ xảy ra với TETR.IO?",
|
||||
},
|
||||
pumpkin="Tôi là một quả bí ngô",
|
||||
}
|
||||
|
||||
@@ -453,14 +453,13 @@ return {
|
||||
tas="TAS (T)",
|
||||
},
|
||||
net_menu={
|
||||
league="Tech League",
|
||||
ffa="FFA",
|
||||
galaxim="Galaxim",
|
||||
rooms="房间列表",
|
||||
resetPW="重置密码",
|
||||
logout="退出登录",
|
||||
},
|
||||
net_league={
|
||||
match="匹配对手",
|
||||
net_galaxim={
|
||||
match="进入模拟",
|
||||
},
|
||||
net_rooms={
|
||||
password="密码",
|
||||
@@ -613,6 +612,7 @@ return {
|
||||
|
||||
das="DAS:",arr="ARR:",
|
||||
dascut="DAS打断:",
|
||||
irscut="IRS打断",
|
||||
dropcut="误硬降打断:",
|
||||
sddas="软降DAS:",sdarr="软降ARR:",
|
||||
ihs="提前Hold",
|
||||
@@ -984,7 +984,7 @@ return {
|
||||
"1next 6hold!",
|
||||
"3.1415926535897932384(\\d{3})",
|
||||
"3next 1hold?",
|
||||
"40行世界纪录: 13.650s by WestL",
|
||||
"40行世界纪录: 13.430s by WestL",
|
||||
"6236326236327175",
|
||||
"626in1",
|
||||
"6next 1hold!",
|
||||
@@ -1207,7 +1207,7 @@ return {
|
||||
"豆知识[016]本游戏的B2B是气槽机制,和传统的开关机制不一样哦",
|
||||
"豆知识[017]本游戏内置了几个休(yìng)闲(hé)小游戏哦~",
|
||||
"豆知识[018]本游戏在设计的时候受到了大量其他块游甚至一些音游的启发",
|
||||
"豆知识[019]必须要软降才能到达的位置都会判定为极简操作",
|
||||
"豆知识[019]必须要软降才能到达的位置不会被判定为非极简操作",
|
||||
"豆知识[020]别看攻击效率不高,其实消四还是很强的",
|
||||
"豆知识[021]别问游戏名字怎么取的,问就是随便想的",
|
||||
"豆知识[022]不同人打40行最合适的方式不一样,s1w/63/散消/s2w……",
|
||||
|
||||
@@ -372,14 +372,13 @@ return {
|
||||
tas="TAS(); (T)",
|
||||
},
|
||||
net_menu={
|
||||
league="M.TechLeague();",
|
||||
ffa="M.FFA",
|
||||
galaxim="M.Galaxim();",
|
||||
rooms="M.Rooms();",
|
||||
resetPW="M.ResetPW",
|
||||
logout="M.Logout();",
|
||||
},
|
||||
net_league={
|
||||
match="TL.Match();",
|
||||
net_galaxim={
|
||||
match="GX.Enter();",
|
||||
},
|
||||
net_rooms={
|
||||
password="Password=",
|
||||
@@ -532,6 +531,7 @@ return {
|
||||
|
||||
das="Set.DAS=",arr="Set.SRR=",
|
||||
dascut="Set.DASCut=",
|
||||
irscut="Set.IRSCut=",
|
||||
dropcut="Set.DropCut=",
|
||||
sddas="Set.SDDAS=",sdarr="Set.SDARR=",
|
||||
ihs="Set.IHS",
|
||||
|
||||
@@ -424,14 +424,13 @@ return {
|
||||
tas="TAS (T)",
|
||||
},
|
||||
net_menu={
|
||||
league="Tech League",
|
||||
ffa="FFA",
|
||||
galaxim="Galaxim",
|
||||
rooms="房間列表",
|
||||
resetPW="重設密碼",
|
||||
logout="登出",
|
||||
},
|
||||
net_league={
|
||||
match="匹配對手",
|
||||
net_galaxim={
|
||||
match="进入模拟",
|
||||
},
|
||||
net_rooms={
|
||||
password="密碼",
|
||||
@@ -584,6 +583,7 @@ return {
|
||||
|
||||
das="DAS",arr="ARR",
|
||||
dascut="DAS打斷",
|
||||
irscut="IRS打斷",
|
||||
dropcut="誤硬降打斷",
|
||||
sddas="軟降DAS",sdarr="軟降ARR",
|
||||
ihs="提前Hold",
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
require'parts.scenes.customGame'.initialize()
|
||||
|
||||
return {
|
||||
env={},
|
||||
load=function()
|
||||
@@ -12,10 +14,11 @@ return {
|
||||
PLY.newPlayer(1)
|
||||
local AItype=GAME.modeEnv.opponent:sub(1,2)
|
||||
local AIlevel=tonumber(GAME.modeEnv.opponent:sub(-1))
|
||||
local useHold=GAME.modeEnv.holdCount>0 and GAME.modeEnv.holdMode=='hold'
|
||||
if AItype=='9S' then
|
||||
PLY.newAIPlayer(2,BOT.template{type='9S',speedLV=2*AIlevel,hold=GAME.modeEnv.holdCount})
|
||||
PLY.newAIPlayer(2,BOT.template{type='9S',speedLV=2*AIlevel,hold=useHold})
|
||||
elseif AItype=='CC' then
|
||||
PLY.newAIPlayer(2,BOT.template{type='CC',speedLV=2*AIlevel-1,next=math.floor(AIlevel*.5+1),hold=GAME.modeEnv.holdCount,node=20000+5000*AIlevel})
|
||||
PLY.newAIPlayer(2,BOT.template{type='CC',speedLV=2*AIlevel-1,next=math.floor(AIlevel*.5+1),hold=useHold,node=20000+5000*AIlevel})
|
||||
end
|
||||
|
||||
for _,P in next,PLY_ALIVE do
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
local gc_setColor,gc_draw=love.graphics.setColor,love.graphics.draw
|
||||
local ply_applyField=PLY.draw.applyField
|
||||
|
||||
require'parts.scenes.customGame'.initialize()
|
||||
|
||||
return {
|
||||
env={
|
||||
fkey1=function(P) P.modeData.showMark=1-P.modeData.showMark end,
|
||||
@@ -54,10 +56,11 @@ return {
|
||||
local AItype=GAME.modeEnv.opponent:sub(1,2)
|
||||
local AIlevel=tonumber(GAME.modeEnv.opponent:sub(-1))
|
||||
PLY.newPlayer(1)
|
||||
local useHold=GAME.modeEnv.holdCount>0 and GAME.modeEnv.holdMode=='hold'
|
||||
if AItype=='9S' then
|
||||
PLY.newAIPlayer(2,BOT.template{type='9S',speedLV=2*AIlevel,hold=GAME.modeEnv.holdCount})
|
||||
PLY.newAIPlayer(2,BOT.template{type='9S',speedLV=2*AIlevel,hold=useHold})
|
||||
elseif AItype=='CC' then
|
||||
PLY.newAIPlayer(2,BOT.template{type='CC',speedLV=2*AIlevel-1,next=math.floor(AIlevel*.5+1),hold=GAME.modeEnv.holdCount,node=20000+5000*AIlevel})
|
||||
PLY.newAIPlayer(2,BOT.template{type='CC',speedLV=2*AIlevel-1,next=math.floor(AIlevel*.5+1),hold=useHold,node=20000+5000*AIlevel})
|
||||
end
|
||||
end,
|
||||
savePrivate=function()
|
||||
|
||||
@@ -55,6 +55,12 @@ return {
|
||||
P.modeData.colorSet[i]=P.holeRND:random(25)
|
||||
end
|
||||
P.randomizer_spinren=randomizer(P.holeRND)
|
||||
-- table.insert(P.field,1,LINE.new(0))
|
||||
-- P.field[1][1]=18
|
||||
-- P.field[1][2]=18
|
||||
-- P.field[1][9]=18
|
||||
-- P.field[1][10]=18
|
||||
-- table.insert(P.visTime,1,LINE.new(20))
|
||||
P:pushLineList(get_lines(18,P))
|
||||
P.fieldBeneath=0
|
||||
end,
|
||||
|
||||
@@ -29,8 +29,8 @@ local NET={
|
||||
|
||||
onlineCount="_",
|
||||
|
||||
textBox=WIDGET.newTextBox{name='texts',x=340,y=80,w=600,h=560},
|
||||
inputBox=WIDGET.newInputBox{name='input',x=340,y=660,w=600,h=50,limit=256},
|
||||
textBox=WIDGET.newTextBox{name='texts',x=20,y=110,w=980,h=500},
|
||||
inputBox=WIDGET.newInputBox{name='input',x=20,y=630,w=980,h=50,limit=256},
|
||||
}
|
||||
|
||||
function NET.freshRoomAllReady()
|
||||
@@ -187,17 +187,48 @@ function NET.getAvatar(uid)
|
||||
end
|
||||
end)
|
||||
end
|
||||
function NET.getNotice(lang,count)
|
||||
|
||||
local noticeLang={
|
||||
en='en_us',
|
||||
fr='en_us', -- fr_fr
|
||||
es='en_us', -- es_es
|
||||
id='en_us', -- id_id
|
||||
pt='en_us', -- pt_pt
|
||||
symbol='en_us', -- gl_os
|
||||
ja='en_us', -- ja_jp
|
||||
vi='en_us', -- vi_vn
|
||||
zh='zh_cn',
|
||||
zh_trad='zh_tw',
|
||||
zh_code='zh_cn',
|
||||
}
|
||||
function NET.launchNotice()
|
||||
TASK.new(function()
|
||||
local res=getMsg({
|
||||
pool='getNotice',
|
||||
path='/techmino/api/v1/notice?language='..noticeLang[SETTING.locale]..'&lastCount=1',
|
||||
},6.26)
|
||||
|
||||
if res and res.code==200 then
|
||||
local opt=res.data.contents[1]
|
||||
if opt then
|
||||
MES.new('info',opt.content,12.6)
|
||||
else
|
||||
MES.new('info',text.Techrater.NoticeManager.noticeNotFound)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
function NET.getNotice(count)
|
||||
WAIT{timeout=6.26}
|
||||
TASK.new(function()
|
||||
local res=getMsg({
|
||||
pool='getNotice',
|
||||
path='/techmino/api/v1/notice?language='..(lang or 'zh_cn')..'&lastCount='..(count or 5),
|
||||
path='/techmino/api/v1/notice?language='..noticeLang[SETTING.locale]..'&lastCount='..(count or 5),
|
||||
},6.26)
|
||||
|
||||
if res and res.code==200 and type(res.data)=='string' then
|
||||
local dataStr=""
|
||||
SCN.go('notice',nil,dataStr)
|
||||
if res and res.code==200 then
|
||||
WAIT.interrupt()
|
||||
SCN.go('notice',nil,noticeLang[SETTING.locale],res.data.contents)
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -393,10 +424,19 @@ function NET.wsCallBack.room_chat(body)
|
||||
if SCN.cur~='net_game' then return end
|
||||
TASK.unlock('receiveMessage')
|
||||
TASK.lock('receiveMessage',1)
|
||||
NET.textBox:push{
|
||||
COLOR.Z,_getFullName(body.data.playerId).." ",
|
||||
COLOR.N,body.data.message,
|
||||
}
|
||||
|
||||
local name=_getFullName(body.data.playerId).." "
|
||||
-- P/s: we need to wrap both name and message, not just only message
|
||||
local _,msgWrapped=FONT.get(NET.inputBox.font):getWrap(name..body.data.message,950)
|
||||
-- We don't want to see the name repeat twice :skull:
|
||||
msgWrapped[1]=string.gsub(msgWrapped[1],name,"",1)
|
||||
-- Push the name in white and first line of message in blue first
|
||||
NET.textBox:push{COLOR.Z,name,COLOR.N,msgWrapped[1]}
|
||||
for i, line in ipairs(msgWrapped) do
|
||||
if i ~= 1 then
|
||||
NET.textBox:push{COLOR.N,msgWrapped[i]}
|
||||
end
|
||||
end
|
||||
end
|
||||
function NET.wsCallBack.room_create(body)
|
||||
MES.new('check',text.createRoomSuccessed)
|
||||
|
||||
@@ -29,11 +29,13 @@ return {
|
||||
{font=65,name="怀沙"},
|
||||
{font=65,name="星街书婉"},
|
||||
{font=65,name="老板来两份薯条"},
|
||||
{font=65,name="yumucy"},
|
||||
{font=65,name="[**昆]"},
|
||||
{font=65,name="[**浩]"},
|
||||
{font=65,name="sakurw"},
|
||||
{font=65,name="[**霖]"},
|
||||
{font=65,name="KK"},
|
||||
{font=65,name="武仰绍"},
|
||||
|
||||
{font=25,name="八零哥"},
|
||||
{font=25,name="蕴空之灵"},
|
||||
@@ -151,4 +153,9 @@ return {
|
||||
{font=25,name="电蜥蜴"},
|
||||
{font=25,name="浮芙fufu"},
|
||||
{font=25,name="NOname_awa"},
|
||||
{font=65,name="liaotianhao"},
|
||||
{font=65,name="Aquamarine"},
|
||||
{font=65,name="jacky"},
|
||||
{font=65,name="方块丶小刘"},
|
||||
{font=65,name="DX3906"},
|
||||
}
|
||||
|
||||
@@ -177,12 +177,12 @@ local function _drawField(P,showInvis)
|
||||
if P.falling==0 then-- Blocks only
|
||||
if ENV.upEdge then
|
||||
gc_setShader(shader_lighter)
|
||||
gc_translate(0,-4)
|
||||
gc_translate(0,-6)
|
||||
-- <drawRow>
|
||||
for j=start,min(start+21,#F) do _drawRow(texture,j,V[j],F[j]) end
|
||||
-- </drawRow>
|
||||
gc_setShader(shader_fieldSatur)
|
||||
gc_translate(0,4)
|
||||
gc_translate(0,6)
|
||||
else
|
||||
gc_setShader(shader_fieldSatur)
|
||||
end
|
||||
@@ -197,7 +197,7 @@ local function _drawField(P,showInvis)
|
||||
if ENV.upEdge then
|
||||
gc_push('transform')
|
||||
gc_setShader(shader_lighter)
|
||||
gc_translate(0,-4)
|
||||
gc_translate(0,-6)
|
||||
-- <drawRow>
|
||||
for j=start,min(start+21,#F) do
|
||||
while j==P.clearingRow[h] do
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
return {
|
||||
das=10,arr=2,
|
||||
dascut=0,dropcut=0,
|
||||
dascut=0,irscut=6,dropcut=0,
|
||||
sddas=2,sdarr=2,
|
||||
ihs=true,irs=true,ims=true,
|
||||
logicalIHS=true,logicalIRS=true,logicalIMS=true,
|
||||
|
||||
ghostType='gray',
|
||||
block=true,ghost=.3,center=1,
|
||||
@@ -40,7 +41,7 @@ return {
|
||||
RS='TRS',
|
||||
sequence='bag',
|
||||
seqData={1,2,3,4,5,6,7},
|
||||
skinSet='crystal_scf',
|
||||
skinSet='Crystal (Scf)',
|
||||
face=false,skin=false,
|
||||
mission=false,
|
||||
|
||||
@@ -62,10 +63,16 @@ return {
|
||||
mindas=0,minarr=0,minsdarr=0,
|
||||
noInitSZO=false,
|
||||
|
||||
mesDisp={},
|
||||
hook_drop={},
|
||||
hook_die={},
|
||||
task={},
|
||||
-- Some Events are registered in player/init.lua, see "tableNeedMerge"
|
||||
extraEvent={
|
||||
{'attack',4},
|
||||
},
|
||||
extraEventHandler={
|
||||
attack=function(P,P2,...)
|
||||
P:beAttacked(P2,...)
|
||||
end,
|
||||
},
|
||||
|
||||
eventSet="X",
|
||||
|
||||
bg='none',bgm='race',
|
||||
|
||||
@@ -236,17 +236,8 @@ local function _loadRemoteEnv(P,confStr)-- Load gameEnv
|
||||
end
|
||||
end
|
||||
end
|
||||
local function _mergeFuncTable(f,L)
|
||||
if type(f)=='function' then
|
||||
ins(L,f)
|
||||
elseif type(f)=='table' then
|
||||
for i=1,#f do
|
||||
ins(L,f[i])
|
||||
end
|
||||
end
|
||||
return L
|
||||
end
|
||||
local hooks = {
|
||||
local tableNeedMerge={
|
||||
'task',
|
||||
'mesDisp',
|
||||
'hook_left',
|
||||
'hook_left_manual',
|
||||
@@ -259,36 +250,63 @@ local hooks = {
|
||||
'hook_spawn',
|
||||
'hook_hold',
|
||||
'hook_die',
|
||||
'task'
|
||||
'extraEvent',
|
||||
}
|
||||
for _,k in next,tableNeedMerge do gameEnv0[k]={} end
|
||||
local function _mergeFuncTable(f,L)
|
||||
if type(f)=='function' then
|
||||
ins(L,f)
|
||||
elseif type(f)=='table' then
|
||||
for i=1,#f do
|
||||
ins(L,f[i])
|
||||
end
|
||||
end
|
||||
return L
|
||||
end
|
||||
local function _applyGameEnv(P)-- Finish gameEnv processing
|
||||
local ENV=P.gameEnv
|
||||
|
||||
-- Apply events
|
||||
for i=1,#hooks do
|
||||
ENV[hooks[i]]=_mergeFuncTable(ENV[hooks[i]],{})
|
||||
-- Create event tables
|
||||
for i=1,#tableNeedMerge do
|
||||
ENV[tableNeedMerge[i]]=_mergeFuncTable(ENV[tableNeedMerge[i]],{})
|
||||
end
|
||||
|
||||
-- Apply eventSet
|
||||
if ENV.eventSet and ENV.eventSet~="X" then
|
||||
if type(ENV.eventSet)=='string' then
|
||||
local eventSet=require('parts.eventsets.'..ENV.eventSet)
|
||||
if eventSet then
|
||||
for k,v in next,eventSet do
|
||||
if TABLE.find(hooks,k) then
|
||||
_mergeFuncTable(v,ENV[k])
|
||||
elseif type(v)=='table' then
|
||||
ENV[k]=TABLE.copy(v)
|
||||
while true do
|
||||
if not (ENV.eventSet and ENV.eventSet~="X") then
|
||||
break
|
||||
end
|
||||
if type(ENV.eventSet)~='string' then
|
||||
MES.new('warn',"Wrong event set type: "..type(ENV.eventSet))
|
||||
break
|
||||
end
|
||||
local eventSet=require('parts.eventsets.'..ENV.eventSet)
|
||||
if not eventSet then
|
||||
MES.new('warn',"No event set called: "..ENV.eventSet)
|
||||
break
|
||||
end
|
||||
for k,v in next,eventSet do
|
||||
if k=='extraEventHandler' then
|
||||
for ev,handler in next,v do
|
||||
if ENV.extraEventHandler[ev] then
|
||||
local prevHandler=ENV.extraEventHandler[ev]
|
||||
ENV.extraEventHandler[ev]=function(...)
|
||||
prevHandler(...)
|
||||
handler(...)
|
||||
end
|
||||
else
|
||||
ENV[k]=v
|
||||
ENV.extraEventHandler[ev]=handler
|
||||
end
|
||||
end
|
||||
elseif TABLE.find(tableNeedMerge,k) then
|
||||
_mergeFuncTable(v,ENV[k])
|
||||
elseif type(v)=='table' then
|
||||
ENV[k]=TABLE.copy(v)
|
||||
else
|
||||
MES.new('warn',"No event set called: "..ENV.eventSet)
|
||||
ENV[k]=v
|
||||
end
|
||||
else
|
||||
MES.new('warn',"Wrong event set type: "..type(ENV.eventSet))
|
||||
end
|
||||
break
|
||||
end
|
||||
|
||||
P._20G=ENV.drop==0
|
||||
|
||||
@@ -270,27 +270,61 @@ function Player:act_rotRight()
|
||||
if not self.control then return end
|
||||
if self.cur then
|
||||
self.ctrlCount=self.ctrlCount+1
|
||||
if self.bufferedIRS then
|
||||
-- Ensure IRS is spent before the rotation is processed so it doesn't throw things off.
|
||||
-- This is so that if you for instance, are holding left IRS and then rotate right, it doesn't process
|
||||
-- the left and right rotates in the reverse order.
|
||||
self.keyPressing[3]=false
|
||||
self:resolveIRS()
|
||||
self.keyPressing[3]=true
|
||||
end
|
||||
self:spin(1)
|
||||
self:_triggerEvent('hook_rotate',1)
|
||||
self.keyPressing[3]=false
|
||||
|
||||
-- Disable held inputs if IRS is off
|
||||
if not self.gameEnv.irs then
|
||||
self.keyPressing[3]=false
|
||||
end
|
||||
end
|
||||
end
|
||||
function Player:act_rotLeft()
|
||||
if not self.control then return end
|
||||
if self.cur then
|
||||
self.ctrlCount=self.ctrlCount+1
|
||||
if self.bufferedIRS then
|
||||
-- Ensure IRS is spent before the rotation is processed so it doesn't throw things off.
|
||||
-- This is so that if you for instance, are holding left IRS and then rotate right, it doesn't process
|
||||
-- the left and right rotates in the reverse order.
|
||||
self.keyPressing[4]=false
|
||||
self:resolveIRS()
|
||||
self.keyPressing[4]=true
|
||||
end
|
||||
self:spin(3)
|
||||
self:_triggerEvent('hook_rotate',3)
|
||||
self.keyPressing[4]=false
|
||||
-- Disable held inputs if IRS is off
|
||||
if not self.gameEnv.irs then
|
||||
self.keyPressing[4]=false
|
||||
end
|
||||
end
|
||||
end
|
||||
function Player:act_rot180()
|
||||
if not self.control then return end
|
||||
if self.cur then
|
||||
self.ctrlCount=self.ctrlCount+2
|
||||
if self.bufferedIRS then
|
||||
-- Ensure IRS is spent before the rotation is processed so it doesn't throw things off.
|
||||
-- This is so that if you for instance, are holding left IRS and then rotate right, it doesn't process
|
||||
-- the left and right rotates in the reverse order.
|
||||
self.keyPressing[5]=false
|
||||
self:resolveIRS()
|
||||
self.keyPressing[5]=true
|
||||
end
|
||||
self:spin(2)
|
||||
self:_triggerEvent('hook_rotate',2)
|
||||
self.keyPressing[5]=false
|
||||
-- Disable held inputs if IRS is off
|
||||
if not self.gameEnv.irs then
|
||||
self.keyPressing[5]=false
|
||||
end
|
||||
end
|
||||
end
|
||||
function Player:act_hardDrop()
|
||||
@@ -300,6 +334,10 @@ function Player:act_hardDrop()
|
||||
if self.lastPiece.autoLock and self.frameRun-self.lastPiece.frame<ENV.dropcut then
|
||||
SFX.play('drop_cancel',.3)
|
||||
else
|
||||
if self.bufferedIRS then
|
||||
-- If the player drops quicker than their IRS cut delay, make sure IRS still resolves.
|
||||
self:resolveIRS()
|
||||
end
|
||||
if self.curY>self.ghoY then
|
||||
self:createDropFX()
|
||||
self.curY=self.ghoY
|
||||
@@ -344,7 +382,10 @@ function Player:act_hold()
|
||||
if not self.control then return end
|
||||
if self.cur then
|
||||
if self:hold() then
|
||||
self.keyPressing[8]=false
|
||||
-- Disable held inputs if IHS is off
|
||||
if not self.gameEnv.ihs then
|
||||
self.keyPressing[8]=false
|
||||
end
|
||||
self:_triggerEvent('hook_hold')
|
||||
end
|
||||
end
|
||||
@@ -701,6 +742,40 @@ function Player:_triggerEvent(eventName)
|
||||
return true
|
||||
end
|
||||
end
|
||||
function Player:extraEvent(eventName,...)
|
||||
if not (self.gameEnv.extraEvent and self.gameEnv.extraEventHandler) then return end
|
||||
local list=self.gameEnv.extraEvent
|
||||
local eventID
|
||||
for i=1,#list do
|
||||
if list[i][1]==eventName then
|
||||
eventID=i
|
||||
break
|
||||
end
|
||||
end
|
||||
if not eventID then
|
||||
MES.new('warn',"Extra event '"..eventName.."' doesn't exist in this mode")
|
||||
return
|
||||
end
|
||||
|
||||
local SELF
|
||||
-- Trigger for all non-remote players
|
||||
for _,p in next,PLAYERS do
|
||||
if p.type~='remote' then
|
||||
if p.type=='human' then
|
||||
SELF=p
|
||||
end
|
||||
self.gameEnv.extraEventHandler[eventName](p,self,...)
|
||||
end
|
||||
end
|
||||
|
||||
ins(GAME.rep,SELF.frameRun)
|
||||
ins(GAME.rep,64+eventID)
|
||||
ins(GAME.rep,self.sid)
|
||||
local data={...}
|
||||
for i=1,#data do
|
||||
ins(GAME.rep,data[i])
|
||||
end
|
||||
end
|
||||
|
||||
function Player:getHolePos()-- Get a good garbage-line hole position
|
||||
if self.garbageBeneath==0 then
|
||||
@@ -833,34 +908,13 @@ function Player:ifoverlap(bk,x,y)
|
||||
end
|
||||
end
|
||||
end
|
||||
function Player:attack(R,send,time,line,fromStream)
|
||||
if GAME.net then
|
||||
if self.type=='human' then-- Local player attack others
|
||||
ins(GAME.rep,self.frameRun)
|
||||
ins(GAME.rep,
|
||||
R.sid+
|
||||
send*0x100+
|
||||
time*0x10000+
|
||||
line*0x100000000+
|
||||
0x2000000000000
|
||||
)
|
||||
self:createBeam(R,send)
|
||||
end
|
||||
if fromStream and R.type=='human' then-- Local player receiving lines
|
||||
ins(GAME.rep,R.frameRun)
|
||||
ins(GAME.rep,
|
||||
self.sid+
|
||||
send*0x100+
|
||||
time*0x10000+
|
||||
line*0x100000000+
|
||||
0x1000000000000
|
||||
)
|
||||
R:receive(self,send,time,line)
|
||||
end
|
||||
else
|
||||
R:receive(self,send,time,line)
|
||||
self:createBeam(R,send)
|
||||
end
|
||||
function Player:attack(R,send,time,line)
|
||||
self:extraEvent('attack',R.sid,send,time,line)
|
||||
end
|
||||
function Player:beAttacked(P2,sid,send,time,line)
|
||||
if self==P2 or self.sid~=sid then return end
|
||||
self:receive(P2,send,time,line)
|
||||
P2:createBeam(self,send)
|
||||
end
|
||||
function Player:receive(A,send,time,line)
|
||||
self.lastRecv=A
|
||||
@@ -1151,34 +1205,67 @@ function Player:resetBlock()-- Reset Block's position and execute I*S
|
||||
self.curY=y
|
||||
self.minY=y+sc[1]
|
||||
|
||||
local ENV=self.gameEnv
|
||||
|
||||
-- In the game settings, there are user-set control flags for irs,irs,ims
|
||||
-- These control in what way the user can buffer their rotate/hold/move inputs.
|
||||
-- (If enabled, they may hold these inputs from the previous piece instead of just Entry Delay)
|
||||
|
||||
-- And mode-set flags for logicalIRS,logicalIHS,logicalIMS
|
||||
-- These control whether IRS/IHS/IMS are effective in modifying what you can do.
|
||||
-- (For instance, changing your piece's spawn position in 20g, or saving you from a death).
|
||||
-- If logical IRS is disabled, the player may still IRS, but it will just buffer their input,
|
||||
-- not actually allowing them to survive in a way they could not without.
|
||||
|
||||
local pressing=self.keyPressing
|
||||
-- IMS
|
||||
if self.gameEnv.ims and (pressing[1] and self.movDir==-1 or pressing[2] and self.movDir==1) and self.moving>=self.gameEnv.das then
|
||||
local x=self.curX+self.movDir
|
||||
if not self:ifoverlap(C.bk,x,y) then
|
||||
self.curX=x
|
||||
-- IMS is enabled only when logicalIMS is enabled, because otherwise, it's just faster DAS.
|
||||
if ENV.logicalIMS and (pressing[1] and self.movDir==-1 or pressing[2] and self.movDir==1) and self.moving>=self.gameEnv.das then
|
||||
-- To avoid a top-out
|
||||
if self:ifoverlap(C.bk,self.curX,self.curY) then
|
||||
-- Always perform the shift, since you're topped out anyway
|
||||
self.curX=self.curX+self.movDir
|
||||
elseif ENV.wait>0 and ENV.ims then
|
||||
-- Otherwise, only check IMS if it's enabled and you're in a mode with entry delay (20g)
|
||||
local x=self.curX+self.movDir
|
||||
if not self:ifoverlap(C.bk,x,y) then
|
||||
self.curX=x
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- IRS
|
||||
if self.gameEnv.irs then
|
||||
if not ENV.logicalIRS then
|
||||
-- If logical IRS is disabled, all IRS inputs will be buffered to prevent survival.
|
||||
self.bufferedIRS=true
|
||||
self.bufferedDelay=0
|
||||
if ENV.wait==0 then
|
||||
self.bufferedDelay=ENV.irscut
|
||||
end
|
||||
elseif ENV.wait==0 and ENV.irscut>0 and not self:ifoverlap(C.bk,self.curX,self.curY) then
|
||||
-- If IRS cut delay is enabled and we aren't currently dying, buffer the input instead.
|
||||
self.bufferedIRS=true
|
||||
self.bufferedDelay=ENV.irscut
|
||||
else
|
||||
-- If we're currently dying or in an entry-delay mode (20g), perform the rotation right away.
|
||||
if pressing[5] then
|
||||
self:spin(2,true)
|
||||
self:act_rot180()
|
||||
elseif pressing[3] then
|
||||
if pressing[4] then
|
||||
self:spin(2,true)
|
||||
self:act_rot180()
|
||||
else
|
||||
self:spin(1,true)
|
||||
self:act_rotRight()
|
||||
end
|
||||
elseif pressing[4] then
|
||||
self:spin(3,true)
|
||||
self:act_rotLeft()
|
||||
end
|
||||
end
|
||||
-- Disable held inputs if IRS is off
|
||||
if not ENV.irs then
|
||||
pressing[3],pressing[4],pressing[5]=false,false,false
|
||||
end
|
||||
|
||||
-- DAS cut
|
||||
if self.gameEnv.dascut>0 then
|
||||
self.moving=self.moving-(self.moving>0 and 1 or -1)*self.gameEnv.dascut
|
||||
if ENV.dascut>0 then
|
||||
self.moving=self.moving-(self.moving>0 and 1 or -1)*ENV.dascut
|
||||
end
|
||||
|
||||
-- Spawn SFX
|
||||
@@ -1498,9 +1585,29 @@ function Player:_popNext(ifhold)-- Pop nextQueue to hand
|
||||
local pressing=self.keyPressing
|
||||
|
||||
-- IHS
|
||||
if not ifhold and pressing[8] and ENV.ihs and self.holdTime>0 then
|
||||
self:hold(true)
|
||||
pressing[8]=false
|
||||
if not ifhold and pressing[8] and self.holdTime>0 then
|
||||
if not ENV.logicalIHS then
|
||||
-- If logical IHS is disabled, all IHS inputs will be buffered to prevent survival.
|
||||
self.bufferedIRS=true
|
||||
self.bufferedIHS=true
|
||||
self.bufferedDelay=0
|
||||
if ENV.wait==0 then
|
||||
self.bufferedDelay=ENV.irscut
|
||||
end
|
||||
elseif ENV.wait==0 and ENV.irscut>0 and not self:willDieWith(self.cur) then
|
||||
-- If IRS cut delay is enabled and we're not currently dying, buffer the input instead.
|
||||
self.bufferedIRS=true
|
||||
self.bufferedIHS=true
|
||||
self.bufferedDelay=ENV.irscut
|
||||
self:resetBlock()
|
||||
else
|
||||
-- If we're currently dying or in an entry-delay mode (20g), perform the hold immediately.
|
||||
self:hold(true)
|
||||
end
|
||||
-- Disable held inputs if IHS is off
|
||||
if not ENV.ihs then
|
||||
pressing[8]=false
|
||||
end
|
||||
else
|
||||
self:resetBlock()
|
||||
end
|
||||
@@ -1814,7 +1921,7 @@ do
|
||||
end
|
||||
end
|
||||
|
||||
local yomi = ""
|
||||
local yomi=''
|
||||
|
||||
piece.spin,piece.mini=dospin,false
|
||||
piece.pc,piece.hpc=false,false
|
||||
@@ -1825,7 +1932,7 @@ do
|
||||
cscore=(spinSCR[C.name] or spinSCR[8])[cc]
|
||||
if self.b2b>800 then
|
||||
self:showText(text.b3b..text.block[C.name]..text.spin..text.clear[cc],0,-30,35,'stretch')
|
||||
yomi = yomi..text.b3b..text.block[C.name]..text.spin..text.clear[cc]
|
||||
yomi=yomi..text.b3b..text.block[C.name]..text.spin..text.clear[cc]
|
||||
atk=b2bATK[cc]+cc*.5
|
||||
exblock=exblock+1
|
||||
cscore=cscore*2
|
||||
@@ -1835,7 +1942,7 @@ do
|
||||
end
|
||||
elseif self.b2b>=50 then
|
||||
self:showText(text.b2b..text.block[C.name]..text.spin..text.clear[cc],0,-30,35,'spin')
|
||||
yomi = yomi..text.b2b..text.block[C.name]..text.spin..text.clear[cc]
|
||||
yomi=yomi..text.b2b..text.block[C.name]..text.spin..text.clear[cc]
|
||||
atk=b2bATK[cc]
|
||||
cscore=cscore*1.2
|
||||
Stat.b2b=Stat.b2b+1
|
||||
@@ -1844,13 +1951,13 @@ do
|
||||
end
|
||||
else
|
||||
self:showText(text.block[C.name]..text.spin..text.clear[cc],0,-30,45,'spin')
|
||||
yomi = yomi..text.block[C.name]..text.spin..text.clear[cc]
|
||||
yomi=yomi..text.block[C.name]..text.spin..text.clear[cc]
|
||||
atk=2*cc
|
||||
end
|
||||
sendTime=20+atk*20
|
||||
if mini then
|
||||
self:showText(text.mini,0,-80,35,'appear')
|
||||
yomi = text.mini..' '..yomi
|
||||
yomi=text.mini..' '..yomi
|
||||
atk=atk*.25
|
||||
sendTime=sendTime+60
|
||||
cscore=cscore*.5
|
||||
@@ -1871,7 +1978,7 @@ do
|
||||
cscore=clearSCR[cc]
|
||||
if self.b2b>800 then
|
||||
self:showText(text.b3b..text.clear[cc],0,-30,50,'fly')
|
||||
yomi = text.b3b..text.clear[cc]..yomi
|
||||
yomi=text.b3b..text.clear[cc]..yomi
|
||||
atk=4*cc-10
|
||||
sendTime=100
|
||||
exblock=exblock+1
|
||||
@@ -1882,7 +1989,7 @@ do
|
||||
end
|
||||
elseif self.b2b>=50 then
|
||||
self:showText(text.b2b..text.clear[cc],0,-30,50,'drive')
|
||||
yomi = text.b2b..text.clear[cc]..yomi
|
||||
yomi=text.b2b..text.clear[cc]..yomi
|
||||
sendTime=80
|
||||
atk=3*cc-7
|
||||
cscore=cscore*1.3
|
||||
@@ -1892,7 +1999,7 @@ do
|
||||
end
|
||||
else
|
||||
self:showText(text.clear[cc],0,-30,70,'stretch')
|
||||
yomi = text.clear[cc]..yomi
|
||||
yomi=text.clear[cc]..yomi
|
||||
sendTime=60
|
||||
atk=2*cc-4
|
||||
end
|
||||
@@ -1900,7 +2007,7 @@ do
|
||||
piece.special=true
|
||||
else
|
||||
self:showText(text.clear[cc],0,-30,35,'appear',(8-cc)*.3)
|
||||
yomi = text.clear[cc]..yomi
|
||||
yomi=text.clear[cc]..yomi
|
||||
atk=cc-.5
|
||||
sendTime=20+floor(atk*20)
|
||||
cscore=cscore+clearSCR[cc]
|
||||
@@ -1919,7 +2026,7 @@ do
|
||||
atk=atk+1
|
||||
end
|
||||
self:showText(text.cmb[min(cmb,21)],0,25,15+min(cmb,15)*5,cmb<10 and 'appear' or 'flicker')
|
||||
yomi = yomi..' '..text.cmb[min(cmb,21)]
|
||||
yomi=yomi..' '..text.cmb[min(cmb,21)]
|
||||
cscore=cscore+min(50*cmb,500)*(2*cc-1)
|
||||
end
|
||||
|
||||
@@ -2447,6 +2554,28 @@ local function _updateFX(P,dt)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Player:resolveIRS()
|
||||
if self.bufferedIHS then
|
||||
self:hold(true)
|
||||
self.bufferedIHS=false
|
||||
end
|
||||
|
||||
self.bufferedIRS=false
|
||||
local pressing=self.keyPressing
|
||||
if pressing[5] then
|
||||
self:act_rot180()
|
||||
elseif pressing[3] then
|
||||
if pressing[4] then
|
||||
self:act_rot180()
|
||||
else
|
||||
self:act_rotRight()
|
||||
end
|
||||
elseif pressing[4] then
|
||||
self:act_rotLeft()
|
||||
end
|
||||
end
|
||||
|
||||
local function update_alive(P,dt)
|
||||
local ENV=P.gameEnv
|
||||
|
||||
@@ -2505,6 +2634,18 @@ local function update_alive(P,dt)
|
||||
end
|
||||
end
|
||||
|
||||
-- Buffer IRS after IRS cut delay has elapsed.
|
||||
-- The purpose of this is to allow the player to release their rotate key during the IRS cut delay,
|
||||
-- which will allow them to avoid accidentally using IRS.
|
||||
if P.bufferedDelay then
|
||||
P.bufferedDelay=P.bufferedDelay-1
|
||||
if P.bufferedDelay<=0 then
|
||||
if P.bufferedIRS then
|
||||
P:resolveIRS()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Moving pressed
|
||||
if P.movDir~=0 then
|
||||
local das,arr=ENV.das,ENV.arr
|
||||
@@ -2701,44 +2842,32 @@ local function update_alive(P,dt)
|
||||
end
|
||||
local function update_streaming(P)
|
||||
local eventTime=P.stream[P.streamProgress]
|
||||
while eventTime and P.frameRun==eventTime do
|
||||
while eventTime and P.frameRun==eventTime or eventTime==0 do
|
||||
local event=P.stream[P.streamProgress+1]
|
||||
if event==0 then-- Just wait
|
||||
elseif event<=32 then-- Press key
|
||||
P:pressKey(event)
|
||||
elseif event<=64 then-- Release key
|
||||
P:releaseKey(event-32)
|
||||
elseif event>0x2000000000000 then-- Sending lines
|
||||
local sid=event%0x100
|
||||
local amount=floor(event/0x100)%0x100
|
||||
local time=floor(event/0x10000)%0x10000
|
||||
local line=floor(event/0x100000000)%0x10000
|
||||
for _,p in next,PLY_ALIVE do
|
||||
if p.sid==sid then
|
||||
P.netAtk=P.netAtk+amount
|
||||
if P.netAtk~=P.stat.send then-- He cheated or just desynchronized to death
|
||||
MES.new('warn',"#"..P.uid.." desynchronized")
|
||||
NET.player_finish({reason='desync'})
|
||||
P:lose(true)
|
||||
return
|
||||
end
|
||||
P:attack(p,amount,time,line,true)
|
||||
P:createBeam(p,amount)
|
||||
elseif event<=128 then-- Extra Event
|
||||
local eventName=P.gameEnv.extraEvent[event-64][1]
|
||||
local eventParamCount=P.gameEnv.extraEvent[event-64][2]
|
||||
local sourceSid=P.stream[P.streamProgress+2]
|
||||
local paramList={}
|
||||
for i=1,eventParamCount do
|
||||
ins(paramList,P.stream[P.streamProgress+2+i])
|
||||
end
|
||||
P.streamProgress=P.streamProgress+eventParamCount+1
|
||||
|
||||
local SRC
|
||||
for _,p in next,PLAYERS do
|
||||
if p.sid==sourceSid then
|
||||
SRC=p
|
||||
break
|
||||
end
|
||||
end
|
||||
elseif event>0x1000000000000 then-- Receiving lines
|
||||
local sid=event%0x100
|
||||
for _,p in next,PLY_ALIVE do
|
||||
if p.sid==sid then
|
||||
P:receive(
|
||||
p,
|
||||
floor(event/0x100)%0x100,-- amount
|
||||
floor(event/0x10000)%0x10000,-- time
|
||||
floor(event/0x100000000)%0x10000-- line
|
||||
)
|
||||
break
|
||||
end
|
||||
if SRC then
|
||||
P.gameEnv.extraEventHandler[eventName](P,SRC,unpack(paramList))
|
||||
end
|
||||
end
|
||||
P.streamProgress=P.streamProgress+2
|
||||
@@ -2801,7 +2930,7 @@ function Player:update(dt)
|
||||
end
|
||||
while self.trigFrame>=1 do
|
||||
if self.streamProgress then
|
||||
local frameDelta-- Time between now and end of stream
|
||||
local dataDelta -- How much data wating to be process
|
||||
if self.type=='remote' then
|
||||
if self.loseTimer then
|
||||
self.loseTimer=self.loseTimer-1
|
||||
@@ -2810,25 +2939,26 @@ function Player:update(dt)
|
||||
self:lose(true)
|
||||
end
|
||||
end
|
||||
frameDelta=(self.stream[#self.stream-1] or 0)-self.frameRun
|
||||
if frameDelta==0 then frameDelta=nil end
|
||||
dataDelta=#self.stream-self.streamProgress
|
||||
else
|
||||
frameDelta=0
|
||||
dataDelta=1
|
||||
end
|
||||
if frameDelta then
|
||||
if dataDelta>0 then
|
||||
for _=1,
|
||||
self.loseTimer and min(frameDelta,
|
||||
-- Speed up to finish
|
||||
self.loseTimer and min(dataDelta,
|
||||
self.loseTimer>16 and 2 or
|
||||
self.loseTimer>6.2 and 12 or
|
||||
self.loseTimer>2.6 and 260 or
|
||||
2600
|
||||
) or
|
||||
frameDelta<26 and 1 or
|
||||
frameDelta<50 and 2 or
|
||||
frameDelta<80 and 3 or
|
||||
frameDelta<120 and 5 or
|
||||
frameDelta<160 and 7 or
|
||||
frameDelta<200 and 10 or
|
||||
-- Chasing faster when slower
|
||||
dataDelta<26 and 1 or
|
||||
dataDelta<42 and 2 or
|
||||
dataDelta<62 and 3 or
|
||||
dataDelta<70.23 and 5 or
|
||||
dataDelta<94.2 and 7 or
|
||||
dataDelta<126 and 10 or
|
||||
20
|
||||
do
|
||||
update_streaming(self)
|
||||
@@ -2877,7 +3007,7 @@ function Player:revive()
|
||||
SFX.play('emit')
|
||||
end
|
||||
function Player:torikanEnd(requiredTime)
|
||||
if self.stat.time < requiredTime then
|
||||
if self.stat.time<requiredTime then
|
||||
return false
|
||||
end
|
||||
self:_die()
|
||||
|
||||
@@ -120,20 +120,17 @@ local seqGenerators={
|
||||
-- Pick a mino from pool
|
||||
local tryTime=0
|
||||
local r
|
||||
repeat-- ::REPEAT_pickAgain::
|
||||
local pickAgain
|
||||
repeat
|
||||
r=_poolPick()-- Random mino-index in pool
|
||||
local duplicated
|
||||
for i=1,len do
|
||||
if r==history[i] then
|
||||
tryTime=tryTime+1
|
||||
if tryTime<hisLen then
|
||||
pickAgain=true
|
||||
break-- goto REPEAT_pickAgain
|
||||
end
|
||||
duplicated=true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not pickAgain then break end
|
||||
until true
|
||||
tryTime=tryTime+1
|
||||
until not duplicated or tryTime>hisLen
|
||||
|
||||
-- Give mino to player & update history
|
||||
if history[1]~=0 then
|
||||
|
||||
@@ -29,6 +29,7 @@ function scene.enter()
|
||||
slide=true
|
||||
pathVis=true
|
||||
revKB=false
|
||||
DiscordRPC.update("Playing 15-Puzzle")
|
||||
end
|
||||
|
||||
local function moveU(x,y)
|
||||
|
||||
@@ -234,6 +234,7 @@ function scene.enter()
|
||||
tapControl=false
|
||||
startTime=0
|
||||
reset()
|
||||
DiscordRPC.update("Playing 2048")
|
||||
end
|
||||
|
||||
function scene.mouseDown(x,y,k)
|
||||
|
||||
@@ -40,6 +40,7 @@ function scene.enter()
|
||||
startTime=0
|
||||
time=0
|
||||
state=0
|
||||
DiscordRPC.update("Spamming keyboard")
|
||||
end
|
||||
|
||||
function scene.keyDown(key,isRep)
|
||||
|
||||
@@ -100,6 +100,7 @@ function scene.enter()
|
||||
restart()
|
||||
BGM.play('truth')
|
||||
BG.set('rainbow')
|
||||
DiscordRPC.update("Playing Ultimate Tic-Tac-Toe")
|
||||
end
|
||||
|
||||
function scene.mouseMove(x,y)
|
||||
|
||||
@@ -360,6 +360,7 @@ function scene.enter()
|
||||
drawing=false
|
||||
numScale=1
|
||||
BGM.play('truth')
|
||||
DiscordRPC.update("Playing Arithmetic")
|
||||
end
|
||||
|
||||
function scene.keyDown(key,isRep)
|
||||
|
||||
@@ -28,6 +28,7 @@ function scene.enter()
|
||||
BG.set('none')
|
||||
BGM.stop()
|
||||
reg,val,sym=false,"0",false
|
||||
DiscordRPC.update("Calculating something")
|
||||
end
|
||||
function scene.leave()
|
||||
BGM.play()
|
||||
|
||||
@@ -15,6 +15,7 @@ function scene.enter()
|
||||
ex,ey=626,260
|
||||
BG.set('matrix')
|
||||
BGM.play('hang out')
|
||||
DiscordRPC.update("Shooting cannon balls")
|
||||
end
|
||||
|
||||
function scene.keyDown(key,isRep)
|
||||
|
||||
@@ -1034,6 +1034,7 @@ userG.the_key=first_key
|
||||
function scene.enter()
|
||||
WIDGET.focus(inputBox)
|
||||
BG.set('none')
|
||||
DiscordRPC.update("Hacking the system")
|
||||
end
|
||||
|
||||
function scene.wheelMoved(_,y)
|
||||
|
||||
@@ -59,6 +59,7 @@ function scene.enter()
|
||||
gc.setLineJoin('bevel')
|
||||
BGM.play('push')
|
||||
BG.set('none')
|
||||
DiscordRPC.update("Playing Cubefield")
|
||||
end
|
||||
|
||||
function scene.touchDown(x)
|
||||
|
||||
@@ -38,6 +38,7 @@ function scene.enter()
|
||||
state='menu'
|
||||
BGM.play('hang out')
|
||||
BG.set('space')
|
||||
DiscordRPC.update("Playing Dropper")
|
||||
end
|
||||
|
||||
function scene.keyDown(key,isRep)
|
||||
|
||||
@@ -201,6 +201,7 @@ function scene.enter()
|
||||
reset()
|
||||
BG.set('fixColor',.26,.26,.26)
|
||||
BGM.play(bgm)
|
||||
DiscordRPC.update("Avoiding touching white tiles")
|
||||
end
|
||||
|
||||
local function touch(n)
|
||||
|
||||
@@ -249,6 +249,7 @@ function scene.enter()
|
||||
invis=false
|
||||
newGame()
|
||||
BGM.play('truth')
|
||||
DiscordRPC.update("Playing Link")
|
||||
end
|
||||
|
||||
function scene.keyDown(key,isRep)
|
||||
|
||||
@@ -109,6 +109,7 @@ function scene.enter()
|
||||
BG.set('fixColor',.26,.62,.26)
|
||||
_newGame()
|
||||
selected=false
|
||||
DiscordRPC.update("Playing Mahjong")
|
||||
end
|
||||
|
||||
function scene.mouseMove(x,y)
|
||||
|
||||
@@ -36,6 +36,7 @@ function scene.enter()
|
||||
input=''
|
||||
showNum='memoriZe'
|
||||
BGM.play('reason')
|
||||
DiscordRPC.update("Playing memoriZe")
|
||||
end
|
||||
|
||||
function scene.keyDown(key,isRep)
|
||||
|
||||
@@ -95,6 +95,7 @@ function scene.enter()
|
||||
generateVKey()
|
||||
_notHoldCS()
|
||||
_showVirtualKey(MOBILE)
|
||||
DiscordRPC.update("Playing music")
|
||||
end
|
||||
|
||||
function scene.leave()
|
||||
|
||||
@@ -40,6 +40,7 @@ function scene.enter()
|
||||
end
|
||||
BG.set('none')
|
||||
BGM.play('dream')
|
||||
DiscordRPC.update("Playing polyforge")
|
||||
end
|
||||
|
||||
function scene.keyDown(key,isRep)
|
||||
|
||||
@@ -35,6 +35,7 @@ function scene.enter()
|
||||
vy=0,
|
||||
y0=false,
|
||||
}
|
||||
DiscordRPC.update("Playing Pong")
|
||||
end
|
||||
|
||||
local function start()
|
||||
|
||||
@@ -18,6 +18,7 @@ end
|
||||
function scene.enter()
|
||||
reset()
|
||||
BG.set('none')
|
||||
DiscordRPC.update("Playing Reflect")
|
||||
end
|
||||
|
||||
function scene.keyDown(key,isRep)
|
||||
|
||||
@@ -25,6 +25,7 @@ function scene.enter()
|
||||
mistake=0
|
||||
state=0
|
||||
progress=0
|
||||
DiscordRPC.update("Playing Schulte Grid")
|
||||
end
|
||||
|
||||
local function newBoard()
|
||||
|
||||
@@ -15,6 +15,10 @@ end)
|
||||
|
||||
local scene={}
|
||||
|
||||
function scene.enter()
|
||||
DiscordRPC.update("Playing a non-sense thing")
|
||||
end
|
||||
|
||||
function scene.keyDown(key,isRep)
|
||||
if isRep then return end
|
||||
if key=='space' or key=='return' then
|
||||
|
||||