; 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_TITLE_ASM)
DEF STATE_TITLE_ASM EQU 1


INCLUDE "globals.asm"
INCLUDE "res/title_data.inc"


SECTION "Title Variables", WRAM0
wSelected::  ds 1
wTitleMode:: ds 1
wProfileName:: ds 3
wDisplayingScoreMode:: ds 1
wScoreFlipTimer:: ds 1


SECTION "Title Function Trampolines", ROM0
    ; Trampolines to the banked function.
SwitchToTitle::
    ld b, BANK_TITLE
    rst RSTSwitchBank
    call SwitchToTitleB
    jp RSTRestoreBank

    ; Banks and jumps to the actual handler.
TitleEventLoopHandler::
    ld b, BANK_TITLE
    rst RSTSwitchBank
    call TitleEventLoopHandlerB
    rst RSTRestoreBank
    jp EventLoopPostHandler

    ; Banks and jumps to the actual handler.
TitleVBlankHandler::
    ld b, BANK_TITLE
    rst RSTSwitchBank
    call TitleVBlankHandlerB
    rst RSTRestoreBank
    jp EventLoop

PersistLevel:
    ld b, BANK_OTHER
    rst RSTSwitchBank
    ld a, [hl+]
    ld [rSelectedStartLevel], a
    ld a, [hl]
    ld [rSelectedStartLevel+1], a
    jp RSTRestoreBank

DrawSpeedMain:
    ld b, BANK_OTHER
    rst RSTSwitchBank

    ldh a, [hStartSpeed]
    ld l, a
    ldh a, [hStartSpeed+1]
    ld h, a
    ld a, [hl]
    swap a
    and a, $0F
    ld b, a
    ld a, TILE_0
    add a, b
    ld hl, TITLE_MAIN_START+2
    ld [hl], a

    ldh a, [hStartSpeed]
    ld l, a
    ldh a, [hStartSpeed+1]
    ld h, a
    ld a, [hl]
    and a, $0F
    ld b, a
    ld a, TILE_0
    add a, b
    ld hl, TITLE_MAIN_START+3
    ld [hl], a

    ldh a, [hStartSpeed]
    ld l, a
    ldh a, [hStartSpeed+1]
    ld h, a
    inc hl
    ld a, [hl]
    swap a
    and a, $0F
    ld b, a
    ld a, TILE_0
    add a, b
    ld hl, TITLE_MAIN_START+0
    ld [hl], a

    ldh a, [hStartSpeed]
    ld l, a
    ldh a, [hStartSpeed+1]
    ld h, a
    inc hl
    ld a, [hl]
    and a, $0F
    ld b, a
    ld a, TILE_0
    add a, b
    ld hl, TITLE_MAIN_START+1
    ld [hl], a

    jp RSTRestoreBank

DrawSpeedSettings:
    ld b, BANK_OTHER
    rst RSTSwitchBank

    ldh a, [hStartSpeed]
    ld l, a
    ldh a, [hStartSpeed+1]
    ld h, a
    ld a, [hl]
    swap a
    and a, $0F
    ld b, a
    ld a, TILE_0
    add a, b
    ld hl, TITLE_SETTINGS_START+2
    ld [hl], a

    ldh a, [hStartSpeed]
    ld l, a
    ldh a, [hStartSpeed+1]
    ld h, a
    ld a, [hl]
    and a, $0F
    ld b, a
    ld a, TILE_0
    add a, b
    ld hl, TITLE_SETTINGS_START+3
    ld [hl], a

    ldh a, [hStartSpeed]
    ld l, a
    ldh a, [hStartSpeed+1]
    ld h, a
    inc hl
    ld a, [hl]
    swap a
    and a, $0F
    ld b, a
    ld a, TILE_0
    add a, b
    ld hl, TITLE_SETTINGS_START+0
    ld [hl], a

    ldh a, [hStartSpeed]
    ld l, a
    ldh a, [hStartSpeed+1]
    ld h, a
    inc hl
    ld a, [hl]
    and a, $0F
    ld b, a
    ld a, TILE_0
    add a, b
    ld hl, TITLE_SETTINGS_START+1
    ld [hl], a

    jp RSTRestoreBank


SECTION "Title Functions Banked", ROMX, BANK[BANK_TITLE]
SwitchToTitleB:
    ; Turn the screen off if it's on.
    ldh a, [rLCDC]
    and LCDCF_ON
    jr z, :+ ; Screen is already off.
    wait_vram
    xor a, a
    ldh [rLCDC], a

    ; And the tiles.
:   call LoadTitleTiles

    ; Zero out SCX.
    xor a, a
    ldh [rSCX], a

    ; No screen squish for title.
    call DisableScreenSquish

    ; Clear OAM.
    call ClearOAM

    ; Set up the palettes.
    ld a, PALETTE_INVERTED
    set_bg_palette
    set_obj0_palette
    set_obj1_palette

    ; Go to the correct title screen mode.
    ld a, TITLE_MAIN
    call SwitchTitleMode

    ; Music start
    call SFXKill
    ld a, MUSIC_MENU
    call SFXEnqueue

    ; Make sure the first game loop starts just like all the future ones.
    wait_vblank
    wait_vblank_end
    ret

SwitchTitleMode:
    ; Set title to mode in A.
    ld [wTitleMode], a
    ld a, STATE_TITLE
    ldh [hGameState], a
    xor a, a
    ld [wSelected], a

    ; Turn the screen off if it's on.
    ldh a, [rLCDC]
    and LCDCF_ON
    jr z, :+ ; Screen is already off.
    wait_vram
    xor a, a
    ldh [rLCDC], a

    ; Jump to correct handler.
