MainMenu:
; Check save file
call InitOptions
xor a
ld [wOptionsInitialized], a
inc a
ld [wSaveFileStatus], a
call CheckForPlayerNameInSRAM
jr nc, .mainMenuLoop
predef TryLoadSaveFile
.mainMenuLoop
ld c, 20
call DelayFrames
xor a ; LINK_STATE_NONE
ld [wLinkState], a
ld hl, wPartyAndBillsPCSavedMenuItem
ld [hli], a
ld [hli], a
ld [hli], a
ld [hl], a
ld [wDefaultMap], a
ld hl, wStatusFlags4
res BIT_LINK_CONNECTED, [hl]
call ClearScreen
call RunDefaultPaletteCommand
call LoadTextBoxTilePatterns
call LoadFontTilePatterns
ld hl, wStatusFlags5
set BIT_NO_TEXT_DELAY, [hl]
ld a, [wSaveFileStatus]
cp 1
jr z, .noSaveFile
; there's a save file
hlcoord 0, 0
ld b, 6
ld c, 13
call TextBoxBorder
hlcoord 2, 2
ld de, ContinueText
call PlaceString
jr .next2
.noSaveFile
hlcoord 0, 0
ld b, 4
ld c, 13
call TextBoxBorder
hlcoord 2, 2
ld de, NewGameText
call PlaceString
.next2
ld hl, wStatusFlags5
res BIT_NO_TEXT_DELAY, [hl]
call UpdateSprites
xor a
ld [wCurrentMenuItem], a
ld [wLastMenuItem], a
ld [wMenuJoypadPollCount], a
inc a
ld [wTopMenuItemX], a
inc a
ld [wTopMenuItemY], a
ld a, PAD_A | PAD_B | PAD_START
ld [wMenuWatchedKeys], a
ld a, [wSaveFileStatus]
ld [wMaxMenuItem], a
call HandleMenuInput
bit B_PAD_B, a
jp nz, DisplayTitleScreen ; if so, go back to the title screen
ld c, 20
call DelayFrames
ld a, [wCurrentMenuItem]
ld b, a
ld a, [wSaveFileStatus]
cp 2
jp z, .skipInc
; If there's no save file, increment the current menu item so that the numbers
; are the same whether or not there's a save file.
inc b
.skipInc
ld a, b
and a
jr z, .choseContinue
cp 1
jp z, StartNewGame
call DisplayOptionMenu
ld a, TRUE
ld [wOptionsInitialized], a
jp .mainMenuLoop
.choseContinue
call DisplayContinueGameInfo
ld hl, wCurrentMapScriptFlags
set BIT_CUR_MAP_LOADED_1, [hl]
.inputLoop
xor a
ldh [hJoyPressed], a
ldh [hJoyReleased], a
ldh [hJoyHeld], a
call Joypad
ldh a, [hJoyHeld]
bit B_PAD_A, a
jr nz, .pressedA
bit B_PAD_B, a
jp nz, .mainMenuLoop
jr .inputLoop
.pressedA
call GBPalWhiteOutWithDelay3
call ClearScreen
ld a, PLAYER_DIR_DOWN
ld [wPlayerDirection], a
ld c, 10
call DelayFrames
ld a, [wNumHoFTeams]
and a
jp z, SpecialEnterMap
ld a, [wCurMap]
cp HALL_OF_FAME
jp nz, SpecialEnterMap
xor a
ld [wDestinationMap], a
ld hl, wStatusFlags6
set BIT_FLY_OR_DUNGEON_WARP, [hl]
call PrepareForSpecialWarp
jp SpecialEnterMap
InitOptions:
ld a, 1 << BIT_FAST_TEXT_DELAY
ld [wLetterPrintingDelayFlags], a
ld a, TEXT_DELAY_MEDIUM
ld [wOptions], a
ret
LinkMenu:
xor a
ld [wLetterPrintingDelayFlags], a
ld hl, wStatusFlags4
set BIT_LINK_CONNECTED, [hl]
ld hl, LinkMenuEmptyText
call PrintText
call SaveScreenTilesToBuffer1
ld hl, WhereWouldYouLikeText
call PrintText
hlcoord 5, 5
ld b, $6
ld c, $d
call TextBoxBorder
call UpdateSprites
hlcoord 7, 7
ld de, CableClubOptionsText
call PlaceString
xor a
ld [wUnusedLinkMenuByte], a
ld [wCableClubDestinationMap], a
ld hl, wTopMenuItemY
ld a, 7
ld [hli], a
ASSERT wTopMenuItemY + 1 == wTopMenuItemX
ld a, 6
ld [hli], a
ASSERT wTopMenuItemX + 1 == wCurrentMenuItem
xor a
ld [hli], a
inc hl
ASSERT wCurrentMenuItem + 2 == wMaxMenuItem
ld a, 2
ld [hli], a
ASSERT wMaxMenuItem + 1 == wMenuWatchedKeys
ASSERT 2 + 1 == PAD_A | PAD_B
inc a
ld [hli], a
ASSERT wMenuWatchedKeys + 1 == wLastMenuItem
xor a
ld [hl], a
.waitForInputLoop
call HandleMenuInput
and PAD_A | PAD_B
add a
add a
ld b, a
ld a, [wCurrentMenuItem]
add b
add $d0
ld [wLinkMenuSelectionSendBuffer], a
ld [wLinkMenuSelectionSendBuffer + 1], a
.exchangeMenuSelectionLoop
call Serial_ExchangeLinkMenuSelection
ld a, [wLinkMenuSelectionReceiveBuffer]
ld b, a
and $f0
cp $d0
jr z, .checkEnemyMenuSelection
ld a, [wLinkMenuSelectionReceiveBuffer + 1]
ld b, a
and $f0
cp $d0
jr nz, .exchangeMenuSelectionLoop
.checkEnemyMenuSelection
ld a, b
and $c ; did the enemy press A or B?
jr nz, .enemyPressedAOrB
; the enemy didn't press A or B
ld a, [wLinkMenuSelectionSendBuffer]
and $c ; did the player press A or B?
jr z, .waitForInputLoop ; if neither the player nor the enemy pressed A or B, try again
jr .doneChoosingMenuSelection ; if the player pressed A or B but the enemy didn't, use the player's selection
.enemyPressedAOrB
ld a, [wLinkMenuSelectionSendBuffer]
and $c ; did the player press A or B?
jr z, .useEnemyMenuSelection ; if the enemy pressed A or B but the player didn't, use the enemy's selection
; the enemy and the player both pressed A or B
; The gameboy that is clocking the connection wins.
ldh a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
jr z, .doneChoosingMenuSelection
.useEnemyMenuSelection
ld a, b
ld [wLinkMenuSelectionSendBuffer], a
and $3
ld [wCurrentMenuItem], a
.doneChoosingMenuSelection
ldh a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
jr nz, .skipStartingTransfer
call DelayFrame
call DelayFrame
ld a, SC_START | SC_INTERNAL
ldh [rSC], a
.skipStartingTransfer
ld b, " "
ld c, " "
ld d, "▷"
ld a, [wLinkMenuSelectionSendBuffer]
and PAD_B << 2 ; was B button pressed?
jr nz, .updateCursorPosition
; A button was pressed
ld a, [wCurrentMenuItem]
cp $2
jr z, .updateCursorPosition
ld c, d
ld d, b
dec a
jr z, .updateCursorPosition
ld b, c
ld c, d
.updateCursorPosition
ld a, b
ldcoord_a 6, 7
ld a, c
ldcoord_a 6, 9
ld a, d
ldcoord_a 6, 11
ld c, 40
call DelayFrames
call LoadScreenTilesFromBuffer1
ld a, [wLinkMenuSelectionSendBuffer]
and PAD_B << 2 ; was B button pressed?
jr nz, .choseCancel ; cancel if B pressed
ld a, [wCurrentMenuItem]
cp $2
jr z, .choseCancel
xor a
ld [wWalkBikeSurfState], a ; start walking
ld a, [wCurrentMenuItem]
and a
ld a, COLOSSEUM
jr nz, .next
ld a, TRADE_CENTER
.next
ld [wCableClubDestinationMap], a
ld hl, PleaseWaitText
call PrintText
ld c, 50
call DelayFrames
ld hl, wStatusFlags6
res BIT_DEBUG_MODE, [hl]
ld a, [wDefaultMap]
ld [wDestinationMap], a
call PrepareForSpecialWarp
ld c, 20
call DelayFrames
xor a
ld [wMenuJoypadPollCount], a
ld [wSerialExchangeNybbleSendData], a
inc a ; LINK_STATE_IN_CABLE_CLUB
ld [wLinkState], a
ld [wEnteringCableClub], a
jr SpecialEnterMap
.choseCancel
xor a
ld [wMenuJoypadPollCount], a
vc_hook Wireless_net_stop
call Delay3
call CloseLinkConnection
ld hl, LinkCanceledText
vc_hook Wireless_net_end
call PrintText
ld hl, wStatusFlags4
res BIT_LINK_CONNECTED, [hl]
ret
WhereWouldYouLikeText:
text_far _WhereWouldYouLikeText
text_end
PleaseWaitText:
text_far _PleaseWaitText
text_end
LinkCanceledText:
text_far _LinkCanceledText
text_end
StartNewGame:
ld hl, wStatusFlags6
; Ensure debug mode is not used when starting a regular new game.
; Debug mode persists in saved games for both debug and non-debug builds, and is
; only reset here by the main menu.
res BIT_DEBUG_MODE, [hl]
; fallthrough
StartNewGameDebug:
call OakSpeech
ld c, 20
call DelayFrames
; enter map after using a special warp or loading the game from the main menu
SpecialEnterMap::
xor a
ldh [hJoyPressed], a
ldh [hJoyHeld], a
ldh [hJoy5], a
ld [wCableClubDestinationMap], a
ld hl, wStatusFlags6
set BIT_GAME_TIMER_COUNTING, [hl]
call ResetPlayerSpriteData
ld c, 20
call DelayFrames
ld a, [wEnteringCableClub]
and a
ret nz
jp EnterMap
ContinueText:
db "CONTINUE"
next ""
; fallthrough
NewGameText:
db "NEW GAME"
next "OPTION@"
CableClubOptionsText:
db "TRADE CENTER"
next "COLOSSEUM"
next "CANCEL@"
DisplayContinueGameInfo:
xor a
ldh [hAutoBGTransferEnabled], a
hlcoord 4, 7
ld b, 8
ld c, 14
call TextBoxBorder
hlcoord 5, 9
ld de, SaveScreenInfoText
call PlaceString
hlcoord 12, 9
ld de, wPlayerName
call PlaceString
hlcoord 17, 11
call PrintNumBadges
hlcoord 16, 13
call PrintNumOwnedMons
hlcoord 13, 15
call PrintPlayTime
ld a, 1
ldh [hAutoBGTransferEnabled], a
ld c, 30
jp DelayFrames
PrintSaveScreenText:
xor a
ldh [hAutoBGTransferEnabled], a
hlcoord 4, 0
ld b, $8
ld c, $e
call TextBoxBorder
call LoadTextBoxTilePatterns
call UpdateSprites
hlcoord 5, 2
ld de, SaveScreenInfoText
call PlaceString
hlcoord 12, 2
ld de, wPlayerName
call PlaceString
hlcoord 17, 4
call PrintNumBadges
hlcoord 16, 6
call PrintNumOwnedMons
hlcoord 13, 8
call PrintPlayTime
ld a, $1
ldh [hAutoBGTransferEnabled], a
ld c, 30
jp DelayFrames
PrintNumBadges:
push hl
ld hl, wObtainedBadges
ld b, $1
call CountSetBits
pop hl
ld de, wNumSetBits
lb bc, 1, 2
jp PrintNumber
PrintNumOwnedMons:
push hl
ld hl, wPokedexOwned
ld b, wPokedexOwnedEnd - wPokedexOwned
call CountSetBits
pop hl
ld de, wNumSetBits
lb bc, 1, 3
jp PrintNumber
PrintPlayTime:
ld de, wPlayTimeHours
lb bc, 1, 3
call PrintNumber
ld [hl], $6d
inc hl
ld de, wPlayTimeMinutes
lb bc, LEADING_ZEROES | 1, 2
jp PrintNumber
SaveScreenInfoText:
db "PLAYER"
next "BADGES "
next "#DEX "
next "TIME@"
DisplayOptionMenu:
hlcoord 0, 0
ld b, 3
ld c, 18
call TextBoxBorder
hlcoord 0, 5
ld b, 3
ld c, 18
call TextBoxBorder
hlcoord 0, 10
ld b, 3
ld c, 18
call TextBoxBorder
hlcoord 1, 1
ld de, TextSpeedOptionText
call PlaceString
hlcoord 1, 6
ld de, BattleAnimationOptionText
call PlaceString
hlcoord 1, 11
ld de, BattleStyleOptionText
call PlaceString
hlcoord 2, 16
ld de, OptionMenuCancelText
call PlaceString
xor a
ld [wCurrentMenuItem], a
ld [wLastMenuItem], a
ASSERT BIT_FAST_TEXT_DELAY == 0
inc a ; 1 << BIT_FAST_TEXT_DELAY
ld [wLetterPrintingDelayFlags], a
ld [wOptionsCancelCursorX], a
ld a, 3 ; text speed cursor Y coordinate
ld [wTopMenuItemY], a
call SetCursorPositionsFromOptions
ld a, [wOptionsTextSpeedCursorX] ; text speed cursor X coordinate
ld [wTopMenuItemX], a
ld a, $01
ldh [hAutoBGTransferEnabled], a ; enable auto background transfer
call Delay3
.loop
call PlaceMenuCursor
call SetOptionsFromCursorPositions
.getJoypadStateLoop
call JoypadLowSensitivity
ldh a, [hJoy5]
ld b, a
and ~PAD_SELECT ; any key besides select pressed?
jr z, .getJoypadStateLoop
bit B_PAD_B, b
jr nz, .exitMenu
bit B_PAD_START, b
jr nz, .exitMenu
bit B_PAD_A, b
jr z, .checkDirectionKeys
ld a, [wTopMenuItemY]
cp 16 ; is the cursor on Cancel?
jr nz, .loop
.exitMenu
ld a, SFX_PRESS_AB
call PlaySound
ret
.eraseOldMenuCursor
ld [wTopMenuItemX], a
call EraseMenuCursor
jp .loop
.checkDirectionKeys
ld a, [wTopMenuItemY]
bit B_PAD_DOWN, b
jr nz, .downPressed
bit B_PAD_UP, b
jr nz, .upPressed
cp 8 ; cursor in Battle Animation section?
jr z, .cursorInBattleAnimation
cp 13 ; cursor in Battle Style section?
jr z, .cursorInBattleStyle
cp 16 ; cursor on Cancel?
jr z, .loop
.cursorInTextSpeed
bit B_PAD_LEFT, b
jp nz, .pressedLeftInTextSpeed
jp .pressedRightInTextSpeed
.downPressed
cp 16
ld b, -13
ld hl, wOptionsTextSpeedCursorX
jr z, .updateMenuVariables
ld b, 5
cp 3
inc hl
jr z, .updateMenuVariables
cp 8
inc hl
jr z, .updateMenuVariables
ld b, 3
inc hl
jr .updateMenuVariables
.upPressed
cp 8
ld b, -5
ld hl, wOptionsTextSpeedCursorX
jr z, .updateMenuVariables
cp 13
inc hl
jr z, .updateMenuVariables
cp 16
ld b, -3
inc hl
jr z, .updateMenuVariables
ld b, 13
inc hl
.updateMenuVariables
add b
ld [wTopMenuItemY], a
ld a, [hl]
ld [wTopMenuItemX], a
call PlaceUnfilledArrowMenuCursor
jp .loop
.cursorInBattleAnimation
ld a, [wOptionsBattleAnimCursorX] ; battle animation cursor X coordinate
xor 1 ^ 10 ; toggle between 1 and 10
ld [wOptionsBattleAnimCursorX], a
jp .eraseOldMenuCursor
.cursorInBattleStyle
ld a, [wOptionsBattleStyleCursorX] ; battle style cursor X coordinate
xor 1 ^ 10 ; toggle between 1 and 10
ld [wOptionsBattleStyleCursorX], a
jp .eraseOldMenuCursor
.pressedLeftInTextSpeed
ld a, [wOptionsTextSpeedCursorX] ; text speed cursor X coordinate
cp 1
jr z, .updateTextSpeedXCoord
cp 7
jr nz, .fromSlowToMedium
sub 6
jr .updateTextSpeedXCoord
.fromSlowToMedium
sub 7
jr .updateTextSpeedXCoord
.pressedRightInTextSpeed
ld a, [wOptionsTextSpeedCursorX] ; text speed cursor X coordinate
cp 14
jr z, .updateTextSpeedXCoord
cp 7
jr nz, .fromFastToMedium
add 7
jr .updateTextSpeedXCoord
.fromFastToMedium
add 6
.updateTextSpeedXCoord
ld [wOptionsTextSpeedCursorX], a ; text speed cursor X coordinate
jp .eraseOldMenuCursor
TextSpeedOptionText:
db "TEXT SPEED"
next " FAST MEDIUM SLOW@"
BattleAnimationOptionText:
db "BATTLE ANIMATION"
next " ON OFF@"
BattleStyleOptionText:
db "BATTLE STYLE"
next " SHIFT SET@"
OptionMenuCancelText:
db "CANCEL@"
; sets the options variable according to the current placement of the menu cursors in the options menu
SetOptionsFromCursorPositions:
ld hl, TextSpeedOptionData
ld a, [wOptionsTextSpeedCursorX] ; text speed cursor X coordinate
ld c, a
.loop
ld a, [hli]
cp c
jr z, .textSpeedMatchFound
inc hl
jr .loop
.textSpeedMatchFound
ld a, [hl]
ld d, a
ld a, [wOptionsBattleAnimCursorX] ; battle animation cursor X coordinate
dec a
jr z, .battleAnimationOn
.battleAnimationOff
set BIT_BATTLE_ANIMATION, d
jr .checkBattleStyle
.battleAnimationOn
res BIT_BATTLE_ANIMATION, d
.checkBattleStyle
ld a, [wOptionsBattleStyleCursorX] ; battle style cursor X coordinate
dec a
jr z, .battleStyleShift
.battleStyleSet
set BIT_BATTLE_SHIFT, d
jr .storeOptions
.battleStyleShift
res BIT_BATTLE_SHIFT, d
.storeOptions
ld a, d
ld [wOptions], a
ret
; reads the options variable and places menu cursors in the correct positions within the options menu
SetCursorPositionsFromOptions:
ld hl, TextSpeedOptionData + 1
ld a, [wOptions]
ld c, a
and $3f
push bc
ld de, 2
call IsInArray
pop bc
dec hl
ld a, [hl]
ld [wOptionsTextSpeedCursorX], a ; text speed cursor X coordinate
hlcoord 0, 3
call .placeUnfilledRightArrow
sla c
ld a, 1 ; On
jr nc, .storeBattleAnimationCursorX
ld a, 10 ; Off
.storeBattleAnimationCursorX
ld [wOptionsBattleAnimCursorX], a ; battle animation cursor X coordinate
hlcoord 0, 8
call .placeUnfilledRightArrow
sla c
ld a, 1
jr nc, .storeBattleStyleCursorX
ld a, 10
.storeBattleStyleCursorX
ld [wOptionsBattleStyleCursorX], a ; battle style cursor X coordinate
hlcoord 0, 13
call .placeUnfilledRightArrow
; cursor in front of Cancel
hlcoord 0, 16
ld a, 1
.placeUnfilledRightArrow
ld e, a
ld d, 0
add hl, de
ld [hl], "▷"
ret
; table that indicates how the 3 text speed options affect frame delays
; Format:
; 00: X coordinate of menu cursor
; 01: delay after printing a letter (in frames)
TextSpeedOptionData:
db 14, TEXT_DELAY_SLOW
db 7, TEXT_DELAY_MEDIUM
db 1, TEXT_DELAY_FAST
db 7, -1 ; end (default X coordinate)
CheckForPlayerNameInSRAM:
; Check if the player name data in SRAM has a string terminator character
; (indicating that a name may have been saved there) and return whether it does
; in carry.
ld a, RAMG_SRAM_ENABLE
ld [rRAMG], a
ld a, BMODE_ADVANCED
ld [rBMODE], a
ASSERT BANK(sPlayerName) == BMODE_ADVANCED
ld [rRAMB], a
ld b, NAME_LENGTH
ld hl, sPlayerName
.loop
ld a, [hli]
cp "@"
jr z, .found
dec b
jr nz, .loop
; not found
xor a
ld [rRAMG], a
ld [rBMODE], a
and a
ret
.found
xor a
ld [rRAMG], a
ld [rBMODE], a
scf
ret