1691 lines
32 KiB
NASM
1691 lines
32 KiB
NASM
; DMGTRIS
|
|
; Copyright (C) 2023 - Randy Thiemann <randy.thiemann@gmail.com>
|
|
|
|
; This program is free software: you can redistribute it and/or modify
|
|
; it under the terms of the GNU General Public License as published by
|
|
; the Free Software Foundation, either version 3 of the License, or
|
|
; (at your option) any later version.
|
|
|
|
; This program is distributed in the hope that it will be useful,
|
|
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
; GNU General Public License for more details.
|
|
|
|
; You should have received a copy of the GNU General Public License
|
|
; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
|
IF !DEF(STATE_GAMEPLAY_ASM)
|
|
DEF STATE_GAMEPLAY_ASM EQU 1
|
|
|
|
|
|
INCLUDE "globals.asm"
|
|
INCLUDE "res/gameplay_data.inc"
|
|
INCLUDE "res/gameplay_big_data.inc"
|
|
|
|
|
|
SECTION "High Gameplay Variables", HRAM
|
|
hCurrentPiece:: ds 1
|
|
hCurrentPieceX:: ds 1
|
|
hCurrentPieceY:: ds 1
|
|
hCurrentPieceRotationState:: ds 1
|
|
hHeldPiece:: ds 1
|
|
hHoldSpent:: ds 1
|
|
hMode:: ds 1
|
|
hModeCounter: ds 1
|
|
hPrePause: ds 1
|
|
hRequestedJingle: ds 1
|
|
|
|
|
|
SECTION "Gameplay Variables", WRAM0
|
|
wRollLine: ds 1
|
|
wInStaffRoll:: ds 1
|
|
wBigModeTransfered: ds 1
|
|
wGameOverIgnoreInput: ds 1
|
|
|
|
|
|
SECTION "Gameplay Function Trampolines", ROM0
|
|
; Trampolines to the banked function.
|
|
SwitchToGameplay::
|
|
ld b, BANK_GAMEPLAY
|
|
rst RSTSwitchBank
|
|
call SwitchToGameplayB
|
|
jp RSTRestoreBank
|
|
|
|
; Trampolines to the banked function.
|
|
SwitchToGameplayBig::
|
|
ld b, BANK_GAMEPLAY_BIG
|
|
rst RSTSwitchBank
|
|
call SwitchToGameplayBigB
|
|
jp RSTRestoreBank
|
|
|
|
; Banks and jumps to the actual handler.
|
|
GamePlayEventLoopHandler::
|
|
ld b, BANK_GAMEPLAY
|
|
rst RSTSwitchBank
|
|
call GamePlayEventLoopHandlerB
|
|
rst RSTRestoreBank
|
|
jp EventLoopPostHandler
|
|
|
|
; Banks and jumps to the actual handler.
|
|
GamePlayBigEventLoopHandler::
|
|
ld b, BANK_GAMEPLAY_BIG
|
|
rst RSTSwitchBank
|
|
call GamePlayBigEventLoopHandlerB
|
|
rst RSTRestoreBank
|
|
jp EventLoopPostHandler
|
|
|
|
|
|
SECTION "Gameplay Function Banked", ROMX, BANK[BANK_GAMEPLAY]
|
|
; Change to game play mode. The event loop will call the event loop and vblank handlers for this mode after this returns.
|
|
SwitchToGameplayB:
|
|
; Turn the screen off if it's on.
|
|
ldh a, [rLCDC]
|
|
and LCDCF_ON
|
|
jr z, .loadtilemap ; Screen is already off.
|
|
wait_vram
|
|
xor a, a
|
|
ldh [rLCDC], a
|
|
|
|
; Load the gameplay tilemap.
|
|
.loadtilemap
|
|
ld a, [wSpeedCurveState]
|
|
cp a, SCURVE_CHIL
|
|
jr z, .ungraded
|
|
cp a, SCURVE_MYCO
|
|
jr z, .ungraded
|
|
cp a, SCURVE_TGM3 ; TODO: Remove when this one has grades.
|
|
jr z, .ungraded
|
|
|
|
.graded
|
|
ld de, sGameplayTileMap
|
|
ld hl, $9800
|
|
ld bc, sGameplayTileMapEnd - sGameplayTileMap
|
|
call UnsafeMemCopy
|
|
jr .loadtiles
|
|
|
|
.ungraded
|
|
ld de, sGameplayUngradedTileMap
|
|
ld hl, $9800
|
|
ld bc, sGameplayUngradedTileMapEnd - sGameplayUngradedTileMap
|
|
call UnsafeMemCopy
|
|
|
|
; And the tiles.
|
|
.loadtiles
|
|
call LoadGameplayTiles
|
|
|
|
; Zero out SCX.
|
|
ld a, -2
|
|
ldh [rSCX], a
|
|
|
|
; Screen squish for title.
|
|
call EnableScreenSquish
|
|
|
|
; Clear OAM.
|
|
call ClearOAM
|
|
call SetNumberSpritePositions
|
|
call ApplyTells
|
|
|
|
; Set up the palettes.
|
|
ld a, PALETTE_REGULAR
|
|
set_bg_palette
|
|
set_obj0_palette
|
|
ld a, PALETTE_LIGHTER_1
|
|
set_obj1_palette
|
|
|
|
; Initialize the RNG.
|
|
call RNGInit
|
|
|
|
; Initialize the score, level and field.
|
|
call ScoreInit
|
|
call LevelInit
|
|
call FieldInit
|
|
call GradeInit
|
|
|
|
; We don't start with hold spent.
|
|
xor a, a
|
|
ldh [hHoldSpent], a
|
|
ld [wInStaffRoll], a
|
|
|
|
; Leady mode.
|
|
ld a, MODE_LEADY
|
|
ldh [hMode], a
|
|
ld a, LEADY_TIME
|
|
ldh [hModeCounter], a
|
|
|
|
; GBC init
|
|
call GBCGameplayInit
|
|
|
|
; Install the event loop handlers.
|
|
ld a, STATE_GAMEPLAY
|
|
ldh [hGameState], a
|
|
|
|
; And turn the LCD back on before we start.
|
|
ld a, LCDCF_ON | LCDCF_BGON | LCDCF_OBJON | LCDCF_BLK01
|
|
ldh [rLCDC], a
|
|
|
|
; Music end
|
|
call SFXKill
|
|
|
|
; Make sure the first game loop starts just like all the future ones.
|
|
wait_vblank
|
|
wait_vblank_end
|
|
ret
|
|
|
|
|
|
; Main gameplay event loop.
|
|
GamePlayEventLoopHandlerB::
|
|
; Are we in staff roll?
|
|
ld a, [wInStaffRoll]
|
|
cp a, $FF
|
|
jr nz, .normalevent
|
|
|
|
; Are we in a non-game over mode?
|
|
ldh a, [hMode]
|
|
cp a, MODE_GAME_OVER
|
|
jr z, .normalevent
|
|
|
|
; Did we run out of time?
|
|
ld a, [wCountDownZero]
|
|
cp a, $FF
|
|
jp z, .preGameOverMode
|
|
|
|
; What mode are we in?
|
|
.normalevent
|
|
ld hl, .modejumps
|
|
ldh a, [hMode]
|
|
ld b, 0
|
|
ld c, a
|
|
add hl, bc
|
|
jp hl
|
|
|
|
.modejumps
|
|
jp .leadyMode
|
|
jp .goMode
|
|
jp .postGoMode
|
|
jp .prefetchedPieceMode
|
|
jp .spawnPieceMode
|
|
jp .pieceInMotionMode
|
|
jp .delayMode
|
|
jp .gameOverMode
|
|
jp .preGameOverMode
|
|
jp .pauseMode
|
|
jp .preRollMode
|
|
|
|
|
|
; Draw "READY" and wait a bit.
|
|
.leadyMode
|
|
call ResetGameTime
|
|
ldh a, [hModeCounter]
|
|
cp a, LEADY_TIME
|
|
jr nz, .firstleadyiterskip
|
|
xor a, a
|
|
ld [wInStaffRoll], a
|
|
call SFXKill
|
|
ld a, SFX_READYGO
|
|
call SFXEnqueue
|
|
xor a, a
|
|
ld [wReturnToSmall], a
|
|
ldh a, [hModeCounter]
|
|
.firstleadyiterskip
|
|
dec a
|
|
jr nz, .notdoneleady
|
|
ld a, MODE_GO
|
|
ldh [hMode], a
|
|
ld a, GO_TIME
|
|
.notdoneleady
|
|
ldh [hModeCounter], a
|
|
ld de, sLeady
|
|
ld hl, wField+(14*10)
|
|
ld bc, 10
|
|
call UnsafeMemCopy
|
|
jp .drawStaticInfo
|
|
|
|
|
|
; Draw "GO" and wait a bit.
|
|
.goMode
|
|
call ResetGameTime
|
|
ldh a, [hModeCounter]
|
|
dec a
|
|
jr nz, .notdonego
|
|
ld a, MODE_POSTGO
|
|
ldh [hMode], a
|
|
xor a, a
|
|
.notdonego
|
|
ldh [hModeCounter], a
|
|
ld de, sGo
|
|
ld hl, wField+(14*10)
|
|
ld bc, 10
|
|
call UnsafeMemCopy
|
|
jp .drawStaticInfo
|
|
|
|
|
|
; Clear the field, fetch the piece, ready for gameplay.
|
|
.postGoMode
|
|
ld a, MODE_PREFETCHED_PIECE
|
|
ldh [hMode], a
|
|
call FieldClear
|
|
call ToShadowField
|
|
ldh a, [hNextPiece]
|
|
ldh [hCurrentPiece], a
|
|
call GetNextPiece
|
|
call ResetGameTime
|
|
jp .drawStaticInfo
|
|
|
|
|
|
; Fetch the next piece.
|
|
.prefetchedPieceMode
|
|
; A piece will spawn in the middle, at the top of the screen, not rotated by default.
|
|
ld a, $FF
|
|
ldh [hRequestedJingle], a
|
|
ld a, PIECE_SPAWN_X
|
|
ldh [hCurrentPieceX], a
|
|
ld a, PIECE_SPAWN_Y
|
|
ldh [hCurrentPieceY], a
|
|
xor a, a ; ROTATION_STATE_DEF
|
|
ldh [hCurrentPieceRotationState], a
|
|
ldh [hHoldSpent], a
|
|
|
|
; Check if IHS is requested.
|
|
; Apply the hold if so.
|
|
.checkIHS
|
|
ldh a, [hSelectState]
|
|
or a, a
|
|
jr z, .loaddefaultjingle
|
|
call DoHold
|
|
jr .postjingle
|
|
|
|
; Enqueue the jingle.
|
|
.loaddefaultjingle
|
|
ldh a, [hNextPiece]
|
|
ldh [hRequestedJingle], a
|
|
|
|
; Check if IRS is requested.
|
|
; Apply the rotation if so.
|
|
.checkIRSA
|
|
ld a, [wSwapABState]
|
|
or a, a
|
|
jr z, .lda1
|
|
.ldb1
|
|
ldh a, [hBState]
|
|
or a, a
|
|
jr z, .checkIRSB
|
|
ld a, $FF
|
|
ldh [hBState], a
|
|
jr .cp1
|
|
.lda1
|
|
ldh a, [hAState]
|
|
or a, a
|
|
jr z, .checkIRSB
|
|
ld a, $FF
|
|
ldh [hAState], a
|
|
.cp1
|
|
ld a, ROTATION_STATE_CCW
|
|
ldh [hCurrentPieceRotationState], a
|
|
ldh a, [hNextPiece]
|
|
ld b, a
|
|
ld a, SFX_IRS
|
|
or a, b
|
|
ldh [hRequestedJingle], a
|
|
jr .postjingle
|
|
|
|
.checkIRSB
|
|
ld a, [wSwapABState]
|
|
or a, a
|
|
jr z, .ldb2
|
|
.lda2
|
|
ldh a, [hAState]
|
|
or a, a
|
|
jr z, .postjingle
|
|
ld a, $FF
|
|
ldh [hAState], a
|
|
jr .cp2
|
|
.ldb2
|
|
ldh a, [hBState]
|
|
or a, a
|
|
jr z, .postjingle
|
|
ld a, $FF
|
|
ldh [hBState], a
|
|
.cp2
|
|
ld a, ROTATION_STATE_CW
|
|
ldh [hCurrentPieceRotationState], a
|
|
ldh a, [hNextPiece]
|
|
ld b, a
|
|
ld a, SFX_IRS
|
|
or a, b
|
|
ldh [hRequestedJingle], a
|
|
jr .postjingle
|
|
|
|
.postjingle
|
|
ld a, MODE_SPAWN_PIECE
|
|
ldh [hMode], a
|
|
; State falls through to the next.
|
|
|
|
|
|
; Spawn the piece.
|
|
.spawnPieceMode
|
|
call TrySpawnPiece
|
|
cp a, $FF
|
|
jr z, .canspawn
|
|
ld a, MODE_PRE_GAME_OVER
|
|
ldh [hMode], a
|
|
jp .drawStaticInfo
|
|
.canspawn
|
|
ld a, MODE_PIECE_IN_MOTION
|
|
ldh [hMode], a
|
|
|
|
; Play the next jingle... maybe!
|
|
ldh a, [hHoldSpent]
|
|
cp a, $FF
|
|
jr z, .pieceInMotionMode
|
|
ldh a, [hRequestedJingle]
|
|
cp a, $FF
|
|
jr z, .pieceInMotionMode
|
|
call SFXEnqueue
|
|
|
|
|
|
; This mode lasts for as long as the piece is in motion.
|
|
; Field will let us know when it has locked in place.
|
|
.pieceInMotionMode
|
|
ldh a, [hStartState]
|
|
cp a, 1
|
|
jr nz, .nopauserequested
|
|
call ToBackupField
|
|
ldh a, [hMode]
|
|
ldh [hPrePause], a
|
|
ld a, MODE_PAUSED
|
|
ldh [hMode], a
|
|
jp .drawStaticInfo
|
|
|
|
.nopauserequested
|
|
call FieldProcess
|
|
|
|
; Do we hold?
|
|
ldh a, [hSelectState]
|
|
cp a, 1
|
|
jr nz, .nohold
|
|
ldh a, [hHoldSpent]
|
|
cp a, $FF
|
|
jr z, .nohold
|
|
; Reset position and rotation.
|
|
ld a, PIECE_SPAWN_X
|
|
ldh [hCurrentPieceX], a
|
|
ld a, PIECE_SPAWN_Y
|
|
ldh [hCurrentPieceY], a
|
|
xor a, a ; ROTATION_STATE_DEF
|
|
ldh [hCurrentPieceRotationState], a
|
|
call DoHold
|
|
ld a, MODE_SPAWN_PIECE
|
|
ldh [hMode], a
|
|
|
|
; Do we go into delay state?
|
|
.nohold
|
|
ldh a, [hCurrentLockDelayRemaining]
|
|
or a, a
|
|
jp nz, .drawStaticInfo
|
|
ld a, MODE_DELAY
|
|
ldh [hMode], a
|
|
; No fall through this time.
|
|
|
|
jp .drawStaticInfo
|
|
|
|
|
|
.delayMode
|
|
ldh a, [hStartState]
|
|
cp a, 1
|
|
jr nz, .nodelaypauserequested
|
|
call ToBackupField
|
|
ldh a, [hMode]
|
|
ldh [hPrePause], a
|
|
ld a, MODE_PAUSED
|
|
ldh [hMode], a
|
|
jp .drawStaticInfo
|
|
|
|
.nodelaypauserequested
|
|
call FieldDelay
|
|
|
|
ldh a, [hRemainingDelay]
|
|
or a, a
|
|
jp nz, .drawStaticInfo
|
|
ld a, [wInStaffRoll]
|
|
cp a, $FF
|
|
jr z, .next
|
|
ld a, [wShouldGoStaffRoll]
|
|
cp a, $FF
|
|
jr z, .goroll
|
|
.next
|
|
ld a, MODE_PREFETCHED_PIECE
|
|
ldh [hMode], a
|
|
jp .drawStaticInfo
|
|
.goroll
|
|
ld a, MODE_PREROLL
|
|
ldh [hMode], a
|
|
xor a, a
|
|
ld [wRollLine], a
|
|
ld a, 10
|
|
ldh [hModeCounter], a
|
|
jp .drawStaticInfo
|
|
|
|
|
|
.preGameOverMode
|
|
ld a, $FF
|
|
ld [wGameOverIgnoreInput], a
|
|
|
|
; Is it just a regular game over?
|
|
ld a, [wKillScreenActive]
|
|
cp a, $FF
|
|
jr nz, .regular
|
|
|
|
; GM congratulations?
|
|
ld a, [wDisplayedGrade]
|
|
cp a, GRADE_GM
|
|
jr z, .gm
|
|
|
|
; Condescend if we're not NONE grade.
|
|
cp a, GRADE_NONE
|
|
jr nz, .condescend
|
|
|
|
; And if we're DQeq.
|
|
ld a, [wRankingDisqualified]
|
|
cp a, $FF
|
|
jr z, .condescend
|
|
|
|
.gm
|
|
call FieldInit
|
|
ld de, sYouAreGM
|
|
ld hl, wField+(5*10)
|
|
ld bc, 100
|
|
call UnsafeMemCopy
|
|
|
|
ld a, MODE_GAME_OVER
|
|
ldh [hMode], a
|
|
|
|
jp .gameOverMode
|
|
|
|
.condescend
|
|
call FieldInit
|
|
ld de, sKill
|
|
ld hl, wField+(5*10)
|
|
ld bc, 160
|
|
call UnsafeMemCopy
|
|
|
|
ld a, MODE_GAME_OVER
|
|
ldh [hMode], a
|
|
|
|
jp .gameOverMode
|
|
|
|
.regular
|
|
; Spawn the failed piece.
|
|
call ForceSpawnPiece
|
|
|
|
; Draw the field in grey.
|
|
; Yes. This really unrolls the loop that many times.
|
|
ld hl, wField+(3*10)
|
|
REPT 70
|
|
ld a, [hl]
|
|
cp a, TILE_FIELD_EMPTY
|
|
jr nz, .notempty1\@
|
|
ld a, GAME_OVER_OTHER+1
|
|
ld [hl+], a
|
|
jr .skip1\@
|
|
.notempty1\@
|
|
ld a, GAME_OVER_OTHER
|
|
ld [hl+], a
|
|
.skip1\@
|
|
ENDR
|
|
DEF off = 0
|
|
REPT 10
|
|
ld a, [hl]
|
|
cp a, TILE_FIELD_EMPTY
|
|
jr nz, .notempty2\@
|
|
ld a, GAME_OVER_R10+10+off
|
|
ld [hl+], a
|
|
jr .skip2\@
|
|
.notempty2\@
|
|
ld a, GAME_OVER_R10+off
|
|
ld [hl+], a
|
|
.skip2\@
|
|
DEF off += 1
|
|
ENDR
|
|
REPT 10
|
|
ld a, [hl]
|
|
cp a, TILE_FIELD_EMPTY
|
|
jr nz, .notempty3\@
|
|
ld a, GAME_OVER_OTHER+1
|
|
ld [hl+], a
|
|
jr .skip3\@
|
|
.notempty3\@
|
|
ld a, GAME_OVER_OTHER
|
|
ld [hl+], a
|
|
.skip3\@
|
|
ENDR
|
|
DEF off = 0
|
|
REPT 10
|
|
ld a, [hl]
|
|
cp a, TILE_FIELD_EMPTY
|
|
jr nz, .notempty4\@
|
|
ld a, GAME_OVER_R12+10+off
|
|
ld [hl+], a
|
|
jr .skip4\@
|
|
.notempty4\@
|
|
ld a, GAME_OVER_R12+off
|
|
ld [hl+], a
|
|
.skip4\@
|
|
DEF off += 1
|
|
ENDR
|
|
REPT 10
|
|
ld a, [hl]
|
|
cp a, TILE_FIELD_EMPTY
|
|
jr nz, .notempty5\@
|
|
ld a, GAME_OVER_OTHER+1
|
|
ld [hl+], a
|
|
jr .skip5\@
|
|
.notempty5\@
|
|
ld a, GAME_OVER_OTHER
|
|
ld [hl+], a
|
|
.skip5\@
|
|
ENDR
|
|
DEF off = 0
|
|
REPT 10
|
|
ld a, [hl]
|
|
cp a, TILE_FIELD_EMPTY
|
|
jr nz, .notempty6\@
|
|
ld a, GAME_OVER_R14+10+off
|
|
ld [hl+], a
|
|
jr .skip6\@
|
|
.notempty6\@
|
|
ld a, GAME_OVER_R14+off
|
|
ld [hl+], a
|
|
.skip6\@
|
|
DEF off += 1
|
|
ENDR
|
|
REPT 90
|
|
ld a, [hl]
|
|
cp a, TILE_FIELD_EMPTY
|
|
jr nz, .notempty7\@
|
|
ld a, GAME_OVER_OTHER+1
|
|
ld [hl+], a
|
|
jr .skip7\@
|
|
.notempty7\@
|
|
ld a, GAME_OVER_OTHER
|
|
ld [hl+], a
|
|
.skip7\@
|
|
ENDR
|
|
|
|
ld a, MODE_GAME_OVER
|
|
ldh [hMode], a
|
|
|
|
|
|
.gameOverMode
|
|
; Wait for A and B to not be held down.
|
|
ld a, [wGameOverIgnoreInput]
|
|
or a, a
|
|
jr z, .checkretry
|
|
|
|
ldh a, [hAState]
|
|
or a, a
|
|
jp nz, .drawStaticInfo
|
|
ldh a, [hBState]
|
|
or a, a
|
|
jp nz, .drawStaticInfo
|
|
|
|
xor a, a
|
|
ld [wGameOverIgnoreInput], a
|
|
jp .drawStaticInfo
|
|
|
|
; Retry?
|
|
.checkretry
|
|
ldh a, [hAState]
|
|
cp a, 10
|
|
jr nz, .noretry
|
|
call CheckAndAddHiscore
|
|
call RNGInit
|
|
call ScoreInit
|
|
call LevelInit
|
|
call FieldInit
|
|
call GradeInit
|
|
xor a, a
|
|
ldh [hHoldSpent], a
|
|
ld [wInStaffRoll], a
|
|
ld a, MODE_LEADY
|
|
ldh [hMode], a
|
|
ld a, LEADY_TIME
|
|
ldh [hModeCounter], a
|
|
jp .drawStaticInfo
|
|
|
|
; Quit
|
|
.noretry
|
|
ldh a, [hBState]
|
|
cp a, 10
|
|
jp nz, .drawStaticInfo
|
|
call CheckAndAddHiscore
|
|
jp SwitchToTitle
|
|
|
|
|
|
.pauseMode
|
|
; Quick reset.
|
|
ldh a, [hAState]
|
|
or a, a
|
|
jr z, .noqr
|
|
ldh a, [hBState]
|
|
or a, a
|
|
jr z, .noqr
|
|
ldh a, [hSelectState]
|
|
or a, a
|
|
jr z, .noqr
|
|
jp SwitchToTitle
|
|
|
|
; Unpause
|
|
.noqr
|
|
ldh a, [hStartState]
|
|
cp a, 1
|
|
jr nz, .nounpause
|
|
call FromBackupField
|
|
ldh a, [hPrePause]
|
|
ldh [hMode], a
|
|
xor a, a
|
|
ldh [hLeftState], a
|
|
ldh [hRightState], a
|
|
jp .drawStaticInfo
|
|
|
|
; Draw PAUSE all over the field.
|
|
.nounpause
|
|
ld de, sPause
|
|
ld hl, wField+(0*10)
|
|
ld bc, 40
|
|
call UnsafeMemCopy
|
|
ld de, sPause
|
|
ld hl, wField+(4*10)
|
|
ld bc, 40
|
|
call UnsafeMemCopy
|
|
ld de, sPause
|
|
ld hl, wField+(8*10)
|
|
ld bc, 40
|
|
call UnsafeMemCopy
|
|
ld de, sPause
|
|
ld hl, wField+(12*10)
|
|
ld bc, 40
|
|
call UnsafeMemCopy
|
|
ld de, sPause
|
|
ld hl, wField+(16*10)
|
|
ld bc, 40
|
|
call UnsafeMemCopy
|
|
ld de, sPause
|
|
ld hl, wField+(20*10)
|
|
ld bc, 40
|
|
call UnsafeMemCopy
|
|
jr .drawStaticInfo
|
|
|
|
|
|
; Prepare for staff roll.
|
|
.preRollMode
|
|
ldh a, [hModeCounter]
|
|
dec a
|
|
ldh [hModeCounter], a
|
|
jr nz, .drawStaticInfo
|
|
|
|
; Copy one more line onto the field.
|
|
ld b, 0
|
|
ld a, [wRollLine]
|
|
ld c, a
|
|
ld hl, sFinalChallenge
|
|
add hl, bc
|
|
ld d, h
|
|
ld e, l
|
|
ld hl, wField+(3*10)
|
|
add hl, bc
|
|
ld bc, 10
|
|
call UnsafeMemCopy
|
|
|
|
; Update the offset.
|
|
ld a, [wRollLine]
|
|
add a, 10
|
|
cp a, 210 ; Done?
|
|
jr z, .predone
|
|
ld [wRollLine], a
|
|
ld a, 10
|
|
ldh [hModeCounter], a
|
|
jr .drawStaticInfo
|
|
|
|
.predone
|
|
call FieldClear
|
|
ld a, MODE_PREFETCHED_PIECE
|
|
ldh [hMode], a
|
|
ld a, $FF
|
|
ld [wInStaffRoll], a
|
|
ld a, [wBigStaffRoll]
|
|
cp a, $FF
|
|
jr nz, .staysmall
|
|
call GoBig
|
|
.staysmall
|
|
call ToShadowField
|
|
ldh a, [hNextPiece]
|
|
ldh [hCurrentPiece], a
|
|
call GetNextPiece
|
|
call SFXKill
|
|
ld hl, wStaffRollDuration
|
|
ld a, [hl+]
|
|
ld c, a
|
|
ld b, [hl]
|
|
jp StartCountdown
|
|
|
|
|
|
; Always draw the score, level, next piece, and held piece.
|
|
.drawStaticInfo
|
|
call SetPal
|
|
|
|
ldh a, [hNextPiece]
|
|
call ApplyNext
|
|
|
|
ldh a, [hHeldPiece]
|
|
call ApplyHold
|
|
|
|
ld hl, wSPRScore1
|
|
ld de, hScore
|
|
call ApplyNumbers8
|
|
|
|
ld hl, wSPRCLevel1
|
|
ld de, hCLevel
|
|
call ApplyNumbers4
|
|
|
|
ld hl, wSPRNLevel1
|
|
ld de, hNLevel
|
|
call ApplyNumbers4
|
|
|
|
call SetNumberSpritePositions
|
|
call ApplyTells
|
|
call ApplyTime
|
|
|
|
jp GBCGameplayProcess
|
|
|
|
|
|
; Do the hold action.
|
|
DoHold:
|
|
; Mark hold as spent.
|
|
ld a, $FF
|
|
ldh [hHoldSpent], a
|
|
|
|
; Check if IRS is requested.
|
|
; Apply the rotation if so.
|
|
.checkIRSA
|
|
ld a, [wSwapABState]
|
|
or a, a
|
|
jr z, .lda3
|
|
.ldb3
|
|
ldh a, [hBState]
|
|
or a, a
|
|
jr z, .checkIRSB
|
|
ld a, $FF
|
|
ldh [hBState], a
|
|
jr .cp3
|
|
.lda3
|
|
ldh a, [hAState]
|
|
or a, a
|
|
jr z, .checkIRSB
|
|
ld a, $FF
|
|
ldh [hAState], a
|
|
.cp3
|
|
ld a, ROTATION_STATE_CCW
|
|
ldh [hCurrentPieceRotationState], a
|
|
call SFXKill
|
|
ld a, SFX_IRS | SFX_IHS
|
|
call SFXEnqueue
|
|
jr .doHoldOperation
|
|
|
|
.checkIRSB
|
|
ld a, [wSwapABState]
|
|
or a, a
|
|
jr z, .ldb4
|
|
.lda4
|
|
ldh a, [hAState]
|
|
or a, a
|
|
jr z, .noRotation
|
|
ld a, $FF
|
|
ldh [hAState], a
|
|
jr .cp4
|
|
.ldb4
|
|
ldh a, [hBState]
|
|
or a, a
|
|
jr z, .noRotation
|
|
ld a, $FF
|
|
ldh [hBState], a
|
|
.cp4
|
|
ld a, ROTATION_STATE_CW
|
|
ldh [hCurrentPieceRotationState], a
|
|
call SFXKill
|
|
ld a, SFX_IRS | SFX_IHS
|
|
call SFXEnqueue
|
|
jr .doHoldOperation
|
|
|
|
.noRotation
|
|
call SFXKill
|
|
ld a, SFX_IHS
|
|
call SFXEnqueue
|
|
xor a, a ; ROTATION_STATE_DEF
|
|
ldh [hCurrentPieceRotationState], a
|
|
|
|
.doHoldOperation
|
|
ldh a, [hHeldPiece]
|
|
ld b, a
|
|
ldh a, [hCurrentPiece]
|
|
ldh [hHeldPiece], a
|
|
ld a, b
|
|
ldh [hCurrentPiece], a
|
|
ret
|
|
|
|
|
|
|
|
SECTION "Gameplay Function Big Banked", ROMX, BANK[BANK_GAMEPLAY_BIG]
|
|
; Change to game play mode. The event loop will call the event loop and vblank handlers for this mode after this returns.
|
|
SwitchToGameplayBigB:
|
|
; Turn the screen off if it's on.
|
|
ldh a, [rLCDC]
|
|
and LCDCF_ON
|
|
jr z, .loadtilemap ; Screen is already off.
|
|
wait_vram
|
|
xor a, a
|
|
ldh [rLCDC], a
|
|
|
|
; Load the gameplay tilemap.
|
|
.loadtilemap
|
|
ld a, [wSpeedCurveState]
|
|
cp a, SCURVE_CHIL
|
|
jr z, .ungraded
|
|
cp a, SCURVE_MYCO
|
|
jr z, .ungraded
|
|
cp a, SCURVE_TGM3 ; TODO: Remove when this one has grades.
|
|
jr z, .ungraded
|
|
|
|
.graded
|
|
ld de, sBigGameplayTileMap
|
|
ld hl, $9800
|
|
ld bc, sBigGameplayTileMapEnd - sBigGameplayTileMap
|
|
call UnsafeMemCopy
|
|
jr .loadtiles
|
|
|
|
.ungraded
|
|
ld de, sBigGameplayUngradedTileMap
|
|
ld hl, $9800
|
|
ld bc, sBigGameplayUngradedTileMapEnd - sBigGameplayUngradedTileMap
|
|
call UnsafeMemCopy
|
|
|
|
; And the tiles.
|
|
.loadtiles
|
|
call LoadGameplayTiles
|
|
|
|
; Zero out SCX.
|
|
ld a, -2
|
|
ldh [rSCX], a
|
|
|
|
; Screen squish for title.
|
|
call EnableScreenSquish
|
|
|
|
; Clear OAM.
|
|
call ClearOAM
|
|
call SetNumberSpritePositions
|
|
call ApplyTells
|
|
|
|
; Set up the palettes.
|
|
ld a, PALETTE_REGULAR
|
|
set_bg_palette
|
|
set_obj0_palette
|
|
ld a, PALETTE_LIGHTER_1
|
|
set_obj1_palette
|
|
|
|
; Initialize the RNG.
|
|
call RNGInit
|
|
|
|
; Initialize the score, level and field.
|
|
call ScoreInit
|
|
call LevelInit
|
|
call BigFieldInit
|
|
call GradeInit
|
|
|
|
; We don't start with hold spent.
|
|
xor a, a
|
|
ldh [hHoldSpent], a
|
|
ld [wInStaffRoll], a
|
|
|
|
; Leady mode.
|
|
ld a, MODE_LEADY
|
|
ldh [hMode], a
|
|
ld a, LEADY_TIME
|
|
ldh [hModeCounter], a
|
|
|
|
; GBC init
|
|
call GBCGameplayInit
|
|
|
|
; Install the event loop handlers.
|
|
ld a, STATE_GAMEPLAY_BIG
|
|
ldh [hGameState], a
|
|
|
|
; And turn the LCD back on before we start.
|
|
ld a, LCDCF_ON | LCDCF_BGON | LCDCF_OBJON | LCDCF_BLK01
|
|
ldh [rLCDC], a
|
|
|
|
; Music end
|
|
call SFXKill
|
|
|
|
; Make sure the first game loop starts just like all the future ones.
|
|
wait_vblank
|
|
wait_vblank_end
|
|
ret
|
|
|
|
|
|
; Main gameplay event loop.
|
|
GamePlayBigEventLoopHandlerB:
|
|
; Are we in staff roll?
|
|
ld a, [wInStaffRoll]
|
|
cp a, $FF
|
|
jr nz, .normalevent
|
|
|
|
; Are we in a non-game over mode?
|
|
ldh a, [hMode]
|
|
cp a, MODE_GAME_OVER
|
|
jr z, .normalevent
|
|
|
|
; Did we run out of time?
|
|
ld a, [wCountDownZero]
|
|
cp a, $FF
|
|
jp z, .preGameOverMode
|
|
|
|
; What mode are we in?
|
|
.normalevent
|
|
ld hl, .modejumps
|
|
ldh a, [hMode]
|
|
ld b, 0
|
|
ld c, a
|
|
add hl, bc
|
|
jp hl
|
|
|
|
.modejumps
|
|
jp .leadyMode
|
|
jp .goMode
|
|
jp .postGoMode
|
|
jp .prefetchedPieceMode
|
|
jp .spawnPieceMode
|
|
jp .pieceInMotionMode
|
|
jp .delayMode
|
|
jp .gameOverMode
|
|
jp .preGameOverMode
|
|
jp .pauseMode
|
|
jp .preRollMode
|
|
|
|
|
|
; Draw "READY" and wait a bit.
|
|
.leadyMode
|
|
call ResetGameTime
|
|
ldh a, [hModeCounter]
|
|
cp a, LEADY_TIME
|
|
jr nz, .firstleadyiterskip
|
|
xor a, a
|
|
ld [wInStaffRoll], a
|
|
call SFXKill
|
|
ld a, SFX_READYGO
|
|
call SFXEnqueue
|
|
xor a, a
|
|
ld [wReturnToSmall], a
|
|
ldh a, [hModeCounter]
|
|
.firstleadyiterskip
|
|
dec a
|
|
jr nz, .notdoneleady
|
|
ld a, MODE_GO
|
|
ldh [hMode], a
|
|
ld a, GO_TIME
|
|
.notdoneleady
|
|
ldh [hModeCounter], a
|
|
ld de, sBigLeady
|
|
ld hl, wWideBlittedField+(10*10)
|
|
ld bc, 10
|
|
call UnsafeMemCopy
|
|
jp .drawStaticInfo
|
|
|
|
|
|
; Draw "GO" and wait a bit.
|
|
.goMode
|
|
call ResetGameTime
|
|
ldh a, [hModeCounter]
|
|
dec a
|
|
jr nz, .notdonego
|
|
ld a, MODE_POSTGO
|
|
ldh [hMode], a
|
|
xor a, a
|
|
.notdonego
|
|
ldh [hModeCounter], a
|
|
ld de, sBigGo
|
|
ld hl, wWideBlittedField+(10*10)
|
|
ld bc, 10
|
|
call UnsafeMemCopy
|
|
jp .drawStaticInfo
|
|
|
|
|
|
; Clear the field, fetch the piece, ready for gameplay.
|
|
.postGoMode
|
|
ld a, MODE_PREFETCHED_PIECE
|
|
ldh [hMode], a
|
|
call BigFieldClear
|
|
call BigToShadowField
|
|
ldh a, [hNextPiece]
|
|
ldh [hCurrentPiece], a
|
|
call GetNextPiece
|
|
call ResetGameTime
|
|
jp .drawStaticInfo
|
|
|
|
|
|
; Fetch the next piece.
|
|
.prefetchedPieceMode
|
|
; A piece will spawn in the middle, at the top of the screen, not rotated by default.
|
|
ld a, $FF
|
|
ldh [hRequestedJingle], a
|
|
ld a, PIECE_SPAWN_X_BIG
|
|
ldh [hCurrentPieceX], a
|
|
ld a, PIECE_SPAWN_Y_BIG
|
|
ldh [hCurrentPieceY], a
|
|
xor a, a ; ROTATION_STATE_DEF
|
|
ldh [hCurrentPieceRotationState], a
|
|
ldh [hHoldSpent], a
|
|
|
|
; Check if IHS is requested.
|
|
; Apply the hold if so.
|
|
.checkIHS
|
|
ldh a, [hSelectState]
|
|
or a, a
|
|
jr z, .loaddefaultjingle
|
|
call BigDoHold
|
|
jr .postjingle
|
|
|
|
; Enqueue the jingle.
|
|
.loaddefaultjingle
|
|
ldh a, [hNextPiece]
|
|
ldh [hRequestedJingle], a
|
|
|
|
; Check if IRS is requested.
|
|
; Apply the rotation if so.
|
|
.checkIRSA
|
|
ld a, [wSwapABState]
|
|
or a, a
|
|
jr z, .lda1
|
|
.ldb1
|
|
ldh a, [hBState]
|
|
or a, a
|
|
jr z, .checkIRSB
|
|
ld a, $FF
|
|
ldh [hBState], a
|
|
jr .cp1
|
|
.lda1
|
|
ldh a, [hAState]
|
|
or a, a
|
|
jr z, .checkIRSB
|
|
ld a, $FF
|
|
ldh [hAState], a
|
|
.cp1
|
|
ld a, ROTATION_STATE_CCW
|
|
ldh [hCurrentPieceRotationState], a
|
|
ldh a, [hNextPiece]
|
|
ld b, a
|
|
ld a, SFX_IRS
|
|
or a, b
|
|
ldh [hRequestedJingle], a
|
|
jr .postjingle
|
|
|
|
.checkIRSB
|
|
ld a, [wSwapABState]
|
|
or a, a
|
|
jr z, .ldb2
|
|
.lda2
|
|
ldh a, [hAState]
|
|
or a, a
|
|
jr z, .postjingle
|
|
ld a, $FF
|
|
ldh [hAState], a
|
|
jr .cp2
|
|
.ldb2
|
|
ldh a, [hBState]
|
|
or a, a
|
|
jr z, .postjingle
|
|
ld a, $FF
|
|
ldh [hBState], a
|
|
.cp2
|
|
ld a, ROTATION_STATE_CW
|
|
ldh [hCurrentPieceRotationState], a
|
|
ldh a, [hNextPiece]
|
|
ld b, a
|
|
ld a, SFX_IRS
|
|
or a, b
|
|
ldh [hRequestedJingle], a
|
|
jr .postjingle
|
|
|
|
.postjingle
|
|
ld a, MODE_SPAWN_PIECE
|
|
ldh [hMode], a
|
|
; State falls through to the next.
|
|
|
|
|
|
; Spawn the piece.
|
|
.spawnPieceMode
|
|
call BigTrySpawnPiece
|
|
cp a, $FF
|
|
jr z, .canspawn
|
|
ld a, MODE_PRE_GAME_OVER
|
|
ldh [hMode], a
|
|
jp .drawStaticInfo
|
|
.canspawn
|
|
ld a, MODE_PIECE_IN_MOTION
|
|
ldh [hMode], a
|
|
|
|
; Play the next jingle... maybe!
|
|
ldh a, [hHoldSpent]
|
|
cp a, $FF
|
|
jr z, .pieceInMotionMode
|
|
ldh a, [hRequestedJingle]
|
|
cp a, $FF
|
|
jr z, .pieceInMotionMode
|
|
call SFXEnqueue
|
|
|
|
|
|
; This mode lasts for as long as the piece is in motion.
|
|
; Field will let us know when it has locked in place.
|
|
.pieceInMotionMode
|
|
ldh a, [hStartState]
|
|
cp a, 1
|
|
jr nz, .nopauserequested
|
|
call BigToBackupField
|
|
ldh a, [hMode]
|
|
ldh [hPrePause], a
|
|
ld a, MODE_PAUSED
|
|
ldh [hMode], a
|
|
jp .drawStaticInfo
|
|
|
|
.nopauserequested
|
|
call BigFieldProcess
|
|
|
|
; Do we hold?
|
|
ldh a, [hSelectState]
|
|
cp a, 1
|
|
jr nz, .nohold
|
|
ldh a, [hHoldSpent]
|
|
cp a, $FF
|
|
jr z, .nohold
|
|
; Reset position and rotation.
|
|
ld a, PIECE_SPAWN_X_BIG
|
|
ldh [hCurrentPieceX], a
|
|
ld a, PIECE_SPAWN_Y_BIG
|
|
ldh [hCurrentPieceY], a
|
|
xor a, a ; ROTATION_STATE_DEF
|
|
ldh [hCurrentPieceRotationState], a
|
|
call BigDoHold
|
|
ld a, MODE_SPAWN_PIECE
|
|
ldh [hMode], a
|
|
|
|
; Do we go into delay state?
|
|
.nohold
|
|
ldh a, [hCurrentLockDelayRemaining]
|
|
or a, a
|
|
jp nz, .drawStaticInfo
|
|
ld a, MODE_DELAY
|
|
ldh [hMode], a
|
|
; No fall through this time.
|
|
|
|
|
|
.delayMode
|
|
ldh a, [hStartState]
|
|
cp a, 1
|
|
jr nz, .nodelaypauserequested
|
|
call BigToBackupField
|
|
ldh a, [hMode]
|
|
ldh [hPrePause], a
|
|
ld a, MODE_PAUSED
|
|
ldh [hMode], a
|
|
jp .drawStaticInfo
|
|
|
|
.nodelaypauserequested
|
|
call BigFieldDelay
|
|
|
|
ldh a, [hRemainingDelay]
|
|
or a, a
|
|
jp nz, .drawStaticInfo
|
|
ld a, [wInStaffRoll]
|
|
cp a, $FF
|
|
jr z, .next
|
|
ld a, [wShouldGoStaffRoll]
|
|
cp a, $FF
|
|
jr z, .goroll
|
|
.next
|
|
ld a, MODE_PREFETCHED_PIECE
|
|
ldh [hMode], a
|
|
jp .drawStaticInfo
|
|
.goroll
|
|
ld a, MODE_PREROLL
|
|
ldh [hMode], a
|
|
xor a, a
|
|
ld [wRollLine], a
|
|
ld a, 10
|
|
ldh [hModeCounter], a
|
|
jp .drawStaticInfo
|
|
|
|
|
|
.preGameOverMode
|
|
ld a, $FF
|
|
ld [wGameOverIgnoreInput], a
|
|
|
|
; Is it just a regular game over?
|
|
ld a, [wKillScreenActive]
|
|
cp a, $FF
|
|
jr nz, .regular
|
|
|
|
; GM congratulations?
|
|
ld a, [wDisplayedGrade]
|
|
cp a, GRADE_GM
|
|
jr z, .gm
|
|
|
|
; Condescend if we're not NONE grade.
|
|
cp a, GRADE_NONE
|
|
jr nz, .condescend
|
|
|
|
; And if we're DQeq.
|
|
ld a, [wRankingDisqualified]
|
|
cp a, $FF
|
|
jr z, .condescend
|
|
|
|
.gm
|
|
call BigFieldInit
|
|
ld de, sBigYouAreGM
|
|
ld hl, wWideBlittedField+(3*10)
|
|
ld bc, 100
|
|
call UnsafeMemCopy
|
|
|
|
ld a, MODE_GAME_OVER
|
|
ldh [hMode], a
|
|
|
|
jp .gameOverMode
|
|
|
|
.condescend
|
|
call BigFieldInit
|
|
ld de, sBigKill
|
|
ld hl, wWideBlittedField+(3*10)
|
|
ld bc, 160
|
|
call UnsafeMemCopy
|
|
|
|
ld a, MODE_GAME_OVER
|
|
ldh [hMode], a
|
|
|
|
jp .gameOverMode
|
|
|
|
.regular
|
|
; Spawn the failed piece.
|
|
call BigForceSpawnPiece
|
|
call BigWidenField
|
|
|
|
; Draw the field in grey.
|
|
; Yes. This really unrolls the loop that many times.
|
|
ld hl, wWideBlittedField
|
|
REPT 60
|
|
ld a, [hl]
|
|
cp a, TILE_FIELD_EMPTY
|
|
jr nz, .notempty1\@
|
|
ld a, GAME_OVER_OTHER+1
|
|
ld [hl+], a
|
|
jr .skip1\@
|
|
.notempty1\@
|
|
ld a, GAME_OVER_OTHER
|
|
ld [hl+], a
|
|
.skip1\@
|
|
ENDR
|
|
DEF off = 0
|
|
REPT 10
|
|
ld a, [hl]
|
|
cp a, TILE_FIELD_EMPTY
|
|
jr nz, .notempty2\@
|
|
ld a, GAME_OVER_R10+10+off
|
|
ld [hl+], a
|
|
jr .skip2\@
|
|
.notempty2\@
|
|
ld a, GAME_OVER_R10+off
|
|
ld [hl+], a
|
|
.skip2\@
|
|
DEF off += 1
|
|
ENDR
|
|
REPT 10
|
|
ld a, [hl]
|
|
cp a, TILE_FIELD_EMPTY
|
|
jr nz, .notempty3\@
|
|
ld a, GAME_OVER_OTHER+1
|
|
ld [hl+], a
|
|
jr .skip3\@
|
|
.notempty3\@
|
|
ld a, GAME_OVER_OTHER
|
|
ld [hl+], a
|
|
.skip3\@
|
|
ENDR
|
|
DEF off = 0
|
|
REPT 10
|
|
ld a, [hl]
|
|
cp a, TILE_FIELD_EMPTY
|
|
jr nz, .notempty4\@
|
|
ld a, GAME_OVER_R12+10+off
|
|
ld [hl+], a
|
|
jr .skip4\@
|
|
.notempty4\@
|
|
ld a, GAME_OVER_R12+off
|
|
ld [hl+], a
|
|
.skip4\@
|
|
DEF off += 1
|
|
ENDR
|
|
REPT 10
|
|
ld a, [hl]
|
|
cp a, TILE_FIELD_EMPTY
|
|
jr nz, .notempty5\@
|
|
ld a, GAME_OVER_OTHER+1
|
|
ld [hl+], a
|
|
jr .skip5\@
|
|
.notempty5\@
|
|
ld a, GAME_OVER_OTHER
|
|
ld [hl+], a
|
|
.skip5\@
|
|
ENDR
|
|
DEF off = 0
|
|
REPT 10
|
|
ld a, [hl]
|
|
cp a, TILE_FIELD_EMPTY
|
|
jr nz, .notempty6\@
|
|
ld a, GAME_OVER_R14+10+off
|
|
ld [hl+], a
|
|
jr .skip6\@
|
|
.notempty6\@
|
|
ld a, GAME_OVER_R14+off
|
|
ld [hl+], a
|
|
.skip6\@
|
|
DEF off += 1
|
|
ENDR
|
|
REPT 110
|
|
ld a, [hl]
|
|
cp a, TILE_FIELD_EMPTY
|
|
jr nz, .notempty7\@
|
|
ld a, GAME_OVER_OTHER+1
|
|
ld [hl+], a
|
|
jr .skip7\@
|
|
.notempty7\@
|
|
ld a, GAME_OVER_OTHER
|
|
ld [hl+], a
|
|
.skip7\@
|
|
ENDR
|
|
|
|
ld a, MODE_GAME_OVER
|
|
ldh [hMode], a
|
|
|
|
|
|
.gameOverMode
|
|
; Wait for A and B to not be held down.
|
|
ld a, [wGameOverIgnoreInput]
|
|
or a, a
|
|
jr z, .checkretry
|
|
|
|
ldh a, [hAState]
|
|
or a, a
|
|
jp nz, .drawStaticInfo
|
|
ldh a, [hBState]
|
|
or a, a
|
|
jp nz, .drawStaticInfo
|
|
|
|
xor a, a
|
|
ld [wGameOverIgnoreInput], a
|
|
jp .drawStaticInfo
|
|
|
|
; Retry?
|
|
.checkretry
|
|
ldh a, [hAState]
|
|
cp a, 10
|
|
jr nz, .noretry
|
|
ld a, [wReturnToSmall]
|
|
cp a, $FF
|
|
jr z, .gosmall
|
|
call CheckAndAddHiscore
|
|
call RNGInit
|
|
call ScoreInit
|
|
call LevelInit
|
|
call BigFieldInit
|
|
call GradeInit
|
|
xor a, a
|
|
ldh [hHoldSpent], a
|
|
ld [wInStaffRoll], a
|
|
ld a, MODE_LEADY
|
|
ldh [hMode], a
|
|
ld a, LEADY_TIME
|
|
ldh [hModeCounter], a
|
|
jp .drawStaticInfo
|
|
|
|
.gosmall
|
|
call CheckAndAddHiscore
|
|
call RNGInit
|
|
call ScoreInit
|
|
call LevelInit
|
|
call GoSmall
|
|
call GradeInit
|
|
xor a, a
|
|
ldh [hHoldSpent], a
|
|
ld [wInStaffRoll], a
|
|
ld a, MODE_LEADY
|
|
ldh [hMode], a
|
|
ld a, LEADY_TIME
|
|
ldh [hModeCounter], a
|
|
jp .drawStaticInfo
|
|
|
|
|
|
; Quit
|
|
.noretry
|
|
ldh a, [hBState]
|
|
cp a, 10
|
|
jp nz, .drawStaticInfo
|
|
call CheckAndAddHiscore
|
|
jp SwitchToTitle
|
|
|
|
|
|
.pauseMode
|
|
; Quick reset.
|
|
ldh a, [hAState]
|
|
or a, a
|
|
jr z, .noqr
|
|
ldh a, [hBState]
|
|
or a, a
|
|
jr z, .noqr
|
|
ldh a, [hSelectState]
|
|
or a, a
|
|
jr z, .noqr
|
|
jp SwitchToTitle
|
|
|
|
; Unpause
|
|
.noqr
|
|
ldh a, [hStartState]
|
|
cp a, 1
|
|
jr nz, .nounpause
|
|
call BigFromBackupField
|
|
ldh a, [hPrePause]
|
|
ldh [hMode], a
|
|
xor a, a
|
|
ldh [hLeftState], a
|
|
ldh [hRightState], a
|
|
jp .drawStaticInfo
|
|
|
|
; Draw PAUSE all over the field.
|
|
.nounpause
|
|
ld de, sBigPause
|
|
ld hl, wWideBlittedField+(0*10)
|
|
ld bc, 40
|
|
call UnsafeMemCopy
|
|
ld de, sBigPause
|
|
ld hl, wWideBlittedField+(4*10)
|
|
ld bc, 40
|
|
call UnsafeMemCopy
|
|
ld de, sBigPause
|
|
ld hl, wWideBlittedField+(8*10)
|
|
ld bc, 40
|
|
call UnsafeMemCopy
|
|
ld de, sBigPause
|
|
ld hl, wWideBlittedField+(12*10)
|
|
ld bc, 40
|
|
call UnsafeMemCopy
|
|
ld de, sBigPause
|
|
ld hl, wWideBlittedField+(16*10)
|
|
ld bc, 40
|
|
call UnsafeMemCopy
|
|
ld de, sBigPause
|
|
ld hl, wWideBlittedField+(20*10)
|
|
ld bc, 20
|
|
call UnsafeMemCopy
|
|
jp .drawStaticInfo
|
|
|
|
|
|
; Prepare for staff roll.
|
|
.preRollMode
|
|
ldh a, [hModeCounter]
|
|
dec a
|
|
ldh [hModeCounter], a
|
|
jr nz, .drawStaticInfo
|
|
|
|
; Copy one more line onto the field.
|
|
ld b, 0
|
|
ld a, [wRollLine]
|
|
ld c, a
|
|
ld hl, sBigFinalChallenge
|
|
add hl, bc
|
|
ld d, h
|
|
ld e, l
|
|
ld hl, wWideBlittedField+(1*10)
|
|
add hl, bc
|
|
ld bc, 10
|
|
call UnsafeMemCopy
|
|
|
|
; Update the offset.
|
|
ld a, [wRollLine]
|
|
add a, 10
|
|
cp a, 210 ; Done?
|
|
jr z, .predone
|
|
ld [wRollLine], a
|
|
ld a, 10
|
|
ldh [hModeCounter], a
|
|
jr .drawStaticInfo
|
|
|
|
.predone
|
|
call BigFieldClear
|
|
call BigToShadowField
|
|
ld a, MODE_PREFETCHED_PIECE
|
|
ldh [hMode], a
|
|
ld a, $FF
|
|
ld [wInStaffRoll], a
|
|
ldh a, [hNextPiece]
|
|
ldh [hCurrentPiece], a
|
|
call GetNextPiece
|
|
call SFXKill
|
|
ld hl, wStaffRollDuration
|
|
ld a, [hl+]
|
|
ld c, a
|
|
ld b, [hl]
|
|
call StartCountdown
|
|
|
|
|
|
; Always draw the score, level, next piece, and held piece.
|
|
.drawStaticInfo
|
|
call SetPal
|
|
|
|
ldh a, [hNextPiece]
|
|
call ApplyNext
|
|
|
|
ldh a, [hHeldPiece]
|
|
call ApplyHold
|
|
|
|
ld hl, wSPRScore1
|
|
ld de, hScore
|
|
call ApplyNumbers8
|
|
|
|
ld hl, wSPRCLevel1
|
|
ld de, hCLevel
|
|
call ApplyNumbers4
|
|
|
|
ld hl, wSPRNLevel1
|
|
ld de, hNLevel
|
|
call ApplyNumbers4
|
|
|
|
call SetNumberSpritePositions
|
|
call ApplyTells
|
|
call ApplyTime
|
|
|
|
jp GBCBigGameplayProcess
|
|
|
|
|
|
; Do the hold action.
|
|
BigDoHold:
|
|
; Mark hold as spent.
|
|
ld a, $FF
|
|
ldh [hHoldSpent], a
|
|
|
|
; Check if IRS is requested.
|
|
; Apply the rotation if so.
|
|
.checkIRSA
|
|
ld a, [wSwapABState]
|
|
or a, a
|
|
jr z, .lda3
|
|
.ldb3
|
|
ldh a, [hBState]
|
|
or a, a
|
|
jr z, .checkIRSB
|
|
ld a, $FF
|
|
ldh [hBState], a
|
|
jr .cp3
|
|
.lda3
|
|
ldh a, [hAState]
|
|
or a, a
|
|
jr z, .checkIRSB
|
|
ld a, $FF
|
|
ldh [hAState], a
|
|
.cp3
|
|
ld a, ROTATION_STATE_CCW
|
|
ldh [hCurrentPieceRotationState], a
|
|
call SFXKill
|
|
ld a, SFX_IRS | SFX_IHS
|
|
call SFXEnqueue
|
|
jr .doHoldOperation
|
|
|
|
.checkIRSB
|
|
ld a, [wSwapABState]
|
|
or a, a
|
|
jr z, .ldb4
|
|
.lda4
|
|
ldh a, [hAState]
|
|
or a, a
|
|
jr z, .noRotation
|
|
ld a, $FF
|
|
ldh [hAState], a
|
|
jr .cp4
|
|
.ldb4
|
|
ldh a, [hBState]
|
|
or a, a
|
|
jr z, .noRotation
|
|
ld a, $FF
|
|
ldh [hBState], a
|
|
.cp4
|
|
ld a, ROTATION_STATE_CW
|
|
ldh [hCurrentPieceRotationState], a
|
|
call SFXKill
|
|
ld a, SFX_IRS | SFX_IHS
|
|
call SFXEnqueue
|
|
jr .doHoldOperation
|
|
|
|
.noRotation
|
|
call SFXKill
|
|
ld a, SFX_IHS
|
|
call SFXEnqueue
|
|
xor a, a ; ROTATION_STATE_DEF
|
|
ldh [hCurrentPieceRotationState], a
|
|
|
|
.doHoldOperation
|
|
ldh a, [hHeldPiece]
|
|
ld b, a
|
|
ldh a, [hCurrentPiece]
|
|
ldh [hHeldPiece], a
|
|
ld a, b
|
|
ldh [hCurrentPiece], a
|
|
ret
|
|
|
|
|
|
ENDC
|