Skip to content

Commit 2fc570e

Browse files
committed
implement (untested) negative delay in hz display
Writing a very long explanation here as I think these changes are somewhat brittle. The delay value is stored in hzSpawnDelay, which is thankfully detached from basically all other hz computations. Thus, it's actually simplest to keep all other functionality as it is, i.e. the taps/speed metrics only act on inputs made while a piece is active. Negative delay is currently limited to -3. This choice is somewhat arbitrary and could reasonably be extended in the future, but I think this is pretty realistic for most people who do care about timing. To support other entry delay frames, add a call to checkNegativeDelay in the relevant branch, making sure to set X to the correct value. Negative values themselves are stored as the magnitude ORed with $80, so e.g. -2 is represented as $82. One tricky part is that the entry delay pipeline techincally has multiple paths. The normal path goes through playState_receiveGarbage once and playState_spawnNextTetrimino twice as the last three frames, but the game can spend many more frames in playState_spawnNextTetrimino if the spawnDelay parameter is set, which is done in the tspin and debug modes. There is extra logic to handle positive spawnDelay, but any other changes to how entry delay works might require further refactoring.
1 parent 6c86554 commit 2fc570e

File tree

5 files changed

+62
-8
lines changed

5 files changed

+62
-8
lines changed

src/gamemodestate/initstate.asm

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ gameModeState_initGameState:
149149
@noTypeBPlayfield:
150150

151151
jsr hzStart
152+
lda #0
153+
sta hzSpawnDelay
152154
jsr practiseInitGameState
153155
jsr resetScroll
154156

src/modes/hz.asm

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ hzDebounceThreshold := $10
99

1010
hzStart: ; called in playState_spawnNextTetrimino, gameModeState_initGameState, gameMode_gameTypeMenu
1111
lda #0
12-
sta hzSpawnDelay
1312
sta hzTapCounter
1413
lda #hzDebounceThreshold
1514
sta hzDebounceCounter
@@ -50,7 +49,7 @@ hzControl: ; called in playState_playerControlsActiveTetrimino, gameTypeLoopCont
5049
bne @noDelayInc
5150
lda hzSpawnDelay
5251
cmp #$F
53-
beq @noDelayInc
52+
bcs @noDelayInc
5453
inc hzSpawnDelay
5554
@noDelayInc:
5655
rts
@@ -183,6 +182,33 @@ hzTap:
183182
sta renderFlags
184183
rts
185184

185+
; X: value to store if left or right is newly pressed
186+
checkNegativeDelay:
187+
; the tail of entry delay has two paths: a normal path, and one where
188+
; spawn delay is added (currently, tspins and debug mode)
189+
; if the spawn delay is too large, we shouldn't update here
190+
lda spawnDelay
191+
cmp #3
192+
bcs @ret
193+
lda hzSpawnDelay
194+
bne @ret
195+
lda newlyPressedButtons_player1
196+
and #BUTTON_DPAD
197+
cmp #BUTTON_LEFT
198+
beq @setDelay
199+
lda newlyPressedButtons_player1
200+
and #BUTTON_DPAD
201+
cmp #BUTTON_RIGHT
202+
beq @setDelay
203+
rts
204+
@setDelay:
205+
stx hzSpawnDelay
206+
lda renderFlags
207+
ora #$10
208+
sta renderFlags
209+
@ret:
210+
rts
211+
186212
dasLimitLookup:
187213
.byte 0, 0, 4, 11, 18, 24, 30, 36, 42 , 48; , 54, 60
188214
.byte 0, 0, 3, 7, 12, 16, 20, 24, 28, 32 ; PAL

src/nmi/render_hz.asm

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
11
renderHz:
22
; only set at game start and when player is controlling a piece
33
; during which, no other tile updates are happening
4-
; this is pretty expensive and uses up $7 PPU tile writes and 1 palette write
4+
; this is pretty expensive and uses up $8 PPU tile writes and 1 palette write
55

66
; delay
77

88
lda #$22
99
sta PPUADDR
10-
lda #$68
10+
lda #$67
1111
sta PPUADDR
12+
ldx #$24 ; minus sign
1213
lda hzSpawnDelay
14+
and #$80
15+
bne @isNegative
16+
ldx #$FF ; blank tile
17+
@isNegative:
18+
stx PPUDATA
19+
lda hzSpawnDelay
20+
and #$7F ; clear sign flag
1321
sta PPUDATA
1422

1523
renderHzSpeedTest:

src/playstate/garbage.asm

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,12 @@ playState_receiveGarbage:
3737
lda #$00
3838
sta pendingGarbage
3939
sta vramRow
40-
@ret: inc playState
41-
@delay: rts
40+
@ret: inc playState
41+
lda #$00 ; earliest possible measured point
42+
sta hzSpawnDelay
43+
ldx #$83 ; -3 tap delay
44+
jsr checkNegativeDelay
45+
rts
4246

4347

4448
garbageLines:

src/playstate/spawnnext.asm

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,24 @@ SPAWN_NEXT_ADDONS := 1
33
playState_spawnNextTetrimino:
44
lda vramRow
55
cmp #$20
6-
bmi @ret
6+
bpl :+
7+
ldx #$82 ; -2 tap delay
8+
jsr checkNegativeDelay
9+
rts
710

11+
:
812
.if SPAWN_NEXT_ADDONS
913
lda spawnDelay
1014
beq @notDelaying
15+
; here, spawnDelay=1 means hzSpawnDelay=-2, 2 implies -3, and etc.
16+
cmp #3 ; if spawnDelay is >= 3, don't update
17+
bcs @noCheck
18+
clc
19+
adc #1
20+
ora #$80 ; mark delay as negative
21+
tax
22+
jsr checkNegativeDelay
23+
@noCheck:
1124
dec spawnDelay
1225
jmp @ret
1326
.endif
@@ -24,7 +37,8 @@ playState_spawnNextTetrimino:
2437
sta saveStateDirty
2538
rts
2639
@noSaveState:
27-
40+
ldx #$81 ; -1 tap delay
41+
jsr checkNegativeDelay
2842
jsr hzStart
2943
.endif
3044

0 commit comments

Comments
 (0)