Add subdirectories to engine/ similar to pokecrystal

This commit is contained in:
Rangi 2020-07-02 23:30:21 -04:00
parent 5559d51c86
commit f275790aec
124 changed files with 342 additions and 346 deletions

View file

@ -0,0 +1,78 @@
; function that performs initialization for DisplayTextID
DisplayTextIDInit::
xor a
ld [wListMenuID], a
ld a, [wAutoTextBoxDrawingControl]
bit 0, a
jr nz, .skipDrawingTextBoxBorder
ld a, [hSpriteIndexOrTextID] ; text ID (or sprite ID)
and a
jr nz, .notStartMenu
; if text ID is 0 (i.e. the start menu)
; Note that the start menu text border is also drawn in the function directly
; below this, so this seems unnecessary.
CheckEvent EVENT_GOT_POKEDEX
; start menu with pokedex
coord hl, 10, 0
ld b, $0e
ld c, $08
jr nz, .drawTextBoxBorder
; start menu without pokedex
coord hl, 10, 0
ld b, $0c
ld c, $08
jr .drawTextBoxBorder
; if text ID is not 0 (i.e. not the start menu) then do a standard dialogue text box
.notStartMenu
coord hl, 0, 12
ld b, $04
ld c, $12
.drawTextBoxBorder
call TextBoxBorder
.skipDrawingTextBoxBorder
ld hl, wFontLoaded
set 0, [hl]
ld hl, wFlags_0xcd60
bit 4, [hl]
res 4, [hl]
jr nz, .skipMovingSprites
call UpdateSprites
.skipMovingSprites
; loop to copy C1X9 (direction the sprite is facing) to C2X9 for each sprite
; this is done because when you talk to an NPC, they turn to look your way
; the original direction they were facing must be restored after the dialogue is over
ld hl, wSpriteStateData1 + $19
ld c, $0f
ld de, $0010
.spriteFacingDirectionCopyLoop
ld a, [hl]
inc h
ld [hl], a
dec h
add hl, de
dec c
jr nz, .spriteFacingDirectionCopyLoop
; loop to force all the sprites in the middle of animation to stand still
; (so that they don't like they're frozen mid-step during the dialogue)
ld hl, wSpriteStateData1 + 2
ld de, $0010
ld c, e
.spriteStandStillLoop
ld a, [hl]
cp $ff ; is the sprite visible?
jr z, .nextSprite
; if it is visible
and $fc
ld [hl], a
.nextSprite
add hl, de
dec c
jr nz, .spriteStandStillLoop
ld b, $9c ; window background address
call CopyScreenTileBufferToVRAM ; transfer background in WRAM to VRAM
xor a
ld [hWY], a ; put the window on the screen
call LoadFontTilePatterns
ld a, $01
ld [H_AUTOBGTRANSFERENABLED], a ; enable continuous WRAM to VRAM transfer each V-blank
ret

View file

@ -0,0 +1,120 @@
DrawBadges:
; Draw 4x2 gym leader faces, with the faces replaced by
; badges if they are owned. Used in the player status screen.
; In Japanese versions, names are displayed above faces.
; Instead of removing relevant code, the name graphics were erased.
; Tile ids for face/badge graphics.
ld de, wBadgeOrFaceTiles
ld hl, .FaceBadgeTiles
ld bc, 8
call CopyData
; Booleans for each badge.
ld hl, wTempObtainedBadgesBooleans
ld bc, 8
xor a
call FillMemory
; Alter these based on owned badges.
ld de, wTempObtainedBadgesBooleans
ld hl, wBadgeOrFaceTiles
ld a, [wObtainedBadges]
ld b, a
ld c, 8
.CheckBadge
srl b
jr nc, .NextBadge
ld a, [hl]
add 4 ; Badge graphics are after each face
ld [hl], a
ld a, 1
ld [de], a
.NextBadge
inc hl
inc de
dec c
jr nz, .CheckBadge
; Draw two rows of badges.
ld hl, wBadgeNumberTile
ld a, $d8 ; [1]
ld [hli], a
ld [hl], $60 ; First name
coord hl, 2, 11
ld de, wTempObtainedBadgesBooleans
call .DrawBadgeRow
coord hl, 2, 14
ld de, wTempObtainedBadgesBooleans + 4
; call .DrawBadgeRow
; ret
.DrawBadgeRow
; Draw 4 badges.
ld c, 4
.DrawBadge
push de
push hl
; Badge no.
ld a, [wBadgeNumberTile]
ld [hli], a
inc a
ld [wBadgeNumberTile], a
; Names aren't printed if the badge is owned.
ld a, [de]
and a
ld a, [wBadgeNameTile]
jr nz, .SkipName
call .PlaceTiles
jr .PlaceBadge
.SkipName
inc a
inc a
inc hl
.PlaceBadge
ld [wBadgeNameTile], a
ld de, SCREEN_WIDTH - 1
add hl, de
ld a, [wBadgeOrFaceTiles]
call .PlaceTiles
add hl, de
call .PlaceTiles
; Shift badge array back one byte.
push bc
ld hl, wBadgeOrFaceTiles + 1
ld de, wBadgeOrFaceTiles
ld bc, 8
call CopyData
pop bc
pop hl
ld de, 4
add hl, de
pop de
inc de
dec c
jr nz, .DrawBadge
ret
.PlaceTiles
ld [hli], a
inc a
ld [hl], a
inc a
ret
.FaceBadgeTiles
db $20, $28, $30, $38, $40, $48, $50, $58
GymLeaderFaceAndBadgeTileGraphics:
INCBIN "gfx/trainer_card/badges.2bpp"

View file

@ -0,0 +1,89 @@
; function that displays the start menu
DrawStartMenu::
CheckEvent EVENT_GOT_POKEDEX
; menu with pokedex
coord hl, 10, 0
ld b, $0e
ld c, $08
jr nz, .drawTextBoxBorder
; shorter menu if the player doesn't have the pokedex
coord hl, 10, 0
ld b, $0c
ld c, $08
.drawTextBoxBorder
call TextBoxBorder
ld a, D_DOWN | D_UP | START | B_BUTTON | A_BUTTON
ld [wMenuWatchedKeys], a
ld a, $02
ld [wTopMenuItemY], a ; Y position of first menu choice
ld a, $0b
ld [wTopMenuItemX], a ; X position of first menu choice
ld a, [wBattleAndStartSavedMenuItem] ; remembered menu selection from last time
ld [wCurrentMenuItem], a
ld [wLastMenuItem], a
xor a
ld [wMenuWatchMovingOutOfBounds], a
ld hl, wd730
set 6, [hl] ; no pauses between printing each letter
coord hl, 12, 2
CheckEvent EVENT_GOT_POKEDEX
; case for not having pokedex
ld a, $06
jr z, .storeMenuItemCount
; case for having pokedex
ld de, StartMenuPokedexText
call PrintStartMenuItem
ld a, $07
.storeMenuItemCount
ld [wMaxMenuItem], a ; number of menu items
ld de, StartMenuPokemonText
call PrintStartMenuItem
ld de, StartMenuItemText
call PrintStartMenuItem
ld de, wPlayerName ; player's name
call PrintStartMenuItem
ld a, [wd72e]
bit 6, a ; is the player using the link feature?
; case for not using link feature
ld de, StartMenuSaveText
jr z, .printSaveOrResetText
; case for using link feature
ld de, StartMenuResetText
.printSaveOrResetText
call PrintStartMenuItem
ld de, StartMenuOptionText
call PrintStartMenuItem
ld de, StartMenuExitText
call PlaceString
ld hl, wd730
res 6, [hl] ; turn pauses between printing letters back on
ret
StartMenuPokedexText:
db "POKéDEX@"
StartMenuPokemonText:
db "POKéMON@"
StartMenuItemText:
db "ITEM@"
StartMenuSaveText:
db "SAVE@"
StartMenuResetText:
db "RESET@"
StartMenuExitText:
db "EXIT@"
StartMenuOptionText:
db "OPTION@"
PrintStartMenuItem:
push hl
call PlaceString
pop hl
ld de, SCREEN_WIDTH * 2
add hl, de
ret

120
engine/menus/league_pc.asm Executable file
View file

@ -0,0 +1,120 @@
PKMNLeaguePC:
ld hl, AccessedHoFPCText
call PrintText
ld hl, wd730
set 6, [hl]
push hl
ld a, [wUpdateSpritesEnabled]
push af
ld a, [hTilesetType]
push af
xor a
ld [hTilesetType], a
ld [wSpriteFlipped], a
ld [wUpdateSpritesEnabled], a
ld [wHoFTeamIndex2], a
ld [wHoFTeamNo], a
ld a, [wNumHoFTeams]
ld b, a
cp HOF_TEAM_CAPACITY + 1
jr c, .loop
; If the total number of hall of fame teams is greater than the storage
; capacity, then calculate the number of the first team that is still recorded.
ld b, HOF_TEAM_CAPACITY
sub b
ld [wHoFTeamNo], a
.loop
ld hl, wHoFTeamNo
inc [hl]
push bc
ld a, [wHoFTeamIndex2]
ld [wHoFTeamIndex], a
callba LoadHallOfFameTeams
call LeaguePCShowTeam
pop bc
jr c, .doneShowingTeams
ld hl, wHoFTeamIndex2
inc [hl]
ld a, [hl]
cp b
jr nz, .loop
.doneShowingTeams
pop af
ld [hTilesetType], a
pop af
ld [wUpdateSpritesEnabled], a
pop hl
res 6, [hl]
call GBPalWhiteOutWithDelay3
call ClearScreen
call RunDefaultPaletteCommand
jp GBPalNormal
LeaguePCShowTeam:
ld c, PARTY_LENGTH
.loop
push bc
call LeaguePCShowMon
call WaitForTextScrollButtonPress
ld a, [hJoyHeld]
bit 1, a
jr nz, .exit
ld hl, wHallOfFame + HOF_MON
ld de, wHallOfFame
ld bc, HOF_TEAM - HOF_MON
call CopyData
pop bc
ld a, [wHallOfFame + 0]
cp $ff
jr z, .done
dec c
jr nz, .loop
.done
and a
ret
.exit
pop bc
scf
ret
LeaguePCShowMon:
call GBPalWhiteOutWithDelay3
call ClearScreen
ld hl, wHallOfFame
ld a, [hli]
ld [wHoFMonSpecies], a
ld [wcf91], a
ld [wd0b5], a
ld [wBattleMonSpecies2], a
ld [wWholeScreenPaletteMonSpecies], a
ld a, [hli]
ld [wHoFMonLevel], a
ld de, wcd6d
ld bc, NAME_LENGTH
call CopyData
ld b, SET_PAL_POKEMON_WHOLE_SCREEN
ld c, 0
call RunPaletteCommand
coord hl, 12, 5
call GetMonHeader
call LoadFrontSpriteByMonIndex
call GBPalNormal
coord hl, 0, 13
ld b, 2
ld c, $12
call TextBoxBorder
coord hl, 1, 15
ld de, HallOfFameNoText
call PlaceString
coord hl, 16, 15
ld de, wHoFTeamNo
lb bc, 1, 3
call PrintNumber
jpba HoFDisplayMonInfo
HallOfFameNoText:
db "HALL OF FAME No @"
AccessedHoFPCText:
TX_FAR _AccessedHoFPCText
db "@"

712
engine/menus/main_menu.asm Executable file
View file

