diff options
Diffstat (limited to 'engine/menus')
-rw-r--r-- | engine/menus/display_text_id_init.asm | 76 | ||||
-rw-r--r-- | engine/menus/draw_badges.asm | 120 | ||||
-rw-r--r-- | engine/menus/draw_start_menu.asm | 87 | ||||
-rwxr-xr-x | engine/menus/league_pc.asm | 119 | ||||
-rw-r--r-- | engine/menus/link_menu.asm | 910 | ||||
-rwxr-xr-x | engine/menus/main_menu.asm | 300 | ||||
-rwxr-xr-x | engine/menus/naming_screen.asm | 508 | ||||
-rwxr-xr-x | engine/menus/oaks_pc.asm | 28 | ||||
-rw-r--r-- | engine/menus/options.asm | 443 | ||||
-rwxr-xr-x | engine/menus/party_menu.asm | 314 | ||||
-rwxr-xr-x | engine/menus/pc.asm | 141 | ||||
-rwxr-xr-x | engine/menus/players_pc.asm | 302 | ||||
-rwxr-xr-x | engine/menus/pokedex.asm | 745 | ||||
-rwxr-xr-x | engine/menus/save.asm | 682 | ||||
-rwxr-xr-x | engine/menus/start_sub_menus.asm | 825 | ||||
-rw-r--r-- | engine/menus/swap_items.asm | 149 | ||||
-rw-r--r-- | engine/menus/text_box.asm | 533 |
17 files changed, 6282 insertions, 0 deletions
diff --git a/engine/menus/display_text_id_init.asm b/engine/menus/display_text_id_init.asm new file mode 100644 index 00000000..17f290b4 --- /dev/null +++ b/engine/menus/display_text_id_init.asm @@ -0,0 +1,76 @@ +; 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 + lb bc, 14, 8 + jr nz, .drawTextBoxBorder +; start menu without pokedex + hlcoord 10, 0 + lb bc, 12, 8 + 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 + lb bc, 4, 18 +.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 diff --git a/engine/menus/draw_badges.asm b/engine/menus/draw_badges.asm new file mode 100644 index 00000000..0bb433cc --- /dev/null +++ b/engine/menus/draw_badges.asm @@ -0,0 +1,120 @@ +DrawBadges: +; Draw 4x2 gym leader faces, with the faces replaced by +; badges if they are owned. Used in the player status screen. + +; In Japanese versions, names are displayed above faces. +; Instead of removing relevant code, the name graphics were erased. + +; Tile ids for face/badge graphics. + ld de, wBadgeOrFaceTiles + ld hl, .FaceBadgeTiles + ld bc, 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 +; call .DrawBadgeRow +; ret + +.DrawBadgeRow +; Draw 4 badges. + + ld c, 4 +.DrawBadge + push de + push hl + +; Badge no. + ld a, [wBadgeNumberTile] + ld [hli], a + inc a + ld [wBadgeNumberTile], a + +; Names aren't printed if the badge is owned. + ld a, [de] + and a + ld a, [wBadgeNameTile] + jr nz, .SkipName + call .PlaceTiles + jr .PlaceBadge + +.SkipName + inc a + inc a + inc hl + +.PlaceBadge + ld [wBadgeNameTile], a + ld de, SCREEN_WIDTH - 1 + add hl, de + ld a, [wBadgeOrFaceTiles] + call .PlaceTiles + add hl, de + call .PlaceTiles + +; Shift badge array back one byte. + push bc + ld hl, wBadgeOrFaceTiles + 1 + ld de, wBadgeOrFaceTiles + ld bc, 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" diff --git a/engine/menus/draw_start_menu.asm b/engine/menus/draw_start_menu.asm new file mode 100644 index 00000000..7ca75ecb --- /dev/null +++ b/engine/menus/draw_start_menu.asm @@ -0,0 +1,87 @@ +; function that displays the start menu +DrawStartMenu:: + CheckEvent EVENT_GOT_POKEDEX +; menu with pokedex + hlcoord 10, 0 + lb bc, 14, 8 + jr nz, .drawTextBoxBorder +; shorter menu if the player doesn't have the pokedex + hlcoord 10, 0 + lb bc, 12, 8 +.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 "#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 diff --git a/engine/menus/league_pc.asm b/engine/menus/league_pc.asm new file mode 100755 index 00000000..5551fd0b --- /dev/null +++ b/engine/menus/league_pc.asm @@ -0,0 +1,119 @@ +PKMNLeaguePC: + ld hl, AccessedHoFPCText + call PrintText + ld hl, wd730 + set 6, [hl] + push hl + ld a, [wUpdateSpritesEnabled] + push af + ldh a, [hTilesetType] + push af + xor a + ldh [hTilesetType], a + ld [wSpriteFlipped], a + ld [wUpdateSpritesEnabled], a + ld [wHoFTeamIndex2], a + ld [wHoFTeamNo], a + ld a, [wNumHoFTeams] + ld b, a + cp HOF_TEAM_CAPACITY + 1 + jr c, .loop +; If the total number of hall of fame teams is greater than the storage +; capacity, then calculate the number of the first team that is still recorded. + ld b, HOF_TEAM_CAPACITY + sub b + ld [wHoFTeamNo], a +.loop + ld hl, wHoFTeamNo + inc [hl] + push bc + ld a, [wHoFTeamIndex2] + ld [wHoFTeamIndex], a + 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 [hTilesetType], a + pop af + ld [wUpdateSpritesEnabled], a + pop hl + res 6, [hl] + call GBPalWhiteOutWithDelay3 + call ClearScreen + call RunDefaultPaletteCommand + jp GBPalNormal + +LeaguePCShowTeam: + ld c, PARTY_LENGTH +.loop + push bc + call LeaguePCShowMon + call WaitForTextScrollButtonPress + 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 + lb bc, 2, 18 + call TextBoxBorder + hlcoord 1, 15 + ld de, HallOfFameNoText + call PlaceString + hlcoord 16, 15 + ld de, wHoFTeamNo + lb bc, 1, 3 + call PrintNumber + farjp Func_7033f + +HallOfFameNoText: + db "HALL OF FAME No @" + +AccessedHoFPCText: + text_far _AccessedHoFPCText + text_end diff --git a/engine/menus/link_menu.asm b/engine/menus/link_menu.asm new file mode 100644 index 00000000..2f2db573 --- /dev/null +++ b/engine/menus/link_menu.asm @@ -0,0 +1,910 @@ +Func_f531b:: + ld c, $14 + call DelayFrames + ld a, $1 + ld [wBuffer], a + xor a + ld [wUnknownSerialFlag_d499], a + coord hl, 0, 0 + lb bc, 4, 5 + call TextBoxBorder + ld de, Text_f5791 + coord hl, 1, 2 + call PlaceString + coord hl, 8, 0 + lb bc, 8, 10 + call TextBoxBorder + coord hl, 10, 2 + ld de, Text_f579c + call PlaceString + coord hl, 0, 10 + lb bc, 6, 18 + call TextBoxBorder + call UpdateSprites + xor a + ld [wUnusedCD37], a + ld [wd72d], a + ld [wd11e], a + ld hl, wTopMenuItemY + ld a, $2 + ld [hli], a + ld a, $9 + ld [hli], a + xor a + ld [hli], a + inc hl + ld a, $3 + ld [hli], a + ld a, $3 + ld [hli], a + xor a + ld [hl], a +.asm_f5377 + call Func_f56bd + call HandleMenuInput + and $3 + add a + add a + ld b, a + ld a, [wCurrentMenuItem] + cp $3 + jr nz, .asm_f5390 + bit 2, b + jr z, .asm_f5390 + dec a + ld b, $8 +.asm_f5390 + add b + add $c0 + ld [wLinkMenuSelectionSendBuffer], a + ld [wLinkMenuSelectionSendBuffer+1], a +.asm_f5399 + ld hl, wLinkMenuSelectionSendBuffer + ld a, [hl] + ldh [hSerialSendData], a + call Serial_ExchangeByte + push af + ld hl, wLinkMenuSelectionSendBuffer + ld a, [hl] + ldh [hSerialSendData], a + call Serial_ExchangeByte + pop bc + cp b + jr nz, .asm_f5399 + and $f0 + cp $c0 + jr nz, .asm_f5399 + ld a, b + and $c + jr nz, .asm_f53c4 + ld a, [wLinkMenuSelectionSendBuffer] + and $c + jr z, .asm_f5377 + jr .asm_f53df +.asm_f53c4 + ld a, [wLinkMenuSelectionSendBuffer] + and $c + jr z, .asm_f53d1 + ldh a, [hSerialConnectionStatus] + cp $2 + jr z, .asm_f53df +.asm_f53d1 + ld a, $1 + ld [wd11e], a + ld a, b + ld [wLinkMenuSelectionSendBuffer], a + and $3 + ld [wCurrentMenuItem], a +.asm_f53df + call DelayFrame + call DelayFrame + ld hl, wLinkMenuSelectionSendBuffer + ld a, [hl] + ldh [hSerialSendData], a + call Serial_ExchangeByte + call Serial_ExchangeByte + ld b, $14 +.loop + call DelayFrame + call Serial_SendZeroByte + dec b + jr nz, .loop + ld b, " " + ld c, " " + ld d, " " + ld e, "▷" + ld a, [wLinkMenuSelectionSendBuffer] + bit 3, a + jr nz, .asm_f541a + ld b, e + ld e, c + ld a, [wCurrentMenuItem] + and a + jr z, .asm_f541a + ld c, b + ld b, d + dec a + jr z, .asm_f541a + ld d, c + ld c, b +.asm_f541a + ld a, b + ldcoord_a 9, 2 + ld a, c + ldcoord_a 9, 4 + ld a, d + ldcoord_a 9, 6 + ld a, e + ldcoord_a 9, 8 + ld c, 40 + call DelayFrames + ld a, [wLinkMenuSelectionSendBuffer] + bit 3, a + jr nz, asm_f547f + ld a, [wCurrentMenuItem] + cp $3 + jr z, asm_f547f + inc a + ld [wUnknownSerialFlag_d499], a + ld a, [wCurrentMenuItem] + ld hl, PointerTable_f5488 + ld c, a + ld b, $0 + add hl, bc + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + ld de, .returnaddress + push de + jp hl +.returnaddress + ld [wLinkMenuSelectionSendBuffer], a + xor a + ld [wUnknownSerialCounter], a + ld [wUnknownSerialCounter+1], a + call Serial_SyncAndExchangeNybble + ld a, [wLinkMenuSelectionSendBuffer] + and a + jr nz, asm_f547c + ld a, [wLinkMenuSelectionReceiveBuffer] + and a + jr nz, Func_f5476 + xor a + ld [wUnknownSerialCounter], a + ld [wUnknownSerialCounter+1], a + and a + ret + +Func_f5476:: + ld hl, ColosseumIneligibleText + call PrintText +asm_f547c:: + jp Func_f531b + +asm_f547f:: + xor a + ld [wUnknownSerialCounter], a + ld [wUnknownSerialCounter+1], a + scf + ret + +PointerTable_f5488:: + dw PokeCup + dw PikaCup + dw PetitCup + +PokeCup:: + ld hl, wPartyCount + ld a, [hli] + cp $3 + jp nz, NotThreeMonsInParty + ld b, $3 +.loop + ld a, [hli] + cp MEW + jp z, MewInParty + dec b + jr nz, .loop + dec hl + dec hl + cp [hl] ; is third mon second mon? + jp z, DuplicateSpecies + dec hl ; wPartySpecies + cp [hl] ; is third mon first mon? + jp z, DuplicateSpecies + ld a, [hli] + cp [hl] ; is first mon second mon? + jp z, DuplicateSpecies + ld a, [wPartyMon1Level] + cp 56 + jp nc, LevelAbove55 + cp 50 + jp c, LevelUnder50 + ld b, a + ld a, [wPartyMon2Level] + cp 56 + jp nc, LevelAbove55 + cp 50 + jp c, LevelUnder50 + ld c, a + ld a, [wPartyMon3Level] + cp 56 + jp nc, LevelAbove55 + cp 50 + jp c, LevelUnder50 + add b + add c + cp 156 + jp nc, CombinedLevelsGreaterThan155 + xor a + ret + +PikaCup:: + ld hl, wPartyCount + ld a, [hli] + cp $3 + jp nz, NotThreeMonsInParty + ld b, $3 +.loop + ld a, [hli] ; wPartySpecies + cp MEW + jp z, MewInParty + dec b + jr nz, .loop + dec hl + dec hl + cp [hl] ; is third mon second mon? + jp z, DuplicateSpecies + dec hl ; wPartySpecies + cp [hl] ; is third mon first mon? + jp z, DuplicateSpecies + ld a, [hli] + cp [hl] ; is first mon second mon? + jp z, DuplicateSpecies + ld a, [wPartyMon1Level] + cp 21 + jp nc, LevelAbove20 + cp 15 + jp c, LevelUnder15 + ld b, a + ld a, [wPartyMon2Level] + cp 21 + jp nc, LevelAbove20 + cp 15 + jp c, LevelUnder15 + ld c, a + ld a, [wPartyMon3Level] + cp 21 + jp nc, LevelAbove20 + cp 15 + jp c, LevelUnder15 + add b + add c + cp 51 + jp nc, CombinedLevelsAbove50 + xor a + ret + +PetitCup:: + ld hl, wPartyCount + ld a, [hli] + cp $3 + jp nz, NotThreeMonsInParty + ld b, $3 +.loop + ld a, [hli] + cp MEW + jp z, MewInParty + dec b + jr nz, .loop + dec hl + dec hl + cp [hl] ; is third mon second mon? + jp z, DuplicateSpecies + dec hl ; wPartySpecies + cp [hl] ; is third mon first mon? + jp z, DuplicateSpecies + ld a, [hli] + cp [hl] ; is first mon second mon? + jp z, DuplicateSpecies + dec hl + ld a, [hl] + ld [wcf91], a + push hl + callfar Func_3b10f + pop hl + jp c, asm_f56ad + inc hl + ld a, [hl] + ld [wcf91], a + push hl + callfar Func_3b10f + pop hl + jp c, asm_f56ad + inc hl + ld a, [hl] + ld [wcf91], a + push hl + callfar Func_3b10f + pop hl + jp c, asm_f56ad + dec hl + dec hl + ld b, $3 +.bigloop + ld a, [hli] + push hl + push bc + push af + dec a + ld c, a + ld b, $0 + ld hl, PokedexEntryPointers + add hl, bc + add hl, bc + ld de, wcd6d + ld bc, $2 + ld a, BANK(PokedexEntryPointers) + call FarCopyData + ld hl, wcd6d + ld a, [hli] + ld h, [hl] + ld l, a + ld de, wcd6d + ld bc, $14 + ld a, BANK(PokedexEntryPointers) + call FarCopyData + ld hl, wcd6d +.loop2 + ld a, [hli] + cp "@" + jr nz, .loop2 + ld a, [hli] + cp $7 + jp nc, asm_f5689 + add a + add a + ld b, a + add a + add b + ld b, a + ld a, [hli] + add b + cp $51 + jp nc, asm_f5689 + ld a, [hli] + sub $b9 + ld a, [hl] + sbc $1 + jp nc, asm_f569b + pop af + pop bc + pop hl + dec b + jr nz, .bigloop + ld a, [wPartyMon1Level] + cp 31 + jp nc, LevelAbove30 + cp 25 + jp c, LevelUnder25 + ld b, a + ld a, [wPartyMon2Level] + cp 31 + jp nc, LevelAbove30 + cp 25 + jp c, LevelUnder25 + ld c, a + ld a, [wPartyMon3Level] + cp 31 + jp nc, LevelAbove30 + cp 25 + jp c, LevelUnder25 + add b + add c + cp 81 + jp nc, CombinedLevelsAbove80 + xor a + ret + +NotThreeMonsInParty:: + ld hl, Colosseum3MonsText + call PrintText + ld a, $1 + ret + +MewInParty:: + ld hl, ColosseumMewText + call PrintText + ld a, $2 + ret + +DuplicateSpecies:: + ld hl, ColosseumDifferentMonsText + call PrintText + ld a, $3 + ret + +LevelAbove55:: + ld hl, ColosseumMaxL55Text + call PrintText + ld a, $4 + ret + +LevelUnder50:: + ld hl, ColosseumMinL50Text + call PrintText + ld a, $5 + ret + +CombinedLevelsGreaterThan155:: + ld hl, ColosseumTotalL155Text + call PrintText + ld a, $6 + ret + +LevelAbove30:: + ld hl, ColosseumMaxL30Text + call PrintText + ld a, $7 + ret + +LevelUnder25:: + ld hl, ColosseumMinL25Text + call PrintText + ld a, $8 + ret + +CombinedLevelsAbove80:: + ld hl, ColosseumTotalL80Text + call PrintText + ld a, $9 + ret + +LevelAbove20:: + ld hl, ColosseumMaxL20Text + call PrintText + ld a, $a + ret + +LevelUnder15:: + ld hl, ColosseumMinL15Text + call PrintText + ld a, $b + ret + +CombinedLevelsAbove50:: + ld hl, ColosseumTotalL50Text + call PrintText + ld a, $c + ret + +asm_f5689:: + pop af + pop bc + pop hl + ld [wd11e], a + call GetMonName + ld hl, ColosseumHeightText + call PrintText + ld a, $d + ret + +asm_f569b:: + pop af + pop bc + pop hl + ld [wd11e], a + call GetMonName + ld hl, ColosseumWeightText + call PrintText + ld a, $e + ret + +asm_f56ad:: + ld a, [hl] + ld [wd11e], a + call GetMonName + ld hl, ColosseumEvolvedText + call PrintText + ld a, $f + ret + +Func_f56bd:: + xor a + ldh [hAutoBGTransferEnabled], a + coord hl, 1, 11 + lb bc, 6, 18 + call ClearScreenArea + ld a, [wCurrentMenuItem] + cp $3 + jr nc, .asm_f56e6 + ld hl, PointerTable_f56ee + ld a, [wCurrentMenuItem] + ld c, a + ld b, $0 + add hl, bc + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + ld d, h + ld e, l + coord hl, 1, 12 + call PlaceString +.asm_f56e6 + call Delay3 + ld a, $1 + ldh [hAutoBGTransferEnabled], a + ret + +PointerTable_f56ee:: + dw Text_f56f4 + dw Text_f5728 + dw Text_f575b + +Text_f56f4:: + db "LVs of 3<PKMN>:50-55" + next "Sum of LVs:155 MAX" + next "MEW can't attend.@" + +Text_f5728:: + db "LVs of 3<PKMN>:15-20" + next "Sum of LVs:50 MAX" + next "MEW can't attend.@" + +Text_f575b:: + db "3 Basic <PKMN>.LV25-30" + next "Sum of LVs:80 MAX" + next "6’8” and 44lb MAX@" + +Text_f5791:: + db "View" + next "Rules@" + +Text_f579c:: + db "# Cup" + next "Pika Cup" + next "Petit Cup" + next "CANCEL@" + +Colosseum3MonsText:: + text_far _Colosseum3MonsText + text_end + +ColosseumMewText:: + text_far _ColosseumMewText + text_end + +ColosseumDifferentMonsText:: + text_far _ColosseumDifferentMonsText + text_end + +ColosseumMaxL55Text:: + text_far _ColosseumMaxL55Text + text_end + +ColosseumMinL50Text:: + text_far _ColosseumMinL50Text + text_end + +ColosseumTotalL155Text:: + text_far _ColosseumTotalL155Text + text_end + +ColosseumMaxL30Text:: + text_far _ColosseumMaxL30Text + text_end + +ColosseumMinL25Text:: + text_far _ColosseumMinL25Text + text_end + +ColosseumTotalL80Text:: + text_far _ColosseumTotalL80Text + text_end + +ColosseumMaxL20Text:: + text_far _ColosseumMaxL20Text + text_end + +ColosseumMinL15Text:: + text_far _ColosseumMinL15Text + text_end + +ColosseumTotalL50Text:: + text_far _ColosseumTotalL50Text + text_end + +ColosseumHeightText:: + text_far _ColosseumHeightText + text_end + +ColosseumWeightText:: + text_far _ColosseumWeightText + text_end + +ColosseumEvolvedText:: + text_far _ColosseumEvolvedText + text_end + +ColosseumIneligibleText:: + text_far _ColosseumIneligibleText + text_end + +LinkMenu: + xor a + ld [wLetterPrintingDelayFlags], a + ld hl, wd72e + set 6, [hl] + ld hl, TextTerminator_f5a16 + call PrintText + call SaveScreenTilesToBuffer1 + ld hl, ColosseumWhereToText + call PrintText + hlcoord 5, 3 + lb bc, 8, 13 + call TextBoxBorder + call UpdateSprites + hlcoord 7, 5 + ld de, TradeCenterText + call PlaceString + xor a + ld [wUnusedCD37], a + ld [wd72d], a + ld [wd11e], a + ld hl, wTopMenuItemY + ld a, $5 + ld [hli], a + ld a, $6 + ld [hli], a + xor a + ld [hli], a + inc hl + ld a, $3 + ld [hli], a + ld [hli], a + xor a + ld [hl], a +.waitForInputLoop + call HandleMenuInput + and A_BUTTON | B_BUTTON + add a + add a + ld b, a + ld a, [wCurrentMenuItem] + cp $3 + jr nz, .asm_f586b + bit 2, b + jr z, .asm_f586b + dec a + ld b, $8 +.asm_f586b + 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_f5c7d + ld a, [wLinkMenuSelectionReceiveBuffer + 1] + ld b, a + and $f0 + cp $d0 + jr nz, .exchangeMenuSelectionLoop +.asm_f5c7d + 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, $1 + ld [wd11e], a + ld a, b + ld [wLinkMenuSelectionSendBuffer], a + and $3 + ld [wCurrentMenuItem], a ; wCurrentMenuItem +.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 e, "▷" + ld a, [wLinkMenuSelectionSendBuffer] + and (B_BUTTON << 2) ; was B button pressed? + jr nz, .updateCursorPosition +; A button was pressed + ld a, [wCurrentMenuItem] + cp $2 + jp z, .asm_f5963 + ld b, e + ld e, c + ld a, [wCurrentMenuItem] + and a + jr z, .updateCursorPosition + ld c, b + ld b, d + dec a + jr z, .updateCursorPosition + ld d, c + ld c, b +.updateCursorPosition + call Func_f59ec + 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, ColosseumPleaseWaitText + call PrintText + ld c, 50 + call DelayFrames + ld hl, wd732 + res 1, [hl] + ld a, [wDefaultMap] + ld [wDestinationMap], a + callfar 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 + jpfar SpecialEnterMap +.choseCancel + xor a + ld [wMenuJoypadPollCount], a + call Delay3 + callfar CloseLinkConnection + ld hl, ColosseumCanceledText + call PrintText + ld hl, wd72e + res 6, [hl] + ret + +.asm_f5963 + ld a, [wd11e] + and a + jr nz, .asm_f5974 + ld b, " " + ld c, " " + ld d, "▷" + ld e, " " + call Func_f59ec +.asm_f5974 + xor a + ld [wBuffer], a + ld a, $ff + ld [wSerialExchangeNybbleReceiveData], a + ld a, $b + ld [wLinkMenuSelectionSendBuffer], a + ld b, $78 +.loop + ldh a, [hSerialConnectionStatus] + cp $2 + call z, DelayFrame + dec b + jr z, .asm_f59b2 + call Serial_ExchangeNybble + call DelayFrame + ld a, [wSerialExchangeNybbleReceiveData] + inc a + jr z, .loop + ld b, $f +.loop2 + call DelayFrame + call Serial_ExchangeNybble + dec b + jr nz, .loop2 + ld b, $f +.loop3 + call DelayFrame + call Serial_SendZeroByte + dec b + jr nz, .loop3 + jr .asm_f59d6 + +.asm_f59b2 + xor a + ld [wUnknownSerialCounter], a + ld [wUnknownSerialCounter+1], a + ld a, [wd11e] + and a + jr z, .asm_f59cd + ld b, " " + ld c, " " + ld d, " " + ld e, "▷" + call Func_f59ec + jp .choseCancel + +.asm_f59cd + ld hl, ColosseumVersionText + call PrintText + jp .choseCancel + +.asm_f59d6 + ld b, " " + ld c, " " + ld d, "▷" + ld e, " " + call Func_f59ec + call Func_f531b + jp c, .choseCancel + ld a, $f0 + jp .next + +Func_f59ec:: + ld a, b + ldcoord_a 6, 5 + ld a, c + ldcoord_a 6, 7 + ld a, d + ldcoord_a 6, 9 + ld a, e + ldcoord_a 6, 11 + ld c, 40 + call DelayFrames + ret + +ColosseumWhereToText: + text_far _ColosseumWhereToText + text_end + +ColosseumPleaseWaitText: + text_far _ColosseumPleaseWaitText + text_end + +ColosseumCanceledText: + text_far _ColosseumCanceledText + text_end + +ColosseumVersionText: + text_far _ColosseumVersionText + text_end + +TextTerminator_f5a16: + text_end + +TradeCenterText: + db "TRADE CENTER" + next "COLOSSEUM" + next "COLOSSEUM2" + next "CANCEL@" diff --git a/engine/menus/main_menu.asm b/engine/menus/main_menu.asm new file mode 100755 index 00000000..7d81d2f6 --- /dev/null +++ b/engine/menus/main_menu.asm @@ -0,0 +1,300 @@ +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 + lb bc, 6, 13 + call TextBoxBorder + hlcoord 2, 2 + ld de, ContinueText + call PlaceString + jr .next2 +.noSaveFile + hlcoord 0, 0 + lb bc, 4, 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 + ld a, 64 ; audio? + ld [wPrinterSettings], a + ret + +Func_5cc1: +; unused? + ld a, $6d + cp $80 + ret c ; will always be executed + ld hl, NotEnoughMemoryText + call PrintText + ret + +NotEnoughMemoryText: + text_far _NotEnoughMemoryText + text_end + +StartNewGame: + ld hl, wd732 + res 1, [hl] +StartNewGameDebug: + call OakSpeech + ld a, $8 + ld [wPlayerMovingDirection], a + 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 + call Func_5cc1 + ld a, [wEnteringCableClub] + and a + ret nz + jp EnterMap + +ContinueText: + db "CONTINUE" + next "" + ; fallthrough + +NewGameText: + db "NEW GAME" + next "OPTION@" + +DisplayContinueGameInfo: + xor a + ldh [hAutoBGTransferEnabled], a + hlcoord 4, 7 + lb bc, 8, 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 + lb bc, 8, 14 + 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: + callfar DisplayOptionMenu_ + ret + +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 diff --git a/engine/menus/naming_screen.asm b/engine/menus/naming_screen.asm new file mode 100755 index 00000000..553c47d0 --- /dev/null +++ b/engine/menus/naming_screen.asm @@ -0,0 +1,508 @@ +AskName: + call SaveScreenTilesToBuffer1 + call GetPredefRegisters + push hl + ld a, [wIsInBattle] + dec a + hlcoord 0, 0 + lb bc, 4, 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 + lb bc, 9, 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: +; In Red/Blue, the bank for the ED_tile was defined incorrectly as bank0 +; Luckily, the MBC3 treats loading $0 into $2000-$2fff range as loading bank1 into $4000-$7fff range +; Because Yellow uses the MBC5, loading $0 into $2000 - $2fff range will load bank0 instead of bank1 and thus incorrectly load the tile +; Instead of defining the correct bank, GameFreak decided to simply copy the ED_Tile in the function during HBlank + ld de, ED_Tile + ld hl, vFont tile $70 + ld c, $4 ; number of copies needed +.waitForHBlankLoop + ldh a, [rSTAT] + and %10 ; in HBlank? + jr nz, .waitForHBlankLoop + ld a, [de] + ld [hli], a + ld [hli], a + inc de + ld a, [de] + ld [hli], a + ld [hli], a + inc de + dec c + jr nz, .waitForHBlankLoop + ret + +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?@" diff --git a/engine/menus/oaks_pc.asm b/engine/menus/oaks_pc.asm new file mode 100755 index 00000000..7743e5df --- /dev/null +++ b/engine/menus/oaks_pc.asm @@ -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 diff --git a/engine/menus/options.asm b/engine/menus/options.asm new file mode 100644 index 00000000..110bef2a --- /dev/null +++ b/engine/menus/options.asm @@ -0,0 +1,443 @@ +DisplayOptionMenu_: + call InitOptionsMenu +.optionMenuLoop + call JoypadLowSensitivity + ldh a, [hJoy5] + and START | B_BUTTON + jr nz, .exitOptionMenu + call OptionsControl + jr c, .dpadDelay + call GetOptionPointer + jr c, .exitOptionMenu +.dpadDelay + call OptionsMenu_UpdateCursorPosition + call DelayFrame + call DelayFrame + call DelayFrame + jr .optionMenuLoop +.exitOptionMenu + ret + +GetOptionPointer: + ld a, [wOptionsCursorLocation] + ld e, a + ld d, $0 + ld hl, OptionMenuJumpTable + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + jp hl ; jump to the function for the current highlighted option + +OptionMenuJumpTable: + dw OptionsMenu_TextSpeed + dw OptionsMenu_BattleAnimations + dw OptionsMenu_BattleStyle + dw OptionsMenu_SpeakerSettings + dw OptionsMenu_GBPrinterBrightness + dw OptionsMenu_Dummy + dw OptionsMenu_Dummy + dw OptionsMenu_Cancel + +OptionsMenu_TextSpeed: + call GetTextSpeed + ldh a, [hJoy5] + bit 4, a ; right + jr nz, .pressedRight + bit 5, a + jr nz, .pressedLeft + jr .asm_41ce0 +.pressedRight + ld a, c + cp $2 + jr c, .asm_41cca + ld c, $ff +.asm_41cca + inc c + ld a, e + jr .asm_41cd6 +.pressedLeft + ld a, c + and a + jr nz, .asm_41cd4 + ld c, $3 +.asm_41cd4 + dec c + ld a, d +.asm_41cd6 + ld b, a + ld a, [wOptions] + and $f0 + or b + ld [wOptions], a +.asm_41ce0 + ld b, $0 + ld hl, TextSpeedStringsPointerTable + add hl, bc + add hl, bc + ld e, [hl] + inc hl + ld d, [hl] + hlcoord 14, 2 + call PlaceString + and a + ret + +TextSpeedStringsPointerTable: + dw FastText + dw MidText + dw SlowText + +FastText: + db "FAST@" +MidText: + db "MID @" +SlowText: + db "SLOW@" + +GetTextSpeed: + ld a, [wOptions] + and $f + cp $5 + jr z, .slowTextOption + cp $1 + jr z, .fastTextOption +; mid text option + ld c, $1 + lb de, 1, 5 + ret +.slowTextOption + ld c, $2 + lb de, 3, 1 + ret +.fastTextOption + ld c, $0 + lb de, 5, 3 + ret + +OptionsMenu_BattleAnimations: + ldh a, [hJoy5] + and D_RIGHT | D_LEFT + jr nz, .asm_41d33 + ld a, [wOptions] + and $80 ; mask other bits + jr .asm_41d3b +.asm_41d33 + ld a, [wOptions] + xor $80 + ld [wOptions], a +.asm_41d3b + ld bc, $0 + sla a + rl c + ld hl, AnimationOptionStringsPointerTable + add hl, bc + add hl, bc + ld e, [hl] + inc hl + ld d, [hl] + hlcoord 14, 4 + call PlaceString + and a + ret + +AnimationOptionStringsPointerTable: + dw AnimationOnText + dw AnimationOffText + +AnimationOnText: + db "ON @" +AnimationOffText: + db "OFF@" + +OptionsMenu_BattleStyle: + ldh a, [hJoy5] + and D_LEFT | D_RIGHT + jr nz, .asm_41d6b + ld a, [wOptions] + and $40 ; mask other bits + jr .asm_41d73 +.asm_41d6b + ld a, [wOptions] + xor $40 + ld [wOptions], a +.asm_41d73 + ld bc, $0 + sla a + sla a + rl c + ld hl, BattleStyleOptionStringsPointerTable + add hl, bc + add hl, bc + ld e, [hl] + inc hl + ld d, [hl] + hlcoord 14, 6 + call PlaceString + and a + ret + +BattleStyleOptionStringsPointerTable: + dw BattleStyleShiftText + dw BattleStyleSetText + +BattleStyleShiftText: + db "SHIFT@" +BattleStyleSetText: + db "SET @" + +OptionsMenu_SpeakerSettings: + ld a, [wOptions] + and $30 + swap a + ld c, a + ldh a, [hJoy5] + bit 4, a + jr nz, .pressedRight + bit 5, a + jr nz, .pressedLeft + jr .asm_41dca +.pressedRight + ld a, c + inc a + and $3 + jr .asm_41dba +.pressedLeft + ld a, c + dec a + and $3 +.asm_41dba + ld c, a + swap a + ld b, a + xor a + ldh [rNR51], a + ld a, [wOptions] + and $cf + or b + ld [wOptions], a +.asm_41dca + ld b, $0 + ld hl, SpeakerOptionStringsPointerTable + add hl, bc + add hl, bc + ld e, [hl] + inc hl + ld d, [hl] + hlcoord 8, 8 + call PlaceString + and a + ret + +SpeakerOptionStringsPointerTable: + dw MonoSoundText + dw Earphone1SoundText + dw Earphone2SoundText + dw Earphone3SoundText + +MonoSoundText: + db "MONO @" +Earphone1SoundText: + db "EARPHONE1@" +Earphone2SoundText: + db "EARPHONE2@" +Earphone3SoundText: + db "EARPHONE3@" + +OptionsMenu_GBPrinterBrightness: + call Func_41e7b + ldh a, [hJoy5] + bit 4, a + jr nz, .pressedRight + bit 5, a + jr nz, .pressedLeft + jr .asm_41e32 +.pressedRight + ld a, c + cp $4 + jr c, .asm_41e22 + ld c, $ff +.asm_41e22 + inc c + ld a, e + jr .asm_41e2e +.pressedLeft + ld a, c + and a + jr nz, .asm_41e2c + ld c, $5 +.asm_41e2c + dec c + ld a, d +.asm_41e2e + ld b, a + ld [wPrinterSettings], a +.asm_41e32 + ld b, $0 + ld hl, GBPrinterOptionStringsPointerTable + add hl, bc + add hl, bc + ld e, [hl] + inc hl + ld d, [hl] + hlcoord 8, 10 + call PlaceString + and a + ret + +GBPrinterOptionStringsPointerTable: + dw LightestPrintText + dw LighterPrintText + dw NormalPrintText + dw DarkerPrintText + dw DarkestPrintText + +LightestPrintText: + db "LIGHTEST@" +LighterPrintText: + db "LIGHTER @" +NormalPrintText: + db "NORMAL @" +DarkerPrintText: + db "DARKER @" +DarkestPrintText: + db "DARKEST @" + +Func_41e7b: + ld a, [wPrinterSettings] + and a + jr z, .asm_41e93 + cp $20 + jr z, .asm_41e99 + cp $60 + jr z, .asm_41e9f + cp $7f + jr z, .asm_41ea5 + ld c, $2 + lb de, $20, $60 + ret +.asm_41e93 + ld c, $0 + lb de, $7f, $20 + ret +.asm_41e99 + ld c, $1 + lb de, $0, $40 + ret +.asm_41e9f + ld c, $3 + lb de, $40, $7f + ret +.asm_41ea5 + ld c, $4 + lb de, $60, $0 + ret + +OptionsMenu_Dummy: + and a + ret + +OptionsMenu_Cancel: + ldh a, [hJoy5] + and A_BUTTON + jr nz, .pressedCancel + and a + ret +.pressedCancel + scf + ret + +OptionsControl: + ld hl, wOptionsCursorLocation + ldh a, [hJoy5] + cp D_DOWN + jr z, .pressedDown + cp D_UP + jr z, .pressedUp + and a + ret +.pressedDown + ld a, [hl] + cp $7 + jr nz, .doNotWrapAround + ld [hl], $0 + scf + ret +.doNotWrapAround + cp $4 + jr c, .regularIncrement + ld [hl], $6 +.regularIncrement + inc [hl] + scf + ret +.pressedUp + ld a, [hl] + cp $7 + jr nz, .doNotMoveCursorToPrintOption + ld [hl], $4 + scf + ret +.doNotMoveCursorToPrintOption + and a + jr nz, .regularDecrement + ld [hl], $8 +.regularDecrement + dec [hl] + scf + ret + +OptionsMenu_UpdateCursorPosition: + hlcoord 1, 1 + ld de, SCREEN_WIDTH + ld c, 16 +.loop + ld [hl], " " + add hl, de + dec c + jr nz, .loop + hlcoord 1, 2 + ld bc, SCREEN_WIDTH * 2 + ld a, [wOptionsCursorLocation] + call AddNTimes + ld [hl], "▶" + ret + +InitOptionsMenu: + hlcoord 0, 0 + lb bc, SCREEN_HEIGHT - 2, SCREEN_WIDTH - 2 + call TextBoxBorder + hlcoord 2, 2 + ld de, AllOptionsText + call PlaceString + hlcoord 2, 16 + ld de, OptionMenuCancelText + call PlaceString + xor a + ld [wOptionsCursorLocation], a + ld c, 5 ; the number of options to loop through +.loop + push bc + call GetOptionPointer ; updates the next option + pop bc + ld hl, wOptionsCursorLocation + inc [hl] ; moves the cursor for the highlighted option + dec c + jr nz, .loop + xor a + ld [wOptionsCursorLocation], a + inc a + ldh [hAutoBGTransferEnabled], a + call Delay3 + ret + +AllOptionsText: + db "TEXT SPEED :" + next "ANIMATION :" + next "BATTLESTYLE:" + next "SOUND:" + next "PRINT:@" + +OptionMenuCancelText: + db "CANCEL@" diff --git a/engine/menus/party_menu.asm b/engine/menus/party_menu.asm new file mode 100755 index 00000000..32f47f6a --- /dev/null +++ b/engine/menus/party_menu.asm @@ -0,0 +1,314 @@ +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 + ldh a, [hPartyMonIndex] + ld [wWhichPokemon], a + callfar IsThisPartymonStarterPikachu_Party + jr nc, .regularMon + call CheckPikachuFollowingPlayer + jr z, .regularMon + ld a, $ff + ldh [hPartyMonIndex], a +.regularMon + farcall WriteMonPartySpriteOAMByPartyIndex ; place the appropriate pokemon icon + ld a, [wWhichPokemon] + 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, [hFlagsFFFA] + set 0, a + ldh [hFlagsFFFA], a + add hl, bc + predef DrawHP2 ; draw HP bar and prints current / max HP + ldh a, [hFlagsFFFA] + res 0, a + ldh [hFlagsFFFA], 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 + push hl + ld bc, 20 + 9 ; down 1 row and right 9 columns + 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 + pop hl + push hl + ld bc, 20 + 9 ; down 1 row and right 9 columns + 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 diff --git a/engine/menus/pc.asm b/engine/menus/pc.asm new file mode 100755 index 00000000..4c340e7b --- /dev/null +++ b/engine/menus/pc.asm @@ -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 diff --git a/engine/menus/players_pc.asm b/engine/menus/players_pc.asm new file mode 100755 index 00000000..1fac030b --- /dev/null +++ b/engine/menus/players_pc.asm @@ -0,0 +1,302 @@ +PlayerPC:: + 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 hl, wd730 + set 6, [hl] + ld a, [wParentMenuItem] + ld [wCurrentMenuItem], a + ld hl, wFlags_0xcd60 + set 5, [hl] + call LoadScreenTilesFromBuffer2 + hlcoord 0, 0 + lb bc, 8, 14 + 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 diff --git a/engine/menus/pokedex.asm b/engine/menus/pokedex.asm new file mode 100755 index 00000000..874fe50f --- /dev/null +++ b/engine/menus/pokedex.asm @@ -0,0 +1,745 @@ +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 + callfar LoadPokedexTilePatterns +.loop + ld b, SET_PAL_GENERIC + call RunPaletteCommand +.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 + dec b + jr z, .loop + 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, 8 + 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, 4 + 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 + ldh [hJoy7], 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 + dec a + jr z, .chosePrint +.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 + ld a, $1 + ldh [hJoy7], 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, 8 + ld de, 20 + lb bc, " ", 9 + call DrawTileLine ; cover up the menu cursor in the side menu + pop bc + jr .exitSideMenu + +.choseData + call ShowPokedexDataInternal + ld b, 0 + jr .exitSideMenu + +; play pokemon cry +.choseCry + ld a, [wd11e] + call GetCryData + call PlaySound + jr .handleMenuInput + +.choseArea + predef LoadTownMap_Nest ; display pokemon areas + ld b, 0 + jr .exitSideMenu + +.chosePrint + ldh a, [hTilesetType] + push af + xor a + ldh [hTilesetType], a + ld a, [wd11e] + ld [wcf91], a + callfar PrintPokedexEntry + xor a + ldh [hAutoBGTransferEnabled], a + call ClearScreen + pop af + ldh [hTilesetType], a + ld b, $3 + 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: + call Pokedex_DrawInterface +.loop + call Pokedex_PlacePokemonList + call GBPalNormal + call HandleMenuInput + bit BIT_B_BUTTON, a ; was the B button pressed? + jp nz, .buttonBPressed + bit BIT_A_BUTTON, a ; was the A button pressed? + jp nz, .buttonAPressed +.checkIfUpPressed + bit BIT_D_UP, 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 BIT_D_DOWN, a ; was Down pressed? + jr z, .checkIfRightPressed +.downPressed ; scroll down one row + ld a, [wDexMaxSeenMon] + cp a, 7 + jp c, .loop ; can't if the list is shorter than 7 + sub a, 7 + ld b, a + ld a, [wListScrollOffset] + cp b + jp z, .loop + inc a + ld [wListScrollOffset], a + jp .loop + +.checkIfRightPressed + bit BIT_D_RIGHT, a ; was Right pressed? + jr z, .checkIfLeftPressed +.rightPressed ; scroll down 7 rows + ld a, [wDexMaxSeenMon] + cp a, 7 + jp c, .loop ; can't if the list is shorter than 7 + sub a, 6 + ld b, a + ld a, [wListScrollOffset] + add a, 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 BIT_D_LEFT, a ; was Left pressed? + jr z, .buttonAPressed +.leftPressed + ld a, [wListScrollOffset] + sub a, 7 + ld [wListScrollOffset], a + jp nc, .loop + xor a + ld [wListScrollOffset], a + jp .loop + +.buttonAPressed + scf + ret + +.buttonBPressed + and a + ret + +Pokedex_DrawInterface: + xor a + ldh [hAutoBGTransferEnabled], a +; draw the horizontal line separating the seen and owned amounts from the menu + hlcoord 15, 6 + 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, 2 + 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, 5 + lb bc, 1, 3 + call PrintNumber ; print number of owned pokemon + hlcoord 16, 1 + ld de, PokedexSeenText + call PlaceString + hlcoord 16, 4 + ld de, PokedexOwnText + call PlaceString + hlcoord 1, 1 + ld de, PokedexContentsText + call PlaceString + hlcoord 16, 8 + 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 + ret + +DrawPokedexVerticalLine: + ld c, 9 ; height of line + ld de, SCREEN_WIDTH ; width of screen + ld a, $71 ; vertical line tile +.loop + ld [hl], a + add hl, de + xor a, 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 "PRNT" + next "QUIT@" + +Pokedex_PlacePokemonList: + 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 + ret + +; 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 + ldh a, [hTilesetType] + push af + xor a + ldh [hTilesetType], a + call GBPalWhiteOut ; zero all palettes + ld a, [wd11e] ; pokemon ID + ld [wcf91], a + push af + ld b, SET_PAL_POKEDEX + call RunPaletteCommand + pop af + ld [wd11e], a + call DrawDexEntryOnScreen + call c, Pokedex_PrintFlavorTextAtRow11 +.waitForButtonPress + call JoypadLowSensitivity + ldh a, [hJoy5] + and a, A_BUTTON | B_BUTTON + jr z, .waitForButtonPress + pop af + ldh [hTilesetType], 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 "@" + +DrawDexEntryOnScreen: + call ClearScreen + + 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 + ret z ; 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 + scf + ret + +Pokedex_PrintFlavorTextAtRow11: + bccoord 1, 11 +Pokedex_PrintFlavorTextAtBC: + ld a, %10 + ldh [hClearLetterPrintingDelayFlags], a + call TextCommandProcessor ; print pokedex description text + xor a + ldh [hClearLetterPrintingDelayFlags], a + ret + +Pokedex_PrepareDexEntryForPrinting: + hlcoord 0, 0 + ld de, SCREEN_WIDTH + lb bc, $66, $d + call DrawTileLine + hlcoord 19, 0 + ld b, $67 + call DrawTileLine + hlcoord 0, 13 + ld de, $1 + lb bc, $6f, SCREEN_WIDTH + call DrawTileLine + ld a, $6c + ldcoord_a 0, 13 + ld a, $6e + ldcoord_a 19, 13 + ld a, [wPrinterPokedexEntryTextPointer] + ld l, a + ld a, [wPrinterPokedexEntryTextPointer + 1] + ld h, a + bccoord 1, 1 + ldh a, [hFlagsFFFA] + set 3, a + ldh [hFlagsFFFA], a + call Pokedex_PrintFlavorTextAtBC + ldh a, [hFlagsFFFA] + res 3, a + ldh [hFlagsFFFA], a + ret + +; 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" diff --git a/engine/menus/save.asm b/engine/menus/save.asm new file mode 100755 index 00000000..bcb27ddf --- /dev/null +++ b/engine/menus/save.asm @@ -0,0 +1,682 @@ +LoadSAV: +;(if carry -> write +;"the file data is destroyed") + call ClearScreen + call LoadFontTilePatterns + call LoadTextBoxTilePatterns + call LoadSAV0 + jr c, .badsum + call LoadSAV1 + jr c, .badsum + call LoadSAV2 + jr c, .badsum + ld a, $2 ; good checksum + jr .goodsum +.badsum + ld hl, wd730 + push hl + set 6, [hl] + ld hl, FileDataDestroyedText + call PrintText + ld c, 100 + call DelayFrames + pop hl + res 6, [hl] + ld a, $1 ; bad checksum +.goodsum + ld [wSaveFileStatus], a + ret + +FileDataDestroyedText: + text_far _FileDataDestroyedText + text_end + +LoadSAV0: + call EnableSRAMAndLatchClockData + ld a, $1 + ld [MBC1SRamBank], a + ld hl, sPlayerName ; hero name located in SRAM + ld bc, sMainDataCheckSum - sPlayerName ; but here checks the full SAV + call SAVCheckSum + ld c, a + ld a, [sMainDataCheckSum] ; SAV's checksum + cp c + jp z, .checkSumsMatched + +; If the computed checksum didn't match the saved on, try again. + ld hl, sPlayerName + ld bc, sMainDataCheckSum - sPlayerName + call SAVCheckSum + ld c, a + ld a, [sMainDataCheckSum] ; SAV's checksum + cp c + jp nz, SAVBadCheckSum + +.checkSumsMatched + ld hl, sPlayerName + ld de, wPlayerName + ld bc, NAME_LENGTH + call CopyData + ld hl, sMainData + ld de, wMainDataStart + ld bc, wMainDataEnd - wMainDataStart + call CopyData + ld hl, wCurMapTileset + set 7, [hl] + ld hl, sSpriteData + ld de, wSpriteDataStart + ld bc, wSpriteDataEnd - wSpriteDataStart + call CopyData + ld a, [sTilesetType] + ldh [hTilesetType], a + ld hl, sCurBoxData + ld de, wBoxDataStart + ld bc, wBoxDataEnd - wBoxDataStart + call CopyData + and a + jp SAVGoodChecksum + +LoadSAV1: + call EnableSRAMAndLatchClockData + ld a, $1 + 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: + call EnableSRAMAndLatchClockData + ld a, $1 + 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: + call DisableSRAMAndPrepareClockData + ret + +LoadSAVIgnoreBadCheckSum: +; unused function that loads save data and ignores bad checksums + call LoadSAV0 + call LoadSAV1 + jp LoadSAV2 + +SaveSAV: + farcall PrintSaveScreenText + ld c, 10 + call DelayFrames + ld hl, WouldYouLikeToSaveText + call SaveSAVConfirm + and a ;|0 = Yes|1 = No| + ret nz + ld c, 10 + call DelayFrames + ld a, [wSaveFileStatus] + cp $1 + jr z, .save + call SAVCheckRandomID + jr z, .save + ld hl, OlderFileWillBeErasedText + call SaveSAVConfirm + and a + ret nz +.save + call SaveSAVtoSRAM + ld hl, SavingText + call PrintText + ld c, 128 + call DelayFrames + ld hl, GameSavedText + call PrintText + ld c, 10 + call DelayFrames + ld a, SFX_SAVE + call PlaySoundWaitForCurrent + call WaitForSoundToFinish + ld c, 30 + call DelayFrames + ret + +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 + +SavingText: + text_far _SavingText + text_end + +GameSavedText: + text_far _GameSavedText + text_end + +OlderFileWillBeErasedText: + text_far _OlderFileWillBeErasedText + text_end + +SaveSAVtoSRAM0: + call EnableSRAMAndLatchClockData + ld a, $1 + 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, [hTilesetType] + ld [sTilesetType], a + ld hl, sPlayerName + ld bc, sMainDataCheckSum - sPlayerName + call SAVCheckSum + ld [sMainDataCheckSum], a + call DisableSRAMAndPrepareClockData + ret + +SaveSAVtoSRAM1: +; stored pokémon + call EnableSRAMAndLatchClockData + ld a, $1 + 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 + call DisableSRAMAndPrepareClockData + ret + +SaveSAVtoSRAM2: + call EnableSRAMAndLatchClockData + ld a, $1 + 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, wPikachuHappiness + ld de, sMainData + $179 + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + ld hl, sPlayerName + ld bc, sMainDataCheckSum - sPlayerName + call SAVCheckSum + ld [sMainDataCheckSum], a + call DisableSRAMAndPrepareClockData + ret + +SaveSAVtoSRAM:: + ld a, $2 + ld [wSaveFileStatus], a + call SaveSAVtoSRAM0 + call SaveSAVtoSRAM1 + jp SaveSAVtoSRAM2 + +SAVCheckSum: +;Check Sum (result[1 byte] is complemented) + ld d, 0 +.loop + ld a, [hli] + add d + ld d, a + dec bc + ld a, b + or c + jr nz, .loop + ld a, d + cpl + ret + +CalcIndividualBoxCheckSums: + ld hl, sBox1 ; sBox7 + ld de, sBank2IndividualBoxChecksums ; sBank3IndividualBoxChecksums + ld b, NUM_BOXES / 2 +.loop + push bc + push de + ld bc, wBoxDataEnd - wBoxDataStart + call SAVCheckSum + pop de + ld [de], a + inc de + pop bc + dec b + jr nz, .loop + ret + +GetBoxSRAMLocation: +; in: a = box num +; out: b = box SRAM bank, hl = pointer to start of box + ld hl, BoxSRAMPointerTable + ld a, [wCurrentBoxNum] + and $7f + cp NUM_BOXES / 2 + ld b, 2 + jr c, .next + inc b + sub NUM_BOXES / 2 +.next + ld e, a + ld d, 0 + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + ret + +BoxSRAMPointerTable: + dw sBox1 ; sBox7 + dw sBox2 ; sBox8 + dw sBox3 ; sBox9 + dw sBox4 ; sBox10 + dw sBox5 ; sBox11 + dw sBox6 ; sBox12 + +ChangeBox:: + ld hl, WhenYouChangeBoxText + call PrintText + call YesNoChoice + ld a, [wCurrentMenuItem] + and a + ret nz ; return if No was chosen + ld hl, wCurrentBoxNum + bit 7, [hl] ; is it the first time player is changing the box? + call z, EmptyAllSRAMBoxes ; if so, empty all boxes in SRAM + call DisplayChangeBoxMenu + call UpdateSprites + ld hl, hFlagsFFFA + set 1, [hl] + call HandleMenuInput + ld hl, hFlagsFFFA + res 1, [hl] + bit 1, a ; pressed b + ret nz + ld a, $b6 + call PlaySoundWaitForCurrent + call WaitForSoundToFinish + 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 + ret + +WhenYouChangeBoxText: + text_far _WhenYouChangeBoxText + text_end + +CopyBoxToOrFromSRAM: +; copy an entire box from hl to de with b as the SRAM bank + push hl + call EnableSRAMAndLatchClockData + 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 + call DisableSRAMAndPrepareClockData + 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 + lb bc, 2, 9 + call TextBoxBorder + ld hl, ChooseABoxText + call PrintText + hlcoord 11, 0 + lb bc, 12, 7 + call TextBoxBorder + ld hl, hFlagsFFFA + set 2, [hl] + ld de, BoxNames + hlcoord 13, 1 + call PlaceString + ld hl, hFlagsFFFA + 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) + call EnableSRAMAndLatchClockData + ld a, 2 + ld [MBC1SRamBank], a + call EmptySRAMBoxesInBank + ld a, 3 + ld [MBC1SRamBank], a + call EmptySRAMBoxesInBank + call DisableSRAMAndPrepareClockData + ret + +EmptySRAMBoxesInBank: +; marks every box in the current SRAM bank as empty + ld hl, sBox1 ; sBox7 + call EmptySRAMBox + ld hl, sBox2 ; sBox8 + call EmptySRAMBox + ld hl, sBox3 ; sBox9 + call EmptySRAMBox + ld hl, sBox4 ; sBox10 + call EmptySRAMBox + ld hl, sBox5 ; sBox11 + call EmptySRAMBox + ld hl, sBox6 ; sBox12 + call EmptySRAMBox + ld hl, sBox1 ; sBox7 + ld bc, sBank2AllBoxesChecksum - sBox1 + call SAVCheckSum + ld [sBank2AllBoxesChecksum], a ; sBank3AllBoxesChecksum + call CalcIndividualBoxCheckSums + ret + +EmptySRAMBox: + xor a + ld [hli], a + dec a + ld [hl], a + ret + +GetMonCountsForAllBoxes: + ld hl, wBoxMonCounts + push hl + call EnableSRAMAndLatchClockData + ld a, $2 + ld [MBC1SRamBank], a + call GetMonCountsForBoxesInBank + ld a, $3 + ld [MBC1SRamBank], a + call GetMonCountsForBoxesInBank + call DisableSRAMAndPrepareClockData + pop hl + +; copy the count for the current box from WRAM + ld a, [wCurrentBoxNum] + and $7f + ld c, a + ld b, 0 + add hl, bc + ld a, [wNumInBox] + ld [hl], a + + ret + +GetMonCountsForBoxesInBank: + ld a, [sBox1] ; sBox7 + ld [hli], a + ld a, [sBox2] ; sBox8 + ld [hli], a + ld a, [sBox3] ; sBox9 + ld [hli], a + ld a, [sBox4] ; sBox10 + ld [hli], a + ld a, [sBox5] ; sBox11 + ld [hli], a + ld a, [sBox6] ; sBox12 + ld [hli], a + ret + +SAVCheckRandomID: +; checks if Sav file is the same by checking player's name 1st letter +; and the two random numbers generated at game beginning +; (which are stored at wPlayerID)s + call EnableSRAMAndLatchClockData + ld a, $01 + ld [MBC1SRamBank], a + ld a, [sPlayerName] + and a + jr z, .next + ld hl, sPlayerName + ld bc, sMainDataCheckSum - sPlayerName + call SAVCheckSum + ld c, a + ld a, [sMainDataCheckSum] + cp c + jr nz, .next + ld hl, sMainData + (wPlayerID - wMainDataStart) ; player ID + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wPlayerID] + cp l + jr nz, .next + ld a, [wPlayerID + 1] + cp h +.next + ld a, $00 + ld [MBC1SRamBankingMode], a + ld [MBC1SRamEnable], a + ret + +SaveHallOfFameTeams: + ld a, [wNumHoFTeams] + dec a + cp HOF_TEAM_CAPACITY + jr nc, .shiftHOFTeams + ld hl, sHallOfFame + ld bc, HOF_TEAM + call AddNTimes + ld e, l + ld d, h + ld hl, wHallOfFame + ld bc, HOF_TEAM + jr HallOfFame_Copy + +.shiftHOFTeams +; if the space designated for HOF teams is full, then shift all HOF teams to the next slot, making space for the new HOF team +; this deletes the last HOF team though + ld hl, sHallOfFame + HOF_TEAM + ld de, sHallOfFame + ld bc, HOF_TEAM * (HOF_TEAM_CAPACITY - 1) + call HallOfFame_Copy + ld hl, wHallOfFame + ld de, sHallOfFame + HOF_TEAM * (HOF_TEAM_CAPACITY - 1) + ld bc, HOF_TEAM + jr HallOfFame_Copy + +LoadHallOfFameTeams: + ld hl, sHallOfFame + ld bc, HOF_TEAM + ld a, [wHoFTeamIndex] + call AddNTimes + ld de, wHallOfFame + ld bc, HOF_TEAM + ; fallthrough + +HallOfFame_Copy: + call EnableSRAMAndLatchClockData + xor a + ld [MBC1SRamBank], a + call CopyData + call DisableSRAMAndPrepareClockData + ret + +ClearSAV: + call EnableSRAMAndLatchClockData + ld a, $4 +.loop + dec a + push af + call PadSRAM_FF + pop af + jr nz, .loop + call DisableSRAMAndPrepareClockData + ret + +PadSRAM_FF: + ld [MBC1SRamBank], a + ld hl, SRAM_Begin + ld bc, SRAM_End - SRAM_Begin + ld a, $ff + jp FillMemory + +EnableSRAMAndLatchClockData: + ld a, $1 + ld [MBC1SRamBankingMode], a + ld a, SRAM_ENABLE + ld [MBC1SRamEnable], a + ret + +DisableSRAMAndPrepareClockData: + ld a, SRAM_DISABLE + ld [MBC1SRamBankingMode], a + ld [MBC1SRamEnable], a + ret diff --git a/engine/menus/start_sub_menus.asm b/engine/menus/start_sub_menus.asm new file mode 100755 index 00000000..84583a69 --- /dev/null +++ b/engine/menus/start_sub_menus.asm @@ -0,0 +1,825 @@ +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? + jr nz, .asm_5d4c + call LoadFontTilePatterns + ld hl, wd72e + set 1, [hl] + jp StartMenu_Pokemon +.asm_5d4c + call Func_1510 + jp .goBackToMap +.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, [wcf91] + cp PIKACHU ; is this surfing pikachu? + jr z, .surfingPikachu + ld a, $1 + jr .continue +.surfingPikachu + ld a, $2 +.continue + ld [wd473], a + ld a, SURFBOARD + ld [wcf91], a + ld [wPseudoItemID], a + call UseItem + ld a, [wActionResultOrTookBattleTurn] + and a + jr z, .reloadNormalSprite + call GBPalWhiteOutWithDelay3 + jp .goBackToMap +.reloadNormalSprite + xor a + ld [wd473], a + jp .loop +.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] + call Func_1510 + 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 hl, wListPointer + ld [hl], wNumBagItems & $ff + inc hl + ld [hl], wNumBagItems / $100 ; 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, [hTilesetType] + push af + xor a + ldh [hTilesetType], a + call DrawTrainerInfo + predef DrawBadges ; draw badges + ld b, SET_PAL_TRAINER_CARD + call RunPaletteCommand + call GBPalNormal + call WaitForTextScrollButtonPress ; wait for button press + call GBPalWhiteOut + call LoadFontTilePatterns + call LoadScreenTilesFromBuffer2 ; restore saved screen + call RunDefaultPaletteCommand + call ReloadMapData + farcall DrawStartMenu ; XXX what difference does this make? + call LoadGBPal + pop af + ldh [hTilesetType], a + jp RedisplayStartMenu_DoNotDrawStartMenu + +; 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 FarCopyData + 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 FarCopyData + 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 FarCopyData + +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 diff --git a/engine/menus/swap_items.asm b/engine/menus/swap_items.asm new file mode 100644 index 00000000..2d506ce2 --- /dev/null +++ b/engine/menus/swap_items.asm @@ -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 diff --git a/engine/menus/text_box.asm b/engine/menus/text_box.asm new file mode 100644 index 00000000..7a315af2 --- /dev/null +++ b/engine/menus/text_box.asm @@ -0,0 +1,533 @@ +; 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 + lb bc, 1, 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 + xor a + ld [wTwoOptionMenuID], a + ld hl, wd730 + res 6, [hl] ; turn on the printing delay + 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 + lb bc, 5, 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" |