:   ld b, 0
    ld a, [wTitleMode]
    ld c, a
    ld hl, .jumps
    add hl, bc
    jp hl

.jumps
    jp .switchMain
    jp .switchProfile
    jp .switchSettings
    jp .switchRecords
    jp .switchCredits


.switchMain
    ld de, sTitleScreenMainMap
    ld hl, $9800
    ld bc, sTitleScreenMainMapEnd - sTitleScreenMainMap
    call UnsafeMemCopy

    call GBCTitleInit
    ld a, LCDCF_ON | LCDCF_BGON | LCDCF_BLK01
    ldh [rLCDC], a
    ret

.switchProfile
    ld de, sTitleScreenProfileMap
    ld hl, $9800
    ld bc, sTitleScreenProfileMapEnd - sTitleScreenProfileMap
    call UnsafeMemCopy
    call GBCTitleInit
    ld a, LCDCF_ON | LCDCF_BGON | LCDCF_BLK01
    ldh [rLCDC], a
    ret

.switchSettings
    ld de, sTitleScreenSettingsMap
    ld hl, $9800
    ld bc, sTitleScreenSettingsMapEnd - sTitleScreenSettingsMap
    call UnsafeMemCopy
    call GBCTitleInit
    ld a, LCDCF_ON | LCDCF_BGON | LCDCF_BLK01
    ldh [rLCDC], a
    ret

.switchRecords
    ld de, sTitleScreenRecordsMap
    ld hl, $9800
    ld bc, sTitleScreenRecordsMapEnd - sTitleScreenRecordsMap
    call UnsafeMemCopy
    call GBCTitleInit
    xor a, a
    ldh [hSelectState], a
    ld [wDisplayingScoreMode], a
    ld [wScoreFlipTimer], a
    ld a, [wSpeedCurveState]
    ld [wSelected], a
    call RenderScores
    ld a, LCDCF_ON | LCDCF_BGON | LCDCF_BLK01
    ldh [rLCDC], a
    ret

.switchCredits
    ld de, sTitleScreenCreditsMap
    ld hl, $9800
    ld bc, sTitleScreenCreditsMapEnd - sTitleScreenCreditsMap
    call UnsafeMemCopy
    call GBCTitleInit
    ld a, LCDCF_ON | LCDCF_BGON | LCDCF_BLK01
    ldh [rLCDC], a
    ret


    ; Event loop handlers for title screen.
TitleEventLoopHandlerB:
    call GBCTitleProcess

    ; Jump to the correct eventloop handler.
    ld b, 0
    ld a, [wTitleMode]
    ld c, a
    ld hl, .jumps
    add hl, bc
    jp hl

.jumps
    jp .eventLoopMain
    jp .eventLoopProfile
    jp .eventLoopSettings
    jp .eventLoopRecords
    jp .eventLoopCredits

.eventLoopMain
    ; A/Start?
    ldh a, [hAState]
    cp a, 1
    jp z, MainHandleA
    ldh a, [hStartState]
    cp a, 1
    jp z, MainHandleA

    ; Select?
    ldh a, [hSelectState]
    cp a, 1
    jp z, NextProfile

    ; Directions?
    ldh a, [hUpState]
    cp a, 1
    jp z, MainHandleUp
    cp a, 16
    jp c, .d0
    ldh a, [hFrameCtr]
    and 3
    cp a, 3
    jp z, MainHandleUp

.d0
    ldh a, [hDownState]
    cp a, 1
    jp z, MainHandleDown
    cp a, 16
    ret c
    ldh a, [hFrameCtr]
    and 3
    cp a, 3
    ret nz
    jp MainHandleDown

.eventLoopProfile
    ; A/Start?
    ldh a, [hAState]
    cp a, 1
    jp z, ProfileHandleA
    ldh a, [hStartState]
    cp a, 1
    jp z, ProfileHandleA

    ; B?
    ldh a, [hBState]
    cp a, 1
    jp z, ProfileHandleB

    ; Directions?
    ldh a, [hUpState]
    cp a, 1
    jp z, ProfileHandleUp
    cp a, 16
    jp c, .d2
    ldh a, [hFrameCtr]
    and 3
    cp a, 3
    jp z, ProfileHandleUp

.d2
    ldh a, [hDownState]
    cp a, 1
    jp z, ProfileHandleDown
    cp a, 16
    jp c, .l2
    ldh a, [hFrameCtr]
    and 3
    cp a, 3
    jp z, ProfileHandleDown

.l2
    ldh a, [hLeftState]
    cp a, 1
    jp z, ProfileHandleLeft
    cp a, 16
    jp c, .r2
    ldh a, [hLeftState]
    and 3
    cp a, 3
    jp z, ProfileHandleLeft

.r2
    ldh a, [hRightState]
    cp a, 1
    jp z, ProfileHandleRight
    cp a, 16
    ret c
    ldh a, [hRightState]
    and 3
    cp a, 3
    ret nz
    jp ProfileHandleRight
    ret

.eventLoopSettings
    ; A/Start?
    ldh a, [hAState]
    cp a, 1
    jp z, SettingsHandleA
    ldh a, [hStartState]
    cp a, 1
    jp z, SettingsHandleA

    ; B?
    ldh a, [hBState]
    cp a, 1
    jp z, SettingsHandleB

    ; Directions?
    ldh a, [hUpState]
    cp a, 1
    jp z, SettingsHandleUp
    cp a, 16
    jp c, .d1
    ldh a, [hFrameCtr]
    and 3
    cp a, 3
    jp z, SettingsHandleUp

