This commit is contained in:
dannye 2021-03-23 00:53:43 -05:00
commit e8dd755e18
3702 changed files with 163333 additions and 159040 deletions

View file

@ -0,0 +1,79 @@
; function that performs initialization for DisplayTextID
DisplayTextIDInit::
xor a
ld [wListMenuID], a
ld a, [wAutoTextBoxDrawingControl]
bit 0, a
jr nz, .skipDrawingTextBoxBorder
ldh 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
hlcoord 10, 0
ld b, $0e
ld c, $08
jr nz, .drawTextBoxBorder
; start menu without pokedex
hlcoord 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
hlcoord 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 [x#SPRITESTATEDATA1_FACINGDIRECTION] to
; [x#SPRITESTATEDATA2_ORIGFACINGDIRECTION] for each non-player 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, wSprite01StateData1FacingDirection
ld c, $0f
ld de, $10
.spriteFacingDirectionCopyLoop
ld a, [hl] ; x#SPRITESTATEDATA1_FACINGDIRECTION
inc h
ld [hl], a ; [x#SPRITESTATEDATA2_ORIGFACINGDIRECTION]
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, wSpritePlayerStateData1ImageIndex
ld de, $10
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
ldh [hWY], a ; put the window on the screen
call LoadFontTilePatterns
ld a, $01
ldh [hAutoBGTransferEnabled], a ; enable continuous WRAM to VRAM transfer each V-blank
ret

View file

@ -0,0 +1,119 @@
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, NUM_BADGES
call CopyData
; Booleans for each badge.
ld hl, wTempObtainedBadgesBooleans
ld bc, NUM_BADGES
xor a
call FillMemory
; Alter these based on owned badges.
ld de, wTempObtainedBadgesBooleans
ld hl, wBadgeOrFaceTiles
ld a, [wObtainedBadges]
ld b, a
ld c, NUM_BADGES
.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
hlcoord 2, 11
ld de, wTempObtainedBadgesBooleans
call .DrawBadgeRow
hlcoord 2, 14
ld de, wTempObtainedBadgesBooleans + 4
; fallthrough
.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, NUM_BADGES
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
hlcoord 10, 0
ld b, $0e
ld c, $08
jr nz, .drawTextBoxBorder
; shorter menu if the player doesn't have the pokedex
hlcoord 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
hlcoord 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 Normal 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
ldh a, [hTileAnimations]
push af
xor a
ldh [hTileAnimations], 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
farcall LoadHallOfFameTeams
call LeaguePCShowTeam
pop bc
jr c, .doneShowingTeams
ld hl, wHoFTeamIndex2
inc [hl]
ld a, [hl]
cp b
jr nz, .loop
.doneShowingTeams
pop af
ldh [hTileAnimations], 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
ldh 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
hlcoord 12, 5
call GetMonHeader
call LoadFrontSpriteByMonIndex
call GBPalNormal
hlcoord 0, 13
ld b, 2
ld c, $12
call TextBoxBorder
hlcoord 1, 15
ld de, HallOfFameNoText
call PlaceString
hlcoord 16, 15
ld de, wHoFTeamNo
lb bc, 1, 3
call PrintNumber
farjp HoFDisplayMonInfo
HallOfFameNoText:
db "HALL OF FAME No @"
AccessedHoFPCText:
text_far _AccessedHoFPCText
text_end

715
engine/menus/main_menu.asm Normal file
View file

@ -0,0 +1,715 @@
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
hlcoord 0, 0
ld b, 6
ld c, 13
call TextBoxBorder
hlcoord 2, 2
ld de, ContinueText
call PlaceString
jr .next2
.noSaveFile
hlcoord 0, 0
ld b, 4
ld c, 13
call TextBoxBorder
hlcoord 2, 2
ld de, NewGameText
call PlaceString
.next2
ld hl, 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
ldh [hJoyPressed], a
ldh [hJoyReleased], a
ldh [hJoyHeld], a
call Joypad
ldh 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, LinkMenuEmptyText
call PrintText
call SaveScreenTilesToBuffer1
ld hl, WhereWouldYouLikeText
call PrintText
hlcoord 5, 5
ld b, $6
ld c, $d
call TextBoxBorder
call UpdateSprites
hlcoord 7, 7
ld de, CableClubOptionsText
call PlaceString
xor a
ld [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.
ldh a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
jr z, .doneChoosingMenuSelection
.useEnemyMenuSelection
ld a, b
ld [wLinkMenuSelectionSendBuffer], a
and $3
ld [wCurrentMenuItem], a
.doneChoosingMenuSelection
ldh a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
jr nz, .skipStartingTransfer
call DelayFrame
call DelayFrame
ld a, START_TRANSFER_INTERNAL_CLOCK
ldh [rSC], a
.skipStartingTransfer
ld b, " "
ld c, " "
ld d, "▷"
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
ldcoord_a 6, 7
ld a, c
ldcoord_a 6, 9
ld a, d
ldcoord_a 6, 11
ld c, 40
call DelayFrames
call LoadScreenTilesFromBuffer1
ld a, [wLinkMenuSelectionSendBuffer]
and (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:
text_far _WhereWouldYouLikeText
text_end
PleaseWaitText:
text_far _PleaseWaitText
text_end
LinkCanceledText:
text_far _LinkCanceledText
text_end
StartNewGame:
ld hl, wd732
res 1, [hl]
StartNewGameDebug:
call OakSpeech
ld c, 20
call DelayFrames
; enter map after using a special warp or loading the game from the main menu
SpecialEnterMap::
xor a
ldh [hJoyPressed], a
ldh [hJoyHeld], a
ldh [hJoy5], a
ld [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"
next ""
; fallthrough
NewGameText:
db "NEW GAME"
next "OPTION@"
CableClubOptionsText:
db "TRADE CENTER"
next "COLOSSEUM"
next "CANCEL@"
DisplayContinueGameInfo:
xor a
ldh [hAutoBGTransferEnabled], a
hlcoord 4, 7
ld b, 8
ld c, 14
call TextBoxBorder
hlcoord 5, 9
ld de, SaveScreenInfoText
call PlaceString
hlcoord 12, 9
ld de, wPlayerName
call PlaceString
hlcoord 17, 11
call PrintNumBadges
hlcoord 16, 13
call PrintNumOwnedMons
hlcoord 13, 15
call PrintPlayTime
ld a, 1
ldh [hAutoBGTransferEnabled], a
ld c, 30
jp DelayFrames
PrintSaveScreenText:
xor a
ldh [hAutoBGTransferEnabled], a
hlcoord 4, 0
ld b, $8
ld c, $e
call TextBoxBorder
call LoadTextBoxTilePatterns
call UpdateSprites
hlcoord 5, 2
ld de, SaveScreenInfoText
call PlaceString
hlcoord 12, 2
ld de, wPlayerName
call PlaceString
hlcoord 17, 4
call PrintNumBadges
hlcoord 16, 6
call PrintNumOwnedMons
hlcoord 13, 8
call PrintPlayTime
ld a, $1
ldh [hAutoBGTransferEnabled], a
ld c, 30
jp DelayFrames
PrintNumBadges:
push hl
ld hl, wObtainedBadges
ld b, $1
call CountSetBits
pop hl
ld de, wNumSetBits
lb bc, 1, 2
jp PrintNumber
PrintNumOwnedMons:
push hl
ld hl, wPokedexOwned
ld b, wPokedexOwnedEnd - wPokedexOwned
call CountSetBits
pop hl
ld de, wNumSetBits
lb bc, 1, 3
jp PrintNumber
PrintPlayTime:
ld de, wPlayTimeHours
lb bc, 1, 3
call PrintNumber
ld [hl], $6d
inc hl
ld de, wPlayTimeMinutes
lb bc, LEADING_ZEROES | 1, 2
jp PrintNumber
SaveScreenInfoText:
db "PLAYER"
next "BADGES "
next "#DEX "
next "TIME@"
DisplayOptionMenu:
hlcoord 0, 0
ld b, 3
ld c, 18
call TextBoxBorder
hlcoord 0, 5
ld b, 3
ld c, 18
call TextBoxBorder
hlcoord 0, 10
ld b, 3
ld c, 18
call TextBoxBorder
hlcoord 1, 1
ld de, TextSpeedOptionText
call PlaceString
hlcoord 1, 6
ld de, BattleAnimationOptionText
call PlaceString
hlcoord 1, 11
ld de, BattleStyleOptionText
call PlaceString
hlcoord 2, 16
ld de, OptionMenuCancelText
call PlaceString
xor a
ld [wCurrentMenuItem], a
ld [wLastMenuItem], a
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
ldh [hAutoBGTransferEnabled], a ; enable auto background transfer
call Delay3
.loop
call PlaceMenuCursor
call SetOptionsFromCursorPositions
.getJoypadStateLoop
call JoypadLowSensitivity
ldh 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
hlcoord 0, 3
call .placeUnfilledRightArrow
sla c
ld a, 1 ; On
jr nc, .storeBattleAnimationCursorX
ld a, 10 ; Off
.storeBattleAnimationCursorX
ld [wOptionsBattleAnimCursorX], a ; battle animation cursor X coordinate
hlcoord 0, 8
call .placeUnfilledRightArrow
sla c
ld a, 1
jr nc, .storeBattleStyleCursorX
ld a, 10
.storeBattleStyleCursorX
ld [wOptionsBattleStyleCursorX], a ; battle style cursor X coordinate
hlcoord 0, 13
call .placeUnfilledRightArrow
; cursor in front of Cancel
hlcoord 0, 16
ld a, 1
.placeUnfilledRightArrow
ld e, a
ld d, 0
add hl, de
ld [hl], "▷"
ret
; table that indicates how the 3 text speed options affect frame delays
; Format:
; 00: X coordinate of menu cursor
; 01: delay after printing a letter (in frames)
TextSpeedOptionData:
db 14, 5 ; Slow
db 7, 3 ; Medium
db 1, 1 ; Fast
db 7 ; default X coordinate (Medium)
db -1 ; end
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

View file

@ -0,0 +1,494 @@
AskName:
call SaveScreenTilesToBuffer1
call GetPredefRegisters
push hl
ld a, [wIsInBattle]
dec a
hlcoord 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
hlcoord 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:
text_far _DoYouWantToNicknameText
text_end
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
farcall LoadMonPartySpriteGfx
hlcoord 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
farcall AnimatePartyMon_ForceSpeed1
pop af
ld [wCurrentMenuItem], a
call JoypadLowSensitivity
ldh 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
jpfar 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 "゙"
ld de, Dakutens
jr z, .dakutensAndHandakutens
cp "゚"
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 tile $70
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
ldh [hAutoBGTransferEnabled], a
ld a, [wAlphabetCase]
and a
ld de, LowerCaseAlphabet
jr nz, .lowercase
ld de, UpperCaseAlphabet
.lowercase
hlcoord 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
ldh [hAutoBGTransferEnabled], a
jp Delay3
INCLUDE "data/text/alphabets.asm"
PrintNicknameAndUnderscores:
call CalcStringLength
ld a, c
ld [wNamingScreenNameLength], a
hlcoord 10, 2
lb bc, 1, 10
call ClearScreenArea
hlcoord 10, 2
ld de, wcf4b
call PlaceString
hlcoord 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
hlcoord 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 "data/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:
hlcoord 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
farcall WriteMonPartySpriteOAMBySpecies
pop af
ld [wd11e], a
call GetMonName
hlcoord 4, 1
call PlaceString
ld hl, $1
add hl, bc
ld [hl], "の" ; leftover from Japanese version; blank tile $c9 in English
hlcoord 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 Normal 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:
text_far _GetDexRatedText
text_end
ClosedOaksPCText:
text_far _ClosedOaksPCText
text_waitbutton
text_end
AccessedOaksPCText:
text_far _AccessedOaksPCText
text_end

306
engine/menus/party_menu.asm Normal file
View file

@ -0,0 +1,306 @@
DrawPartyMenu_::
xor a
ldh [hAutoBGTransferEnabled], a
call ClearScreen
call UpdateSprites
farcall LoadMonPartySpriteGfxWithLCDDisabled ; load pokemon icon graphics
RedrawPartyMenu_::
ld a, [wPartyMenuTypeOrMessageID]
cp SWAP_MONS_PARTY_MENU
jp z, .printMessage
call ErasePartyMenuCursors
farcall InitPartyMenuBlkPacket
hlcoord 3, 0
ld de, wPartySpecies
xor a
ld c, a
ldh [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
farcall WriteMonPartySpriteOAMByPartyIndex ; place the appropriate pokemon icon
ldh a, [hPartyMonIndex]
ld [wWhichPokemon], a
inc a
ldh [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
ldh a, [hUILayoutFlags]
set 0, a
ldh [hUILayoutFlags], a
add hl, bc
predef DrawHP2 ; draw HP bar and prints current / max HP
ldh a, [hUILayoutFlags]
res 0, a
ldh [hUILayoutFlags], 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 FIRST_PARTY_MENU_TEXT_ID
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
ldh [hAutoBGTransferEnabled], 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:
text_far _PartyMenuNormalText
text_end
PartyMenuItemUseText:
text_far _PartyMenuItemUseText
text_end
PartyMenuBattleText:
text_far _PartyMenuBattleText
text_end
PartyMenuUseTMText:
text_far _PartyMenuUseTMText
text_end
PartyMenuSwapMonText:
text_far _PartyMenuSwapMonText
text_end
PotionText:
text_far _PotionText
text_end
AntidoteText:
text_far _AntidoteText
text_end
ParlyzHealText:
text_far _ParlyzHealText
text_end
BurnHealText:
text_far _BurnHealText
text_end
IceHealText:
text_far _IceHealText
text_end
AwakeningText:
text_far _AwakeningText
text_end
FullHealText:
text_far _FullHealText
text_end
ReviveText:
text_far _ReviveText
text_end
RareCandyText:
text_far _RareCandyText
sound_get_item_1 ; probably supposed to play SFX_LEVEL_UP but the wrong music bank is loaded
text_promptbutton
text_end
SetPartyMenuHPBarColor:
ld hl, wPartyMenuHPBarColors
ld a, [wWhichPartyMenuHPBar]
ld c, a
ld b, 0
add hl, bc
call GetHealthBarColor
ld b, SET_PAL_PARTY_MENU_HP_BARS
call RunPaletteCommand
ld hl, wWhichPartyMenuHPBar
inc [hl]
ret

141
engine/menus/pc.asm Normal 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:
farcall 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
farcall PlayerPC
jr ReloadMainMenu
OaksPC:
ld a, SFX_ENTER_PC
call PlaySound
call WaitForSoundToFinish
farcall OpenOaksPC
jr ReloadMainMenu
PKMNLeague:
ld a, SFX_ENTER_PC
call PlaySound
call WaitForSoundToFinish
farcall 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
farcall 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:
text_far _TurnedOnPC1Text
text_end
AccessedBillsPCText:
text_far _AccessedBillsPCText
text_end
AccessedSomeonesPCText:
text_far _AccessedSomeonesPCText
text_end
AccessedMyPCText:
text_far _AccessedMyPCText
text_end
; removes one of the specified item ID [hItemToRemoveID] from bag (if existent)
RemoveItemByID::
ld hl, wBagItems
ldh a, [hItemToRemoveID]
ld b, a
xor a
ldh [hItemToRemoveIndex], a
.loop
ld a, [hli]
cp -1 ; reached terminator?
ret z
cp b
jr z, .foundItem
inc hl
ldh a, [hItemToRemoveIndex]
inc a
ldh [hItemToRemoveIndex], a
jr .loop
.foundItem
ld a, $1
ld [wItemQuantity], a
ldh a, [hItemToRemoveIndex]
ld [wWhichPokemon], a
ld hl, wNumBagItems
jp RemoveItemFromInventory

303
engine/menus/players_pc.asm Normal 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
hlcoord 0, 0
ld b, $8
ld c, $e
call TextBoxBorder
call UpdateSprites
hlcoord 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:
text_far _TurnedOnPC2Text
text_end
WhatDoYouWantText:
text_far _WhatDoYouWantText
text_end
WhatToDepositText:
text_far _WhatToDepositText
text_end
DepositHowManyText:
text_far _DepositHowManyText
text_end
ItemWasStoredText:
text_far _ItemWasStoredText
text_end
NothingToDepositText:
text_far _NothingToDepositText
text_end
NoRoomToStoreText:
text_far _NoRoomToStoreText
text_end
WhatToWithdrawText:
text_far _WhatToWithdrawText
text_end
WithdrawHowManyText:
text_far _WithdrawHowManyText
text_end
WithdrewItemText:
text_far _WithdrewItemText
text_end
NothingStoredText:
text_far _NothingStoredText
text_end
CantCarryMoreText:
text_far _CantCarryMoreText
text_end
WhatToTossText:
text_far _WhatToTossText
text_end
TossHowManyText:
text_far _TossHowManyText
text_end

665
engine/menus/pokedex.asm Normal 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
ldh [hJoy7], a
.setUpGraphics
ld b, SET_PAL_GENERIC
call RunPaletteCommand
callfar 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
ldh [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
hlcoord 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
hlcoord 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]
push af
call PlayCry
pop af
ld [wd11e], a
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
ldh [hAutoBGTransferEnabled], a
; draw the horizontal line separating the seen and owned amounts from the menu
hlcoord 15, 8
ld a, "─"
ld [hli], a
ld [hli], a
ld [hli], a
ld [hli], a
ld [hli], a
hlcoord 14, 0
ld [hl], $71 ; vertical line tile
hlcoord 14, 1
call DrawPokedexVerticalLine
hlcoord 14, 9
call DrawPokedexVerticalLine
ld hl, wPokedexSeen
ld b, wPokedexSeenEnd - wPokedexSeen
call CountSetBits
ld de, wNumSetBits
hlcoord 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
hlcoord 16, 6
lb bc, 1, 3
call PrintNumber ; print number of owned pokemon
hlcoord 16, 2
ld de, PokedexSeenText
call PlaceString
hlcoord 16, 5
ld de, PokedexOwnText
call PlaceString
hlcoord 1, 1
ld de, PokedexContentsText
call PlaceString
hlcoord 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
ldh [hAutoBGTransferEnabled], a
hlcoord 4, 2
lb bc, 14, 10
call ClearScreenArea
hlcoord 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
ldh [hAutoBGTransferEnabled], 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
callfar 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
ldh [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
ldh a, [hTileAnimations]
push af
xor a
ldh [hTileAnimations], a
hlcoord 0, 0
ld de, 1
lb bc, $64, SCREEN_WIDTH
call DrawTileLine ; draw top border
hlcoord 0, 17
ld b, $6f
call DrawTileLine ; draw bottom border
hlcoord 0, 1
ld de, 20
lb bc, $66, $10
call DrawTileLine ; draw left border
hlcoord 19, 1
ld b, $67
call DrawTileLine ; draw right border
ld a, $63 ; upper left corner tile
ldcoord_a 0, 0
ld a, $65 ; upper right corner tile
ldcoord_a 19, 0
ld a, $6c ; lower left corner tile
ldcoord_a 0, 17
ld a, $6e ; lower right corner tile
ldcoord_a 19, 17
hlcoord 0, 9
ld de, PokedexDataDividerLine
call PlaceString ; draw horizontal divider line
hlcoord 9, 6
ld de, HeightWeightText
call PlaceString
call GetMonName
hlcoord 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
hlcoord 9, 4
call PlaceString ; print species name
ld h, b
ld l, c
push de
ld a, [wd11e]
push af
call IndexToPokedex
hlcoord 2, 8
ld a, "№"
ld [hli], a
ld a, "<DOT>"
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
hlcoord 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
hlcoord 12, 6
lb bc, 1, 2
call PrintNumber ; print feet (height)
ld a, ""
ld [hl], a
inc de
inc de ; de = address of inches (height)
hlcoord 15, 6
lb bc, LEADING_ZEROES | 1, 2
call PrintNumber ; print inches (height)
ld a, "″"
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
hlcoord 11, 8
lb bc, 2, 5 ; 2 bytes, 5 digits
call PrintNumber ; print weight
hlcoord 14, 8
ldh a, [hDexWeight + 1]
sub 10
ldh 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], "<DOT>" ; decimal point tile
pop af
ldh [hDexWeight + 1], a ; restore original value of [hDexWeight + 1]
pop af
ldh [hDexWeight], a ; restore original value of [hDexWeight]
pop hl
inc hl ; hl = address of pokedex description text
bccoord 1, 11
ld a, %10
ldh [hClearLetterPrintingDelayFlags], a
call TextCommandProcessor ; print pokedex description text
xor a
ldh [hClearLetterPrintingDelayFlags], a
.waitForButtonPress
call JoypadLowSensitivity
ldh a, [hJoy5]
and A_BUTTON | B_BUTTON
jr z, .waitForButtonPress
pop af
ldh [hTileAnimations], a
call GBPalWhiteOut
call ClearScreen
call RunDefaultPaletteCommand
call LoadTextBoxTilePatterns
call GBPalNormal
ld hl, wd72c
res 1, [hl]
ld a, $77 ; max volume
ldh [rNR50], a
ret
HeightWeightText:
db "HT ???″"
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, $69, $6B, $69, $6B, $6B
db $6B, $6B, $69, $6B, $69, $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/pokemon/dex_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/pokemon/dex_order.asm"

759
engine/menus/save.asm Normal file
View file

@ -0,0 +1,759 @@
LoadSAV:
;(if carry -> write
;"the file data is destroyed")
call ClearScreen
call LoadFontTilePatterns
call LoadTextBoxTilePatterns
ld a, 1
ld [wHaltAudio], a
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
ld a, 0
ld [wHaltAudio], a
ret
FileDataDestroyedText:
text_far _FileDataDestroyedText
text_end
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, [sTileAnimations]
ldh [hTileAnimations], 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:
farcall 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
hlcoord 1, 13
lb bc, 4, 18
call ClearScreenArea
hlcoord 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
hlcoord 0, 7
lb bc, 8, 1
ld a, TWO_OPTION_MENU
ld [wTextBoxID], a
call DisplayTextBoxID ; yes/no menu
ld a, [wCurrentMenuItem]
ret
WouldYouLikeToSaveText:
text_far _WouldYouLikeToSaveText
text_end
GameSavedText:
text_far _GameSavedText
text_end
OlderFileWillBeErasedText:
text_far _OlderFileWillBeErasedText
text_end
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
ldh a, [hTileAnimations]
ld [sTileAnimations], 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
ld a, 1
ld [wHaltAudio], a
call SaveSAVtoSRAM0
call SaveSAVtoSRAM1
call SaveSAVtoSRAM2
ld a, 0
ld [wHaltAudio], a
ret
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, hUILayoutFlags
set 1, [hl]
call HandleMenuInput
ld hl, hUILayoutFlags
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:
text_far _WhenYouChangeBoxText
text_end
CopyBoxToOrFromSRAM:
; copy an entire box from hl to de with b as the SRAM bank
ld a, 1
ld [wHaltAudio], a
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
xor a
ld [wHaltAudio], a
ret
DisplayChangeBoxMenu:
xor a
ldh [hAutoBGTransferEnabled], 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
hlcoord 0, 0
ld b, 2
ld c, 9
call TextBoxBorder
ld hl, ChooseABoxText
call PrintText
hlcoord 11, 0
ld b, 12
ld c, 7
call TextBoxBorder
ld hl, hUILayoutFlags
set 2, [hl]
ld de, BoxNames
hlcoord 13, 1
call PlaceString
ld hl, hUILayoutFlags
res 2, [hl]
ld a, [wCurrentBoxNum]
and $7f
cp 9
jr c, .singleDigitBoxNum
sub 9
hlcoord 8, 2
ld [hl], "1"
add "0"
jr .next
.singleDigitBoxNum
add "1"
.next
ldcoord_a 9, 2
hlcoord 1, 2
ld de, BoxNoText
call PlaceString
call GetMonCountsForAllBoxes
hlcoord 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
ldh [hAutoBGTransferEnabled], a
ret
ChooseABoxText:
text_far _ChooseABoxText
text_end
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, 1
ld [wHaltAudio], a
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
xor a
ld [wHaltAudio], 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 a, 1
ld [wHaltAudio], a
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
xor a
ld [wHaltAudio], 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
; and the two random numbers generated at game beginning
; (which are stored at wPlayerID)s
ld a, 1
ld [wHaltAudio], a
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
xor a
ld [wHaltAudio], 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, 1
ld [wHaltAudio], a
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
xor a
ld [wHaltAudio], a
ret
ClearSAV:
ld a, 1
ld [wHaltAudio], a
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
xor a
ld [wHaltAudio], a
ret
PadSRAM_FF:
ld [MBC1SRamBank], a
ld hl, SRAM_Begin
ld bc, SRAM_End - SRAM_Begin
ld a, $ff
jp FillMemory

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
ldh 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 BIT_THUNDERBADGE, a
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 BIT_CASCADEBADGE, a
jp z, .newBadgeRequired
predef UsedCut
ld a, [wActionResultOrTookBattleTurn]
and a
jp z, .loop
jp CloseTextDisplay
.surf
bit BIT_SOULBADGE, a
jp z, .newBadgeRequired
farcall 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 BIT_RAINBOWBADGE, a
jp z, .newBadgeRequired
predef PrintStrengthTxt
call GBPalWhiteOutWithDelay3
jp .goBackToMap
.flash
bit BIT_BOULDERBADGE, a
jp z, .newBadgeRequired
xor a
ld [wMapPalOffset], a
ld hl, .flashLightsAreaText
call PrintText
call GBPalWhiteOutWithDelay3
jp .goBackToMap
.flashLightsAreaText
text_far _FlashLightsAreaText
text_end
.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
text_far _WarpToLastPokemonCenterText
text_end
.cannotUseTeleportNowText
text_far _CannotUseTeleportNowText
text_end
.cannotFlyHereText
text_far _CannotFlyHereText
text_end
.softboiled
ld hl, wPartyMon1MaxHP
ld a, [wWhichPokemon]
ld bc, wPartyMon2 - wPartyMon1
call AddNTimes
ld a, [hli]
ldh [hDividend], a
ld a, [hl]
ldh [hDividend + 1], a
ld a, 5
ldh [hDivisor], a
ld b, 2 ; number of bytes
call Divide
ld bc, wPartyMon1HP - wPartyMon1MaxHP
add hl, bc
ld a, [hld]
ld b, a
ldh a, [hQuotient + 3]
sub b
ld b, [hl]
ldh a, [hQuotient + 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
text_far _NotHealthyEnoughText
text_end
.goBackToMap
call RestoreScreenTilesAndReloadTilePatterns
jp CloseTextDisplay
.newBadgeRequired
ld hl, .newBadgeRequiredText
call PrintText
jp .loop
.newBadgeRequiredText
text_far _NewBadgeRequiredText
text_end
; writes a blank tile to all possible menu cursor positions on the party menu
ErasePartyMenuCursors::
hlcoord 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, " "
ldcoord_a 5, 4
ldcoord_a 5, 6
ldcoord_a 5, 8
ldcoord_a 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 HM01
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:
text_far _CannotUseItemsHereText
text_end
CannotGetOffHereText:
text_far _CannotGetOffHereText
text_end
INCLUDE "data/items/use_party.asm"
INCLUDE "data/items/use_overworld.asm"
StartMenu_TrainerInfo::
call GBPalWhiteOut
call ClearScreen
call UpdateSprites
ldh a, [hTileAnimations]
push af
xor a
ldh [hTileAnimations], 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
ldh [hTileAnimations], 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
hlcoord 0, 2
ld a, " "
call TrainerInfo_DrawVerticalLine
hlcoord 1, 2
call TrainerInfo_DrawVerticalLine
ld hl, vChars2 tile $07
ld de, vChars2 tile $00
ld bc, $1c tiles
call CopyData
ld hl, TrainerInfoTextBoxTileGraphics ; trainer info text box tile patterns
ld de, vChars2 tile $77
ld bc, 8 tiles
push bc
call TrainerInfo_FarCopyData
ld hl, BlankLeaderNames
ld de, vChars2 tile $60
ld bc, $17 tiles
call TrainerInfo_FarCopyData
pop bc
ld hl, BadgeNumbersTileGraphics ; badge number tile patterns
ld de, vChars1 tile $58
call TrainerInfo_FarCopyData
ld hl, GymLeaderFaceAndBadgeTileGraphics ; gym leader face and badge tile patterns
ld de, vChars2 tile $20
ld bc, 8 * 8 tiles
ld a, BANK(GymLeaderFaceAndBadgeTileGraphics)
call FarCopyData2
ld hl, TextBoxGraphics
ld de, 13 tiles
add hl, de ; hl = colon tile pattern
ld de, vChars1 tile $56
ld bc, 1 tiles
ld a, BANK(TextBoxGraphics)
push bc
call FarCopyData2
pop bc
ld hl, TrainerInfoTextBoxTileGraphics tile 8 ; background tile pattern
ld de, vChars1 tile $57
call TrainerInfo_FarCopyData
call EnableLCD
ld hl, wTrainerInfoTextBoxWidthPlus1
ld a, 18 + 1
ld [hli], a
dec a
ld [hli], a
ld [hl], 1
hlcoord 0, 0
call TrainerInfo_DrawTextBox
ld hl, wTrainerInfoTextBoxWidthPlus1
ld a, 16 + 1
ld [hli], a
dec a
ld [hli], a
ld [hl], 3
hlcoord 1, 10
call TrainerInfo_DrawTextBox
hlcoord 0, 10
ld a, $d7
call TrainerInfo_DrawVerticalLine
hlcoord 19, 10
call TrainerInfo_DrawVerticalLine
hlcoord 6, 9
ld de, TrainerInfo_BadgesText
call PlaceString
hlcoord 2, 2
ld de, TrainerInfo_NameMoneyTimeText
call PlaceString
hlcoord 7, 2
ld de, wPlayerName
call PlaceString
hlcoord 8, 4
ld de, wPlayerMoney
ld c, $e3
call PrintBCDNumber
hlcoord 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
ldh [hAutoBGTransferEnabled], a
call ClearScreen
call UpdateSprites
callfar 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
hlcoord 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]
ldh [hSwapTemp], a
ld a, [de]
ld [hl], a
ldh 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
ldh [hSwapItemID], a ; save second item ID
ld a, [hld]
ldh [hSwapItemQuantity], a ; save 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
ldh a, [hSwapItemQuantity]
ld [de], a ; put second item quantity in first item slot
dec de
ldh a, [hSwapItemID]
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

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

@ -0,0 +1,561 @@
; 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
hlcoord 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
INCLUDE "data/text_boxes.asm"
DisplayMoneyBox:
ld hl, wd730
set 6, [hl]
ld a, MONEY_BOX_TEMPLATE
ld [wTextBoxID], a
call DisplayTextBoxID
hlcoord 13, 1
ld b, 1
ld c, 6
call ClearScreenArea
hlcoord 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
INCLUDE "data/yes_no_menu_strings.asm"
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
hlcoord 11, 11
ld b, 5
ld c, 7
call TextBoxBorder
call UpdateSprites
ld a, 12
ldh [hFieldMoveMonMenuTopMenuItemX], a
hlcoord 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.
hlcoord 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.
hlcoord 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]
ldh [hFieldMoveMonMenuTopMenuItemX], a
hlcoord 0, 12
ld a, [wFieldMovesLeftmostXCoord]
inc a
ld e, a
ld d, 0
add hl, de
ld de, PokemonMenuEntries
jp PlaceString
INCLUDE "data/moves/field_move_names.asm"
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
INCLUDE "data/moves/field_moves.asm"