summaryrefslogtreecommitdiff
path: root/src/engine/duel
diff options
context:
space:
mode:
authorElectroDeoxys <ElectroDeoxys@gmail.com>2021-09-23 18:37:05 +0100
committerElectroDeoxys <ElectroDeoxys@gmail.com>2021-09-23 18:37:05 +0100
commitca15abf2ffc14fdb92079f6fccff09eb04305d18 (patch)
treed558ad09e12c7e6ed497f64573f858eb1fb9fa60 /src/engine/duel
parent8dee6b7a11e85d6d4b9f8ec9fb9d53a499fd37dc (diff)
Split bank1
Diffstat (limited to 'src/engine/duel')
-rw-r--r--src/engine/duel/core.asm8415
1 files changed, 8415 insertions, 0 deletions
diff --git a/src/engine/duel/core.asm b/src/engine/duel/core.asm
new file mode 100644
index 0000000..3b4b95c
--- /dev/null
+++ b/src/engine/duel/core.asm
@@ -0,0 +1,8415 @@
+; try to resume a saved duel from the main menu
+TryContinueDuel:
+ call SetupDuel
+ call LoadAndValidateDuelSaveData
+ ldtx hl, BackUpIsBrokenText
+ jr c, HandleFailedToContinueDuel
+; fallthrough
+
+_ContinueDuel:
+ ld hl, sp+$00
+ ld a, l
+ ld [wDuelReturnAddress], a
+ ld a, h
+ ld [wDuelReturnAddress + 1], a
+ call ClearJoypad
+ ld a, [wDuelTheme]
+ call PlaySong
+ xor a
+ ld [wDuelFinished], a
+ call DuelMainInterface
+ jp MainDuelLoop.between_turns
+
+HandleFailedToContinueDuel:
+ call DrawWideTextBox_WaitForInput
+ call ResetSerial
+ scf
+ ret
+
+; this function begins the duel after the opponent's graphics, name and deck have been introduced
+; loads both player's decks and sets up the variables and resources required to begin a duel.
+StartDuel_VSAIOpp:
+ ld a, PLAYER_TURN
+ ldh [hWhoseTurn], a
+ ld a, DUELIST_TYPE_PLAYER
+ ld [wPlayerDuelistType], a
+ ld a, [wNPCDuelDeckID]
+ ld [wOpponentDeckID], a
+ call LoadPlayerDeck
+ call SwapTurn
+ call LoadOpponentDeck
+ call SwapTurn
+ jr StartDuel
+
+StartDuel_VSLinkOpp:
+ ld a, MUSIC_DUEL_THEME_1
+ ld [wDuelTheme], a
+ ld hl, wOpponentName
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ld [wIsPracticeDuel], a
+; fallthrough
+
+StartDuel:
+ ld hl, sp+$0
+ ld a, l
+ ld [wDuelReturnAddress], a
+ ld a, h
+ ld [wDuelReturnAddress + 1], a
+ xor a
+ ld [wCurrentDuelMenuItem], a
+ call SetupDuel
+ ld a, [wNPCDuelPrizes]
+ ld [wDuelInitialPrizes], a
+ call InitVariablesToBeginDuel
+ ld a, [wDuelTheme]
+ call PlaySong
+ call HandleDuelSetup
+ ret c
+; fallthrough
+
+; the loop returns here after every turn switch
+MainDuelLoop:
+ xor a
+ ld [wCurrentDuelMenuItem], a
+ call UpdateSubstatusConditions_StartOfTurn
+ call DisplayDuelistTurnScreen
+ call HandleTurn
+
+.between_turns
+ call ExchangeRNG
+ ld a, [wDuelFinished]
+ or a
+ jr nz, .duel_finished
+ call UpdateSubstatusConditions_EndOfTurn
+ call HandleBetweenTurnsEvents
+ call Func_3b31
+ call ExchangeRNG
+ ld a, [wDuelFinished]
+ or a
+ jr nz, .duel_finished
+ ld hl, wDuelTurns
+ inc [hl]
+ ld a, [wDuelType]
+ cp DUELTYPE_PRACTICE
+ jr z, .practice_duel
+
+.next_turn
+ call SwapTurn
+ jr MainDuelLoop
+
+.practice_duel
+ ld a, [wIsPracticeDuel]
+ or a
+ jr z, .next_turn
+ ld a, [hl]
+ cp 15 ; the practice duel lasts 15 turns (8 player turns and 7 opponent turns)
+ jr c, .next_turn
+ xor a ; DUEL_WIN
+ ld [wDuelResult], a
+ ret
+
+.duel_finished
+ call ZeroObjectPositionsAndToggleOAMCopy
+ call EmptyScreen
+ ld a, BOXMSG_DECISION
+ call DrawDuelBoxMessage
+ ldtx hl, DecisionText
+ call DrawWideTextBox_WaitForInput
+ call EmptyScreen
+ ldh a, [hWhoseTurn]
+ push af
+ ld a, PLAYER_TURN
+ ldh [hWhoseTurn], a
+ call DrawDuelistPortraitsAndNames
+ call PrintDuelResultStats
+ pop af
+ ldh [hWhoseTurn], a
+ call Func_3b21
+
+; animate the duel result screen
+; load the correct music and animation depending on result
+ ld a, [wDuelFinished]
+ cp TURN_PLAYER_WON
+ jr z, .active_duelist_won_duel
+ cp TURN_PLAYER_LOST
+ jr z, .active_duelist_lost_duel
+ ld a, DUEL_ANIM_DUEL_DRAW
+ ld c, MUSIC_MATCH_DRAW
+ ldtx hl, DuelWasADrawText
+ jr .handle_duel_finished
+.active_duelist_won_duel
+ ldh a, [hWhoseTurn]
+ cp PLAYER_TURN
+ jr nz, .opponent_won_duel
+.player_won_duel
+ xor a ; DUEL_WIN
+ ld [wDuelResult], a
+ ld a, DUEL_ANIM_DUEL_WIN
+ ld c, MUSIC_MATCH_VICTORY
+ ldtx hl, WonDuelText
+ jr .handle_duel_finished
+.active_duelist_lost_duel
+ ldh a, [hWhoseTurn]
+ cp PLAYER_TURN
+ jr nz, .player_won_duel
+.opponent_won_duel
+ ld a, DUEL_LOSS
+ ld [wDuelResult], a
+ ld a, DUEL_ANIM_DUEL_LOSS
+ ld c, MUSIC_MATCH_LOSS
+ ldtx hl, LostDuelText
+
+.handle_duel_finished
+ call PlayDuelAnimation
+ ld a, c
+ call PlaySong
+ ld a, OPPONENT_TURN
+ ldh [hWhoseTurn], a
+ call DrawWideTextBox_PrintText
+ call EnableLCD
+.wait_song
+ call DoFrame
+ call AssertSongFinished
+ or a
+ jr nz, .wait_song
+ ld a, [wDuelFinished]
+ cp TURN_PLAYER_TIED
+ jr z, .tied_duel
+ call PlayDefaultSong
+ call WaitForWideTextBoxInput
+ call Func_3b31
+ call ResetSerial
+ ld a, PLAYER_TURN
+ ldh [hWhoseTurn], a
+ ret
+
+.tied_duel
+ call WaitForWideTextBoxInput
+ call Func_3b31
+ ld a, [wDuelTheme]
+ call PlaySong
+ ldtx hl, StartSuddenDeathMatchText
+ call DrawWideTextBox_WaitForInput
+ ld a, 1
+ ld [wDuelInitialPrizes], a
+ call InitVariablesToBeginDuel
+ ld a, [wDuelType]
+ cp DUELTYPE_LINK
+ jr z, .link_duel
+ ld a, PLAYER_TURN
+ ldh [hWhoseTurn], a
+ call HandleDuelSetup
+ jp MainDuelLoop
+.link_duel
+ call ExchangeRNG
+ ld h, PLAYER_TURN
+ ld a, [wSerialOp]
+ cp $29
+ jr z, .got_turn
+ ld h, OPPONENT_TURN
+.got_turn
+ ld a, h
+ ldh [hWhoseTurn], a
+ call HandleDuelSetup
+ jp nc, MainDuelLoop
+ ret
+
+; empty the screen, and setup text and graphics for a duel
+SetupDuel:
+ xor a ; SYM_SPACE
+ ld [wTileMapFill], a
+ call ZeroObjectPositionsAndToggleOAMCopy
+ call EmptyScreen
+ call LoadSymbolsFont
+ call SetDefaultPalettes
+ lb de, $38, $9f
+ call SetupText
+ call EnableLCD
+ ret
+
+; handle the turn of the duelist identified by hWhoseTurn.
+; if player's turn, display the animation of the player drawing the card at
+; hTempCardIndex_ff98, and save the duel state to SRAM.
+HandleTurn:
+ ld a, DUELVARS_DUELIST_TYPE
+ call GetTurnDuelistVariable
+ ld [wDuelistType], a
+ ld a, [wDuelTurns]
+ cp 2
+ jr c, .skip_let_evolve ; jump if it's the turn holder's first turn
+ call SetAllPlayAreaPokemonCanEvolve
+.skip_let_evolve
+ call InitVariablesToBeginTurn
+ call DisplayDrawOneCardScreen
+ call DrawCardFromDeck
+ jr nc, .deck_not_empty
+ ld a, TURN_PLAYER_LOST
+ ld [wDuelFinished], a
+ ret
+
+.deck_not_empty
+ ldh [hTempCardIndex_ff98], a
+ call AddCardToHand
+ ld a, [wDuelistType]
+ cp DUELIST_TYPE_PLAYER
+ jr z, .player_turn
+
+; opponent's turn
+ call SwapTurn
+ call IsClairvoyanceActive
+ call SwapTurn
+ call c, DisplayPlayerDrawCardScreen
+ jr DuelMainInterface
+
+; player's turn
+.player_turn
+ call DisplayPlayerDrawCardScreen
+ call SaveDuelStateToSRAM
+; fallthrough
+
+; when a practice duel turn needs to be restarted because the player did not
+; follow the instructions correctly, the game loops back here
+RestartPracticeDuelTurn:
+ ld a, PRACTICEDUEL_PRINT_TURN_INSTRUCTIONS
+ call DoPracticeDuelAction
+; fallthrough
+
+; print the main interface during a duel, including background, Pokemon, HUDs and a text box.
+; the bottom text box changes depending on whether the turn belongs to the player (show the duel menu),
+; an AI opponent (print "Waiting..." and a reduced menu) or a link opponent (print "<Duelist> is thinking").
+DuelMainInterface:
+ call DrawDuelMainScene
+ ld a, [wDuelistType]
+ cp DUELIST_TYPE_PLAYER
+ jr z, PrintDuelMenuAndHandleInput
+ cp DUELIST_TYPE_LINK_OPP
+ jp z, DoLinkOpponentTurn
+ ; DUELIST_TYPE_AI_OPP
+ xor a
+ ld [wVBlankCounter], a
+ ld [wSkipDuelistIsThinkingDelay], a
+ ldtx hl, DuelistIsThinkingText
+ call DrawWideTextBox_PrintTextNoDelay
+ call AIDoAction_Turn
+ ld a, $ff
+ ld [wPlayerAttackingCardIndex], a
+ ld [wPlayerAttackingAttackIndex], a
+ ret
+
+PrintDuelMenuAndHandleInput:
+ call DrawWideTextBox
+ ld hl, DuelMenuData
+ call PlaceTextItems
+.menu_items_printed
+ call SaveDuelData
+ ld a, [wDuelFinished]
+ or a
+ ret nz
+ ld a, [wCurrentDuelMenuItem]
+ call SetMenuItem
+
+.handle_input
+ call DoFrame
+ ldh a, [hKeysHeld]
+ and B_BUTTON
+ jr z, .b_not_held
+ ldh a, [hKeysPressed]
+ bit D_UP_F, a
+ jr nz, DuelMenuShortcut_OpponentPlayArea
+ bit D_DOWN_F, a
+ jr nz, DuelMenuShortcut_PlayerPlayArea
+ bit D_LEFT_F, a
+ jr nz, DuelMenuShortcut_PlayerDiscardPile
+ bit D_RIGHT_F, a
+ jr nz, DuelMenuShortcut_OpponentDiscardPile
+ bit START_F, a
+ jp nz, DuelMenuShortcut_OpponentActivePokemon
+
+.b_not_held
+ ldh a, [hKeysPressed]
+ and START
+ jp nz, DuelMenuShortcut_PlayerActivePokemon
+ ldh a, [hKeysPressed]
+ bit SELECT_F, a
+ jp nz, DuelMenuShortcut_BothActivePokemon
+ ld a, [wDebugSkipDuelMenuInput]
+ or a
+ jr nz, .handle_input
+ call HandleDuelMenuInput
+ ld a, e
+ ld [wCurrentDuelMenuItem], a
+ jr nc, .handle_input
+ ldh a, [hCurMenuItem]
+ ld hl, DuelMenuFunctionTable
+ jp JumpToFunctionInTable
+
+DuelMenuFunctionTable:
+ dw DuelMenu_Hand
+ dw DuelMenu_Attack
+ dw DuelMenu_Check
+ dw DuelMenu_PkmnPower
+ dw DuelMenu_Retreat
+ dw DuelMenu_Done
+
+DrawCardFromDeckToHand:
+ call DrawCardFromDeck
+ call nc, AddCardToHand
+ ld a, OPPACTION_DRAW_CARD
+ call SetOppAction_SerialSendDuelData
+ jp PrintDuelMenuAndHandleInput.menu_items_printed
+
+; triggered by pressing B + UP in the duel menu
+DuelMenuShortcut_OpponentPlayArea:
+ call OpenNonTurnHolderPlayAreaScreen
+ jp DuelMainInterface
+
+; triggered by pressing B + DOWN in the duel menu
+DuelMenuShortcut_PlayerPlayArea:
+ call OpenTurnHolderPlayAreaScreen
+ jp DuelMainInterface
+
+; triggered by pressing B + RIGHT in the duel menu
+DuelMenuShortcut_OpponentDiscardPile:
+ call OpenNonTurnHolderDiscardPileScreen
+ jp c, PrintDuelMenuAndHandleInput
+ jp DuelMainInterface
+
+; triggered by pressing B + LEFT in the duel menu
+DuelMenuShortcut_PlayerDiscardPile:
+ call OpenTurnHolderDiscardPileScreen
+ jp c, PrintDuelMenuAndHandleInput
+ jp DuelMainInterface
+
+; draw the non-turn holder's play area screen
+OpenNonTurnHolderPlayAreaScreen:
+ call SwapTurn
+ call OpenTurnHolderPlayAreaScreen
+ call SwapTurn
+ ret
+
+; draw the turn holder's play area screen
+OpenTurnHolderPlayAreaScreen:
+ call HasAlivePokemonInPlayArea
+ jp OpenPlayAreaScreenForViewing
+
+; draw the non-turn holder's discard pile screen
+OpenNonTurnHolderDiscardPileScreen:
+ call SwapTurn
+ call OpenDiscardPileScreen
+ jp SwapTurn
+
+; draw the turn holder's discard pile screen
+OpenTurnHolderDiscardPileScreen:
+ jp OpenDiscardPileScreen
+
+; draw the non-turn holder's hand screen. simpler version of OpenPlayerHandScreen
+; used only for checking the cards rather than for playing them.
+OpenNonTurnHolderHandScreen_Simple:
+ call SwapTurn
+ call OpenTurnHolderHandScreen_Simple
+ jp SwapTurn
+
+; draw the turn holder's hand screen. simpler version of OpenPlayerHandScreen
+; used only for checking the cards rather than for playing them.
+; used for example in the "Your Play Area" screen of the Check menu
+OpenTurnHolderHandScreen_Simple:
+ call CreateHandCardList
+ jr c, .no_cards_in_hand
+ call InitAndDrawCardListScreenLayout
+ ld a, START + A_BUTTON
+ ld [wNoItemSelectionMenuKeys], a
+ jp DisplayCardList
+.no_cards_in_hand
+ ldtx hl, NoCardsInHandText
+ jp DrawWideTextBox_WaitForInput
+
+; triggered by pressing B + START in the duel menu
+DuelMenuShortcut_OpponentActivePokemon:
+ call SwapTurn
+ call OpenActivePokemonScreen
+ call SwapTurn
+ jp DuelMainInterface
+
+; triggered by pressing START in the duel menu
+DuelMenuShortcut_PlayerActivePokemon:
+ call OpenActivePokemonScreen
+ jp DuelMainInterface
+
+; draw the turn holder's active Pokemon screen if it exists
+OpenActivePokemonScreen:
+ ld a, DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ cp -1
+ ret z
+ call GetCardIDFromDeckIndex
+ call LoadCardDataToBuffer1_FromCardID
+ ld hl, wCurPlayAreaSlot
+ xor a
+ ld [hli], a
+ ld [hl], a ; wCurPlayAreaY
+ call OpenCardPage_FromCheckPlayArea
+ ret
+
+; triggered by selecting the "Pkmn Power" item in the duel menu
+DuelMenu_PkmnPower:
+ call Func_6431
+ jp c, DuelMainInterface
+ call UseAttackOrPokemonPower
+ jp DuelMainInterface
+
+; triggered by selecting the "Done" item in the duel menu
+DuelMenu_Done:
+ ld a, PRACTICEDUEL_REPEAT_INSTRUCTIONS
+ call DoPracticeDuelAction
+ ; always jumps on practice duel (no action requires player to select Done)
+ jp c, RestartPracticeDuelTurn
+ ld a, OPPACTION_FINISH_NO_ATTACK
+ call SetOppAction_SerialSendDuelData
+ call ClearNonTurnTemporaryDuelvars
+ ret
+
+; triggered by selecting the "Retreat" item in the duel menu
+DuelMenu_Retreat:
+ ld a, DUELVARS_ARENA_CARD_STATUS
+ call GetTurnDuelistVariable
+ and CNF_SLP_PRZ
+ cp CONFUSED
+ ldh [hTemp_ffa0], a
+ jr nz, .not_confused
+ ld a, [wGotHeadsFromConfusionCheckDuringRetreat]
+ or a
+ jr nz, .unable_due_to_confusion
+ call CheckAbleToRetreat
+ jr c, .unable_to_retreat
+ call DisplayRetreatScreen
+ jr c, .done
+ ldtx hl, SelectPkmnOnBenchToSwitchWithActiveText
+ call DrawWideTextBox_WaitForInput
+ call OpenPlayAreaScreenForSelection
+ jr c, .done
+ ld [wBenchSelectedPokemon], a
+ ld a, [wBenchSelectedPokemon]
+ ldh [hTempPlayAreaLocation_ffa1], a
+ ld a, OPPACTION_ATTEMPT_RETREAT
+ call SetOppAction_SerialSendDuelData
+ call AttemptRetreat
+ jr nc, .done
+ call DrawDuelMainScene
+
+.unable_due_to_confusion
+ ldtx hl, UnableToRetreatText
+ call DrawWideTextBox_WaitForInput
+ jp PrintDuelMenuAndHandleInput
+
+.not_confused
+ ; note that the energy cards are discarded (DiscardRetreatCostCards), then returned
+ ; (ReturnRetreatCostCardsToArena), then discarded again for good (AttemptRetreat).
+ ; It's done this way so that the retreating Pokemon is listed with its energies updated
+ ; when the Play Area screen is shown to select the Pokemon to switch to. The reason why
+ ; AttemptRetreat is responsible for discarding the energy cards is because, if the
+ ; Pokemon is confused, it may not be able to retreat, so they cannot be discarded earlier.
+ call CheckAbleToRetreat
+ jr c, .unable_to_retreat
+ call DisplayRetreatScreen
+ jr c, .done
+ call DiscardRetreatCostCards
+ ldtx hl, SelectPkmnOnBenchToSwitchWithActiveText
+ call DrawWideTextBox_WaitForInput
+ call OpenPlayAreaScreenForSelection
+ ld [wBenchSelectedPokemon], a
+ ldh [hTempPlayAreaLocation_ffa1], a
+ push af
+ call ReturnRetreatCostCardsToArena
+ pop af
+ jp c, DuelMainInterface
+ ld a, OPPACTION_ATTEMPT_RETREAT
+ call SetOppAction_SerialSendDuelData
+ call AttemptRetreat
+
+.done
+ jp DuelMainInterface
+
+.unable_to_retreat
+ call DrawWideTextBox_WaitForInput
+ jp PrintDuelMenuAndHandleInput
+
+; triggered by selecting the "Hand" item in the duel menu
+DuelMenu_Hand:
+ ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND
+ call GetTurnDuelistVariable
+ or a
+ jr nz, OpenPlayerHandScreen
+ ldtx hl, NoCardsInHandText
+ call DrawWideTextBox_WaitForInput
+ jp PrintDuelMenuAndHandleInput
+
+; draw the screen for the player's hand and handle user input to for example check
+; a card or attempt to use a card, playing the card if possible in that case.
+OpenPlayerHandScreen:
+ call CreateHandCardList
+ call InitAndDrawCardListScreenLayout
+ ldtx hl, PleaseSelectHandText
+ call SetCardListInfoBoxText
+ ld a, PLAY_CHECK
+ ld [wCardListItemSelectionMenuType], a
+.handle_input
+ call DisplayCardList
+ push af
+ ld a, [wSortCardListByID]
+ or a
+ call nz, SortHandCardsByID
+ pop af
+ jp c, DuelMainInterface
+ ldh a, [hTempCardIndex_ff98]
+ call LoadCardDataToBuffer1_FromDeckIndex
+ ld a, [wLoadedCard1Type]
+ ld c, a
+ bit TYPE_TRAINER_F, c
+ jr nz, .trainer_card
+ bit TYPE_ENERGY_F, c
+ jr nz, PlayEnergyCard
+ call PlayPokemonCard
+ jr c, ReloadCardListScreen ; jump if card not played
+ jp DuelMainInterface
+.trainer_card
+ call PlayTrainerCard
+ jr c, ReloadCardListScreen ; jump if card not played
+ jp DuelMainInterface
+
+; play the energy card with deck index at hTempCardIndex_ff98
+; c contains the type of energy card being played
+PlayEnergyCard:
+ ld a, c
+ cp TYPE_ENERGY_WATER
+ jr nz, .not_water_energy
+ call IsRainDanceActive
+ jr c, .rain_dance_active
+
+.not_water_energy
+ ld a, [wAlreadyPlayedEnergy]
+ or a
+ jr nz, .already_played_energy
+ call HasAlivePokemonInPlayArea
+ call OpenPlayAreaScreenForSelection ; choose card to play energy card on
+ jp c, DuelMainInterface ; exit if no card was chosen
+.play_energy_set_played
+ ld a, 1
+ ld [wAlreadyPlayedEnergy], a
+.play_energy
+ ldh a, [hTempPlayAreaLocation_ff9d]
+ ldh [hTempPlayAreaLocation_ffa1], a
+ ld e, a
+ ldh a, [hTempCardIndex_ff98]
+ ldh [hTemp_ffa0], a
+ call PutHandCardInPlayArea
+ call PrintPlayAreaCardList_EnableLCD
+ ld a, OPPACTION_PLAY_ENERGY
+ call SetOppAction_SerialSendDuelData
+ call PrintAttachedEnergyToPokemon
+ jp DuelMainInterface
+
+.rain_dance_active
+ call HasAlivePokemonInPlayArea
+ call OpenPlayAreaScreenForSelection ; choose card to play energy card on
+ jp c, DuelMainInterface ; exit if no card was chosen
+ call CheckRainDanceScenario
+ jr c, .play_energy
+ ld a, [wAlreadyPlayedEnergy]
+ or a
+ jr z, .play_energy_set_played
+ ldtx hl, MayOnlyAttachOneEnergyCardText
+ call DrawWideTextBox_WaitForInput
+ jp OpenPlayerHandScreen
+
+.already_played_energy
+ ldtx hl, MayOnlyAttachOneEnergyCardText
+ call DrawWideTextBox_WaitForInput
+; fallthrough
+
+; reload the card list screen after the card trying to play couldn't be played
+ReloadCardListScreen:
+ call CreateHandCardList
+ ; skip doing the things that have already been done when initially opened
+ call DrawCardListScreenLayout
+ jp OpenPlayerHandScreen.handle_input
+
+; place a basic Pokemon card on the arena or bench, or place an stage 1 or 2
+; Pokemon card over a Pokemon card already in play to evolve it.
+; the card to use is loaded in wLoadedCard1 and its deck index is at hTempCardIndex_ff98.
+; return nc if the card was played, carry if it wasn't.
+PlayPokemonCard:
+ ld a, [wLoadedCard1Stage]
+ or a ; BASIC
+ jr nz, .try_evolve ; jump if the card being played is a Stage 1 or 2 Pokemon
+ ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA
+ call GetTurnDuelistVariable
+ cp MAX_PLAY_AREA_POKEMON
+ jr nc, .no_space
+ ldh a, [hTempCardIndex_ff98]
+ ldh [hTemp_ffa0], a
+ call PutHandPokemonCardInPlayArea
+ ldh [hTempPlayAreaLocation_ff9d], a
+ add DUELVARS_ARENA_CARD_STAGE
+ call GetTurnDuelistVariable
+ ld [hl], BASIC
+ ld a, OPPACTION_PLAY_BASIC_PKMN
+ call SetOppAction_SerialSendDuelData
+ ldh a, [hTempCardIndex_ff98]
+ call LoadCardDataToBuffer1_FromDeckIndex
+ ld a, 20
+ call CopyCardNameAndLevel
+ ld [hl], $00
+ ld hl, $0000
+ call LoadTxRam2
+ ldtx hl, PlacedOnTheBenchText
+ call DrawWideTextBox_WaitForInput
+ call Func_161e
+ or a
+ ret
+
+.no_space
+ ldtx hl, NoSpaceOnTheBenchText
+ call DrawWideTextBox_WaitForInput
+ scf
+ ret
+
+.try_evolve
+ ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA
+ call GetTurnDuelistVariable
+ ld c, a
+ ldh a, [hTempCardIndex_ff98]
+ ld d, a
+ ld e, PLAY_AREA_ARENA
+ push de
+ push bc
+.next_play_area_pkmn
+ push de
+ call CheckIfCanEvolveInto
+ pop de
+ jr nc, .can_evolve
+ inc e
+ dec c
+ jr nz, .next_play_area_pkmn
+ pop bc
+ pop de
+.find_cant_evolve_reason_loop
+ push de
+ call CheckIfCanEvolveInto
+ pop de
+ ldtx hl, CantEvolvePokemonInSameTurnItsPlacedText
+ jr nz, .cant_same_turn
+ inc e
+ dec c
+ jr nz, .find_cant_evolve_reason_loop
+ ldtx hl, NoPokemonCapableOfEvolvingText
+.cant_same_turn
+ ; don't bother opening the selection screen if there are no pokemon capable of evolving
+ call DrawWideTextBox_WaitForInput
+ scf
+ ret
+
+.can_evolve
+ pop bc
+ pop de
+ call IsPrehistoricPowerActive
+ jr c, .prehistoric_power
+ call HasAlivePokemonInPlayArea
+.try_evolve_loop
+ call OpenPlayAreaScreenForSelection
+ jr c, .done
+ ldh a, [hTempCardIndex_ff98]
+ ldh [hTemp_ffa0], a
+ ldh a, [hTempPlayAreaLocation_ff9d]
+ ldh [hTempPlayAreaLocation_ffa1], a
+ call EvolvePokemonCardIfPossible
+ jr c, .try_evolve_loop ; jump if evolution wasn't successful somehow
+ ld a, OPPACTION_EVOLVE_PKMN
+ call SetOppAction_SerialSendDuelData
+ call PrintPlayAreaCardList_EnableLCD
+ call PrintPokemonEvolvedIntoPokemon
+ call Func_161e
+.done
+ or a
+ ret
+
+.prehistoric_power
+ call DrawWideTextBox_WaitForInput
+ scf
+ ret
+
+; triggered by selecting the "Check" item in the duel menu
+DuelMenu_Check:
+ call Func_3b31
+ call OpenDuelCheckMenu
+ jp DuelMainInterface
+
+; triggered by pressing SELECT in the duel menu
+DuelMenuShortcut_BothActivePokemon:
+ call Func_3b31
+ call Func_4597
+ jp DuelMainInterface
+
+Func_4597:
+ call OpenInPlayAreaScreen_FromSelectButton
+ ret c
+ call .Func_45a9
+ ret c
+ call SwapTurn
+ call .Func_45a9
+ call SwapTurn
+ ret
+
+.Func_45a9
+ call HasAlivePokemonInPlayArea
+ ld a, $02
+ ld [wcbd4], a
+ call OpenPlayAreaScreenForViewing
+ ldh a, [hKeysPressed]
+ and B_BUTTON
+ ret z
+ scf
+ ret
+
+; check if the turn holder's arena Pokemon is unable to retreat due to
+; some status condition or due the bench containing no alive Pokemon.
+; return carry if unable, nc if able.
+CheckAbleToRetreat:
+ call CheckCantRetreatDueToAcid
+ ret c
+ call CheckIfActiveCardParalyzedOrAsleep
+ ret c
+ call HasAlivePokemonInBench
+ jr c, .unable_to_retreat
+ ld a, DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ call GetCardIDFromDeckIndex
+ call LoadCardDataToBuffer1_FromCardID
+ ld a, [wLoadedCard1Type]
+ cp TYPE_TRAINER
+ jr z, .unable_to_retreat
+ call CheckIfEnoughEnergiesToRetreat
+ jr c, .not_enough_energies
+ or a
+ ret
+.not_enough_energies
+ ld a, [wEnergyCardsRequiredToRetreat]
+ ld l, a
+ ld h, $00
+ call LoadTxRam3
+ ldtx hl, EnergyCardsRequiredToRetreatText
+ jr .done
+.unable_to_retreat
+ ldtx hl, UnableToRetreatText
+.done
+ scf
+ ret
+
+; check if the turn holder's arena Pokemon has enough energies attached to it
+; in order to retreat. Return carry if it doesn't.
+; load amount of energies required to wEnergyCardsRequiredToRetreat.
+CheckIfEnoughEnergiesToRetreat:
+ ld e, PLAY_AREA_ARENA
+ call GetPlayAreaCardAttachedEnergies
+ xor a
+ ldh [hTempPlayAreaLocation_ff9d], a
+ call GetPlayAreaCardRetreatCost
+ ld [wEnergyCardsRequiredToRetreat], a
+ ld c, a
+ ld a, [wTotalAttachedEnergies]
+ cp c
+ ret c
+ ld [wNumRetreatEnergiesSelected], a
+ ld a, c
+ ld [wEnergyCardsRequiredToRetreat], a
+ or a
+ ret
+
+; display the screen that prompts the player to select energy cards to discard
+; in order to retreat a Pokemon card. also handle input in order to display
+; the amount of energy cards already selected, and return whenever enough
+; energy cards have been selected or if the player declines to retreat.
+DisplayRetreatScreen:
+ ld a, $ff
+ ldh [hTempRetreatCostCards], a
+ ld a, [wEnergyCardsRequiredToRetreat]
+ or a
+ ret z ; return if no energy cards are required at all
+ xor a
+ ld [wNumRetreatEnergiesSelected], a
+ call CreateArenaOrBenchEnergyCardList
+ call SortCardsInDuelTempListByID
+ ld a, LOW(hTempRetreatCostCards)
+ ld [wTempRetreatCostCardsPos], a
+ xor a
+ call DisplayEnergyDiscardScreen
+ ld a, [wEnergyCardsRequiredToRetreat]
+ ld [wEnergyDiscardMenuDenominator], a
+.select_energies_loop
+ ld a, [wNumRetreatEnergiesSelected]
+ ld [wEnergyDiscardMenuNumerator], a
+ call HandleEnergyDiscardMenuInput
+ ret c
+ ldh a, [hTempCardIndex_ff98]
+ call LoadCardDataToBuffer2_FromDeckIndex
+ ; append selected energy card to hTempRetreatCostCards
+ ld hl, wTempRetreatCostCardsPos
+ ld c, [hl]
+ inc [hl]
+ ldh a, [hTempCardIndex_ff98]
+ ld [$ff00+c], a
+ ; accumulate selected energy card
+ ld c, 1
+ ld a, [wLoadedCard2Type]
+ cp TYPE_ENERGY_DOUBLE_COLORLESS
+ jr nz, .not_double
+ inc c
+.not_double
+ ld hl, wNumRetreatEnergiesSelected
+ ld a, [hl]
+ add c
+ ld [hl], a
+ ld hl, wEnergyCardsRequiredToRetreat
+ cp [hl]
+ jr nc, .enough
+ ; not enough energies selected yet
+ ldh a, [hTempCardIndex_ff98]
+ call RemoveCardFromDuelTempList
+ call DisplayEnergyDiscardMenu
+ jr .select_energies_loop
+.enough
+ ; terminate hTempRetreatCostCards array with $ff
+ ld a, [wTempRetreatCostCardsPos]
+ ld c, a
+ ld a, $ff
+ ld [$ff00+c], a
+ or a
+ ret
+
+; display the screen that prompts the player to select energy cards to discard
+; in order to retreat a Pokemon card or use an attack like Ember. includes the
+; card's information and a menu to select the attached energy cards to discard.
+; input: a = PLAY_AREA_* of the Pokemon trying to discard energies from.
+DisplayEnergyDiscardScreen:
+ ld [wcbe0], a
+ call EmptyScreen
+ call LoadDuelCardSymbolTiles
+ call LoadDuelFaceDownCardTiles
+ ld a, [wcbe0]
+ ld hl, wCurPlayAreaSlot
+ ld [hli], a
+ ld [hl], 0 ; wCurPlayAreaY
+ call PrintPlayAreaCardInformation
+ xor a
+ ld [wEnergyDiscardMenuNumerator], a
+ inc a
+ ld [wEnergyDiscardMenuDenominator], a
+; fallthrough
+
+; display the menu that belongs to the energy discard screen that lets the player
+; select energy cards attached to a Pokemon card in order to retreat it or use
+; an attack like Ember, Flamethrower...
+DisplayEnergyDiscardMenu:
+ lb de, 0, 3
+ lb bc, 20, 10
+ call DrawRegularTextBox
+ ldtx hl, ChooseEnergyCardToDiscardText
+ call DrawWideTextBox_PrintTextNoDelay
+ call EnableLCD
+ call CountCardsInDuelTempList
+ ld hl, EnergyDiscardCardListParameters
+ lb de, 0, 0 ; initial page scroll offset, initial item (in the visible page)
+ call PrintCardListItems
+ ld a, 4
+ ld [wCardListIndicatorYPosition], a
+ ret
+
+; if [wEnergyDiscardMenuDenominator] non-0:
+ ; prints "[wEnergyDiscardMenuNumerator]/[wEnergyDiscardMenuDenominator]" at 16,16
+ ; where [wEnergyDiscardMenuNumerator] is the number of energy cards already selected to discard
+ ; and [wEnergyDiscardMenuDenominator] is the total number of energies that are required to discard.
+; if [wEnergyDiscardMenuDenominator] == 0:
+ ; prints only "[wEnergyDiscardMenuNumerator]"
+HandleEnergyDiscardMenuInput:
+ lb bc, 16, 16
+ ld a, [wEnergyDiscardMenuDenominator]
+ or a
+ jr z, .print_single_number
+ ld a, [wEnergyDiscardMenuNumerator]
+ add SYM_0
+ call WriteByteToBGMap0
+ inc b
+ ld a, SYM_SLASH
+ call WriteByteToBGMap0
+ inc b
+ ld a, [wEnergyDiscardMenuDenominator]
+ add SYM_0
+ call WriteByteToBGMap0
+ jr .wait_input
+.print_single_number
+ ld a, [wEnergyDiscardMenuNumerator]
+ inc b
+ call WriteTwoDigitNumberInTxSymbolFormat
+.wait_input
+ call DoFrame
+ call HandleCardListInput
+ jr nc, .wait_input
+ cp $ff ; B pressed?
+ jr z, .return_carry
+ call GetCardInDuelTempList_OnlyDeckIndex
+ or a
+ ret
+.return_carry
+ scf
+ ret
+
+EnergyDiscardCardListParameters:
+ db 1, 5 ; cursor x, cursor y
+ db 4 ; item x
+ db 14 ; maximum length, in tiles, occupied by the name and level string of each card in the list
+ db 4 ; number of items selectable without scrolling
+ db SYM_CURSOR_R ; cursor tile number
+ db SYM_SPACE ; tile behind cursor
+ dw NULL ; function pointer if non-0
+
+; triggered by selecting the "Attack" item in the duel menu
+DuelMenu_Attack:
+ call HandleCantAttackSubstatus
+ jr c, .alert_cant_attack_and_cancel_menu
+ call CheckIfActiveCardParalyzedOrAsleep
+ jr nc, .can_attack
+.alert_cant_attack_and_cancel_menu
+ call DrawWideTextBox_WaitForInput
+ jp PrintDuelMenuAndHandleInput
+
+.can_attack
+ xor a
+ ld [wSelectedDuelSubMenuItem], a
+.try_open_attack_menu
+ call PrintAndLoadAttacksToDuelTempList
+ or a
+ jr nz, .open_attack_menu
+ ldtx hl, NoSelectableAttackText
+ call DrawWideTextBox_WaitForInput
+ jp PrintDuelMenuAndHandleInput
+
+.open_attack_menu
+ push af
+ ld a, [wSelectedDuelSubMenuItem]
+ ld hl, AttackMenuParameters
+ call InitializeMenuParameters
+ pop af
+ ld [wNumMenuItems], a
+ ldh a, [hWhoseTurn]
+ ld h, a
+ ld l, DUELVARS_ARENA_CARD
+ ld a, [hl]
+ call LoadCardDataToBuffer1_FromDeckIndex
+
+.wait_for_input
+ call DoFrame
+ ldh a, [hKeysPressed]
+ and START
+ jr nz, .display_selected_attack_info
+ call HandleMenuInput
+ jr nc, .wait_for_input
+ cp -1 ; was B pressed?
+ jp z, PrintDuelMenuAndHandleInput
+ ld [wSelectedDuelSubMenuItem], a
+ call CheckIfEnoughEnergiesToAttack
+ jr nc, .enough_energy
+ ldtx hl, NotEnoughEnergyCardsText
+ call DrawWideTextBox_WaitForInput
+ jr .try_open_attack_menu
+
+.enough_energy
+ ldh a, [hCurMenuItem]
+ add a
+ ld e, a
+ ld d, $00
+ ld hl, wDuelTempList
+ add hl, de
+ ld d, [hl] ; card's deck index (0 to 59)
+ inc hl
+ ld e, [hl] ; attack index (0 or 1)
+ call CopyAttackDataAndDamage_FromDeckIndex
+ call HandleAmnesiaSubstatus
+ jr c, .cannot_use_due_to_amnesia
+ ld a, PRACTICEDUEL_VERIFY_PLAYER_TURN_ACTIONS
+ call DoPracticeDuelAction
+ ; if player did something wrong in the practice duel, jump in order to restart turn
+ jp c, RestartPracticeDuelTurn
+ call UseAttackOrPokemonPower
+ jp c, DuelMainInterface
+ ret
+
+.cannot_use_due_to_amnesia
+ call DrawWideTextBox_WaitForInput
+ jr .try_open_attack_menu
+
+.display_selected_attack_info
+ call OpenAttackPage
+ call DrawDuelMainScene
+ jp .try_open_attack_menu
+
+; draw the attack page of the card at wLoadedCard1 and of the attack selected in the Attack
+; menu by hCurMenuItem, and listen for input in order to switch the page or to exit.
+OpenAttackPage:
+ ld a, CARDPAGE_POKEMON_OVERVIEW
+ ld [wCardPageNumber], a
+ xor a
+ ld [wCurPlayAreaSlot], a
+ call EmptyScreen
+ call Func_3b31
+ ld de, v0Tiles1 + $20 tiles
+ call LoadLoaded1CardGfx
+ call SetOBP1OrSGB3ToCardPalette
+ call SetBGP6OrSGB3ToCardPalette
+ call FlushAllPalettesOrSendPal23Packet
+ lb de, $38, $30 ; X Position and Y Position of top-left corner
+ call PlaceCardImageOAM
+ lb de, 6, 4
+ call ApplyBGP6OrSGB3ToCardImage
+ ldh a, [hCurMenuItem]
+ ld [wSelectedDuelSubMenuItem], a
+ add a
+ ld e, a
+ ld d, $00
+ ld hl, wDuelTempList + 1
+ add hl, de
+ ld a, [hl]
+ or a
+ jr nz, .attack_2
+ xor a ; ATTACKPAGE_ATTACK1_1
+ jr .attack_1
+
+.attack_2
+ ld a, ATTACKPAGE_ATTACK2_1
+
+.attack_1
+ ld [wAttackPageNumber], a
+
+.open_page
+ call DisplayAttackPage
+ call EnableLCD
+
+.loop
+ call DoFrame
+ ; switch page (see SwitchAttackPage) if Right or Left pressed
+ ldh a, [hDPadHeld]
+ and D_RIGHT | D_LEFT
+ jr nz, .open_page
+ ; return to Attack menu if A or B pressed
+ ldh a, [hKeysPressed]
+ and A_BUTTON | B_BUTTON
+ jr z, .loop
+ ret
+
+AttackMenuParameters:
+ db 1, 13 ; cursor x, cursor y
+ db 2 ; y displacement between items
+ db 2 ; number of items
+ db SYM_CURSOR_R ; cursor tile number
+ db SYM_SPACE ; tile behind cursor
+ dw NULL ; function pointer if non-0
+
+; display the card page with id at wAttackPageNumber of wLoadedCard1
+DisplayAttackPage:
+ ld a, [wAttackPageNumber]
+ ld hl, AttackPageDisplayPointerTable
+ jp JumpToFunctionInTable
+
+AttackPageDisplayPointerTable:
+ dw DisplayAttackPage_Attack1Page1 ; ATTACKPAGE_ATTACK1_1
+ dw DisplayAttackPage_Attack1Page2 ; ATTACKPAGE_ATTACK1_2
+ dw DisplayAttackPage_Attack2Page1 ; ATTACKPAGE_ATTACK2_1
+ dw DisplayAttackPage_Attack2Page2 ; ATTACKPAGE_ATTACK2_2
+
+; display ATTACKPAGE_ATTACK1_1
+DisplayAttackPage_Attack1Page1:
+ call DisplayCardPage_PokemonAttack1Page1
+ jr SwitchAttackPage
+
+; display ATTACKPAGE_ATTACK1_2 if it exists. otherwise return in order
+; to switch back to ATTACKPAGE_ATTACK1_1 and display it instead.
+DisplayAttackPage_Attack1Page2:
+ ld hl, wLoadedCard1Atk1Description + 2
+ ld a, [hli]
+ or [hl]
+ ret z
+ call DisplayCardPage_PokemonAttack1Page2
+ jr SwitchAttackPage
+
+; display ATTACKPAGE_ATTACK2_1
+DisplayAttackPage_Attack2Page1:
+ call DisplayCardPage_PokemonAttack2Page1
+ jr SwitchAttackPage
+
+; display ATTACKPAGE_ATTACK2_2 if it exists. otherwise return in order
+; to switch back to ATTACKPAGE_ATTACK2_1 and display it instead.
+DisplayAttackPage_Attack2Page2:
+ ld hl, wLoadedCard1Atk2Description + 2
+ ld a, [hli]
+ or [hl]
+ ret z
+ call DisplayCardPage_PokemonAttack2Page2
+; fallthrough
+
+; switch to ATTACKPAGE_ATTACK*_2 if in ATTACKPAGE_ATTACK*_1 and vice versa.
+; sets the next attack page to switch to if Right or Left are pressed.
+SwitchAttackPage:
+ ld hl, wAttackPageNumber
+ ld a, $01
+ xor [hl]
+ ld [hl], a
+ ret
+
+; given the card at hTempCardIndex_ff98, for each non-empty, non-Pokemon Power attack slot,
+; prints its information at lines 13 (first attack, if any), and 15 (second attack, if any)
+; also, copies zero, one, or both of the following to wDuelTempList, $ff terminated:
+; if pokemon's first attack slot isn't empty or a Pokemon Power: <card_index>, 0
+; if pokemon's second attack slot isn't empty or a Pokemon Power: <card_index>, 1
+; return the amount of non-empty, non-Pokemon Power attacks in a.
+PrintAndLoadAttacksToDuelTempList:
+ call DrawWideTextBox
+ ld a, DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ ldh [hTempCardIndex_ff98], a
+ call LoadCardDataToBuffer1_FromDeckIndex
+ ld c, 0
+ ld b, 13
+ ld hl, wDuelTempList
+ xor a
+ ld [wCardPageNumber], a
+ ld de, wLoadedCard1Atk1Name
+ call CheckAttackSlotEmptyOrPokemonPower
+ jr c, .check_second_atk_slot
+ ldh a, [hTempCardIndex_ff98]
+ ld [hli], a
+ xor a
+ ld [hli], a
+ inc c
+ push hl
+ push bc
+ ld e, b
+ ld hl, wLoadedCard1Atk1Name
+ call PrintAttackOrPkmnPowerInformation
+ pop bc
+ pop hl
+ inc b
+ inc b ; 15
+
+.check_second_atk_slot
+ ld de, wLoadedCard1Atk2Name
+ call CheckAttackSlotEmptyOrPokemonPower
+ jr c, .done
+ ldh a, [hTempCardIndex_ff98]
+ ld [hli], a
+ ld a, $01
+ ld [hli], a
+ inc c
+ push hl
+ push bc
+ ld e, b
+ ld hl, wLoadedCard1Atk2Name
+ call PrintAttackOrPkmnPowerInformation
+ pop bc
+ pop hl
+
+.done
+ ld a, c
+ ret
+
+; given de = wLoadedCard*Atk*Name, return carry if the attack is a
+; Pkmn Power or if the attack slot is empty.
+CheckAttackSlotEmptyOrPokemonPower:
+ push hl
+ push de
+ push bc
+ ld a, [de]
+ ld c, a
+ inc de
+ ld a, [de]
+ or c
+ jr z, .return_no_atk_found
+ ld hl, CARD_DATA_ATTACK1_CATEGORY - (CARD_DATA_ATTACK1_NAME + 1)
+ add hl, de
+ ld a, [hl]
+ and $ff ^ RESIDUAL
+ cp POKEMON_POWER
+ jr z, .return_no_atk_found
+ or a
+.return
+ pop bc
+ pop de
+ pop hl
+ ret
+.return_no_atk_found
+ scf
+ jr .return
+
+; check if the arena pokemon card has enough energy attached to it
+; in order to use the selected attack.
+; returns: carry if not enough energy, nc if enough energy.
+CheckIfEnoughEnergiesToAttack:
+ push hl
+ push bc
+ ld e, PLAY_AREA_ARENA
+ call GetPlayAreaCardAttachedEnergies
+ call HandleEnergyBurn
+ ldh a, [hCurMenuItem]
+ add a
+ ld e, a
+ ld d, $0
+ ld hl, wDuelTempList
+ add hl, de
+ ld d, [hl] ; card's deck index (0 to 59)
+ inc hl
+ ld e, [hl] ; attack index (0 or 1)
+ call _CheckIfEnoughEnergiesToAttack
+ pop bc
+ pop hl
+ ret
+
+; check if a pokemon card has enough energy attached to it in order to use an attack
+; input:
+; d = deck index of card (0 to 59)
+; e = attack index (0 or 1)
+; wAttachedEnergies and wTotalAttachedEnergies
+; returns: carry if not enough energy, nc if enough energy.
+_CheckIfEnoughEnergiesToAttack:
+ push de
+ ld a, d
+ call LoadCardDataToBuffer1_FromDeckIndex
+ pop bc
+ push bc
+ ld de, wLoadedCard1Atk1EnergyCost
+ ld a, c
+ or a
+ jr z, .got_atk
+ ld de, wLoadedCard1Atk2EnergyCost
+
+.got_atk
+ ld hl, CARD_DATA_ATTACK1_NAME - CARD_DATA_ATTACK1_ENERGY_COST
+ add hl, de
+ ld a, [hli]
+ or [hl]
+ jr z, .not_usable_or_not_enough_energies
+ ld hl, CARD_DATA_ATTACK1_CATEGORY - CARD_DATA_ATTACK1_ENERGY_COST
+ add hl, de
+ ld a, [hl]
+ cp POKEMON_POWER
+ jr z, .not_usable_or_not_enough_energies
+ xor a
+ ld [wAttachedEnergiesAccum], a
+ ld hl, wAttachedEnergies
+ ld c, (NUM_COLORED_TYPES) / 2
+
+.next_energy_type_pair
+ ld a, [de]
+ swap a
+ call CheckIfEnoughEnergiesOfType
+ jr c, .not_usable_or_not_enough_energies
+ ld a, [de]
+ call CheckIfEnoughEnergiesOfType
+ jr c, .not_usable_or_not_enough_energies
+ inc de
+ dec c
+ jr nz, .next_energy_type_pair
+ ld a, [de] ; colorless energy
+ swap a
+ and $f
+ ld b, a
+ ld a, [wAttachedEnergiesAccum]
+ ld c, a
+ ld a, [wTotalAttachedEnergies]
+ sub c
+ cp b
+ jr c, .not_usable_or_not_enough_energies
+ or a
+.done
+ pop de
+ ret
+
+.not_usable_or_not_enough_energies
+ scf
+ jr .done
+
+; given the amount of energies of a specific type required for an attack in the
+; lower nybble of register a, test if the pokemon card has enough energies of that type
+; to use the attack. Return carry if not enough energy, nc if enough energy.
+CheckIfEnoughEnergiesOfType:
+ and $f
+ push af
+ push hl
+ ld hl, wAttachedEnergiesAccum
+ add [hl]
+ ld [hl], a ; accumulate the amount of energies required
+ pop hl
+ pop af
+ jr z, .enough_energies ; jump if no energies of this type are required
+ cp [hl]
+ ; jump if the energies required of this type are not more than the amount attached
+ jr z, .enough_energies
+ jr c, .enough_energies
+ inc hl
+ scf
+ ret
+
+.enough_energies
+ inc hl
+ or a
+ ret
+
+; return carry and the corresponding text in hl if the turn holder's
+; arena Pokemon card is paralyzed or asleep.
+CheckIfActiveCardParalyzedOrAsleep:
+ ld a, DUELVARS_ARENA_CARD_STATUS
+ call GetTurnDuelistVariable
+ and CNF_SLP_PRZ
+ cp PARALYZED
+ jr z, .paralyzed
+ cp ASLEEP
+ jr z, .asleep
+ or a
+ ret
+.paralyzed
+ ldtx hl, UnableDueToParalysisText
+ jr .return_with_status_condition
+.asleep
+ ldtx hl, UnableDueToSleepText
+.return_with_status_condition
+ scf
+ ret
+
+; display the animation of the turn duelist drawing one card at the beginning of the turn
+; if there isn't any card left in the deck, let the player know with a text message
+DisplayDrawOneCardScreen:
+ ld a, 1
+; fallthrough
+
+; display the animation of the turn duelist drawing number of cards that is in a.
+; if there isn't any card left in the deck, let the player know with a text message.
+; input:
+; - a = number of cards to draw
+DisplayDrawNCardsScreen:
+ push hl
+ push de
+ push bc
+ ld [wNumCardsTryingToDraw], a
+ xor a
+ ld [wNumCardsBeingDrawn], a
+ ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK
+ call GetTurnDuelistVariable
+ ld a, DECK_SIZE
+ sub [hl]
+ ld hl, wNumCardsTryingToDraw
+ cp [hl]
+ jr nc, .has_cards_left
+ ; trying to draw more cards than there are left in the deck
+ ld [hl], a ; 0
+.has_cards_left
+ ld a, [wDuelDisplayedScreen]
+ cp DRAW_CARDS
+ jr z, .portraits_drawn
+ cp SHUFFLE_DECK
+ jr z, .portraits_drawn
+ call EmptyScreen
+ call DrawDuelistPortraitsAndNames
+.portraits_drawn
+ ld a, DRAW_CARDS
+ ld [wDuelDisplayedScreen], a
+ call PrintDeckAndHandIconsAndNumberOfCards
+ ld a, [wNumCardsTryingToDraw]
+ or a
+ jr nz, .can_draw
+ ; if wNumCardsTryingToDraw set to 0 before, it's because not enough cards in deck
+ ldtx hl, CannotDrawCardBecauseNoCardsInDeckText
+ call DrawWideTextBox_WaitForInput
+ jr .done
+.can_draw
+ ld l, a
+ ld h, 0
+ call LoadTxRam3
+ ldtx hl, DrawCardsFromTheDeckText
+ call DrawWideTextBox_PrintText
+ call EnableLCD
+.anim_drawing_cards_loop
+ call PlayTurnDuelistDrawAnimation
+ ld hl, wNumCardsBeingDrawn
+ inc [hl]
+ call PrintNumberOfHandAndDeckCards
+ ld a, [wNumCardsBeingDrawn]
+ ld hl, wNumCardsTryingToDraw
+ cp [hl]
+ jr c, .anim_drawing_cards_loop
+ ld c, 30
+.wait_loop
+ call DoFrame
+ call CheckSkipDelayAllowed
+ jr c, .done
+ dec c
+ jr nz, .wait_loop
+.done
+ pop bc
+ pop de
+ pop hl
+ ret
+
+; animates the screen for Turn Duelist drawing a card
+PlayTurnDuelistDrawAnimation:
+ call Func_3b21
+ ld e, DUEL_ANIM_PLAYER_DRAW
+ ldh a, [hWhoseTurn]
+ cp PLAYER_TURN
+ jr z, .got_duelist
+ ld e, DUEL_ANIM_OPP_DRAW
+.got_duelist
+ ld a, e
+ call PlayDuelAnimation
+
+.loop_anim
+ call DoFrame
+ call CheckSkipDelayAllowed
+ jr c, .done_anim
+ call CheckAnyAnimationPlaying
+ jr c, .loop_anim
+
+.done_anim
+ call Func_3b31
+ ret
+
+; prints, for each duelist, the number of cards in the hand along with the
+; hand icon, and the number of cards in the deck, along with the deck icon,
+; according to each element's placement in the draw card(s) screen.
+PrintDeckAndHandIconsAndNumberOfCards:
+ call LoadDuelDrawCardsScreenTiles
+ ld hl, DeckAndHandIconsTileData
+ call WriteDataBlocksToBGMap0
+ ld a, [wConsole]
+ cp CONSOLE_CGB
+ jr nz, .not_cgb
+ call BankswitchVRAM1
+ ld hl, DeckAndHandIconsCGBPalData
+ call WriteDataBlocksToBGMap0
+ call BankswitchVRAM0
+.not_cgb
+ call PrintPlayerNumberOfHandAndDeckCards
+ call PrintOpponentNumberOfHandAndDeckCards
+ ret
+
+; prints, for each duelist, the number of cards in the hand, and the number
+; of cards in the deck, according to their placement in the draw card(s) screen.
+; input: wNumCardsBeingDrawn = number of cards being drawn (in order to add
+; them to the hand cards and subtract them from the deck cards).
+PrintNumberOfHandAndDeckCards:
+ ldh a, [hWhoseTurn]
+ cp PLAYER_TURN
+ jr nz, PrintOpponentNumberOfHandAndDeckCards
+; fallthrough
+
+PrintPlayerNumberOfHandAndDeckCards:
+ ld a, [wPlayerNumberOfCardsInHand]
+ ld hl, wNumCardsBeingDrawn
+ add [hl]
+ ld d, a
+ ld a, DECK_SIZE
+ ld hl, wPlayerNumberOfCardsNotInDeck
+ sub [hl]
+ ld hl, wNumCardsBeingDrawn
+ sub [hl]
+ ld e, a
+ ld a, d
+ lb bc, 16, 10
+ call WriteTwoDigitNumberInTxSymbolFormat
+ ld a, e
+ lb bc, 10, 10
+ jp WriteTwoDigitNumberInTxSymbolFormat
+
+PrintOpponentNumberOfHandAndDeckCards:
+ ld a, [wOpponentNumberOfCardsInHand]
+ ld hl, wNumCardsBeingDrawn
+ add [hl]
+ ld d, a
+ ld a, DECK_SIZE
+ ld hl, wOpponentNumberOfCardsNotInDeck
+ sub [hl]
+ ld hl, wNumCardsBeingDrawn
+ sub [hl]
+ ld e, a
+ ld a, d
+ lb bc, 5, 3
+ call WriteTwoDigitNumberInTxSymbolFormat
+ ld a, e
+ lb bc, 11, 3
+ jp WriteTwoDigitNumberInTxSymbolFormat
+
+DeckAndHandIconsTileData:
+; x, y, tiles[], 0
+ db 4, 3, SYM_CROSS, 0 ; x for opponent's hand
+ db 10, 3, SYM_CROSS, 0 ; x for opponent's deck
+ db 8, 2, $f4, $f5, 0 ; opponent's deck icon
+ db 8, 3, $f6, $f7, 0 ; opponent's deck icon
+ db 2, 2, $f8, $f9, 0 ; opponent's hand icon
+ db 2, 3, $fa, $fb, 0 ; opponent's hand icon
+ db 9, 10, SYM_CROSS, 0 ; x for player's deck
+ db 15, 10, SYM_CROSS, 0 ; x for player's hand
+ db 7, 9, $f4, $f5, 0 ; player's deck icon
+ db 7, 10, $f6, $f7, 0 ; player's deck icon
+ db 13, 9, $f8, $f9, 0 ; player's hand icon
+ db 13, 10, $fa, $fb, 0 ; player's hand icon
+ db $ff
+
+DeckAndHandIconsCGBPalData:
+; x, y, pals[], 0
+ db 8, 2, $02, $02, 0
+ db 8, 3, $02, $02, 0
+ db 2, 2, $02, $02, 0
+ db 2, 3, $02, $02, 0
+ db 7, 9, $02, $02, 0
+ db 7, 10, $02, $02, 0
+ db 13, 9, $02, $02, 0
+ db 13, 10, $02, $02, 0
+ db $ff
+
+; draw the portraits of the two duelists and print their names.
+; also draw an horizontal line separating the two sides.
+DrawDuelistPortraitsAndNames:
+ call LoadSymbolsFont
+ ; player's name
+ ld de, wDefaultText
+ push de
+ call CopyPlayerName
+ lb de, 0, 11
+ call InitTextPrinting
+ pop hl
+ call ProcessText
+ ; player's portrait
+ lb bc, 0, 5
+ call DrawPlayerPortrait
+ ; opponent's name (aligned to the right)
+ ld de, wDefaultText
+ push de
+ call CopyOpponentName
+ pop hl
+ call GetTextLengthInTiles
+ push hl
+ add SCREEN_WIDTH
+ ld d, a
+ ld e, 0
+ call InitTextPrinting
+ pop hl
+ call ProcessText
+ ; opponent's portrait
+ ld a, [wOpponentPortrait]
+ lb bc, 13, 1
+ call Func_3e2a
+ ; middle line
+ call DrawDuelHorizontalSeparator
+ ret
+
+; print the number of prizes left, of active Pokemon, and of cards left in the deck
+; of both duelists. this is called when the duel ends.
+PrintDuelResultStats:
+ lb de, 8, 8
+ call PrintDuelistResultStats
+ call SwapTurn
+ lb de, 1, 1
+ call PrintDuelistResultStats
+ call SwapTurn
+ ret
+
+; print, at d,e, the number of prizes left, of active Pokemon, and of cards left in
+; the deck of the turn duelist. b,c are used throughout as input coords for
+; WriteTwoDigitNumberInTxSymbolFormat, and d,e for InitTextPrinting_ProcessTextFromID.
+PrintDuelistResultStats:
+ call SetNoLineSeparation
+ ldtx hl, PrizesLeftActivePokemonCardsInDeckText
+ call InitTextPrinting_ProcessTextFromID
+ call SetOneLineSeparation
+ ld c, e
+ ld a, d
+ add 7
+ ld b, a
+ inc a
+ inc a
+ ld d, a
+ call CountPrizes
+ call .print_x_cards
+ inc e
+ inc c
+ ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA
+ call GetTurnDuelistVariable
+ ldtx hl, YesText
+ or a
+ jr nz, .pkmn_in_play_area
+ ldtx hl, NoneText
+.pkmn_in_play_area
+ dec d
+ call InitTextPrinting_ProcessTextFromID
+ inc e
+ inc d
+ inc c
+ ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK
+ call GetTurnDuelistVariable
+ ld a, DECK_SIZE
+ sub [hl]
+.print_x_cards
+ call WriteTwoDigitNumberInTxSymbolFormat
+ ldtx hl, CardsText
+ call InitTextPrinting_ProcessTextFromID
+ ret
+
+; display the animation of the player drawing the card at hTempCardIndex_ff98
+DisplayPlayerDrawCardScreen:
+ ldtx hl, YouDrewText
+ ldh a, [hTempCardIndex_ff98]
+; fallthrough
+
+; display card detail when a card is drawn or played
+; hl is text to display
+; a is the card's deck index
+DisplayCardDetailScreen:
+ call LoadCardDataToBuffer1_FromDeckIndex
+ call _DisplayCardDetailScreen
+ ret
+
+Func_4b38:
+ ld a, [wDuelTempList]
+ cp $ff
+ ret z
+ call InitAndDrawCardListScreenLayout
+ call CountCardsInDuelTempList ; list length
+ ld hl, CardListParameters ; other list params
+ lb de, 0, 0 ; initial page scroll offset, initial item (in the visible page)
+ call PrintCardListItems
+ ldtx hl, TheCardYouReceivedText
+ lb de, 1, 1
+ call InitTextPrinting
+ call PrintTextNoDelay
+ ldtx hl, YouReceivedTheseCardsText
+ call DrawWideTextBox_WaitForInput
+ ret
+
+; handles the initial duel actions:
+; - drawing starting hand and placing the Basic Pokemon cards
+; - placing the appropriate number of prize cards
+; - tossing coin to determine first player to go
+HandleDuelSetup:
+; init variables and shuffle cards
+ call InitializeDuelVariables
+ call SwapTurn
+ call InitializeDuelVariables
+ call SwapTurn
+ call PlayShuffleAndDrawCardsAnimation_BothDuelists
+ call ShuffleDeckAndDrawSevenCards
+ ldh [hTemp_ffa0], a
+ call SwapTurn
+ call ShuffleDeckAndDrawSevenCards
+ call SwapTurn
+ ld c, a
+
+; check if any Basic Pokémon cards were drawn
+ ldh a, [hTemp_ffa0]
+ ld b, a
+ and c
+ jr nz, .hand_cards_ok
+ ld a, b
+ or c
+ jr z, .neither_drew_basic_pkmn
+ ld a, b
+ or a
+ jr nz, .opp_drew_no_basic_pkmn
+
+;.player_drew_no_basic_pkmn
+.ensure_player_basic_pkmn_loop
+ call DisplayNoBasicPokemonInHandScreenAndText
+ call InitializeDuelVariables
+ call PlayShuffleAndDrawCardsAnimation_TurnDuelist
+ call ShuffleDeckAndDrawSevenCards
+ jr c, .ensure_player_basic_pkmn_loop
+ jr .hand_cards_ok
+
+.opp_drew_no_basic_pkmn
+ call SwapTurn
+.ensure_opp_basic_pkmn_loop
+ call DisplayNoBasicPokemonInHandScreenAndText
+ call InitializeDuelVariables
+ call PlayShuffleAndDrawCardsAnimation_TurnDuelist
+ call ShuffleDeckAndDrawSevenCards
+ jr c, .ensure_opp_basic_pkmn_loop
+ call SwapTurn
+ jr .hand_cards_ok
+
+.neither_drew_basic_pkmn
+ ldtx hl, NeitherPlayerHasBasicPkmnText
+ call DrawWideTextBox_WaitForInput
+ call DisplayNoBasicPokemonInHandScreen
+ call InitializeDuelVariables
+ call SwapTurn
+ call DisplayNoBasicPokemonInHandScreen
+ call InitializeDuelVariables
+ call SwapTurn
+ call PrintReturnCardsToDeckDrawAgain
+ jp HandleDuelSetup
+
+.hand_cards_ok
+ ldh a, [hWhoseTurn]
+ push af
+ ld a, PLAYER_TURN
+ ldh [hWhoseTurn], a
+ call ChooseInitialArenaAndBenchPokemon
+ call SwapTurn
+ call ChooseInitialArenaAndBenchPokemon
+ call SwapTurn
+ jp c, .error
+ call DrawPlayAreaToPlacePrizeCards
+ ldtx hl, PlacingThePrizesText
+ call DrawWideTextBox_WaitForInput
+ call ExchangeRNG
+
+ ld a, [wDuelInitialPrizes]
+ ld l, a
+ ld h, 0
+ call LoadTxRam3
+ ldtx hl, PleasePlacePrizesText
+ call DrawWideTextBox_PrintText
+ call EnableLCD
+ call .PlacePrizes
+ call WaitForWideTextBoxInput
+ pop af
+
+ ldh [hWhoseTurn], a
+ call InitTurnDuelistPrizes
+ call SwapTurn
+ call InitTurnDuelistPrizes
+ call SwapTurn
+ call EmptyScreen
+ ld a, BOXMSG_COIN_TOSS
+ call DrawDuelBoxMessage
+ ldtx hl, CoinTossToDecideWhoPlaysFirstText
+ call DrawWideTextBox_WaitForInput
+ ldh a, [hWhoseTurn]
+ cp PLAYER_TURN
+ jr nz, .opponent_turn
+
+; player flips coin
+ ld de, wDefaultText
+ call CopyPlayerName
+ ld hl, $0000
+ call LoadTxRam2
+ ldtx hl, YouPlayFirstText
+ ldtx de, IfHeadsDuelistPlaysFirstText
+ call TossCoin
+ jr c, .play_first
+ call SwapTurn
+ ldtx hl, YouPlaySecondText
+.play_first
+ call DrawWideTextBox_WaitForInput
+ call ExchangeRNG
+ or a
+ ret
+
+.opponent_turn
+; opp flips coin
+ ld de, wDefaultText
+ call CopyOpponentName
+ ld hl, $0000
+ call LoadTxRam2
+ ldtx hl, YouPlaySecondText
+ ldtx de, IfHeadsDuelistPlaysFirstText
+ call TossCoin
+ jr c, .play_second
+ call SwapTurn
+ ldtx hl, YouPlayFirstText
+.play_second
+ call DrawWideTextBox_WaitForInput
+ call ExchangeRNG
+ or a
+ ret
+
+.error
+ pop af
+ ldh [hWhoseTurn], a
+ scf
+ ret
+
+; places the prize cards on both sides
+; of the Play Area (player & opp)
+.PlacePrizes
+ ld hl, .PrizeCardCoordinates
+ ld e, DECK_SIZE - 7 - 1 ; deck size - cards drawn - 1
+ ld a, [wDuelInitialPrizes]
+ ld d, a
+
+.place_prize
+ push de
+ ld b, 20 ; frames to delay
+.loop_delay
+ call DoFrame
+ call CheckSkipDelayAllowed
+ jr c, .skip_delay
+ dec b
+ jr nz, .loop_delay
+.skip_delay
+ call .DrawPrizeTile
+ call .DrawPrizeTile
+
+ push hl
+ ld a, SFX_08
+ call PlaySFX
+ ; print new deck card number
+ lb bc, 3, 5
+ ld a, e
+ call WriteTwoDigitNumberInTxSymbolFormat
+ lb bc, 18, 7
+ ld a, e
+ call WriteTwoDigitNumberInTxSymbolFormat
+ pop hl
+ pop de
+ dec e ; decrease number of cards in deck
+ dec d ; decrease number of prize cards left
+ jr nz, .place_prize
+ ret
+
+.DrawPrizeTile
+ ld b, [hl]
+ inc hl
+ ld c, [hl]
+ inc hl
+ ld a, $ac ; prize card tile
+ jp WriteByteToBGMap0
+
+.PrizeCardCoordinates
+; player x, player y, opp x, opp y
+ db 5, 6, 14, 5 ; Prize 1
+ db 6, 6, 13, 5 ; Prize 2
+ db 5, 7, 14, 4 ; Prize 3
+ db 6, 7, 13, 4 ; Prize 4
+ db 5, 8, 14, 3 ; Prize 5
+ db 6, 8, 13, 3 ; Prize 6
+
+; have the turn duelist place, at the beginning of the duel, the active Pokemon
+; and 0 more bench Pokemon, all of which must be basic Pokemon cards.
+; also transmits the turn holder's duelvars to the other duelist in a link duel.
+; called twice, once for each duelist.
+ChooseInitialArenaAndBenchPokemon:
+ ld a, DUELVARS_DUELIST_TYPE
+ call GetTurnDuelistVariable
+ cp DUELIST_TYPE_PLAYER
+ jr z, .choose_arena
+ cp DUELIST_TYPE_LINK_OPP
+ jr z, .exchange_duelvars
+
+; AI opponent's turn
+ push af
+ push hl
+ call AIDoAction_StartDuel
+ pop hl
+ pop af
+ ld [hl], a
+ or a
+ ret
+
+; link opponent's turn
+.exchange_duelvars
+ ldtx hl, TransmittingDataText
+ call DrawWideTextBox_PrintText
+ call ExchangeRNG
+ ld hl, wPlayerDuelVariables
+ ld de, wOpponentDuelVariables
+ ld c, (wOpponentDuelVariables - wPlayerDuelVariables) / 2
+ call SerialExchangeBytes
+ jr c, .error
+ ld c, (wOpponentDuelVariables - wPlayerDuelVariables) / 2
+ call SerialExchangeBytes
+ jr c, .error
+ ld a, DUELVARS_DUELIST_TYPE
+ call GetTurnDuelistVariable
+ ld [hl], DUELIST_TYPE_LINK_OPP
+ or a
+ ret
+.error
+ jp DuelTransmissionError
+
+; player's turn (either AI or link duel)
+; prompt (force) the player to choose a basic Pokemon card to place in the arena
+.choose_arena
+ call EmptyScreen
+ ld a, BOXMSG_ARENA_POKEMON
+ call DrawDuelBoxMessage
+ ldtx hl, ChooseBasicPkmnToPlaceInArenaText
+ call DrawWideTextBox_WaitForInput
+ ld a, PRACTICEDUEL_DRAW_SEVEN_CARDS
+ call DoPracticeDuelAction
+.choose_arena_loop
+ xor a
+ ldtx hl, PleaseChooseAnActivePokemonText
+ call DisplayPlaceInitialPokemonCardsScreen
+ jr c, .choose_arena_loop
+ ldh a, [hTempCardIndex_ff98]
+ call LoadCardDataToBuffer1_FromDeckIndex
+ ld a, PRACTICEDUEL_PLAY_GOLDEEN
+ call DoPracticeDuelAction
+ jr c, .choose_arena_loop
+ ldh a, [hTempCardIndex_ff98]
+ call PutHandPokemonCardInPlayArea
+ ldh a, [hTempCardIndex_ff98]
+ ldtx hl, PlacedInTheArenaText
+ call DisplayCardDetailScreen
+ jr .choose_bench
+
+; after choosing the active Pokemon, let the player place 0 or more basic Pokemon
+; cards in the bench. loop until the player decides to stop placing Pokemon cards.
+.choose_bench
+ call EmptyScreen
+ ld a, BOXMSG_BENCH_POKEMON
+ call DrawDuelBoxMessage
+ ldtx hl, ChooseUpTo5BasicPkmnToPlaceOnBenchText
+ call PrintScrollableText_NoTextBoxLabel
+ ld a, PRACTICEDUEL_PUT_STARYU_IN_BENCH
+ call DoPracticeDuelAction
+.bench_loop
+ ld a, TRUE
+ ldtx hl, ChooseYourBenchPokemonText
+ call DisplayPlaceInitialPokemonCardsScreen
+ jr c, .bench_done
+ ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA
+ call GetTurnDuelistVariable
+ cp MAX_PLAY_AREA_POKEMON
+ jr nc, .no_space
+ ldh a, [hTempCardIndex_ff98]
+ call PutHandPokemonCardInPlayArea
+ ldh a, [hTempCardIndex_ff98]
+ ldtx hl, PlacedOnTheBenchText
+ call DisplayCardDetailScreen
+ ld a, PRACTICEDUEL_DONE_PUTTING_ON_BENCH
+ call DoPracticeDuelAction
+ jr .bench_loop
+
+.no_space
+ ldtx hl, NoSpaceOnTheBenchText
+ call DrawWideTextBox_WaitForInput
+ jr .bench_loop
+
+.bench_done
+ ld a, PRACTICEDUEL_VERIFY_INITIAL_PLAY
+ call DoPracticeDuelAction
+ jr c, .bench_loop
+ or a
+ ret
+
+; the turn duelist shuffles the deck unless it's a practice duel, then draws 7 cards
+; returns $00 in a and carry if no basic Pokemon cards are drawn, and $01 in a otherwise
+ShuffleDeckAndDrawSevenCards:
+ call InitializeDuelVariables
+ ld a, [wDuelType]
+ cp DUELTYPE_PRACTICE
+ jr z, .deck_ready
+ call ShuffleDeck
+ call ShuffleDeck
+.deck_ready
+ ld b, 7
+.draw_loop
+ call DrawCardFromDeck
+ call AddCardToHand
+ dec b
+ jr nz, .draw_loop
+ ld a, DUELVARS_HAND
+ call GetTurnDuelistVariable
+ ld b, $00
+ ld c, 7
+.cards_loop
+ ld a, [hli]
+ push hl
+ push bc
+ call LoadCardDataToBuffer1_FromDeckIndex
+ call IsLoadedCard1BasicPokemon.skip_mysterious_fossil_clefairy_doll
+ pop bc
+ pop hl
+ or b
+ ld b, a
+ dec c
+ jr nz, .cards_loop
+ ld a, b
+ or a
+ ret nz
+ xor a
+ scf
+ ret
+
+; return nc if the card at wLoadedCard1 is a basic Pokemon card
+; MYSTERIOUS_FOSSIL and CLEFAIRY_DOLL do count as basic Pokemon cards
+IsLoadedCard1BasicPokemon:
+ ld a, [wLoadedCard1ID]
+ cp MYSTERIOUS_FOSSIL
+ jr z, .basic
+ cp CLEFAIRY_DOLL
+ jr z, .basic
+; fallthrough
+
+; return nc if the card at wLoadedCard1 is a basic Pokemon card
+; MYSTERIOUS_FOSSIL and CLEFAIRY_DOLL do NOT count unless already checked
+.skip_mysterious_fossil_clefairy_doll
+ ld a, [wLoadedCard1Type]
+ cp TYPE_ENERGY
+ jr nc, .energy_trainer_nonbasic
+ ld a, [wLoadedCard1Stage]
+ or a
+ jr nz, .energy_trainer_nonbasic
+
+; basic
+ ld a, $01
+ ret ; z
+
+.energy_trainer_nonbasic
+ xor a
+ scf
+ ret
+
+.basic ; MYSTERIOUS_FOSSIL or CLEFAIRY_DOLL
+ ld a, $01
+ or a
+ ret ; nz
+
+DisplayNoBasicPokemonInHandScreenAndText:
+ ldtx hl, ThereAreNoBasicPokemonInHand
+ call DrawWideTextBox_WaitForInput
+ call DisplayNoBasicPokemonInHandScreen
+; fallthrough
+
+; prints ReturnCardsToDeckAndDrawAgainText in a textbox and calls ExchangeRNG
+PrintReturnCardsToDeckDrawAgain:
+ ldtx hl, ReturnCardsToDeckAndDrawAgainText
+ call DrawWideTextBox_WaitForInput
+ call ExchangeRNG
+ ret
+
+; display a bare list of seven hand cards of the turn duelist, and the duelist's name above
+; used to let the player know that there are no basic Pokemon in the hand and need to redraw
+DisplayNoBasicPokemonInHandScreen:
+ call EmptyScreen
+ call LoadDuelCardSymbolTiles
+ lb de, 0, 0
+ lb bc, 20, 18
+ call DrawRegularTextBox
+ call CreateHandCardList
+ call CountCardsInDuelTempList
+ ld hl, NoBasicPokemonCardListParameters
+ lb de, 0, 0
+ call PrintCardListItems
+ ldtx hl, DuelistHandText
+ lb de, 1, 1
+ call InitTextPrinting
+ call PrintTextNoDelay
+ call EnableLCD
+ call WaitForWideTextBoxInput
+ ret
+
+NoBasicPokemonCardListParameters:
+ db 1, 3 ; cursor x, cursor y
+ db 4 ; item x
+ db 14 ; maximum length, in tiles, occupied by the name and level string of each card in the list
+ db 7 ; number of items selectable without scrolling
+ db SYM_CURSOR_R ; cursor tile number
+ db SYM_SPACE ; tile behind cursor
+ dw NULL ; function pointer if non-0
+
+; used only during the practice duel with Sam.
+; displays the list with the player's cards in hand, and the player's name above the list.
+DisplayPracticeDuelPlayerHandScreen:
+ call CreateHandCardList
+ call EmptyScreen
+ call LoadDuelCardSymbolTiles
+ lb de, 0, 0
+ lb bc, 20, 13
+ call DrawRegularTextBox
+ call CountCardsInDuelTempList ; list length
+ ld hl, CardListParameters ; other list params
+ lb de, 0, 0 ; initial page scroll offset, initial item (in the visible page)
+ call PrintCardListItems
+ ldtx hl, DuelistHandText
+ lb de, 1, 1
+ call InitTextPrinting
+ call PrintTextNoDelay
+ call EnableLCD
+ ret
+
+PlayShuffleAndDrawCardsAnimation_TurnDuelist:
+ ld b, DUEL_ANIM_PLAYER_SHUFFLE
+ ld c, DUEL_ANIM_PLAYER_DRAW
+ ldh a, [hWhoseTurn]
+ cp PLAYER_TURN
+ jr z, .play_anim
+ ld b, DUEL_ANIM_OPP_SHUFFLE
+ ld c, DUEL_ANIM_OPP_DRAW
+.play_anim
+ ldtx hl, ShufflesTheDeckText
+ ldtx de, Drew7CardsText
+ jr PlayShuffleAndDrawCardsAnimation
+
+PlayShuffleAndDrawCardsAnimation_BothDuelists:
+ ld b, DUEL_ANIM_BOTH_SHUFFLE
+ ld c, DUEL_ANIM_BOTH_DRAW
+ ldtx hl, EachPlayerShuffleOpponentsDeckText
+ ldtx de, EachPlayerDraw7CardsText
+ ld a, [wDuelType]
+ cp DUELTYPE_PRACTICE
+ jr nz, PlayShuffleAndDrawCardsAnimation
+ ldtx hl, ThisIsJustPracticeDoNotShuffleText
+; fallthrough
+
+; animate the shuffle and drawing screen
+; input:
+; b = shuffling animation index
+; c = drawing animation index
+; hl = text to print while shuffling
+; de = text to print while drawing
+PlayShuffleAndDrawCardsAnimation:
+ push bc
+ push de
+ push hl
+ call ZeroObjectPositionsAndToggleOAMCopy
+ call EmptyScreen
+ call DrawDuelistPortraitsAndNames
+ call LoadDuelDrawCardsScreenTiles
+ ld a, SHUFFLE_DECK
+ ld [wDuelDisplayedScreen], a
+ pop hl
+ call DrawWideTextBox_PrintText
+ call EnableLCD
+ ld a, [wDuelType]
+ cp DUELTYPE_PRACTICE
+ jr nz, .not_practice
+ call WaitForWideTextBoxInput
+ jr .print_deck_info
+
+.not_practice
+; get the shuffling animation from input value of b
+ call Func_3b21
+ ld hl, sp+$03
+ ; play animation 3 times
+ ld a, [hl]
+ call PlayDuelAnimation
+ ld a, [hl]
+ call PlayDuelAnimation
+ ld a, [hl]
+ call PlayDuelAnimation
+
+.loop_shuffle_anim
+ call DoFrame
+ call CheckSkipDelayAllowed
+ jr c, .done_shuffle
+ call CheckAnyAnimationPlaying
+ jr c, .loop_shuffle_anim
+.done_shuffle
+ call Func_3b31
+
+.print_deck_info
+ xor a
+ ld [wNumCardsBeingDrawn], a
+ call PrintDeckAndHandIconsAndNumberOfCards
+ call Func_3b21
+ pop hl
+ call DrawWideTextBox_PrintText
+.draw_card
+; get the draw animation from input value of c
+ ld hl, sp+$00
+ ld a, [hl]
+ call PlayDuelAnimation
+
+.loop_drawing_anim
+ call DoFrame
+ call CheckSkipDelayAllowed
+ jr c, .done
+ call CheckAnyAnimationPlaying
+ jr c, .loop_drawing_anim
+
+ ld hl, wNumCardsBeingDrawn
+ inc [hl]
+ ld hl, sp+$00
+ ld a, [hl]
+ cp DUEL_ANIM_BOTH_DRAW
+ jr nz, .one_duelist_shuffled
+ ; if both duelists shuffled
+ call PrintDeckAndHandIconsAndNumberOfCards.not_cgb
+ jr .check_num_cards
+.one_duelist_shuffled
+ call PrintNumberOfHandAndDeckCards
+
+.check_num_cards
+ ld a, [wNumCardsBeingDrawn]
+ cp 7
+ jr c, .draw_card
+
+ ld c, 30
+.wait_loop
+ call DoFrame
+ call CheckSkipDelayAllowed
+ jr c, .done
+ dec c
+ jr nz, .wait_loop
+
+.done
+ call Func_3b31
+ pop bc
+ ret
+
+Func_4f2d:
+ ld a, [wDuelDisplayedScreen]
+ cp SHUFFLE_DECK
+ jr z, .skip_draw_scene
+ call ZeroObjectPositionsAndToggleOAMCopy
+ call EmptyScreen
+ call DrawDuelistPortraitsAndNames
+.skip_draw_scene
+ ld a, SHUFFLE_DECK
+ ld [wDuelDisplayedScreen], a
+
+; if duelist has only one card in deck,
+; skip shuffling animation
+ ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK
+ call GetTurnDuelistVariable
+ ld a, DECK_SIZE
+ sub [hl]
+ cp 2
+ jr c, .one_card_in_deck
+
+ ldtx hl, ShufflesTheDeckText
+ call DrawWideTextBox_PrintText
+ call EnableLCD
+ call Func_3b21
+
+; load correct animation depending on turn duelist
+ ld e, DUEL_ANIM_PLAYER_SHUFFLE
+ ldh a, [hWhoseTurn]
+ cp PLAYER_TURN
+ jr z, .load_anim
+ ld e, DUEL_ANIM_OPP_SHUFFLE
+.load_anim
+; play animation 3 times
+ ld a, e
+ call PlayDuelAnimation
+ ld a, e
+ call PlayDuelAnimation
+ ld a, e
+ call PlayDuelAnimation
+
+.loop_anim
+ call DoFrame
+ call CheckSkipDelayAllowed
+ jr c, .done_anim
+ call CheckAnyAnimationPlaying
+ jr c, .loop_anim
+
+.done_anim
+ call Func_3b31
+ ld a, $01
+ ret
+
+.one_card_in_deck
+; no animation, just print text and delay
+ ld l, a
+ ld h, $00
+ call LoadTxRam3
+ ldtx hl, DeckHasXCardsText
+ call DrawWideTextBox_PrintText
+ call EnableLCD
+ ld a, 60
+.loop_wait
+ call DoFrame
+ dec a
+ jr nz, .loop_wait
+ ld a, $01
+ ret
+
+; draw the main scene during a duel, except the contents of the bottom text box,
+; which depend on the type of duelist holding the turn.
+; includes the background, both arena Pokemon, and both HUDs.
+DrawDuelMainScene:
+ ld a, DUELVARS_DUELIST_TYPE
+ call GetTurnDuelistVariable
+ cp DUELIST_TYPE_PLAYER
+ jr z, .draw
+ ldh a, [hWhoseTurn]
+ push af
+ ld a, PLAYER_TURN
+ ldh [hWhoseTurn], a
+ call .draw
+ pop af
+ ldh [hWhoseTurn], a
+ ret
+.draw
+; first, load the graphics and draw the background scene
+ ld a, [wDuelDisplayedScreen]
+ cp DUEL_MAIN_SCENE
+ ret z
+ call ZeroObjectPositionsAndToggleOAMCopy
+ call EmptyScreen
+ call LoadSymbolsFont
+ ld a, DUEL_MAIN_SCENE
+ ld [wDuelDisplayedScreen], a
+ ld a, DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ ld de, v0Tiles1 + $50 tiles
+ call LoadPlayAreaCardGfx
+ call SetBGP7OrSGB2ToCardPalette
+ call SwapTurn
+ ld a, DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ ld de, v0Tiles1 + $20 tiles
+ call LoadPlayAreaCardGfx
+ call SetBGP6OrSGB3ToCardPalette
+ call FlushAllPalettesOrSendPal23Packet
+ call SwapTurn
+; next, draw the Pokemon in the arena
+;.place_player_arena_pkmn
+ ld a, DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ cp -1
+ jr z, .place_opponent_arena_pkmn
+ ld a, $d0 ; v0Tiles1 + $50 tiles
+ lb hl, 6, 1
+ lb de, 0, 5
+ lb bc, 8, 6
+ call FillRectangle
+ call ApplyBGP7OrSGB2ToCardImage
+.place_opponent_arena_pkmn
+ call SwapTurn
+ ld a, DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ cp -1
+ jr z, .place_other_elements
+ ld a, $a0 ; v0Tiles1 + $20 tiles
+ lb hl, 6, 1
+ lb de, 12, 1
+ lb bc, 8, 6
+ call FillRectangle
+ call ApplyBGP6OrSGB3ToCardImage
+.place_other_elements
+ call SwapTurn
+ ld hl, DuelEAndHPTileData
+ call WriteDataBlocksToBGMap0
+ call DrawDuelHorizontalSeparator
+ call DrawDuelHUDs
+ call DrawWideTextBox
+ call EnableLCD
+ ret
+
+; draws the main elements of the main duel interface, including HUDs, HPs, card names
+; and color symbols, attached cards, and other information, of both duelists.
+DrawDuelHUDs:
+ ld a, DUELVARS_DUELIST_TYPE
+ call GetTurnDuelistVariable
+ cp DUELIST_TYPE_PLAYER
+ jr z, .draw_hud
+ ldh a, [hWhoseTurn]
+ push af
+ ld a, PLAYER_TURN
+ ldh [hWhoseTurn], a
+ call .draw_hud
+ pop af
+ ldh [hWhoseTurn], a
+ ret
+.draw_hud
+ lb de, 1, 11 ; coordinates for player's arena card name and info icons
+ lb bc, 11, 8 ; coordinates for player's attached energies and HP bar
+ call DrawDuelHUD
+ lb bc, 8, 5
+ ld a, DUELVARS_ARENA_CARD_STATUS
+ call GetTurnDuelistVariable
+ call CheckPrintCnfSlpPrz
+ inc c
+ call CheckPrintPoisoned
+ inc c
+ call CheckPrintDoublePoisoned ; if double poisoned, print a second poison icon
+ call SwapTurn
+ lb de, 7, 0 ; coordinates for opponent's arena card name and info icons
+ lb bc, 3, 1 ; coordinates for opponent's attached energies and HP bar
+ call GetNonTurnDuelistVariable
+ call DrawDuelHUD
+ lb bc, 11, 6
+ ld a, DUELVARS_ARENA_CARD_STATUS
+ call GetTurnDuelistVariable
+ call CheckPrintCnfSlpPrz
+ dec c
+ call CheckPrintPoisoned
+ dec c
+ call CheckPrintDoublePoisoned ; if double poisoned, print a second poison icon
+ call SwapTurn
+ ret
+
+DrawDuelHUD:
+ ld hl, wHUDEnergyAndHPBarsX
+ ld [hl], b
+ inc hl
+ ld [hl], c ; wHUDEnergyAndHPBarsY
+ push de ; push coordinates for the arena card name
+ ld d, 1 ; opponent's info icons start in the second tile to the right
+ ld a, e
+ or a
+ jr z, .go
+ ld d, 15 ; player's info icons start in the 15th tile to the right
+.go
+ push de
+ pop bc
+
+ ; print the Pokemon icon along with the no. of play area Pokemon
+ ld a, SYM_POKEMON
+ call WriteByteToBGMap0
+ inc b
+ ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA
+ call GetTurnDuelistVariable
+ add SYM_0 - 1
+ call WriteByteToBGMap0
+ inc b
+
+ ; print the Prize icon along with the no. of prizes yet to draw
+ ld a, SYM_PRIZE
+ call WriteByteToBGMap0
+ inc b
+ call CountPrizes
+ add SYM_0
+ call WriteByteToBGMap0
+
+ ; print the arena Pokemon card name and level text
+ pop de
+ ld a, DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ cp -1
+ ret z
+ call LoadCardDataToBuffer1_FromDeckIndex
+ push de
+ ld a, 32
+ call CopyCardNameAndLevel
+ ld [hl], TX_END
+
+ ; print the arena Pokemon card color symbol just before the name
+ pop de
+ ld a, e
+ or a
+ jr nz, .print_color_icon
+ ld hl, wDefaultText
+ call GetTextLengthInTiles
+ add SCREEN_WIDTH
+ ld d, a
+.print_color_icon
+ call InitTextPrinting
+ ld hl, wDefaultText
+ call ProcessText
+ push de
+ pop bc
+ call GetArenaCardColor
+ inc a ; TX_SYMBOL color tiles start at 1
+ dec b ; place the color symbol one tile to the left of the start of the card's name
+ call JPWriteByteToBGMap0
+
+ ; print attached energies
+ ld hl, wHUDEnergyAndHPBarsX
+ ld b, [hl]
+ inc hl
+ ld c, [hl] ; wHUDEnergyAndHPBarsY
+ lb de, 9, PLAY_AREA_ARENA
+ call PrintPlayAreaCardAttachedEnergies
+
+ ; print HP bar
+ ld a, DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ call LoadCardDataToBuffer1_FromDeckIndex
+ ld a, [wLoadedCard1HP]
+ ld d, a ; max HP
+ ld a, DUELVARS_ARENA_CARD_HP
+ call GetTurnDuelistVariable
+ ld e, a ; cur HP
+ call DrawHPBar
+ ld hl, wHUDEnergyAndHPBarsX
+ ld b, [hl]
+ inc hl
+ ld c, [hl] ; wHUDEnergyAndHPBarsY
+ inc c ; [wHUDEnergyAndHPBarsY] + 1
+ call BCCoordToBGMap0Address
+ push de
+ ld hl, wDefaultText
+ ld b, HP_BAR_LENGTH / 2 ; first row of the HP bar
+ call SafeCopyDataHLtoDE
+ pop de
+ ld hl, BG_MAP_WIDTH
+ add hl, de
+ ld e, l
+ ld d, h
+ ld hl, wDefaultText + HP_BAR_LENGTH / 2
+ ld b, HP_BAR_LENGTH / 2 ; second row of the HP bar
+ call SafeCopyDataHLtoDE
+
+ ; print number of attached Pluspower and Defender with respective icon, if any
+ ld hl, wHUDEnergyAndHPBarsX
+ ld a, [hli]
+ add 6
+ ld b, a
+ ld c, [hl] ; wHUDEnergyAndHPBarsY
+ inc c
+ ld a, DUELVARS_ARENA_CARD_ATTACHED_PLUSPOWER
+ call GetTurnDuelistVariable
+ or a
+ jr z, .check_defender
+ ld a, SYM_PLUSPOWER
+ call WriteByteToBGMap0
+ inc b
+ ld a, [hl] ; number of attached Pluspower
+ add SYM_0
+ call WriteByteToBGMap0
+ dec b
+.check_defender
+ ld a, DUELVARS_ARENA_CARD_ATTACHED_DEFENDER
+ call GetTurnDuelistVariable
+ or a
+ jr z, .done
+ inc c
+ ld a, SYM_DEFENDER
+ call WriteByteToBGMap0
+ inc b
+ ld a, [hl] ; number of attached Defender
+ add SYM_0
+ call WriteByteToBGMap0
+.done
+ ret
+
+; draws an horizontal line that separates the arena side of each duelist
+; also colorizes the line on CGB
+DrawDuelHorizontalSeparator:
+ ld hl, DuelHorizontalSeparatorTileData
+ call WriteDataBlocksToBGMap0
+ ld a, [wConsole]
+ cp CONSOLE_CGB
+ ret nz
+ call BankswitchVRAM1
+ ld hl, DuelHorizontalSeparatorCGBPalData
+ call WriteDataBlocksToBGMap0
+ call BankswitchVRAM0
+ ret
+
+DuelEAndHPTileData:
+; x, y, tiles[], 0
+ db 1, 1, SYM_E, 0
+ db 1, 2, SYM_HP, 0
+ db 9, 8, SYM_E, 0
+ db 9, 9, SYM_HP, 0
+ db $ff
+
+DuelHorizontalSeparatorTileData:
+; x, y, tiles[], 0
+ db 0, 4, $37, $37, $37, $37, $37, $37, $37, $37, $37, $31, $32, 0
+ db 9, 5, $33, $34, 0
+ db 9, 6, $33, $34, 0
+ db 9, 7, $35, $36, $37, $37, $37, $37, $37, $37, $37, $37, $37, 0
+ db $ff
+
+DuelHorizontalSeparatorCGBPalData:
+; x, y, pals[], 0
+ db 0, 4, $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, 0
+ db 9, 5, $02, $02, 0
+ db 9, 6, $02, $02, 0
+ db 9, 7, $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, 0
+ db $ff
+
+; if this is a practice duel, execute the practice duel action at wPracticeDuelAction
+; if not a practice duel, always return nc
+; the practice duel functions below return carry when something's wrong
+DoPracticeDuelAction:
+ ld [wPracticeDuelAction], a
+ ld a, [wIsPracticeDuel]
+ or a
+ ret z
+ ld a, [wPracticeDuelAction]
+ ld hl, PracticeDuelActionTable
+ jp JumpToFunctionInTable
+
+PracticeDuelActionTable:
+ dw NULL
+ dw PracticeDuel_DrawSevenCards
+ dw PracticeDuel_PlayGoldeen
+ dw PracticeDuel_PutStaryuInBench
+ dw PracticeDuel_VerifyInitialPlay
+ dw PracticeDuel_DonePuttingOnBench
+ dw PracticeDuel_PrintTurnInstructions
+ dw PracticeDuel_VerifyPlayerTurnActions
+ dw PracticeDuel_RepeatInstructions
+ dw PracticeDuel_PlayStaryuFromBench
+ dw PracticeDuel_ReplaceKnockedOutPokemon
+
+PracticeDuel_DrawSevenCards:
+ call DisplayPracticeDuelPlayerHandScreen
+ call EnableLCD
+ ldtx hl, DrawSevenCardsPracticeDuelText
+ jp PrintPracticeDuelDrMasonInstructions
+
+PracticeDuel_PlayGoldeen:
+ ld a, [wLoadedCard1ID]
+ cp GOLDEEN
+ ret z
+ ldtx hl, ChooseGoldeenPracticeDuelText
+ ldtx de, DrMasonText
+ scf
+ jp PrintPracticeDuelDrMasonInstructions
+
+PracticeDuel_PutStaryuInBench:
+ call DisplayPracticeDuelPlayerHandScreen
+ call EnableLCD
+ ldtx hl, PutPokemonOnBenchPracticeDuelText
+ jp PrintPracticeDuelDrMasonInstructions
+
+PracticeDuel_VerifyInitialPlay:
+ ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA
+ call GetTurnDuelistVariable
+ cp 2
+ ret z
+ ldtx hl, ChooseStaryuPracticeDuelText
+ scf
+ jp PrintPracticeDuelDrMasonInstructions
+
+PracticeDuel_DonePuttingOnBench:
+ call DisplayPracticeDuelPlayerHandScreen
+ call EnableLCD
+ ld a, $ff
+ ld [wPracticeDuelTurn], a
+ ldtx hl, PressBToFinishPracticeDuelText
+ jp PrintPracticeDuelDrMasonInstructions
+
+PracticeDuel_PrintTurnInstructions:
+ call DrawPracticeDuelInstructionsTextBox
+ call EnableLCD
+ ld a, [wDuelTurns]
+ ld hl, wPracticeDuelTurn
+ cp [hl]
+ ld [hl], a
+ ; calling PrintPracticeDuelInstructionsForCurrentTurn with a = 0 means that Dr. Mason's
+ ; instructions are also printed along with each of the point-by-point instructions
+ ld a, 0
+ jp nz, PrintPracticeDuelInstructionsForCurrentTurn
+ ; if we're here, the player followed the current turn actions wrong and has to
+ ; repeat them. ask the player whether to show detailed instructions again, in
+ ; order to call PrintPracticeDuelInstructionsForCurrentTurn with a = 0 or a = 1.
+ ldtx de, DrMasonText
+ ldtx hl, NeedPracticeAgainPracticeDuelText
+ call PrintScrollableText_WithTextBoxLabel_NoWait
+ call YesOrNoMenu
+ jp PrintPracticeDuelInstructionsForCurrentTurn
+
+PracticeDuel_VerifyPlayerTurnActions:
+ ld a, [wDuelTurns]
+ srl a
+ ld hl, PracticeDuelTurnVerificationPointerTable
+ call JumpToFunctionInTable
+ ; return nc if player followed instructions correctly
+ ret nc
+; fallthrough
+
+PracticeDuel_RepeatInstructions:
+ ldtx hl, FollowMyGuidancePracticeDuelText
+ call PrintPracticeDuelDrMasonInstructions
+ ; restart the turn from the saved data of the previous turn
+ ld a, $02
+ call BankswitchSRAM
+ ld de, sCurrentDuel
+ call LoadSavedDuelData
+ xor a
+ call BankswitchSRAM
+ ; return carry in order to repeat instructions
+ scf
+ ret
+
+PracticeDuel_PlayStaryuFromBench:
+ ld a, [wDuelTurns]
+ cp 7
+ jr z, .its_sam_turn_4
+ or a
+ ret
+.its_sam_turn_4
+ ; ask player to choose Staryu from bench to replace knocked out Seaking
+ call DrawPracticeDuelInstructionsTextBox
+ call EnableLCD
+ ld hl, PracticeDuelText_SamTurn4
+ jp PrintPracticeDuelInstructions
+
+PracticeDuel_ReplaceKnockedOutPokemon:
+ ldh a, [hTempPlayAreaLocation_ff9d]
+ cp PLAY_AREA_BENCH_1
+ ret z
+ ; if player selected Drowzee instead (which is at PLAY_AREA_BENCH_2)
+ call HasAlivePokemonInBench
+ ldtx hl, SelectStaryuPracticeDuelText
+ scf
+; fallthrough
+
+; print a text box with given the text id at hl, labeled as 'Dr. Mason'
+PrintPracticeDuelDrMasonInstructions:
+ push af
+ ldtx de, DrMasonText
+ call PrintScrollableText_WithTextBoxLabel
+ pop af
+ ret
+
+INCLUDE "data/duel/practice_text.asm"
+
+; in a practice duel, draws the text box where the point-by-point
+; instructions for the next player action will be written into
+DrawPracticeDuelInstructionsTextBox:
+ call EmptyScreen
+ lb de, 0, 0
+ lb bc, 20, 12
+ call DrawRegularTextBox
+; fallthrough
+
+; print "<Player>'s Turn [wDuelTurns]" (usually) as the textbox label
+PrintPracticeDuelInstructionsTextBoxLabel:
+ ld a, [wDuelTurns]
+ cp 7
+ jr z, .replace_due_to_knockout
+ ; load the player's turn number to TX_RAM3 in order to print it
+ srl a
+ inc a
+ ld l, a
+ ld h, $00
+ call LoadTxRam3
+ lb de, 1, 0
+ call InitTextPrinting
+ ldtx hl, PlayersTurnPracticeDuelText
+ jp PrintText
+.replace_due_to_knockout
+ ; when the player needs to replace a knocked out Pokemon, the label text is different
+ ; this happens at the end of Sam's fourth turn
+ lb de, 1, 0
+ ldtx hl, ReplaceDueToKnockoutPracticeDuelText
+ jp InitTextPrinting_ProcessTextFromID
+
+; print the instructions of the current practice duel turn, taken from
+; one of the structs in PracticeDuelTextPointerTable.
+; if a != 0, only the point-by-point instructions are printed, otherwise
+; Dr. Mason instructions are also shown in a textbox at the bottom of the screen.
+PrintPracticeDuelInstructionsForCurrentTurn:
+ push af
+ ld a, [wDuelTurns]
+ and %11111110
+ ld e, a
+ ld d, $00
+ ld hl, PracticeDuelTextPointerTable
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ pop af
+ or a
+ jr nz, PrintPracticeDuelInstructions_Fast
+; fallthrough
+
+; print practice duel instructions given hl = PracticeDuelText_*
+; each practicetext entry (see above) contains a Dr. Mason text along with
+; a numbered instruction text, that is later printed without text delay.
+PrintPracticeDuelInstructions:
+ xor a
+ ld [wPracticeDuelTextY], a
+ ld a, l
+ ld [wPracticeDuelTextPointer], a
+ ld a, h
+ ld [wPracticeDuelTextPointer + 1], a
+.print_instructions_loop
+ call PrintNextPracticeDuelInstruction
+ ld a, [hli]
+ ld [wPracticeDuelTextY], a
+ or a
+ jr z, PrintPracticeDuelLetsPlayTheGame
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+ push hl
+ ld l, e
+ ld h, d
+ ldtx de, DrMasonText
+ call PrintScrollableText_WithTextBoxLabel
+ pop hl
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+ push hl
+ call SetNoLineSeparation
+ ld l, e
+ ld h, d
+ ld a, [wPracticeDuelTextY]
+ ld e, a
+ ld d, 1
+ call InitTextPrinting_ProcessTextFromID
+ call SetOneLineSeparation
+ pop hl
+ jr .print_instructions_loop
+
+; print the generic Dr. Mason's text that completes all his practice duel instructions
+PrintPracticeDuelLetsPlayTheGame:
+ ldtx hl, LetsPlayTheGamePracticeDuelText
+ call PrintPracticeDuelDrMasonInstructions
+ ret
+
+; simplified version of PrintPracticeDuelInstructions that skips Dr. Mason's text
+; and instead places the point-by-point instructions all at once.
+PrintPracticeDuelInstructions_Fast:
+ ld a, [hli]
+ or a
+ jr z, PrintPracticeDuelLetsPlayTheGame
+ ld e, a ; y
+ ld d, 1 ; x
+ call PrintPracticeDuelNumberedInstruction
+ jr PrintPracticeDuelInstructions_Fast
+
+; print a practice duel point-by-point instruction at d,e, with text id at hl,
+; that has been read from an entry of PracticeDuelText_*
+PrintPracticeDuelNumberedInstruction:
+ inc hl
+ inc hl
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+ inc hl
+ push hl
+ ld l, c
+ ld h, b
+ call SetNoLineSeparation
+ call InitTextPrinting_ProcessTextFromID
+ call SetOneLineSeparation
+ pop hl
+ ret
+
+; print a single instruction bullet for the current turn
+PrintNextPracticeDuelInstruction:
+ ld a, $01
+ ldh [hffb0], a
+ push hl
+ call PrintPracticeDuelInstructionsTextBoxLabel
+ ld hl, wPracticeDuelTextPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+.next
+ ld a, [wPracticeDuelTextY]
+ cp [hl]
+ jr c, .done
+ ld a, [hli]
+ or a
+ jr z, .done
+ ld e, a ; y
+ ld d, 1 ; x
+ call PrintPracticeDuelNumberedInstruction
+ jr .next
+.done
+ pop hl
+ xor a
+ ldh [hffb0], a
+ ret
+
+PracticeDuelTurnVerificationPointerTable:
+ dw PracticeDuelVerify_Turn1
+ dw PracticeDuelVerify_Turn2
+ dw PracticeDuelVerify_Turn3
+ dw PracticeDuelVerify_Turn4
+ dw PracticeDuelVerify_Turn5
+ dw PracticeDuelVerify_Turn6
+ dw PracticeDuelVerify_Turn7Or8
+ dw PracticeDuelVerify_Turn7Or8
+
+PracticeDuelVerify_Turn1:
+ ld a, [wTempCardID_ccc2]
+ cp GOLDEEN
+ jp nz, ReturnWrongAction
+ ret
+
+PracticeDuelVerify_Turn2:
+ ld a, [wTempCardID_ccc2]
+ cp SEAKING
+ jp nz, ReturnWrongAction
+ ld a, [wSelectedAttack]
+ cp 1
+ jp nz, ReturnWrongAction
+ ld e, PLAY_AREA_ARENA
+ call GetPlayAreaCardAttachedEnergies
+ ld a, [wAttachedEnergies + PSYCHIC]
+ or a
+ jr z, ReturnWrongAction
+ ret
+
+PracticeDuelVerify_Turn3:
+ ld a, [wTempCardID_ccc2]
+ cp SEAKING
+ jr nz, ReturnWrongAction
+ ld e, PLAY_AREA_BENCH_1
+ call GetPlayAreaCardAttachedEnergies
+ ld a, [wAttachedEnergies + WATER]
+ or a
+ jr z, ReturnWrongAction
+ ret
+
+PracticeDuelVerify_Turn4:
+ ld a, [wPlayerNumberOfPokemonInPlayArea]
+ cp 3
+ jr nz, ReturnWrongAction
+ ld e, PLAY_AREA_BENCH_2
+ call GetPlayAreaCardAttachedEnergies
+ ld a, [wAttachedEnergies + WATER]
+ or a
+ jr z, ReturnWrongAction
+ ld a, [wTempCardID_ccc2]
+ cp SEAKING
+ jr nz, ReturnWrongAction
+ ld a, [wSelectedAttack]
+ cp 1
+ jr nz, ReturnWrongAction
+ ret
+
+PracticeDuelVerify_Turn5:
+ ld e, PLAY_AREA_ARENA
+ call GetPlayAreaCardAttachedEnergies
+ ld a, [wAttachedEnergies + WATER]
+ cp 2
+ jr nz, ReturnWrongAction
+ ld a, [wTempCardID_ccc2]
+ cp STARYU
+ jr nz, ReturnWrongAction
+ ret
+
+PracticeDuelVerify_Turn6:
+ ld e, PLAY_AREA_ARENA
+ call GetPlayAreaCardAttachedEnergies
+ ld a, [wAttachedEnergies + WATER]
+ cp 3
+ jr nz, ReturnWrongAction
+ ld a, [wPlayerArenaCardHP]
+ cp 40
+ jr nz, ReturnWrongAction
+ ld a, [wTempCardID_ccc2]
+ cp STARYU
+ jr nz, ReturnWrongAction
+ ret
+
+PracticeDuelVerify_Turn7Or8:
+ ld a, [wTempCardID_ccc2]
+ cp STARMIE
+ jr nz, ReturnWrongAction
+ ld a, [wSelectedAttack]
+ cp 1
+ jr nz, ReturnWrongAction
+ ret
+
+ReturnWrongAction:
+ scf
+ ret
+
+; display BOXMSG_PLAYERS_TURN or BOXMSG_OPPONENTS_TURN and print
+; DuelistTurnText in a textbox. also call ExchangeRNG.
+DisplayDuelistTurnScreen:
+ call EmptyScreen
+ ld c, BOXMSG_PLAYERS_TURN
+ ldh a, [hWhoseTurn]
+ cp PLAYER_TURN
+ jr z, .got_turn
+ inc c ; BOXMSG_OPPONENTS_TURN
+.got_turn
+ ld a, c
+ call DrawDuelBoxMessage
+ ldtx hl, DuelistTurnText
+ call DrawWideTextBox_WaitForInput
+ call ExchangeRNG
+ ret
+
+Unknown_54e2: ; unreferenced
+ db $00, $0c, $06, $0f, $00, $00, $00
+
+DuelMenuData:
+ ; x, y, text id
+ textitem 3, 14, HandText
+ textitem 9, 14, CheckText
+ textitem 15, 14, RetreatText
+ textitem 3, 16, AttackText
+ textitem 9, 16, PKMNPowerText
+ textitem 15, 16, DoneText
+ db $ff
+
+; display the screen that prompts the player to choose a Pokemon card to
+; place in the arena or in the bench at the beginning of the duel.
+; input:
+ ; a = 0 -> prompted to place Pokemon card in arena
+ ; a = 1 -> prompted to place Pokemon card in bench
+; return carry if no card was placed (only allowed for bench)
+DisplayPlaceInitialPokemonCardsScreen:
+ ld [wPlacingInitialBenchPokemon], a
+ push hl
+ call CreateHandCardList
+ call InitAndDrawCardListScreenLayout
+ pop hl
+ call SetCardListInfoBoxText
+ ld a, PLAY_CHECK
+ ld [wCardListItemSelectionMenuType], a
+.display_card_list
+ call DisplayCardList
+ jr nc, .card_selected
+ ; attempted to exit screen
+ ld a, [wPlacingInitialBenchPokemon]
+ or a
+ ; player is forced to place a Pokemon card in the arena
+ jr z, .display_card_list
+ ; in the bench, however, we can get away without placing anything
+ ; alternatively, the player doesn't want or can't place more bench Pokemon
+ scf
+ jr .done
+.card_selected
+ ldh a, [hTempCardIndex_ff98]
+ call LoadCardDataToBuffer1_FromDeckIndex
+ call IsLoadedCard1BasicPokemon
+ jr nc, .done
+ ; invalid card selected, tell the player and go back
+ ldtx hl, YouCannotSelectThisCardText
+ call DrawWideTextBox_WaitForInput
+ call DrawCardListScreenLayout
+ jr .display_card_list
+.done
+ ; valid basic Pokemon card selected, or no card selected (bench only)
+ push af
+ ld a, [wSortCardListByID]
+ or a
+ call nz, SortHandCardsByID
+ pop af
+ ret
+
+Func_5542:
+ call CreateDiscardPileCardList
+ ret c
+ call InitAndDrawCardListScreenLayout
+ call SetDiscardPileScreenTexts
+ call DisplayCardList
+ ret
+
+; draw the turn holder's discard pile screen
+OpenDiscardPileScreen:
+ call CreateDiscardPileCardList
+ jr c, .discard_pile_empty
+ call InitAndDrawCardListScreenLayout
+ call SetDiscardPileScreenTexts
+ ld a, START + A_BUTTON
+ ld [wNoItemSelectionMenuKeys], a
+ call DisplayCardList
+ or a
+ ret
+.discard_pile_empty
+ ldtx hl, TheDiscardPileHasNoCardsText
+ call DrawWideTextBox_WaitForInput
+ scf
+ ret
+
+; set wCardListHeaderText and SetCardListInfoBoxText to the text
+; that correspond to the Discard Pile screen
+SetDiscardPileScreenTexts:
+ ldtx de, YourDiscardPileText
+ ldh a, [hWhoseTurn]
+ cp PLAYER_TURN
+ jr z, .got_header_text
+ ldtx de, OpponentsDiscardPileText
+.got_header_text
+ ldtx hl, ChooseTheCardYouWishToExamineText
+ call SetCardListHeaderText
+ ret
+
+SetCardListHeaderText:
+ ld a, e
+ ld [wCardListHeaderText], a
+ ld a, d
+ ld [wCardListHeaderText + 1], a
+; fallthrough
+
+SetCardListInfoBoxText:
+ ld a, l
+ ld [wCardListInfoBoxText], a
+ ld a, h
+ ld [wCardListInfoBoxText + 1], a
+ ret
+
+Func_5591:
+ call InitAndDrawCardListScreenLayout
+ ld a, SELECT_CHECK
+ ld [wCardListItemSelectionMenuType], a
+ ret
+
+; draw the layout of the screen that displays the player's Hand card list or a
+; Discard Pile card list, including a bottom-right image of the current card.
+; since this loads the text for the Hand card list screen, SetDiscardPileScreenTexts
+; is called after this if the screen corresponds to a Discard Pile list.
+; the dimensions of text box where the card list is printed are 20x13, in order to accommodate
+; another text box below it (wCardListInfoBoxText) as well as the image of the selected card.
+InitAndDrawCardListScreenLayout:
+ xor a
+ ld hl, wSelectedDuelSubMenuItem
+ ld [hli], a
+ ld [hl], a
+ ld [wSortCardListByID], a
+ ld hl, wPrintSortNumberInCardListPtr
+ ld [hli], a
+ ld [hl], a
+ ld [wCardListItemSelectionMenuType], a
+ ld a, START
+ ld [wNoItemSelectionMenuKeys], a
+ ld hl, wCardListInfoBoxText
+ ldtx [hl], PleaseSelectHandText, & $ff
+ inc hl
+ ldtx [hl], PleaseSelectHandText, >> 8
+ inc hl ; wCardListHeaderText
+ ldtx [hl], DuelistHandText, & $ff
+ inc hl
+ ldtx [hl], DuelistHandText, >> 8
+; fallthrough
+
+; same as InitAndDrawCardListScreenLayout, except that variables like wSelectedDuelSubMenuItem,
+; wNoItemSelectionMenuKeys, wCardListInfoBoxText, wCardListHeaderText, etc already set by caller.
+DrawCardListScreenLayout:
+ call ZeroObjectPositionsAndToggleOAMCopy
+ call EmptyScreen
+ call LoadSymbolsFont
+ call LoadDuelCardSymbolTiles
+ ; draw the surrounding box
+ lb de, 0, 0
+ lb bc, 20, 13
+ call DrawRegularTextBox
+ ; draw the image of the selected card
+ ld a, $a0
+ lb hl, 6, 1
+ lb de, 12, 12
+ lb bc, 8, 6
+ call FillRectangle
+ call ApplyBGP6OrSGB3ToCardImage
+ call Func_5744
+ ld a, [wDuelTempList]
+ cp $ff
+ scf
+ ret z
+ or a
+ ret
+
+; displays a list of cards and handles input in order to navigate through the list,
+; select a card, open a card page, etc.
+; input:
+ ; - text IDs at wCardListInfoBoxText and wCardListHeaderText
+ ; - $ff-terminated list of cards to display at wDuelTempList
+ ; - wSelectedDuelSubMenuItem (initial item) and wSelectedDuelSubMenuScrollOffset
+ ; (initial page scroll offset). Usually both 0 to begin with the first card.
+; returns carry if B is pressed to exit the card list screen.
+; otherwise returns the selected card at hTempCardIndex_ff98 and at a.
+DisplayCardList:
+ call DrawNarrowTextBox
+ call PrintCardListHeaderAndInfoBoxTexts
+.reload_list
+ ; get the list length
+ call CountCardsInDuelTempList
+ ; get the position and scroll within the list
+ ld hl, wSelectedDuelSubMenuItem
+ ld e, [hl] ; initial item (in the visible page)
+ inc hl
+ ld d, [hl] ; initial page scroll offset
+ ld hl, CardListParameters ; other list params
+ call PrintCardListItems
+ call LoadSelectedCardGfx
+ call EnableLCD
+.wait_button
+ call DoFrame
+ call Func_5690
+ call HandleCardListInput
+ jr nc, .wait_button
+ ; refresh the position of the last checked card of the list, so that
+ ; the cursor points to said card when the list is reloaded
+ ld hl, wSelectedDuelSubMenuItem
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ldh a, [hKeysPressed]
+ ld b, a
+ bit SELECT_F, b
+ jr nz, .select_pressed
+ bit B_BUTTON_F, b
+ jr nz, .b_pressed
+ ld a, [wNoItemSelectionMenuKeys]
+ and b
+ jr nz, .open_card_page
+ ; display the item selection menu (PLAY|CHECK or SELECT|CHECK) for the selected card
+ ; open the card page if CHECK is selected
+ ldh a, [hCurMenuItem]
+ call GetCardInDuelTempList_OnlyDeckIndex
+ call CardListItemSelectionMenu
+ ; jump back if B pressed to exit the item selection menu
+ jr c, DisplayCardList
+ ldh a, [hTempCardIndex_ff98]
+ or a
+ ret
+.select_pressed
+ ; sort cards by ID if SELECT is pressed and return to the first item
+ ld a, [wSortCardListByID]
+ or a
+ jr nz, .wait_button
+ call SortCardsInDuelTempListByID
+ xor a
+ ld hl, wSelectedDuelSubMenuItem
+ ld [hli], a
+ ld [hl], a
+ ld a, 1
+ ld [wSortCardListByID], a
+ call EraseCursor
+ jr .reload_list
+.open_card_page
+ ; open the card page directly, without an item selection menu
+ ; in this mode, D_UP and D_DOWN can be used to open the card page
+ ; of the card above and below the current card
+ ldh a, [hCurMenuItem]
+ call GetCardInDuelTempList
+ call LoadCardDataToBuffer1_FromDeckIndex
+ call OpenCardPage_FromCheckHandOrDiscardPile
+ ldh a, [hDPadHeld]
+ bit D_UP_F, a
+ jr nz, .up_pressed
+ bit D_DOWN_F, a
+ jr nz, .down_pressed
+ ; if B pressed, exit card page and reload the card list
+ call DrawCardListScreenLayout
+ jp DisplayCardList
+.up_pressed
+ ldh a, [hCurMenuItem]
+ or a
+ jr z, .open_card_page ; if can't go up, reload card page of current card
+ dec a
+ jr .move_to_another_card
+.down_pressed
+ call CountCardsInDuelTempList
+ ld b, a
+ ldh a, [hCurMenuItem]
+ inc a
+ cp b
+ jr nc, .open_card_page ; if can't go down, reload card page of current card
+.move_to_another_card
+ ; update hCurMenuItem, and wSelectedDuelSubMenuScrollOffset.
+ ; this means that when navigating up/down through card pages, the page is
+ ; scrolled to reflect the movement, rather than the cursor going up/down.
+ ldh [hCurMenuItem], a
+ ld hl, wSelectedDuelSubMenuItem
+ ld [hl], $00
+ inc hl
+ ld [hl], a
+ jr .open_card_page
+.b_pressed
+ ldh a, [hCurMenuItem]
+ scf
+ ret
+
+Func_5690:
+ ldh a, [hDPadHeld]
+ and D_PAD
+ ret z
+ ld a, $01
+ ldh [hffb0], a
+ call PrintCardListHeaderAndInfoBoxTexts
+ xor a
+ ldh [hffb0], a
+ ret
+
+; prints the text ID at wCardListHeaderText at 1,1
+; and the text ID at wCardListInfoBoxText at 1,14
+PrintCardListHeaderAndInfoBoxTexts:
+ lb de, 1, 14
+ call AdjustCoordinatesForBGScroll
+ call InitTextPrinting
+ ld hl, wCardListInfoBoxText
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call PrintTextNoDelay
+ ld hl, wCardListHeaderText
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ lb de, 1, 1
+ call InitTextPrinting
+ call PrintTextNoDelay
+ ret
+
+; display the SELECT|CHECK or PLAY|CHECK menu when a card of a list is selected
+; and handle input. return carry if b is pressed.
+; input: wCardListItemSelectionMenuType
+CardListItemSelectionMenu:
+ ld a, [wCardListItemSelectionMenuType]
+ or a
+ ret z
+ ldtx hl, SelectCheckText
+ ld a, [wCardListItemSelectionMenuType]
+ cp PLAY_CHECK
+ jr nz, .got_text
+ ldh a, [hTempCardIndex_ff98]
+ call LoadCardDataToBuffer1_FromDeckIndex
+ ldtx hl, PlayCheck2Text ; identical to PlayCheck1Text
+ ld a, [wLoadedCard1Type]
+ cp TYPE_TRAINER
+ jr nz, .got_text
+ ldtx hl, PlayCheck1Text
+.got_text
+ call DrawNarrowTextBox_PrintTextNoDelay
+ ld hl, ItemSelectionMenuParameters
+ xor a
+ call InitializeMenuParameters
+.wait_a_or_b
+ call DoFrame
+ call HandleMenuInput
+ jr nc, .wait_a_or_b
+ cp -1
+ jr z, .b_pressed
+ ; A pressed
+ or a
+ ret z
+ ; CHECK option selected: open the card page
+ ldh a, [hTempCardIndex_ff98]
+ call LoadCardDataToBuffer1_FromDeckIndex
+ call OpenCardPage_FromHand
+ call DrawCardListScreenLayout
+.b_pressed
+ scf
+ ret
+
+ItemSelectionMenuParameters:
+ db 1, 14 ; cursor x, cursor y
+ db 2 ; y displacement between items
+ db 2 ; number of items
+ db SYM_CURSOR_R ; cursor tile number
+ db SYM_SPACE ; tile behind cursor
+ dw NULL ; function pointer if non-0
+
+CardListParameters:
+ db 1, 3 ; cursor x, cursor y
+ db 4 ; item x
+ db 14 ; maximum length, in tiles, occupied by the name and level string of each card in the list
+ db 5 ; number of items selectable without scrolling
+ db SYM_CURSOR_R ; cursor tile number
+ db SYM_SPACE ; tile behind cursor
+ dw CardListFunction ; function pointer if non-0
+
+; return carry if any of the buttons is pressed, and load the graphics
+; of the card pointed to by the cursor whenever a d-pad key is released.
+; also return $ff unto hCurMenuItem if B is pressed.
+CardListFunction:
+ ldh a, [hKeysPressed]
+ bit B_BUTTON_F, a
+ jr nz, .exit
+ and A_BUTTON | SELECT | START
+ jr nz, .action_button
+ ldh a, [hKeysReleased]
+ and D_PAD
+ jr nz, .reload_card_image ; jump if the D_PAD key was released this frame
+ ret
+.exit
+ ld a, $ff
+ ldh [hCurMenuItem], a
+.action_button
+ scf
+ ret
+.reload_card_image
+ call LoadSelectedCardGfx
+ or a
+ ret
+
+Func_5735:
+ ld hl, wPrintSortNumberInCardListPtr
+ ld de, PrintSortNumberInCardList
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ld a, 1
+ ld [wSortCardListByID], a
+ ret
+
+Func_5744:
+ ld hl, wPrintSortNumberInCardListPtr
+ jp CallIndirect
+
+; goes through list in wDuelTempList + 10
+; and prints the number stored in each entry
+; beside the corresponding card in screen.
+; used in lists for reordering cards in the Deck.
+PrintSortNumberInCardList:
+ lb bc, 1, 2
+ ld hl, wDuelTempList + 10
+.next
+ ld a, [hli]
+ cp $ff
+ jr z, .done
+ or a ; SYM_SPACE
+ jr z, .space
+ add SYM_0 ; load number symbol
+.space
+ call WriteByteToBGMap0
+ ; move two lines down
+ inc c
+ inc c
+ jr .next
+.done
+ ret
+
+; draw the card page of the card at wLoadedCard1 and listen for input
+; in order to switch the page or to exit.
+; triggered by checking a hand card or a discard pile card in the Check menu.
+; D_UP and D_DOWN exit the card page allowing the caller to load the card page
+; of the card above or below in the list.
+OpenCardPage_FromCheckHandOrDiscardPile:
+ ld a, B_BUTTON | D_UP | D_DOWN
+ ld [wCardPageExitKeys], a
+ xor a ; CARDPAGETYPE_NOT_PLAY_AREA
+ jr OpenCardPage
+
+; draw the card page of the card at wLoadedCard1 and listen for input
+; in order to switch the page or to exit.
+; triggered by checking an arena card or a bench card in the Check menu.
+OpenCardPage_FromCheckPlayArea:
+ ld a, B_BUTTON
+ ld [wCardPageExitKeys], a
+ ld a, CARDPAGETYPE_PLAY_AREA
+ jr OpenCardPage
+
+; draw the card page of the card at wLoadedCard1 and listen for input
+; in order to switch the page or to exit.
+; triggered by checking a card in the Hand menu.
+OpenCardPage_FromHand:
+ ld a, B_BUTTON
+ ld [wCardPageExitKeys], a
+ xor a ; CARDPAGETYPE_NOT_PLAY_AREA
+; fallthrough
+
+; draw the card page of the card at wLoadedCard1 and listen for input
+; in order to switch the page or to exit.
+OpenCardPage:
+ ld [wCardPageType], a
+ call ZeroObjectPositionsAndToggleOAMCopy
+ call EmptyScreen
+ call Func_3b31
+ ; load the graphics and display the card image of wLoadedCard1
+ call LoadDuelCardSymbolTiles
+ ld de, v0Tiles1 + $20 tiles
+ call LoadLoaded1CardGfx
+ call SetOBP1OrSGB3ToCardPalette
+ call SetBGP6OrSGB3ToCardPalette
+ call FlushAllPalettesOrSendPal23Packet
+ lb de, $38, $30 ; X Position and Y Position of top-left corner
+ call PlaceCardImageOAM
+ lb de, 6, 4
+ call ApplyBGP6OrSGB3ToCardImage
+ ; display the initial card page for the card at wLoadedCard1
+ xor a
+ ld [wCardPageNumber], a
+.load_next
+ call DisplayFirstOrNextCardPage
+ jr c, .done ; done if trying to advance past the last page with START or A_BUTTON
+ call EnableLCD
+.input_loop
+ call DoFrame
+ ldh a, [hDPadHeld]
+ ld b, a
+ ld a, [wCardPageExitKeys]
+ and b
+ jr nz, .done
+ ; START and A_BUTTON advance to the next valid card page, but close it
+ ; after trying to advance from the last page
+ ldh a, [hKeysPressed]
+ and START | A_BUTTON
+ jr nz, .load_next
+ ; D_RIGHT and D_LEFT advance to the next and previous valid card page respectively.
+ ; however, unlike START and A_BUTTON, D_RIGHT past the last page goes back to the start.
+ ldh a, [hKeysPressed]
+ and D_RIGHT | D_LEFT
+ jr z, .input_loop
+ call DisplayCardPageOnLeftOrRightPressed
+ jr .input_loop
+.done
+ ret
+
+; display the previous valid card page of the card at wLoadedCard1 if bit D_LEFT_F
+; of a is set, and the first or next valid card page otherwise.
+; DisplayFirstOrNextCardPage and DisplayPreviousCardPage only call DisplayCardPage
+; when GoToFirstOrNextCardPage and GoToPreviousCardPage respectively return nc
+; so the "call c, DisplayCardPage" instructions makes sure the card page switched
+; to is always displayed.
+DisplayCardPageOnLeftOrRightPressed:
+ bit D_LEFT_F, a
+ jr nz, .left
+;.right
+ call DisplayFirstOrNextCardPage
+ call c, DisplayCardPage
+ ret
+.left
+ call DisplayPreviousCardPage
+ call c, DisplayCardPage
+ ret
+
+; draws text box that covers the whole screen
+; and prints the text ID in hl, then
+; waits for Player input.
+DrawWholeScreenTextBox:
+ push hl
+ call EmptyScreen
+ lb de, 0, 0
+ lb bc, 20, 18
+ call DrawRegularTextBox
+ ld a, 19
+ lb de, 1, 1
+ call InitTextPrintingInTextbox
+ call SetNoLineSeparation
+ pop hl
+ call ProcessTextFromID
+ call EnableLCD
+ call SetOneLineSeparation
+ call WaitForWideTextBoxInput
+ ret
+
+Func_5805:
+ call Func_3b31
+ ld a, [wNumberPrizeCardsToTake]
+ ld l, a
+ ld h, $00
+ call LoadTxRam3
+ ld a, DUELVARS_DUELIST_TYPE
+ call GetTurnDuelistVariable
+ cp DUELIST_TYPE_PLAYER
+ jr nz, .opponent
+
+; player
+ ldtx hl, WillDrawNPrizesText
+ call DrawWideTextBox_WaitForInput
+ ld a, [wNumberPrizeCardsToTake]
+ call SelectPrizeCards
+ ld hl, hTemp_ffa0
+ ld d, [hl]
+ inc hl
+ ld e, [hl]
+ call SerialSend8Bytes
+
+.return_has_prizes
+ call ExchangeRNG
+ ld a, DUELVARS_PRIZES
+ call GetTurnDuelistVariable
+ or a
+ ret nz
+ scf
+ ret
+
+.opponent
+ call Func_588a
+ ldtx hl, WillDrawNPrizesText
+ call DrawWideTextBox_PrintText
+ call CountPrizes
+ ld [wTempNumRemainingPrizeCards], a
+ ld a, DUELVARS_DUELIST_TYPE
+ call GetTurnDuelistVariable
+ cp DUELIST_TYPE_LINK_OPP
+ jr z, .link_opponent
+ call AIDoAction_TakePrize
+ ld c, 60
+.delay_loop
+ call DoFrame
+ dec c
+ jr nz, .delay_loop
+ jr .asm_586f
+
+.link_opponent
+ call SerialRecv8Bytes
+ ld a, DUELVARS_PRIZES
+ call GetTurnDuelistVariable
+ ld [hl], d
+ ld a, e
+ cp $ff
+ call nz, AddCardToHand
+
+.asm_586f
+ ld a, [wTempNumRemainingPrizeCards]
+ ld hl, wNumberPrizeCardsToTake
+ cp [hl]
+ jr nc, .asm_587e
+ ld l, a
+ ld h, $00
+ call LoadTxRam3
+.asm_587e
+ farcall Func_82b6
+ ldtx hl, DrewNPrizesText
+ call DrawWideTextBox_WaitForInput
+ jr .return_has_prizes
+
+Func_588a:
+ ld l, PLAYER_TURN
+ ldh a, [hWhoseTurn]
+ ld h, a
+ jp DrawYourOrOppPlayAreaScreen_Bank0
+
+; display the previous valid card page
+DisplayPreviousCardPage:
+ call GoToPreviousCardPage
+ jr nc, DisplayCardPage
+ ret
+
+; display the next valid card page or load the first valid card page if [wCardPageNumber] == 0
+DisplayFirstOrNextCardPage:
+ call GoToFirstOrNextCardPage
+ ret c
+; fallthrough
+
+; display the card page with id at wCardPageNumber of wLoadedCard1
+DisplayCardPage:
+ ld a, [wCardPageNumber]
+ ld hl, CardPageDisplayPointerTable
+ call JumpToFunctionInTable
+ call EnableLCD
+ or a
+ ret
+
+; load the tiles and palette of the card selected in card list screen
+LoadSelectedCardGfx:
+ ldh a, [hCurMenuItem]
+ call GetCardInDuelTempList
+ call LoadCardDataToBuffer1_FromCardID
+ ld de, v0Tiles1 + $20 tiles
+ call LoadLoaded1CardGfx
+ ld de, $c0c ; useless
+ call SetBGP6OrSGB3ToCardPalette
+ call FlushAllPalettesOrSendPal23Packet
+ ret
+
+CardPageDisplayPointerTable:
+ dw DrawDuelMainScene
+ dw DisplayCardPage_PokemonOverview ; CARDPAGE_POKEMON_OVERVIEW
+ dw DisplayCardPage_PokemonAttack1Page1 ; CARDPAGE_POKEMON_ATTACK1_1
+ dw DisplayCardPage_PokemonAttack1Page2 ; CARDPAGE_POKEMON_ATTACK1_2
+ dw DisplayCardPage_PokemonAttack2Page1 ; CARDPAGE_POKEMON_ATTACK2_1
+ dw DisplayCardPage_PokemonAttack2Page2 ; CARDPAGE_POKEMON_ATTACK2_2
+ dw DisplayCardPage_PokemonDescription ; CARDPAGE_POKEMON_DESCRIPTION
+ dw DrawDuelMainScene
+ dw DrawDuelMainScene
+ dw DisplayCardPage_Energy ; CARDPAGE_ENERGY
+ dw DisplayCardPage_Energy ; CARDPAGE_ENERGY + 1
+ dw DrawDuelMainScene
+ dw DrawDuelMainScene
+ dw DisplayCardPage_TrainerPage1 ; CARDPAGE_TRAINER_1
+ dw DisplayCardPage_TrainerPage2 ; CARDPAGE_TRAINER_2
+ dw DrawDuelMainScene
+
+; given the current card page at [wCardPageNumber], go to the next valid card page or load
+; the first valid card page of the current card at wLoadedCard1 if [wCardPageNumber] == 0
+GoToFirstOrNextCardPage:
+ ld a, [wCardPageNumber]
+ or a
+ jr nz, .advance_page
+ ; load the first page for this type of card
+ ld a, [wLoadedCard1Type]
+ ld b, a
+ ld a, CARDPAGE_ENERGY
+ bit TYPE_ENERGY_F, b
+ jr nz, .set_initial_page
+ ld a, CARDPAGE_TRAINER_1
+ bit TYPE_TRAINER_F, b
+ jr nz, .set_initial_page
+ ld a, CARDPAGE_POKEMON_OVERVIEW
+.set_initial_page
+ ld [wCardPageNumber], a
+ or a
+ ret
+.advance_page
+ ld hl, wCardPageNumber
+ inc [hl]
+ ld a, [hl]
+ call SwitchCardPage
+ jr c, .set_card_page
+ ; stay in this page if it exists, or skip to previous page if it doesn't
+ or a
+ ret nz
+ ; non-existent page: skip to next
+ jr .advance_page
+.set_card_page
+ ld [wCardPageNumber], a
+ ret
+
+; given the current card page at [wCardPageNumber], go to the previous
+; valid card page for the current card at wLoadedCard1
+GoToPreviousCardPage:
+ ld hl, wCardPageNumber
+ dec [hl]
+ ld a, [hl]
+ call SwitchCardPage
+ jr c, .set_card_page
+ ; stay in this page if it exists, or skip to previous page if it doesn't
+ or a
+ ret nz
+ ; non-existent page: skip to previous
+ jr GoToPreviousCardPage
+.set_card_page
+ ld [wCardPageNumber], a
+.previous_page_loop
+ call SwitchCardPage
+ or a
+ jr nz, .stay
+ ld hl, wCardPageNumber
+ dec [hl]
+ jr .previous_page_loop
+.stay
+ scf
+ ret
+
+; check if the card page trying to switch to is valid for the card at wLoadedCard1
+; return with the equivalent to one of these three actions:
+ ; stay in card page trying to switch to (nc, nz)
+ ; change to card page returned in a if D_LEFT/D_RIGHT pressed, or exit if A_BUTTON/START pressed (c)
+ ; non-existent page, so skip to next/previous (nc, z)
+SwitchCardPage:
+ ld hl, CardPageSwitchPointerTable
+ jp JumpToFunctionInTable
+
+CardPageSwitchPointerTable:
+ dw CardPageSwitch_00
+ dw CardPageSwitch_PokemonOverviewOrDescription ; CARDPAGE_POKEMON_OVERVIEW
+ dw CardPageSwitch_PokemonAttack1Page1 ; CARDPAGE_POKEMON_ATTACK1_1
+ dw CardPageSwitch_PokemonAttack1Page2 ; CARDPAGE_POKEMON_ATTACK1_2
+ dw CardPageSwitch_PokemonAttack2Page1 ; CARDPAGE_POKEMON_ATTACK2_1
+ dw CardPageSwitch_PokemonAttack2Page2 ; CARDPAGE_POKEMON_ATTACK2_2
+ dw CardPageSwitch_PokemonOverviewOrDescription ; CARDPAGE_POKEMON_DESCRIPTION
+ dw CardPageSwitch_PokemonEnd
+ dw CardPageSwitch_08
+ dw CardPageSwitch_EnergyOrTrainerPage1 ; CARDPAGE_ENERGY
+ dw CardPageSwitch_TrainerPage2 ; CARDPAGE_ENERGY + 1
+ dw CardPageSwitch_EnergyEnd
+ dw CardPageSwitch_0c
+ dw CardPageSwitch_EnergyOrTrainerPage1 ; CARDPAGE_TRAINER_1
+ dw CardPageSwitch_TrainerPage2 ; CARDPAGE_TRAINER_2
+ dw CardPageSwitch_TrainerEnd
+
+; return with CARDPAGE_POKEMON_DESCRIPTION
+CardPageSwitch_00:
+ ld a, CARDPAGE_POKEMON_DESCRIPTION
+ scf
+ ret
+
+; return with current page
+CardPageSwitch_PokemonOverviewOrDescription:
+ ld a, $1
+ or a
+ ret ; nz
+
+; return with current page if [wLoadedCard1Atk1Name] non-0
+; (if card has at least one attack)
+CardPageSwitch_PokemonAttack1Page1:
+ ld hl, wLoadedCard1Atk1Name
+ jr CheckCardPageExists
+
+; return with current page if [wLoadedCard1Atk1Description + 2] non-0
+; (if card's first attack has a two-page description)
+CardPageSwitch_PokemonAttack1Page2:
+ ld hl, wLoadedCard1Atk1Description + 2
+ jr CheckCardPageExists
+
+; return with current page if [wLoadedCard1Atk2Name] non-0
+; (if card has two attacks)
+CardPageSwitch_PokemonAttack2Page1:
+ ld hl, wLoadedCard1Atk2Name
+ jr CheckCardPageExists
+
+; return with current page if [wLoadedCard1Atk1Description + 2] non-0
+; (if card's second attack has a two-page description)
+CardPageSwitch_PokemonAttack2Page2:
+ ld hl, wLoadedCard1Atk2Description + 2
+; fallthrough
+
+CheckCardPageExists:
+ ld a, [hli]
+ or [hl]
+ ret
+
+; return with CARDPAGE_POKEMON_OVERVIEW
+CardPageSwitch_PokemonEnd:
+ ld a, CARDPAGE_POKEMON_OVERVIEW
+ scf
+ ret
+
+; return with CARDPAGE_ENERGY + 1
+CardPageSwitch_08:
+ ld a, CARDPAGE_ENERGY + 1
+ scf
+ ret
+
+; return with current page
+CardPageSwitch_EnergyOrTrainerPage1:
+ ld a, $1
+ or a
+ ret ; nz
+
+; return with current page if [wLoadedCard1NonPokemonDescription + 2] non-0
+; (if this trainer card has a two-page description)
+CardPageSwitch_TrainerPage2:
+ ld hl, wLoadedCard1NonPokemonDescription + 2
+ jr CheckCardPageExists
+
+; return with CARDPAGE_ENERGY
+CardPageSwitch_EnergyEnd:
+ ld a, CARDPAGE_ENERGY
+ scf
+ ret
+
+; return with CARDPAGE_TRAINER_2
+CardPageSwitch_0c:
+ ld a, CARDPAGE_TRAINER_2
+ scf
+ ret
+
+; return with CARDPAGE_TRAINER_1
+CardPageSwitch_TrainerEnd:
+ ld a, CARDPAGE_TRAINER_1
+ scf
+ ret
+
+ZeroObjectPositionsAndToggleOAMCopy:
+ call ZeroObjectPositions
+ ld a, $01
+ ld [wVBlankOAMCopyToggle], a
+ ret
+
+; place OAM for a 8x6 image, using object size 8x16 and obj palette 1.
+; d, e: X Position and Y Position of the top-left corner.
+; starting tile number is $a0 (v0Tiles1 + $20 tiles).
+; used to draw the image of a card in the check card screens.
+PlaceCardImageOAM:
+ call Set_OBJ_8x16
+ ld l, $a0
+ ld c, 8 ; number of rows
+.next_column
+ ld b, 3 ; number of columns
+ push de
+.next_row
+ push bc
+ ld c, l ; tile number
+ ld b, 1 ; attributes (palette)
+ call SetOneObjectAttributes
+ pop bc
+ inc l
+ inc l ; next 8x16 tile
+ ld a, 16
+ add e ; Y Position += 16 (next 8x16 row)
+ ld e, a
+ dec b
+ jr nz, .next_row
+ pop de
+ ld a, 8
+ add d ; X Position += 8 (next 8x16 column)
+ ld d, a
+ dec c
+ jr nz, .next_column
+ ld a, $01
+ ld [wVBlankOAMCopyToggle], a
+ ret
+
+; given the deck index of a card in the play area (i.e. -1 indicates empty)
+; load the graphics (tiles and palette) of the card to de
+LoadPlayAreaCardGfx:
+ cp -1
+ ret z
+ push de
+ call LoadCardDataToBuffer1_FromDeckIndex
+ pop de
+; fallthrough
+
+; load the graphics (tiles and palette) of the card loaded in wLoadedCard1 to de
+LoadLoaded1CardGfx:
+ ld hl, wLoadedCard1Gfx
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ lb bc, $30, TILE_SIZE
+ call LoadCardGfx
+ ret
+
+SetBGP7OrSGB2ToCardPalette:
+ ld a, [wConsole]
+ or a ; CONSOLE_DMG
+ ret z
+ cp CONSOLE_SGB
+ jr z, .sgb
+ ld a, $07 ; CGB BG Palette 7
+ call CopyCGBCardPalette
+ ret
+.sgb
+ ld hl, wCardPalette
+ ld de, wTempSGBPacket + 1 ; PAL Packet color #0 (PAL23's SGB2)
+ ld b, CGB_PAL_SIZE
+.copy_pal_loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .copy_pal_loop
+ ret
+
+SetBGP6OrSGB3ToCardPalette:
+ ld a, [wConsole]
+ or a ; CONSOLE_DMG
+ ret z
+ cp CONSOLE_SGB
+ jr z, SetSGB3ToCardPalette
+ ld a, $06 ; CGB BG Palette 6
+ call CopyCGBCardPalette
+ ret
+
+SetSGB3ToCardPalette:
+ ld hl, wCardPalette + 2
+ ld de, wTempSGBPacket + 9 ; Pal Packet color #4 (PAL23's SGB3)
+ ld b, 6
+ jr SetBGP7OrSGB2ToCardPalette.copy_pal_loop
+
+SetOBP1OrSGB3ToCardPalette:
+ ld a, $e4
+ ld [wOBP0], a
+ ld a, [wConsole]
+ or a ; CONSOLE_DMG
+ ret z
+ cp CONSOLE_SGB
+ jr z, SetSGB3ToCardPalette
+ ld a, $09 ; CGB Object Palette 1
+; fallthrough
+
+CopyCGBCardPalette:
+ add a
+ add a
+ add a ; a *= CGB_PAL_SIZE
+ ld e, a
+ ld d, $00
+ ld hl, wBackgroundPalettesCGB ; wObjectPalettesCGB - 8 palettes
+ add hl, de
+ ld de, wCardPalette
+ ld b, CGB_PAL_SIZE
+.copy_pal_loop
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec b
+ jr nz, .copy_pal_loop
+ ret
+
+FlushAllPalettesOrSendPal23Packet:
+ ld a, [wConsole]
+ or a ; CONSOLE_DMG
+ ret z
+ cp CONSOLE_SGB
+ jr z, .sgb
+ call FlushAllPalettes
+ ret
+.sgb
+; sgb PAL23, 1 ; sgb_command, length
+; rgb 28, 28, 24
+; colors 1-7 carried over
+ ld a, PAL23 << 3 + 1
+ ld hl, wTempSGBPacket
+ ld [hli], a
+ ld a, LOW(24 << 10 | 28 << 5 | 28)
+ ld [hli], a
+ ld a, HIGH(24 << 10 | 28 << 5 | 28)
+ ld [hld], a
+ dec hl
+ xor a
+ ld [wTempSGBPacket + $f], a
+ call SendSGB
+ ret
+
+ApplyBGP6OrSGB3ToCardImage:
+ ld a, [wConsole]
+ or a ; CONSOLE_DMG
+ ret z
+ cp CONSOLE_SGB
+ jr z, .sgb
+ ld a, $06 ; CGB BG Palette 6
+ call ApplyCardCGBAttributes
+ ret
+.sgb
+ ld a, 3 << 0 + 3 << 2 ; Color Palette Designation
+; fallthrough
+
+SendCardAttrBlkPacket:
+ call CreateCardAttrBlkPacket
+ call SendSGB
+ ret
+
+ApplyBGP7OrSGB2ToCardImage:
+ ld a, [wConsole]
+ or a ; CONSOLE_DMG
+ ret z
+ cp CONSOLE_SGB
+ jr z, .sgb
+ ld a, $07 ; CGB BG Palette 7
+ call ApplyCardCGBAttributes
+ ret
+.sgb
+ ld a, 2 << 0 + 2 << 2 ; Color Palette Designation
+ jr SendCardAttrBlkPacket
+
+Func_5a81:
+ ld a, [wConsole]
+ or a ; CONSOLE_DMG
+ ret z
+ cp CONSOLE_SGB
+ jr z, .sgb
+ lb de, 0, 5
+ call ApplyBGP7OrSGB2ToCardImage
+ lb de, 12, 1
+ call ApplyBGP6OrSGB3ToCardImage
+ ret
+.sgb
+ ld a, 2 << 0 + 2 << 2 ; Data Set #1: Color Palette Designation
+ lb de, 0, 5 ; Data Set #1: X, Y
+ call CreateCardAttrBlkPacket
+ push hl
+ ld a, 2
+ ld [wTempSGBPacket + 1], a ; set number of data sets to 2
+ ld hl, wTempSGBPacket + 8
+ ld a, 3 << 0 + 3 << 2 ; Data Set #2: Color Palette Designation
+ lb de, 12, 1 ; Data Set #2: X, Y
+ call CreateCardAttrBlkPacket_DataSet
+ pop hl
+ call SendSGB
+ ret
+
+CreateCardAttrBlkPacket:
+; sgb ATTR_BLK, 1 ; sgb_command, length
+; db 1 ; number of data sets
+ ld hl, wTempSGBPacket
+ push hl
+ ld [hl], ATTR_BLK << 3 + 1
+ inc hl
+ ld [hl], 1
+ inc hl
+ call CreateCardAttrBlkPacket_DataSet
+ xor a
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ pop hl
+ ret
+
+CreateCardAttrBlkPacket_DataSet:
+; Control Code, Color Palette Designation, X1, Y1, X2, Y2
+; db ATTR_BLK_CTRL_INSIDE + ATTR_BLK_CTRL_LINE, a, d, e, d+7, e+5 ; data set 1
+ ld [hl], ATTR_BLK_CTRL_INSIDE + ATTR_BLK_CTRL_LINE
+ inc hl
+ ld [hl], a
+ inc hl
+ ld [hl], d
+ inc hl
+ ld [hl], e
+ inc hl
+ ld a, 7
+ add d
+ ld [hli], a
+ ld a, 5
+ add e
+ ld [hli], a
+ ret
+
+; given the 8x6 card image with coordinates at de, fill its BGMap attributes with a
+ApplyCardCGBAttributes:
+ call BankswitchVRAM1
+ lb hl, 0, 0
+ lb bc, 8, 6
+ call FillRectangle
+ call BankswitchVRAM0
+ ret
+
+; set the default game palettes for all three systems
+; BGP and OBP0 on DMG
+; SGB0 and SGB1 on SGB
+; BGP0 to BGP5 and OBP1 on CGB
+SetDefaultPalettes:
+ ld a, [wConsole]
+ cp CONSOLE_SGB
+ jr z, .sgb
+ cp CONSOLE_CGB
+ jr z, .cgb
+ ld a, $e4
+ ld [wOBP0], a
+ ld [wBGP], a
+ ld a, $01 ; equivalent to FLUSH_ONE_PAL
+ ld [wFlushPaletteFlags], a
+ ret
+.cgb
+ ld a, $04
+ ld [wTextBoxFrameType], a
+ ld de, CGBDefaultPalettes
+ ld hl, wBackgroundPalettesCGB
+ ld c, 5 palettes
+ call .copy_de_to_hl
+ ld de, CGBDefaultPalettes
+ ld hl, wObjectPalettesCGB
+ ld c, CGB_PAL_SIZE
+ call .copy_de_to_hl
+ call FlushAllPalettes
+ ret
+.sgb
+ ld a, $04
+ ld [wTextBoxFrameType], a
+ ld a, PAL01 << 3 + 1
+ ld hl, wTempSGBPacket
+ push hl
+ ld [hli], a
+ ld de, Pal01Packet_Default
+ ld c, $0e
+ call .copy_de_to_hl
+ ld [hl], c
+ pop hl
+ call SendSGB
+ ret
+
+.copy_de_to_hl
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec c
+ jr nz, .copy_de_to_hl
+ ret
+
+CGBDefaultPalettes:
+; BGP0 and OBP0
+ rgb 28, 28, 24
+ rgb 21, 21, 16
+ rgb 10, 10, 8
+ rgb 0, 0, 0
+; BGP1
+ rgb 28, 28, 24
+ rgb 30, 29, 0
+ rgb 30, 3, 0
+ rgb 0, 0, 0
+; BGP2
+ rgb 28, 28, 24
+ rgb 0, 18, 0
+ rgb 12, 11, 20
+ rgb 0, 0, 0
+; BGP3
+ rgb 28, 28, 24
+ rgb 22, 0, 22
+ rgb 27, 7, 3
+ rgb 0, 0, 0
+; BGP4
+ rgb 28, 28, 24
+ rgb 26, 10, 0
+ rgb 28, 0, 0
+ rgb 0, 0, 0
+
+; first and last byte of the packet not contained here (see SetDefaultPalettes.sgb)
+Pal01Packet_Default:
+; SGB0
+ rgb 28, 28, 24
+ rgb 21, 21, 16
+ rgb 10, 10, 8
+ rgb 0, 0, 0
+; SGB1
+ rgb 26, 10, 0
+ rgb 28, 0, 0
+ rgb 0, 0, 0
+
+JPWriteByteToBGMap0:
+ jp WriteByteToBGMap0
+
+DisplayCardPage_PokemonOverview:
+ ld a, [wCardPageType]
+ or a ; CARDPAGETYPE_NOT_PLAY_AREA
+ jr nz, .play_area_card_page
+
+; CARDPAGETYPE_NOT_PLAY_AREA
+ ; print surrounding box, card name at 5,1, type, set 2, and rarity
+ call PrintPokemonCardPageGenericInformation
+ ; print fixed text and draw the card symbol associated to its TYPE_*
+ ld hl, CardPageRetreatWRTextData
+ call PlaceTextItems
+ ld hl, CardPageLvHPNoTextTileData
+ call WriteDataBlocksToBGMap0
+ lb de, 3, 2
+ call DrawCardSymbol
+ ; print pre-evolution's name (if any)
+ ld a, [wLoadedCard1Stage]
+ or a
+ jr z, .basic
+ ld hl, wLoadedCard1PreEvoName
+ lb de, 1, 3
+ call InitTextPrinting_ProcessTextFromPointerToID
+.basic
+ ; print card level and maximum HP
+ lb bc, 12, 2
+ ld a, [wLoadedCard1Level]
+ call WriteTwoDigitNumberInTxSymbolFormat
+ lb bc, 16, 2
+ ld a, [wLoadedCard1HP]
+ call WriteTwoByteNumberInTxSymbolFormat
+ jr .print_numbers_and_energies
+
+; CARDPAGETYPE_PLAY_AREA
+.play_area_card_page
+ ; draw the surrounding box, and print fixed text
+ call DrawCardPageSurroundingBox
+ call LoadDuelCheckPokemonScreenTiles
+ ld hl, CardPageRetreatWRTextData
+ call PlaceTextItems
+ ld hl, CardPageNoTextTileData
+ call WriteDataBlocksToBGMap0
+ ld a, 1
+ ld [wCurPlayAreaY], a
+ ; print set 2 icon and rarity symbol at fixed positions
+ call DrawCardPageSet2AndRarityIcons
+ ; print (Y coord at [wCurPlayAreaY]) card name, level, type, energies, HP, location...
+ call PrintPlayAreaCardInformationAndLocation
+
+; common for both card page types
+.print_numbers_and_energies
+ ; print Pokedex number in the bottom right corner (16,16)
+ lb bc, 16, 16
+ ld a, [wLoadedCard1PokedexNumber]
+ call WriteTwoByteNumberInTxSymbolFormat
+ ; print the name, damage, and energy cost of each attack and/or Pokemon power that exists
+ ; first attack at 5,10 and second at 5,12
+ lb bc, 5, 10
+
+.attacks
+ ld e, c
+ ld hl, wLoadedCard1Atk1Name
+ call PrintAttackOrPkmnPowerInformation
+ inc c
+ inc c ; 12
+ ld e, c
+ ld hl, wLoadedCard1Atk2Name
+ call PrintAttackOrPkmnPowerInformation
+ ; print the retreat cost (some amount of colorless energies) at 8,14
+ inc c
+ inc c ; 14
+ ld b, 8
+ ld a, [wLoadedCard1RetreatCost]
+ ld e, a
+ inc e
+.retreat_cost_loop
+ dec e
+ jr z, .retreat_cost_done
+ ld a, SYM_COLORLESS
+ call JPWriteByteToBGMap0
+ inc b
+ jr .retreat_cost_loop
+.retreat_cost_done
+ ; print the colors (energies) of the weakness(es) and resistance(s)
+ inc c ; 15
+ ld a, [wCardPageType]
+ or a
+ jr z, .wr_from_loaded_card
+ ld a, [wCurPlayAreaSlot]
+ or a
+ jr nz, .wr_from_loaded_card
+ call GetArenaCardWeakness
+ ld d, a
+ call GetArenaCardResistance
+ ld e, a
+ jr .got_wr
+.wr_from_loaded_card
+ ld a, [wLoadedCard1Weakness]
+ ld d, a
+ ld a, [wLoadedCard1Resistance]
+ ld e, a
+.got_wr
+ ld a, d
+ ld b, 8
+ call PrintCardPageWeaknessesOrResistances
+ inc c ; 16
+ ld a, e
+ call PrintCardPageWeaknessesOrResistances
+ ret
+
+; displays the name, damage, and energy cost of an attack or Pokemon power.
+; used in the Attack menu and in the card page of a Pokemon.
+; input:
+ ; hl: pointer to attack 1 name in a atk_data_struct (which can be inside at card_data_struct)
+ ; e: Y coordinate to start printing the data at
+PrintAttackOrPkmnPowerInformation:
+ ld a, [hli]
+ or [hl]
+ ret z
+ push bc
+ push hl
+ dec hl
+ ; print text ID pointed to by hl at 7,e
+ ld d, 7
+ call InitTextPrinting_ProcessTextFromPointerToID
+ pop hl
+ inc hl
+ inc hl
+ ld a, [wCardPageNumber]
+ or a
+ jr nz, .print_damage
+ dec hl
+ ld a, [hli]
+ or [hl]
+ jr z, .print_damage
+ ; if in Attack menu and attack 1 description exists, print at 18,e:
+ ld b, 18
+ ld c, e
+ ld a, SYM_ATK_DESCR
+ call WriteByteToBGMap0
+.print_damage
+ inc hl
+ inc hl
+ inc hl
+ push hl
+ ld a, [hl]
+ or a
+ jr z, .print_category
+ ; print attack damage at 15,(e+1) if non-0
+ ld b, 15 ; unless damage has three digits, this is effectively 16
+ ld c, e
+ inc c
+ call WriteTwoByteNumberInTxSymbolFormat
+.print_category
+ pop hl
+ inc hl
+ ld a, [hl]
+ and $ff ^ RESIDUAL
+ jr z, .print_energy_cost
+ cp POKEMON_POWER
+ jr z, .print_pokemon_power
+ ; register a is DAMAGE_PLUS, DAMAGE_MINUS, or DAMAGE_X
+ ; print the damage modifier (+, -, x) at 18,(e+1) (after the damage value)
+ add SYM_PLUS - DAMAGE_PLUS
+ ld b, 18
+ ld c, e
+ inc c
+ call WriteByteToBGMap0
+ jr .print_energy_cost
+.print_energy_cost
+ ld bc, CARD_DATA_ATTACK1_ENERGY_COST - CARD_DATA_ATTACK1_CATEGORY
+ add hl, bc
+ ld c, e
+ ld b, 2 ; bc = 2, e
+ lb de, NUM_TYPES / 2, 0
+.energy_loop
+ ld a, [hl]
+ swap a
+ call PrintEnergiesOfColor
+ ld a, [hli]
+ call PrintEnergiesOfColor
+ dec d
+ jr nz, .energy_loop
+ pop bc
+ ret
+.print_pokemon_power
+ ; print "PKMN PWR" at 2,e
+ ld d, 2
+ ldtx hl, PKMNPWRText
+ call InitTextPrinting_ProcessTextFromID
+ pop bc
+ ret
+
+; print the number of energies required of color (type) e, and return e ++ (next color).
+; the requirement of the current color is provided as input in the lower nybble of a.
+PrintEnergiesOfColor:
+ inc e
+ and $0f
+ ret z
+ push de
+ ld d, a
+.print_energies_loop
+ ld a, e
+ call JPWriteByteToBGMap0
+ inc b
+ dec d
+ jr nz, .print_energies_loop
+ pop de
+ ret
+
+; print the weaknesses or resistances of a Pokemon card, given in a, at b,c
+PrintCardPageWeaknessesOrResistances:
+ push bc
+ push de
+ ld d, a
+ xor a ; FIRE
+.loop
+ ; each WR_* constant is a different bit. rotate the value to find out
+ ; which bits are set and therefore which WR_* values are active.
+ ; a is kept updated with the equivalent TYPE_* constant.
+ inc a
+ cp 8
+ jr nc, .done
+ rl d
+ jr nc, .loop
+ push af
+ call JPWriteByteToBGMap0
+ inc b
+ pop af
+ jr .loop
+.done
+ pop de
+ pop bc
+ ret
+
+; prints surrounding box, card name at 5,1, type, set 2, and rarity.
+; used in all CARDPAGE_POKEMON_* and ATTACKPAGE_*, except in
+; CARDPAGE_POKEMON_OVERVIEW when wCardPageType is CARDPAGETYPE_PLAY_AREA.
+PrintPokemonCardPageGenericInformation:
+ call DrawCardPageSurroundingBox
+ lb de, 5, 1
+ ld hl, wLoadedCard1Name
+ call InitTextPrinting_ProcessTextFromPointerToID
+ ld a, [wCardPageType]
+ or a
+ jr z, .from_loaded_card
+ ld a, [wCurPlayAreaSlot]
+ call GetPlayAreaCardColor
+ jr .got_color
+.from_loaded_card
+ ld a, [wLoadedCard1Type]
+.got_color
+ lb bc, 18, 1
+ inc a
+ call JPWriteByteToBGMap0
+ call DrawCardPageSet2AndRarityIcons
+ ret
+
+; draws the 20x18 surrounding box and also colorizes the card image
+DrawCardPageSurroundingBox:
+ ld hl, wTextBoxFrameType
+ set 7, [hl] ; colorize textbox border also on SGB (with SGB1)
+ push hl
+ lb de, 0, 0
+ lb bc, 20, 18
+ call DrawRegularTextBox
+ pop hl
+ res 7, [hl]
+ lb de, 6, 4
+ call ApplyBGP6OrSGB3ToCardImage
+ ret
+
+CardPageRetreatWRTextData:
+ textitem 1, 14, RetreatCostText
+ textitem 1, 15, WeaknessText
+ textitem 1, 16, ResistanceText
+ db $ff
+
+CardPageLvHPNoTextTileData:
+ db 11, 2, SYM_Lv, 0
+ db 15, 2, SYM_HP, 0
+; continues to CardPageNoTextTileData
+
+CardPageNoTextTileData:
+ db 15, 16, SYM_No, 0
+ db $ff
+
+DisplayCardPage_PokemonAttack1Page1:
+ ld hl, wLoadedCard1Atk1Name
+ ld de, wLoadedCard1Atk1Description
+ jr DisplayPokemonAttackCardPage
+
+DisplayCardPage_PokemonAttack1Page2:
+ ld hl, wLoadedCard1Atk1Name
+ ld de, wLoadedCard1Atk1Description + 2
+ jr DisplayPokemonAttackCardPage
+
+DisplayCardPage_PokemonAttack2Page1:
+ ld hl, wLoadedCard1Atk2Name
+ ld de, wLoadedCard1Atk2Description
+ jr DisplayPokemonAttackCardPage
+
+DisplayCardPage_PokemonAttack2Page2:
+ ld hl, wLoadedCard1Atk2Name
+ ld de, wLoadedCard1Atk2Description + 2
+; fallthrough
+
+; input:
+ ; hl = address of the attack's name (text id)
+ ; de = address of the attack's description (either first or second text id)
+DisplayPokemonAttackCardPage:
+ push de
+ push hl
+ ; print surrounding box, card name at 5,1, type, set 2, and rarity
+ call PrintPokemonCardPageGenericInformation
+ ; print name, damage, and energy cost of attack or Pokemon power starting at line 2
+ ld e, 2
+ pop hl
+ call PrintAttackOrPkmnPowerInformation
+ pop hl
+; fallthrough
+
+; print, if non-null, the description of the trainer card, energy card, attack,
+; or Pokemon power, given as a pointer to text id in hl, starting from 1,11
+PrintAttackOrNonPokemonCardDescription:
+ ld a, [hli]
+ or [hl]
+ ret z
+ dec hl
+ lb de, 1, 11
+ call PrintAttackOrCardDescription
+ ret
+
+DisplayCardPage_PokemonDescription:
+ ; print surrounding box, card name at 5,1, type, set 2, and rarity
+ call PrintPokemonCardPageGenericInformation
+ call LoadDuelCardSymbolTiles2
+ ; print "LENGTH", "WEIGHT", "Lv", and "HP" where it corresponds in the page
+ ld hl, CardPageLengthWeightTextData
+ call PlaceTextItems
+ ld hl, CardPageLvHPTextTileData
+ call WriteDataBlocksToBGMap0
+ ; draw the card symbol associated to its TYPE_* at 3,2
+ lb de, 3, 2
+ call DrawCardSymbol
+ ; print the Level and HP numbers at 12,2 and 16,2 respectively
+ lb bc, 12, 2
+ ld a, [wLoadedCard1Level]
+ call WriteTwoDigitNumberInTxSymbolFormat
+ lb bc, 16, 2
+ ld a, [wLoadedCard1HP]
+ call WriteTwoByteNumberInTxSymbolFormat
+ ; print the Pokemon's category at 1,10 (just above the length and weight texts)
+ lb de, 1, 10
+ ld hl, wLoadedCard1Category
+ call InitTextPrinting_ProcessTextFromPointerToID
+ ld a, TX_KATAKANA
+ call ProcessSpecialTextCharacter
+ ldtx hl, PokemonText
+ call ProcessTextFromID
+ ; print the length and weight values at 5,11 and 5,12 respectively
+ lb bc, 5, 11
+ ld hl, wLoadedCard1Length
+ ld a, [hli]
+ ld l, [hl]
+ ld h, a
+ call PrintPokemonCardLength
+ lb bc, 5, 12
+ ld hl, wLoadedCard1Weight
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call PrintPokemonCardWeight
+ ldtx hl, LbsText
+ call InitTextPrinting_ProcessTextFromID
+ ; print the card's description without line separation
+ call SetNoLineSeparation
+ ld hl, wLoadedCard1Description
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call CountLinesOfTextFromID
+ lb de, 1, 13
+ cp 4
+ jr nc, .print_description
+ inc e ; move a line down, as the description is short enough to fit in three lines
+.print_description
+ ld a, 19 ; line length
+ call InitTextPrintingInTextbox
+ ld hl, wLoadedCard1Description
+ call ProcessTextFromPointerToID
+ call SetOneLineSeparation
+ ret
+
+; given a card rarity constant in a, and CardRarityTextIDs in hl,
+; print the text character associated to it at d,e
+PrintCardPageRarityIcon:
+ inc a
+ add a
+ ld c, a
+ ld b, $00
+ add hl, bc
+ call InitTextPrinting_ProcessTextFromPointerToID
+ ret
+
+; prints the card's set 2 icon and the full width text character of the card's rarity
+DrawCardPageSet2AndRarityIcons:
+ ld a, [wLoadedCard1Set]
+ call LoadCardSet2Tiles
+ jr c, .icon_done
+ ; draw the 2x2 set 2 icon of this card
+ ld a, $fc
+ lb hl, 1, 2
+ lb bc, 2, 2
+ lb de, 15, 8
+ call FillRectangle
+.icon_done
+ lb de, 18, 9
+ ld hl, CardRarityTextIDs
+ ld a, [wLoadedCard1Rarity]
+ cp PROMOSTAR
+ call nz, PrintCardPageRarityIcon
+ ret
+
+CardPageLengthWeightTextData:
+ textitem 1, 11, LengthText
+ textitem 1, 12, WeightText
+ db $ff
+
+CardPageLvHPTextTileData:
+ db 11, 2, SYM_Lv, 0
+ db 15, 2, SYM_HP, 0
+ db $ff
+
+CardRarityTextIDs:
+ tx PromostarRarityText ; PROMOSTAR (unused)
+ tx CircleRarityText ; CIRCLE
+ tx DiamondRarityText ; DIAMOND
+ tx StarRarityText ; STAR
+
+DisplayCardPage_TrainerPage1:
+ xor a ; HEADER_TRAINER
+ ld hl, wLoadedCard1NonPokemonDescription
+ jr DisplayEnergyOrTrainerCardPage
+
+DisplayCardPage_TrainerPage2:
+ xor a ; HEADER_TRAINER
+ ld hl, wLoadedCard1NonPokemonDescription + 2
+ jr DisplayEnergyOrTrainerCardPage
+
+DisplayCardPage_Energy:
+ ld a, HEADER_ENERGY
+ ld hl, wLoadedCard1NonPokemonDescription
+; fallthrough
+
+; input:
+ ; a = HEADER_ENERGY or HEADER_TRAINER
+ ; hl = address of the card's description (text id)
+DisplayEnergyOrTrainerCardPage:
+ push hl
+ call LoadCardTypeHeaderTiles
+ ; draw surrounding box
+ lb de, 0, 0
+ lb bc, 20, 18
+ call DrawRegularTextBox
+ ; print the card's name at 4,3
+ lb de, 4, 3
+ ld hl, wLoadedCard1Name
+ call InitTextPrinting_ProcessTextFromPointerToID
+ ; colorize the card image
+ lb de, 6, 4
+ call ApplyBGP6OrSGB3ToCardImage
+ ; display the card type header
+ ld a, $e0
+ lb hl, 1, 8
+ lb de, 6, 1
+ lb bc, 8, 2
+ call FillRectangle
+ ; print the set 2 icon and rarity symbol of the card
+ call DrawCardPageSet2AndRarityIcons
+ pop hl
+ call PrintAttackOrNonPokemonCardDescription
+ ret
+
+; display the card details of the card in wLoadedCard1
+; print the text at hl
+_DisplayCardDetailScreen:
+ push hl
+ call DrawLargePictureOfCard
+ ld a, 18
+ call CopyCardNameAndLevel
+ ld [hl], TX_END
+ ld hl, 0
+ call LoadTxRam2
+ pop hl
+ call DrawWideTextBox_WaitForInput
+ ret
+
+; draw a large picture of the card loaded in wLoadedCard1, including its image
+; and a header indicating the type of card (TRAINER, ENERGY, PoKéMoN)
+DrawLargePictureOfCard:
+ call ZeroObjectPositionsAndToggleOAMCopy
+ call EmptyScreen
+ call LoadSymbolsFont
+ call SetDefaultPalettes
+ ld a, LARGE_CARD_PICTURE
+ ld [wDuelDisplayedScreen], a
+ call LoadCardOrDuelMenuBorderTiles
+ ld e, HEADER_TRAINER
+ ld a, [wLoadedCard1Type]
+ cp TYPE_TRAINER
+ jr z, .draw
+ ld e, HEADER_ENERGY
+ and TYPE_ENERGY
+ jr nz, .draw
+ ld e, HEADER_POKEMON
+.draw
+ ld a, e
+ call LoadCardTypeHeaderTiles
+ ld de, v0Tiles1 + $20 tiles
+ call LoadLoaded1CardGfx
+ call SetBGP6OrSGB3ToCardPalette
+ call FlushAllPalettesOrSendPal23Packet
+ ld hl, LargeCardTileData
+ call WriteDataBlocksToBGMap0
+ lb de, 6, 3
+ call ApplyBGP6OrSGB3ToCardImage
+ ret
+
+LargeCardTileData:
+ db 5, 0, $d0, $d4, $d4, $d4, $d4, $d4, $d4, $d4, $d4, $d1, 0 ; top border
+ db 5, 1, $d6, $e0, $e1, $e2, $e3, $e4, $e5, $e6, $e7, $d7, 0 ; header top
+ db 5, 2, $d6, $e8, $e9, $ea, $eb, $ec, $ed, $ee, $ef, $d7, 0 ; header bottom
+ db 5, 3, $d6, $a0, $a6, $ac, $b2, $b8, $be, $c4, $ca, $d7, 0 ; image
+ db 5, 4, $d6, $a1, $a7, $ad, $b3, $b9, $bf, $c5, $cb, $d7, 0 ; image
+ db 5, 5, $d6, $a2, $a8, $ae, $b4, $ba, $c0, $c6, $cc, $d7, 0 ; image
+ db 5, 6, $d6, $a3, $a9, $af, $b5, $bb, $c1, $c7, $cd, $d7, 0 ; image
+ db 5, 7, $d6, $a4, $aa, $b0, $b6, $bc, $c2, $c8, $ce, $d7, 0 ; image
+ db 5, 8, $d6, $a5, $ab, $b1, $b7, $bd, $c3, $c9, $cf, $d7, 0 ; image
+ db 5, 9, $d6, 0 ; empty line 1 (left)
+ db 14, 9, $d7, 0 ; empty line 1 (right)
+ db 5, 10, $d6, 0 ; empty line 2 (left)
+ db 14, 10, $d7, 0 ; empty line 2 (right)
+ db 5, 11, $d2, $d5, $d5, $d5, $d5, $d5, $d5, $d5, $d5, $d3, 0 ; bottom border
+ db $ff
+
+; print lines of text with no separation between them
+SetNoLineSeparation:
+ ld a, $01
+; fallthrough
+
+SetLineSeparation:
+ ld [wLineSeparation], a
+ ret
+
+; separate lines of text by an empty line
+SetOneLineSeparation:
+ xor a
+ jr SetLineSeparation
+
+; given a number in hl, print it divided by 10 at b,c, with decimal part
+; separated by a dot (unless it's 0). used to print a Pokemon card's weight.
+PrintPokemonCardWeight:
+ push bc
+ ld de, -1
+ ld bc, -10
+.divide_by_10_loop
+ inc de
+ add hl, bc
+ jr c, .divide_by_10_loop
+ ld bc, 10
+ add hl, bc
+ pop bc
+ push hl
+ push bc
+ ld l, e
+ ld h, d
+ call TwoByteNumberToTxSymbol_TrimLeadingZeros_Bank1
+ pop bc
+ pop hl
+ ld a, l
+ ld hl, wStringBuffer + 5
+ or a
+ jr z, .decimal_done
+ ld [hl], SYM_DOT
+ inc hl
+ add SYM_0
+ ld [hli], a
+.decimal_done
+ ld [hl], 0
+ push bc
+ call BCCoordToBGMap0Address
+ ld hl, wStringBuffer
+.find_first_digit_loop
+ ld a, [hli]
+ or a
+ jr z, .find_first_digit_loop
+ dec hl
+ push hl
+ ld b, -1
+.get_number_length_loop
+ inc b
+ ld a, [hli]
+ or a
+ jr nz, .get_number_length_loop
+ pop hl
+ push bc
+ call SafeCopyDataHLtoDE
+ pop bc
+ pop de
+ ld a, b
+ add d
+ ld d, a
+ ret
+
+; given a number in h and another in l, print them formatted as <l>'<h>" at b,c.
+; used to print the length (feet and inches) of a Pokemon card.
+PrintPokemonCardLength:
+ push hl
+ ld l, h
+ ld h, $00
+ ldtx de, FeetText ; '
+ call .print_feet_or_inches
+ pop hl
+ ld h, $00
+ ldtx de, InchesText ; "
+ call .print_feet_or_inches
+ ret
+
+.print_feet_or_inches
+; keep track how many digits each number consists of in wPokemonLengthPrintOffset,
+; in order to align the rest of the string. the text with id at de
+; is printed after the number.
+ push de
+ push bc
+ call TwoByteNumberToTxSymbol_TrimLeadingZeros_Bank1
+ ld a, b
+ inc a
+ ld [wPokemonLengthPrintOffset], a
+ pop bc
+ push bc
+ push hl
+ call BCCoordToBGMap0Address
+ ld a, [wPokemonLengthPrintOffset]
+ ld b, a
+ pop hl
+ call SafeCopyDataHLtoDE
+ pop bc
+ ld a, [wPokemonLengthPrintOffset]
+ add b
+ ld b, a
+ pop hl
+ push bc
+ ld e, c
+ ld d, b
+ call InitTextPrinting
+ call ProcessTextFromID
+ pop bc
+ inc b
+ ret
+
+; return carry if the turn holder has any Pokemon with non-zero HP on the bench.
+; return how many Pokemon with non-zero HP in b.
+; does this by calculating how many Pokemon in play area minus one
+HasAlivePokemonInBench:
+ ld a, $01
+ jr _HasAlivePokemonInPlayArea
+
+; return carry if the turn holder has any Pokemon with non-zero HP in the play area.
+; return how many Pokemon with non-zero HP in b.
+HasAlivePokemonInPlayArea:
+ xor a
+; fallthrough
+
+_HasAlivePokemonInPlayArea:
+ ld [wExcludeArenaPokemon], a
+ ld b, a
+ ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA
+ call GetTurnDuelistVariable
+ sub b
+ ld c, a
+ ld a, DUELVARS_ARENA_CARD_HP
+ add b
+ call GetTurnDuelistVariable
+ ld b, 0
+ inc c
+ xor a
+ ld [wPlayAreaScreenLoaded], a
+ ld [wcbd4], a
+ jr .next_pkmn
+.loop
+ ld a, [hli]
+ or a
+ jr z, .next_pkmn ; jump if this play area Pokemon has 0 HP
+ inc b
+.next_pkmn
+ dec c
+ jr nz, .loop
+ ld a, b
+ or a
+ ret nz
+ scf
+ ret
+
+OpenPlayAreaScreenForViewing:
+ ld a, START + A_BUTTON
+ jr DisplayPlayAreaScreen
+
+OpenPlayAreaScreenForSelection:
+ ld a, START
+; fallthrough
+
+DisplayPlayAreaScreen:
+ ld [wNoItemSelectionMenuKeys], a
+ ldh a, [hTempCardIndex_ff98]
+ push af
+ ld a, [wPlayAreaScreenLoaded]
+ or a
+ jr nz, .skip_ahead
+ xor a
+ ld [wSelectedDuelSubMenuItem], a
+ inc a
+ ld [wPlayAreaScreenLoaded], a
+.asm_6022
+ call ZeroObjectPositionsAndToggleOAMCopy
+ call EmptyScreen
+ call LoadDuelCardSymbolTiles
+ call LoadDuelCheckPokemonScreenTiles
+ call PrintPlayAreaCardList
+ call EnableLCD
+.skip_ahead
+ ld hl, PlayAreaScreenMenuParameters_ActivePokemonIncluded
+ ld a, [wExcludeArenaPokemon]
+ or a
+ jr z, .init_menu_params
+ ld hl, PlayAreaScreenMenuParameters_ActivePokemonExcluded
+.init_menu_params
+ ld a, [wSelectedDuelSubMenuItem]
+ call InitializeMenuParameters
+ ld a, [wNumPlayAreaItems]
+ ld [wNumMenuItems], a
+.asm_604c
+ call DoFrame
+ call Func_60dd
+ jr nc, .asm_6061
+ cp $02
+ jp z, .asm_60ac
+ pop af
+ ldh [hTempCardIndex_ff98], a
+ ld a, [wcbd4] ; useless
+ jr OpenPlayAreaScreenForSelection
+.asm_6061
+ call HandleMenuInput
+ jr nc, .asm_604c
+ ld a, e
+ ld [wSelectedDuelSubMenuItem], a
+ ld a, [wExcludeArenaPokemon]
+ add e
+ ld [wCurPlayAreaSlot], a
+ ld a, [wNoItemSelectionMenuKeys]
+ ld b, a
+ ldh a, [hKeysPressed]
+ and b
+ jr z, .asm_6091
+ ld a, [wCurPlayAreaSlot]
+ add DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ cp -1
+ jr z, .asm_6022
+ call GetCardIDFromDeckIndex
+ call LoadCardDataToBuffer1_FromCardID
+ call OpenCardPage_FromCheckPlayArea
+ jr .asm_6022
+.asm_6091
+ ld a, [wExcludeArenaPokemon]
+ ld c, a
+ ldh a, [hCurMenuItem]
+ add c
+ ldh [hTempPlayAreaLocation_ff9d], a
+ ldh a, [hCurMenuItem]
+ cp $ff
+ jr z, .asm_60b5
+ ldh a, [hTempPlayAreaLocation_ff9d]
+ add DUELVARS_ARENA_CARD_HP
+ call GetTurnDuelistVariable
+ or a
+ jr nz, .asm_60ac
+ jr .skip_ahead
+.asm_60ac
+ pop af
+ ldh [hTempCardIndex_ff98], a
+ ldh a, [hTempPlayAreaLocation_ff9d]
+ ldh [hCurMenuItem], a
+ or a
+ ret
+.asm_60b5
+ pop af
+ ldh [hTempCardIndex_ff98], a
+ ldh a, [hTempPlayAreaLocation_ff9d]
+ ldh [hCurMenuItem], a
+ scf
+ ret
+
+PlayAreaScreenMenuParameters_ActivePokemonIncluded:
+ db 0, 0 ; cursor x, cursor y
+ db 3 ; y displacement between items
+ db 6 ; number of items
+ db SYM_CURSOR_R ; cursor tile number
+ db SYM_SPACE ; tile behind cursor
+ dw PlayAreaScreenMenuFunction ; function pointer if non-0
+
+PlayAreaScreenMenuParameters_ActivePokemonExcluded:
+ db 0, 3 ; cursor x, cursor y
+ db 3 ; y displacement between items
+ db 6 ; number of items
+ db SYM_CURSOR_R ; cursor tile number
+ db SYM_SPACE ; tile behind cursor
+ dw PlayAreaScreenMenuFunction ; function pointer if non-0
+
+PlayAreaScreenMenuFunction:
+ ldh a, [hKeysPressed]
+ and A_BUTTON | B_BUTTON | START
+ ret z
+ bit B_BUTTON_F, a
+ jr z, .start_or_a
+ ld a, $ff
+ ldh [hCurMenuItem], a
+.start_or_a
+ scf
+ ret
+
+Func_60dd:
+ ld a, [wcbd4]
+ or a
+ ret z
+ ldh a, [hKeysPressed]
+ and SELECT
+ ret z
+ ld a, [wcbd4]
+ cp $02
+ jr z, .asm_6121
+ xor a
+ ld [wCurrentDuelMenuItem], a
+.asm_60f2
+ call DrawDuelMainScene
+ ldtx hl, SelectingBenchPokemonHandExamineBackText
+ call DrawWideTextBox_PrintTextNoDelay
+ call Func_615c
+.asm_60fe
+ call DoFrame
+ ldh a, [hKeysPressed]
+ and A_BUTTON
+ jr nz, .a_pressed
+ call Func_6137
+ call RefreshMenuCursor
+ xor a
+ call Func_6862
+ jr nc, .asm_60fe
+ ldh a, [hKeysPressed]
+ and SELECT
+ jr z, .asm_60f2
+.asm_6119
+ call HasAlivePokemonInBench
+ ld a, $01
+ ld [wcbd4], a
+.asm_6121
+ scf
+ ret
+.a_pressed
+ ld a, [wCurrentDuelMenuItem]
+ cp 2
+ jr z, .asm_6119
+ or a
+ jr z, .asm_6132
+ call OpenDuelCheckMenu
+ jr .asm_60f2
+.asm_6132
+ call OpenTurnHolderHandScreen_Simple
+ jr .asm_60f2
+
+Func_6137:
+ ldh a, [hDPadHeld]
+ bit 1, a
+ ret nz
+ and D_RIGHT | D_LEFT
+ ret z
+ ld b, a
+ ld a, [wCurrentDuelMenuItem]
+ bit D_LEFT_F, b
+ jr z, .asm_6150
+ dec a
+ bit D_DOWN_F, a
+ jr z, .asm_6156
+ ld a, 2
+ jr .asm_6156
+.asm_6150
+ inc a
+ cp 3
+ jr c, .asm_6156
+ xor a
+.asm_6156
+ ld [wCurrentDuelMenuItem], a
+ call EraseCursor
+; fallthrough
+
+Func_615c:
+ ld a, [wCurrentDuelMenuItem]
+ ld d, a
+ add a
+ add d
+ add a
+ add 2
+ ld d, a
+ ld e, 16
+ lb bc, SYM_CURSOR_R, SYM_SPACE
+ jp SetCursorParametersForTextBox
+
+Func_616e:
+ ldh [hTempPlayAreaLocation_ff9d], a
+ call ZeroObjectPositionsAndToggleOAMCopy
+ call EmptyScreen
+ call LoadDuelCardSymbolTiles
+ call LoadDuelCheckPokemonScreenTiles
+ xor a
+ ld [wExcludeArenaPokemon], a
+ call PrintPlayAreaCardList
+ call EnableLCD
+; fallthrough
+
+Func_6186:
+ ld hl, wCurPlayAreaSlot
+ ldh a, [hTempPlayAreaLocation_ff9d]
+ ld [hli], a
+ ld c, a
+ add a
+ add c
+ ld [hl], a
+ call PrintPlayAreaCardInformationAndLocation
+ ret
+
+Func_6194:
+ call Func_6186
+ ld a, [wCurPlayAreaY]
+ ld e, a
+ ld d, 0
+ call SetCursorParametersForTextBox_Default
+ ret
+
+Func_61a1:
+ xor a
+ ld [wExcludeArenaPokemon], a
+ ld a, [wDuelDisplayedScreen]
+ cp PLAY_AREA_CARD_LIST
+ ret z
+ call ZeroObjectPositionsAndToggleOAMCopy
+ call EmptyScreen
+ call LoadDuelCardSymbolTiles
+ call LoadDuelCheckPokemonScreenTiles
+ ret
+
+; for each turn holder's play area Pokemon card, print the name, level,
+; face down stage card, color symbol, status symbol (if any), pluspower/defender
+; symbols (if any), attached energies (if any), and HP bar.
+; also print the play area locations (ACT/BPx indicators) for each of the six slots.
+; return the value of wNumPlayAreaItems (as returned from PrintPlayAreaCardList) in a.
+PrintPlayAreaCardList_EnableLCD:
+ ld a, PLAY_AREA_CARD_LIST
+ ld [wDuelDisplayedScreen], a
+ call PrintPlayAreaCardList
+ call EnableLCD
+ ld a, [wNumPlayAreaItems]
+ ret
+
+; for each turn holder's play area Pokemon card, print the name, level,
+; face down stage card, color symbol, status symbol (if any), pluspower/defender
+; symbols (if any), attached energies (if any), and HP bar.
+; also print the play area locations (ACT/BPx indicators) for each of the six slots.
+PrintPlayAreaCardList:
+ ld a, PLAY_AREA_CARD_LIST
+ ld [wDuelDisplayedScreen], a
+ ld de, wDuelTempList
+ call SetListPointer
+ ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA
+ call GetTurnDuelistVariable
+ ld c, a
+ ld b, $00
+.print_cards_info_loop
+ ; for each Pokemon card in play area, print its information (and location)
+ push hl
+ push bc
+ ld a, b
+ ld [wCurPlayAreaSlot], a
+ ld a, b
+ add a
+ add b
+ ld [wCurPlayAreaY], a
+ ld a, b
+ add DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ call SetNextElementOfList
+ call PrintPlayAreaCardInformationAndLocation
+ pop bc
+ pop hl
+ inc b
+ dec c
+ jr nz, .print_cards_info_loop
+ push bc
+.print_locations_loop
+ ; print all play area location indicators (even if there's no Pokemon card on it)
+ ld a, b
+ cp MAX_PLAY_AREA_POKEMON
+ jr z, .locations_printed
+ ld [wCurPlayAreaSlot], a
+ add a
+ add b
+ ld [wCurPlayAreaY], a
+ push bc
+ call PrintPlayAreaCardLocation
+ pop bc
+ inc b
+ jr .print_locations_loop
+.locations_printed
+ pop bc
+ ld a, b
+ ld [wNumPlayAreaItems], a
+ ld a, [wExcludeArenaPokemon]
+ or a
+ ret z
+ ; if wExcludeArenaPokemon is set, decrement [wNumPlayAreaItems] and shift back wDuelTempList
+ dec b
+ ld a, b
+ ld [wNumPlayAreaItems], a
+ ld hl, wDuelTempList + 1
+ ld de, wDuelTempList
+.shift_back_loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .shift_back_loop
+ ret
+
+; print a turn holder's play area Pokemon card's name, level, face down stage card,
+; color symbol, status symbol (if any), pluspower/defender symbols (if any),
+; attached energies (if any), HP bar, and the play area location (ACT/BPx indicator)
+; input:
+ ; wCurPlayAreaSlot: PLAY_AREA_* of the card to display the information of
+ ; wCurPlayAreaY: Y coordinate of where to print the card's information
+; total space occupied is a rectangle of 20x3 tiles
+PrintPlayAreaCardInformationAndLocation:
+ ld a, [wCurPlayAreaSlot]
+ add DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ cp -1
+ ret z
+ call PrintPlayAreaCardInformation
+; fallthrough
+
+; print a turn holder's play area Pokemon card's location (ACT/BPx indicator)
+PrintPlayAreaCardLocation:
+ ; print the ACT/BPx indicator
+ ld a, [wCurPlayAreaSlot]
+ add a
+ add a
+ ld e, a
+ ld d, $00
+ ld hl, PlayAreaLocationTileNumbers
+ add hl, de
+ ldh a, [hWhoseTurn]
+ cp PLAYER_TURN
+ jr z, .write_tiles
+ ; move forward to the opponent's side tile numbers
+ ; they have black letters and white background instead of the other way around
+ ld d, $0a
+.write_tiles
+ ld a, [wCurPlayAreaY]
+ ld b, 1
+ ld c, a
+ ld a, [hli]
+ add d
+ call WriteByteToBGMap0
+ inc c
+ ld a, [hli]
+ add d
+ call WriteByteToBGMap0
+ inc c
+ ld a, [hli]
+ add d
+ call WriteByteToBGMap0
+ ret
+
+PlayAreaLocationTileNumbers:
+ db $e0, $e1, $e2, $00 ; ACT
+ db $e3, $e4, $e5, $00 ; BP1
+ db $e3, $e4, $e6, $00 ; BP2
+ db $e3, $e4, $e7, $00 ; BP3
+ db $e3, $e4, $e8, $00 ; BP4
+ db $e3, $e4, $e9, $00 ; BP5
+
+; print a turn holder's play area Pokemon card's name, level, face down stage card,
+; color symbol, status symbol (if any), pluspower/defender symbols (if any),
+; attached energies (if any), and HP bar.
+; input:
+ ; wCurPlayAreaSlot: PLAY_AREA_* of the card to display the information of
+ ; wCurPlayAreaY: Y coordinate of where to print the card's information
+; total space occupied is a rectangle of 20x3 tiles
+PrintPlayAreaCardInformation:
+ ; print name, level, color, stage, status, pluspower/defender
+ call PrintPlayAreaCardHeader
+ ; print the symbols of the attached energies
+ ld a, [wCurPlayAreaSlot]
+ ld e, a
+ ld a, [wCurPlayAreaY]
+ inc a
+ ld c, a
+ ld b, 7
+ call PrintPlayAreaCardAttachedEnergies
+ ld a, [wCurPlayAreaY]
+ inc a
+ ld c, a
+ ld b, 5
+ ld a, SYM_E
+ call WriteByteToBGMap0
+ ; print the HP bar
+ inc c
+ ld a, SYM_HP
+ call WriteByteToBGMap0
+ ld a, [wCurPlayAreaSlot]
+ add DUELVARS_ARENA_CARD_HP
+ call GetTurnDuelistVariable
+ or a
+ jr z, .zero_hp
+ ld e, a
+ ld a, [wLoadedCard1HP]
+ ld d, a
+ call DrawHPBar
+ ld a, [wCurPlayAreaY]
+ inc a
+ inc a
+ ld c, a
+ ld b, 7
+ call BCCoordToBGMap0Address
+ ld hl, wDefaultText
+ ld b, 12
+ call SafeCopyDataHLtoDE
+ ret
+.zero_hp
+ ; if fainted, print "Knock Out" in place of the HP bar
+ ld a, [wCurPlayAreaY]
+ inc a
+ inc a
+ ld e, a
+ ld d, 7
+ ldtx hl, KnockOutText
+ call InitTextPrinting_ProcessTextFromID
+ ret
+
+; print a turn holder's play area Pokemon card's name, level, face down stage card,
+; color symbol, status symbol (if any), and pluspower/defender symbols (if any).
+; input:
+ ; wCurPlayAreaSlot: PLAY_AREA_* of the card to display the information of
+ ; wCurPlayAreaY: Y coordinate of where to print the card's information
+PrintPlayAreaCardHeader:
+ ; start by printing the Pokemon's name
+ ld a, [wCurPlayAreaSlot]
+ add DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ call LoadCardDataToBuffer1_FromDeckIndex
+ ld a, [wCurPlayAreaY]
+ ld e, a
+ ld d, 4
+ call InitTextPrinting
+ ; copy the name to wDefaultText (max. 10 characters)
+ ; then call ProcessText with hl = wDefaultText
+ ld hl, wLoadedCard1Name
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, wDefaultText
+ push de
+ ld a, 10 ; card name maximum length
+ call CopyTextData_FromTextID
+ pop hl
+ call ProcessText
+
+ ; print the Pokemon's color and the level
+ ld a, [wCurPlayAreaY]
+ ld c, a
+ ld b, 18
+ ld a, [wCurPlayAreaSlot]
+ call GetPlayAreaCardColor
+ inc a
+ call JPWriteByteToBGMap0
+ ld b, 14
+ ld a, SYM_Lv
+ call WriteByteToBGMap0
+ ld a, [wCurPlayAreaY]
+ ld c, a
+ ld b, 15
+ ld a, [wLoadedCard1Level]
+ call WriteTwoDigitNumberInTxSymbolFormat
+
+ ; print the 2x2 face down card image depending on the Pokemon's evolution stage
+ ld a, [wCurPlayAreaSlot]
+ add DUELVARS_ARENA_CARD_STAGE
+ call GetTurnDuelistVariable
+ add a
+ ld e, a
+ ld d, $00
+ ld hl, FaceDownCardTileNumbers
+ add hl, de
+ ld a, [hli] ; starting tile to fill the 2x2 rectangle with
+ push hl
+ push af
+ lb hl, 1, 2
+ lb bc, 2, 2
+ ld a, [wCurPlayAreaY]
+ ld e, a
+ ld d, 2
+ pop af
+ call FillRectangle
+ pop hl
+ ld a, [wConsole]
+ cp CONSOLE_CGB
+ jr nz, .not_cgb
+ ; in cgb, we have to take care of coloring it too
+ ld a, [hl]
+ lb hl, 0, 0
+ lb bc, 2, 2
+ call BankswitchVRAM1
+ call FillRectangle
+ call BankswitchVRAM0
+
+.not_cgb
+ ; print the status condition symbol if any (only for the arena Pokemon card)
+ ld hl, wCurPlayAreaSlot
+ ld a, [hli]
+ or a
+ jr nz, .skip_status
+ ld c, [hl]
+ inc c
+ inc c
+ ld b, 2
+ ld a, DUELVARS_ARENA_CARD_STATUS
+ call GetTurnDuelistVariable
+ call CheckPrintCnfSlpPrz
+ inc b
+ call CheckPrintPoisoned
+ inc b
+ call CheckPrintDoublePoisoned
+
+.skip_status
+ ; finally check whether to print the Pluspower and/or Defender symbols
+ ld a, [wCurPlayAreaSlot]
+ add DUELVARS_ARENA_CARD_ATTACHED_PLUSPOWER
+ call GetTurnDuelistVariable
+ or a
+ jr z, .not_pluspower
+ ld a, [wCurPlayAreaY]
+ inc a
+ ld c, a
+ ld b, 15
+ ld a, SYM_PLUSPOWER
+ call WriteByteToBGMap0
+ inc b
+ ld a, [hl]
+ add SYM_0
+ call WriteByteToBGMap0
+.not_pluspower
+ ld a, [wCurPlayAreaSlot]
+ add DUELVARS_ARENA_CARD_ATTACHED_DEFENDER
+ call GetTurnDuelistVariable
+ or a
+ jr z, .not_defender
+ ld a, [wCurPlayAreaY]
+ inc a
+ ld c, a
+ ld b, 17
+ ld a, SYM_DEFENDER
+ call WriteByteToBGMap0
+ inc b
+ ld a, [hl]
+ add SYM_0
+ call WriteByteToBGMap0
+.not_defender
+ ret
+
+FaceDownCardTileNumbers:
+; starting tile number, cgb palette (grey, yellow/red, green/blue, pink/orange)
+ db $d0, $02 ; basic
+ db $d4, $02 ; stage 1
+ db $d8, $01 ; stage 2
+ db $dc, $01 ; stage 2 special
+
+; given a card's status in a, print the Poison symbol at bc if it's poisoned
+CheckPrintPoisoned:
+ push af
+ and POISONED
+ jr z, .print
+.poison
+ ld a, SYM_POISONED
+.print
+ call WriteByteToBGMap0
+ pop af
+ ret
+
+; given a card's status in a, print the Poison symbol at bc if it's double poisoned
+CheckPrintDoublePoisoned:
+ push af
+ and DOUBLE_POISONED & (POISONED ^ $ff)
+ jr nz, CheckPrintPoisoned.poison ; double poisoned (print SYM_POISONED)
+ jr CheckPrintPoisoned.print ; not double poisoned (print SYM_SPACE)
+
+; given a card's status in a, print the Confusion, Sleep, or Paralysis symbol at bc
+; for each of those status that is active
+CheckPrintCnfSlpPrz:
+ push af
+ push hl
+ push de
+ and CNF_SLP_PRZ
+ ld e, a
+ ld d, $00
+ ld hl, .status_symbols
+ add hl, de
+ ld a, [hl]
+ call WriteByteToBGMap0
+ pop de
+ pop hl
+ pop af
+ ret
+
+.status_symbols
+ ; NO_STATUS, CONFUSED, ASLEEP, PARALYZED
+ db SYM_SPACE, SYM_CONFUSED, SYM_ASLEEP, SYM_PARALYZED
+
+; print the symbols of the attached energies of a turn holder's play area card
+; input:
+; - e: PLAY_AREA_*
+; - b, c: where to print (x, y)
+; - wAttachedEnergies and wTotalAttachedEnergies
+PrintPlayAreaCardAttachedEnergies:
+ push bc
+ call GetPlayAreaCardAttachedEnergies
+ ld hl, wDefaultText
+ push hl
+ ld c, NUM_TYPES
+ xor a
+.empty_loop
+ ld [hli], a
+ dec c
+ jr nz, .empty_loop
+ pop hl
+ ld de, wAttachedEnergies
+ lb bc, SYM_FIRE, NUM_TYPES - 1
+.next_color
+ ld a, [de] ; energy count of current color
+ inc de
+ inc a
+ jr .check_amount
+.has_energy
+ ld [hl], b
+ inc hl
+.check_amount
+ dec a
+ jr nz, .has_energy
+ inc b
+ dec c
+ jr nz, .next_color
+ ld a, [wTotalAttachedEnergies]
+ cp 9
+ jr c, .place_tiles
+ ld a, SYM_PLUS
+ ld [wDefaultText + 7], a
+.place_tiles
+ pop bc
+ call BCCoordToBGMap0Address
+ ld hl, wDefaultText
+ ld b, NUM_TYPES
+ call SafeCopyDataHLtoDE
+ ret
+
+Func_6423:
+ ld hl, wDefaultText
+ ld e, $08
+.asm_6428
+ ld a, [hli]
+ call JPWriteByteToBGMap0
+ inc b
+ dec e
+ jr nz, .asm_6428
+ ret
+
+Func_6431:
+ xor a
+ ld [wSelectedDuelSubMenuItem], a
+
+Func_6435:
+ call Func_64b0
+ ld hl, PlayAreaScreenMenuParameters_ActivePokemonIncluded
+ ld a, [wSelectedDuelSubMenuItem]
+ call InitializeMenuParameters
+ ld a, [wNumPlayAreaItems]
+ ld [wNumMenuItems], a
+.asm_6447
+ call DoFrame
+ call HandleMenuInput
+ ldh [hTempPlayAreaLocation_ff9d], a
+ ld [wHUDEnergyAndHPBarsX], a
+ jr nc, .asm_6447
+ cp $ff
+ jr z, .asm_649b
+ ld [wSelectedDuelSubMenuItem], a
+ ldh a, [hKeysPressed]
+ and START
+ jr nz, .asm_649d
+ ldh a, [hCurMenuItem]
+ add a
+ ld e, a
+ ld d, $00
+ ld hl, wDuelTempList + 1
+ add hl, de
+ ld a, [hld]
+ cp $04
+ jr nz, .asm_6447
+ ld a, [hl]
+ ldh [hTempCardIndex_ff98], a
+ ld d, a
+ ld e, $00
+ call CopyAttackDataAndDamage_FromDeckIndex
+ call DisplayUsePokemonPowerScreen
+ ld a, EFFECTCMDTYPE_INITIAL_EFFECT_1
+ call TryExecuteEffectCommandFunction
+ jr nc, .asm_648c
+ ldtx hl, PokemonPowerSelectNotRequiredText
+ call DrawWideTextBox_WaitForInput
+ jp Func_6435
+.asm_648c
+ ldtx hl, UseThisPokemonPowerText
+ call YesOrNoMenuWithText
+ jp c, Func_6435
+ ldh a, [hTempCardIndex_ff98]
+ ldh [hTemp_ffa0], a
+ or a
+ ret
+.asm_649b
+ scf
+ ret
+.asm_649d
+ ldh a, [hCurMenuItem]
+ add DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ call GetCardIDFromDeckIndex
+ call LoadCardDataToBuffer1_FromCardID
+ call OpenCardPage_FromCheckPlayArea
+ jp Func_6435
+
+Func_64b0:
+ call ZeroObjectPositionsAndToggleOAMCopy
+ call EmptyScreen
+ call LoadDuelCardSymbolTiles
+ call LoadDuelCheckPokemonScreenTiles
+ ld de, wDuelTempList
+ call SetListPointer
+ ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA
+ call GetTurnDuelistVariable
+ ld c, a
+ ld b, $00
+.asm_64ca
+ push hl
+ push bc
+ ld a, b
+ ld [wHUDEnergyAndHPBarsX], a
+ ld a, b
+ add a
+ add b
+ ld [wCurPlayAreaY], a
+ ld a, b
+ add DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ call SetNextElementOfList
+ call PrintPlayAreaCardHeader
+ call PrintPlayAreaCardLocation
+ call Func_64fc
+ ld a, [wLoadedCard1Atk1Category]
+ call SetNextElementOfList
+ pop bc
+ pop hl
+ inc b
+ dec c
+ jr nz, .asm_64ca
+ ld a, b
+ ld [wNumPlayAreaItems], a
+ call EnableLCD
+ ret
+
+Func_64fc:
+ ld a, [wLoadedCard1Atk1Category]
+ cp POKEMON_POWER
+ ret nz
+ ld a, [wCurPlayAreaY]
+ inc a
+ ld e, a
+ ld d, $04
+ ld hl, wLoadedCard1Atk1Name
+ call InitTextPrinting_ProcessTextFromPointerToID
+ ret
+
+; display the screen that prompts the player to use the selected card's
+; Pokemon Power. Includes the card's information above, and the Pokemon Power's
+; description below.
+; input: hTempPlayAreaLocation_ff9d
+DisplayUsePokemonPowerScreen:
+ ldh a, [hTempPlayAreaLocation_ff9d]
+ ld [wCurPlayAreaSlot], a
+ xor a
+ ld [wCurPlayAreaY], a
+ call ZeroObjectPositionsAndToggleOAMCopy
+ call EmptyScreen
+ call LoadDuelCardSymbolTiles
+ call LoadDuelCheckPokemonScreenTiles
+ call PrintPlayAreaCardInformationAndLocation
+ lb de, 1, 4
+ call InitTextPrinting
+ ld hl, wLoadedCard1Atk1Name
+ call InitTextPrinting_ProcessTextFromPointerToID
+ lb de, 1, 6
+ ld hl, wLoadedCard1Atk1Description
+ call PrintAttackOrCardDescription
+ ret
+
+; print the description of an attack, a Pokemon power, or a trainer or energy card
+; x,y coordinates of where to start printing the text are given at de
+; don't separate lines of text
+PrintAttackOrCardDescription:
+ call SetNoLineSeparation
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call CountLinesOfTextFromID
+ cp 7
+ jr c, .print
+ dec e ; move one line up to fit (assumes it will be enough)
+.print
+ ld a, 19
+ call InitTextPrintingInTextbox
+ call ProcessTextFromID
+ call SetOneLineSeparation
+ ret
+
+; moves the cards loaded by deck index at hTempRetreatCostCards to the discard pile
+DiscardRetreatCostCards:
+ ld hl, hTempRetreatCostCards
+.discard_loop
+ ld a, [hli]
+ cp $ff
+ ret z
+ call PutCardInDiscardPile
+ jr .discard_loop
+
+; moves the discard pile cards that were loaded to hTempRetreatCostCards back to the active Pokemon.
+; this exists because they will be discarded again during the call to AttemptRetreat, so
+; it prevents the energy cards from being discarded twice.
+ReturnRetreatCostCardsToArena:
+ ld hl, hTempRetreatCostCards
+.loop
+ ld a, [hli]
+ cp $ff
+ ret z
+ push hl
+ call MoveDiscardPileCardToHand
+ call AddCardToHand
+ ld e, PLAY_AREA_ARENA
+ call PutHandCardInPlayArea
+ pop hl
+ jr .loop
+
+; discard retreat cost energy cards and attempt retreat of the arena card.
+; return carry if unable to retreat this turn due to unsuccessful confusion check
+; if successful, the retreated card is replaced with a bench Pokemon card
+AttemptRetreat:
+ call DiscardRetreatCostCards
+ ldh a, [hTemp_ffa0]
+ and CNF_SLP_PRZ
+ cp CONFUSED
+ jr nz, .success
+ ldtx de, ConfusionCheckRetreatText
+ call TossCoin
+ jr c, .success
+ ld a, 1
+ ld [wGotHeadsFromConfusionCheckDuringRetreat], a
+ scf
+ ret
+.success
+ ldh a, [hTempPlayAreaLocation_ffa1]
+ ld e, a
+ call SwapArenaWithBenchPokemon
+ xor a
+ ld [wGotHeadsFromConfusionCheckDuringRetreat], a
+ ret
+
+; given a number between 0-255 in a, converts it to TX_SYMBOL format,
+; and writes it to wStringBuffer + 2 and to the BGMap0 address at bc.
+; leading zeros replaced with SYM_SPACE.
+WriteTwoByteNumberInTxSymbolFormat:
+ push de
+ push bc
+ ld l, a
+ ld h, $00
+ call TwoByteNumberToTxSymbol_TrimLeadingZeros_Bank1
+ pop bc
+ push bc
+ call BCCoordToBGMap0Address
+ ld hl, wStringBuffer + 2
+ ld b, 3
+ call SafeCopyDataHLtoDE
+ pop bc
+ pop de
+ ret
+
+; given a number between 0-99 in a, converts it to TX_SYMBOL format,
+; and writes it to wStringBuffer + 3 and to the BGMap0 address at bc.
+; if the number is between 0-9, the first digit is replaced with SYM_SPACE.
+WriteTwoDigitNumberInTxSymbolFormat:
+ push hl
+ push de
+ push bc
+ ld l, a
+ ld h, $00
+ call TwoByteNumberToTxSymbol_TrimLeadingZeros_Bank1
+ pop bc
+ push bc
+ call BCCoordToBGMap0Address
+ ld hl, wStringBuffer + 3
+ ld b, 2
+ call SafeCopyDataHLtoDE
+ pop bc
+ pop de
+ pop hl
+ ret
+
+; convert the number at hl to TX_SYMBOL text format and write it to wStringBuffer
+; replace leading zeros with SYM_SPACE
+TwoByteNumberToTxSymbol_TrimLeadingZeros_Bank1:
+ ld de, wStringBuffer
+ ld bc, -10000
+ call .get_digit
+ ld bc, -1000
+ call .get_digit
+ ld bc, -100
+ call .get_digit
+ ld bc, -10
+ call .get_digit
+ ld bc, -1
+ call .get_digit
+ xor a ; TX_END
+ ld [de], a
+ ld hl, wStringBuffer
+ ld b, 4
+.digit_loop
+ ld a, [hl]
+ cp SYM_0
+ jr nz, .done ; jump if not zero
+ ld [hl], SYM_SPACE ; trim leading zero
+ inc hl
+ dec b
+ jr nz, .digit_loop
+.done
+ ret
+
+.get_digit
+ ld a, SYM_0 - 1
+.subtract_loop
+ inc a
+ add hl, bc
+ jr c, .subtract_loop
+ ld [de], a
+ inc de
+ ld a, l
+ sub c
+ ld l, a
+ ld a, h
+ sbc b
+ ld h, a
+ ret
+
+; input d, e: max. HP, current HP
+DrawHPBar:
+ ld a, MAX_HP
+ ld c, SYM_SPACE
+ call .fill_hp_bar ; empty bar
+ ld a, d
+ ld c, SYM_HP_OK
+ call .fill_hp_bar ; fill (max. HP) with HP counters
+ ld a, d
+ sub e
+ ld c, SYM_HP_NOK
+ ; fill (max. HP - current HP) with damaged HP counters
+.fill_hp_bar
+ or a
+ ret z
+ ld hl, wDefaultText
+ ld b, HP_BAR_LENGTH
+.tile_loop
+ ld [hl], c
+ inc hl
+ dec b
+ ret z
+ sub MAX_HP / HP_BAR_LENGTH
+ jr nz, .tile_loop
+ ret
+
+; when an opponent's Pokemon card attacks, this displays a screen
+; containing the description and information of the used attack
+DisplayOpponentUsedAttackScreen:
+ call ZeroObjectPositionsAndToggleOAMCopy
+ call EmptyScreen
+ call LoadDuelCardSymbolTiles
+ call LoadDuelFaceDownCardTiles
+ ld a, [wTempCardID_ccc2]
+ ld e, a
+ ld d, $00
+ call LoadCardDataToBuffer1_FromCardID
+ ld a, CARDPAGE_POKEMON_OVERVIEW
+ ld [wCardPageNumber], a
+ ld hl, wLoadedCard1Atk1Name
+ ld a, [wSelectedAttack]
+ or a
+ jr z, .first_atk
+ ld hl, wLoadedCard1Atk2Name
+.first_atk
+ ld e, 1
+ call PrintAttackOrPkmnPowerInformation
+ lb de, 1, 4
+ ld hl, wLoadedAttackDescription
+ call PrintAttackOrCardDescription
+ ret
+
+; display card detail when a trainer card is used, and print "Used xxx"
+; hTempCardIndex_ff9f contains the card's deck index
+DisplayUsedTrainerCardDetailScreen:
+ ldh a, [hTempCardIndex_ff9f]
+ ldtx hl, UsedText
+ call DisplayCardDetailScreen
+ ret
+
+; prints the name and description of a trainer card, along with the
+; "Used xxx" text in a text box. this function is used to show the player
+; the information of a trainer card being used by the opponent.
+PrintUsedTrainerCardDescription:
+ call EmptyScreen
+ call SetNoLineSeparation
+ lb de, 1, 1
+ call InitTextPrinting
+ ld hl, wLoadedCard1Name
+ call ProcessTextFromPointerToID
+ ld a, 19
+ lb de, 1, 3
+ call InitTextPrintingInTextbox
+ ld hl, wLoadedCard1NonPokemonDescription
+ call ProcessTextFromPointerToID
+ call SetOneLineSeparation
+ ldtx hl, UsedText
+ call DrawWideTextBox_WaitForInput
+ ret
+
+; save data of the current duel to sCurrentDuel
+; byte 0 is $01, bytes 1 and 2 are the checksum, byte 3 is [wDuelType]
+; next $33a bytes come from DuelDataToSave
+SaveDuelData:
+ farcall CommentedOut_1a6cc
+ ld de, sCurrentDuel
+; fallthrough
+
+; save data of the current duel to de (in SRAM)
+; byte 0 is $01, bytes 1 and 2 are the checksum, byte 3 is [wDuelType]
+; next $33a bytes come from DuelDataToSave
+SaveDuelDataToDE:
+ call EnableSRAM
+ push de
+ inc de
+ inc de
+ inc de
+ inc de
+ ld hl, DuelDataToSave
+ push de
+.save_duel_data_loop
+ ; start copying data to de = sCurrentDuelData + $1
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+ inc hl
+ ld a, c
+ or b
+ jr z, .data_done
+ push hl
+ push bc
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+ inc hl
+ pop hl
+ call CopyDataHLtoDE
+ pop hl
+ inc hl
+ inc hl
+ jr .save_duel_data_loop
+.data_done
+ pop hl
+ ; save a checksum to hl = sCurrentDuelData + $1
+ lb de, $23, $45
+ ld bc, $334 ; misses last 6 bytes to calculate checksum
+.checksum_loop
+ ld a, e
+ sub [hl]
+ ld e, a
+ ld a, [hli]
+ xor d
+ ld d, a
+ dec bc
+ ld a, c
+ or b
+ jr nz, .checksum_loop
+ pop hl
+ ld a, $01
+ ld [hli], a ; sCurrentDuel
+ ld [hl], e ; sCurrentDuelChecksum
+ inc hl
+ ld [hl], d ; sCurrentDuelChecksum
+ inc hl
+ ld a, [wDuelType]
+ ld [hl], a ; sCurrentDuelData
+ call DisableSRAM
+ ret
+
+; loads current Duel data from SRAM and also general save data
+; if the data is not valid, returns carry
+LoadAndValidateDuelSaveData:
+ ld hl, sCurrentDuel
+ call ValidateSavedDuelData
+ ret c
+ ld de, sCurrentDuel
+ call LoadSavedDuelData
+
+ call ValidateGeneralSaveData
+ ret nc
+ call LoadGeneralSaveData
+ or a
+ ret
+
+; load the data saved in sCurrentDuelData to WRAM according to the distribution
+; of DuelDataToSave. assumes saved data exists and that the checksum is valid.
+LoadSavedDuelData:
+ call EnableSRAM
+ inc de
+ inc de
+ inc de
+ inc de
+ ld hl, DuelDataToSave
+.next_block
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+ inc hl
+ ld a, c
+ or b
+ jr z, .done
+ push hl
+ push bc
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+ inc hl
+ pop hl
+.copy_loop
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec bc
+ ld a, c
+ or b
+ jr nz, .copy_loop
+ pop hl
+ inc hl
+ inc hl
+ jr .next_block
+.done
+ call DisableSRAM
+ ret
+
+DuelDataToSave:
+; dw address, number of bytes to copy
+ dw wPlayerDuelVariables, wOpponentDuelVariables - wPlayerDuelVariables
+ dw wOpponentDuelVariables, wPlayerDeck - wOpponentDuelVariables
+ dw wPlayerDeck, wDuelTempList - wPlayerDeck
+ dw wWhoseTurn, wDuelTheme + $1 - wWhoseTurn
+ dw hWhoseTurn, $1
+ dw wRNG1, wRNGCounter + $1 - wRNG1
+ dw wAIDuelVars, wAIDuelVarsEnd - wAIDuelVars
+ dw NULL
+
+; return carry if there is no data saved at sCurrentDuel or if the checksum isn't correct,
+; or if the value saved from wDuelType is DUELTYPE_LINK
+ValidateSavedNonLinkDuelData:
+ call EnableSRAM
+ ld hl, sCurrentDuel
+ ld a, [sCurrentDuelData]
+ call DisableSRAM
+ cp DUELTYPE_LINK
+ jr nz, ValidateSavedDuelData
+ ; ignore any saved data of a link duel
+ scf
+ ret
+
+; return carry if there is no data saved at sCurrentDuel or if the checksum isn't correct
+; input: hl = sCurrentDuel
+ValidateSavedDuelData:
+ call EnableSRAM
+ push de
+ ld a, [hli]
+ or a
+ jr z, .no_saved_data
+ lb de, $23, $45
+ ld bc, $334
+ ld a, [hl]
+ sub e
+ ld e, a
+ inc hl
+ ld a, [hl]
+ xor d
+ ld d, a
+ inc hl
+ inc hl
+.loop
+ ld a, [hl]
+ add e
+ ld e, a
+ ld a, [hli]
+ xor d
+ ld d, a
+ dec bc
+ ld a, c
+ or b
+ jr nz, .loop
+ ld a, e
+ or d
+ jr z, .ok
+.no_saved_data
+ scf
+.ok
+ call DisableSRAM
+ pop de
+ ret
+
+; discard data of a duel that was saved by SaveDuelData, by setting the first byte
+; of sCurrentDuel to $00, and zeroing the checksum (next two bytes)
+DiscardSavedDuelData:
+ call EnableSRAM
+ ld hl, sCurrentDuel
+ xor a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ call DisableSRAM
+ ret
+
+; loads a player deck (sDeck*Cards) from SRAM to wPlayerDeck
+; sCurrentlySelectedDeck determines which sDeck*Cards source (0-3)
+LoadPlayerDeck:
+ call EnableSRAM
+ ld a, [sCurrentlySelectedDeck]
+ ld l, a
+ ld h, sDeck2Cards - sDeck1Cards
+ call HtimesL
+ ld de, sDeck1Cards
+ add hl, de
+ ld de, wPlayerDeck
+ ld c, DECK_SIZE
+.copy_cards_loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .copy_cards_loop
+ call DisableSRAM
+ ret
+
+; returns carry if wSkipDelayAllowed is non-0 and B is being held in order to branch
+; out of the caller's wait frames loop. probably only used for debugging.
+CheckSkipDelayAllowed:
+ ld a, [wSkipDelayAllowed]
+ or a
+ ret z
+ ldh a, [hKeysHeld]
+ and B_BUTTON
+ ret z
+ scf
+ ret
+
+; related to AI taking their turn in a duel
+; called multiple times during one AI turn
+; each call results in the execution of an OppActionTable function
+AIMakeDecision:
+ ldh [hOppActionTableIndex], a
+ ld hl, wSkipDuelistIsThinkingDelay
+ ld a, [hl]
+ ld [hl], $0
+ or a
+ jr nz, .skip_delay
+.delay_loop
+ call DoFrame
+ ld a, [wVBlankCounter]
+ cp 60
+ jr c, .delay_loop
+
+.skip_delay
+ ldh a, [hOppActionTableIndex]
+ ld hl, wOpponentTurnEnded
+ ld [hl], 0
+ ld hl, OppActionTable
+ call JumpToFunctionInTable
+ ld a, [wDuelFinished]
+ ld hl, wOpponentTurnEnded
+ or [hl]
+ jr nz, .turn_ended
+ ld a, [wSkipDuelistIsThinkingDelay]
+ or a
+ ret nz
+ ld [wVBlankCounter], a
+ ldtx hl, DuelistIsThinkingText
+ call DrawWideTextBox_PrintTextNoDelay
+ or a
+ ret
+
+.turn_ended
+ scf
+ ret
+
+Func_67fb:
+ ld a, 10
+.delay_loop
+ call DoFrame
+ dec a
+ jr nz, .delay_loop
+ ld [wCurrentDuelMenuItem], a ; 0
+.asm_6806
+ ld a, PLAYER_TURN
+ ldh [hWhoseTurn], a
+ ldtx hl, WaitingHandExamineText
+ call DrawWideTextBox_PrintTextNoDelay
+ call Func_6850
+.asm_6813
+ call DoFrame
+ call Func_683e
+ call RefreshMenuCursor
+ ldh a, [hKeysPressed]
+ bit 0, a
+ jr nz, .asm_682e
+ ld a, $01
+ call Func_6862
+ jr nc, .asm_6813
+.asm_6829
+ call DrawDuelMainScene
+ jr .asm_6806
+.asm_682e
+ ld a, [wCurrentDuelMenuItem]
+ or a
+ jr z, .asm_6839
+ call OpenDuelCheckMenu
+ jr .asm_6829
+.asm_6839
+ call OpenTurnHolderHandScreen_Simple
+ jr .asm_6829
+
+Func_683e:
+ ldh a, [hDPadHeld]
+ bit 1, a
+ ret nz
+ and D_LEFT | D_RIGHT
+ ret z
+ call EraseCursor
+ ld hl, wCurrentDuelMenuItem
+ ld a, [hl]
+ xor $01
+ ld [hl], a
+; fallthrough
+
+Func_6850:
+ ld d, 2
+ ld a, [wCurrentDuelMenuItem]
+ or a
+ jr z, .set_cursor_params
+ ld d, 8
+.set_cursor_params
+ ld e, 16
+ lb bc, SYM_CURSOR_R, SYM_SPACE
+ jp SetCursorParametersForTextBox
+
+Func_6862:
+ ld [wcbff], a
+ ldh a, [hKeysPressed]
+ bit START_F, a
+ jr nz, .start_pressed
+ bit SELECT_F, a
+ jr nz, .select_pressed
+ ldh a, [hKeysHeld]
+ and B_BUTTON
+ ret z
+ ldh a, [hKeysPressed]
+ bit D_DOWN_F, a
+ jr nz, .down_pressed
+ bit D_LEFT_F, a
+ jr nz, .left_pressed
+ bit D_UP_F, a
+ jr nz, .up_pressed
+ bit D_RIGHT_F, a
+ jr nz, .right_pressed
+ or a
+ ret
+.start_pressed
+ ld a, DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ cp -1
+ jr z, .return_carry
+ call GetCardIDFromDeckIndex
+ call LoadCardDataToBuffer1_FromCardID
+ ld hl, wCurPlayAreaSlot
+ xor a
+ ld [hli], a
+ ld [hl], a ; wCurPlayAreaY
+ call OpenCardPage_FromCheckPlayArea
+.return_carry
+ scf
+ ret
+.select_pressed
+ ld a, [wcbff]
+ or a
+ jr nz, .asm_68ad
+ call OpenInPlayAreaScreen_FromSelectButton
+ jr .return_carry
+.asm_68ad
+ call Func_4597
+ jr .return_carry
+.down_pressed
+ call OpenTurnHolderPlayAreaScreen
+ jr .return_carry
+.left_pressed
+ call OpenTurnHolderDiscardPileScreen
+ jr .return_carry
+.up_pressed
+ call OpenNonTurnHolderPlayAreaScreen
+ jr .return_carry
+.right_pressed
+ call OpenNonTurnHolderDiscardPileScreen
+ jr .return_carry
+
+Func_68c6:
+ call Func_3b31
+ ld hl, sp+$00
+ ld a, l
+ ld [wcbf7], a
+ ld a, h
+ ld [wcbf7 + 1], a
+ ld de, Func_0f1d
+ ld hl, wDoFrameFunction
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ret
+
+ResetDoFrameFunction_Bank1:
+ xor a
+ ld hl, wDoFrameFunction
+ ld [hli], a
+ ld [hl], a
+ ret
+
+; print the AttachedEnergyToPokemonText, given the energy card to attach in hTempCardIndex_ff98,
+; and the PLAY_AREA_* of the turn holder's Pokemon to attach the energy to in hTempPlayAreaLocation_ff9d
+PrintAttachedEnergyToPokemon:
+ ldh a, [hTempPlayAreaLocation_ff9d]
+ add DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ call LoadCardNameToTxRam2_b
+ ldh a, [hTempCardIndex_ff98]
+ call LoadCardNameToTxRam2
+ ldtx hl, AttachedEnergyToPokemonText
+ call DrawWideTextBox_WaitForInput
+ ret
+
+; print the PokemonEvolvedIntoPokemonText, given the Pokemon card to evolve in wPreEvolutionPokemonCard,
+; and the evolved Pokemon card in hTempCardIndex_ff98. also play a sound effect.
+PrintPokemonEvolvedIntoPokemon:
+ ld a, SFX_5E
+ call PlaySFX
+ ld a, [wPreEvolutionPokemonCard]
+ call LoadCardNameToTxRam2
+ ldh a, [hTempCardIndex_ff98]
+ call LoadCardNameToTxRam2_b
+ ldtx hl, PokemonEvolvedIntoPokemonText
+ call DrawWideTextBox_WaitForInput
+ ret
+
+; handle the opponent's turn in a link duel
+; loop until either [wOpponentTurnEnded] or [wDuelFinished] is non-0
+DoLinkOpponentTurn:
+ xor a
+ ld [wOpponentTurnEnded], a
+ xor a
+ ld [wSkipDuelistIsThinkingDelay], a
+.link_opp_turn_loop
+ ld a, [wSkipDuelistIsThinkingDelay]
+ or a
+ jr nz, .asm_6932
+ call Func_68c6
+ call Func_67fb
+ ld a, [wDuelDisplayedScreen]
+ cp CHECK_PLAY_AREA
+ jr nz, .asm_6932
+ lb de, $38, $9f
+ call SetupText
+.asm_6932
+ call ResetDoFrameFunction_Bank1
+ call SerialRecvDuelData
+ ld a, OPPONENT_TURN
+ ldh [hWhoseTurn], a
+ ld a, [wSerialFlags]
+ or a
+ jp nz, DuelTransmissionError
+ xor a
+ ld [wSkipDuelistIsThinkingDelay], a
+ ldh a, [hOppActionTableIndex]
+ cp $17
+ jp nc, DuelTransmissionError
+ ld hl, OppActionTable
+ call JumpToFunctionInTable
+ ld hl, wOpponentTurnEnded
+ ld a, [wDuelFinished]
+ or [hl]
+ jr z, .link_opp_turn_loop
+ ret
+
+; actions for the opponent's turn
+; on a link duel, this is referenced by DoLinkOpponentTurn in a loop (on each opponent's HandleTurn)
+; on a non-link duel (vs AI opponent), this is referenced by AIMakeDecision
+OppActionTable:
+ dw DuelTransmissionError
+ dw OppAction_PlayBasicPokemonCard
+ dw OppAction_EvolvePokemonCard
+ dw OppAction_PlayEnergyCard
+ dw OppAction_AttemptRetreat
+ dw OppAction_FinishTurnWithoutAttacking
+ dw OppAction_PlayTrainerCard
+ dw OppAction_ExecuteTrainerCardEffectCommands
+ dw OppAction_BeginUseAttack
+ dw OppAction_UseAttack
+ dw OppAction_PlayAttackAnimationDealAttackDamage
+ dw OppAction_DrawCard
+ dw OppAction_UsePokemonPower
+ dw OppAction_ExecutePokemonPowerEffect
+ dw OppAction_ForceSwitchActive
+ dw OppAction_NoAction
+ dw OppAction_NoAction
+ dw OppAction_TossCoinATimes
+ dw OppAction_6b30
+ dw OppAction_NoAction
+ dw OppAction_UseMetronomeAttack
+ dw OppAction_6b15
+ dw OppAction_DrawDuelMainScene
+
+OppAction_DrawCard:
+ call DrawCardFromDeck
+ call nc, AddCardToHand
+ ret
+
+OppAction_FinishTurnWithoutAttacking:
+ call DrawDuelMainScene
+ call ClearNonTurnTemporaryDuelvars
+ ldtx hl, FinishedTurnWithoutAttackingText
+ call DrawWideTextBox_WaitForInput
+ ld a, 1
+ ld [wOpponentTurnEnded], a
+ ret
+
+; attach an energy card from hand to the arena or a benched Pokemon
+OppAction_PlayEnergyCard:
+ ldh a, [hTempPlayAreaLocation_ffa1]
+ ldh [hTempPlayAreaLocation_ff9d], a
+ ld e, a
+ ldh a, [hTemp_ffa0]
+ ldh [hTempCardIndex_ff98], a
+ call PutHandCardInPlayArea
+ ldh a, [hTemp_ffa0]
+ call LoadCardDataToBuffer1_FromDeckIndex
+ call DrawLargePictureOfCard
+ call PrintAttachedEnergyToPokemon
+ ld a, 1
+ ld [wAlreadyPlayedEnergy], a
+ call DrawDuelMainScene
+ ret
+
+; evolve a Pokemon card in the arena or in the bench
+OppAction_EvolvePokemonCard:
+ ldh a, [hTempPlayAreaLocation_ffa1]
+ ldh [hTempPlayAreaLocation_ff9d], a
+ ldh a, [hTemp_ffa0]
+ ldh [hTempCardIndex_ff98], a
+ call LoadCardDataToBuffer1_FromDeckIndex
+ call DrawLargePictureOfCard
+ call EvolvePokemonCardIfPossible
+ call PrintPokemonEvolvedIntoPokemon
+ call Func_161e
+ call DrawDuelMainScene
+ ret
+
+; place a basic Pokemon card from hand in the bench
+OppAction_PlayBasicPokemonCard:
+ ldh a, [hTemp_ffa0]
+ ldh [hTempCardIndex_ff98], a
+ call PutHandPokemonCardInPlayArea
+ ldh [hTempPlayAreaLocation_ff9d], a
+ add DUELVARS_ARENA_CARD_STAGE
+ call GetTurnDuelistVariable
+ ld [hl], 0
+ ldh a, [hTemp_ffa0]
+ ldtx hl, PlacedOnTheBenchText
+ call DisplayCardDetailScreen
+ call Func_161e
+ call DrawDuelMainScene
+ ret
+
+; attempt the retreat of the active Pokemon card
+; if successful, discard the required energy cards for retreat and
+; swap the retreated card with a Pokemon card from the bench
+OppAction_AttemptRetreat:
+ ld a, DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ push af
+ call AttemptRetreat
+ ldtx hl, RetreatWasUnsuccessfulText
+ jr c, .failed
+ xor a
+ ld [wDuelDisplayedScreen], a
+ ldtx hl, RetreatedToTheBenchText
+.failed
+ push hl
+ call DrawDuelMainScene
+ pop hl
+ pop af
+ push hl
+ call LoadCardNameToTxRam2
+ pop hl
+ call DrawWideTextBox_WaitForInput_Bank1
+ ret
+
+; play trainer card from hand
+OppAction_PlayTrainerCard:
+ call LoadNonPokemonCardEffectCommands
+ call DisplayUsedTrainerCardDetailScreen
+ call PrintUsedTrainerCardDescription
+ call ExchangeRNG
+ ld a, $01
+ ld [wSkipDuelistIsThinkingDelay], a
+ ret
+
+; execute the effect commands of the trainer card that is being played
+; used only for Trainer cards, as a continuation of OppAction_PlayTrainerCard
+OppAction_ExecuteTrainerCardEffectCommands:
+ ld a, EFFECTCMDTYPE_DISCARD_ENERGY
+ call TryExecuteEffectCommandFunction
+ ld a, EFFECTCMDTYPE_BEFORE_DAMAGE
+ call TryExecuteEffectCommandFunction
+ call DrawDuelMainScene
+ ldh a, [hTempCardIndex_ff9f]
+ call MoveHandCardToDiscardPile
+ call ExchangeRNG
+ call DrawDuelMainScene
+ ret
+
+; begin the execution of an attack and handle the attack being
+; possibly unsuccessful due to Sand Attack or Smokescreen
+OppAction_BeginUseAttack:
+ ldh a, [hTempCardIndex_ff9f]
+ ld d, a
+ ldh a, [hTemp_ffa0]
+ ld e, a
+ call CopyAttackDataAndDamage_FromDeckIndex
+ call Func_16f6
+ ld a, $01
+ ld [wSkipDuelistIsThinkingDelay], a
+ call CheckSandAttackOrSmokescreenSubstatus
+ jr c, .has_status
+ ld a, DUELVARS_ARENA_CARD_STATUS
+ call GetTurnDuelistVariable
+ and CNF_SLP_PRZ
+ cp CONFUSED
+ jr z, .has_status
+ call ExchangeRNG
+ ret
+
+; we make it here is attacker is affected by
+; Sand Attack, Smokescreen, or confusion
+.has_status
+ call DrawDuelMainScene
+ call PrintPokemonsAttackText
+ call WaitForWideTextBoxInput
+ call ExchangeRNG
+ call HandleSandAttackOrSmokescreenSubstatus
+ ret nc ; return if attack is successful (won the coin toss)
+ call ClearNonTurnTemporaryDuelvars
+ ; end the turn if the attack fails
+ ld a, 1
+ ld [wOpponentTurnEnded], a
+ ret
+
+; display the attack used by the opponent, and handle
+; EFFECTCMDTYPE_DISCARD_ENERGY and confusion damage to self
+OppAction_UseAttack:
+ ld a, EFFECTCMDTYPE_DISCARD_ENERGY
+ call TryExecuteEffectCommandFunction
+ call CheckSelfConfusionDamage
+ jr c, .confusion_damage
+ call DisplayOpponentUsedAttackScreen
+ call PrintPokemonsAttackText
+ call WaitForWideTextBoxInput
+ call ExchangeRNG
+ ld a, $01
+ ld [wSkipDuelistIsThinkingDelay], a
+ ret
+.confusion_damage
+ call HandleConfusionDamageToSelf
+ ; end the turn if dealing damage to self due to confusion
+ ld a, 1
+ ld [wOpponentTurnEnded], a
+ ret
+
+OppAction_PlayAttackAnimationDealAttackDamage:
+ call PlayAttackAnimation_DealAttackDamage
+ ld a, 1
+ ld [wOpponentTurnEnded], a
+ ret
+
+; force the player to switch the active Pokemon with a benched Pokemon
+OppAction_ForceSwitchActive:
+ ldtx hl, SelectPkmnOnBenchToSwitchWithActiveText
+ call DrawWideTextBox_WaitForInput
+ call SwapTurn
+ call HasAlivePokemonInBench
+ ld a, $01
+ ld [wcbd4], a
+.force_selection
+ call OpenPlayAreaScreenForSelection
+ jr c, .force_selection
+ call SwapTurn
+ ldh a, [hTempPlayAreaLocation_ff9d]
+ call SerialSendByte
+ ret
+
+OppAction_UsePokemonPower:
+ ldh a, [hTempCardIndex_ff9f]
+ ld d, a
+ ld e, $00
+ call CopyAttackDataAndDamage_FromDeckIndex
+ ldh a, [hTemp_ffa0]
+ ldh [hTempPlayAreaLocation_ff9d], a
+ call DisplayUsePokemonPowerScreen
+ ldh a, [hTempCardIndex_ff9f]
+ call LoadCardNameToTxRam2
+ ld hl, wLoadedAttackName
+ ld a, [hli]
+ ld [wTxRam2_b], a
+ ld a, [hl]
+ ld [wTxRam2_b + 1], a
+ ldtx hl, WillUseThePokemonPowerText
+ call DrawWideTextBox_WaitForInput_Bank1
+ call ExchangeRNG
+ ld a, $01
+ ld [wSkipDuelistIsThinkingDelay], a
+ ret
+
+; execute the EFFECTCMDTYPE_BEFORE_DAMAGE command of the used Pokemon Power
+OppAction_ExecutePokemonPowerEffect:
+ call Func_7415
+ ld a, EFFECTCMDTYPE_BEFORE_DAMAGE
+ call TryExecuteEffectCommandFunction
+ ld a, $01
+ ld [wSkipDuelistIsThinkingDelay], a
+ ret
+
+; execute the EFFECTCMDTYPE_AFTER_DAMAGE command of the used Pokemon Power
+OppAction_6b15:
+ ld a, EFFECTCMDTYPE_AFTER_DAMAGE
+ call TryExecuteEffectCommandFunction
+ ld a, $01
+ ld [wSkipDuelistIsThinkingDelay], a
+ ret
+
+OppAction_DrawDuelMainScene:
+ call DrawDuelMainScene
+ ret
+
+OppAction_TossCoinATimes:
+ call SerialRecv8Bytes
+ call TossCoinATimes
+ ld a, $01
+ ld [wSkipDuelistIsThinkingDelay], a
+ ret
+
+OppAction_6b30:
+ ldh a, [hWhoseTurn]
+ push af
+ ldh a, [hTemp_ffa0]
+ ldh [hWhoseTurn], a
+ call Func_4f2d
+ pop af
+ ldh [hWhoseTurn], a
+ ret
+
+OppAction_UseMetronomeAttack:
+ call DrawDuelMainScene
+ ld a, DUELVARS_ARENA_CARD_STATUS
+ call GetTurnDuelistVariable
+ and CNF_SLP_PRZ
+ cp CONFUSED
+ jr z, .asm_6b56
+ call PrintPokemonsAttackText
+ call .asm_6b56
+ call WaitForWideTextBoxInput
+ ret
+.asm_6b56
+ call SerialRecv8Bytes
+ push bc
+ call SwapTurn
+ call CopyAttackDataAndDamage_FromDeckIndex
+ call SwapTurn
+ ldh a, [hTempCardIndex_ff9f]
+ ld [wPlayerAttackingCardIndex], a
+ ld a, [wSelectedAttack]
+ ld [wPlayerAttackingAttackIndex], a
+ ld a, [wTempCardID_ccc2]
+ ld [wPlayerAttackingCardID], a
+ call Func_16f6
+ pop bc
+ ld a, c
+ ld [wMetronomeEnergyCost], a
+ ret
+
+OppAction_NoAction:
+ ret
+
+; load the text ID of the card name with deck index given in a to TxRam2
+; also loads the card to wLoadedCard1
+LoadCardNameToTxRam2:
+ call LoadCardDataToBuffer1_FromDeckIndex
+ ld a, [wLoadedCard1Name]
+ ld [wTxRam2], a
+ ld a, [wLoadedCard1Name + 1]
+ ld [wTxRam2 + 1], a
+ ret
+
+; load the text ID of the card name with deck index given in a to TxRam2_b
+; also loads the card to wLoadedCard1
+LoadCardNameToTxRam2_b:
+ call LoadCardDataToBuffer1_FromDeckIndex
+ ld a, [wLoadedCard1Name]
+ ld [wTxRam2_b], a
+ ld a, [wLoadedCard1Name + 1]
+ ld [wTxRam2_b + 1], a
+ ret
+
+DrawWideTextBox_WaitForInput_Bank1:
+ call DrawWideTextBox_WaitForInput
+ ret
+
+Func_6ba2:
+ call DrawWideTextBox_PrintText
+ ld a, [wDuelistType]
+ cp DUELIST_TYPE_LINK_OPP
+ ret z
+ call WaitForWideTextBoxInput
+ ret
+
+; apply and/or refresh status conditions and other events that trigger between turns
+HandleBetweenTurnsEvents:
+ call IsArenaPokemonAsleepOrPoisoned
+ jr c, .something_to_handle
+ cp PARALYZED
+ jr z, .something_to_handle
+ call SwapTurn
+ call IsArenaPokemonAsleepOrPoisoned
+ call SwapTurn
+ jr c, .something_to_handle
+ call DiscardAttachedPluspowers
+ call SwapTurn
+ call DiscardAttachedDefenders
+ call SwapTurn
+ ret
+
+.something_to_handle
+ ; either:
+ ; 1. turn holder's arena Pokemon is paralyzed, asleep, poisoned or double poisoned
+ ; 2. non-turn holder's arena Pokemon is asleep, poisoned or double poisoned
+ call Func_3b21
+ call ZeroObjectPositionsAndToggleOAMCopy
+ call EmptyScreen
+ ld a, BOXMSG_BETWEEN_TURNS
+ call DrawDuelBoxMessage
+ ldtx hl, BetweenTurnsText
+ call DrawWideTextBox_WaitForInput
+
+ ld a, DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ call GetCardIDFromDeckIndex
+ ld a, e
+ ld [wTempNonTurnDuelistCardID], a
+ ld l, DUELVARS_ARENA_CARD_STATUS
+ ld a, [hl]
+ or a
+ jr z, .discard_pluspower
+ ; has status condition
+ call HandlePoisonDamage
+ jr c, .discard_pluspower
+ call HandleSleepCheck
+ ld a, [hl]
+ and CNF_SLP_PRZ
+ cp PARALYZED
+ jr nz, .discard_pluspower
+ ; heal paralysis
+ ld a, DOUBLE_POISONED
+ and [hl]
+ ld [hl], a
+ call Func_6c7e
+ ldtx hl, IsCuredOfParalysisText
+ call Func_6ce4
+ ld a, DUEL_ANIM_HEAL
+ call Func_6cab
+ call WaitForWideTextBoxInput
+
+.discard_pluspower
+ call DiscardAttachedPluspowers
+ call SwapTurn
+ ld a, DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ call GetCardIDFromDeckIndex
+ ld a, e
+ ld [wTempNonTurnDuelistCardID], a
+ ld l, DUELVARS_ARENA_CARD_STATUS
+ ld a, [hl]
+ or a
+ jr z, .asm_6c3a
+ call HandlePoisonDamage
+ jr c, .asm_6c3a
+ call HandleSleepCheck
+.asm_6c3a
+ call DiscardAttachedDefenders
+ call SwapTurn
+ call Func_6e4c
+ ret
+
+; discard any PLUSPOWER attached to the turn holder's arena and/or bench Pokemon
+DiscardAttachedPluspowers:
+ ld a, DUELVARS_ARENA_CARD_ATTACHED_PLUSPOWER
+ call GetTurnDuelistVariable
+ ld e, MAX_PLAY_AREA_POKEMON
+ xor a
+.unattach_pluspower_loop
+ ld [hli], a
+ dec e
+ jr nz, .unattach_pluspower_loop
+ ld de, PLUSPOWER
+ jp MoveCardToDiscardPileIfInArena
+
+; discard any DEFENDER attached to the turn holder's arena and/or bench Pokemon
+DiscardAttachedDefenders:
+ ld a, DUELVARS_ARENA_CARD_ATTACHED_DEFENDER
+ call GetTurnDuelistVariable
+ ld e, MAX_PLAY_AREA_POKEMON
+ xor a
+.unattach_defender_loop
+ ld [hli], a
+ dec e
+ jr nz, .unattach_defender_loop
+ ld de, DEFENDER
+ jp MoveCardToDiscardPileIfInArena
+
+; return carry if the turn holder's arena Pokemon card is asleep, poisoned, or double poisoned.
+; also, if confused, paralyzed, or asleep, return the status condition in a.
+IsArenaPokemonAsleepOrPoisoned:
+ ld a, DUELVARS_ARENA_CARD_STATUS
+ call GetTurnDuelistVariable
+ or a
+ ret z
+ ; note that POISONED | DOUBLE_POISONED is the same as just DOUBLE_POISONED ($c0)
+ ; poison status masking is normally done with PSN_DBLPSN ($f0)
+ and POISONED | DOUBLE_POISONED
+ jr nz, .set_carry
+ ld a, [hl]
+ and CNF_SLP_PRZ
+ cp ASLEEP
+ jr z, .set_carry
+ or a
+ ret
+.set_carry
+ scf
+ ret
+
+Func_6c7e:
+ ld a, [wDuelDisplayedScreen]
+ cp DUEL_MAIN_SCENE
+ jr z, .asm_6c98
+ ld hl, wWhoseTurn
+ ldh a, [hWhoseTurn]
+ cp [hl]
+ jp z, DrawDuelMainScene
+ call SwapTurn
+ call DrawDuelMainScene
+ call SwapTurn
+ ret
+
+.asm_6c98
+ ld hl, wWhoseTurn
+ ldh a, [hWhoseTurn]
+ cp [hl]
+ jp z, DrawDuelHUDs
+ call SwapTurn
+ call DrawDuelHUDs
+ call SwapTurn
+ ret
+
+; input:
+; a = animation ID
+Func_6cab:
+ push af
+ ld a, [wDuelType]
+ or a
+ jr nz, .store_duelist_turn
+ ld a, [wWhoseTurn]
+ cp PLAYER_TURN
+ jr z, .store_duelist_turn
+ call SwapTurn
+ ldh a, [hWhoseTurn]
+ ld [wDuelAnimDuelistSide], a
+ call SwapTurn
+ jr .asm_6ccb
+
+.store_duelist_turn
+ ldh a, [hWhoseTurn]
+ ld [wDuelAnimDuelistSide], a
+
+.asm_6ccb
+ xor a
+ ld [wDuelAnimLocationParam], a
+ ld a, DUEL_ANIM_SCREEN_MAIN_SCENE
+ ld [wDuelAnimationScreen], a
+ pop af
+
+; play animation
+ call PlayDuelAnimation
+.loop_anim
+ call DoFrame
+ call CheckAnyAnimationPlaying
+ jr c, .loop_anim
+ call Func_6c7e.asm_6c98
+ ret
+
+; prints the name of the card at wTempNonTurnDuelistCardID in a text box
+Func_6ce4:
+ push hl
+ ld a, [wTempNonTurnDuelistCardID]
+ ld e, a
+ call LoadCardDataToBuffer1_FromCardID
+ ld hl, wLoadedCard1Name
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call LoadTxRam2
+ pop hl
+ call DrawWideTextBox_PrintText
+ ret
+
+; handles the sleep check for the NonTurn Duelist
+; heals sleep status if coin is heads, else
+; it plays sleeping animation
+HandleSleepCheck:
+ ld a, [hl]
+ and CNF_SLP_PRZ
+ cp ASLEEP
+ ret nz ; quit if not asleep
+
+ push hl
+ ld a, [wTempNonTurnDuelistCardID]
+ ld e, a
+ call LoadCardDataToBuffer1_FromCardID
+ ld a, 18
+ call CopyCardNameAndLevel
+ ld [hl], TX_END
+ ld hl, wTxRam2
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ldtx de, PokemonsSleepCheckText
+ call TossCoin
+ ld a, DUEL_ANIM_SLEEP
+ ldtx hl, IsStillAsleepText
+ jr nc, .tails
+
+; coin toss was heads, cure sleep status
+ pop hl
+ push hl
+ ld a, DOUBLE_POISONED
+ and [hl]
+ ld [hl], a
+ ld a, DUEL_ANIM_HEAL
+ ldtx hl, IsCuredOfSleepText
+
+.tails
+ push af
+ push hl
+ call Func_6c7e
+ pop hl
+ call Func_6ce4
+ pop af
+ call Func_6cab
+ pop hl
+ call WaitForWideTextBoxInput
+ ret
+
+HandlePoisonDamage:
+ or a
+ bit POISONED_F , [hl]
+ ret z ; quit if not poisoned
+
+; load damage and text according to normal/double poison
+ push hl
+ bit DOUBLE_POISONED_F, [hl]
+ ld a, PSN_DAMAGE
+ ldtx hl, Received10DamageDueToPoisonText
+ jr z, .not_double_poisoned
+ ld a, DBLPSN_DAMAGE
+ ldtx hl, Received20DamageDueToPoisonText
+
+.not_double_poisoned
+ push af
+ ld [wDuelAnimDamage], a
+ xor a
+ ld [wDuelAnimDamage + 1], a
+
+ push hl
+ call Func_6c7e
+ pop hl
+ call Func_6ce4
+
+; play animation
+ ld a, DUEL_ANIM_POISON
+ call Func_6cab
+ pop af
+
+; deal poison damage
+ ld e, a
+ ld d, $00
+ ld a, DUELVARS_ARENA_CARD_HP
+ call GetTurnDuelistVariable
+ call SubtractHP
+ push hl
+ ld a, $8c
+ call Func_6cab
+ pop hl
+
+ call PrintKnockedOutIfHLZero
+ push af
+ call WaitForWideTextBoxInput
+ pop af
+ pop hl
+ ret
+
+; given the deck index of a turn holder's card in register a,
+; and a pointer in hl to the wLoadedCard* buffer where the card data is loaded,
+; check if the card is Clefairy Doll or Mysterious Fossil, and, if so, convert it
+; to a Pokemon card in the wLoadedCard* buffer, using .trainer_to_pkmn_data.
+ConvertSpecialTrainerCardToPokemon:
+ ld c, a
+ ld a, [hl]
+ cp TYPE_TRAINER
+ ret nz ; return if the card is not TRAINER type
+ push hl
+ ldh a, [hWhoseTurn]
+ ld h, a
+ ld l, c
+ ld a, [hl]
+ and CARD_LOCATION_PLAY_AREA
+ pop hl
+ ret z ; return if the card is not in the arena or bench
+ ld a, e
+ cp MYSTERIOUS_FOSSIL
+ jr nz, .check_for_clefairy_doll
+ ld a, d
+ cp $00 ; MYSTERIOUS_FOSSIL >> 8
+ jr z, .start_ram_data_overwrite
+ ret
+.check_for_clefairy_doll
+ cp CLEFAIRY_DOLL
+ ret nz
+ ld a, d
+ cp $00 ; CLEFAIRY_DOLL >> 8
+ ret nz
+.start_ram_data_overwrite
+ push de
+ ld [hl], TYPE_PKMN_COLORLESS
+ ld bc, CARD_DATA_HP
+ add hl, bc
+ ld de, .trainer_to_pkmn_data
+ ld c, CARD_DATA_UNKNOWN2 - CARD_DATA_HP
+.loop
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ pop de
+ ret
+
+.trainer_to_pkmn_data
+ db 10 ; CARD_DATA_HP
+ ds $07 ; CARD_DATA_ATTACK1_NAME - (CARD_DATA_HP + 1)
+ tx DiscardName ; CARD_DATA_ATTACK1_NAME
+ tx DiscardDescription ; CARD_DATA_ATTACK1_DESCRIPTION
+ ds $03 ; CARD_DATA_ATTACK1_CATEGORY - (CARD_DATA_ATTACK1_DESCRIPTION + 2)
+ db POKEMON_POWER ; CARD_DATA_ATTACK1_CATEGORY
+ dw TrainerCardAsPokemonEffectCommands ; CARD_DATA_ATTACK1_EFFECT_COMMANDS
+ ds $18 ; CARD_DATA_RETREAT_COST - (CARD_DATA_ATTACK1_EFFECT_COMMANDS + 2)
+ db UNABLE_RETREAT ; CARD_DATA_RETREAT_COST
+ ds $0d ; PKMN_CARD_DATA_LENGTH - (CARD_DATA_RETREAT_COST + 1)
+
+; this function applies status conditions to the defending Pokemon,
+; returned by the effect functions in wEffectFunctionsFeedback
+Func_6df1:
+ xor a
+ ld [wPlayerArenaCardLastTurnStatus], a
+ ld [wOpponentArenaCardLastTurnStatus], a
+ ld hl, wEffectFunctionsFeedbackIndex
+ ld a, [hl]
+ or a
+ ret z
+ ld e, [hl]
+ ld d, $00
+ ld hl, wEffectFunctionsFeedback
+ add hl, de
+ ld [hl], $00
+ call CheckNoDamageOrEffect
+ jr c, .no_damage_or_effect
+ ld hl, wEffectFunctionsFeedback
+.apply_status_loop
+ ld a, [hli]
+ or a
+ jr z, .done
+ ld d, a
+ call ApplyStatusConditionToArenaPokemon
+ jr .apply_status_loop
+.done
+ scf
+ ret
+.no_damage_or_effect
+ ld a, l
+ or h
+ call nz, DrawWideTextBox_PrintText
+ ld hl, wEffectFunctionsFeedback
+.asm_6e23
+ ld a, [hli]
+ or a
+ jr z, .asm_6e37
+ ld d, a
+ ld a, [wWhoseTurn]
+ cp d
+ jr z, .asm_6e32
+ inc hl
+ inc hl
+ jr .asm_6e23
+.asm_6e32
+ call ApplyStatusConditionToArenaPokemon
+ jr .asm_6e23
+.asm_6e37
+ ret
+
+; apply the status condition at hl+1 to the arena Pokemon
+; discard the arena Pokemon's status conditions contained in the bitmask at hl
+ApplyStatusConditionToArenaPokemon:
+ ld e, DUELVARS_ARENA_CARD_STATUS
+ ld a, [de]
+ and [hl]
+ inc hl
+ or [hl]
+ ld [de], a
+ dec hl
+ ld e, DUELVARS_ARENA_CARD_LAST_TURN_STATUS
+ ld a, [de]
+ and [hl]
+ inc hl
+ or [hl]
+ inc hl
+ ld [de], a
+ ret
+
+Func_6e49:
+ call HandleDestinyBondSubstatus
+ ; fallthrough
+
+Func_6e4c:
+ call ClearDamageReductionSubstatus2OfKnockedOutPokemon
+ xor a
+ ld [wcce8], a
+ call SwapTurn
+ call Func_6ef6
+ call SwapTurn
+ ld a, [wcce8]
+ or a
+ jr z, .asm_6e86
+ call Func_6ff7
+ jr c, .asm_6e86
+ call CountKnockedOutPokemon
+ ld c, a
+ call SwapTurn
+ call CountPrizes
+ call SwapTurn
+ dec a
+ cp c
+ jr c, .asm_6e86
+ ld a, c
+ call SwapTurn
+ call TakeAPrizes
+ call SwapTurn
+ ld a, $01
+ jr .asm_6ecc
+.asm_6e86
+ call Func_6ef6
+ ld a, [wcce8]
+ cp $01
+ jr nz, .asm_6e9f
+ call SwapTurn
+ call Func_6ff7
+ call SwapTurn
+ jr c, .asm_6e9f
+ ld a, $02
+ jr .asm_6ecc
+.asm_6e9f
+ call SwapTurn
+ call Func_6eff
+ call SwapTurn
+ call Func_6eff
+ ld a, [wcce8]
+ or a
+ jr nz, .asm_6ec4
+ xor a
+.asm_6eb2
+ push af
+ call MoveAllTurnHolderKnockedOutPokemonToDiscardPile
+ call SwapTurn
+ call MoveAllTurnHolderKnockedOutPokemonToDiscardPile
+ call SwapTurn
+ call ShiftAllPokemonToFirstPlayAreaSlots
+ pop af
+ ret
+.asm_6ec4
+ ld e, a
+ ld d, $00
+ ld hl, Data_6ed2
+ add hl, de
+ ld a, [hl]
+.asm_6ecc
+ ld [wDuelFinished], a
+ scf
+ jr .asm_6eb2
+
+Data_6ed2:
+ db DUEL_NOT_FINISHED, TURN_PLAYER_LOST, TURN_PLAYER_WON, TURN_PLAYER_TIED
+ db TURN_PLAYER_LOST, TURN_PLAYER_LOST, TURN_PLAYER_TIED, TURN_PLAYER_LOST
+ db TURN_PLAYER_WON, TURN_PLAYER_TIED, TURN_PLAYER_WON, TURN_PLAYER_WON
+ db TURN_PLAYER_TIED, TURN_PLAYER_LOST, TURN_PLAYER_WON, TURN_PLAYER_TIED
+
+; clears SUBSTATUS2_REDUCE_BY_20, SUBSTATUS2_POUNCE, SUBSTATUS2_GROWL,
+; SUBSTATUS2_TAIL_WAG, and SUBSTATUS2_LEER for each arena Pokemon with 0 HP
+ClearDamageReductionSubstatus2OfKnockedOutPokemon:
+ call SwapTurn
+ call .clear
+ call SwapTurn
+.clear
+ ld a, DUELVARS_ARENA_CARD_HP
+ call GetNonTurnDuelistVariable
+ or a
+ ret nz
+ call ClearDamageReductionSubstatus2
+ ret
+
+Func_6ef6:
+ call Func_6fa5
+ ld hl, wcce8
+ rl [hl]
+ ret
+
+Func_6eff:
+ call ReplaceKnockedOutPokemon
+ ld hl, wcce8
+ rl [hl]
+ ret
+
+; for each Pokemon in the turn holder's play area (arena and bench),
+; move that card to the discard pile if its HP is 0
+MoveAllTurnHolderKnockedOutPokemonToDiscardPile:
+ ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA
+ call GetTurnDuelistVariable
+ ld d, a
+ ld l, DUELVARS_ARENA_CARD_HP
+ ld e, PLAY_AREA_ARENA
+.loop
+ ld a, [hl]
+ or a
+ jr nz, .next
+ push hl
+ push de
+ call MovePlayAreaCardToDiscardPile
+ pop de
+ pop hl
+.next
+ inc hl
+ inc e
+ dec d
+ jr nz, .loop
+ ret
+
+; have the turn holder replace the arena Pokemon card when it's been knocked out.
+; if there are no Pokemon cards in the turn holder's bench, return carry.
+ReplaceKnockedOutPokemon:
+ ld a, DUELVARS_ARENA_CARD_HP
+ call GetTurnDuelistVariable
+ or a
+ ret nz
+ call ClearAllStatusConditions
+ call HasAlivePokemonInBench
+ jr nc, .can_replace_pokemon
+
+; if we made it here, the duelist can't replace the knocked out Pokemon
+ bank1call DrawDuelMainScene
+ ldtx hl, ThereAreNoPokemonInPlayAreaText
+ call DrawWideTextBox_WaitForInput
+ call ExchangeRNG
+ scf
+ ret
+
+.can_replace_pokemon
+ ld a, DUELVARS_DUELIST_TYPE
+ call GetTurnDuelistVariable
+ cp DUELIST_TYPE_PLAYER
+ jr nz, .opponent
+
+; prompt the player to replace the knocked out Pokemon with one from bench
+ bank1call DrawDuelMainScene
+ ldtx hl, SelectPokemonToPlaceInTheArenaText
+ call DrawWideTextBox_WaitForInput
+ ld a, $01
+ ld [wcbd4], a
+ ld a, PRACTICEDUEL_PLAY_STARYU_FROM_BENCH
+ call DoPracticeDuelAction
+.select_pokemon
+ call OpenPlayAreaScreenForSelection
+ jr c, .select_pokemon
+ ldh a, [hTempPlayAreaLocation_ff9d]
+ call SerialSend8Bytes
+
+; replace the arena Pokemon with the one at location [hTempPlayAreaLocation_ff9d]
+.replace_pokemon
+ call Func_3b31
+ ld a, PRACTICEDUEL_REPLACE_KNOCKED_OUT_POKEMON
+ call DoPracticeDuelAction
+ jr c, .select_pokemon
+ ldh a, [hTempPlayAreaLocation_ff9d]
+ ld d, a
+ ld e, PLAY_AREA_ARENA
+ call SwapPlayAreaPokemon
+ ld a, DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ ldtx hl, DuelistPlacedACardText
+ bank1call DisplayCardDetailScreen
+ call ExchangeRNG
+ or a
+ ret
+
+; the AI opponent replaces the knocked out Pokemon with one from bench
+.opponent
+ cp DUELIST_TYPE_LINK_OPP
+ jr z, .link_opponent
+ call AIDoAction_KOSwitch
+ ldh a, [hTemp_ffa0]
+ ldh [hTempPlayAreaLocation_ff9d], a
+ jr .replace_pokemon
+
+; wait for link opponent to replace the knocked out Pokemon with one from bench
+.link_opponent
+ bank1call DrawDuelMainScene
+ ldtx hl, DuelistIsSelectingPokemonToPlaceInArenaText
+ call DrawWideTextBox_PrintText
+ call SerialRecv8Bytes
+ ldh [hTempPlayAreaLocation_ff9d], a
+ jr .replace_pokemon
+
+Func_6fa5:
+ call CountKnockedOutPokemon
+ ret nc
+ ; at least one Pokemon knocked out
+ call SwapTurn
+ bank1call Func_5805
+ call SwapTurn
+ ret nc
+ call SwapTurn
+ bank1call DrawDuelMainScene
+ ldtx hl, TookAllThePrizesText
+ call DrawWideTextBox_WaitForInput
+ call ExchangeRNG
+ call SwapTurn
+ scf
+ ret
+
+; return in wNumberPrizeCardsToTake the amount of Pokemon in the turn holder's
+; play area that are still there despite having 0 HP.
+; that is, the number of Pokemon that have just been knocked out.
+; Clefairy Doll and Mysterious Fossil don't count.
+CountKnockedOutPokemon:
+ ld a, DUELVARS_ARENA_CARD_HP
+ call GetTurnDuelistVariable
+ ld d, h
+ ld e, DUELVARS_ARENA_CARD
+ ld b, PLAY_AREA_ARENA
+ ld c, MAX_PLAY_AREA_POKEMON
+.loop
+ ld a, [de]
+ cp -1
+ jr z, .next ; jump if no Pokemon in this location
+ ld a, [hl]
+ or a
+ jr nz, .next ; jump if this Pokemon's HP isn't 0
+ ; this Pokemon's HP has just become 0
+ ld a, [de]
+ push de
+ call GetCardIDFromDeckIndex
+ call GetCardType
+ pop de
+ cp TYPE_TRAINER
+ jr z, .next ; jump if this is a trainer card (Clefairy Doll or Mysterious Fossil)
+ inc b
+.next
+ inc hl
+ inc de
+ dec c
+ jr nz, .loop
+ ld a, b
+ ld [wNumberPrizeCardsToTake], a
+ or a
+ ret z
+ scf
+ ret
+
+Func_6ff7:
+ ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA
+ call GetTurnDuelistVariable
+ ld c, a
+ ld l, DUELVARS_ARENA_CARD_HP
+.loop
+ ld a, [hli]
+ or a
+ jr nz, .non_zero_hp
+ dec c
+ jr nz, .loop
+ scf
+ ret
+.non_zero_hp
+ or a
+ ret
+
+; print one of the "There was no effect from" texts depending
+; on the value at wNoEffectFromWhichStatus (NO_STATUS or a status condition constant)
+PrintThereWasNoEffectFromStatusText:
+ ld a, [wNoEffectFromWhichStatus]
+ or a
+ jr nz, .status
+ ld hl, wLoadedAttackName
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call LoadTxRam2
+ ldtx hl, ThereWasNoEffectFromTxRam2Text
+ ret
+.status
+ ld c, a
+ ldtx hl, ThereWasNoEffectFromPoisonConfusionText
+ cp POISONED | CONFUSED
+ ret z
+ and PSN_DBLPSN
+ jr nz, .poison
+ ld a, c
+ and CNF_SLP_PRZ
+ ldtx hl, ThereWasNoEffectFromParalysisText
+ cp PARALYZED
+ ret z
+ ldtx hl, ThereWasNoEffectFromSleepText
+ cp ASLEEP
+ ret z
+ ldtx hl, ThereWasNoEffectFromConfusionText
+ ret
+.poison
+ ldtx hl, ThereWasNoEffectFromPoisonText
+ cp POISONED
+ ret z
+ ldtx hl, ThereWasNoEffectFromToxicText
+ ret
+
+; returns carry if card at hTempPlayAreaLocation_ff9d
+; is a basic card.
+; otherwise, lists the card indices of all stages in
+; that card location, and returns the card one
+; stage below.
+; input:
+; hTempPlayAreaLocation_ff9d = play area location to check;
+; output:
+; a = card index in hTempPlayAreaLocation_ff9d;
+; d = card index of card one stage below;
+; carry set if card is a basic card.
+GetCardOneStageBelow:
+ ldh a, [hTempPlayAreaLocation_ff9d]
+ add DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ call LoadCardDataToBuffer2_FromDeckIndex
+ ld a, [wLoadedCard2Stage]
+ or a
+ jr nz, .not_basic
+ scf
+ ret
+
+.not_basic
+ ld hl, wAllStagesIndices
+ ld a, $ff
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+
+; loads deck indices of the stages present in hTempPlayAreaLocation_ff9d.
+; the three stages are loaded consecutively in wAllStagesIndices.
+ ldh a, [hTempPlayAreaLocation_ff9d]
+ or CARD_LOCATION_ARENA
+ ld c, a
+ ld a, DUELVARS_CARD_LOCATIONS
+ call GetTurnDuelistVariable
+.loop
+ ld a, [hl]
+ cp c
+ jr nz, .next
+ ld a, l
+ call LoadCardDataToBuffer2_FromDeckIndex
+ ld a, [wLoadedCard2Type]
+ cp TYPE_ENERGY
+ jr nc, .next
+ ld b, l
+ push hl
+ ld a, [wLoadedCard2Stage]
+ ld e, a
+ ld d, $00
+ ld hl, wAllStagesIndices
+ add hl, de
+ ld [hl], b
+ pop hl
+.next
+ inc l
+ ld a, l
+ cp DECK_SIZE
+ jr c, .loop
+
+; if card at hTempPlayAreaLocation_ff9d is a stage 1, load d with basic card.
+; otherwise if stage 2, load d with the stage 1 card.
+ ldh a, [hTempPlayAreaLocation_ff9d]
+ add DUELVARS_ARENA_CARD_STAGE
+ call GetTurnDuelistVariable
+ ld hl, wAllStagesIndices ; pointing to basic
+ cp STAGE1
+ jr z, .done
+ ; if stage1 was skipped, hl should point to Basic stage card
+ cp STAGE2_WITHOUT_STAGE1
+ jr z, .done
+ inc hl ; pointing to stage 1
+.done
+ ld d, [hl]
+ ldh a, [hTempPlayAreaLocation_ff9d]
+ add DUELVARS_ARENA_CARD
+ call GetTurnDuelistVariable
+ ld e, a
+ or a
+ ret
+
+; initializes variables when a duel begins, such as zeroing wDuelFinished or wDuelTurns,
+; and setting wDuelType based on wPlayerDuelistType and wOpponentDuelistType
+InitVariablesToBeginDuel:
+ xor a
+ ld [wDuelFinished], a
+ ld [wDuelTurns], a
+ ld [wcce7], a
+ ld a, $ff
+ ld [wcc0f], a
+ ld [wPlayerAttackingCardIndex], a
+ ld [wPlayerAttackingAttackIndex], a
+ call EnableSRAM
+ ld a, [sSkipDelayAllowed]
+ ld [wSkipDelayAllowed], a
+ call DisableSRAM
+ ld a, [wPlayerDuelistType]
+ cp DUELIST_TYPE_LINK_OPP
+ jr z, .set_duel_type
+ bit 7, a ; DUELIST_TYPE_AI_OPP
+ jr nz, .set_duel_type
+ ld a, [wOpponentDuelistType]
+ cp DUELIST_TYPE_LINK_OPP
+ jr z, .set_duel_type
+ bit 7, a ; DUELIST_TYPE_AI_OPP
+ jr nz, .set_duel_type
+ xor a
+.set_duel_type
+ ld [wDuelType], a
+ ret
+
+; init variables that last a single player's turn
+InitVariablesToBeginTurn:
+ xor a
+ ld [wAlreadyPlayedEnergy], a
+ ld [wGotHeadsFromConfusionCheckDuringRetreat], a
+ ld [wGotHeadsFromSandAttackOrSmokescreenCheck], a
+ ldh a, [hWhoseTurn]
+ ld [wWhoseTurn], a
+ ret
+
+; make all Pokemon in the turn holder's play area able to evolve. called from the
+; player's second turn on, in order to allow evolution of all Pokemon already played.
+SetAllPlayAreaPokemonCanEvolve:
+ ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA
+ call GetTurnDuelistVariable
+ ld c, a
+ ld l, DUELVARS_ARENA_CARD_FLAGS
+.next_pkmn_loop
+ res 5, [hl]
+ set CAN_EVOLVE_THIS_TURN_F, [hl]
+ inc l
+ dec c
+ jr nz, .next_pkmn_loop
+ ret
+
+; initializes duel variables such as cards in deck and in hand, or Pokemon in play area
+; player turn: [c200, c2ff]
+; opponent turn: [c300, c3ff]
+InitializeDuelVariables:
+ ldh a, [hWhoseTurn]
+ ld h, a
+ ld l, DUELVARS_DUELIST_TYPE
+ ld a, [hl]
+ push hl
+ push af
+ xor a
+ ld l, a
+.zero_duel_variables_loop
+ ld [hl], a
+ inc l
+ jr nz, .zero_duel_variables_loop
+ pop af
+ pop hl
+ ld [hl], a
+ lb bc, DUELVARS_CARD_LOCATIONS, DECK_SIZE
+ ld l, DUELVARS_DECK_CARDS
+.init_duel_variables_loop
+; zero card locations and cards in hand, and init order of cards in deck
+ push hl
+ ld [hl], b
+ ld l, b
+ ld [hl], $0
+ pop hl
+ inc l
+ inc b
+ dec c
+ jr nz, .init_duel_variables_loop
+ ld l, DUELVARS_ARENA_CARD
+ ld c, 1 + MAX_BENCH_POKEMON + 1
+.init_play_area
+; initialize to $ff card in arena as well as cards in bench (plus a terminator)
+ ld [hl], -1
+ inc l
+ dec c
+ jr nz, .init_play_area
+ ret
+
+; draw [wDuelInitialPrizes] cards from the turn holder's deck and place them as prizes:
+; write their deck indexes to DUELVARS_PRIZE_CARDS, set their location to
+; CARD_LOCATION_PRIZE, and set [wDuelInitialPrizes] bits of DUELVARS_PRIZES.
+InitTurnDuelistPrizes:
+ ldh a, [hWhoseTurn]
+ ld d, a
+ ld e, DUELVARS_PRIZE_CARDS
+ ld a, [wDuelInitialPrizes]
+ ld c, a
+ ld b, 0
+.draw_prizes_loop
+ call DrawCardFromDeck
+ ld [de], a
+ inc de
+ ld h, d
+ ld l, a
+ ld [hl], CARD_LOCATION_PRIZE
+ inc b
+ ld a, b
+ cp c
+ jr nz, .draw_prizes_loop
+ push hl
+ ld e, c
+ ld d, $00
+ ld hl, PrizeBitmasks
+ add hl, de
+ ld a, [hl]
+ pop hl
+ ld l, DUELVARS_PRIZES
+ ld [hl], a
+ ret
+
+PrizeBitmasks:
+ db %0, %1, %11, %111, %1111, %11111, %111111
+
+; update the turn holder's DUELVARS_PRIZES following that duelist
+; drawing a number of prizes equal to register a
+TakeAPrizes:
+ or a
+ ret z
+ ld c, a
+ call CountPrizes
+ sub c
+ jr nc, .no_underflow
+ xor a
+.no_underflow
+ ld c, a
+ ld b, $00
+ ld hl, PrizeBitmasks
+ add hl, bc
+ ld b, [hl]
+ ld a, DUELVARS_PRIZES
+ call GetTurnDuelistVariable
+ ld [hl], b
+ ret
+
+; clear the non-turn holder's duelvars starting at DUELVARS_ARENA_CARD_DISABLED_ATTACK_INDEX
+; these duelvars only last a two-player turn at most.
+ClearNonTurnTemporaryDuelvars:
+ ld a, DUELVARS_ARENA_CARD_DISABLED_ATTACK_INDEX
+ call GetNonTurnDuelistVariable
+ xor a
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ ret
+
+; same as ClearNonTurnTemporaryDuelvars, except the non-turn holder's arena
+; Pokemon status condition is copied to wccc5
+ClearNonTurnTemporaryDuelvars_CopyStatus:
+ ld a, DUELVARS_ARENA_CARD_STATUS
+ call GetNonTurnDuelistVariable
+ ld [wccc5], a
+ call ClearNonTurnTemporaryDuelvars
+ ret
+
+; update non-turn holder's DUELVARS_ARENA_CARD_LAST_TURN_DAMAGE
+; if wccef == 0: set to [wDealtDamage]
+; if wceef != 0: set to 0
+Func_7195:
+ ld a, DUELVARS_ARENA_CARD_LAST_TURN_DAMAGE
+ call GetNonTurnDuelistVariable
+ ld a, [wccef]
+ or a
+ jr nz, .zero
+ ld a, [wDealtDamage]
+ ld [hli], a
+ ld a, [wDealtDamage + 1]
+ ld [hl], a
+ ret
+.zero
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ret
+
+_TossCoin:
+ ld [wCoinTossTotalNum], a
+ ld a, [wDuelDisplayedScreen]
+ cp COIN_TOSS
+ jr z, .print_text
+ xor a
+ ld [wCoinTossNumTossed], a
+ call EmptyScreen
+ call LoadDuelCoinTossResultTiles
+
+.print_text
+; no need to print text if this is not the first coin toss
+ ld a, [wCoinTossNumTossed]
+ or a
+ jr nz, .clear_text_pointer
+ ld a, COIN_TOSS
+ ld [wDuelDisplayedScreen], a
+ lb de, 0, 12
+ lb bc, 20, 6
+ ld hl, $0000
+ call DrawLabeledTextBox
+ call EnableLCD
+ lb de, 1, 14
+ ld a, 19
+ call InitTextPrintingInTextbox
+ ld hl, wCoinTossScreenTextID
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call PrintText
+
+.clear_text_pointer
+ ld hl, wCoinTossScreenTextID
+ xor a
+ ld [hli], a
+ ld [hl], a
+
+; store duelist type and reset number of heads
+ call EnableLCD
+ ld a, DUELVARS_DUELIST_TYPE
+ call GetTurnDuelistVariable
+ ld [wCoinTossDuelistType], a
+ call ExchangeRNG
+ xor a
+ ld [wCoinTossNumHeads], a
+
+.print_coin_tally
+; skip printing text if it's only one coin toss
+ ld a, [wCoinTossTotalNum]
+ cp 2
+ jr c, .asm_7223
+
+; write "#coin/#total coins"
+ lb bc, 15, 11
+ ld a, [wCoinTossNumTossed]
+ inc a ; current coin number is wCoinTossNumTossed + 1
+ call WriteTwoDigitNumberInTxSymbolFormat
+ ld b, 17
+ ld a, SYM_SLASH
+ call WriteByteToBGMap0
+ inc b
+ ld a, [wCoinTossTotalNum]
+ call WriteTwoDigitNumberInTxSymbolFormat
+
+.asm_7223
+ call Func_3b21
+ ld a, DUEL_ANIM_COIN_SPIN
+ call PlayDuelAnimation
+
+ ld a, [wCoinTossDuelistType]
+ or a
+ jr z, .asm_7236
+ call Func_7324
+ jr .asm_723c
+
+.asm_7236
+ call WaitForWideTextBoxInput
+ call Func_72ff
+
+.asm_723c
+ call Func_3b21
+ ld d, DUEL_ANIM_COIN_TOSS2
+ ld e, $0 ; heads
+ call UpdateRNGSources
+ rra
+ jr c, .got_result
+ ld d, DUEL_ANIM_COIN_TOSS1
+ ld e, $1 ; tails
+
+.got_result
+; already decided on coin toss result,
+; load the correct tossing animation
+; and wait for it to finish
+ ld a, d
+ call PlayDuelAnimation
+ ld a, [wCoinTossDuelistType]
+ or a
+ jr z, .wait_anim
+ ld a, e
+ call Func_7310
+ ld e, a
+ jr .done_toss_anim
+.wait_anim
+ push de
+ call DoFrame
+ call CheckAnyAnimationPlaying
+ pop de
+ jr c, .wait_anim
+ ld a, e
+ call Func_72ff
+
+.done_toss_anim
+ ld b, DUEL_ANIM_COIN_HEADS
+ ld c, $34 ; tile for circle
+ ld a, e
+ or a
+ jr z, .show_result
+ ld b, DUEL_ANIM_COIN_TAILS
+ ld c, $30 ; tile for cross
+ ld hl, wCoinTossNumHeads
+ inc [hl]
+
+.show_result
+ ld a, b
+ call PlayDuelAnimation
+
+; load correct sound effect
+; the sound of the coin toss result
+; is dependant on whether it was the Player
+; or the Opponent to get heads/tails
+ ld a, [wCoinTossDuelistType]
+ or a
+ jr z, .check_sfx
+ ld a, $1
+ xor e ; invert result in case it's not Player
+ ld e, a
+.check_sfx
+ ld d, SFX_54
+ ld a, e
+ or a
+ jr nz, .got_sfx
+ ld d, SFX_55
+.got_sfx
+ ld a, d
+ call PlaySFX
+
+; in case it's a multiple coin toss scenario,
+; then the result needs to be registered on screen
+; with a circle (o) or a cross (x)
+ ld a, [wCoinTossTotalNum]
+ dec a
+ jr z, .incr_num_coin_tossed ; skip if not more than 1 coin toss
+ ld a, c
+ push af
+ ld e, 0
+ ld a, [wCoinTossNumTossed]
+; calculate the offset to draw the circle/cross
+.asm_72a3
+ ; if < 10, then the offset is simply calculated
+ ; from wCoinTossNumTossed * 2...
+ cp 10
+ jr c, .got_offset
+ ; ...else the y-offset is added for each multiple of 10
+ inc e
+ inc e
+ sub 10
+ jr .asm_72a3
+
+.got_offset
+ add a
+ ld d, a
+ lb bc, 2, 2
+ lb hl, 1, 2
+ pop af
+ call FillRectangle
+
+.incr_num_coin_tossed
+ ld hl, wCoinTossNumTossed
+ inc [hl]
+
+ ld a, [wCoinTossDuelistType]
+ or a
+ jr z, .asm_72dc
+ ld a, [hl]
+ ld hl, wCoinTossTotalNum
+ cp [hl]
+ call z, WaitForWideTextBoxInput
+ call Func_7324
+ ld a, [wCoinTossTotalNum]
+ ld hl, wCoinTossNumHeads
+ or [hl]
+ jr nz, .asm_72e2
+ call z, WaitForWideTextBoxInput
+ jr .asm_72e2
+
+.asm_72dc
+ call WaitForWideTextBoxInput
+ call Func_72ff
+
+.asm_72e2
+ call Func_3b31
+ ld a, [wCoinTossNumTossed]
+ ld hl, wCoinTossTotalNum
+ cp [hl]
+ jp c, .print_coin_tally
+ call ExchangeRNG
+ call Func_3b31
+ call Func_3b21
+
+; return carry if at least 1 heads
+ ld a, [wCoinTossNumHeads]
+ or a
+ ret z
+ scf
+ ret
+
+Func_72ff:
+ ldh [hff96], a
+ ld a, [wDuelType]
+ cp DUELTYPE_LINK
+ ret nz
+ ldh a, [hff96]
+ call SerialSendByte
+ call Func_7344
+ ret
+
+Func_7310:
+ ldh [hff96], a
+ ld a, [wDuelType]
+ cp DUELTYPE_LINK
+ jr z, Func_7338
+.loop_anim
+ call DoFrame
+ call CheckAnyAnimationPlaying
+ jr c, .loop_anim
+ ldh a, [hff96]
+ ret
+
+Func_7324:
+ ldh [hff96], a
+ ld a, [wDuelType]
+ cp DUELTYPE_LINK
+ jr z, Func_7338
+
+; delay coin flip for AI opponent
+ ld a, 30
+.asm_732f
+ call DoFrame
+ dec a
+ jr nz, .asm_732f
+ ldh a, [hff96]
+ ret
+
+Func_7338:
+ call DoFrame
+ call SerialRecvByte
+ jr c, Func_7338
+ call Func_7344
+ ret
+
+Func_7344:
+ push af
+ ld a, [wSerialFlags]
+ or a
+ jr nz, .asm_734d
+ pop af
+ ret
+.asm_734d
+ call Func_3b31
+ call DuelTransmissionError
+ ret
+
+BuildVersion:
+ db "VER 12/20 09:36", TX_END
+
+; possibly unreferenced, used for testing
+; enters computer opponent selection screen
+; handles input to select/cancel/scroll through deck IDs
+; loads the NPC duel configurations if one was selected
+; returns carry if selection was cancelled
+Func_7364:
+ xor a
+ ld [wTileMapFill], a
+ call ZeroObjectPositionsAndToggleOAMCopy
+ call EmptyScreen
+ call LoadSymbolsFont
+ lb de, $38, $9f
+ call SetupText
+ call DrawWideTextBox
+ call EnableLCD
+
+ xor a
+ ld [wOpponentDeckID], a
+ call DrawOpponentSelectionScreen
+.wait_input
+ call DoFrame
+ ldh a, [hDPadHeld]
+ or a
+ jr z, .wait_input
+ ld b, a
+
+ ; handle selection/cancellation buttons
+ and A_BUTTON | START
+ jr nz, .select_opp
+ bit B_BUTTON_F, b
+ jr nz, .cancel
+
+; handle D-pad inputs
+; check right
+ ld a, [wOpponentDeckID]
+ bit D_RIGHT_F, b
+ jr z, .check_left
+ inc a ; next deck ID
+ cp DECK_IDS_END + 1
+ jr c, .check_left
+ xor a ; wrap around to first deck ID
+
+.check_left
+ bit D_LEFT_F, b
+ jr z, .check_up
+ or a
+ jr nz, .not_first_deck_id
+ ld a, DECK_IDS_END ; wrap around to last deck ID
+ jr .check_up
+.not_first_deck_id
+ dec a ; previous deck ID
+
+.check_up
+ bit D_UP_F, b
+ jr z, .check_down
+ add 10
+ cp DECK_IDS_END + 1
+ jr c, .check_down
+ xor a ; wrap around to first deck ID
+
+.check_down
+ bit D_DOWN_F, b
+ jr z, .got_deck_id
+ sub 10
+ jr nc, .got_deck_id
+ ld a, DECK_IDS_END ; wrap around to last deck ID
+
+.got_deck_id
+ ld [wOpponentDeckID], a
+ call DrawOpponentSelectionScreen
+ jr .wait_input
+
+.cancel
+ scf
+ ret
+.select_opp
+ ld a, [wOpponentDeckID]
+ ld [wNPCDuelDeckID], a
+ call GetNPCDuelConfigurations
+ or a
+ ret
+
+; draws the current opponent to be selected
+; (his/her portrait and name)
+; and prints text box for selection
+DrawOpponentSelectionScreen:
+ ld a, [wOpponentDeckID]
+ ld [wNPCDuelDeckID], a
+ call GetNPCDuelConfigurations
+ jr c, .ok
+ ; duel configuration not found for the NPC
+ ; so load a default portrait and name
+ xor a
+ ld [wOpponentPortrait], a
+ ld hl, wOpponentName
+ ld [hli], a
+ ld [hl], a
+.ok
+ ld hl, SelectComputerOpponentData
+ call PlaceTextItems
+ call DrawDuelistPortraitsAndNames
+ ld a, [wOpponentDeckID]
+ lb bc, 5, 16
+ call WriteTwoByteNumberInTxSymbolFormat
+ ld a, [wNPCDuelPrizes]
+ lb bc, 15, 10
+ call WriteTwoByteNumberInTxSymbolFormat
+ ret
+
+SelectComputerOpponentData:
+ textitem 10, 0, ClearOpponentNameText
+ textitem 10, 10, NumberOfPrizesText
+ textitem 3, 14, SelectComputerOpponentText
+ db $ff
+
+Func_7415:
+ xor a
+ ld [wce7e], a
+ ret
+
+Func_741a:
+ ld hl, wEffectFunctionsFeedbackIndex
+ ld a, [hl]
+ or a
+ ret z
+ ld e, a
+ ld d, $00
+ ld hl, wEffectFunctionsFeedback
+ add hl, de
+ ld [hl], $00
+ ld hl, wEffectFunctionsFeedback
+.loop
+ ld a, [hli]
+ or a
+ jr z, .done
+ ld d, a
+ inc hl
+ ld a, [hli]
+ ld e, ATK_ANIM_SLEEP
+ cp ASLEEP
+ jr z, .got_anim
+ ld e, ATK_ANIM_PARALYSIS
+ cp PARALYZED
+ jr z, .got_anim
+ ld e, ATK_ANIM_POISON
+ cp POISONED
+ jr z, .got_anim
+ ld e, ATK_ANIM_POISON
+ cp DOUBLE_POISONED
+ jr z, .got_anim
+ ld e, ATK_ANIM_CONFUSION
+ cp CONFUSED
+ jr nz, .loop
+ ldh a, [hWhoseTurn]
+ cp d
+ jr nz, .got_anim
+ ld e, ATK_ANIM_IMAKUNI_CONFUSION
+.got_anim
+ ld a, e
+ ld [wLoadedAttackAnimation], a
+ xor a
+ ld [wDuelAnimLocationParam], a
+ push hl
+ farcall PlayAttackAnimationCommands
+ pop hl
+ jr .loop
+.done
+ ret
+
+; this is a simple version of PlayAttackAnimation_DealAttackDamage that doesn't
+; take into account status conditions, damage modifiers, etc, for damage calculation.
+; used for confusion damage to self and for damage to benched Pokemon, for example
+PlayAttackAnimation_DealAttackDamageSimple:
+ push hl
+ push de
+ call PlayAttackAnimation
+ call WaitAttackAnimation
+ pop de
+ pop hl
+ call SubtractHP
+ ld a, [wDuelDisplayedScreen]
+ cp DUEL_MAIN_SCENE
+ ret nz
+ push hl
+ push de
+ call DrawDuelHUDs
+ pop de
+ pop hl
+ ret
+
+; if [wLoadedAttackAnimation] != 0, wait until the animation is over
+WaitAttackAnimation:
+ ld a, [wLoadedAttackAnimation]
+ or a
+ ret z
+ push de
+.anim_loop
+ call DoFrame
+ call CheckAnyAnimationPlaying
+ jr c, .anim_loop
+ pop de
+ ret
+
+; play attack animation
+; input:
+; - [wLoadedAttackAnimation]: animation to play
+; - de: damage dealt by the attack (to display the animation with the number)
+; - c: a wDamageEffectiveness constant (to print WEAK or RESIST if necessary)
+PlayAttackAnimation:
+ ldh a, [hWhoseTurn]
+ push af
+ push hl
+ push de
+ push bc
+ ld a, [wWhoseTurn]
+ ldh [hWhoseTurn], a
+ ld a, c
+ ld [wce81], a
+ ldh a, [hWhoseTurn]
+ cp h
+ jr z, .asm_74aa
+ set 7, b
+.asm_74aa
+ ld a, b
+ ld [wce82], a
+ ld a, [wWhoseTurn]
+ ld [wce83], a
+ ld a, [wTempNonTurnDuelistCardID]
+ ld [wce84], a
+ ld hl, wce7f
+ ld [hl], e
+ inc hl
+ ld [hl], d
+
+; if damage >= 70, ATK_ANIM_HIT becomes ATK_ANIM_BIG_HIT
+ ld a, [wLoadedAttackAnimation]
+ cp ATK_ANIM_HIT
+ jr nz, .got_anim
+ ld a, e
+ cp 70
+ jr c, .got_anim
+ ld a, ATK_ANIM_BIG_HIT
+ ld [wLoadedAttackAnimation], a
+
+.got_anim
+ farcall PlayAttackAnimationCommands
+ pop bc
+ pop de
+ pop hl
+ pop af
+ ldh [hWhoseTurn], a
+ ret
+
+Func_74dc:
+ call EmptyScreen
+ call EnableLCD
+ ld a, GRASS_ENERGY
+ ld [wPrizeCardSelectionFrameCounter], a
+.wait_input
+ call DoFrame
+ ldh a, [hDPadHeld]
+ ld b, a
+ ld a, [wPrizeCardSelectionFrameCounter]
+; left
+ bit D_LEFT_F, b
+ jr z, .right
+ dec a ; previous card
+.right
+ bit D_RIGHT_F, b
+ jr z, .up
+ inc a ; next card
+.up
+ bit D_UP_F, b
+ jr z, .down
+ add 10
+.down
+ bit D_DOWN_F, b
+ jr z, .got_card_id
+ sub 10
+
+.got_card_id
+ ld [wPrizeCardSelectionFrameCounter], a
+ lb bc, 5, 5
+ bank1call WriteTwoByteNumberInTxSymbolFormat
+ ldh a, [hKeysPressed]
+ and START
+ jr z, .wait_input
+ ld a, [wPrizeCardSelectionFrameCounter]
+ ld e, a
+ ld d, $0
+.card_loop
+ call LoadCardDataToBuffer1_FromCardID
+ ret c ; card not found
+ push de
+ ld a, e
+ call Func_758a
+ pop de
+ inc de
+ jr .card_loop
+
+; seems to communicate with other device
+; for starting a duel
+; outputs in hl either wPlayerDuelVariables
+; or wOpponentDuelVariables depending on wSerialOp
+DecideLinkDuelVariables:
+ call Func_0e8e
+ ldtx hl, PressStartWhenReadyText
+ call DrawWideTextBox_PrintText
+ call EnableLCD
+.input_loop
+ call DoFrame
+ ldh a, [hKeysPressed]
+ bit B_BUTTON_F, a
+ jr nz, .link_cancel
+ and START
+ call Func_0cc5
+ jr nc, .input_loop
+ ld hl, wPlayerDuelVariables
+ ld a, [wSerialOp]
+ cp $29
+ jr z, .link_continue
+ ld hl, wOpponentDuelVariables
+ cp $12
+ jr z, .link_continue
+.link_cancel
+ call ResetSerial
+ scf
+ ret
+.link_continue
+ or a
+ ret
+
+ ret ; stray ret