.d1
    ldh a, [hDownState]
    cp a, 1
    jp z, SettingsHandleDown
    cp a, 16
    jp c, .l1
    ldh a, [hFrameCtr]
    and 3
    cp a, 3
    jp z, SettingsHandleDown

.l1
    ldh a, [hLeftState]
    cp a, 1
    jp z, SettingsHandleLeft
    cp a, 16
    jp c, .r1
    ldh a, [hLeftState]
    and 3
    cp a, 3
    jp z, SettingsHandleLeft

.r1
    ldh a, [hRightState]
    cp a, 1
    jp z, SettingsHandleRight
    cp a, 16
    ret c
    ldh a, [hRightState]
    and 3
    cp a, 3
    ret nz
    jp SettingsHandleRight

.eventLoopRecords
    ; B?
    ldh a, [hBState]
    cp a, 1
    jp z, .quitrecords

    ; L/R?
    ldh a, [hLeftState]
    cp a, 1
    jp z, RecordsHandleLeft
    ldh a, [hRightState]
    cp a, 1
    jp z, RecordsHandleRight

    ; Select
    ldh a, [hSelectState]
    cp a, 255 ; Max hold duraction
    jp z, RecordsHandleSelect

    ld a, [wScoreFlipTimer]
    inc a
    ld [wScoreFlipTimer], a
    cp a, 180
    ret nz
    xor a, a
    ld [wScoreFlipTimer], a
    ld a, [wDisplayingScoreMode]
    cpl
    ld [wDisplayingScoreMode], a
    jp RenderScores

.eventLoopCredits
    ldh a, [hAState]
    cp a, 1
    jp z, .quitcredits
    ldh a, [hBState]
    cp a, 1
    jp z, .quitcredits
    ldh a, [hStartState]
    cp a, 1
    jp z, .quitcredits
    ret

.quitcredits
.quitrecords
    ld a, TITLE_MAIN
    jp SwitchTitleMode


    ; VBLank handlers for title screen.
TitleVBlankHandlerB:
    call ToATTR

    ; Jump to the correct vblank handler.
    ld b, 0
    ld a, [wTitleMode]
    ld c, a
    ld hl, .jumps
    add hl, bc
    jp hl

.jumps
    jp .vblankMain
    jp .vblankProfile
    jp .vblankSettings
    jp .vblankRecords
    jp .vblankCredits

.vblankMain
    ; What is the current option?
    DEF option = 0
    REPT TITLE_MAIN_OPTIONS
        ld hl, TITLE_MAIN_OPTION_BASE+(32*option)
        ld a, [wSelected]
        cp a, option
        jr z, .selected\@
.notselected\@:
        ld a, TILE_UNSELECTED
        ld [hl], a
        jr .done\@
.selected\@:
        ld a, TILE_SELECTED
        ld [hl], a
.done\@:
        DEF option += 1
    ENDR

    ; RNG mode.
    ld b, 0
    ld a, [wRNGModeState]
    add a, a
    add a, a
    ld c, a
    ld hl, sRNGMode
    add hl, bc
    ld d, h
    ld e, l
    ld hl, TITLE_MAIN_RNG
    ld bc, 4
    call UnsafeMemCopy

    ; ROT mode.
    ld b, 0
    ld a, [wRotModeState]
    add a, a
    add a, a
    ld c, a
    ld hl, sROTMode
    add hl, bc
    ld d, h
    ld e, l
    ld hl, TITLE_MAIN_ROT
    ld bc, 4
    call UnsafeMemCopy

    ; DROP mode.
    ld b, 0
    ld a, [wDropModeState]
    add a, a
    add a, a
    ld c, a
    ld hl, sDROPMode
    add hl, bc
    ld d, h
    ld e, l
    ld hl, TITLE_MAIN_DROP
    ld bc, 4
    call UnsafeMemCopy

    ; CURVE mode.
    ld b, 0
    ld a, [wSpeedCurveState]
    add a, a
    add a, a
    ld c, a
    ld hl, sCURVEMode
    add hl, bc
    ld d, h
    ld e, l
    ld hl, TITLE_MAIN_SCURVE
    ld bc, 4
    call UnsafeMemCopy

    ; HIG mode.
    ld a, [wSpeedCurveState]
    cp a, SCURVE_DEAT
    jr z, .disabled
    cp a, SCURVE_SHIR
    jr z, .disabled
    xor a, a
    ld b, a
    ld a, [wAlways20GState]
    add a, a
    add a, a
    ld c, a
    ld hl, sHIGMode
    add hl, bc
    ld d, h
    ld e, l
    ld hl, TITLE_MAIN_HIG
    ld bc, 4
    call UnsafeMemCopy
    jr .profile
.disabled
    ld de, sDisabled
    ld hl, TITLE_MAIN_HIG
    ld bc, 4
    call UnsafeMemCopy

    ; PROFILE name.
.profile
    ld de, wProfileName
    ld hl, TITLE_MAIN_PROFILE
    ld bc, 3
    call UnsafeMemCopy

    ; START level.
    jp DrawSpeedMain

.vblankProfile
    ; What is the current option?
    DEF option = 0
    REPT TITLE_PROFILE_OPTIONS
        ld hl, TITLE_PROFILE_OPTION_BASE+(32*option)
        ld a, [wSelected]
        cp a, option
        jr z, .selected\@
.notselected\@:
        ld a, TILE_UNSELECTED
        ld [hl], a
        jr .done\@
.selected\@:
        ld a, TILE_SELECTED
        ld [hl], a