@ -0,0 +1,712 @@
MainMenu:
; Check save file
call InitOptions
xor a
ld [wOptionsInitialized], a
inc a
ld [wSaveFileStatus], a
call CheckForPlayerNameInSRAM
jr nc, .mainMenuLoop
predef LoadSAV
.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, wd72e
res 6, [hl]
call ClearScreen
call RunDefaultPaletteCommand
call LoadTextBoxTilePatterns
call LoadFontTilePatterns
ld hl, wd730
set 6, [hl]
ld a, [wSaveFileStatus]
cp 1
jr z, .noSaveFile
; there's a save file
coord hl, 0, 0
ld b, 6
ld c, 13
call TextBoxBorder
coord hl, 2, 2
ld de, ContinueText
call PlaceString
jr .next2
.noSaveFile
coord hl, 0, 0
ld b, 4
ld c, 13
call TextBoxBorder
coord hl, 2, 2
ld de, NewGameText
call PlaceString
.next2
ld hl, wd730
res 6, [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, A_BUTTON | B_BUTTON | START
ld [wMenuWatchedKeys], a
ld a, [wSaveFileStatus]
ld [wMaxMenuItem], a
call HandleMenuInput
bit 1, a ; pressed B?
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, 1
ld [wOptionsInitialized], a
jp .mainMenuLoop
.choseContinue
call DisplayContinueGameInfo
ld hl, wCurrentMapScriptFlags
set 5, [hl]
.inputLoop
xor a
ld [hJoyPressed], a
ld [hJoyReleased], a
ld [hJoyHeld], a
call Joypad
ld a, [hJoyHeld]
bit 0, a
jr nz, .pressedA
bit 1, a
jp nz, .mainMenuLoop ; pressed B
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] ; map ID
cp HALL_OF_FAME
jp nz, SpecialEnterMap
xor a
ld [wDestinationMap], a
ld hl, wd732
set 2, [hl] ; fly warp or dungeon warp
call SpecialWarpIn
jp SpecialEnterMap
InitOptions:
ld a, 1 ; no delay
ld [wLetterPrintingDelayFlags], a
ld a, 3 ; medium speed
ld [wOptions], a
ret
LinkMenu:
xor a
ld [wLetterPrintingDelayFlags], a
ld hl, wd72e
set 6, [hl]
ld hl, TextTerminator_6b20
call PrintText
call SaveScreenTilesToBuffer1
ld hl, WhereWouldYouLikeText
call PrintText
coord hl, 5, 5
ld b, $6
ld c, $d
call TextBoxBorder
call UpdateSprites
coord hl, 7, 7
ld de, CableClubOptionsText
call PlaceString
xor a
ld [wUnusedCD37], a
ld [wd72d], a
ld hl, wTopMenuItemY
ld a, $7
ld [hli], a
ld a, $6
ld [hli], a
xor a
ld [hli], a
inc hl
ld a, $2
ld [hli], a
inc a
; ld a, A_BUTTON | B_BUTTON
ld [hli], a ; wMenuWatchedKeys
xor a
ld [hl], a
.waitForInputLoop
call HandleMenuInput
and A_BUTTON | B_BUTTON
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, .asm_5c7d
ld a, [wLinkMenuSelectionReceiveBuffer + 1]
ld b, a
and $f0
cp $d0
jr nz, .exchangeMenuSelectionLoop
.asm_5c7d
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.
ld a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
jr z, .doneChoosingMenuSelection
.useEnemyMenuSelection
ld a, b
ld [wLinkMenuSelectionSendBuffer], a
and $3
ld [wCurrentMenuItem], a
.doneChoosingMenuSelection
ld a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
jr nz, .skipStartingTransfer
call DelayFrame
call DelayFrame
ld a, START_TRANSFER_INTERNAL_CLOCK
ld [rSC], a
.skipStartingTransfer
ld b, $7f
ld c, $7f
ld d, $ec
ld a, [wLinkMenuSelectionSendBuffer]
and (B_BUTTON << 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
Coorda 6, 7
ld a, c
Coorda 6, 9
ld a, d
Coorda 6, 11
ld c, 40
call DelayFrames
call LoadScreenTilesFromBuffer1
ld a, [wLinkMenuSelectionSendBuffer]
and (B_BUTTON << 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 [wd72d], a
ld hl, PleaseWaitText
call PrintText
ld c, 50
call DelayFrames
ld hl, wd732
res 1, [hl]
ld a, [wDefaultMap]
ld [wDestinationMap], a
call SpecialWarpIn
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
call Delay3
call CloseLinkConnection
ld hl, LinkCanceledText
call PrintText
ld hl, wd72e
res 6, [hl]
ret
WhereWouldYouLikeText:
TX_FAR _WhereWouldYouLikeText
db "@"
PleaseWaitText:
TX_FAR _PleaseWaitText
db "@"
LinkCanceledText:
TX_FAR _LinkCanceledText
db "@"
StartNewGame:
ld hl, wd732
res 1, [hl]
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
ld [hJoyPressed], a
ld [hJoyHeld], a
ld [hJoy5], a
ld [wd72d], a
ld hl, wd732
set 0, [hl] ; count play time
call ResetPlayerSpriteData
ld c, 20
call DelayFrames
ld a, [wEnteringCableClub]
and a
ret nz
jp EnterMap
ContinueText:
db "CONTINUE", $4e
NewGameText:
db "NEW GAME"
next "OPTION@"
CableClubOptionsText:
db "TRADE CENTER"
next "COLOSSEUM"
next "CANCEL@"
DisplayContinueGameInfo:
xor a
ld [H_AUTOBGTRANSFERENABLED], a
coord hl, 4, 7
ld b, 8
ld c, 14
call TextBoxBorder
coord hl, 5, 9
ld de, SaveScreenInfoText
call PlaceString
coord hl, 12, 9
ld de, wPlayerName
call PlaceString
coord hl, 17, 11
call PrintNumBadges
coord hl, 16, 13
call PrintNumOwnedMons
coord hl, 13, 15
call PrintPlayTime
ld a, 1
ld [H_AUTOBGTRANSFERENABLED], a
ld c, 30
jp DelayFrames
PrintSaveScreenText:
xor a
ld [H_AUTOBGTRANSFERENABLED], a
coord hl, 4, 0
ld b, $8
ld c, $e
call TextBoxBorder
call LoadTextBoxTilePatterns
call UpdateSprites
coord hl, 5, 2
ld de, SaveScreenInfoText
call PlaceString
coord hl, 12, 2
ld de, wPlayerName
call PlaceString
coord hl, 17, 4
call PrintNumBadges
coord hl, 16, 6
call PrintNumOwnedMons
coord hl, 13, 8
call PrintPlayTime
ld a, $1
ld [H_AUTOBGTRANSFERENABLED], 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:
coord hl, 0, 0
ld b, 3
ld c, 18
call TextBoxBorder
coord hl, 0, 5
ld b, 3
ld c, 18
call TextBoxBorder
coord hl, 0, 10
ld b, 3
ld c, 18
call TextBoxBorder
coord hl, 1, 1
ld de, TextSpeedOptionText
call PlaceString
coord hl, 1, 6
ld de, BattleAnimationOptionText
call PlaceString
coord hl, 1, 11
ld de, BattleStyleOptionText
call PlaceString
coord hl, 2, 16
ld de, OptionMenuCancelText
call PlaceString
xor a
ld [wCurrentMenuItem], a
ld [wLastMenuItem], a
inc a
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
ld [H_AUTOBGTRANSFERENABLED], a ; enable auto background transfer
call Delay3
.loop
call PlaceMenuCursor
call SetOptionsFromCursorPositions
.getJoypadStateLoop
call JoypadLowSensitivity
ld a, [hJoy5]
ld b, a
and A_BUTTON | B_BUTTON | START | D_RIGHT | D_LEFT | D_UP | D_DOWN ; any key besides select pressed?
jr z, .getJoypadStateLoop
bit 1, b ; B button pressed?
jr nz, .exitMenu
bit 3, b ; Start button pressed?
jr nz, .exitMenu
bit 0, b ; A button pressed?
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 7, b ; Down pressed?
jr nz, .downPressed
bit 6, b ; Up pressed?
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 5, b ; Left pressed?
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 $0b ; toggle between 1 and 10
ld [wOptionsBattleAnimCursorX], a
jp .eraseOldMenuCursor
.cursorInBattleStyle
ld a, [wOptionsBattleStyleCursorX] ; battle style cursor X coordinate
xor $0b ; 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 7, d
jr .checkBattleStyle
.battleAnimationOn
res 7, d
.checkBattleStyle
ld a, [wOptionsBattleStyleCursorX] ; battle style cursor X coordinate
dec a
jr z, .battleStyleShift
.battleStyleSet
set 6, d
jr .storeOptions
.battleStyleShift
res 6, 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
coord hl, 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
coord hl, 0, 8
call .placeUnfilledRightArrow
sla c
ld a, 1
jr nc, .storeBattleStyleCursorX
ld a, 10
.storeBattleStyleCursorX
ld [wOptionsBattleStyleCursorX], a ; battle style cursor X coordinate
coord hl, 0, 13
call .placeUnfilledRightArrow
; cursor in front of Cancel
coord hl, 0, 16
ld a, 1
.placeUnfilledRightArrow
ld e, a
ld d, 0
add hl, de
ld [hl], $ec ; unfilled right arrow menu cursor
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,5 ; Slow
db 7,3 ; Medium
db 1,1 ; Fast
db 7 ; default X coordinate (Medium)
db $ff ; terminator
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, SRAM_ENABLE
ld [MBC1SRamEnable], a
ld a, $1
ld [MBC1SRamBankingMode], a
ld [MBC1SRamBank], 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 [MBC1SRamEnable], a
ld [MBC1SRamBankingMode], a
and a
ret
.found
xor a
ld [MBC1SRamEnable], a
ld [MBC1SRamBankingMode], a
scf
ret

494
engine/menus/naming_screen.asm Executable file
View file

@ -0,0 +1,494 @@
AskName:
call SaveScreenTilesToBuffer1
call GetPredefRegisters
push hl
ld a, [wIsInBattle]
dec a
coord hl, 0, 0
ld b, 4
ld c, 11
call z, ClearScreenArea ; only if in wild battle
ld a, [wcf91]
ld [wd11e], a
call GetMonName
ld hl, DoYouWantToNicknameText
call PrintText
coord hl, 14, 7
lb bc, 8, 15
ld a, TWO_OPTION_MENU
ld [wTextBoxID], a
call DisplayTextBoxID
pop hl
ld a, [wCurrentMenuItem]
and a
jr nz, .declinedNickname
ld a, [wUpdateSpritesEnabled]
push af
xor a
ld [wUpdateSpritesEnabled], a
push hl
ld a, NAME_MON_SCREEN
ld [wNamingScreenType], a
call DisplayNamingScreen
ld a, [wIsInBattle]
and a
jr nz, .inBattle
call ReloadMapSpriteTilePatterns
.inBattle
call LoadScreenTilesFromBuffer1
pop hl
pop af
ld [wUpdateSpritesEnabled], a
ld a, [wcf4b]
cp "@"
ret nz
.declinedNickname
ld d, h
ld e, l
ld hl, wcd6d
ld bc, NAME_LENGTH
jp CopyData
DoYouWantToNicknameText:
TX_FAR _DoYouWantToNicknameText
db "@"
DisplayNameRaterScreen::
ld hl, wBuffer
xor a
ld [wUpdateSpritesEnabled], a
ld a, NAME_MON_SCREEN
ld [wNamingScreenType], a
call DisplayNamingScreen
call GBPalWhiteOutWithDelay3
call RestoreScreenTilesAndReloadTilePatterns
call LoadGBPal
ld a, [wcf4b]
cp "@"
jr z, .playerCancelled
ld hl, wPartyMonNicks
ld bc, NAME_LENGTH
ld a, [wWhichPokemon]
call AddNTimes
ld e, l
ld d, h
ld hl, wBuffer
ld bc, NAME_LENGTH
call CopyData
and a
ret
.playerCancelled
scf
ret
DisplayNamingScreen:
push hl
ld hl, wd730
set 6, [hl]
call GBPalWhiteOutWithDelay3
call ClearScreen
call UpdateSprites
ld b, SET_PAL_GENERIC
call RunPaletteCommand
call LoadHpBarAndStatusTilePatterns
call LoadEDTile
callba LoadMonPartySpriteGfx
coord hl, 0, 4
ld b, 9
ld c, 18
call TextBoxBorder
call PrintNamingText
ld a, 3
ld [wTopMenuItemY], a
ld a, 1
ld [wTopMenuItemX], a
ld [wLastMenuItem], a
ld [wCurrentMenuItem], a
ld a, $ff
ld [wMenuWatchedKeys], a
ld a, 7
ld [wMaxMenuItem], a
ld a, "@"
ld [wcf4b], a
xor a
ld hl, wNamingScreenSubmitName
ld [hli], a
ld [hli], a
ld [wAnimCounter], a
.selectReturnPoint
call PrintAlphabet
call GBPalNormal
.ABStartReturnPoint
ld a, [wNamingScreenSubmitName]
and a
jr nz, .submitNickname
call PrintNicknameAndUnderscores
.dPadReturnPoint
call PlaceMenuCursor
.inputLoop
ld a, [wCurrentMenuItem]
push af
callba AnimatePartyMon_ForceSpeed1
pop af
ld [wCurrentMenuItem], a
call JoypadLowSensitivity
ld a, [hJoyPressed]
and a
jr z, .inputLoop
ld hl, .namingScreenButtonFunctions
.checkForPressedButton
sla a
jr c, .foundPressedButton
inc hl
inc hl
inc hl
inc hl
jr .checkForPressedButton
.foundPressedButton
ld a, [hli]
ld e, a
ld a, [hli]
ld d, a
ld a, [hli]
ld h, [hl]
ld l, a
push de
jp hl
.submitNickname
pop de
ld hl, wcf4b
ld bc, NAME_LENGTH
call CopyData
call GBPalWhiteOutWithDelay3
call ClearScreen
call ClearSprites
call RunDefaultPaletteCommand
call GBPalNormal
xor a
ld [wAnimCounter], a
ld hl, wd730
res 6, [hl]
ld a, [wIsInBattle]
and a
jp z, LoadTextBoxTilePatterns
jpab LoadHudTilePatterns
.namingScreenButtonFunctions
dw .dPadReturnPoint
dw .pressedDown
dw .dPadReturnPoint
dw .pressedUp
dw .dPadReturnPoint
dw .pressedLeft
dw .dPadReturnPoint
dw .pressedRight
dw .ABStartReturnPoint
dw .pressedStart
dw .selectReturnPoint
dw .pressedSelect
dw .ABStartReturnPoint
dw .pressedB
dw .ABStartReturnPoint
dw .pressedA
.pressedA_changedCase
pop de
ld de, .selectReturnPoint
push de
.pressedSelect
ld a, [wAlphabetCase]
xor $1
ld [wAlphabetCase], a
ret
.pressedStart
ld a, 1
ld [wNamingScreenSubmitName], a
ret
.pressedA
ld a, [wCurrentMenuItem]
cp $5 ; "ED" row
jr nz, .didNotPressED
ld a, [wTopMenuItemX]
cp $11 ; "ED" column
jr z, .pressedStart
.didNotPressED
ld a, [wCurrentMenuItem]
cp $6 ; case switch row
jr nz, .didNotPressCaseSwtich
ld a, [wTopMenuItemX]
cp $1 ; case switch column
jr z, .pressedA_changedCase
.didNotPressCaseSwtich
ld hl, wMenuCursorLocation
ld a, [hli]
ld h, [hl]
ld l, a
inc hl
ld a, [hl]
ld [wNamingScreenLetter], a
call CalcStringLength
ld a, [wNamingScreenLetter]
cp $e5
ld de, Dakutens
jr z, .dakutensAndHandakutens
cp $e4
ld de, Handakutens
jr z, .dakutensAndHandakutens
ld a, [wNamingScreenType]
cp NAME_MON_SCREEN
jr nc, .checkMonNameLength
ld a, [wNamingScreenNameLength]
cp $7 ; max length of player/rival names
jr .checkNameLength
.checkMonNameLength
ld a, [wNamingScreenNameLength]
cp $a ; max length of pokemon nicknames
.checkNameLength
jr c, .addLetter
ret
.dakutensAndHandakutens
push hl
call DakutensAndHandakutens
pop hl
ret nc
dec hl
.addLetter
ld a, [wNamingScreenLetter]
ld [hli], a
ld [hl], "@"
ld a, SFX_PRESS_AB
call PlaySound
ret
.pressedB
ld a, [wNamingScreenNameLength]
and a
ret z
call CalcStringLength
dec hl
ld [hl], "@"
ret
.pressedRight
ld a, [wCurrentMenuItem]
cp $6
ret z ; can't scroll right on bottom row
ld a, [wTopMenuItemX]
cp $11 ; max
jp z, .wrapToFirstColumn
inc a
inc a
jr .done
.wrapToFirstColumn
ld a, $1
jr .done
.pressedLeft
ld a, [wCurrentMenuItem]
cp $6
ret z ; can't scroll right on bottom row
ld a, [wTopMenuItemX]
dec a
jp z, .wrapToLastColumn
dec a
jr .done
.wrapToLastColumn
ld a, $11 ; max
jr .done
.pressedUp
ld a, [wCurrentMenuItem]
dec a
ld [wCurrentMenuItem], a
and a
ret nz
ld a, $6 ; wrap to bottom row
ld [wCurrentMenuItem], a
ld a, $1 ; force left column
jr .done
.pressedDown
ld a, [wCurrentMenuItem]
inc a
ld [wCurrentMenuItem], a
cp $7
jr nz, .wrapToTopRow
ld a, $1
ld [wCurrentMenuItem], a
jr .done
.wrapToTopRow
cp $6
ret nz
ld a, $1
.done
ld [wTopMenuItemX], a
jp EraseMenuCursor
LoadEDTile:
ld de, ED_Tile
ld hl, vFont + $700
ld bc, (ED_TileEnd - ED_Tile) / $8
; to fix the graphical bug on poor emulators
;lb bc, BANK(ED_Tile), (ED_TileEnd - ED_Tile) / $8
jp CopyVideoDataDouble
ED_Tile:
INCBIN "gfx/font/ED.1bpp"
ED_TileEnd:
PrintAlphabet:
xor a
ld [H_AUTOBGTRANSFERENABLED], a
ld a, [wAlphabetCase]
and a
ld de, LowerCaseAlphabet
jr nz, .lowercase
ld de, UpperCaseAlphabet
.lowercase
coord hl, 2, 5
lb bc, 5, 9 ; 5 rows, 9 columns
.outerLoop
push bc
.innerLoop
ld a, [de]
ld [hli], a
inc hl
inc de
dec c
jr nz, .innerLoop
ld bc, SCREEN_WIDTH + 2
add hl, bc
pop bc
dec b
jr nz, .outerLoop
call PlaceString
ld a, $1
ld [H_AUTOBGTRANSFERENABLED], a
jp Delay3
INCLUDE "text/alphabets.asm"
PrintNicknameAndUnderscores:
call CalcStringLength
ld a, c
ld [wNamingScreenNameLength], a
coord hl, 10, 2
lb bc, 1, 10
call ClearScreenArea
coord hl, 10, 2
ld de, wcf4b
call PlaceString
coord hl, 10, 3
ld a, [wNamingScreenType]
cp NAME_MON_SCREEN
jr nc, .pokemon1
ld b, 7 ; player or rival max name length
jr .playerOrRival1
.pokemon1
ld b, 10 ; pokemon max name length
.playerOrRival1
ld a, $76 ; underscore tile id
.placeUnderscoreLoop
ld [hli], a
dec b
jr nz, .placeUnderscoreLoop
ld a, [wNamingScreenType]
cp NAME_MON_SCREEN
ld a, [wNamingScreenNameLength]
jr nc, .pokemon2
cp 7 ; player or rival max name length
jr .playerOrRival2
.pokemon2
cp 10 ; pokemon max name length
.playerOrRival2
jr nz, .emptySpacesRemaining
; when all spaces are filled, force the cursor onto the ED tile
call EraseMenuCursor
ld a, $11 ; "ED" x coord
ld [wTopMenuItemX], a
ld a, $5 ; "ED" y coord
ld [wCurrentMenuItem], a
ld a, [wNamingScreenType]
cp NAME_MON_SCREEN
ld a, 9 ; keep the last underscore raised
jr nc, .pokemon3
ld a, 6 ; keep the last underscore raised
.pokemon3
.emptySpacesRemaining
ld c, a
ld b, $0
coord hl, 10, 3
add hl, bc
ld [hl], $77 ; raised underscore tile id
ret
DakutensAndHandakutens:
push de
call CalcStringLength
dec hl
ld a, [hl]
pop hl
ld de, $2
call IsInArray
ret nc
inc hl
ld a, [hl]
ld [wNamingScreenLetter], a
ret
INCLUDE "text/dakutens.asm"
; calculates the length of the string at wcf4b and stores it in c
CalcStringLength:
ld hl, wcf4b
ld c, $0
.loop
ld a, [hl]
cp "@"
ret z
inc hl
inc c
jr .loop
PrintNamingText:
coord hl, 0, 1
ld a, [wNamingScreenType]
ld de, YourTextString
and a
jr z, .notNickname
ld de, RivalsTextString
dec a
jr z, .notNickname
ld a, [wcf91]
ld [wMonPartySpriteSpecies], a
push af
callba WriteMonPartySpriteOAMBySpecies
pop af
ld [wd11e], a
call GetMonName
coord hl, 4, 1
call PlaceString
ld hl, $1
add hl, bc
ld [hl], $c9
coord hl, 1, 3
ld de, NicknameTextString
jr .placeString
.notNickname
call PlaceString
ld l, c
ld h, b
ld de, NameTextString
.placeString
jp PlaceString
YourTextString:
db "YOUR @"
RivalsTextString:
db "RIVAL's @"
NameTextString:
db "NAME?@"
NicknameTextString:
db "NICKNAME?@"

28
engine/menus/oaks_pc.asm Executable file
View file

@ -0,0 +1,28 @@
OpenOaksPC:
call SaveScreenTilesToBuffer2
ld hl, AccessedOaksPCText
call PrintText
ld hl, GetDexRatedText
call PrintText
call YesNoChoice
ld a, [wCurrentMenuItem]
and a
jr nz, .closePC
predef DisplayDexRating
.closePC
ld hl, ClosedOaksPCText
call PrintText
jp LoadScreenTilesFromBuffer2
GetDexRatedText:
TX_FAR _GetDexRatedText
db "@"
ClosedOaksPCText:
TX_FAR _ClosedOaksPCText
TX_WAIT
db "@"
AccessedOaksPCText:
TX_FAR _AccessedOaksPCText
db "@"

325
engine/menus/party_menu.asm Executable file
View file

@ -0,0 +1,325 @@
; [wPartyMenuTypeOrMessageID] = menu type / message ID
; if less than $F0, it is a menu type
; menu types:
; 00: normal pokemon menu (e.g. Start menu)
; 01: use healing item on pokemon menu
; 02: in-battle switch pokemon menu
; 03: learn TM/HM menu
; 04: swap pokemon positions menu
; 05: use evolution stone on pokemon menu
; otherwise, it is a message ID
; f0: poison healed
; f1: burn healed
; f2: freeze healed
; f3: sleep healed
; f4: paralysis healed
; f5: HP healed
; f6: health returned
; f7: revitalized
; f8: leveled up
DrawPartyMenu_::
xor a
ld [H_AUTOBGTRANSFERENABLED], a
call ClearScreen
call UpdateSprites
callba LoadMonPartySpriteGfxWithLCDDisabled ; load pokemon icon graphics
RedrawPartyMenu_::
ld a, [wPartyMenuTypeOrMessageID]
cp SWAP_MONS_PARTY_MENU
jp z, .printMessage
call ErasePartyMenuCursors
callba InitPartyMenuBlkPacket
coord hl, 3, 0
ld de, wPartySpecies
xor a
ld c, a
ld [hPartyMonIndex], a
ld [wWhichPartyMenuHPBar], a
.loop
ld a, [de]
cp $FF ; reached the terminator?
jp z, .afterDrawingMonEntries
push bc
push de
push hl
ld a, c
push hl
ld hl, wPartyMonNicks
call GetPartyMonName
pop hl
call PlaceString ; print the pokemon's name
callba WriteMonPartySpriteOAMByPartyIndex ; place the appropriate pokemon icon
ld a, [hPartyMonIndex]
ld [wWhichPokemon], a
inc a
ld [hPartyMonIndex], a
call LoadMonData
pop hl
push hl
ld a, [wMenuItemToSwap]
and a ; is the player swapping pokemon positions?
jr z, .skipUnfilledRightArrow
; if the player is swapping pokemon positions
dec a
ld b, a
ld a, [wWhichPokemon]
cp b ; is the player swapping the current pokemon in the list?
jr nz, .skipUnfilledRightArrow
; the player is swapping the current pokemon in the list
dec hl
dec hl
dec hl
ld a, "▷" ; unfilled right arrow menu cursor
ld [hli], a ; place the cursor
inc hl
inc hl
.skipUnfilledRightArrow
ld a, [wPartyMenuTypeOrMessageID] ; menu type
cp TMHM_PARTY_MENU
jr z, .teachMoveMenu
cp EVO_STONE_PARTY_MENU
jr z, .evolutionStoneMenu
push hl
ld bc, 14 ; 14 columns to the right
add hl, bc
ld de, wLoadedMonStatus
call PrintStatusCondition
pop hl
push hl
ld bc, SCREEN_WIDTH + 1 ; down 1 row and right 1 column
ld a, [hFlags_0xFFF6]
set 0, a
ld [hFlags_0xFFF6], a
add hl, bc
predef DrawHP2 ; draw HP bar and prints current / max HP
ld a, [hFlags_0xFFF6]
res 0, a
ld [hFlags_0xFFF6], a
call SetPartyMenuHPBarColor ; color the HP bar (on SGB)
pop hl
jr .printLevel
.teachMoveMenu
push hl
predef CanLearnTM ; check if the pokemon can learn the move
pop hl
ld de, .ableToLearnMoveText
ld a, c
and a
jr nz, .placeMoveLearnabilityString
ld de, .notAbleToLearnMoveText
.placeMoveLearnabilityString
ld bc, 20 + 9 ; down 1 row and right 9 columns
push hl
add hl, bc
call PlaceString
pop hl
.printLevel
ld bc, 10 ; move 10 columns to the right
add hl, bc
call PrintLevel
pop hl
pop de
inc de
ld bc, 2 * 20
add hl, bc
pop bc
inc c
jp .loop
.ableToLearnMoveText
db "ABLE@"
.notAbleToLearnMoveText
db "NOT ABLE@"
.evolutionStoneMenu
push hl
ld hl, EvosMovesPointerTable
ld b, 0
ld a, [wLoadedMonSpecies]
dec a
add a
rl b
ld c, a
add hl, bc
ld de, wEvosMoves
ld a, BANK(EvosMovesPointerTable)
ld bc, 2
call FarCopyData
ld hl, wEvosMoves
ld a, [hli]
ld h, [hl]
ld l, a
ld de, wEvosMoves
ld a, BANK(EvosMovesPointerTable)
ld bc, wEvosMoves.end - wEvosMoves
call FarCopyData
ld hl, wEvosMoves
ld de, .notAbleToEvolveText
; loop through the pokemon's evolution entries
.checkEvolutionsLoop
ld a, [hli]
and a ; reached terminator?
jr z, .placeEvolutionStoneString ; if so, place the "NOT ABLE" string
inc hl
inc hl
cp EV_ITEM
jr nz, .checkEvolutionsLoop
; if it's a stone evolution entry
dec hl
dec hl
ld b, [hl]
ld a, [wEvoStoneItemID] ; the stone the player used
inc hl
inc hl
inc hl
cp b ; does the player's stone match this evolution entry's stone?
jr nz, .checkEvolutionsLoop
; if it does match
ld de, .ableToEvolveText
.placeEvolutionStoneString
ld bc, 20 + 9 ; down 1 row and right 9 columns
pop hl
push hl
add hl, bc
call PlaceString
pop hl
jr .printLevel
.ableToEvolveText
db "ABLE@"
.notAbleToEvolveText
db "NOT ABLE@"
.afterDrawingMonEntries
ld b, SET_PAL_PARTY_MENU
call RunPaletteCommand
.printMessage
ld hl, wd730
ld a, [hl]
push af
push hl
set 6, [hl] ; turn off letter printing delay
ld a, [wPartyMenuTypeOrMessageID] ; message ID
cp $F0
jr nc, .printItemUseMessage
add a
ld hl, PartyMenuMessagePointers
ld b, 0
ld c, a
add hl, bc
ld a, [hli]
ld h, [hl]
ld l, a
call PrintText
.done
pop hl
pop af
ld [hl], a
ld a, 1
ld [H_AUTOBGTRANSFERENABLED], a
call Delay3
jp GBPalNormal
.printItemUseMessage
and $0F
ld hl, PartyMenuItemUseMessagePointers
add a
ld c, a
ld b, 0
add hl, bc
ld a, [hli]
ld h, [hl]
ld l, a
push hl
ld a, [wUsedItemOnWhichPokemon]
ld hl, wPartyMonNicks
call GetPartyMonName
pop hl
call PrintText
jr .done
PartyMenuItemUseMessagePointers:
dw AntidoteText
dw BurnHealText
dw IceHealText
dw AwakeningText
dw ParlyzHealText
dw PotionText
dw FullHealText
dw ReviveText
dw RareCandyText
PartyMenuMessagePointers:
dw PartyMenuNormalText
dw PartyMenuItemUseText
dw PartyMenuBattleText
dw PartyMenuUseTMText
dw PartyMenuSwapMonText
dw PartyMenuItemUseText
PartyMenuNormalText:
TX_FAR _PartyMenuNormalText
db "@"
PartyMenuItemUseText:
TX_FAR _PartyMenuItemUseText
db "@"
PartyMenuBattleText:
TX_FAR _PartyMenuBattleText
db "@"
PartyMenuUseTMText:
TX_FAR _PartyMenuUseTMText
db "@"
PartyMenuSwapMonText:
TX_FAR _PartyMenuSwapMonText
db "@"
PotionText:
TX_FAR _PotionText
db "@"
AntidoteText:
TX_FAR _AntidoteText
db "@"
ParlyzHealText:
TX_FAR _ParlyzHealText
db "@"
BurnHealText:
TX_FAR _BurnHealText
db "@"
IceHealText:
TX_FAR _IceHealText
db "@"
AwakeningText:
TX_FAR _AwakeningText
db "@"
FullHealText:
TX_FAR _FullHealText
db "@"
ReviveText:
TX_FAR _ReviveText
db "@"
RareCandyText:
TX_FAR _RareCandyText
TX_SFX_ITEM_1 ; probably supposed to play SFX_LEVEL_UP but the wrong music bank is loaded
TX_BLINK
db "@"
SetPartyMenuHPBarColor:
ld hl, wPartyMenuHPBarColors
ld a, [wWhichPartyMenuHPBar]
ld c, a
ld b, 0
add hl, bc
call GetHealthBarColor
ld b, UPDATE_PARTY_MENU_BLK_PACKET
call RunPaletteCommand
ld hl, wWhichPartyMenuHPBar
inc [hl]
ret

141
engine/menus/pc.asm Executable file
View file

@ -0,0 +1,141 @@
ActivatePC::
call SaveScreenTilesToBuffer2
ld a, SFX_TURN_ON_PC
call PlaySound
ld hl, TurnedOnPC1Text
call PrintText
call WaitForSoundToFinish
ld hl, wFlags_0xcd60
set 3, [hl]
call LoadScreenTilesFromBuffer2
call Delay3
PCMainMenu:
callba DisplayPCMainMenu
ld hl, wFlags_0xcd60
set 5, [hl]
call HandleMenuInput
bit 1, a ;if player pressed B
jp nz, LogOff
ld a, [wMaxMenuItem]
cp 2
jr nz, .next ;if not 2 menu items (not counting log off) (2 occurs before you get the pokedex)
ld a, [wCurrentMenuItem]
and a
jp z, BillsPC ;if current menu item id is 0, it's bills pc
cp 1
jr z, .playersPC ;if current menu item id is 1, it's players pc
jp LogOff ;otherwise, it's 2, and you're logging off
.next
cp 3
jr nz, .next2 ;if not 3 menu items (not counting log off) (3 occurs after you get the pokedex, before you beat the pokemon league)
ld a, [wCurrentMenuItem]
and a
jp z, BillsPC ;if current menu item id is 0, it's bills pc
cp 1
jr z, .playersPC ;if current menu item id is 1, it's players pc
cp 2
jp z, OaksPC ;if current menu item id is 2, it's oaks pc
jp LogOff ;otherwise, it's 3, and you're logging off
.next2
ld a, [wCurrentMenuItem]
and a
jp z, BillsPC ;if current menu item id is 0, it's bills pc
cp 1
jr z, .playersPC ;if current menu item id is 1, it's players pc
cp 2
jp z, OaksPC ;if current menu item id is 2, it's oaks pc
cp 3
jp z, PKMNLeague ;if current menu item id is 3, it's pkmnleague
jp LogOff ;otherwise, it's 4, and you're logging off
.playersPC
ld hl, wFlags_0xcd60
res 5, [hl]
set 3, [hl]
ld a, SFX_ENTER_PC
call PlaySound
call WaitForSoundToFinish
ld hl, AccessedMyPCText
call PrintText
callba PlayerPC
jr ReloadMainMenu
OaksPC:
ld a, SFX_ENTER_PC
call PlaySound
call WaitForSoundToFinish
callba OpenOaksPC
jr ReloadMainMenu
PKMNLeague:
ld a, SFX_ENTER_PC
call PlaySound
call WaitForSoundToFinish
callba PKMNLeaguePC
jr ReloadMainMenu
BillsPC:
ld a, SFX_ENTER_PC
call PlaySound
call WaitForSoundToFinish
CheckEvent EVENT_MET_BILL
jr nz, .billsPC ;if you've met bill, use that bill's instead of someone's
ld hl, AccessedSomeonesPCText
jr .printText
.billsPC
ld hl, AccessedBillsPCText
.printText
call PrintText
callba BillsPC_
ReloadMainMenu:
xor a
ld [wDoNotWaitForButtonPressAfterDisplayingText], a
call ReloadMapData
call UpdateSprites
jp PCMainMenu
LogOff:
ld a, SFX_TURN_OFF_PC
call PlaySound
call WaitForSoundToFinish
ld hl, wFlags_0xcd60
res 3, [hl]
res 5, [hl]
ret
TurnedOnPC1Text:
TX_FAR _TurnedOnPC1Text
db "@"
AccessedBillsPCText:
TX_FAR _AccessedBillsPCText
db "@"
AccessedSomeonesPCText:
TX_FAR _AccessedSomeonesPCText
db "@"
AccessedMyPCText:
TX_FAR _AccessedMyPCText
db "@"
; removes one of the specified item ID [hItemToRemoveID] from bag (if existent)
RemoveItemByID::
ld hl, wBagItems
ld a, [hItemToRemoveID]
ld b, a
xor a
ld [hItemToRemoveIndex], a
.loop
ld a, [hli]
cp -1 ; reached terminator?
ret z
cp b
jr z, .foundItem
inc hl
ld a, [hItemToRemoveIndex]
inc a
ld [hItemToRemoveIndex], a
jr .loop
.foundItem
ld a, $1
ld [wItemQuantity], a
ld a, [hItemToRemoveIndex]
ld [wWhichPokemon], a
ld hl, wNumBagItems
jp RemoveItemFromInventory

303
engine/menus/players_pc.asm Executable file
View file

@ -0,0 +1,303 @@
PlayerPC::
ld hl, wd730
set 6, [hl]
ld a, ITEM_NAME
ld [wNameListType], a
call SaveScreenTilesToBuffer1
xor a
ld [wBagSavedMenuItem], a
ld [wParentMenuItem], a
ld a, [wFlags_0xcd60]
bit 3, a ; accessing player's PC through another PC?
jr nz, PlayerPCMenu
; accessing it directly
ld a, SFX_TURN_ON_PC
call PlaySound
ld hl, TurnedOnPC2Text
call PrintText
PlayerPCMenu:
ld a, [wParentMenuItem]
ld [wCurrentMenuItem], a
ld hl, wFlags_0xcd60
set 5, [hl]
call LoadScreenTilesFromBuffer2
coord hl, 0, 0
ld b, $8
ld c, $e
call TextBoxBorder
call UpdateSprites
coord hl, 2, 2
ld de, PlayersPCMenuEntries
call PlaceString
ld hl, wTopMenuItemY
ld a, 2
ld [hli], a ; wTopMenuItemY
dec a
ld [hli], a ; wTopMenuItemX
inc hl
inc hl
ld a, 3
ld [hli], a ; wMaxMenuItem
ld a, A_BUTTON | B_BUTTON
ld [hli], a ; wMenuWatchedKeys
xor a
ld [hl], a
ld hl, wListScrollOffset
ld [hli], a ; wListScrollOffset
ld [hl], a ; wMenuWatchMovingOutOfBounds
ld [wPlayerMonNumber], a
ld hl, WhatDoYouWantText
call PrintText
call HandleMenuInput
bit 1, a
jp nz, ExitPlayerPC
call PlaceUnfilledArrowMenuCursor
ld a, [wCurrentMenuItem]
ld [wParentMenuItem], a
and a
jp z, PlayerPCWithdraw
dec a
jp z, PlayerPCDeposit
dec a
jp z, PlayerPCToss
ExitPlayerPC:
ld a, [wFlags_0xcd60]
bit 3, a ; accessing player's PC through another PC?
jr nz, .next
; accessing it directly
ld a, SFX_TURN_OFF_PC
call PlaySound
call WaitForSoundToFinish
.next
ld hl, wFlags_0xcd60
res 5, [hl]
call LoadScreenTilesFromBuffer2
xor a
ld [wListScrollOffset], a
ld [wBagSavedMenuItem], a
ld hl, wd730
res 6, [hl]
xor a
ld [wDoNotWaitForButtonPressAfterDisplayingText], a
ret
PlayerPCDeposit:
xor a
ld [wCurrentMenuItem], a
ld [wListScrollOffset], a
ld a, [wNumBagItems]
and a
jr nz, .loop
ld hl, NothingToDepositText
call PrintText
jp PlayerPCMenu
.loop
ld hl, WhatToDepositText
call PrintText
ld hl, wNumBagItems
ld a, l
ld [wListPointer], a
ld a, h
ld [wListPointer + 1], a
xor a
ld [wPrintItemPrices], a
ld a, ITEMLISTMENU
ld [wListMenuID], a
call DisplayListMenuID
jp c, PlayerPCMenu
call IsKeyItem
ld a, 1
ld [wItemQuantity], a
ld a, [wIsKeyItem]
and a
jr nz, .next
; if it's not a key item, there can be more than one of the item
ld hl, DepositHowManyText
call PrintText
call DisplayChooseQuantityMenu
cp $ff
jp z, .loop
.next
ld hl, wNumBoxItems
call AddItemToInventory
jr c, .roomAvailable
ld hl, NoRoomToStoreText
call PrintText
jp .loop
.roomAvailable
ld hl, wNumBagItems
call RemoveItemFromInventory
call WaitForSoundToFinish
ld a, SFX_WITHDRAW_DEPOSIT
call PlaySound
call WaitForSoundToFinish
ld hl, ItemWasStoredText
call PrintText
jp .loop
PlayerPCWithdraw:
xor a
ld [wCurrentMenuItem], a
ld [wListScrollOffset], a
ld a, [wNumBoxItems]
and a
jr nz, .loop
ld hl, NothingStoredText
call PrintText
jp PlayerPCMenu
.loop
ld hl, WhatToWithdrawText
call PrintText
ld hl, wNumBoxItems
ld a, l
ld [wListPointer], a
ld a, h
ld [wListPointer + 1], a
xor a
ld [wPrintItemPrices], a
ld a, ITEMLISTMENU
ld [wListMenuID], a
call DisplayListMenuID
jp c, PlayerPCMenu
call IsKeyItem
ld a, 1
ld [wItemQuantity], a
ld a, [wIsKeyItem]
and a
jr nz, .next
; if it's not a key item, there can be more than one of the item
ld hl, WithdrawHowManyText
call PrintText
call DisplayChooseQuantityMenu
cp $ff
jp z, .loop
.next
ld hl, wNumBagItems
call AddItemToInventory
jr c, .roomAvailable
ld hl, CantCarryMoreText
call PrintText
jp .loop
.roomAvailable
ld hl, wNumBoxItems
call RemoveItemFromInventory
call WaitForSoundToFinish
ld a, SFX_WITHDRAW_DEPOSIT
call PlaySound
call WaitForSoundToFinish
ld hl, WithdrewItemText
call PrintText
jp .loop
PlayerPCToss:
xor a
ld [wCurrentMenuItem], a
ld [wListScrollOffset], a
ld a, [wNumBoxItems]
and a
jr nz, .loop
ld hl, NothingStoredText
call PrintText
jp PlayerPCMenu
.loop
ld hl, WhatToTossText
call PrintText
ld hl, wNumBoxItems
ld a, l
ld [wListPointer], a
ld a, h
ld [wListPointer + 1], a
xor a
ld [wPrintItemPrices], a
ld a, ITEMLISTMENU
ld [wListMenuID], a
push hl
call DisplayListMenuID
pop hl
jp c, PlayerPCMenu
push hl
call IsKeyItem
pop hl
ld a, 1
ld [wItemQuantity], a
ld a, [wIsKeyItem]
and a
jr nz, .next
ld a, [wcf91]
call IsItemHM
jr c, .next
; if it's not a key item, there can be more than one of the item
push hl
ld hl, TossHowManyText
call PrintText
call DisplayChooseQuantityMenu
pop hl
cp $ff
jp z, .loop
.next
call TossItem ; disallows tossing key items
jp .loop
PlayersPCMenuEntries:
db "WITHDRAW ITEM"
next "DEPOSIT ITEM"
next "TOSS ITEM"
next "LOG OFF@"
TurnedOnPC2Text:
TX_FAR _TurnedOnPC2Text
db "@"
WhatDoYouWantText:
TX_FAR _WhatDoYouWantText
db "@"
WhatToDepositText:
TX_FAR _WhatToDepositText
db "@"
DepositHowManyText:
TX_FAR _DepositHowManyText
db "@"
ItemWasStoredText:
TX_FAR _ItemWasStoredText
db "@"
NothingToDepositText:
TX_FAR _NothingToDepositText
db "@"
NoRoomToStoreText:
TX_FAR _NoRoomToStoreText
db "@"
WhatToWithdrawText:
TX_FAR _WhatToWithdrawText
db "@"
WithdrawHowManyText:
TX_FAR _WithdrawHowManyText
db "@"
WithdrewItemText:
TX_FAR _WithdrewItemText
db "@"
NothingStoredText:
TX_FAR _NothingStoredText
db "@"
CantCarryMoreText:
TX_FAR _CantCarryMoreText
db "@"
WhatToTossText:
TX_FAR _WhatToTossText
db "@"
TossHowManyText:
TX_FAR _TossHowManyText
db "@"

665
engine/menus/pokedex.asm Executable file
View file

@ -0,0 +1,665 @@
ShowPokedexMenu:
call GBPalWhiteOut
call ClearScreen
call UpdateSprites
ld a, [wListScrollOffset]
push af
xor a
ld [wCurrentMenuItem], a
ld [wListScrollOffset], a
ld [wLastMenuItem], a
inc a
ld [wd11e], a
ld [hJoy7], a
.setUpGraphics
ld b, SET_PAL_GENERIC
call RunPaletteCommand
callab LoadPokedexTilePatterns
.doPokemonListMenu
ld hl, wTopMenuItemY
ld a, 3
ld [hli], a ; top menu item Y
xor a
ld [hli], a ; top menu item X
inc a
ld [wMenuWatchMovingOutOfBounds], a
inc hl
inc hl
ld a, 6
ld [hli], a ; max menu item ID
ld [hl], D_LEFT | D_RIGHT | B_BUTTON | A_BUTTON
call HandlePokedexListMenu
jr c, .goToSideMenu ; if the player chose a pokemon from the list
.exitPokedex
xor a
ld [wMenuWatchMovingOutOfBounds], a
ld [wCurrentMenuItem], a
ld [wLastMenuItem], a
ld [hJoy7], a
ld [wWastedByteCD3A], a
ld [wOverrideSimulatedJoypadStatesMask], a
pop af
ld [wListScrollOffset], a
call GBPalWhiteOutWithDelay3
call RunDefaultPaletteCommand
jp ReloadMapData
.goToSideMenu
call HandlePokedexSideMenu
dec b
jr z, .exitPokedex ; if the player chose Quit
dec b
jr z, .doPokemonListMenu ; if pokemon not seen or player pressed B button
jp .setUpGraphics ; if pokemon data or area was shown
; handles the menu on the lower right in the pokedex screen
; OUTPUT:
; b = reason for exiting menu
; 00: showed pokemon data or area
; 01: the player chose Quit
; 02: the pokemon has not been seen yet or the player pressed the B button
HandlePokedexSideMenu:
call PlaceUnfilledArrowMenuCursor
ld a, [wCurrentMenuItem]
push af
ld b, a
ld a, [wLastMenuItem]
push af
ld a, [wListScrollOffset]
push af
add b
inc a
ld [wd11e], a
ld a, [wd11e]
push af
ld a, [wDexMaxSeenMon]
push af ; this doesn't need to be preserved
ld hl, wPokedexSeen
call IsPokemonBitSet
ld b, 2
jr z, .exitSideMenu
call PokedexToIndex
ld hl, wTopMenuItemY
ld a, 10
ld [hli], a ; top menu item Y
ld a, 15
ld [hli], a ; top menu item X
xor a
ld [hli], a ; current menu item ID
inc hl
ld a, 3
ld [hli], a ; max menu item ID
;ld a, A_BUTTON | B_BUTTON
ld [hli], a ; menu watched keys (A button and B button)
xor a
ld [hli], a ; old menu item ID
ld [wMenuWatchMovingOutOfBounds], a
.handleMenuInput
call HandleMenuInput
bit 1, a ; was the B button pressed?
ld b, 2
jr nz, .buttonBPressed
ld a, [wCurrentMenuItem]
and a
jr z, .choseData
dec a
jr z, .choseCry
dec a
jr z, .choseArea
.choseQuit
ld b, 1
.exitSideMenu
pop af
ld [wDexMaxSeenMon], a
pop af
ld [wd11e], a
pop af
ld [wListScrollOffset], a
pop af
ld [wLastMenuItem], a
pop af
ld [wCurrentMenuItem], a
push bc
coord hl, 0, 3
ld de, 20
lb bc, " ", 13
call DrawTileLine ; cover up the menu cursor in the pokemon list
pop bc
ret
.buttonBPressed
push bc
coord hl, 15, 10
ld de, 20
lb bc, " ", 7
call DrawTileLine ; cover up the menu cursor in the side menu
pop bc
jr .exitSideMenu
.choseData
call ShowPokedexDataInternal
ld b, 0
jr .exitSideMenu
; play pokemon cry
.choseCry
ld a, [wd11e]
call GetCryData
call PlaySound
jr .handleMenuInput
.choseArea
predef LoadTownMap_Nest ; display pokemon areas
ld b, 0
jr .exitSideMenu
; handles the list of pokemon on the left of the pokedex screen
; sets carry flag if player presses A, unsets carry flag if player presses B
HandlePokedexListMenu:
xor a
ld [H_AUTOBGTRANSFERENABLED], a
; draw the horizontal line separating the seen and owned amounts from the menu
coord hl, 15, 8
ld a, "─"
ld [hli], a
ld [hli], a
ld [hli], a
ld [hli], a
ld [hli], a
coord hl, 14, 0
ld [hl], $71 ; vertical line tile
coord hl, 14, 1
call DrawPokedexVerticalLine
coord hl, 14, 9
call DrawPokedexVerticalLine
ld hl, wPokedexSeen
ld b, wPokedexSeenEnd - wPokedexSeen
call CountSetBits
ld de, wNumSetBits
coord hl, 16, 3
lb bc, 1, 3
call PrintNumber ; print number of seen pokemon
ld hl, wPokedexOwned
ld b, wPokedexOwnedEnd - wPokedexOwned
call CountSetBits
ld de, wNumSetBits
coord hl, 16, 6
lb bc, 1, 3
call PrintNumber ; print number of owned pokemon
coord hl, 16, 2
ld de, PokedexSeenText
call PlaceString
coord hl, 16, 5
ld de, PokedexOwnText
call PlaceString
coord hl, 1, 1
ld de, PokedexContentsText
call PlaceString
coord hl, 16, 10
ld de, PokedexMenuItemsText
call PlaceString
; find the highest pokedex number among the pokemon the player has seen
ld hl, wPokedexSeenEnd - 1
ld b, (wPokedexSeenEnd - wPokedexSeen) * 8 + 1
.maxSeenPokemonLoop
ld a, [hld]
ld c, 8
.maxSeenPokemonInnerLoop
dec b
sla a
jr c, .storeMaxSeenPokemon
dec c
jr nz, .maxSeenPokemonInnerLoop
jr .maxSeenPokemonLoop
.storeMaxSeenPokemon
ld a, b
ld [wDexMaxSeenMon], a
.loop
xor a
ld [H_AUTOBGTRANSFERENABLED], a
coord hl, 4, 2
lb bc, 14, 10
call ClearScreenArea
coord hl, 1, 3
ld a, [wListScrollOffset]
ld [wd11e], a
ld d, 7
ld a, [wDexMaxSeenMon]
cp 7
jr nc, .printPokemonLoop
ld d, a
dec a
ld [wMaxMenuItem], a
; loop to print pokemon pokedex numbers and names
; if the player has owned the pokemon, it puts a pokeball beside the name
.printPokemonLoop
ld a, [wd11e]
inc a
ld [wd11e], a
push af
push de
push hl
ld de, -SCREEN_WIDTH
add hl, de
ld de, wd11e
lb bc, LEADING_ZEROES | 1, 3
call PrintNumber ; print the pokedex number
ld de, SCREEN_WIDTH
add hl, de
dec hl
push hl
ld hl, wPokedexOwned
call IsPokemonBitSet
pop hl
ld a, " "
jr z, .writeTile
ld a, $72 ; pokeball tile
.writeTile
ld [hl], a ; put a pokeball next to pokemon that the player has owned
push hl
ld hl, wPokedexSeen
call IsPokemonBitSet
jr nz, .getPokemonName ; if the player has seen the pokemon
ld de, .dashedLine ; print a dashed line in place of the name if the player hasn't seen the pokemon
jr .skipGettingName
.dashedLine ; for unseen pokemon in the list
db "----------@"
.getPokemonName
call PokedexToIndex
call GetMonName
.skipGettingName
pop hl
inc hl
call PlaceString
pop hl
ld bc, 2 * SCREEN_WIDTH
add hl, bc
pop de
pop af
ld [wd11e], a
dec d
jr nz, .printPokemonLoop
ld a, 01
ld [H_AUTOBGTRANSFERENABLED], a
call Delay3
call GBPalNormal
call HandleMenuInput
bit 1, a ; was the B button pressed?
jp nz, .buttonBPressed
.checkIfUpPressed
bit 6, a ; was Up pressed?
jr z, .checkIfDownPressed
.upPressed ; scroll up one row
ld a, [wListScrollOffset]
and a
jp z, .loop
dec a
ld [wListScrollOffset], a
jp .loop
.checkIfDownPressed
bit 7, a ; was Down pressed?
jr z, .checkIfRightPressed
.downPressed ; scroll down one row
ld a, [wDexMaxSeenMon]
cp 7
jp c, .loop ; can't if the list is shorter than 7
sub 7
ld b, a
ld a, [wListScrollOffset]
cp b
jp z, .loop
inc a
ld [wListScrollOffset], a
jp .loop
.checkIfRightPressed
bit 4, a ; was Right pressed?
jr z, .checkIfLeftPressed
.rightPressed ; scroll down 7 rows
ld a, [wDexMaxSeenMon]
cp 7
jp c, .loop ; can't if the list is shorter than 7
sub 6
ld b, a
ld a, [wListScrollOffset]
add 7
ld [wListScrollOffset], a
cp b
jp c, .loop
dec b
ld a, b
ld [wListScrollOffset], a
jp .loop
.checkIfLeftPressed ; scroll up 7 rows
bit 5, a ; was Left pressed?
jr z, .buttonAPressed
.leftPressed
ld a, [wListScrollOffset]
sub 7
ld [wListScrollOffset], a
jp nc, .loop
xor a
ld [wListScrollOffset], a
jp .loop
.buttonAPressed
scf
ret
.buttonBPressed
and a
ret
DrawPokedexVerticalLine:
ld c, 9 ; height of line
ld de, SCREEN_WIDTH
ld a, $71 ; vertical line tile
.loop
ld [hl], a
add hl, de
xor 1 ; toggle between vertical line tile and box tile
dec c
jr nz, .loop
ret
PokedexSeenText:
db "SEEN@"
PokedexOwnText:
db "OWN@"
PokedexContentsText:
db "CONTENTS@"
PokedexMenuItemsText:
db "DATA"
next "CRY"
next "AREA"
next "QUIT@"
; tests if a pokemon's bit is set in the seen or owned pokemon bit fields
; INPUT:
; [wd11e] = pokedex number
; hl = address of bit field
IsPokemonBitSet:
ld a, [wd11e]
dec a
ld c, a
ld b, FLAG_TEST
predef FlagActionPredef
ld a, c
and a
ret
; function to display pokedex data from outside the pokedex
ShowPokedexData:
call GBPalWhiteOutWithDelay3
call ClearScreen
call UpdateSprites
callab LoadPokedexTilePatterns ; load pokedex tiles
; function to display pokedex data from inside the pokedex
ShowPokedexDataInternal:
ld hl, wd72c
set 1, [hl]
ld a, $33 ; 3/7 volume
ld [rNR50], a
call GBPalWhiteOut ; zero all palettes
call ClearScreen
ld a, [wd11e] ; pokemon ID
ld [wcf91], a
push af
ld b, SET_PAL_POKEDEX
call RunPaletteCommand
pop af
ld [wd11e], a
ld a, [hTilesetType]
push af
xor a
ld [hTilesetType], a
coord hl, 0, 0
ld de, 1
lb bc, $64, SCREEN_WIDTH
call DrawTileLine ; draw top border
coord hl, 0, 17
ld b, $6f
call DrawTileLine ; draw bottom border
coord hl, 0, 1
ld de, 20
lb bc, $66, $10
call DrawTileLine ; draw left border
coord hl, 19, 1
ld b, $67
call DrawTileLine ; draw right border
ld a, $63 ; upper left corner tile
Coorda 0, 0
ld a, $65 ; upper right corner tile
Coorda 19, 0
ld a, $6c ; lower left corner tile
Coorda 0, 17
ld a, $6e ; lower right corner tile
Coorda 19, 17
coord hl, 0, 9
ld de, PokedexDataDividerLine
call PlaceString ; draw horizontal divider line
coord hl, 9, 6
ld de, HeightWeightText
call PlaceString
call GetMonName
coord hl, 9, 2
call PlaceString
ld hl, PokedexEntryPointers
ld a, [wd11e]
dec a
ld e, a
ld d, 0
add hl, de
add hl, de
ld a, [hli]
ld e, a
ld d, [hl] ; de = address of pokedex entry
coord hl, 9, 4
call PlaceString ; print species name
ld h, b
ld l, c
push de
ld a, [wd11e]
push af
call IndexToPokedex
coord hl, 2, 8
ld a, "№"
ld [hli], a
ld a, "⠄"
ld [hli], a
ld de, wd11e
lb bc, LEADING_ZEROES | 1, 3
call PrintNumber ; print pokedex number
ld hl, wPokedexOwned
call IsPokemonBitSet
pop af
ld [wd11e], a
ld a, [wcf91]
ld [wd0b5], a
pop de
push af
push bc
push de
push hl
call Delay3
call GBPalNormal
call GetMonHeader ; load pokemon picture location
coord hl, 1, 1
call LoadFlippedFrontSpriteByMonIndex ; draw pokemon picture
ld a, [wcf91]
call PlayCry ; play pokemon cry
pop hl
pop de
pop bc
pop af
ld a, c
and a
jp z, .waitForButtonPress ; if the pokemon has not been owned, don't print the height, weight, or description
inc de ; de = address of feet (height)
ld a, [de] ; reads feet, but a is overwritten without being used
coord hl, 12, 6
lb bc, 1, 2
call PrintNumber ; print feet (height)
ld a, $60 ; feet symbol tile (one tick)
ld [hl], a
inc de
inc de ; de = address of inches (height)
coord hl, 15, 6
lb bc, LEADING_ZEROES | 1, 2
call PrintNumber ; print inches (height)
ld a, $61 ; inches symbol tile (two ticks)
ld [hl], a
; now print the weight (note that weight is stored in tenths of pounds internally)
inc de
inc de
inc de ; de = address of upper byte of weight
push de
; put weight in big-endian order at hDexWeight
ld hl, hDexWeight
ld a, [hl] ; save existing value of [hDexWeight]
push af
ld a, [de] ; a = upper byte of weight
ld [hli], a ; store upper byte of weight in [hDexWeight]
ld a, [hl] ; save existing value of [hDexWeight + 1]
push af
dec de
ld a, [de] ; a = lower byte of weight
ld [hl], a ; store lower byte of weight in [hDexWeight + 1]
ld de, hDexWeight
coord hl, 11, 8
lb bc, 2, 5 ; 2 bytes, 5 digits
call PrintNumber ; print weight
coord hl, 14, 8
ld a, [hDexWeight + 1]
sub 10
ld a, [hDexWeight]
sbc 0
jr nc, .next
ld [hl], "0" ; if the weight is less than 10, put a 0 before the decimal point
.next
inc hl
ld a, [hli]
ld [hld], a ; make space for the decimal point by moving the last digit forward one tile
ld [hl], "⠄" ; decimal point tile
pop af
ld [hDexWeight + 1], a ; restore original value of [hDexWeight + 1]
pop af
ld [hDexWeight], a ; restore original value of [hDexWeight]
pop hl
inc hl ; hl = address of pokedex description text
coord bc, 1, 11
ld a, 2
ld [$fff4], a
call TextCommandProcessor ; print pokedex description text
xor a
ld [$fff4], a
.waitForButtonPress
call JoypadLowSensitivity
ld a, [hJoy5]
and A_BUTTON | B_BUTTON
jr z, .waitForButtonPress
pop af
ld [hTilesetType], a
call GBPalWhiteOut
call ClearScreen
call RunDefaultPaletteCommand
call LoadTextBoxTilePatterns
call GBPalNormal
ld hl, wd72c
res 1, [hl]
ld a, $77 ; max volume
ld [rNR50], a
ret
HeightWeightText:
db "HT ?",$60,"??",$61
next "WT ???lb@"
; XXX does anything point to this?
PokeText:
db "#@"
; horizontal line that divides the pokedex text description from the rest of the data
PokedexDataDividerLine:
db $68,$69,$6B,$69,$6B
db $69,$6B,$69,$6B,$6B
db $6B,$6B,$69,$6B,$69
db $6B,$69,$6B,$69,$6A
db "@"
; draws a line of tiles
; INPUT:
; b = tile ID
; c = number of tile ID's to write
; de = amount to destination address after each tile (1 for horizontal, 20 for vertical)
; hl = destination address
DrawTileLine:
push bc
push de
.loop
ld [hl], b
add hl, de
dec c
jr nz, .loop
pop de
pop bc
ret
INCLUDE "data/pokedex_entries.asm"
PokedexToIndex:
; converts the Pokédex number at wd11e to an index
push bc
push hl
ld a, [wd11e]
ld b, a
ld c, 0
ld hl, PokedexOrder
.loop ; go through the list until we find an entry with a matching dex number
inc c
ld a, [hli]
cp b
jr nz, .loop
ld a, c
ld [wd11e], a
pop hl
pop bc
ret
IndexToPokedex:
; converts the index number at wd11e to a Pokédex number
push bc
push hl
ld a, [wd11e]
dec a
ld hl, PokedexOrder
ld b, 0
ld c, a
add hl, bc
ld a, [hl]
ld [wd11e], a
pop hl
pop bc
ret
INCLUDE "data/pokedex_order.asm"

708
engine/menus/save.asm Executable file
View file

@ -0,0 +1,708 @@
LoadSAV:
;(if carry -> write
;"the file data is destroyed")
call ClearScreen
call LoadFontTilePatterns
call LoadTextBoxTilePatterns
call LoadSAV0
jr c, .badsum
call LoadSAV1
jr c, .badsum
call LoadSAV2
jr c, .badsum
ld a, $2 ; good checksum
jr .goodsum
.badsum
ld hl, wd730
push hl
set 6, [hl]
ld hl, FileDataDestroyedText
call PrintText
ld c, 100
call DelayFrames
pop hl
res 6, [hl]
ld a, $1 ; bad checksum
.goodsum
ld [wSaveFileStatus], a
ret
FileDataDestroyedText:
TX_FAR _FileDataDestroyedText
db "@"
LoadSAV0:
ld a, SRAM_ENABLE
ld [MBC1SRamEnable], a
ld a, $1
ld [MBC1SRamBankingMode], a
ld [MBC1SRamBank], a
ld hl, sPlayerName ; hero name located in SRAM
ld bc, sMainDataCheckSum - sPlayerName ; but here checks the full SAV
call SAVCheckSum
ld c, a
ld a, [sMainDataCheckSum] ; SAV's checksum
cp c
jp z, .checkSumsMatched
; If the computed checksum didn't match the saved on, try again.
ld hl, sPlayerName
ld bc, sMainDataCheckSum - sPlayerName
call SAVCheckSum
ld c, a
ld a, [sMainDataCheckSum] ; SAV's checksum
cp c
jp nz, SAVBadCheckSum
.checkSumsMatched
ld hl, sPlayerName
ld de, wPlayerName
ld bc, NAME_LENGTH
call CopyData
ld hl, sMainData
ld de, wMainDataStart
ld bc, wMainDataEnd - wMainDataStart
call CopyData
ld hl, wCurMapTileset
set 7, [hl]
ld hl, sSpriteData
ld de, wSpriteDataStart
ld bc, wSpriteDataEnd - wSpriteDataStart
call CopyData
ld a, [sTilesetType]
ld [hTilesetType], a
ld hl, sCurBoxData
ld de, wBoxDataStart
ld bc, wBoxDataEnd - wBoxDataStart
call CopyData
and a
jp SAVGoodChecksum
LoadSAV1:
ld a, SRAM_ENABLE
ld [MBC1SRamEnable], a
ld a, $1
ld [MBC1SRamBankingMode], a
ld [MBC1SRamBank], a
ld hl, sPlayerName ; hero name located in SRAM
ld bc, sMainDataCheckSum - sPlayerName ; but here checks the full SAV
call SAVCheckSum
ld c, a
ld a, [sMainDataCheckSum] ; SAV's checksum
cp c
jr nz, SAVBadCheckSum
ld hl, sCurBoxData
ld de, wBoxDataStart
ld bc, wBoxDataEnd - wBoxDataStart
call CopyData
and a
jp SAVGoodChecksum
LoadSAV2:
ld a, SRAM_ENABLE
ld [MBC1SRamEnable], a
ld a, $1
ld [MBC1SRamBankingMode], a
ld [MBC1SRamBank], a
ld hl, sPlayerName ; hero name located in SRAM
ld bc, sMainDataCheckSum - sPlayerName ; but here checks the full SAV
call SAVCheckSum
ld c, a
ld a, [sMainDataCheckSum] ; SAV's checksum
cp c
jp nz, SAVBadCheckSum
ld hl, sPartyData
ld de, wPartyDataStart
ld bc, wPartyDataEnd - wPartyDataStart
call CopyData
ld hl, sMainData
ld de, wPokedexOwned
ld bc, wPokedexSeenEnd - wPokedexOwned
call CopyData
and a
jp SAVGoodChecksum
SAVBadCheckSum:
scf
SAVGoodChecksum:
ld a, $0
ld [MBC1SRamBankingMode], a
ld [MBC1SRamEnable], a
ret
LoadSAVIgnoreBadCheckSum:
; unused function that loads save data and ignores bad checksums
call LoadSAV0
call LoadSAV1
jp LoadSAV2
SaveSAV:
callba PrintSaveScreenText
ld hl, WouldYouLikeToSaveText
call SaveSAVConfirm
and a ;|0 = Yes|1 = No|
ret nz
ld a, [wSaveFileStatus]
dec a
jr z, .save
call SAVCheckRandomID
jr z, .save
ld hl, OlderFileWillBeErasedText
call SaveSAVConfirm
and a
ret nz
.save
call SaveSAVtoSRAM
coord hl, 1, 13
lb bc, 4, 18
call ClearScreenArea
coord hl, 1, 14
ld de, NowSavingString
call PlaceString
ld c, 120
call DelayFrames
ld hl, GameSavedText
call PrintText
ld a, SFX_SAVE
call PlaySoundWaitForCurrent
call WaitForSoundToFinish
ld c, 30
jp DelayFrames
NowSavingString:
db "Now saving...@"
SaveSAVConfirm:
call PrintText
coord hl, 0, 7
lb bc, 8, 1
ld a, TWO_OPTION_MENU
ld [wTextBoxID], a
call DisplayTextBoxID ; yes/no menu
ld a, [wCurrentMenuItem]
ret
WouldYouLikeToSaveText:
TX_FAR _WouldYouLikeToSaveText
db "@"
GameSavedText:
TX_FAR _GameSavedText
db "@"
OlderFileWillBeErasedText:
TX_FAR _OlderFileWillBeErasedText
db "@"
SaveSAVtoSRAM0:
ld a, SRAM_ENABLE
ld [MBC1SRamEnable], a
ld a, $1
ld [MBC1SRamBankingMode], a
ld [MBC1SRamBank], a
ld hl, wPlayerName
ld de, sPlayerName
ld bc, NAME_LENGTH
call CopyData
ld hl, wMainDataStart
ld de, sMainData
ld bc, wMainDataEnd - wMainDataStart
call CopyData
ld hl, wSpriteDataStart
ld de, sSpriteData
ld bc, wSpriteDataEnd - wSpriteDataStart
call CopyData
ld hl, wBoxDataStart
ld de, sCurBoxData
ld bc, wBoxDataEnd - wBoxDataStart
call CopyData
ld a, [hTilesetType]
ld [sTilesetType], a
ld hl, sPlayerName
ld bc, sMainDataCheckSum - sPlayerName
call SAVCheckSum
ld [sMainDataCheckSum], a
xor a
ld [MBC1SRamBankingMode], a
ld [MBC1SRamEnable], a
ret
SaveSAVtoSRAM1:
; stored pokémon
ld a, SRAM_ENABLE
ld [MBC1SRamEnable], a
ld a, $1
ld [MBC1SRamBankingMode], a
ld [MBC1SRamBank], a
ld hl, wBoxDataStart
ld de, sCurBoxData
ld bc, wBoxDataEnd - wBoxDataStart
call CopyData
ld hl, sPlayerName
ld bc, sMainDataCheckSum - sPlayerName
call SAVCheckSum
ld [sMainDataCheckSum], a
xor a
ld [MBC1SRamBankingMode], a
ld [MBC1SRamEnable], a
ret
SaveSAVtoSRAM2:
ld a, SRAM_ENABLE
ld [MBC1SRamEnable], a
ld a, $1
ld [MBC1SRamBankingMode], a
ld [MBC1SRamBank], a
ld hl, wPartyDataStart
ld de, sPartyData
ld bc, wPartyDataEnd - wPartyDataStart
call CopyData
ld hl, wPokedexOwned ; pokédex only
ld de, sMainData
ld bc, wPokedexSeenEnd - wPokedexOwned
call CopyData
ld hl, sPlayerName
ld bc, sMainDataCheckSum - sPlayerName
call SAVCheckSum
ld [sMainDataCheckSum], a
xor a
ld [MBC1SRamBankingMode], a
ld [MBC1SRamEnable], a
ret
SaveSAVtoSRAM::
ld a, $2
ld [wSaveFileStatus], a
call SaveSAVtoSRAM0
call SaveSAVtoSRAM1
jp SaveSAVtoSRAM2
SAVCheckSum:
;Check Sum (result[1 byte] is complemented)
ld d, 0
.loop
ld a, [hli]
add d
ld d, a
dec bc
ld a, b
or c
jr nz, .loop
ld a, d
cpl
ret
CalcIndividualBoxCheckSums:
ld hl, sBox1 ; sBox7
ld de, sBank2IndividualBoxChecksums ; sBank3IndividualBoxChecksums
ld b, NUM_BOXES / 2
.loop
push bc
push de
ld bc, wBoxDataEnd - wBoxDataStart
call SAVCheckSum
pop de
ld [de], a
inc de
pop bc
dec b
jr nz, .loop
ret
GetBoxSRAMLocation:
; in: a = box num
; out: b = box SRAM bank, hl = pointer to start of box
ld hl, BoxSRAMPointerTable
ld a, [wCurrentBoxNum]
and $7f
cp NUM_BOXES / 2
ld b, 2
jr c, .next
inc b
sub NUM_BOXES / 2
.next
ld e, a
ld d, 0
add hl, de
add hl, de
ld a, [hli]
ld h, [hl]
ld l, a
ret
BoxSRAMPointerTable:
dw sBox1 ; sBox7
dw sBox2 ; sBox8
dw sBox3 ; sBox9
dw sBox4 ; sBox10
dw sBox5 ; sBox11
dw sBox6 ; sBox12
ChangeBox::
ld hl, WhenYouChangeBoxText
call PrintText
call YesNoChoice
ld a, [wCurrentMenuItem]
and a
ret nz ; return if No was chosen
ld hl, wCurrentBoxNum
bit 7, [hl] ; is it the first time player is changing the box?
call z, EmptyAllSRAMBoxes ; if so, empty all boxes in SRAM
call DisplayChangeBoxMenu
call UpdateSprites
ld hl, hFlags_0xFFF6
set 1, [hl]
call HandleMenuInput
ld hl, hFlags_0xFFF6
res 1, [hl]
bit 1, a ; pressed b
ret nz
call GetBoxSRAMLocation
ld e, l
ld d, h
ld hl, wBoxDataStart
call CopyBoxToOrFromSRAM ; copy old box from WRAM to SRAM
ld a, [wCurrentMenuItem]
set 7, a
ld [wCurrentBoxNum], a
call GetBoxSRAMLocation
ld de, wBoxDataStart
call CopyBoxToOrFromSRAM ; copy new box from SRAM to WRAM
ld hl, wMapTextPtr
ld de, wChangeBoxSavedMapTextPointer
ld a, [hli]
ld [de], a
inc de
ld a, [hl]
ld [de], a
call RestoreMapTextPointer
call SaveSAVtoSRAM
ld hl, wChangeBoxSavedMapTextPointer
call SetMapTextPointer
ld a, SFX_SAVE
call PlaySoundWaitForCurrent
call WaitForSoundToFinish
ret
WhenYouChangeBoxText:
TX_FAR _WhenYouChangeBoxText
db "@"
CopyBoxToOrFromSRAM:
; copy an entire box from hl to de with b as the SRAM bank
push hl
ld a, SRAM_ENABLE
ld [MBC1SRamEnable], a
ld a, $1
ld [MBC1SRamBankingMode], a
ld a, b
ld [MBC1SRamBank], a
ld bc, wBoxDataEnd - wBoxDataStart
call CopyData
pop hl
; mark the memory that the box was copied from as am empty box
xor a
ld [hli], a
dec a
ld [hl], a
ld hl, sBox1 ; sBox7
ld bc, sBank2AllBoxesChecksum - sBox1
call SAVCheckSum
ld [sBank2AllBoxesChecksum], a ; sBank3AllBoxesChecksum
call CalcIndividualBoxCheckSums
xor a
ld [MBC1SRamBankingMode], a
ld [MBC1SRamEnable], a
ret
DisplayChangeBoxMenu:
xor a
ld [H_AUTOBGTRANSFERENABLED], a
ld a, A_BUTTON | B_BUTTON
ld [wMenuWatchedKeys], a
ld a, 11
ld [wMaxMenuItem], a
ld a, 1
ld [wTopMenuItemY], a
ld a, 12
ld [wTopMenuItemX], a
xor a
ld [wMenuWatchMovingOutOfBounds], a
ld a, [wCurrentBoxNum]
and $7f
ld [wCurrentMenuItem], a
ld [wLastMenuItem], a
coord hl, 0, 0
ld b, 2
ld c, 9
call TextBoxBorder
ld hl, ChooseABoxText
call PrintText
coord hl, 11, 0
ld b, 12
ld c, 7
call TextBoxBorder
ld hl, hFlags_0xFFF6
set 2, [hl]
ld de, BoxNames
coord hl, 13, 1
call PlaceString
ld hl, hFlags_0xFFF6
res 2, [hl]
ld a, [wCurrentBoxNum]
and $7f
cp 9
jr c, .singleDigitBoxNum
sub 9
coord hl, 8, 2
ld [hl], "1"
add "0"
jr .next
.singleDigitBoxNum
add "1"
.next
Coorda 9, 2
coord hl, 1, 2
ld de, BoxNoText
call PlaceString
call GetMonCountsForAllBoxes
coord hl, 18, 1
ld de, wBoxMonCounts
ld bc, SCREEN_WIDTH
ld a, $c
.loop
push af
ld a, [de]
and a ; is the box empty?
jr z, .skipPlacingPokeball
ld [hl], $78 ; place pokeball tile next to box name if box not empty
.skipPlacingPokeball
add hl, bc
inc de
pop af
dec a
jr nz, .loop
ld a, 1
ld [H_AUTOBGTRANSFERENABLED], a
ret
ChooseABoxText:
TX_FAR _ChooseABoxText
db "@"
BoxNames:
db "BOX 1"
next "BOX 2"
next "BOX 3"
next "BOX 4"
next "BOX 5"
next "BOX 6"
next "BOX 7"
next "BOX 8"
next "BOX 9"
next "BOX10"
next "BOX11"
next "BOX12@"
BoxNoText:
db "BOX No.@"
EmptyAllSRAMBoxes:
; marks all boxes in SRAM as empty (initialisation for the first time the
; player changes the box)
ld a, SRAM_ENABLE
ld [MBC1SRamEnable], a
ld a, $1
ld [MBC1SRamBankingMode], a
ld a, 2
ld [MBC1SRamBank], a
call EmptySRAMBoxesInBank
ld a, 3
ld [MBC1SRamBank], a
call EmptySRAMBoxesInBank
xor a
ld [MBC1SRamBankingMode], a
ld [MBC1SRamEnable], a
ret
EmptySRAMBoxesInBank:
; marks every box in the current SRAM bank as empty
ld hl, sBox1 ; sBox7
call EmptySRAMBox
ld hl, sBox2 ; sBox8
call EmptySRAMBox
ld hl, sBox3 ; sBox9
call EmptySRAMBox
ld hl, sBox4 ; sBox10
call EmptySRAMBox
ld hl, sBox5 ; sBox11
call EmptySRAMBox
ld hl, sBox6 ; sBox12
call EmptySRAMBox
ld hl, sBox1 ; sBox7
ld bc, sBank2AllBoxesChecksum - sBox1
call SAVCheckSum
ld [sBank2AllBoxesChecksum], a ; sBank3AllBoxesChecksum
call CalcIndividualBoxCheckSums
ret
EmptySRAMBox:
xor a
ld [hli], a
dec a
ld [hl], a
ret
GetMonCountsForAllBoxes:
ld hl, wBoxMonCounts
push hl
ld a, SRAM_ENABLE
ld [MBC1SRamEnable], a
ld a, $1
ld [MBC1SRamBankingMode], a
ld a, $2
ld [MBC1SRamBank], a
call GetMonCountsForBoxesInBank
ld a, $3
ld [MBC1SRamBank], a
call GetMonCountsForBoxesInBank
xor a
ld [MBC1SRamBankingMode], a
ld [MBC1SRamEnable], a
pop hl
; copy the count for the current box from WRAM
ld a, [wCurrentBoxNum]
and $7f
ld c, a
ld b, 0
add hl, bc
ld a, [wNumInBox]
ld [hl], a
ret
GetMonCountsForBoxesInBank:
ld a, [sBox1] ; sBox7
ld [hli], a
ld a, [sBox2] ; sBox8
ld [hli], a
ld a, [sBox3] ; sBox9
ld [hli], a
ld a, [sBox4] ; sBox10
ld [hli], a
ld a, [sBox5] ; sBox11
ld [hli], a
ld a, [sBox6] ; sBox12
ld [hli], a
ret
SAVCheckRandomID:
;checks if Sav file is the same by checking player's name 1st letter ($a598)
; and the two random numbers generated at game beginning
;(which are stored at wPlayerID)s
ld a, $0a
ld [MBC1SRamEnable], a
ld a, $01
ld [MBC1SRamBankingMode], a
ld [MBC1SRamBank], a
ld a, [sPlayerName]
and a
jr z, .next
ld hl, sPlayerName
ld bc, sMainDataCheckSum - sPlayerName
call SAVCheckSum
ld c, a
ld a, [sMainDataCheckSum]
cp c
jr nz, .next
ld hl, sMainData + (wPlayerID - wMainDataStart) ; player ID
ld a, [hli]
ld h, [hl]
ld l, a
ld a, [wPlayerID]
cp l
jr nz, .next
ld a, [wPlayerID + 1]
cp h
.next
ld a, $00
ld [MBC1SRamBankingMode], a
ld [MBC1SRamEnable], a
ret
SaveHallOfFameTeams:
ld a, [wNumHoFTeams]
dec a
cp HOF_TEAM_CAPACITY
jr nc, .shiftHOFTeams
ld hl, sHallOfFame
ld bc, HOF_TEAM
call AddNTimes
ld e, l
ld d, h
ld hl, wHallOfFame
ld bc, HOF_TEAM
jr HallOfFame_Copy
.shiftHOFTeams
; if the space designated for HOF teams is full, then shift all HOF teams to the next slot, making space for the new HOF team
; this deletes the last HOF team though
ld hl, sHallOfFame + HOF_TEAM
ld de, sHallOfFame
ld bc, HOF_TEAM * (HOF_TEAM_CAPACITY - 1)
call HallOfFame_Copy
ld hl, wHallOfFame
ld de, sHallOfFame + HOF_TEAM * (HOF_TEAM_CAPACITY - 1)
ld bc, HOF_TEAM
jr HallOfFame_Copy
LoadHallOfFameTeams:
ld hl, sHallOfFame
ld bc, HOF_TEAM
ld a, [wHoFTeamIndex]
call AddNTimes
ld de, wHallOfFame
ld bc, HOF_TEAM
; fallthrough
HallOfFame_Copy:
ld a, SRAM_ENABLE
ld [MBC1SRamEnable], a
ld a, $1
ld [MBC1SRamBankingMode], a
xor a
ld [MBC1SRamBank], a
call CopyData
xor a
ld [MBC1SRamBankingMode], a
ld [MBC1SRamEnable], a
ret
ClearSAV:
ld a, SRAM_ENABLE
ld [MBC1SRamEnable], a
ld a, $1
ld [MBC1SRamBankingMode], a
xor a
call PadSRAM_FF
ld a, $1
call PadSRAM_FF
ld a, $2
call PadSRAM_FF
ld a, $3
call PadSRAM_FF
xor a
ld [MBC1SRamBankingMode], a
ld [MBC1SRamEnable], a
ret
PadSRAM_FF:
ld [MBC1SRamBank], a
ld hl, $a000
ld bc, $2000
ld a, $ff
jp FillMemory

808
engine/menus/start_sub_menus.asm Executable file
View file

@ -0,0 +1,808 @@
StartMenu_Pokedex::
predef ShowPokedexMenu
call LoadScreenTilesFromBuffer2 ; restore saved screen
call Delay3
call LoadGBPal
call UpdateSprites
jp RedisplayStartMenu
StartMenu_Pokemon::
ld a, [wPartyCount]
and a
jp z, RedisplayStartMenu
xor a
ld [wMenuItemToSwap], a
ld [wPartyMenuTypeOrMessageID], a
ld [wUpdateSpritesEnabled], a
call DisplayPartyMenu
jr .checkIfPokemonChosen
.loop
xor a
ld [wMenuItemToSwap], a
ld [wPartyMenuTypeOrMessageID], a
call GoBackToPartyMenu
.checkIfPokemonChosen
jr nc, .chosePokemon
.exitMenu
call GBPalWhiteOutWithDelay3
call RestoreScreenTilesAndReloadTilePatterns
call LoadGBPal
jp RedisplayStartMenu
.chosePokemon
call SaveScreenTilesToBuffer1
ld a, FIELD_MOVE_MON_MENU
ld [wTextBoxID], a
call DisplayTextBoxID ; display pokemon menu options
ld hl, wFieldMoves
lb bc, 2, 12 ; max menu item ID, top menu item Y
ld e, 5
.adjustMenuVariablesLoop
dec e
jr z, .storeMenuVariables
ld a, [hli]
and a ; end of field moves?
jr z, .storeMenuVariables
inc b
dec c
dec c
jr .adjustMenuVariablesLoop
.storeMenuVariables
ld hl, wTopMenuItemY
ld a, c
ld [hli], a ; top menu item Y
ld a, [hFieldMoveMonMenuTopMenuItemX]
ld [hli], a ; top menu item X
xor a
ld [hli], a ; current menu item ID
inc hl
ld a, b
ld [hli], a ; max menu item ID
ld a, A_BUTTON | B_BUTTON
ld [hli], a ; menu watched keys
xor a
ld [hl], a
call HandleMenuInput
push af
call LoadScreenTilesFromBuffer1 ; restore saved screen
pop af
bit 1, a ; was the B button pressed?
jp nz, .loop
; if the B button wasn't pressed
ld a, [wMaxMenuItem]
ld b, a
ld a, [wCurrentMenuItem] ; menu selection
cp b
jp z, .exitMenu ; if the player chose Cancel
dec b
cp b
jr z, .choseSwitch
dec b
cp b
jp z, .choseStats
ld c, a
ld b, 0
ld hl, wFieldMoves
add hl, bc
jp .choseOutOfBattleMove
.choseSwitch
ld a, [wPartyCount]
cp 2 ; is there more than one pokemon in the party?
jp c, StartMenu_Pokemon ; if not, no switching
call SwitchPartyMon_InitVarOrSwapData ; init [wMenuItemToSwap]
ld a, SWAP_MONS_PARTY_MENU
ld [wPartyMenuTypeOrMessageID], a
call GoBackToPartyMenu
jp .checkIfPokemonChosen
.choseStats
call ClearSprites
xor a ; PLAYER_PARTY_DATA
ld [wMonDataLocation], a
predef StatusScreen
predef StatusScreen2
call ReloadMapData
jp StartMenu_Pokemon
.choseOutOfBattleMove
push hl
ld a, [wWhichPokemon]
ld hl, wPartyMonNicks
call GetPartyMonName
pop hl
ld a, [hl]
dec a
add a
ld b, 0
ld c, a
ld hl, .outOfBattleMovePointers
add hl, bc
ld a, [hli]
ld h, [hl]
ld l, a
ld a, [wObtainedBadges] ; badges obtained
jp hl
.outOfBattleMovePointers
dw .cut
dw .fly
dw .surf
dw .surf
dw .strength
dw .flash
dw .dig
dw .teleport
dw .softboiled
.fly
bit 2, a ; does the player have the Thunder Badge?
jp z, .newBadgeRequired
call CheckIfInOutsideMap
jr z, .canFly
ld a, [wWhichPokemon]
ld hl, wPartyMonNicks
call GetPartyMonName
ld hl, .cannotFlyHereText
call PrintText
jp .loop
.canFly
call ChooseFlyDestination
ld a, [wd732]
bit 3, a ; did the player decide to fly?
jp nz, .goBackToMap
call LoadFontTilePatterns
ld hl, wd72e
set 1, [hl]
jp StartMenu_Pokemon
.cut
bit 1, a ; does the player have the Cascade Badge?
jp z, .newBadgeRequired
predef UsedCut
ld a, [wActionResultOrTookBattleTurn]
and a
jp z, .loop
jp CloseTextDisplay
.surf
bit 4, a ; does the player have the Soul Badge?
jp z, .newBadgeRequired
callba IsSurfingAllowed
ld hl, wd728
bit 1, [hl]
res 1, [hl]
jp z, .loop
ld a, SURFBOARD
ld [wcf91], a
ld [wPseudoItemID], a
call UseItem
ld a, [wActionResultOrTookBattleTurn]
and a
jp z, .loop
call GBPalWhiteOutWithDelay3
jp .goBackToMap
.strength
bit 3, a ; does the player have the Rainbow Badge?
jp z, .newBadgeRequired
predef PrintStrengthTxt
call GBPalWhiteOutWithDelay3
jp .goBackToMap
.flash
bit 0, a ; does the player have the Boulder Badge?
jp z, .newBadgeRequired
xor a
ld [wMapPalOffset], a
ld hl, .flashLightsAreaText
call PrintText
call GBPalWhiteOutWithDelay3
jp .goBackToMap
.flashLightsAreaText
TX_FAR _FlashLightsAreaText
db "@"
.dig
ld a, ESCAPE_ROPE
ld [wcf91], a
ld [wPseudoItemID], a
call UseItem
ld a, [wActionResultOrTookBattleTurn]
and a
jp z, .loop
call GBPalWhiteOutWithDelay3
jp .goBackToMap
.teleport
call CheckIfInOutsideMap
jr z, .canTeleport
ld a, [wWhichPokemon]
ld hl, wPartyMonNicks
call GetPartyMonName
ld hl, .cannotUseTeleportNowText
call PrintText
jp .loop
.canTeleport
ld hl, .warpToLastPokemonCenterText
call PrintText
ld hl, wd732
set 3, [hl]
set 6, [hl]
ld hl, wd72e
set 1, [hl]
res 4, [hl]
ld c, 60
call DelayFrames
call GBPalWhiteOutWithDelay3
jp .goBackToMap
.warpToLastPokemonCenterText
TX_FAR _WarpToLastPokemonCenterText
db "@"
.cannotUseTeleportNowText
TX_FAR _CannotUseTeleportNowText
db "@"
.cannotFlyHereText
TX_FAR _CannotFlyHereText
db "@"
.softboiled
ld hl, wPartyMon1MaxHP
ld a, [wWhichPokemon]
ld bc, wPartyMon2 - wPartyMon1
call AddNTimes
ld a, [hli]
ld [H_DIVIDEND], a
ld a, [hl]
ld [H_DIVIDEND + 1], a
ld a, 5
ld [H_DIVISOR], a
ld b, 2 ; number of bytes
call Divide
ld bc, wPartyMon1HP - wPartyMon1MaxHP
add hl, bc
ld a, [hld]
ld b, a
ld a, [H_QUOTIENT + 3]
sub b
ld b, [hl]
ld a, [H_QUOTIENT + 2]
sbc b
jp nc, .notHealthyEnough
ld a, [wPartyAndBillsPCSavedMenuItem]
push af
ld a, POTION
ld [wcf91], a
ld [wPseudoItemID], a
call UseItem
pop af
ld [wPartyAndBillsPCSavedMenuItem], a
jp .loop
.notHealthyEnough ; if current HP is less than 1/5 of max HP
ld hl, .notHealthyEnoughText
call PrintText
jp .loop
.notHealthyEnoughText
TX_FAR _NotHealthyEnoughText
db "@"
.goBackToMap
call RestoreScreenTilesAndReloadTilePatterns
jp CloseTextDisplay
.newBadgeRequired
ld hl, .newBadgeRequiredText
call PrintText
jp .loop
.newBadgeRequiredText
TX_FAR _NewBadgeRequiredText
db "@"
; writes a blank tile to all possible menu cursor positions on the party menu
ErasePartyMenuCursors::
coord hl, 0, 1
ld bc, 2 * 20 ; menu cursor positions are 2 rows apart
ld a, 6 ; 6 menu cursor positions
.loop
ld [hl], " "
add hl, bc
dec a
jr nz, .loop
ret
ItemMenuLoop:
call LoadScreenTilesFromBuffer2DisableBGTransfer ; restore saved screen
call RunDefaultPaletteCommand
StartMenu_Item::
ld a, [wLinkState]
dec a ; is the player in the Colosseum or Trade Centre?
jr nz, .notInCableClubRoom
ld hl, CannotUseItemsHereText
call PrintText
jr .exitMenu
.notInCableClubRoom
ld bc, wNumBagItems
ld hl, wListPointer
ld a, c
ld [hli], a
ld [hl], b ; store item bag pointer in wListPointer (for DisplayListMenuID)
xor a
ld [wPrintItemPrices], a
ld a, ITEMLISTMENU
ld [wListMenuID], a
ld a, [wBagSavedMenuItem]
ld [wCurrentMenuItem], a
call DisplayListMenuID
ld a, [wCurrentMenuItem]
ld [wBagSavedMenuItem], a
jr nc, .choseItem
.exitMenu
call LoadScreenTilesFromBuffer2 ; restore saved screen
call LoadTextBoxTilePatterns
call UpdateSprites
jp RedisplayStartMenu
.choseItem
; erase menu cursor (blank each tile in front of an item name)
ld a, " "
Coorda 5, 4
Coorda 5, 6
Coorda 5, 8
Coorda 5, 10
call PlaceUnfilledArrowMenuCursor
xor a
ld [wMenuItemToSwap], a
ld a, [wcf91]
cp BICYCLE
jp z, .useOrTossItem
.notBicycle1
ld a, USE_TOSS_MENU_TEMPLATE
ld [wTextBoxID], a
call DisplayTextBoxID
ld hl, wTopMenuItemY
ld a, 11
ld [hli], a ; top menu item Y
ld a, 14
ld [hli], a ; top menu item X
xor a
ld [hli], a ; current menu item ID
inc hl
inc a ; a = 1
ld [hli], a ; max menu item ID
ld a, A_BUTTON | B_BUTTON
ld [hli], a ; menu watched keys
xor a
ld [hl], a ; old menu item id
call HandleMenuInput
call PlaceUnfilledArrowMenuCursor
bit 1, a ; was the B button pressed?
jr z, .useOrTossItem
jp ItemMenuLoop
.useOrTossItem ; if the player made the choice to use or toss the item
ld a, [wcf91]
ld [wd11e], a
call GetItemName
call CopyStringToCF4B ; copy name to wcf4b
ld a, [wcf91]
cp BICYCLE
jr nz, .notBicycle2
ld a, [wd732]
bit 5, a
jr z, .useItem_closeMenu
ld hl, CannotGetOffHereText
call PrintText
jp ItemMenuLoop
.notBicycle2
ld a, [wCurrentMenuItem]
and a
jr nz, .tossItem
; use item
ld [wPseudoItemID], a ; a must be 0 due to above conditional jump
ld a, [wcf91]
cp HM_01
jr nc, .useItem_partyMenu
ld hl, UsableItems_CloseMenu
ld de, 1
call IsInArray
jr c, .useItem_closeMenu
ld a, [wcf91]
ld hl, UsableItems_PartyMenu
ld de, 1
call IsInArray
jr c, .useItem_partyMenu
call UseItem
jp ItemMenuLoop
.useItem_closeMenu
xor a
ld [wPseudoItemID], a
call UseItem
ld a, [wActionResultOrTookBattleTurn]
and a
jp z, ItemMenuLoop
jp CloseStartMenu
.useItem_partyMenu
ld a, [wUpdateSpritesEnabled]
push af
call UseItem
ld a, [wActionResultOrTookBattleTurn]
cp $02
jp z, .partyMenuNotDisplayed
call GBPalWhiteOutWithDelay3
call RestoreScreenTilesAndReloadTilePatterns
pop af
ld [wUpdateSpritesEnabled], a
jp StartMenu_Item
.partyMenuNotDisplayed
pop af
ld [wUpdateSpritesEnabled], a
jp ItemMenuLoop
.tossItem
call IsKeyItem
ld a, [wIsKeyItem]
and a
jr nz, .skipAskingQuantity
ld a, [wcf91]
call IsItemHM
jr c, .skipAskingQuantity
call DisplayChooseQuantityMenu
inc a
jr z, .tossZeroItems
.skipAskingQuantity
ld hl, wNumBagItems
call TossItem
.tossZeroItems
jp ItemMenuLoop
CannotUseItemsHereText:
TX_FAR _CannotUseItemsHereText
db "@"
CannotGetOffHereText:
TX_FAR _CannotGetOffHereText
db "@"
INCLUDE "data/party_items.asm"
INCLUDE "data/overworld_items.asm"
StartMenu_TrainerInfo::
call GBPalWhiteOut
call ClearScreen
call UpdateSprites
ld a, [hTilesetType]
push af
xor a
ld [hTilesetType], a
call DrawTrainerInfo
predef DrawBadges ; draw badges
ld b, SET_PAL_TRAINER_CARD
call RunPaletteCommand
call GBPalNormal
call WaitForTextScrollButtonPress ; wait for button press
call GBPalWhiteOut
call LoadFontTilePatterns
call LoadScreenTilesFromBuffer2 ; restore saved screen
call RunDefaultPaletteCommand
call ReloadMapData
call LoadGBPal
pop af
ld [hTilesetType], a
jp RedisplayStartMenu
; loads tile patterns and draws everything except for gym leader faces / badges
DrawTrainerInfo:
ld de, RedPicFront
lb bc, BANK(RedPicFront), $01
predef DisplayPicCenteredOrUpperRight
call DisableLCD
coord hl, 0, 2
ld a, " "
call TrainerInfo_DrawVerticalLine
coord hl, 1, 2
call TrainerInfo_DrawVerticalLine
ld hl, vChars2 + $70
ld de, vChars2
ld bc, $70 * 4
call CopyData
ld hl, TrainerInfoTextBoxTileGraphics ; trainer info text box tile patterns
ld de, vChars2 + $770
ld bc, $0080
push bc
call TrainerInfo_FarCopyData
ld hl, BlankLeaderNames
ld de, vChars2 + $600
ld bc, $0170
call TrainerInfo_FarCopyData
pop bc
ld hl, BadgeNumbersTileGraphics ; badge number tile patterns
ld de, vChars1 + $580
call TrainerInfo_FarCopyData
ld hl, GymLeaderFaceAndBadgeTileGraphics ; gym leader face and badge tile patterns
ld de, vChars2 + $200
ld bc, $0400
ld a, $03
call FarCopyData2
ld hl, TextBoxGraphics
ld de, $00d0
add hl, de ; hl = colon tile pattern
ld de, vChars1 + $560
ld bc, $0010
ld a, $04
push bc
call FarCopyData2
pop bc
ld hl, TrainerInfoTextBoxTileGraphics + $80 ; background tile pattern
ld de, vChars1 + $570
call TrainerInfo_FarCopyData
call EnableLCD
ld hl, wTrainerInfoTextBoxWidthPlus1
ld a, 18 + 1
ld [hli], a
dec a
ld [hli], a
ld [hl], 1
coord hl, 0, 0
call TrainerInfo_DrawTextBox
ld hl, wTrainerInfoTextBoxWidthPlus1
ld a, 16 + 1
ld [hli], a
dec a
ld [hli], a
ld [hl], 3
coord hl, 1, 10
call TrainerInfo_DrawTextBox
coord hl, 0, 10
ld a, $d7
call TrainerInfo_DrawVerticalLine
coord hl, 19, 10
call TrainerInfo_DrawVerticalLine
coord hl, 6, 9
ld de, TrainerInfo_BadgesText
call PlaceString
coord hl, 2, 2
ld de, TrainerInfo_NameMoneyTimeText
call PlaceString
coord hl, 7, 2
ld de, wPlayerName
call PlaceString
coord hl, 8, 4
ld de, wPlayerMoney
ld c, $e3
call PrintBCDNumber
coord hl, 9, 6
ld de, wPlayTimeHours ; hours
lb bc, LEFT_ALIGN | 1, 3
call PrintNumber
ld [hl], $d6 ; colon tile ID
inc hl
ld de, wPlayTimeMinutes ; minutes
lb bc, LEADING_ZEROES | 1, 2
jp PrintNumber
TrainerInfo_FarCopyData:
ld a, BANK(TrainerInfoTextBoxTileGraphics)
jp FarCopyData2
TrainerInfo_NameMoneyTimeText:
db "NAME/"
next "MONEY/"
next "TIME/@"
; $76 is a circle tile
TrainerInfo_BadgesText:
db $76,"BADGES",$76,"@"
; draws a text box on the trainer info screen
; height is always 6
; INPUT:
; hl = destination address
; [wTrainerInfoTextBoxWidthPlus1] = width
; [wTrainerInfoTextBoxWidth] = width - 1
; [wTrainerInfoTextBoxNextRowOffset] = distance from the end of a text box row to the start of the next
TrainerInfo_DrawTextBox:
ld a, $79 ; upper left corner tile ID
lb de, $7a, $7b ; top edge and upper right corner tile ID's
call TrainerInfo_DrawHorizontalEdge ; draw top edge
call TrainerInfo_NextTextBoxRow
ld a, [wTrainerInfoTextBoxWidthPlus1]
ld e, a
ld d, 0
ld c, 6 ; height of the text box
.loop
ld [hl], $7c ; left edge tile ID
add hl, de
ld [hl], $78 ; right edge tile ID
call TrainerInfo_NextTextBoxRow
dec c
jr nz, .loop
ld a, $7d ; lower left corner tile ID
lb de, $77, $7e ; bottom edge and lower right corner tile ID's
TrainerInfo_DrawHorizontalEdge:
ld [hli], a ; place left corner tile
ld a, [wTrainerInfoTextBoxWidth]
ld c, a
ld a, d
.loop
ld [hli], a ; place edge tile
dec c
jr nz, .loop
ld a, e
ld [hl], a ; place right corner tile
ret
TrainerInfo_NextTextBoxRow:
ld a, [wTrainerInfoTextBoxNextRowOffset] ; distance to the start of the next row
.loop
inc hl
dec a
jr nz, .loop
ret
; draws a vertical line
; INPUT:
; hl = address of top tile in the line
; a = tile ID
TrainerInfo_DrawVerticalLine:
ld de, SCREEN_WIDTH
ld c, 8
.loop
ld [hl], a
add hl, de
dec c
jr nz, .loop
ret
StartMenu_SaveReset::
ld a, [wd72e]
bit 6, a ; is the player using the link feature?
jp nz, Init
predef SaveSAV ; save the game
call LoadScreenTilesFromBuffer2 ; restore saved screen
jp HoldTextDisplayOpen
StartMenu_Option::
xor a
ld [H_AUTOBGTRANSFERENABLED], a
call ClearScreen
call UpdateSprites
callab DisplayOptionMenu
call LoadScreenTilesFromBuffer2 ; restore saved screen
call LoadTextBoxTilePatterns
call UpdateSprites
jp RedisplayStartMenu
SwitchPartyMon::
call SwitchPartyMon_InitVarOrSwapData ; swap data
ld a, [wSwappedMenuItem]
call SwitchPartyMon_ClearGfx
ld a, [wCurrentMenuItem]
call SwitchPartyMon_ClearGfx
jp RedrawPartyMenu_
SwitchPartyMon_ClearGfx:
push af
coord hl, 0, 0
ld bc, SCREEN_WIDTH * 2
call AddNTimes
ld c, SCREEN_WIDTH * 2
ld a, " "
.clearMonBGLoop ; clear the mon's row in the party menu
ld [hli], a
dec c
jr nz, .clearMonBGLoop
pop af
ld hl, wOAMBuffer
ld bc, $10
call AddNTimes
ld de, $4
ld c, e
.clearMonOAMLoop
ld [hl], $a0
add hl, de
dec c
jr nz, .clearMonOAMLoop
call WaitForSoundToFinish
ld a, SFX_SWAP
jp PlaySound
SwitchPartyMon_InitVarOrSwapData:
; This is used to initialise [wMenuItemToSwap] and to actually swap the data.
ld a, [wMenuItemToSwap]
and a ; has [wMenuItemToSwap] been initialised yet?
jr nz, .pickedMonsToSwap
; If not, initialise [wMenuItemToSwap] so that it matches the current mon.
ld a, [wWhichPokemon]
inc a ; [wMenuItemToSwap] counts from 1
ld [wMenuItemToSwap], a
ret
.pickedMonsToSwap
xor a
ld [wPartyMenuTypeOrMessageID], a
ld a, [wMenuItemToSwap]
dec a
ld b, a
ld a, [wCurrentMenuItem]
ld [wSwappedMenuItem], a
cp b ; swapping a mon with itself?
jr nz, .swappingDifferentMons
; can't swap a mon with itself
xor a
ld [wMenuItemToSwap], a
ld [wPartyMenuTypeOrMessageID], a
ret
.swappingDifferentMons
ld a, b
ld [wMenuItemToSwap], a
push hl
push de
ld hl, wPartySpecies
ld d, h
ld e, l
ld a, [wCurrentMenuItem]
add l
ld l, a
jr nc, .noCarry
inc h
.noCarry
ld a, [wMenuItemToSwap]
add e
ld e, a
jr nc, .noCarry2
inc d
.noCarry2
ld a, [hl]
ld [hSwapTemp], a
ld a, [de]
ld [hl], a
ld a, [hSwapTemp]
ld [de], a
ld hl, wPartyMons
ld bc, wPartyMon2 - wPartyMon1
ld a, [wCurrentMenuItem]
call AddNTimes
push hl
ld de, wSwitchPartyMonTempBuffer
ld bc, wPartyMon2 - wPartyMon1
call CopyData
ld hl, wPartyMons
ld bc, wPartyMon2 - wPartyMon1
ld a, [wMenuItemToSwap]
call AddNTimes
pop de
push hl
ld bc, wPartyMon2 - wPartyMon1
call CopyData
pop de
ld hl, wSwitchPartyMonTempBuffer
ld bc, wPartyMon2 - wPartyMon1
call CopyData
ld hl, wPartyMonOT
ld a, [wCurrentMenuItem]
call SkipFixedLengthTextEntries
push hl
ld de, wSwitchPartyMonTempBuffer
ld bc, NAME_LENGTH
call CopyData
ld hl, wPartyMonOT
ld a, [wMenuItemToSwap]
call SkipFixedLengthTextEntries
pop de
push hl
ld bc, NAME_LENGTH
call CopyData
pop de
ld hl, wSwitchPartyMonTempBuffer
ld bc, NAME_LENGTH
call CopyData
ld hl, wPartyMonNicks
ld a, [wCurrentMenuItem]
call SkipFixedLengthTextEntries
push hl
ld de, wSwitchPartyMonTempBuffer
ld bc, NAME_LENGTH
call CopyData
ld hl, wPartyMonNicks
ld a, [wMenuItemToSwap]
call SkipFixedLengthTextEntries
pop de
push hl
ld bc, NAME_LENGTH
call CopyData
pop de
ld hl, wSwitchPartyMonTempBuffer
ld bc, NAME_LENGTH
call CopyData
ld a, [wMenuItemToSwap]
ld [wSwappedMenuItem], a
xor a
ld [wMenuItemToSwap], a
ld [wPartyMenuTypeOrMessageID], a
pop de
pop hl
ret

149
engine/menus/swap_items.asm Normal file
View file

@ -0,0 +1,149 @@
HandleItemListSwapping::
ld a, [wListMenuID]
cp ITEMLISTMENU
jp nz, DisplayListMenuIDLoop ; only rearrange item list menus
push hl
ld hl, wListPointer
ld a, [hli]
ld h, [hl]
ld l, a
inc hl ; hl = beginning of list entries
ld a, [wCurrentMenuItem]
ld b, a
ld a, [wListScrollOffset]
add b
add a
ld c, a
ld b, 0
add hl, bc ; hl = address of currently selected item entry
ld a, [hl]
pop hl
inc a
jp z, DisplayListMenuIDLoop ; ignore attempts to swap the Cancel menu item
ld a, [wMenuItemToSwap] ; ID of item chosen for swapping (counts from 1)
and a ; has the first item to swap already been chosen?
jr nz, .swapItems
; if not, set the currently selected item as the first item
ld a, [wCurrentMenuItem]
inc a
ld b, a
ld a, [wListScrollOffset] ; index of top (visible) menu item within the list
add b
ld [wMenuItemToSwap], a ; ID of item chosen for swapping (counts from 1)
ld c, 20
call DelayFrames
jp DisplayListMenuIDLoop
.swapItems
ld a, [wCurrentMenuItem]
inc a
ld b, a
ld a, [wListScrollOffset]
add b
ld b, a
ld a, [wMenuItemToSwap] ; ID of item chosen for swapping (counts from 1)
cp b ; is the currently selected item the same as the first item to swap?
jp z, DisplayListMenuIDLoop ; ignore attempts to swap an item with itself
dec a
ld [wMenuItemToSwap], a ; ID of item chosen for swapping (counts from 1)
ld c, 20
call DelayFrames
push hl
push de
ld hl, wListPointer
ld a, [hli]
ld h, [hl]
ld l, a
inc hl ; hl = beginning of list entries
ld d, h
ld e, l ; de = beginning of list entries
ld a, [wCurrentMenuItem]
ld b, a
ld a, [wListScrollOffset]
add b
add a
ld c, a
ld b, 0
add hl, bc ; hl = address of currently selected item entry
ld a, [wMenuItemToSwap] ; ID of item chosen for swapping (counts from 1)
add a
add e
ld e, a
jr nc, .noCarry
inc d
.noCarry ; de = address of first item to swap
ld a, [de]
ld b, a
ld a, [hli]
cp b
jr z, .swapSameItemType
.swapDifferentItems
ld [$ff95], a ; [$ff95] = second item ID
ld a, [hld]
ld [$ff96], a ; [$ff96] = second item quantity
ld a, [de]
ld [hli], a ; put first item ID in second item slot
inc de
ld a, [de]
ld [hl], a ; put first item quantity in second item slot
ld a, [$ff96]
ld [de], a ; put second item quantity in first item slot
dec de
ld a, [$ff95]
ld [de], a ; put second item ID in first item slot
xor a
ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped
pop de
pop hl
jp DisplayListMenuIDLoop
.swapSameItemType
inc de
ld a, [hl]
ld b, a
ld a, [de]
add b ; a = sum of both item quantities
cp 100 ; is the sum too big for one item slot?
jr c, .combineItemSlots
; swap enough items from the first slot to max out the second slot if they can't be combined
sub 99
ld [de], a
ld a, 99
ld [hl], a
jr .done
.combineItemSlots
ld [hl], a ; put the sum in the second item slot
ld hl, wListPointer
ld a, [hli]
ld h, [hl]
ld l, a
dec [hl] ; decrease the number of items
ld a, [hl]
ld [wListCount], a ; update number of items variable
cp 1
jr nz, .skipSettingMaxMenuItemID
ld [wMaxMenuItem], a ; if the number of items is only one now, update the max menu item ID
.skipSettingMaxMenuItemID
dec de
ld h, d
ld l, e
inc hl
inc hl ; hl = address of item after first item to swap
.moveItemsUpLoop ; erase the first item slot and move up all the following item slots to fill the gap
ld a, [hli]
ld [de], a
inc de
inc a ; reached the $ff terminator?
jr z, .afterMovingItemsUp
ld a, [hli]
ld [de], a
inc de
jr .moveItemsUpLoop
.afterMovingItemsUp
xor a
ld [wListScrollOffset], a
ld [wCurrentMenuItem], a
.done
xor a
ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped
pop de
pop hl
jp DisplayListMenuIDLoop

767
engine/menus/text_box.asm Normal file
View file

@ -0,0 +1,767 @@
; function to draw various text boxes
DisplayTextBoxID_::
ld a, [wTextBoxID]
cp TWO_OPTION_MENU
jp z, DisplayTwoOptionMenu
ld c, a
ld hl, TextBoxFunctionTable
ld de, 3
call SearchTextBoxTable
jr c, .functionTableMatch
ld hl, TextBoxCoordTable
ld de, 5
call SearchTextBoxTable
jr c, .coordTableMatch
ld hl, TextBoxTextAndCoordTable
ld de, 9
call SearchTextBoxTable
jr c, .textAndCoordTableMatch
.done
ret
.functionTableMatch
ld a, [hli]
ld h, [hl]
ld l, a ; hl = address of function
ld de, .done
push de
jp hl ; jump to the function
.coordTableMatch
call GetTextBoxIDCoords
call GetAddressOfScreenCoords
call TextBoxBorder
ret
.textAndCoordTableMatch
call GetTextBoxIDCoords
push hl
call GetAddressOfScreenCoords
call TextBoxBorder
pop hl
call GetTextBoxIDText
ld a, [wd730]
push af
ld a, [wd730]
set 6, a ; no pauses between printing each letter
ld [wd730], a
call PlaceString
pop af
ld [wd730], a
call UpdateSprites
ret
; function to search a table terminated with $ff for a byte matching c in increments of de
; sets carry flag if a match is found and clears carry flag if not
SearchTextBoxTable:
dec de
.loop
ld a, [hli]
cp $ff
jr z, .notFound
cp c
jr z, .found
add hl, de
jr .loop
.found
scf
.notFound
ret
; function to load coordinates from the TextBoxCoordTable or the TextBoxTextAndCoordTable
; INPUT:
; hl = address of coordinates
; OUTPUT:
; b = height
; c = width
; d = row of upper left corner
; e = column of upper left corner
GetTextBoxIDCoords:
ld a, [hli] ; column of upper left corner
ld e, a
ld a, [hli] ; row of upper left corner
ld d, a
ld a, [hli] ; column of lower right corner
sub e
dec a
ld c, a ; c = width
ld a, [hli] ; row of lower right corner
sub d
dec a
ld b, a ; b = height
ret
; function to load a text address and text coordinates from the TextBoxTextAndCoordTable
GetTextBoxIDText:
ld a, [hli]
ld e, a
ld a, [hli]
ld d, a ; de = address of text
push de ; save text address
ld a, [hli]
ld e, a ; column of upper left corner of text
ld a, [hl]
ld d, a ; row of upper left corner of text
call GetAddressOfScreenCoords
pop de ; restore text address
ret
; function to point hl to the screen coordinates
; INPUT:
; d = row
; e = column
; OUTPUT:
; hl = address of upper left corner of text box
GetAddressOfScreenCoords:
push bc
coord hl, 0, 0
ld bc, 20
.loop ; loop to add d rows to the base address
ld a, d
and a
jr z, .addedRows
add hl, bc
dec d
jr .loop
.addedRows
pop bc
add hl, de
ret
; Format:
; 00: text box ID
; 01-02: function address
TextBoxFunctionTable:
dbw MONEY_BOX, DisplayMoneyBox
dbw BUY_SELL_QUIT_MENU, DoBuySellQuitMenu
dbw FIELD_MOVE_MON_MENU, DisplayFieldMoveMonMenu
db $ff ; terminator
; Format:
; 00: text box ID
; 01: column of upper left corner
; 02: row of upper left corner
; 03: column of lower right corner
; 04: row of lower right corner
TextBoxCoordTable:
db MESSAGE_BOX, 0, 12, 19, 17
db $03, 0, 0, 19, 14
db $07, 0, 0, 11, 6
db LIST_MENU_BOX, 4, 2, 19, 12
db $10, 7, 0, 19, 17
db MON_SPRITE_POPUP, 6, 4, 14, 13
db $ff ; terminator
; Format:
; 00: text box ID
; 01: column of upper left corner
; 02: row of upper left corner
; 03: column of lower right corner
; 04: row of lower right corner
; 05-06: address of text
; 07: column of beginning of text
; 08: row of beginning of text
; table of window positions and corresponding text [key, start column, start row, end column, end row, text pointer [2 bytes], text column, text row]
TextBoxTextAndCoordTable:
db JP_MOCHIMONO_MENU_TEMPLATE
db 0,0,14,17 ; text box coordinates
dw JapaneseMochimonoText
db 3,0 ; text coordinates
db USE_TOSS_MENU_TEMPLATE
db 13,10,19,14 ; text box coordinates
dw UseTossText
db 15,11 ; text coordinates
db JP_SAVE_MESSAGE_MENU_TEMPLATE
db 0,0,7,5 ; text box coordinates
dw JapaneseSaveMessageText
db 2,2 ; text coordinates
db JP_SPEED_OPTIONS_MENU_TEMPLATE
db 0,6,5,10 ; text box coordinates
dw JapaneseSpeedOptionsText
db 2,7 ; text coordinates
db BATTLE_MENU_TEMPLATE
db 8,12,19,17 ; text box coordinates
dw BattleMenuText
db 10,14 ; text coordinates
db SAFARI_BATTLE_MENU_TEMPLATE
db 0,12,19,17 ; text box coordinates
dw SafariZoneBattleMenuText
db 2,14 ; text coordinates
db SWITCH_STATS_CANCEL_MENU_TEMPLATE
db 11,11,19,17 ; text box coordinates
dw SwitchStatsCancelText
db 13,12 ; text coordinates
db BUY_SELL_QUIT_MENU_TEMPLATE
db 0,0,10,6 ; text box coordinates
dw BuySellQuitText
db 2,1 ; text coordinates
db MONEY_BOX_TEMPLATE
db 11,0,19,2 ; text box coordinates
dw MoneyText
db 13,0 ; text coordinates
db JP_AH_MENU_TEMPLATE
db 7,6,11,10 ; text box coordinates
dw JapaneseAhText
db 8,8 ; text coordinates
db JP_POKEDEX_MENU_TEMPLATE
db 11,8,19,17 ; text box coordinates
dw JapanesePokedexMenu
db 12,10 ; text coordinates
; note that there is no terminator
BuySellQuitText:
db "BUY"
next "SELL"
next "QUIT@@"
UseTossText:
db "USE"
next "TOSS@"
JapaneseSaveMessageText:
db "きろく"
next "メッセージ@"
JapaneseSpeedOptionsText:
db "はやい"
next "おそい@"
MoneyText:
db "MONEY@"
JapaneseMochimonoText:
db "もちもの@"
JapaneseMainMenuText:
db "つづきから"
next "さいしょから@"
BattleMenuText:
db "FIGHT ",$E1,$E2
next "ITEM RUN@"
SafariZoneBattleMenuText:
db "BALL× BAIT"
next "THROW ROCK RUN@"
SwitchStatsCancelText:
db "SWITCH"
next "STATS"
next "CANCEL@"
JapaneseAhText:
db "アッ!@"
JapanesePokedexMenu:
db "データをみる"
next "なきごえ"
next "ぶんぷをみる"
next "キャンセル@"
DisplayMoneyBox:
ld hl, wd730
set 6, [hl]
ld a, MONEY_BOX_TEMPLATE
ld [wTextBoxID], a
call DisplayTextBoxID
coord hl, 13, 1
ld b, 1
ld c, 6
call ClearScreenArea
coord hl, 12, 1
ld de, wPlayerMoney
ld c, $a3
call PrintBCDNumber
ld hl, wd730
res 6, [hl]
ret
CurrencyString:
db " ¥@"
DoBuySellQuitMenu:
ld a, [wd730]
set 6, a ; no printing delay
ld [wd730], a
xor a
ld [wChosenMenuItem], a
ld a, BUY_SELL_QUIT_MENU_TEMPLATE
ld [wTextBoxID], a
call DisplayTextBoxID
ld a, A_BUTTON | B_BUTTON
ld [wMenuWatchedKeys], a
ld a, $2
ld [wMaxMenuItem], a
ld a, $1
ld [wTopMenuItemY], a
ld a, $1
ld [wTopMenuItemX], a
xor a
ld [wCurrentMenuItem], a
ld [wLastMenuItem], a
ld [wMenuWatchMovingOutOfBounds], a
ld a, [wd730]
res 6, a ; turn on the printing delay
ld [wd730], a
call HandleMenuInput
call PlaceUnfilledArrowMenuCursor
bit 0, a ; was A pressed?
jr nz, .pressedA
bit 1, a ; was B pressed? (always true since only A/B are watched)
jr z, .pressedA
ld a, CANCELLED_MENU
ld [wMenuExitMethod], a
jr .quit
.pressedA
ld a, CHOSE_MENU_ITEM
ld [wMenuExitMethod], a
ld a, [wCurrentMenuItem]
ld [wChosenMenuItem], a
ld b, a
ld a, [wMaxMenuItem]
cp b
jr z, .quit
ret
.quit
ld a, CANCELLED_MENU
ld [wMenuExitMethod], a
ld a, [wCurrentMenuItem]
ld [wChosenMenuItem], a
scf
ret
; displays a menu with two options to choose from
; b = Y of upper left corner of text region
; c = X of upper left corner of text region
; hl = address where the text box border should be drawn
DisplayTwoOptionMenu:
push hl
ld a, [wd730]
set 6, a ; no printing delay
ld [wd730], a
; pointless because both values are overwritten before they are read
xor a
ld [wChosenMenuItem], a
ld [wMenuExitMethod], a
ld a, A_BUTTON | B_BUTTON
ld [wMenuWatchedKeys], a
ld a, $1
ld [wMaxMenuItem], a
ld a, b
ld [wTopMenuItemY], a
ld a, c
ld [wTopMenuItemX], a
xor a
ld [wLastMenuItem], a
ld [wMenuWatchMovingOutOfBounds], a
push hl
ld hl, wTwoOptionMenuID
bit 7, [hl] ; select second menu item by default?
res 7, [hl]
jr z, .storeCurrentMenuItem
inc a
.storeCurrentMenuItem
ld [wCurrentMenuItem], a
pop hl
push hl
push hl
call TwoOptionMenu_SaveScreenTiles
ld a, [wTwoOptionMenuID]
ld hl, TwoOptionMenuStrings
ld e, a
ld d, $0
ld a, $5
.menuStringLoop
add hl, de
dec a
jr nz, .menuStringLoop
ld a, [hli]
ld c, a
ld a, [hli]
ld b, a
ld e, l
ld d, h
pop hl
push de
ld a, [wTwoOptionMenuID]
cp TRADE_CANCEL_MENU
jr nz, .notTradeCancelMenu
call CableClub_TextBoxBorder
jr .afterTextBoxBorder
.notTradeCancelMenu
call TextBoxBorder
.afterTextBoxBorder
call UpdateSprites
pop hl
ld a, [hli]
and a ; put blank line before first menu item?
ld bc, 20 + 2
jr z, .noBlankLine
ld bc, 2 * 20 + 2
.noBlankLine
ld a, [hli]
ld e, a
ld a, [hli]
ld d, a
pop hl
add hl, bc
call PlaceString
ld hl, wd730
res 6, [hl] ; turn on the printing delay
ld a, [wTwoOptionMenuID]
cp NO_YES_MENU
jr nz, .notNoYesMenu
; No/Yes menu
; this menu type ignores the B button
; it only seems to be used when confirming the deletion of a save file
xor a
ld [wTwoOptionMenuID], a
ld a, [wFlags_0xcd60]
push af
push hl
ld hl, wFlags_0xcd60
bit 5, [hl]
set 5, [hl] ; don't play sound when A or B is pressed in menu
pop hl
.noYesMenuInputLoop
call HandleMenuInput
bit 1, a ; A button pressed?
jr nz, .noYesMenuInputLoop ; try again if A was not pressed
pop af
pop hl
ld [wFlags_0xcd60], a
ld a, SFX_PRESS_AB
call PlaySound
jr .pressedAButton
.notNoYesMenu
xor a
ld [wTwoOptionMenuID], a
call HandleMenuInput
pop hl
bit 1, a ; A button pressed?
jr nz, .choseSecondMenuItem ; automatically choose the second option if B is pressed
.pressedAButton
ld a, [wCurrentMenuItem]
ld [wChosenMenuItem], a
and a
jr nz, .choseSecondMenuItem
; chose first menu item
ld a, CHOSE_FIRST_ITEM
ld [wMenuExitMethod], a
ld c, 15
call DelayFrames
call TwoOptionMenu_RestoreScreenTiles
and a
ret
.choseSecondMenuItem
ld a, 1
ld [wCurrentMenuItem], a
ld [wChosenMenuItem], a
ld a, CHOSE_SECOND_ITEM
ld [wMenuExitMethod], a
ld c, 15
call DelayFrames
call TwoOptionMenu_RestoreScreenTiles
scf
ret
; Some of the wider/taller two option menus will not have the screen areas
; they cover be fully saved/restored by the two functions below.
; The bottom and right edges of the menu may remain after the function returns.
TwoOptionMenu_SaveScreenTiles:
ld de, wBuffer
lb bc, 5, 6
.loop
ld a, [hli]
ld [de], a
inc de
dec c
jr nz, .loop
push bc
ld bc, SCREEN_WIDTH - 6
add hl, bc
pop bc
ld c, $6
dec b
jr nz, .loop
ret
TwoOptionMenu_RestoreScreenTiles:
ld de, wBuffer
lb bc, 5, 6
.loop
ld a, [de]
inc de
ld [hli], a
dec c
jr nz, .loop
push bc
ld bc, SCREEN_WIDTH - 6
add hl, bc
pop bc
ld c, 6
dec b
jr nz, .loop
call UpdateSprites
ret
; Format:
; 00: byte width
; 01: byte height
; 02: byte put blank line before first menu item
; 03: word text pointer
TwoOptionMenuStrings:
db 4,3,0
dw .YesNoMenu
db 6,3,0
dw .NorthWestMenu
db 6,3,0
dw .SouthEastMenu
db 6,3,0
dw .YesNoMenu
db 6,3,0
dw .NorthEastMenu
db 7,3,0
dw .TradeCancelMenu
db 7,4,1
dw .HealCancelMenu
db 4,3,0
dw .NoYesMenu
.NoYesMenu
db "NO"
next "YES@"
.YesNoMenu
db "YES"
next "NO@"
.NorthWestMenu
db "NORTH"
next "WEST@"
.SouthEastMenu
db "SOUTH"
next "EAST@"
.NorthEastMenu
db "NORTH"
next "EAST@"
.TradeCancelMenu
db "TRADE"
next "CANCEL@"
.HealCancelMenu
db "HEAL"
next "CANCEL@"
DisplayFieldMoveMonMenu:
xor a
ld hl, wFieldMoves
ld [hli], a ; wFieldMoves
ld [hli], a ; wFieldMoves + 1
ld [hli], a ; wFieldMoves + 2
ld [hli], a ; wFieldMoves + 3
ld [hli], a ; wNumFieldMoves
ld [hl], 12 ; wFieldMovesLeftmostXCoord
call GetMonFieldMoves
ld a, [wNumFieldMoves]
and a
jr nz, .fieldMovesExist
; no field moves
coord hl, 11, 11
ld b, 5
ld c, 7
call TextBoxBorder
call UpdateSprites
ld a, 12
ld [hFieldMoveMonMenuTopMenuItemX], a
coord hl, 13, 12
ld de, PokemonMenuEntries
jp PlaceString
.fieldMovesExist
push af
; Calculate the text box position and dimensions based on the leftmost X coord
; of the field move names before adjusting for the number of field moves.
coord hl, 0, 11
ld a, [wFieldMovesLeftmostXCoord]
dec a
ld e, a
ld d, 0
add hl, de
ld b, 5
ld a, 18
sub e
ld c, a
pop af
; For each field move, move the top of the text box up 2 rows while the leaving
; the bottom of the text box at the bottom of the screen.
ld de, -SCREEN_WIDTH * 2
.textBoxHeightLoop
add hl, de
inc b
inc b
dec a
jr nz, .textBoxHeightLoop
; Make space for an extra blank row above the top field move.
ld de, -SCREEN_WIDTH
add hl, de
inc b
call TextBoxBorder
call UpdateSprites
; Calculate the position of the first field move name to print.
coord hl, 0, 12
ld a, [wFieldMovesLeftmostXCoord]
inc a
ld e, a
ld d, 0
add hl, de
ld de, -SCREEN_WIDTH * 2
ld a, [wNumFieldMoves]
.calcFirstFieldMoveYLoop
add hl, de
dec a
jr nz, .calcFirstFieldMoveYLoop
xor a
ld [wNumFieldMoves], a
ld de, wFieldMoves
.printNamesLoop
push hl
ld hl, FieldMoveNames
ld a, [de]
and a
jr z, .donePrintingNames
inc de
ld b, a ; index of name
.skipNamesLoop ; skip past names before the name we want
dec b
jr z, .reachedName
.skipNameLoop ; skip past current name
ld a, [hli]
cp "@"
jr nz, .skipNameLoop
jr .skipNamesLoop
.reachedName
ld b, h
ld c, l
pop hl
push de
ld d, b
ld e, c
call PlaceString
ld bc, SCREEN_WIDTH * 2
add hl, bc
pop de
jr .printNamesLoop
.donePrintingNames
pop hl
ld a, [wFieldMovesLeftmostXCoord]
ld [hFieldMoveMonMenuTopMenuItemX], a
coord hl, 0, 12
ld a, [wFieldMovesLeftmostXCoord]
inc a
ld e, a
ld d, 0
add hl, de
ld de, PokemonMenuEntries
jp PlaceString
FieldMoveNames:
db "CUT@"
db "FLY@"
db "@"
db "SURF@"
db "STRENGTH@"
db "FLASH@"
db "DIG@"
db "TELEPORT@"
db "SOFTBOILED@"
PokemonMenuEntries:
db "STATS"
next "SWITCH"
next "CANCEL@"
GetMonFieldMoves:
ld a, [wWhichPokemon]
ld hl, wPartyMon1Moves
ld bc, wPartyMon2 - wPartyMon1
call AddNTimes
ld d, h
ld e, l
ld c, NUM_MOVES + 1
ld hl, wFieldMoves
.loop
push hl
.nextMove
dec c
jr z, .done
ld a, [de] ; move ID
and a
jr z, .done
ld b, a
inc de
ld hl, FieldMoveDisplayData
.fieldMoveLoop
ld a, [hli]
cp $ff
jr z, .nextMove ; if the move is not a field move
cp b
jr z, .foundFieldMove
inc hl
inc hl
jr .fieldMoveLoop
.foundFieldMove
ld a, b
ld [wLastFieldMoveID], a
ld a, [hli] ; field move name index
ld b, [hl] ; field move leftmost X coordinate
pop hl
ld [hli], a ; store name index in wFieldMoves
ld a, [wNumFieldMoves]
inc a
ld [wNumFieldMoves], a
ld a, [wFieldMovesLeftmostXCoord]
cp b
jr c, .skipUpdatingLeftmostXCoord
ld a, b
ld [wFieldMovesLeftmostXCoord], a
.skipUpdatingLeftmostXCoord
ld a, [wLastFieldMoveID]
ld b, a
jr .loop
.done
pop hl
ret
; Format: [Move id], [name index], [leftmost tile]
; Move id = id of move
; Name index = index of name in FieldMoveNames
; Leftmost tile = -1 + tile column in which the first letter of the move's name should be displayed
; "SOFTBOILED" is $08 because it has 4 more letters than "SURF", for example, whose value is $0C
FieldMoveDisplayData:
db CUT, $01, $0C
db FLY, $02, $0C
db $B4, $03, $0C ; unused field move
db SURF, $04, $0C
db STRENGTH, $05, $0A
db FLASH, $06, $0C
db DIG, $07, $0C
db TELEPORT, $08, $0A
db SOFTBOILED, $09, $08
db $ff ; list terminator