Compare commits
21 Commits
pre0.17.0-
...
pre0.17.0-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13d98be051 | ||
|
|
a350ff3182 | ||
|
|
e0360cc7eb | ||
|
|
4249a29b63 | ||
|
|
43b2a0a8c8 | ||
|
|
6d6584f99e | ||
|
|
077c651226 | ||
|
|
3fc872aa76 | ||
|
|
cb0b347a38 | ||
|
|
d08967c688 | ||
|
|
3666c0caa9 | ||
|
|
4ef179fccb | ||
|
|
861f9b3caa | ||
|
|
05292df456 | ||
|
|
9fed692223 | ||
|
|
b1c04c1fea | ||
|
|
bc9adc2cd3 | ||
|
|
cdf149afca | ||
|
|
73145b4e5e | ||
|
|
f8b9f30fd6 | ||
|
|
e6bc567b12 |
@@ -24,6 +24,9 @@ end
|
||||
function BG.getList()
|
||||
return BGlist
|
||||
end
|
||||
function BG.remList(name)
|
||||
table.remove(BGlist,TABLE.find(BGlist,name))
|
||||
end
|
||||
function BG.send(...)
|
||||
if BG.event then
|
||||
BG.event(...)
|
||||
|
||||
@@ -74,7 +74,7 @@ local xOy=SCR.xOy
|
||||
local ITP=xOy.inverseTransformPoint
|
||||
local max,min=math.max,math.min
|
||||
|
||||
local mx,my,mouseShow,cursorSpd=-20,-20,false,0
|
||||
local mx,my,mouseShow,cursorSpd=640,360,false,0
|
||||
local jsState={}--map, joystickID->axisStates: {axisName->axisVal}
|
||||
local errData={}--list, each error create {mes={errMes strings},scene=sceneNameStr}
|
||||
|
||||
@@ -154,7 +154,7 @@ local function _triggerMouseDown(x,y,k)
|
||||
lastX,lastY=x,y
|
||||
if SETTING.clickFX then SYSFX.newTap(3,x,y)end
|
||||
end
|
||||
local function _mouse_update(dt)
|
||||
local function mouse_update(dt)
|
||||
if not KBisDown('lctrl','rctrl')and KBisDown('up','down','left','right')then
|
||||
local dx,dy=0,0
|
||||
if KBisDown('up')then dy=dy-cursorSpd end
|
||||
@@ -173,6 +173,26 @@ local function _mouse_update(dt)
|
||||
cursorSpd=6
|
||||
end
|
||||
end
|
||||
local function gp_update(js,dt)
|
||||
local sx,sy=js._jsObj:getGamepadAxis('leftx'),js._jsObj:getGamepadAxis('lefty')
|
||||
if math.abs(sx)>.1 or math.abs(sy)>.1 then
|
||||
local dx,dy=0,0
|
||||
if sy<-.1 then dy=dy+2*sy*cursorSpd end
|
||||
if sy>.1 then dy=dy+2*sy*cursorSpd end
|
||||
if sx<-.1 then dx=dx+2*sx*cursorSpd end
|
||||
if sx>.1 then dx=dx+2*sx*cursorSpd end
|
||||
mx=max(min(mx+dx,1280),0)
|
||||
my=max(min(my+dy,720),0)
|
||||
if my==0 or my==720 then
|
||||
WIDGET.sel=false
|
||||
WIDGET.drag(0,0,0,-dy)
|
||||
end
|
||||
_updateMousePos(mx,my,dx,dy)
|
||||
cursorSpd=min(cursorSpd+dt*26,12.6)
|
||||
else
|
||||
cursorSpd=6
|
||||
end
|
||||
end
|
||||
function love.mousepressed(x,y,k,touch)
|
||||
if touch then return end
|
||||
mouseShow=true
|
||||
@@ -347,35 +367,38 @@ local dPadToKey={
|
||||
back='escape',
|
||||
}
|
||||
function love.joystickadded(JS)
|
||||
jsState[JS:getID()]={
|
||||
_loveJSObj=JS,
|
||||
table.insert(jsState,{
|
||||
_id=JS:getID(),
|
||||
_jsObj=JS,
|
||||
leftx=0,lefty=0,
|
||||
rightx=0,righty=0,
|
||||
triggerleft=0,triggerright=0
|
||||
}
|
||||
})
|
||||
MES.new('info',"Joystick added")
|
||||
end
|
||||
function love.joystickremoved(JS)
|
||||
local js=jsState[JS:getID()]
|
||||
if js then
|
||||
for i=1,#gamePadKeys do
|
||||
if JS:isGamepadDown(gamePadKeys[i])then
|
||||
love.gamepadreleased(JS,gamePadKeys[i])
|
||||
for i=1,#jsState do
|
||||
if jsState[i]._jsObj==JS then
|
||||
for j=1,#gamePadKeys do
|
||||
if JS:isGamepadDown(gamePadKeys[j])then
|
||||
love.gamepadreleased(JS,gamePadKeys[j])
|
||||
end
|
||||
end
|
||||
love.gamepadaxis(JS,'leftx',0)
|
||||
love.gamepadaxis(JS,'lefty',0)
|
||||
love.gamepadaxis(JS,'rightx',0)
|
||||
love.gamepadaxis(JS,'righty',0)
|
||||
love.gamepadaxis(JS,'triggerleft',-1)
|
||||
love.gamepadaxis(JS,'triggerright',-1)
|
||||
MES.new('info',"Joystick removed")
|
||||
table.remove(jsState,i)
|
||||
break
|
||||
end
|
||||
love.gamepadaxis(JS,'leftx',0)
|
||||
love.gamepadaxis(JS,'lefty',0)
|
||||
love.gamepadaxis(JS,'rightx',0)
|
||||
love.gamepadaxis(JS,'righty',0)
|
||||
love.gamepadaxis(JS,'triggerleft',-1)
|
||||
love.gamepadaxis(JS,'triggerright',-1)
|
||||
jsState[JS:getID()]=nil
|
||||
MES.new('info',"Joystick removed")
|
||||
end
|
||||
end
|
||||
function love.gamepadaxis(JS,axis,val)
|
||||
local js=jsState[JS:getID()]
|
||||
if js then
|
||||
if JS==jsState[1]._jsObj then
|
||||
local js=jsState[1]
|
||||
if axis=='leftx'or axis=='lefty'or axis=='rightx'or axis=='righty'then
|
||||
local newVal=--range: [0,1]
|
||||
val>.4 and 1 or
|
||||
@@ -395,7 +418,7 @@ function love.gamepadaxis(JS,axis,val)
|
||||
js[axis]=newVal
|
||||
end
|
||||
elseif axis=='triggerleft'or axis=='triggerright'then
|
||||
local newVal=val>-.3 and 1 or 0--range: [-1,1]
|
||||
local newVal=val>.3 and 1 or 0--range: [0,1]
|
||||
if newVal~=js[axis]then
|
||||
if newVal==1 then
|
||||
love.gamepadpressed(JS,jsAxisEventName[axis])
|
||||
@@ -622,7 +645,6 @@ function love.run()
|
||||
local TASK_update=TASK.update
|
||||
local SYSFX_update,SYSFX_draw=SYSFX.update,SYSFX.draw
|
||||
local WIDGET_update,WIDGET_draw=WIDGET.update,WIDGET.draw
|
||||
local VOC_update,BG_update=VOC.update,BG.update
|
||||
local STEP,WAIT=love.timer.step,love.timer.sleep
|
||||
local FPS,MINI=love.timer.getFPS,love.window.isMinimized
|
||||
local PUMP,POLL=love.event.pump,love.event.poll
|
||||
@@ -661,9 +683,10 @@ function love.run()
|
||||
|
||||
--UPDATE
|
||||
STEP()
|
||||
if mouseShow then _mouse_update(dt)end
|
||||
VOC_update()
|
||||
BG_update(dt)
|
||||
if mouseShow then mouse_update(dt)end
|
||||
if next(jsState)then gp_update(jsState[1],dt)end
|
||||
VOC.update()
|
||||
BG.update(dt)
|
||||
TEXT_update(dt)
|
||||
MES_update(dt)
|
||||
WS_update(dt)
|
||||
|
||||
@@ -16,7 +16,6 @@ local next=next
|
||||
local int,ceil=math.floor,math.ceil
|
||||
local max,min=math.max,math.min
|
||||
local sub,ins,rem=string.sub,table.insert,table.remove
|
||||
local mDraw,mDraw_X,mDraw_Y=GC.draw,GC.simpX,GC.simpY
|
||||
local xOy=SCR.xOy
|
||||
local FONT=FONT
|
||||
local mStr=GC.mStr
|
||||
@@ -74,7 +73,7 @@ function text:draw()
|
||||
local c=self.color
|
||||
gc_setColor(c[1],c[2],c[3],self.alpha)
|
||||
if self.align=='M'then
|
||||
mDraw_X(self.obj,self.x,self.y)
|
||||
gc_draw(self.obj,self.x-self.obj:getWidth()*.5,self.y)
|
||||
elseif self.align=='L'then
|
||||
gc_draw(self.obj,self.x,self.y)
|
||||
elseif self.align=='R'then
|
||||
@@ -181,32 +180,34 @@ function button:draw()
|
||||
|
||||
--Drawable
|
||||
local obj=self.obj
|
||||
local ox,oy=obj:getWidth()*.5,obj:getHeight()*.5
|
||||
local y0=y+h*.5-ATV*.5
|
||||
gc_setColor(1,1,1,.2+ATV*.05)
|
||||
if self.align=='M'then
|
||||
local x0=x+w*.5
|
||||
mDraw(obj,x0-1,y0-1)
|
||||
mDraw(obj,x0-1,y0+1)
|
||||
mDraw(obj,x0+1,y0-1)
|
||||
mDraw(obj,x0+1,y0+1)
|
||||
local kx=obj:type()=='Text'and min(w/ox/2,1)or 1
|
||||
gc_draw(obj,x0-1,y0-1,nil,kx,1,ox,oy)
|
||||
gc_draw(obj,x0-1,y0+1,nil,kx,1,ox,oy)
|
||||
gc_draw(obj,x0+1,y0-1,nil,kx,1,ox,oy)
|
||||
gc_draw(obj,x0+1,y0+1,nil,kx,1,ox,oy)
|
||||
gc_setColor(r*.55,g*.55,b*.55)
|
||||
mDraw(obj,x0,y0)
|
||||
gc_draw(obj,x0,y0,nil,kx,1,ox,oy)
|
||||
elseif self.align=='L'then
|
||||
local edge=self.edge
|
||||
mDraw_Y(obj,x+edge-1,y0-1)
|
||||
mDraw_Y(obj,x+edge-1,y0+1)
|
||||
mDraw_Y(obj,x+edge+1,y0-1)
|
||||
mDraw_Y(obj,x+edge+1,y0+1)
|
||||
gc_draw(obj,x+edge-1,y0-1-oy)
|
||||
gc_draw(obj,x+edge-1,y0+1-oy)
|
||||
gc_draw(obj,x+edge+1,y0-1-oy)
|
||||
gc_draw(obj,x+edge+1,y0+1-oy)
|
||||
gc_setColor(r*.55,g*.55,b*.55)
|
||||
mDraw_Y(obj,x+edge,y0)
|
||||
gc_draw(obj,x+edge,y0-oy)
|
||||
elseif self.align=='R'then
|
||||
local x0=x+w-self.edge-obj:getWidth()
|
||||
mDraw_Y(obj,x0-1,y0-1)
|
||||
mDraw_Y(obj,x0-1,y0+1)
|
||||
mDraw_Y(obj,x0+1,y0-1)
|
||||
mDraw_Y(obj,x0+1,y0+1)
|
||||
local x0=x+w-self.edge-ox*2
|
||||
gc_draw(obj,x0-1,y0-1-oy)
|
||||
gc_draw(obj,x0-1,y0+1-oy)
|
||||
gc_draw(obj,x0+1,y0-1-oy)
|
||||
gc_draw(obj,x0+1,y0+1-oy)
|
||||
gc_setColor(r*.55,g*.55,b*.55)
|
||||
mDraw_Y(obj,x0,y0)
|
||||
gc_draw(obj,x0,y0-oy)
|
||||
end
|
||||
end
|
||||
function button:getInfo()
|
||||
@@ -311,11 +312,11 @@ function key:draw()
|
||||
if self.fShade then
|
||||
gc_setColor(r,g,b,ATV*.25)
|
||||
if align=='M'then
|
||||
mDraw(self.fShade,x+w*.5,y+h*.5)
|
||||
gc_draw(self.fShade,x+w*.5-self.fShade:getWidth()*.5,y+h*.5-self.fShade:getHeight()*.5)
|
||||
elseif align=='L'then
|
||||
mDraw_Y(self.fShade,x+self.edge,y+h*.5)
|
||||
gc_draw(self.fShade,x+self.edge,y+h*.5-self.fShade:getHeight()*.5)
|
||||
elseif align=='R'then
|
||||
mDraw_Y(self.fShade,x+w-self.edge-self.fShade:getWidth(),y+h*.5)
|
||||
gc_draw(self.fShade,x+w-self.edge-self.fShade:getWidth(),y+h*.5-self.fShade:getHeight()*.5)
|
||||
end
|
||||
else
|
||||
gc_setColor(1,1,1,ATV*.05)
|
||||
@@ -323,13 +324,16 @@ function key:draw()
|
||||
end
|
||||
|
||||
--Drawable
|
||||
local obj=self.obj
|
||||
local ox,oy=obj:getWidth()*.5,obj:getHeight()*.5
|
||||
gc_setColor(r,g,b)
|
||||
if align=='M'then
|
||||
mDraw(self.obj,x+w*.5,y+h*.5)
|
||||
local kx=obj:type()=='Text'and min(w/ox/2,1)or 1
|
||||
gc_draw(obj,x+w*.5,y+h*.5,nil,kx,1,ox,oy)
|
||||
elseif align=='L'then
|
||||
mDraw_Y(self.obj,x+self.edge,y+h*.5)
|
||||
gc_draw(obj,x+self.edge,y-oy+h*.5)
|
||||
elseif align=='R'then
|
||||
mDraw_Y(self.obj,x+w-self.edge-self.obj:getWidth(),y+h*.5)
|
||||
gc_draw(obj,x+w-self.edge-ox*2,y-oy+h*.5)
|
||||
end
|
||||
end
|
||||
function key:getInfo()
|
||||
@@ -438,7 +442,7 @@ end
|
||||
function switch:press()
|
||||
self.code()
|
||||
if self.sound then
|
||||
SFX.play('touch')
|
||||
SFX.play(self.disp()and'check'or'uncheck')
|
||||
end
|
||||
end
|
||||
function WIDGET.newSwitch(D)--name,x,y[,lim][,fText][,color][,font=30][,fType][,sound=true][,disp][,code][,hideF][,hide]
|
||||
@@ -749,7 +753,7 @@ function selector:press(x)
|
||||
self.select=s
|
||||
self.selText=self.list[s]
|
||||
if self.sound then
|
||||
SFX.play('prerotate')
|
||||
SFX.play('selector')
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -769,7 +773,7 @@ function selector:scroll(n)
|
||||
self.select=s
|
||||
self.selText=self.list[s]
|
||||
if self.sound then
|
||||
SFX.play('prerotate')
|
||||
SFX.play('selector')
|
||||
end
|
||||
end
|
||||
function selector:arrowKey(k)
|
||||
@@ -870,7 +874,7 @@ function inputBox:draw()
|
||||
local f=self.font
|
||||
FONT.set(f,self.fType)
|
||||
if self.obj then
|
||||
mDraw_Y(self.obj,x-12-self.obj:getWidth(),y+h*.5)
|
||||
gc_draw(self.obj,x-12-self.obj:getWidth(),y+h*.5-self.obj:getHeight()*.5)
|
||||
end
|
||||
if self.secret then
|
||||
y=y+h*.5-f*.2
|
||||
@@ -1160,7 +1164,7 @@ function listBox:press(x,y)
|
||||
if self.list[y]then
|
||||
if self.selected~=y then
|
||||
self.selected=y
|
||||
SFX.play('click',.4)
|
||||
SFX.play('selector',.8,0,12)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1387,7 +1391,7 @@ function WIDGET.textinput(texts)
|
||||
WIDGET.sel.value=WIDGET.sel.value..texts
|
||||
SFX.play('touch')
|
||||
else
|
||||
SFX.play('finesseError',.3)
|
||||
SFX.play('drop_cancel')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
1
main.lua
1
main.lua
@@ -380,6 +380,7 @@ for _,v in next,fs.getDirectoryItems('parts/backgrounds')do
|
||||
BG.add(name,require('parts.backgrounds.'..name))
|
||||
end
|
||||
end
|
||||
BG.remList('none')BG.remList('gray')BG.remList('custom')
|
||||
--Load scene files from SOURCE ONLY
|
||||
for _,v in next,fs.getDirectoryItems('parts/scenes')do
|
||||
if isSafeFile('parts/scenes/'..v)then
|
||||
|
||||
Binary file not shown.
BIN
media/effect/chiptune/check.ogg
Normal file
BIN
media/effect/chiptune/check.ogg
Normal file
Binary file not shown.
Binary file not shown.
BIN
media/effect/chiptune/selector.ogg
Normal file
BIN
media/effect/chiptune/selector.ogg
Normal file
Binary file not shown.
BIN
media/effect/chiptune/uncheck.ogg
Normal file
BIN
media/effect/chiptune/uncheck.ogg
Normal file
Binary file not shown.
@@ -1,16 +1,31 @@
|
||||
--Secret custom background
|
||||
local gc=love.graphics
|
||||
local gc_clear,gc_setColor=love.graphics.clear,love.graphics.setColor
|
||||
local back={}
|
||||
|
||||
local image=false
|
||||
local alpha=.26
|
||||
|
||||
local mx,my,k
|
||||
|
||||
function back.init()
|
||||
back.resize()
|
||||
end
|
||||
function back.resize()
|
||||
mx,my=SCR.w*.5,SCR.h*.5
|
||||
if image then
|
||||
k=math.max(SCR.w/image:getWidth(),SCR.h/image:getHeight())
|
||||
end
|
||||
end
|
||||
function back.draw()
|
||||
gc.clear(.1,.1,.1)
|
||||
gc.setColor(1,1,1,alpha)
|
||||
local k=math.max(SCR.w/image:getWidth(),SCR.h/image:getHeight())
|
||||
mDraw(image,SCR.w*.5,SCR.h*.5,nil,k)
|
||||
gc_clear(.1,.1,.1)
|
||||
if image then
|
||||
gc_setColor(1,1,1,alpha)
|
||||
mDraw(image,mx,my,nil,k)
|
||||
end
|
||||
end
|
||||
function back.event(a,img)
|
||||
if a then alpha=a end
|
||||
if img then image=img end
|
||||
back.resize()
|
||||
end
|
||||
return back
|
||||
|
||||
@@ -119,13 +119,17 @@ function applyBG()
|
||||
BG.lock()
|
||||
elseif SETTING.bg=='custom'then
|
||||
if love.filesystem.getInfo('conf/customBG')then
|
||||
BG.unlock()
|
||||
BG.set('custom')
|
||||
gc.setDefaultFilter('linear','linear')
|
||||
local image=gc.newImage(love.filesystem.newFile('conf/customBG'))
|
||||
gc.setDefaultFilter('nearest','nearest')
|
||||
BG.send(SETTING.bgAlpha,image)
|
||||
BG.lock()
|
||||
local res,image=pcall(gc.newImage,love.filesystem.newFile('conf/customBG'))
|
||||
if res then
|
||||
BG.unlock()
|
||||
BG.set('custom')
|
||||
gc.setDefaultFilter('linear','linear')
|
||||
BG.send(SETTING.bgAlpha,image)
|
||||
gc.setDefaultFilter('nearest','nearest')
|
||||
BG.lock()
|
||||
else
|
||||
MES.new('error',text.customBGloadFailed)
|
||||
end
|
||||
else
|
||||
SETTING.bg='off'
|
||||
applyBG()
|
||||
|
||||
@@ -744,7 +744,7 @@ return{
|
||||
"For advanced players who want to play faster, the recommended values are DAS 4-6f (67-100ms), ARR 0f (0ms). (At 0ms ARR, pieces will instantly snap to the wall once you get past DAS.)\n\nThe ideal configuration strategy for advanced players is to minimize DAS while still being able to reliably control whether to tap or hold, and to set to ARR to 0 if possible, or as low as possible otherwise.",
|
||||
},
|
||||
{"DAS cut",
|
||||
"dascut",
|
||||
"dascut dcd",
|
||||
"term",
|
||||
"Techmino exclusive: in Techmino, the DAS timer can be cleared or discharged for a short time when the player starts to control a new piece. This can reduce the case where a piece instantly starts moving if spawned with a direction button held.\n\nOther games may have a similar feature but may function differently.",
|
||||
},
|
||||
|
||||
@@ -548,35 +548,35 @@ return{
|
||||
"term",
|
||||
"主流方块游戏中七种块的颜色会使用同一套彩虹配色:\nZ:红 S:绿 J:蓝 L:橙 T:紫 O:黄 I:青\n\nTechmino默认也使用这一套“标准”配色。",
|
||||
},
|
||||
{"IRS",
|
||||
{"提前旋转 IRS",
|
||||
"提前 irs initialrotatesystem",
|
||||
"term",
|
||||
"Initial Rotation System\n提前旋转系统,方块出现前提前按下旋转后,出现时就是转好的形状,有时可以避免死亡。",
|
||||
"Initial Rotation System 提前旋转系统\n方块出现前提前按下旋转后,出现时就是转好的形状,有时可以避免死亡。",
|
||||
},
|
||||
{"IHS",
|
||||
{"提前暂存 IHS",
|
||||
"提前 ihs initialholdsystem",
|
||||
"term",
|
||||
"Initial Hold System\n提前Hold系统,方块出现前提前按下hold后,直接出现hold里的方块,有时可以避免死亡。",
|
||||
"Initial Hold System 提前Hold系统\n方块出现前提前按下hold后,直接出现hold里的方块,有时可以避免死亡。",
|
||||
},
|
||||
{"IMS",
|
||||
{"提前移动 IMS",
|
||||
"提前 ims initialmovesystem",
|
||||
"term",
|
||||
"Initial Move System\n提前移动系统,方块出现前提前按住移动后,出现时会朝移动方向偏一格,有时可以避免死亡(Techmino限定)。\n注:需要块出现时das已充满",
|
||||
"Initial Move System 提前移动系统\n方块出现前提前按住移动后,出现时会朝移动方向偏一格,有时可以避免死亡(Techmino限定)。\n注:需要块出现时das已充满",
|
||||
},
|
||||
{"Next",
|
||||
{"预览 Next",
|
||||
"预览 下一个 next yulan xiayige",
|
||||
"term",
|
||||
"预览功能,指示后边几个块的顺序。\n提前思考手上这块怎么摆可以让后面轻松是玩家提升的必需技能。\n\n关于玩家玩的时候到底看了几个Next:这个数字并不固定,不同玩家、不同模式、不同局面,计算next的数量都不一样,通过调整可见Next数量打40L比较时间等方式测得的数据并不准确。\n\n具体例如,一个比较熟练的玩家几乎永远会提前算好一个Next,不然不会锁定手里的块;场地上将要出现或可以构造消四洞(T坑)的时候会找最近的I(T)什么时候来,如果太远了就会直接挖掉放弃本次攻击以防被对手偷袭。这两种情况并不独立,有很多介于中间的情况。所以,一个玩家看的Next数量是时刻在变的,“某人看几个Next”没有精确答案,必须在指明情况的时候数字才能作为参考。",
|
||||
"指示后边几个块的顺序。\n提前思考手上这块怎么摆可以让后面轻松是玩家提升的必需技能。\n\n关于玩家玩的时候到底看了几个Next:这个数字并不固定,不同玩家、不同模式、不同局面,计算next的数量都不一样,通过调整可见Next数量打40L比较时间等方式测得的数据并不准确。\n\n具体例如,一个比较熟练的玩家几乎永远会提前算好一个Next,不然不会锁定手里的块;场地上将要出现或可以构造消四洞(T坑)的时候会找最近的I(T)什么时候来,如果太远了就会直接挖掉放弃本次攻击以防被对手偷袭。这两种情况并不独立,有很多介于中间的情况。所以,一个玩家看的Next数量是时刻在变的,“某人看几个Next”没有精确答案,必须在指明情况的时候数字才能作为参考。",
|
||||
},
|
||||
{"Hold",
|
||||
{"暂存 Hold",
|
||||
"暂存 交换 hold zancun",
|
||||
"term",
|
||||
"暂存功能,将手里的方块和Hold槽中的交换,一般不能连续使用。\n用来调整块序,更容易摆出你想要的形状。\n本游戏中有一个“物理hold”机制,开启后hold换出的方块会直接出现在当前方块所在的位置\n\n用不用hold各有好处,不用的话看到序列是什么就是什么,减少了思考量;并且减少了按键的种类,操作简单容易提升KPS,有些人的40L记录就是不用Hold打出的。用Hold可以灵活地调整序列,减少高重力等规则带来的难度,算力足够的情况下可以达成更复杂的目标,甚至反过来显著减少总按键数。",
|
||||
"将手里的方块和Hold槽中的交换,一般不能连续使用。\n用来调整块序,更容易摆出你想要的形状。\n本游戏中有一个“物理hold”机制,开启后hold换出的方块会直接出现在当前方块所在的位置\n\n用不用hold各有好处,不用的话看到序列是什么就是什么,减少了思考量;并且减少了按键的种类,操作简单容易提升KPS,有些人的40L记录就是不用Hold打出的。用Hold可以灵活地调整序列,减少高重力等规则带来的难度,算力足够的情况下可以达成更复杂的目标,甚至反过来显著减少总按键数。",
|
||||
},
|
||||
{"Swap",
|
||||
{"置换 Swap",
|
||||
"交换 swap hold jiaohuan zancun",
|
||||
"term",
|
||||
"交换功能,Hold的另一种表现形式,将手里的方块和Next槽中的第一个交换,一般同样不能连续使用。",
|
||||
"Hold的另一种表现形式,将手里的方块和Next槽中的第一个交换,一般同样不能连续使用。",
|
||||
},
|
||||
{"深降",
|
||||
"深降 deepdrop shenjiang",
|
||||
@@ -598,12 +598,12 @@ return{
|
||||
"term",
|
||||
"在……之下\n用于表示成绩,单位一般可不写,比如40L成绩Sub 30是秒,1000行Sub 15是分钟,不写项目默认是40L\n\n例:39.95s是Sub 40,40.**s不是Sub 40。\n请不要使用Sub 62之类的词,因为sub本身就是表示大约, 一分钟左右的成绩精确到5~10s就可以了,一般30s以内的成绩用sub** 的时候才会精确到1s。",
|
||||
},
|
||||
{"挖掘",
|
||||
{"挖掘 Dig",
|
||||
"挖掘 dig downstack ds wajue",
|
||||
"term",
|
||||
"指消除从场地底部进入的垃圾行(对手攻击打过来或者模式中自动生成)。",
|
||||
},
|
||||
{"捐赠",
|
||||
{"捐赠 Donate",
|
||||
"捐赠 捐献 donate juanzeng",
|
||||
"term",
|
||||
"指刻意临时堵住(可以消四的)洞做T-spin,打出T-spin后就会解开,是比较进阶的保持/提升火力的技巧。\n不标准用法:有时候只要堵住了个坑,即使不是消四洞也会用这个词。",
|
||||
@@ -618,7 +618,7 @@ return{
|
||||
"term",
|
||||
"通过消除给对手发送垃圾行=攻击\n别人打过来攻击之后用攻击抵消=防御(相杀)\n抵消/吃下所有攻击后打出攻击=反击\n\n注:大多游戏的攻防是1:1的,4行攻击抵消对手的4行攻击",
|
||||
},
|
||||
{"连击",
|
||||
{"连击 Combo",
|
||||
"连击 ren combo",
|
||||
"term",
|
||||
"从第二次消除起叫1Ren/Combo,打出的攻击根据游戏设计的不同也不同",
|
||||
@@ -714,37 +714,37 @@ return{
|
||||
"term",
|
||||
"现代方块的最高下落速度,表观就是方块瞬间到底,不存在中间的下落过程,可能会让方块无法跨越壕沟/从山谷爬出。\n20G一般指的其实是“无限下落速度”,就算场地不止20格,“20G”也会让方块瞬间到底。\n本游戏(和部分其他游戏,推荐这么设计)中20G的优先级比其他玩家操作都高,即使是0arr的水平方向“瞬间移动”中途也会受到20G的影响。",
|
||||
},
|
||||
{"锁定延迟",
|
||||
"锁定延迟 重力 lock delay suoyan zhongli gravity",
|
||||
{"锁定延迟 LD",
|
||||
"锁定延迟 重力 lock delay lockdown delay suoyan zhongli gravity",
|
||||
"term",
|
||||
"方块<碰到地面到锁定>之间的时间。经典块仅方块下落一格时刷新倒计时,而现代方块中往往任何操作都将重置该倒计时(但是方块本身必须可以移动/旋转),所以连续移动和操作可以让方块不马上锁定,拖一会时间(本游戏和部分游戏重置次数有限,一般是15)。",
|
||||
},
|
||||
{"出块延迟",
|
||||
{"出块延迟 ARE",
|
||||
"出块延迟 are delay chukuaiyanchi",
|
||||
"term",
|
||||
"方块<锁定完成到下一个方块出现>之间的时间,英文是ARE。",
|
||||
},
|
||||
{"消行延迟",
|
||||
{"消行延迟 ARE",
|
||||
"消行延迟 line are delay xiaohangyanchi",
|
||||
"term",
|
||||
"方块<锁定完成能消行时的消行动画>占据的时间,英文是line ARE。",
|
||||
},
|
||||
{"窒息延迟",
|
||||
{"窒息延迟 DD",
|
||||
"窒息延迟 choke are delay zhixiyanchi",
|
||||
"term",
|
||||
"当前方块锁定后如果下一块的生成位置被阻挡,那么下一块的出块延迟会被再额外加上这个延迟的值,方便使用提前系统来避免死亡\n想法来自NOT_A_ROBOT",
|
||||
},
|
||||
{"Finesse",
|
||||
{"极简 Finesse",
|
||||
"极简操作 最简操作 finesse jijiancaozuo zuijiancaozuo",
|
||||
"term",
|
||||
"极简操作\n用最少的按键数将方块移到想去的位置的技术(大多数时候只考虑纯硬降的落点),节约时间和减少Misdrop。\n\n该技能学习越早越好,建议先去找教程视频,看懂了然后自己多练习,开始以准确率第一,速度快慢不重要,熟练后自然就快了。\n\n注意,本游戏使用的极简判定系统不是说完全和理论最少操作数一样,而是不需要软降就能达到的位置才会按照标准出块方向和你的按键次数执行极简检测,故在此不像js存在软降后误杀。但是多了一些新的条件,比如【手上和Hold一样/已经按了超过3次按键后】再hold后按键次数不重置(让下一块极简失误)。\n极简率计算:\n没有超过标准极简法操作数的为Perfect计100%,超出一步为Great计50%,超出两步为Bad计25%,两步以上为Miss计0%,其中Bad和Miss会断连\n\n注:20G下极简系统和0G一样工作,所以得到的数值不准确,参考价值偏低。",
|
||||
"用最少的按键数将方块移到想去的位置的技术(大多数时候只考虑纯硬降的落点),节约时间和减少Misdrop。\n\n该技能学习越早越好,建议先去找教程视频,看懂了然后自己多练习,开始以准确率第一,速度快慢不重要,熟练后自然就快了。\n\n注意,本游戏使用的极简判定系统不是说完全和理论最少操作数一样,而是不需要软降就能达到的位置才会按照标准出块方向和你的按键次数执行极简检测,故在此不像js存在软降后误杀。但是多了一些新的条件,比如【手上和Hold一样/已经按了超过3次按键后】再hold后按键次数不重置(让下一块极简失误)。\n极简率计算:\n没有超过标准极简法操作数的为Perfect计100%,超出一步为Great计50%,超出两步为Bad计25%,两步以上为Miss计0%,其中Bad和Miss会断连\n\n注:20G下极简系统和0G一样工作,所以得到的数值不准确,参考价值偏低。",
|
||||
},
|
||||
{"科研",
|
||||
"科研 keyan",
|
||||
"term",
|
||||
"常用语,指在低重力的单人模式里减速研究怎么做各种T-spin,本游戏中拓展了含义,用于称呼几乎需要全程Spin的游戏模式。",
|
||||
},
|
||||
{"手感",
|
||||
{"手感 Handling",
|
||||
"手感 feel shougan",
|
||||
"term",
|
||||
"决定手感的几个主要因素:\n(1) 输入延迟受设备配置或者设备状况影响。可以重启/换设备解决\n(2) 程序运行稳定性程序设计(或者实现)得不好,时不时会卡一下。把设置画面效果拉低可能可以缓解\n(3) 游戏设计故意的。自己适应\n(4) 参数设置设置不当。去改设置\n(5) 游玩姿势姿势不当。不便用力,换个姿势\n(6) 换键位或者换设备后不适应,操作不习惯。多习惯习惯,改改设置\n(7) 肌肉疲劳反应和协调能力下降。睡一觉或者做点体育运动,过段时间(也可能要几天)再来玩",
|
||||
@@ -764,17 +764,17 @@ return{
|
||||
"term",
|
||||
"对于不是刚入门的并且了解极简操作的玩家来说推荐ARR=0,DAS=4~6(具体看个人手部协调性,只要能控制区别就不大)\n新人如果实在觉得太快可以适当增加一点DAS,ARR要改的话强烈建议不要超过2\n\n最佳调整方法:DAS越小越好,小到依然能准确区分单点/长按为止;ARR能0就0,游戏不允许的话就能拉多小拉多小",
|
||||
},
|
||||
{"DAS打断",
|
||||
"dascut daduan",
|
||||
{"DAS打断 DCD",
|
||||
"dascut dcd daduan",
|
||||
"term",
|
||||
"本游戏中指玩家的操作焦点转移到新方块的瞬间,此时减小(重置)DAS计时器,让自动移动不会立刻生效,减少“移动键松开晚了导致下一块一出来就立即开始移动”的情况\n注:其他游戏中的DAS打断机制可能和本游戏的有区别,仅供参考",
|
||||
},
|
||||
{"误硬降打断",
|
||||
{"误硬降打断 HCD",
|
||||
"autolockcut mdcut daduan",
|
||||
"term",
|
||||
"为了防止玩家硬降时当前方块已经锁定,下一块出现就被立刻硬降导致严重md,所以设计了此打断参数。\n方块自然锁定之后几帧内硬降键是无效的,具体看设置了多久。\n注:其他游戏中的防误硬降机制可能和本游戏的有区别,仅供参考",
|
||||
},
|
||||
{"SDF",
|
||||
{"软降倍率 SDF",
|
||||
"软降速度 sdf softdropfactor",
|
||||
"term",
|
||||
"Soft Drop Factor,软降速度因子(倍率)\n部分游戏中的软降机制就是在按住软降键时方块受到的重力变为原来的若干倍,SDF就是这个变大的倍数。\n基本所有官块和TETR.IO使用这个机制,但本游戏不使用。",
|
||||
@@ -804,8 +804,8 @@ return{
|
||||
"term",
|
||||
"(该词仅在本游戏内使用)回声出块,bag算法的分支,把bag的每一块重复随机次数(重复越多概率越小,理论范围是0~6,具体比较复杂这里不展开)",
|
||||
},
|
||||
{"Hypertap",
|
||||
"超连点 hypertap",
|
||||
{"超连点 Hypertap",
|
||||
"超连点 hypertap chaoliandian",
|
||||
"term",
|
||||
"快速震动手指,实现比长按更快速+灵活的高速单点移动,主要在经典块的高难度下(因为das不可调而且特别慢,高速下很容易md导致失败,此时手动连点就比自动移动更快)或者受特殊情况限制不适合用自动移动时使用。会使用这个技术的人称为“Hypertapper”。",
|
||||
},
|
||||
@@ -817,7 +817,7 @@ return{
|
||||
{"Techmino攻击表",
|
||||
"攻击表 tech attack",
|
||||
"term",
|
||||
"攻击系统:\n 普通消除:\n 消<4行打出[消行数-0.5]攻击\n 特殊消除:\n 如果是Spin,打出[2*消行数]攻击,\n B2B攻击+[1/1/2/4/8(spin1~5)]\n B3B攻击在B2B基础上+消行数*0.5,+1额外抵挡\n Mini减至25%\n 不是spin但是单次消≥4行,打出[消行数]攻击,\n B2B攻击+1\n B3B攻击+50%,+1额外抵挡\n 特殊消除会增加B2B点数,让之后的特殊消除获得B2B(B3B)增益(详细说明见下文)\n 半全消(<下方有剩余方块>的全消,如果是I消1行则必须不剩余玩家放置的方块):伤害+2,额外抵挡+2\n 全消:将上述伤害之和减半,再+8~20(本局内递增2),+2额外抵挡(注:本局消行数>4时会将B2B点数拉满)\n 连击:每次连击给予上述攻击[连击数*25%(如果只消一行就是15%)]的加成,12 Combo达到上限,连击≥3次时再额外加1攻击\n 根据上述规则计算后,向下取整,攻击打出",
|
||||
"详见主菜单右下角的说明书页面",
|
||||
},
|
||||
{"C2序列",
|
||||
"c2序列 seq",
|
||||
@@ -829,7 +829,7 @@ return{
|
||||
"term",
|
||||
"左,右,下,左下,右下,左2,右2\n(任何方块的任何旋转都使用这个表)。",
|
||||
},
|
||||
{"堆叠",
|
||||
{"堆叠 Stack",
|
||||
"堆叠 duidie stack",
|
||||
"term",
|
||||
"将方块无缝隙地堆起来,需要玩家有预读Next的能力,可以通过不使用Hold并且用十个消四完成40L模式进行练习。\n这项能力从入坑到封神都是非常重要的。",
|
||||
@@ -844,12 +844,12 @@ return{
|
||||
"term",
|
||||
"指能够使用顺+逆时针+180°旋转三个旋转键的技术,任何方块放哪只需要旋转一次即可(Spin不算)\n但由于只有部分游戏有180°旋转所以改操作并不通用,而且对速度提升的效果不如从单旋转双旋显著,不追求极限速度的玩家可不学",
|
||||
},
|
||||
{"干旱",
|
||||
{"干旱 Drought",
|
||||
"干旱 drought ganhan",
|
||||
"term",
|
||||
"经典块术语,指长时间不来I方块(长条)。现代方块使用的Bag7出块规则下干旱几乎不可能,平均7块就会有一个I,理论极限两个I最远中间隔12块。",
|
||||
},
|
||||
{"骨块",
|
||||
{"骨块 Bone",
|
||||
"骨块 gukuai bone tgm",
|
||||
"term",
|
||||
"最早的方块游戏使用的方块样式。\n很久以前的电脑没有可以显示复杂图案的屏幕,只能往上打字,所以一格方块用两个方括号[ ]表示,长得像骨头所以叫骨块。\n基于骨块的特点,本游戏把骨块重新定义为,“所有形状使用的同一个比较花眼的贴图”,不同的皮肤有不同的骨块样式。",
|
||||
@@ -891,7 +891,7 @@ return{
|
||||
},
|
||||
|
||||
--定式
|
||||
{"开局定式",
|
||||
{"开局定式 Setup",
|
||||
"开局定式 setup opening kaijudingshi",
|
||||
"setup",
|
||||
"开局定式,定式一般指开局定式这个概念。\n指开局后可以使用的套路摆法。局中情况合适的时候也可以摆出同样的形状,但是和摆法开局一般都不一样。\n\n能称为定式的摆法要尽量满足以下至少2~3条:\n能适应大多数块序\n输出高,尽量不浪费T块\n很多方块无需软降,极简操作数少\n有明确后续,分支尽量少。\n\n注:绝大多数定式基于bag7,序列规律性强才有发明定式的可能。",
|
||||
@@ -1158,7 +1158,7 @@ return{
|
||||
{"Jonas",
|
||||
"jonas",
|
||||
"name",
|
||||
"经典块一流玩家,曾经的经典块第一,CTWC4连冠\n(1981-2021)",
|
||||
"(1981-2021)经典块一流玩家,曾经的经典块第一,CTWC4连冠",
|
||||
},
|
||||
{"Joseph",
|
||||
"joseph",
|
||||
|
||||
@@ -139,6 +139,7 @@ return{
|
||||
|
||||
keySettingInstruction="Press to bind key\nescape: cancel\nbackspace: delete",
|
||||
customBGhelp="Drop image file here to apply custom background",
|
||||
customBGloadFailed="Unsupport image format for custom background",
|
||||
|
||||
errorMsg="Techmino ran into a problem and needs to restart.\nYou can send the error log to the developers.",
|
||||
tryAnotherBuild="[Invalid UTF-8] If you are on Windows, try downloading Techmino-win32 or Techmino-win64 (different from what you are using now).",
|
||||
@@ -392,9 +393,9 @@ return{
|
||||
clean="Quick Draw",
|
||||
fullscreen="Fullscreen",
|
||||
|
||||
bg_on="Normal Backgrounds",
|
||||
bg_off="No Background",
|
||||
bg_custom="Apply Custom BG",
|
||||
bg_on="Normal B.G.",
|
||||
bg_off="No B.G.",
|
||||
bg_custom="Use Custom B.G.",
|
||||
|
||||
blockSatur="Block Saturation",
|
||||
fieldSatur="Field Saturation",
|
||||
@@ -502,8 +503,8 @@ return{
|
||||
|
||||
copy="Copy Field+Seq+Mssn",
|
||||
paste="Paste Field+Seq+Mssn",
|
||||
clear="Start-Clear",
|
||||
puzzle="Start-Puzzle",
|
||||
play_clear="Start-Clear",
|
||||
play_puzzle="Start-Puzzle",
|
||||
|
||||
reset="Reset (Del)",
|
||||
advance="More (A)",
|
||||
|
||||
@@ -128,6 +128,7 @@ return{
|
||||
|
||||
-- keySettingInstruction="Press to bind key\nescape: cancel\nbackspace: delete",
|
||||
-- customBGhelp="Drop image file here to apply custom background",
|
||||
-- customBGloadFailed="Unsupport image format for custom background",
|
||||
|
||||
errorMsg="Ha ocurrido un error y Techmino necesita reiniciarse.\nSe creó un registro de error, puedes enviarlo al autor.",
|
||||
-- tryAnotherBuild="[Invalid UTF-8] If you are on Windows, try downloading Techmino-win32 or Techmino-win64 (different from what you are using now).",
|
||||
@@ -358,9 +359,9 @@ return{
|
||||
clean="Fast Draw",
|
||||
fullscreen="Pant. Completa",
|
||||
|
||||
-- bg_on="Normal Backgrounds",
|
||||
-- bg_off="No Background",
|
||||
-- bg_custom="Apply Custom BG",
|
||||
-- bg_on="Normal B.G.",
|
||||
-- bg_on="No B.G.",
|
||||
-- bg_custom="Use Custom B.G.",
|
||||
|
||||
blockSatur="Saturac. de los Bloques",
|
||||
fieldSatur="Saturac. del Tablero",
|
||||
@@ -467,8 +468,8 @@ return{
|
||||
|
||||
copy="Copiar Campo+Sec.+Mis.",
|
||||
paste="Pegar Campo+Sec.+Mis.",
|
||||
clear="Inicio-Fin",
|
||||
puzzle="Inicio-Puzzle",
|
||||
play_clear="Inicio-Fin",
|
||||
play_puzzle="Inicio-Puzzle",
|
||||
|
||||
reset="Reiniciar (Supr)",
|
||||
advance="Más opciones (A)",
|
||||
|
||||
@@ -129,6 +129,7 @@ return{
|
||||
|
||||
-- keySettingInstruction="Press to bind key\nescape: cancel\nbackspace: delete",
|
||||
-- customBGhelp="Drop image file here to apply custom background",
|
||||
-- customBGloadFailed="Unsupport image format for custom background",
|
||||
|
||||
errorMsg="Une erreur est survenue et Techmino doit redémarrer.\nDes informations concernant l'erreur ont été créées, et vous pouvez les envoyer au créateur.",
|
||||
-- tryAnotherBuild="[Invalid UTF-8] If you are on Windows, try downloading Techmino-win32 or Techmino-win64 (different from what you are using now).",
|
||||
@@ -356,9 +357,9 @@ return{
|
||||
-- clean="Fast Draw",
|
||||
fullscreen="Plein écran",
|
||||
|
||||
-- bg_on="Normal Backgrounds",
|
||||
-- bg_off="No Background",
|
||||
-- bg_custom="Apply Custom BG",
|
||||
-- bg_on="Normal B.G.",
|
||||
-- bg_on="No B.G.",
|
||||
-- bg_custom="Use Custom B.G.",
|
||||
|
||||
-- blockSatur="Block Saturation",
|
||||
-- fieldSatur="Field Saturation",
|
||||
@@ -468,8 +469,8 @@ return{
|
||||
|
||||
copy="Copier Mtrc+Seq+Missn",
|
||||
paste="Coller Mtrc+Seq+Missn",
|
||||
clear="Démarrer Clear",
|
||||
puzzle="Démarrer Puzzle",
|
||||
play_clear="Démarrer Clear",
|
||||
play_puzzle="Démarrer Puzzle",
|
||||
|
||||
-- reset="Reset (Del)",
|
||||
advance="Plus (A)",
|
||||
|
||||
@@ -127,6 +127,7 @@ return{
|
||||
|
||||
-- keySettingInstruction="Press to bind key\nescape: cancel\nbackspace: delete",
|
||||
-- customBGhelp="Drop image file here to apply custom background",
|
||||
-- customBGloadFailed="Unsupport image format for custom background",
|
||||
|
||||
errorMsg="Um erro ocorreu e Techmino precisa reiniciar.\nInformação do erro foi criada, e você pode mandar ao autor.",
|
||||
-- tryAnotherBuild="[Invalid UTF-8] If you are on Windows, try downloading Techmino-win32 or Techmino-win64 (different from what you are using now).",
|
||||
@@ -380,9 +381,9 @@ return{
|
||||
-- clean="Fast Draw",
|
||||
fullscreen="Tela cheia",
|
||||
|
||||
-- bg_on="Normal Backgrounds",
|
||||
-- bg_off="No Background",
|
||||
-- bg_custom="Apply Custom BG",
|
||||
-- bg_on="Normal B.G.",
|
||||
-- bg_on="No B.G.",
|
||||
-- bg_custom="Use Custom B.G.",
|
||||
|
||||
-- blockSatur="Block Saturation",
|
||||
-- fieldSatur="Field Saturation",
|
||||
@@ -490,8 +491,8 @@ return{
|
||||
|
||||
copy="Copiar Tab.+Seq+Misn",
|
||||
paste="Colar Tab.+Seq+Misn",
|
||||
clear="Iniciar-Limpar",
|
||||
puzzle="Iniciar-Puzzle",
|
||||
play_clear="Iniciar-Limpar",
|
||||
play_puzzle="Iniciar-Puzzle",
|
||||
|
||||
-- reset="Reset (Del)",
|
||||
advance="Mais (A)",
|
||||
|
||||
@@ -393,8 +393,8 @@ return{
|
||||
|
||||
copy="Field+Seq+Misn→__",
|
||||
paste="__→Field+Seq+Misn",
|
||||
clear="Start-Clear",
|
||||
puzzle="Start-Puzzle",
|
||||
play_clear="Start-Clear",
|
||||
play_puzzle="Start-Puzzle",
|
||||
|
||||
reset="Reset (Del)",
|
||||
advance="More (A)",
|
||||
|
||||
@@ -139,6 +139,7 @@ return{
|
||||
|
||||
keySettingInstruction="点击添加键位绑定\nesc取消选中\n退格键清空选中",
|
||||
customBGhelp="把图片文件拖到这个窗口里使用自定义背景",
|
||||
customBGloadFailed="自定义背景的图片文件格式不支持",
|
||||
|
||||
errorMsg="Techmino遭受了雷击,需要重新启动。\n我们已收集了一些错误信息,你可以向作者进行反馈。",
|
||||
tryAnotherBuild="[解码UTF-8错误] 如果你现在用的是Windows系统,请重新下载 Techmino-32位 或者 Techmino-64位 (和现在运行的不一样的那个)。",
|
||||
@@ -501,8 +502,8 @@ return{
|
||||
|
||||
copy="复制场地+序列+任务",
|
||||
paste="粘贴场地+序列+任务",
|
||||
clear="开始-消除",
|
||||
puzzle="开始-拼图",
|
||||
play_clear="开始-消除",
|
||||
play_puzzle="开始-拼图",
|
||||
|
||||
reset="重置所有(Del)",
|
||||
advance="更多设置(A)",
|
||||
|
||||
@@ -137,6 +137,7 @@ return{
|
||||
|
||||
keySettingInstruction="按绑定键\n退出:取消\n退格:删除",
|
||||
customBGhelp="将图像文件拖放到此处以应用自定义背景",
|
||||
customBGloadFailed="不支持自定义背景的图像格式",
|
||||
|
||||
errorMsg="技术米诺遇到问题,需要重新启动。\n您可以将错误日志发送给开发人员。",
|
||||
tryAnotherBuild="[无效UTF-8]如果您在Windows上,请尝试下载Techmino-win32或Techmino-win64(与您现在使用的不同)",
|
||||
@@ -499,8 +500,8 @@ return{
|
||||
|
||||
copy="复制字段+序号+使命",
|
||||
paste="粘贴字段+序号+使命",
|
||||
clear="清场",
|
||||
puzzle="开始拼图",
|
||||
play_clear="清场",
|
||||
play_puzzle="开始拼图",
|
||||
|
||||
reset="复位(Del)",
|
||||
advance="更多(A)",
|
||||
|
||||
@@ -139,6 +139,7 @@ return{
|
||||
|
||||
keySettingInstruction="點擊來設置鍵位\n按esc來取消選中\n按退格鍵來清除選中",
|
||||
customBGhelp="把圖片檔案拖到這個視窗裏使用自定義背景",
|
||||
customBGloadFailed="自定義背景的圖片檔案格式不支持",
|
||||
|
||||
errorMsg="Techmino遇到問題,需要重新啟動。\n我們已經收集了一些錯誤信息,你可以反饋給作者。",
|
||||
tryAnotherBuild="[無效的 UTF-8] 如果你使用的是Windows作業系統,請嘗試下載Techmino-win32或Techmino-win64(與你現在使用的不同的版本)。",
|
||||
@@ -500,8 +501,8 @@ return{
|
||||
|
||||
copy="拷貝場地+序列+任務",
|
||||
paste="黏貼場地+序列+任務",
|
||||
clear="開始-清除",
|
||||
puzzle="開始-拼圖",
|
||||
play_clear="開始-清除",
|
||||
play_puzzle="開始-拼圖",
|
||||
|
||||
reset="重設所有(Del)",
|
||||
advance="更多設置(A)",
|
||||
|
||||
@@ -127,4 +127,5 @@ return{
|
||||
{font=25,name="零醇丘卡"},
|
||||
{font=25,name="Hathtiz"},
|
||||
{font=25,name="江江江江17"},
|
||||
{font=25,name="TetraCepra"},
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ function scene.sceneInit()
|
||||
end
|
||||
|
||||
function scene.mouseDown(x,y)
|
||||
if x>55 and y>550 and x<510 and y<670 then
|
||||
if x>55 and y>550 and x<450 and y<670 then
|
||||
loadGame('stack_e',true)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,6 +7,8 @@ local inputBox=WIDGET.newInputBox{name='input',x=40,y=650,w=1200,h=50,fType='mon
|
||||
local outputBox=WIDGET.newTextBox{name='output',x=40,y=30,w=1200,h=610,font=25,fType='mono',lineH=23,fix=true}
|
||||
|
||||
local function log(str)outputBox:push(str)end
|
||||
_SCLOG=log
|
||||
|
||||
log{C.lP,"Techmino Console"}
|
||||
log{C.lC,"©2021 26F Studio some rights reserved"}
|
||||
log{C.dR,"WARNING: DO NOT RUN ANY CODE THAT YOU DON'T UNDERSTAND."}
|
||||
@@ -51,7 +53,7 @@ local commands={}do
|
||||
local body=commands[cmd]
|
||||
log(
|
||||
body.description and
|
||||
{C.Z,cmd,C.H," "..body.description}
|
||||
{C.Z,cmd,C.H,(" $1 $2"):repD(("·"):rep(16-#cmd),body.description)}
|
||||
or
|
||||
log{C.Z,cmd}
|
||||
)
|
||||
@@ -704,7 +706,9 @@ local commands={}do
|
||||
elseif code=="7126"then
|
||||
sudomode=true
|
||||
log{C.Y,"* SUDO MODE ON - DO NOT RUN ANY CODES IF YOU DO NOT KNOW WHAT THEY DO *"}
|
||||
log{C.Y,"* Use function _SCLOG(message) to print message here *"}
|
||||
log{C.Y,"* 最高权限模式开启, 请不要执行任何自己不懂确切含义的代码 *"}
|
||||
log{C.Y,"* 使用_SCLOG(信息)函数在控制台打印信息 *"}
|
||||
else
|
||||
log{C.Y,"Password incorrect"}
|
||||
end
|
||||
|
||||
@@ -67,10 +67,10 @@ end
|
||||
|
||||
function scene.keyDown(key,isRep)
|
||||
if isRep then return true end
|
||||
if key=='return'and kb.isDown('lctrl','lalt')then
|
||||
if kb.isDown('lalt')and #FIELD[1]>0 then
|
||||
if key=='return'and kb.isDown('lctrl','lalt')or key=='play1'or key=='play2'then
|
||||
if(key=='play2'or kb.isDown('lalt'))and #FIELD[1]>0 then
|
||||
_play('puzzle')
|
||||
elseif kb.isDown('lctrl')then
|
||||
elseif key=='play1'or kb.isDown('lctrl')then
|
||||
_play('clear')
|
||||
end
|
||||
elseif key=='f'then
|
||||
@@ -218,8 +218,8 @@ scene.widgetList={
|
||||
--Copy / Paste / Start
|
||||
WIDGET.newButton{name='copy', x=1070,y=300,w=310,h=70,color='lR',font=25,code=pressKey'cC'},
|
||||
WIDGET.newButton{name='paste', x=1070,y=380,w=310,h=70,color='lB',font=25,code=pressKey'cV'},
|
||||
WIDGET.newButton{name='clear', x=1070,y=460,w=310,h=70,color='lY',font=35,code=pressKey'return'},
|
||||
WIDGET.newButton{name='puzzle', x=1070,y=540,w=310,h=70,color='lM',font=35,code=pressKey'return2',hideF=function()return #FIELD[1]==0 end},
|
||||
WIDGET.newButton{name='play_clear', x=1070,y=460,w=310,h=70,color='lY',font=35,code=pressKey'play1'},
|
||||
WIDGET.newButton{name='play_puzzle', x=1070,y=540,w=310,h=70,color='lM',font=35,code=pressKey'play2',hideF=function()return #FIELD[1]==0 end},
|
||||
WIDGET.newButton{name='back', x=1140,y=640,w=170,h=80,font=60,fText=CHAR.icon.back,code=pressKey'escape'},
|
||||
|
||||
--Rule set
|
||||
|
||||
@@ -162,11 +162,16 @@ function scene.update()
|
||||
if kb.isDown('down', 's')then dy=dy-10 F=true end
|
||||
if kb.isDown('left', 'a')then dx=dx+10 F=true end
|
||||
if kb.isDown('right','d')then dx=dx-10 F=true end
|
||||
local js1=Z.js[1]
|
||||
if js1 then
|
||||
dx=dx+12.6*js1:getGamepadAxis('leftx')
|
||||
dy=dy+12.6*js1:getGamepadAxis('lefty')
|
||||
F=true
|
||||
local js=Z.js[1]
|
||||
if js then
|
||||
local sx,sy=js._jsObj:getGamepadAxis('leftx'),js._jsObj:getGamepadAxis('lefty')
|
||||
if math.abs(sx)>.1 or math.abs(sy)>.1 then
|
||||
if sy<-.1 then dy=dy-12.6*sy end
|
||||
if sy>.1 then dy=dy-12.6*sy end
|
||||
if sx<-.1 then dx=dx-12.6*sx end
|
||||
if sx>.1 then dx=dx-12.6*sx end
|
||||
F=true
|
||||
end
|
||||
end
|
||||
end
|
||||
if F then
|
||||
|
||||
@@ -7,13 +7,94 @@ local scene={}
|
||||
local selected--if waiting for key
|
||||
local keyList
|
||||
|
||||
local keyNames={
|
||||
normal={
|
||||
a='A',b='B',c='C',d='D',e='E',f='F',g='G',
|
||||
h='H',i='I',j='J',k='K',l='L',m='M',n='N',
|
||||
o='O',p='P',q='Q',r='R',s='S',t='T',
|
||||
u='U',v='V',w='W',x='X',y='Y',z='Z',
|
||||
f1='F1',f2='F2',f3='F3',f4='F4',f5='F5',f6='F6',
|
||||
f7='F7',f8='F8',f9='F9',f10='F10',f11='F11',f12='F12',
|
||||
backspace=CHAR.key.backspace,
|
||||
['return']=CHAR.key.enter_or_return,
|
||||
kpenter='kp'..CHAR.key.enter_or_return,
|
||||
tab=CHAR.key.tab,
|
||||
capslock=CHAR.key.capslock,
|
||||
lshift='L shift',
|
||||
rshift='R shift',
|
||||
lctrl='L ctrl',
|
||||
rctrl='R ctrl',
|
||||
lalt='L alt',
|
||||
ralt='R alt',
|
||||
lgui='L'..CHAR.key.windows,
|
||||
rgui='R'..CHAR.key.windows,
|
||||
space=CHAR.key.space,
|
||||
delete='Del',
|
||||
pageup='PgUp',
|
||||
pagedown='PgDn',
|
||||
home='Home',
|
||||
['end']='End',
|
||||
insert='Ins',
|
||||
numlock='Numlock',
|
||||
menu=CHAR.key.winMenu,
|
||||
up=CHAR.key.up,
|
||||
down=CHAR.key.down,
|
||||
left=CHAR.key.left,
|
||||
right=CHAR.key.right,
|
||||
},
|
||||
apple={
|
||||
kpenter=CHAR.key.macEnter,
|
||||
tab=CHAR.key.mactab,
|
||||
lshift='L'..CHAR.key.shift,
|
||||
rshift='R'..CHAR.key.shift,
|
||||
lctrl='L'..CHAR.key.macCtrl,
|
||||
rctrl='R'..CHAR.key.macCtrl,
|
||||
lalt='L'..CHAR.key.macOpt,
|
||||
ralt='R'..CHAR.key.macOpt,
|
||||
lgui='L'..CHAR.key.macCmd,
|
||||
rgui='R'..CHAR.key.macCmd,
|
||||
space=CHAR.key.space,
|
||||
delete=CHAR.key.del,
|
||||
pageup=CHAR.key.macPgup,
|
||||
pagedown=CHAR.key.macPgdn,
|
||||
home=CHAR.key.macHome,
|
||||
['end']=CHAR.key.macEnd,
|
||||
numlock=CHAR.key.clear,
|
||||
},
|
||||
controller={
|
||||
x=CHAR.controller.xboxX,
|
||||
y=CHAR.controller.xboxY,
|
||||
a=CHAR.controller.xboxA,
|
||||
b=CHAR.controller.xboxB,
|
||||
dpup=CHAR.controller.dpadU,
|
||||
dpdown=CHAR.controller.dpadD,
|
||||
dpleft=CHAR.controller.dpadL,
|
||||
dpright=CHAR.controller.dpadR,
|
||||
triggerleft=CHAR.controller.lt,
|
||||
triggerright=CHAR.controller.rt,
|
||||
leftshoulder=CHAR.controller.lb,
|
||||
rightshoulder=CHAR.controller.rb,
|
||||
leftstick_up=CHAR.controller.jsLU,
|
||||
leftstick_down=CHAR.controller.jsLD,
|
||||
leftstick_left=CHAR.controller.jsLL,
|
||||
leftstick_right=CHAR.controller.jsLR,
|
||||
rightstick_up=CHAR.controller.jsRU,
|
||||
rightstick_down=CHAR.controller.jsRD,
|
||||
rightstick_left=CHAR.controller.jsRL,
|
||||
rightstick_right=CHAR.controller.jsRR,
|
||||
},
|
||||
}setmetatable(keyNames.apple,{__index=keyNames.normal})
|
||||
|
||||
local function _freshKeyList()
|
||||
keyList={}for i=0,20 do keyList[i]={}end
|
||||
|
||||
local keynames=SYSTEM:find'OS'and keyNames.apple or keyNames.normal
|
||||
for k,v in next,KEY_MAP.keyboard do
|
||||
ins(keyList[v],{COLOR.lB,k})
|
||||
ins(keyList[v],{COLOR.lB,keynames[k]or k})
|
||||
end
|
||||
for k,v in next,KEY_MAP.joystick do
|
||||
ins(keyList[v],{COLOR.lR,k})
|
||||
|
||||
for b,v in next,KEY_MAP.joystick do
|
||||
ins(keyList[v],{COLOR.lR,keyNames.controller[b]or b})
|
||||
end
|
||||
end
|
||||
|
||||
@@ -92,10 +173,10 @@ function scene.draw()
|
||||
for i=0,20 do
|
||||
for j=1,#keyList[i]do
|
||||
local key=keyList[i][j]
|
||||
local font=#key[2]==1 and 40 or #key[2]<6 and 30 or 15
|
||||
local font=#key[2]<=4 and 35 or #key[2]<=7 and 25 or 15
|
||||
setFont(font)
|
||||
mStr(key,
|
||||
(i>10 and 940 or 210)+100*j,
|
||||
(i>10 and 820 or 200)+80*j,
|
||||
(
|
||||
i>10 and 60*(i-10)-23 or
|
||||
i>0 and 60*i-23 or
|
||||
@@ -109,9 +190,9 @@ function scene.draw()
|
||||
gc.setLineWidth(3)
|
||||
gc.setColor(COLOR[TIME()%.26<.13 and'F'or'Y'])
|
||||
gc.rectangle('line',
|
||||
selected>10 and 910 or 270,
|
||||
selected>10 and 860 or 240,
|
||||
selected>10 and 60*(selected-10)-50 or selected>0 and 60*selected-50 or 640,
|
||||
360,60
|
||||
400,60
|
||||
)
|
||||
end
|
||||
end
|
||||
@@ -126,29 +207,29 @@ local function _setSel(i)
|
||||
end
|
||||
end
|
||||
scene.widgetList={
|
||||
WIDGET.newKey{name='a1',x=160,y=40,w=200,h=60,code=function()_setSel(1)end},
|
||||
WIDGET.newKey{name='a2',x=160,y=100,w=200,h=60,code=function()_setSel(2)end},
|
||||
WIDGET.newKey{name='a3',x=160,y=160,w=200,h=60,code=function()_setSel(3)end},
|
||||
WIDGET.newKey{name='a4',x=160,y=220,w=200,h=60,code=function()_setSel(4)end},
|
||||
WIDGET.newKey{name='a5',x=160,y=280,w=200,h=60,code=function()_setSel(5)end},
|
||||
WIDGET.newKey{name='a6',x=160,y=340,w=200,h=60,code=function()_setSel(6)end},
|
||||
WIDGET.newKey{name='a7',x=160,y=400,w=200,h=60,code=function()_setSel(7)end},
|
||||
WIDGET.newKey{name='a8',x=160,y=460,w=200,h=60,code=function()_setSel(8)end},
|
||||
WIDGET.newKey{name='a9',x=160,y=520,w=200,h=60,code=function()_setSel(9)end},
|
||||
WIDGET.newKey{name='a10',x=160,y=580,w=200,h=60,code=function()_setSel(10)end},
|
||||
WIDGET.newKey{name='a1',x=150,y=40,w=180,h=60,font=25,code=function()_setSel(1)end},
|
||||
WIDGET.newKey{name='a2',x=150,y=100,w=180,h=60,font=25,code=function()_setSel(2)end},
|
||||
WIDGET.newKey{name='a3',x=150,y=160,w=180,h=60,font=25,code=function()_setSel(3)end},
|
||||
WIDGET.newKey{name='a4',x=150,y=220,w=180,h=60,font=25,code=function()_setSel(4)end},
|
||||
WIDGET.newKey{name='a5',x=150,y=280,w=180,h=60,font=25,code=function()_setSel(5)end},
|
||||
WIDGET.newKey{name='a6',x=150,y=340,w=180,h=60,font=25,code=function()_setSel(6)end},
|
||||
WIDGET.newKey{name='a7',x=150,y=400,w=180,h=60,font=25,code=function()_setSel(7)end},
|
||||
WIDGET.newKey{name='a8',x=150,y=460,w=180,h=60,font=25,code=function()_setSel(8)end},
|
||||
WIDGET.newKey{name='a9',x=150,y=520,w=180,h=60,font=25,code=function()_setSel(9)end},
|
||||
WIDGET.newKey{name='a10',x=150,y=580,w=180,h=60,font=25,code=function()_setSel(10)end},
|
||||
|
||||
WIDGET.newKey{name='a11',x=800,y=40,w=200,h=60,code=function()_setSel(11)end},
|
||||
WIDGET.newKey{name='a12',x=800,y=100,w=200,h=60,code=function()_setSel(12)end},
|
||||
WIDGET.newKey{name='a13',x=800,y=160,w=200,h=60,code=function()_setSel(13)end},
|
||||
WIDGET.newKey{name='a14',x=800,y=220,w=200,h=60,code=function()_setSel(14)end},
|
||||
WIDGET.newKey{name='a15',x=800,y=280,w=200,h=60,code=function()_setSel(15)end},
|
||||
WIDGET.newKey{name='a16',x=800,y=340,w=200,h=60,code=function()_setSel(16)end},
|
||||
WIDGET.newKey{name='a17',x=800,y=400,w=200,h=60,code=function()_setSel(17)end},
|
||||
WIDGET.newKey{name='a18',x=800,y=460,w=200,h=60,code=function()_setSel(18)end},
|
||||
WIDGET.newKey{name='a19',x=800,y=520,w=200,h=60,code=function()_setSel(19)end},
|
||||
WIDGET.newKey{name='a20',x=800,y=580,w=200,h=60,code=function()_setSel(20)end},
|
||||
WIDGET.newKey{name='a11',x=770,y=40,w=180,h=60,font=25,code=function()_setSel(11)end},
|
||||
WIDGET.newKey{name='a12',x=770,y=100,w=180,h=60,font=25,code=function()_setSel(12)end},
|
||||
WIDGET.newKey{name='a13',x=770,y=160,w=180,h=60,font=25,code=function()_setSel(13)end},
|
||||
WIDGET.newKey{name='a14',x=770,y=220,w=180,h=60,font=25,code=function()_setSel(14)end},
|
||||
WIDGET.newKey{name='a15',x=770,y=280,w=180,h=60,font=25,code=function()_setSel(15)end},
|
||||
WIDGET.newKey{name='a16',x=770,y=340,w=180,h=60,font=25,code=function()_setSel(16)end},
|
||||
WIDGET.newKey{name='a17',x=770,y=400,w=180,h=60,font=25,code=function()_setSel(17)end},
|
||||
WIDGET.newKey{name='a18',x=770,y=460,w=180,h=60,font=25,code=function()_setSel(18)end},
|
||||
WIDGET.newKey{name='a19',x=770,y=520,w=180,h=60,font=25,code=function()_setSel(19)end},
|
||||
WIDGET.newKey{name='a20',x=770,y=580,w=180,h=60,font=25,code=function()_setSel(20)end},
|
||||
|
||||
WIDGET.newKey{name='restart',x=160,y=670,w=200,h=60,code=function()_setSel(0)end},
|
||||
WIDGET.newKey{name='restart',x=150,y=670,w=180,h=60,code=function()_setSel(0)end},
|
||||
|
||||
WIDGET.newButton{name='back',x=1140,y=640,w=190,h=80,font=60,fText=CHAR.icon.back,code=backScene},
|
||||
}
|
||||
|
||||
@@ -8,9 +8,13 @@ end
|
||||
|
||||
|
||||
function scene.fileDropped(file)
|
||||
love.filesystem.write('conf/customBG',file:read('data'))
|
||||
SETTING.bg='custom'
|
||||
applyBG()
|
||||
if pcall(gc.newImage,file)then
|
||||
love.filesystem.write('conf/customBG',file:read('data'))
|
||||
SETTING.bg='custom'
|
||||
applyBG()
|
||||
else
|
||||
MES.new('error',text.customBGloadFailed)
|
||||
end
|
||||
end
|
||||
|
||||
local fakeBlock={{true}}
|
||||
@@ -80,8 +84,8 @@ scene.widgetList={
|
||||
WIDGET.newSwitch{name='clean', x=950,y=1160,lim=360,disp=SETval('cleanCanvas'), code=SETrev('cleanCanvas')},
|
||||
WIDGET.newSwitch{name='fullscreen', x=950,y=1250,lim=360,disp=SETval('fullscreen'), code=function()SETTING.fullscreen=not SETTING.fullscreen applyFullscreen()end},
|
||||
|
||||
WIDGET.newKey{name='bg_on', x=900,y=1340,w=200,h=80,code=function()SETTING.bg='on'applyBG()end},
|
||||
WIDGET.newKey{name='bg_off', x=680,y=1340,w=200,h=80,code=function()SETTING.bg='off'applyBG()end},
|
||||
WIDGET.newKey{name='bg_on', x=680,y=1340,w=200,h=80,code=function()SETTING.bg='on'applyBG()end},
|
||||
WIDGET.newKey{name='bg_off', x=900,y=1340,w=200,h=80,code=function()SETTING.bg='off'applyBG()end},
|
||||
WIDGET.newKey{name='bg_custom', x=1120,y=1340,w=200,h=80,
|
||||
code=function()
|
||||
if love.filesystem.getInfo('conf/customBG')then
|
||||
|
||||
@@ -20,7 +20,7 @@ end
|
||||
|
||||
function scene.mouseDown(x,y)
|
||||
local T=40*math.min(time,45)
|
||||
if x>230 and x<1050 then
|
||||
if x>330 and x<950 then
|
||||
if math.abs(y-800+T)<70 then
|
||||
loadGame('sprintLock',true)
|
||||
elseif math.abs(y-2160+T)<70 then
|
||||
|
||||
@@ -49,7 +49,7 @@ function scene.sceneInit()
|
||||
end
|
||||
|
||||
function scene.mouseDown(x,y)
|
||||
if x>35 and y>515 and x<490 and y<705 then
|
||||
if x>40 and y>520 and x<440 and y<695 then
|
||||
loadGame('sprintMD',true)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
return[=[
|
||||
未来小游戏:
|
||||
Tetro-1010(2C2N, 重力); Tetra-link(桌游)
|
||||
噗哟; 泡泡龙; 求合体; 坦克大战; 扫雷; 接水管; 记忆
|
||||
求合体; 坦克大战; 扫雷; 接水管; 记忆
|
||||
其他未来内容:
|
||||
模式包系统; 新模组系统; 加速下落; spike相关统计数据
|
||||
实时统计数据可视化; 教学关脚本语言; 从录像继续
|
||||
@@ -18,17 +18,19 @@ return[=[
|
||||
新旋转系统:DRS_weak,移除了滞后旋转(五连块朝向风格模仿) #441
|
||||
新BGM:malate(暂未使用)
|
||||
新机制:出块延迟打断(ARE打断)(默认关闭) #471
|
||||
添加锁定在外判负(lockout)规则(默认关闭)
|
||||
新增自定义图片背景功能(可调透明度)(目前仅电脑可用)
|
||||
全局默认使用5帧窒息延迟
|
||||
支持摇杆和扳机(参数暂时不能调整)
|
||||
没有键盘全支持的场景可以用方向键控制光标操作 #329
|
||||
新机制:锁定在外判负(lockout)(默认关闭)
|
||||
新机制:全局默认使用5帧窒息延迟
|
||||
新功能:自定义图片背景功能(可调透明度)(目前仅电脑可用)
|
||||
新功能:支持摇杆和扳机(参数暂时不能调整)
|
||||
新功能:没有键盘全支持的场景可以用方向键控制光标操作 #329
|
||||
改动:
|
||||
关闭背景时亮度可调 #119
|
||||
调整游戏大logo为正体字
|
||||
软降n格的键也可以触发深降
|
||||
优化键位设置菜单各种键的显示
|
||||
修改默认和zday节日的主菜单BGM
|
||||
三个高难隐形使用不同模式图标 #493
|
||||
修改按钮音效,给复选框和选择器添加新音效
|
||||
ultra模式计时器改为秒表,重开的时候会重播bgm
|
||||
出块/消行延迟逻辑修正,现在真的是0延迟,不再有一帧等待了(略微影响手感,更滑)
|
||||
生成位置预览开启后hold的生成位置也可见 #453
|
||||
@@ -36,8 +38,10 @@ return[=[
|
||||
优化pc训练模式体验,添加胜利条件,不再无尽
|
||||
堆积模式添加15帧的窒息延迟 #465
|
||||
修改部分不常用设置时会显示警告
|
||||
两种按钮上的文本也会挤压绘制了
|
||||
小程序arm加入计时器和重置按钮
|
||||
控制台使用等宽字体,更有味道(
|
||||
美化控制台help命令列表
|
||||
代码:
|
||||
BGM模块可限制最大加载数,不容易达到上限导致没声 #447
|
||||
语音模块支持设置轻微随机音调偏移半径(游戏内固定使用1)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
return{
|
||||
["apkCode"]=412,
|
||||
["apkCode"]=413,
|
||||
["code"]=1700,
|
||||
["string"]="V0.17.0",
|
||||
["room"]="ver A-2",
|
||||
|
||||
Reference in New Issue
Block a user