.done\@:
        DEF option += 1
    ENDR

    ; Which profile.
    ld a, [rLastProfile]
    add a, "0"
    ld hl, TITLE_PROFILE_INDEX
    ld [hl], a

    ; Name.
    ld a, [wProfileName+0]
    ld hl, TITLE_PROFILE_NAME_0
    ld [hl], a
    ld a, [wProfileName+1]
    ld hl, TITLE_PROFILE_NAME_1
    ld [hl], a
    ld a, [wProfileName+2]
    ld hl, TITLE_PROFILE_NAME_2
    ld [hl], a

.buttons
    ld b, 0
    ld a, [wSwapABState]
    add a, a
    add a, a
    ld c, a
    ld hl, sBUTTONSMode
    add hl, bc
    ld d, h
    ld e, l
    ld hl, TITLE_PROFILE_BUTTONS
    ld bc, 4
    call UnsafeMemCopy

.filter
    ld b, 0
    ldh a, [hFilterMode]
    add a, a
    add a, a
    ld c, a
    ld hl, sFilterMode
    add hl, bc
    ld d, h
    ld e, l
    ld hl, TITLE_PROFILE_FILTER
    ld bc, 4
    call UnsafeMemCopy

.bg
    ld b, 0
    ld a, [wBGMode]
    add a, a
    add a, a
    ld c, a
    ld hl, sBGMode
    add hl, bc
    ld d, h
    ld e, l
    ld hl, TITLE_PROFILE_BG
    ld bc, 4
    call UnsafeMemCopy

    ; Tetry!
    ld a, [wSelected]
    ld hl, sTetryProfileNumber
    ld bc, 64
:   or a, a
    jr z, .donetetry2
    dec a
    add hl, bc
    jr :-
.donetetry2
    ld d, h
    ld e, l
    ld hl, TITLE_PROFILE_TETRY
    ld bc, 16
    call SafeMemCopy
    ld hl, TITLE_PROFILE_TETRY+(1*32)
    ld bc, 16
    call SafeMemCopy
    ld hl, TITLE_PROFILE_TETRY+(2*32)
    ld bc, 16
    call SafeMemCopy
    ld hl, TITLE_PROFILE_TETRY+(3*32)
    ld bc, 16
    jp SafeMemCopy


.vblankSettings
    ; What is the current option?
    DEF option = 0
    REPT TITLE_SETTINGS_OPTIONS
        ld hl, TITLE_SETTINGS_OPTION_BASE+(32*option)
        ld a, [wSelected]
        cp a, option
        jr z, .selected\@
.notselected\@:
        ld a, TILE_UNSELECTED
        ld [hl], a
        jr .done\@
.selected\@:
        ld a, TILE_SELECTED
        ld [hl], a
.done\@:
        DEF option += 1
    ENDR

    ; RNG mode.
    ld b, 0
    ld a, [wRNGModeState]
    add a, a
    add a, a
    ld c, a
    ld hl, sRNGMode
    add hl, bc
    ld d, h
    ld e, l
    ld hl, TITLE_SETTINGS_RNG
    ld bc, 4
    call UnsafeMemCopy

    ; ROT mode.
    ld b, 0
    ld a, [wRotModeState]
    add a, a
    add a, a
    ld c, a
    ld hl, sROTMode
    add hl, bc
    ld d, h
    ld e, l
    ld hl, TITLE_SETTINGS_ROT
    ld bc, 4
    call UnsafeMemCopy

    ; DROP mode.
    ld b, 0
    ld a, [wDropModeState]
    add a, a
    add a, a
    ld c, a
    ld hl, sDROPMode
    add hl, bc
    ld d, h
    ld e, l
    ld hl, TITLE_SETTINGS_DROP
    ld bc, 4
    call UnsafeMemCopy

    ; CURVE mode.
    ld b, 0
    ld a, [wSpeedCurveState]
    add a, a
    add a, a
    ld c, a
    ld hl, sCURVEMode
    add hl, bc
    ld d, h
    ld e, l
    ld hl, TITLE_SETTINGS_SCURVE
    ld bc, 4
    call UnsafeMemCopy

    ; HIG mode.
    ld a, [wSpeedCurveState]
    cp a, SCURVE_DEAT
    jr z, .disabled1
    cp a, SCURVE_SHIR
    jr z, .disabled1
    xor a, a
    ld b, a
    ld a, [wAlways20GState]
    add a, a
    add a, a
    ld c, a
    ld hl, sHIGMode
    add hl, bc
    ld d, h
    ld e, l
    ld hl, TITLE_SETTINGS_HIG
    ld bc, 4
    call UnsafeMemCopy
    jr .start
.disabled1
    ld de, sDisabled
    ld hl, TITLE_SETTINGS_HIG
    ld bc, 4
    call UnsafeMemCopy

    ; START level.
.start
    call DrawSpeedSettings

    ; Tetry!
    ld a, [wSelected]
    ld hl, sTetryRNG
    ld bc, 64
:   or a, a
    jr z, .donetetry1
    dec a
    add hl, bc
    jr :-
.donetetry1
    ld d, h
    ld e, l
    ld hl, TITLE_SETTINGS_TETRY
    ld bc, 16
    call SafeMemCopy
    ld hl, TITLE_SETTINGS_TETRY+(1*32)
    ld bc, 16
    call SafeMemCopy
    ld hl, TITLE_SETTINGS_TETRY+(2*32)
    ld bc, 16
    call SafeMemCopy
    ld hl, TITLE_SETTINGS_TETRY+(3*32)
    ld bc, 16
    jp SafeMemCopy

