Skip to content

Commit c897d83

Browse files
Add Autoskip feature to TAS (26F-Studio#992)
1 parent 6836d87 commit c897d83

File tree

2 files changed

+100
-32
lines changed

2 files changed

+100
-32
lines changed

parts/scenes/app_console.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -853,7 +853,7 @@ local commands={} do
853853
saveSettings()
854854
log("Allow TAS: "..bool)
855855
if bool then
856-
log("Hot keys: f1=play/pause f2=slow down f3=speed up/next frame")
856+
log("Hot keys: f1=play/pause f2=slow down f3=speed up/next frame f4=adjust skip settings")
857857
end
858858
else
859859
log{C.A,"Usage: tas <on|off>"}

parts/scenes/game.lua

Lines changed: 99 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -10,62 +10,78 @@ local setFont,mStr=FONT.set,GC.mStr
1010
local noTouch,noKey=false,false
1111
local touchMoveLastFrame=false
1212
local trigGameRate,gameRate
13+
local autoSkip=0
1314
local modeTextPos,modeTextWidK
1415

1516
local replaying
1617
local repRateStrings={[0]="pause",[.125]="0.125x",[.5]="0.5x",[1]="1x",[2]="2x",[5]="5x"}
1718

1819
local scene={}
1920

21+
-- Widget hashmap (key = widget name, value = index)
22+
local widgetHashmap={}
23+
local function widgetWithName(name)
24+
if #widgetHashmap==0 then widgetHashmap=TABLE.kvSwap(TABLE.extract(scene.widgetList,'name')) end
25+
return scene.widgetList[widgetHashmap[name]]
26+
end
27+
2028
local function _updateMenuButtons()
21-
scene.widgetList.restart.hide=replaying
29+
widgetWithName('restart').hide=replaying
2230

2331
local pos=(GAME.tasUsed or replaying) and 'right' or SETTING.menuPos
2432
modeTextWidK=math.min(280/TEXTOBJ.modeName:getWidth(),1)
2533
if SETTING.portrait then
26-
scene.widgetList.restart.y=25-400
27-
scene.widgetList.pause.y=25-400
34+
widgetWithName('restart').y=25-400
35+
widgetWithName('pause').y=25-400
2836
else
29-
scene.widgetList.restart.y=25
30-
scene.widgetList.pause.y=25
37+
widgetWithName('restart').y=25
38+
widgetWithName('pause').y=25
3139
end
3240
if GAME.replaying then
33-
scene.widgetList.pause.x=1195
41+
widgetWithName('pause').x=1195
3442
modeTextPos=1185-TEXTOBJ.modeName:getWidth()*modeTextWidK
3543
elseif pos=='right' then
36-
scene.widgetList.restart.x=1125
37-
scene.widgetList.pause.x=1195
44+
widgetWithName('restart').x=1125
45+
widgetWithName('pause').x=1195
3846
modeTextPos=1115-TEXTOBJ.modeName:getWidth()*modeTextWidK
3947
elseif pos=='middle' then
40-
scene.widgetList.restart.x=360
41-
scene.widgetList.pause.x=860
48+
widgetWithName('restart').x=360
49+
widgetWithName('pause').x=860
4250
modeTextPos=940
4351
elseif pos=='left' then
44-
scene.widgetList.restart.x=120
45-
scene.widgetList.pause.x=190
52+
widgetWithName('restart').x=120
53+
widgetWithName('pause').x=190
4654
modeTextPos=1200-TEXTOBJ.modeName:getWidth()*modeTextWidK
4755
end
4856
end
57+
58+
local speedButtons={'rep0','repP8','repP2','rep1','rep2','rep5'}
59+
local stepButtons={'step','autoSkip'}
60+
local replayButtons=TABLE.combine(speedButtons,stepButtons)
4961
local function _updateRepButtons()
5062
local L=scene.widgetList
5163
if replaying or GAME.tasUsed then
52-
for i=1,6 do L[i].hide=false end L[7].hide=true
64+
for i=1,#speedButtons do
65+
widgetWithName(speedButtons[i]).hide=false
66+
end
67+
for i=1,#stepButtons do
68+
widgetWithName(stepButtons[i]).hide=gameRate~=0
69+
end
5370
if gameRate==0 then
54-
L[1].hide=true
55-
L[7].hide=false
71+
widgetWithName('rep0').hide=true
5672
elseif gameRate==.125 then
57-
L[2].hide=true
73+
widgetWithName('repP8').hide=true
5874
elseif gameRate==.5 then
59-
L[3].hide=true
75+
widgetWithName('repP2').hide=true
6076
elseif gameRate==1 then
61-
L[4].hide=true
77+
widgetWithName('rep1').hide=true
6278
elseif gameRate==2 then
63-
L[5].hide=true
79+
widgetWithName('rep2').hide=true
6480
elseif gameRate==5 then
65-
L[6].hide=true
81+
widgetWithName('rep5').hide=true
6682
end
6783
else
68-
for i=1,7 do L[i].hide=true end
84+
for i=1,#replayButtons do widgetWithName(replayButtons[i]).hide=true end
6985
end
7086
end
7187
local function _speedUp()
@@ -115,7 +131,46 @@ local function _rep5()
115131
gameRate=5
116132
_updateRepButtons()
117133
end
118-
local function _step() trigGameRate=trigGameRate+1 end
134+
local function _skip(P)
135+
if P.frameRun<179 then
136+
trigGameRate=trigGameRate+(179-P.frameRun)
137+
else
138+
trigGameRate=trigGameRate+MATH.clamp(P.waiting+P.falling,1,300)
139+
end
140+
end
141+
local fastForwardObj = GC.newText(FONT.get(40),CHAR.icon.fastForward)
142+
local nextFrameObj = GC.newText(FONT.get(40),CHAR.icon.nextFrame)
143+
local function _updateStepButton()
144+
local w=PLAYERS[1].waiting+PLAYERS[1].falling
145+
if (autoSkip==1 and w>1) or (autoSkip>0 and PLAYERS[1].frameRun<178) then
146+
widgetWithName('step').obj=fastForwardObj
147+
else
148+
widgetWithName('step').obj=nextFrameObj
149+
end
150+
end
151+
local function _step()
152+
local P=PLAYERS[1]
153+
if autoSkip>0 then
154+
_skip(P)
155+
else
156+
trigGameRate=trigGameRate+1
157+
end
158+
end
159+
local function _fullSkipCheck()
160+
if autoSkip<2 or PLAYERS[1].waiting+PLAYERS[1].falling<=0 then return end
161+
_step()
162+
end
163+
local function _setAS(v)
164+
autoSkip=v
165+
if v==1 then _updateStepButton() end
166+
end
167+
local function _autoSkipDisp()
168+
return (
169+
autoSkip==0 and 'No skip' or
170+
autoSkip==1 and 'Semi-skip' or
171+
autoSkip==2 and 'Full skip'
172+
)
173+
end
119174

120175
local function _restart()
121176
resetGameData(PLAYERS[1].frameRun<240 and 'q')
@@ -131,6 +186,8 @@ local function _checkGameKeyDown(key)
131186
if noKey then return end
132187
PLAYERS[1]:pressKey(k)
133188
VK.press(k)
189+
_updateStepButton()
190+
_fullSkipCheck()
134191
return
135192
elseif not GAME.fromRepMenu then
136193
_restart()
@@ -155,11 +212,14 @@ function scene.enter()
155212
elseif not replaying then
156213
if GAME.tasUsed then
157214
trigGameRate,gameRate=0,0
215+
autoSkip=1
158216
else
159217
trigGameRate,gameRate=0,1
218+
autoSkip=0
160219
end
161220
end
162221

222+
_updateStepButton()
163223
_updateRepButtons()
164224
_updateMenuButtons()
165225
end
@@ -172,6 +232,8 @@ function scene.touchDown(x,y)
172232
if t then
173233
PLAYERS[1]:pressKey(t)
174234
VK.touch(t,x,y)
235+
_updateStepButton()
236+
_fullSkipCheck()
175237
end
176238
end
177239
function scene.touchUp(x,y)
@@ -250,6 +312,8 @@ function scene.keyDown(key,isRep)
250312
elseif not isRep then
251313
_speedUp()
252314
end
315+
elseif key=='f4' then
316+
autoSkip=(autoSkip+1)%3
253317
end
254318
end
255319
if key=='escape' then
@@ -275,6 +339,8 @@ function scene.gamepadDown(key)
275339
if k>0 then
276340
PLAYERS[1]:pressKey(k)
277341
VK.press(k)
342+
_updateStepButton()
343+
_fullSkipCheck()
278344
else
279345
_restart()
280346
end
@@ -314,6 +380,7 @@ function scene.update(dt)
314380
while trigGameRate>=1 do
315381
trigGameRate=trigGameRate-1
316382
_update_common(dt)
383+
_updateStepButton()
317384
end
318385
end
319386

@@ -403,15 +470,16 @@ function scene.draw()
403470
drawWarning()
404471
end
405472
scene.widgetList={
406-
WIDGET.newKey{name='rep0', x=40, y=50,w=60,code=_rep0, font=40,fText=CHAR.icon.pause},
407-
WIDGET.newKey{name='repP8', x=105,y=50,w=60,code=_repP8, font=40,fText=CHAR.icon.speedOneEights},
408-
WIDGET.newKey{name='repP2', x=170,y=50,w=60,code=_repP2, font=40,fText=CHAR.icon.speedOneHalf},
409-
WIDGET.newKey{name='rep1', x=235,y=50,w=60,code=_rep1, font=40,fText=CHAR.icon.speedOne},
410-
WIDGET.newKey{name='rep2', x=300,y=50,w=60,code=_rep2, font=40,fText=CHAR.icon.speedTwo},
411-
WIDGET.newKey{name='rep5', x=365,y=50,w=60,code=_rep5, font=40,fText=CHAR.icon.speedFive},
412-
WIDGET.newKey{name='step', x=430,y=50,w=60,code=_step, font=40,fText=CHAR.icon.nextFrame},
413-
WIDGET.newKey{name='restart',x=0, y=25,w=60,code=_restart, font=40,fText=CHAR.icon.retry_spin},
414-
WIDGET.newKey{name='pause', x=0, y=25,w=60,code=pauseGame,font=40,fText=CHAR.icon.pause},
473+
WIDGET.newKey {name='rep0', x=40, y=50, w=60, code=_rep0, font=40, fText=CHAR.icon.pause}, -- 1
474+
WIDGET.newKey {name='repP8', x=105,y=50, w=60, code=_repP8, font=40, fText=CHAR.icon.speedOneEights}, -- 2
475+
WIDGET.newKey {name='repP2', x=170,y=50, w=60, code=_repP2, font=40, fText=CHAR.icon.speedOneHalf}, -- 3
476+
WIDGET.newKey {name='rep1', x=235,y=50, w=60, code=_rep1, font=40, fText=CHAR.icon.speedOne}, -- 4
477+
WIDGET.newKey {name='rep2', x=300,y=50, w=60, code=_rep2, font=40, fText=CHAR.icon.speedTwo}, -- 5
478+
WIDGET.newKey {name='rep5', x=365,y=50, w=60, code=_rep5, font=40, fText=CHAR.icon.speedFive}, -- 6
479+
WIDGET.newKey {name='step', x=40, y=50, w=60, code=_step, font=40, fText=CHAR.icon.nextFrame}, -- 7
480+
WIDGET.newSlider{name='autoSkip',x=40, y=130,w=100,code=_setAS, axis={0,2,1}, disp=function()return autoSkip end,show=_autoSkipDisp},
481+
WIDGET.newKey {name='restart', x=0, y=25, w=60, code=_restart, font=40, fText=CHAR.icon.retry_spin}, -- 10
482+
WIDGET.newKey {name='pause', x=0, y=25, w=60, code=pauseGame,font=40, fText=CHAR.icon.pause}, -- 11
415483
}
416484

417485
return scene

0 commit comments

Comments
 (0)