.vblankRecords
    ld hl, TITLE_RECORDS_RESET_LOC
    ld b, TITLE_RECORDS_RESET_BASE
    ld [hl], b
    ldh a, [hSelectState]
    or a, a
    ret z
    inc b
    ld [hl], b
    cp a, 30
    ret c
    inc b
    ld [hl], b
    cp a, 60
    ret c
    inc b
    ld [hl], b
    cp a, 90
    ret c
    inc b
    ld [hl], b
    cp a, 120
    ret c
    inc b
    ld [hl], b
    cp a, 150
    ret c
    inc b
    ld [hl], b
    cp a, 180
    ret c
    inc b
    ld [hl], b
    cp a, 210
    ret c
    inc b
    ld [hl], b
    cp a, 240
    ret c
    inc b
    ld [hl], b
    ret

.vblankCredits
    ret


MainHandleA:
    ld a, [wSelected]
    ld b, a
    add a, b
    add a, b
    ld c, a
    ld b, 0
    ld hl, .jumps
    add hl, bc
    jp hl

.jumps
    jp SwitchToGameplay
    jp SwitchToGameplayBig
    jp .toprofile
    jp .tosettings
    jp .torecords
    jp .tocredits

.tosettings
    ld a, TITLE_SETTINGS
    jp SwitchTitleMode

.tocredits
    ld a, TITLE_CREDITS
    jp SwitchTitleMode

.toprofile
    ld a, TITLE_PROFILE
    jp SwitchTitleMode

.torecords
    ld a, TITLE_RECORDS
    jp SwitchTitleMode


MainHandleUp:
    ld a, [wSelected]
    or a, a
    jr z, :+
    dec a
    ld [wSelected], a
    ret
:   ld a, TITLE_MAIN_OPTIONS-1
    ld [wSelected], a
    ret


MainHandleDown:
    ld a, [wSelected]
    cp a, TITLE_MAIN_OPTIONS-1
    jr z, :+
    inc a
    ld [wSelected], a
    ret
:   xor a, a
    ld [wSelected], a
    ret


SettingsHandleA:
    ld a, [wSelected]
    cp a, TITLE_SETTINGS_SEL_BACK
    jp nz, SettingsHandleRight
    ld a, TITLE_MAIN
    jp SwitchTitleMode


ProfileHandleB:
SettingsHandleB:
    ld a, TITLE_MAIN
    jp SwitchTitleMode


SettingsHandleDown:
    ld a, [wSelected]
    cp a, TITLE_SETTINGS_OPTIONS-1
    jr z, :+
    inc a
    ld [wSelected], a
    ret
:   xor a, a
    ld [wSelected], a
    ret


SettingsHandleUp:
    ld a, [wSelected]
    or a, a
    jr z, :+
    dec a
    ld [wSelected], a
    ret
:   ld a, TITLE_SETTINGS_OPTIONS-1
    ld [wSelected], a
    ret


SettingsHandleLeft:
    ld a, [wSelected]
    cp a, TITLE_SETTINGS_SEL_BACK
    ret z

    ld b, a
    add a, b
    add a, b
    ld c, a
    ld b, 0
    ld hl, .jumps
    add hl, bc
    jp hl

.jumps
    jp .rng
    jp .rot
    jp .drop
    jp .curve
    jp .hig
    jp DecrementLevel
    no_jump

.rng
    ld a, [wRNGModeState]
    or a, a
    jr z, :+
    dec a
    ld [wRNGModeState], a
    ld [rRNGModeState], a
    ret
:   ld a, RNG_MODE_COUNT-1
    ld [wRNGModeState], a
    ld [rRNGModeState], a
    ret

.rot
    ld a, [wRotModeState]
    or a, a
    jr z, :+
    dec a
    ld [wRotModeState], a
    ld [rRotModeState], a
    ret
:   ld a, ROT_MODE_COUNT-1
    ld [wRotModeState], a
    ld [rRotModeState], a
    ret

.drop
    ld a, [wDropModeState]
    or a, a
    jr z, :+
    dec a
    ld [wDropModeState], a
    ld [rDropModeState], a
    ret
:   ld a, DROP_MODE_COUNT-1
    ld [wDropModeState], a
    ld [rDropModeState], a
    ret

.curve
    ld a, [wSpeedCurveState]
    or a, a
    jr z, :+
    dec a
    ld [wSpeedCurveState], a
    ld [rSpeedCurveState], a
    call InitSpeedCurve
    ret
:   ld a, SCURVE_COUNT-1
    ld [wSpeedCurveState], a
    ld [rSpeedCurveState], a
    call InitSpeedCurve
    ret

.hig
    ld a, [wAlways20GState]
    or a, a
    jr z, :+
    dec a
    ld [wAlways20GState], a
    ld [rAlways20GState], a
    ret
:   ld a, HIG_MODE_COUNT-1
    ld [wAlways20GState], a
    ld [rAlways20GState], a
    ret


SettingsHandleRight:
    ld a, [wSelected]
    cp a, TITLE_SETTINGS_SEL_BACK
    ret z

    ld b, a
    add a, b
    add a, b
    ld c, a
    ld b, 0
    ld hl, .jumps
    add hl, bc
    jp hl

.jumps
    jp .rng
    jp .rot
    jp .drop
    jp .curve
    jp .hig
    jp IncrementLevel
    no_jump

.rng
    ld a, [wRNGModeState]
    cp a, RNG_MODE_COUNT-1
    jr z, :+
    inc a
    ld [wRNGModeState], a
    ld [rRNGModeState], a
    ret
:   xor a, a
    ld [wRNGModeState], a
    ld [rRNGModeState], a
    ret

.rot
    ld a, [wRotModeState]
    cp a, ROT_MODE_COUNT-1
    jr z, :+
    inc a
    ld [wRotModeState], a
    ld [rRotModeState], a
    ret
:   xor a, a
    ld [wRotModeState], a
    ld [rRotModeState], a
    ret

.drop
    ld a, [wDropModeState]
    cp a, DROP_MODE_COUNT-1
    jr z, :+
    inc a
    ld [wDropModeState], a
    ld [rDropModeState], a
    ret
:   xor a, a
    ld [wDropModeState], a
    ld [rDropModeState], a
    ret

.curve
    ld a, [wSpeedCurveState]
    cp a, SCURVE_COUNT-1
    jr z, :+
    inc a
    ld [wSpeedCurveState], a
    ld [rSpeedCurveState], a
    call InitSpeedCurve
    ret
:   xor a, a
    ld [wSpeedCurveState], a
    ld [rSpeedCurveState], a
    call InitSpeedCurve
    ret

.hig
    ld a, [wAlways20GState]
    cp a, HIG_MODE_COUNT-1
    jr z, :+
    inc a
    ld [wAlways20GState], a
    ld [rAlways20GState], a
    ret
:   xor a, a
    ld [wAlways20GState], a
    ld [rAlways20GState], a
    ret


ProfileHandleA:
    ld a, [wSelected]
    cp a, TITLE_PROFILE_SEL_BACK
    ld b, a
    ld a, TITLE_MAIN
    jp z, SwitchTitleMode
    ld a, b
    cp a, TITLE_PROFILE_SEL_RESET
    jp z, ResetProfile
    jp ProfileHandleRight


ProfileHandleRight:
    ld a, [wSelected]
    cp a, TITLE_PROFILE_SEL_BACK
    ret z
    cp a, TITLE_PROFILE_SEL_RESET
    ret z

    ld b, a
    add a, b
    add a, b
    ld c, a
    ld b, 0
    ld hl, .jumps
    add hl, bc
    jp hl

.jumps
    jp .idx
    jp .l0
    jp .l1
    jp .l2
    jp .buttons
    jp .filter
    jp .bg
    no_jump
    no_jump

.idx
    ld a, [rLastProfile]
    inc a
    cp a, PROFILE_COUNT
    jr nz, .doit
    xor a, a
.doit
    jp ChangeProfile

.l0
    ld a, [wProfileName+0]
    inc a
    cp a, "Z"+1
    jr nz, .doit1
    ld a, "0"-1
.doit1
    ld [wProfileName+0], a
    ld [rProfileName+0], a
    ret

.l1
    ld a, [wProfileName+1]
    inc a
    cp a, "Z"+1
    jr nz, .doit2
    ld a, "0"-1
.doit2
    ld [wProfileName+1], a
    ld [rProfileName+1], a
    ret

.l2
    ld a, [wProfileName+2]
    inc a
    cp a, "Z"+1
    jr nz, .doit3
    ld a, "0"-1
.doit3
    ld [wProfileName+2], a
    ld [rProfileName+2], a
    ret

.buttons
    ld a, [wSwapABState]
    cp a, BUTTON_MODE_COUNT-1
    jr z, :+
    inc a
    ld [wSwapABState], a
    ld [rSwapABState], a
    ret
:   xor a, a
    ld [wSwapABState], a
    ld [rSwapABState], a
    ret

.filter
    ldh a, [hFilterMode]
    cp a, FILTER_MODE_COUNT-1
    jr z, :+
    inc a
    ldh [hFilterMode], a
    ld [rFilterMode], a
    ret
:   xor a, a
    ldh [hFilterMode], a
    ld [rFilterMode], a
    ret

.bg
    ld a, [wBGMode]
    cp a, BG_MODE_COUNT-1
    jr z, :+
    inc a
    ld [wBGMode], a
    ld [rBGMode], a
    ret
:   xor a, a
    ld [wBGMode], a
    ld [rBGMode], a
    ret


ProfileHandleLeft:
    ld a, [wSelected]
    cp a, TITLE_PROFILE_SEL_BACK
    ret z
    cp a, TITLE_PROFILE_SEL_RESET
    ret z

    ld b, a
    add a, b
    add a, b
    ld c, a
    ld b, 0
    ld hl, .jumps
    add hl, bc
    jp hl

.jumps
    jp .idx
    jp .l0
    jp .l1
    jp .l2
    jp .buttons
    jp .filter
    jp .bg
    no_jump
    no_jump

.idx
    ld a, [rLastProfile]
    dec a
    cp a, $FF
    jr nz, .doit
    ld a, PROFILE_COUNT-1
.doit
    jp ChangeProfile

.l0
    ld a, [wProfileName+0]
    dec a
    cp a, "0"-2
    jr nz, .doit1
    ld a, "Z"
.doit1
    ld [wProfileName+0], a
    ld [rProfileName+0], a
    ret

.l1
    ld a, [wProfileName+1]
    dec a
    cp a, "0"-2
    jr nz, .doit2
    ld a, "Z"
.doit2
    ld [wProfileName+1], a
    ld [rProfileName+1], a
    ret

.l2
    ld a, [wProfileName+2]
    dec a
    cp a, "0"-2
    jr nz, .doit3
    ld a, "Z"
.doit3
    ld [wProfileName+2], a
    ld [rProfileName+2], a
    ret

.buttons
    ld a, [wSwapABState]
    or a, a
    jr z, :+
    dec a
    ld [wSwapABState], a
    ld [rSwapABState], a
    ret
:   ld a, BUTTON_MODE_COUNT-1
    ld [wSwapABState], a
    ld [rSwapABState], a
    ret

.filter
    ldh a, [hFilterMode]
    or a, a
    jr z, :+
    dec a
    ldh [hFilterMode], a
    ld [rFilterMode], a
    ret
:   ld a, FILTER_MODE_COUNT-1
    ldh [hFilterMode], a
    ld [rFilterMode], a
    ret

.bg
    ld a, [wBGMode]
    or a, a
    jr z, :+
    dec a
    ld [wBGMode], a
    ld [rBGMode], a
    ret
:   ld a, BG_MODE_COUNT-1
    ld [wBGMode], a
    ld [rBGMode], a
    ret


ProfileHandleDown:
    ld a, [wSelected]
    cp a, TITLE_PROFILE_OPTIONS-1
    jr z, :+
    inc a
    ld [wSelected], a
    ret
:   xor a, a
    ld [wSelected], a
    ret


ProfileHandleUp:
    ld a, [wSelected]
    or a, a
    jr z, :+
    dec a
    ld [wSelected], a
    ret
:   ld a, TITLE_PROFILE_OPTIONS-1
    ld [wSelected], a
    ret


    ; Decrements start level.
DecrementLevel:
    ; Decrement
    ldh a, [hStartSpeed]
    ld l, a
    ldh a, [hStartSpeed+1]
    ld h, a
    ld bc, -SCURVE_ENTRY_SIZE
    add hl, bc
    ld a, l
    ldh [hStartSpeed], a
    ld a, h
    ldh [hStartSpeed+1], a
    call PersistLevel
    jp CheckLevelRange


    ; Increments start level.
IncrementLevel:
    ; Increment
    ldh a, [hStartSpeed]
    ld l, a
    ldh a, [hStartSpeed+1]
    ld h, a
    ld bc, SCURVE_ENTRY_SIZE
    add hl, bc
    ld a, l
    ldh [hStartSpeed], a
    ld a, h
    ldh [hStartSpeed+1], a
    call PersistLevel
    jp CheckLevelRange


    ; Wipes the start level upon selecting a new speed curve.
InitSpeedCurve:
    ld a, [wSpeedCurveState]
    call GetStart
    ld a, l
    ldh [hStartSpeed], a
    ld a, h
    ldh [hStartSpeed+1], a
    jp PersistLevel


    ; Gets the end of a speed curve.
GetEnd:
    ld a, [wSpeedCurveState]
    cp a, SCURVE_DMGT
    jr nz, :+
    ld bc, sDMGTSpeedCurveEnd
    ret
:   cp a, SCURVE_TGM1
    jr nz, :+
    ld bc, sTGM1SpeedCurveEnd
    ret
:   cp a, SCURVE_TGM3
    jr nz, :+
    ld bc, sTGM3SpeedCurveEnd
    ret
:   cp a, SCURVE_DEAT
    jr nz, :+
    ld bc, sDEATSpeedCurveEnd
    ret
:   cp a, SCURVE_SHIR
    jr nz, :+
    ld bc, sSHIRSpeedCurveEnd
    ret
:   cp a, SCURVE_CHIL
    jr nz, :+
    ld bc, sCHILSpeedCurveEnd
    ret
:   ld bc, sMYCOSpeedCurveEnd
    ret


    ; Gets the beginning of a speed curve.
GetStart:
    ld a, [wSpeedCurveState]
    cp a, SCURVE_DMGT
    jr nz, :+
    ld hl, sDMGTSpeedCurve
    ret
:   cp a, SCURVE_TGM1
    jr nz, :+
    ld hl, sTGM1SpeedCurve
    ret
:   cp a, SCURVE_TGM3
    jr nz, :+
    ld hl, sTGM3SpeedCurve
    ret
:   cp a, SCURVE_DEAT
    jr nz, :+
    ld hl, sDEATSpeedCurve
    ret
:   cp a, SCURVE_SHIR
    jr nz, :+
    ld hl, sSHIRSpeedCurve
    ret
:   cp a, SCURVE_CHIL
    jr nz, :+
    ld hl, sCHILSpeedCurve
    ret
:   ld hl, sMYCOSpeedCurve
    ret


    ; Make sure we don't overflow the level range.
CheckLevelRange:
    ; At end?
    call GetEnd
    ldh a, [hStartSpeed]
    cp a, c
    jr nz, .notatend
    ldh a, [hStartSpeed+1]
    cp a, b
    jr nz, .notatend
    call GetStart
    ld a, l
    ldh [hStartSpeed], a
    ld a, h
    ldh [hStartSpeed+1], a
    call PersistLevel

.notatend
    ld de, -SCURVE_ENTRY_SIZE

    call GetStart
    add hl, de
    ldh a, [hStartSpeed]
    cp a, l
    jr nz, .notatstart
    ldh a, [hStartSpeed+1]
    cp a, h
    jr nz, .notatstart

    call GetEnd
    ld h, b
    ld l, c
    add hl, de
    ld a, l
    ldh [hStartSpeed], a
    ld a, h
    ldh [hStartSpeed+1], a
    call PersistLevel

.notatstart
    ret

RecordsHandleLeft:
    xor a, a
    ldh [hSelectState], a
    ld [wDisplayingScoreMode], a
    ld [wScoreFlipTimer], a
    ld a, [wSelected]
    or a, a
    jr z, :+
    dec a
    ld [wSelected], a
    jp RenderScores
:   ld a, SCURVE_COUNT-1
    ld [wSelected], a
    jp RenderScores

RecordsHandleRight:
    xor a, a
    ldh [hSelectState], a
    ld [wDisplayingScoreMode], a
    ld [wScoreFlipTimer], a
    ld a, [wSelected]
    cp a, SCURVE_COUNT-1
    jr z, :+
    inc a
    ld [wSelected], a
    jp RenderScores
:   xor a, a
    ld [wSelected], a
    jp RenderScores

RecordsHandleSelect:
    xor a, a
    ldh [hSelectState], a
    call ResetScores
    jp RenderScores

RenderScores:
    ; Draw the mode.
:   ld b, 0
    ld a, [wSelected]
    add a, a
    add a, a
    ld c, a
    ld hl, sCURVEMode
    add hl, bc
    ld d, h
    ld e, l
    ld hl, TITLE_RECORDS_MODE
    ld bc, 4
    call SafeMemCopy

    ; Get the correct speed curve.
    ld a, [wSelected]
    call InitTargetHSTable

    ; Start of table is at HL. Put it in DE.
    ld d, h
    ld e, l

    ld hl, TITLE_RECORDS_SCORE_BASE+4

    REPT 10
        ld a, [wDisplayingScoreMode]
        cp a, $FF
        jr z, .level\@

        ; Render score.
.score\@
        ld a, [de]
        inc de
        add a, "0"
        ld b, a
        wait_vram
        ld [hl], b
        inc hl
        ld a, [de]
        inc de
        add a, "0"
        ld b, a
        wait_vram
        ld [hl], b
        inc hl
        ld a, [de]
        inc de
        add a, "0"
        ld b, a
        wait_vram
        ld [hl], b
        inc hl
        ld a, [de]
        inc de
        add a, "0"
        ld b, a
        wait_vram
        ld [hl], b
        inc hl
        ld a, [de]
        inc de
        add a, "0"
        ld b, a
        wait_vram
        ld [hl], b
        inc hl
        ld a, [de]
        inc de
        add a, "0"
        ld b, a
        wait_vram
        ld [hl], b
        inc hl
        ld a, [de]
        inc de
        add a, "0"
        ld b, a
        wait_vram
        ld [hl], b
        inc hl
        ld a, [de]
        inc de
        add a, "0"
        ld b, a
        wait_vram
        ld [hl], b
        inc hl

        ; Go render the name.
        jr .name\@

        ; Jump forward to level in the score.
.level\@
        push hl
        ld h, d
        ld l, e
        ld bc, 16
        add hl, bc
        ld d, h
        ld e, l
        pop hl

        ; Render it.
        ld a, "L"
        ld b, a
        wait_vram
        ld [hl], b
        inc hl
        ld a, "V"
        ld b, a
        wait_vram
        ld [hl], b
        inc hl
        ld a, "L"
        ld b, a
        wait_vram
        ld [hl], b
        inc hl
        ld a, 58
        ld b, a
        wait_vram
        ld [hl], b
        inc hl
        ld a, [de]
        inc de
        add a, "0"
        ld b, a
        wait_vram
        ld [hl], b
        inc hl
        ld a, [de]
        inc de
        add a, "0"
        ld b, a
        wait_vram
        ld [hl], b
        inc hl
        ld a, [de]
        inc de
        add a, "0"
        ld b, a
        wait_vram
        ld [hl], b
        inc hl
        ld a, [de]
        inc de
        add a, "0"
        ld b, a
        wait_vram
        ld [hl], b
        inc hl

        ; And jump back to the name.
        push hl
        ld h, d
        ld l, e
        ld bc, -12
        add hl, bc
        ld d, h
        ld e, l
        pop hl


.name\@
        ; Jump back to Name.
        ld bc, -12
        add hl, bc

        ; Render name.
        ld a, [de]
        inc de
        ld b, a
        wait_vram
        ld [hl], b
        inc hl
        ld a, [de]
        inc de
        ld b, a
        wait_vram
        ld [hl], b
        inc hl
        ld a, [de]
        inc de
        ld b, a
        wait_vram
        ld [hl], b
        inc hl

        ; Jump to tells.
        ld bc, 10
        add hl, bc

        ; Render them.
        ld a, [de]
        inc de
        cp a, GRADE_NONE
        jr nz, .grade\@
.nograde\@
        ld a, 149
        ld b, a
        wait_vram
        ld [hl], b
        inc hl
        jr .postgrade\@
.grade\@
        add a, TITLE_RECORDS_GRADE_BASE
        ld b, a
        wait_vram
        ld [hl], b
        inc hl
.postgrade\@
        ld a, [de]
        inc de
        add a, TITLE_RECORDS_RNG_BASE
        ld b, a
        wait_vram
        ld [hl], b
        inc hl
        ld a, [de]
        inc de
        add a, TITLE_RECORDS_ROT_BASE
        ld b, a
        wait_vram
        ld [hl], b
        inc hl
        ld a, [de]
        inc de
        add a, TITLE_RECORDS_DROP_BASE
        ld b, a
        wait_vram
        ld [hl], b
        inc hl
        ld a, [de]
        inc de
        add a, TITLE_RECORDS_HIG_BASE
        ld b, a
        wait_vram
        ld [hl], b
        inc hl

        ; Jump to next line.
        push hl
        ld h, d
        ld l, e
        ld bc, 16
        add hl, bc
        ld d, h
        ld e, l
        pop hl
        ld bc, 18
        add hl, bc
    ENDR

    ret


ENDC
