diff options
author | dannye <33dannye@gmail.com> | 2020-12-20 13:19:33 -0600 |
---|---|---|
committer | dannye <33dannye@gmail.com> | 2020-12-20 13:19:33 -0600 |
commit | b276b23d4e9ea34d64766ddb92c768b4bc4f1b8f (patch) | |
tree | 9ba304cf8d635d6f6c81c85ce864b0311108b414 /src/engine/effect_functions.asm | |
parent | a134c1f9a9c197ee9662c8177fa487ec938f5294 (diff) | |
parent | 68f371effcfc31927dc093a68505af85f523d243 (diff) |
Merge branch 'master' of https://github.com/pret/poketcg
Diffstat (limited to 'src/engine/effect_functions.asm')
-rw-r--r-- | src/engine/effect_functions.asm | 11003 |
1 files changed, 10932 insertions, 71 deletions
diff --git a/src/engine/effect_functions.asm b/src/engine/effect_functions.asm index d881a5c..77c0375 100644 --- a/src/engine/effect_functions.asm +++ b/src/engine/effect_functions.asm @@ -15,6 +15,8 @@ Paralysis50PercentEffect: ; 2c011 (b:4011) ldtx de, ParalysisCheckText call TossCoin_BankB ret nc + +ParalysisEffect: ; 2c018 (b:4018) lb bc, PSN_DBLPSN, PARALYZED jr ApplyStatusEffect @@ -27,6 +29,7 @@ ConfusionEffect: ; 2c024 (b:4024) lb bc, PSN_DBLPSN, CONFUSED jr ApplyStatusEffect +Sleep50PercentEffect: ; 2c029 (b:4029) ldtx de, SleepCheckText call TossCoin_BankB ret nc @@ -57,7 +60,7 @@ ApplyStatusEffect: ; 2c035 (b:4035) .cant_induce_status ld a, c - ld [wNoEffectFromStatus], a + ld [wNoEffectFromWhichStatus], a call SetNoEffectFromStatus or a ret @@ -143,7 +146,8 @@ Func_2c0bd: ; 2c0bd (b:40bd) call ShuffleDeck ret -Func_2c0c7: ; 2c0c7 (b:40c7) +; return carry if Player is the Turn Duelist +IsPlayerTurn: ; 2c0c7 (b:40c7) ld a, DUELVARS_DUELIST_TYPE call GetTurnDuelistVariable cp DUELIST_TYPE_PLAYER @@ -154,7 +158,8 @@ Func_2c0c7: ; 2c0c7 (b:40c7) scf ret -; Sets some flags for AI use +; Stores information about the attack damage for AI purposes +; taking into account poison damage between turns. ; if target poisoned ; [wAIMinDamage] <- [wDamage] ; [wAIMaxDamage] <- [wDamage] @@ -162,19 +167,23 @@ Func_2c0c7: ; 2c0c7 (b:40c7) ; [wAIMinDamage] <- [wDamage] + d ; [wAIMaxDamage] <- [wDamage] + e ; [wDamage] <- [wDamage] + a -Func_2c0d4: ; 2c0d4 (b:40d4) +UpdateExpectedAIDamage_AccountForPoison: ; 2c0d4 (b:40d4) push af ld a, DUELVARS_ARENA_CARD_STATUS call GetNonTurnDuelistVariable and POISONED | DOUBLE_POISONED - jr z, Func_2c0e9.skip_push_af + jr z, UpdateExpectedAIDamage.skip_push_af pop af ld a, [wDamage] ld [wAIMinDamage], a ld [wAIMaxDamage], a ret -Func_2c0e9: ; 2c0e9 (b:40e9) +; Sets some variables for AI use +; [wAIMinDamage] <- [wDamage] + d +; [wAIMaxDamage] <- [wDamage] + e +; [wDamage] <- [wDamage] + a +UpdateExpectedAIDamage: ; 2c0e9 (b:40e9) push af .skip_push_af @@ -190,11 +199,11 @@ Func_2c0e9: ; 2c0e9 (b:40e9) ld [hl], a ret -; Sets some flags for AI use -; [wDamage] <- a -; [wAIMinDamage] <- d -; [wAIMaxDamage] <- e -Func_2c0fb: ; 2c0fb (b:40fb) +; Stores information about the attack damage for AI purposes +; [wDamage] <- a (average amount of damage) +; [wAIMinDamage] <- d (minimum) +; [wAIMaxDamage] <- e (maximum) +SetExpectedAIDamage: ; 2c0fb (b:40fb) ld [wDamage], a xor a ld [wDamage + 1], a @@ -223,7 +232,7 @@ DealDamageToAllBenchedPokemon: ; 2c117 (b:4117) jr .skip_to_bench .loop push bc - call DealDamageToPlayAreaPokemon + call DealDamageToPlayAreaPokemon_RegularAnim pop bc .skip_to_bench inc b @@ -268,7 +277,7 @@ ApplySubstatus2ToDefendingCard: ; 2c149 (b:4149) .no_damage_orEffect pop af push hl - bank1call $4f9d + bank1call DrawDuelMainScene pop hl ld a, l or h @@ -277,7 +286,7 @@ ApplySubstatus2ToDefendingCard: ; 2c149 (b:4149) ; overwrites in wDamage, wAIMinDamage and wAIMaxDamage ; with the value in a. -StoreDamageInfo: ; 2c166 (b:4166) +SetDefiniteDamage: ; 2c166 (b:4166) ld [wDamage], a ld [wAIMinDamage], a ld [wAIMaxDamage], a @@ -286,7 +295,122 @@ StoreDamageInfo: ; 2c166 (b:4166) ret ; 0x2c174 - INCROM $2c174, $2c1ec +; overwrites wAIMinDamage and wAIMaxDamage +; with value in wDamage. +SetMinMaxDamageSameAsDamage: ; 2c174 (b:4174) + ld a, [wDamage] + ld [wAIMinDamage], a + ld [wAIMaxDamage], a + ret +; 0x2c17e + +; returns in a some random occupied Play Area location +; in Turn Duelist's Play Area. +PickRandomPlayAreaCard: ; 2c17e (b:417e) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + call Random + or a + ret +; 0x2c188 + +; outputs in hl the next position +; in hTempList to place a new card, +; and increments hCurSelectionItem. +GetNextPositionInTempList: ; 2c188 (b:4188) + push de + ld hl, hCurSelectionItem + ld a, [hl] + inc [hl] + ld e, a + ld d, $00 + ld hl, hTempList + add hl, de + pop de + ret +; 0x2c197 + +; creates in wDuelTempList list of attached Fire Energy cards +; that are attached to the Turn Duelist's Arena card. +CreateListOfFireEnergyAttachedToArena: ; 2c197 (b:4197) + ld a, TYPE_ENERGY_FIRE + ; fallthrough + +; creates in wDuelTempList a list of cards that +; are in the Arena of the same type as input a. +; this is called to list Energy cards of a specific type +; that are attached to the Arena Pokemon. +; input: +; a = TYPE_ENERGY_* constant +; output: +; a = number of cards in list; +; wDuelTempList filled with cards, terminated by $ff +CreateListOfEnergyAttachedToArena: ; 2c199 (b:4199) + ld b, a + ld c, 0 + ld de, wDuelTempList + ld a, DUELVARS_CARD_LOCATIONS + call GetTurnDuelistVariable +.loop + ld a, [hl] + cp CARD_LOCATION_ARENA + jr nz, .next + push de + ld a, l + call GetCardIDFromDeckIndex + call GetCardType + pop de + cp b + jr nz, .next ; is same as input type? + ld a, l + ld [de], a + inc de + inc c +.next + inc l + ld a, l + cp DECK_SIZE + jr c, .loop + + ld a, $ff + ld [de], a + ld a, c + ret +; 0x2c1c4 + +; prints the text "<X> devolved to <Y>!" with +; the proper card names and levels. +; input: +; d = deck index of the lower stage card +; e = deck index of card that was devolved +PrintDevolvedCardNameAndLevelText: ; 2c1c4 (b:41c4) + push de + ld a, e + call LoadCardDataToBuffer1_FromDeckIndex + ld bc, wTxRam2 + ld hl, wLoadedCard1Name + ld a, [hli] + ld [bc], a + inc bc + ld a, [hl] + ld [bc], a + + inc bc ; wTxRam2_b + xor a + ld [bc], a + inc bc + ld [bc], a + + ld a, d + call LoadCardDataToBuffer1_FromDeckIndex + ld a, 18 + call CopyCardNameAndLevel + ld [hl], $00 + ldtx hl, PokemonDevolvedToText + call DrawWideTextBox_WaitForInput + pop de + ret +; 0x2c1ec HandleSwitchDefendingPokemonEffect: ; 2c1ec (b:41ec) ld e, a @@ -305,7 +429,7 @@ HandleSwitchDefendingPokemonEffect: ; 2c1ec (b:41ec) pop de .switch - call .HandleNoDamageOrEffect + call HandleNoDamageOrEffect ret c ; attack was successful, switch Defending Pokemon @@ -322,7 +446,7 @@ HandleSwitchDefendingPokemonEffect: ; 2c1ec (b:41ec) ; returns carry if Defending has No Damage or Effect ; if so, print its appropriate text. -.HandleNoDamageOrEffect: ; 2c216 (b:4216) +HandleNoDamageOrEffect: ; 2c216 (b:4216) call CheckNoDamageOrEffect ret nc ld a, l @@ -332,16 +456,144 @@ HandleSwitchDefendingPokemonEffect: ; 2c1ec (b:41ec) ret ; 0x2c221 - INCROM $2c221, $2c2a4 +; applies HP recovery on Pokemon after an attack +; with HP recovery effect, and handles its animation. +; input: +; d = damage effectiveness +; e = HP amount to recover +ApplyAndAnimateHPRecovery: ; 2c221 (b:4221) + push de + ld hl, wccbd + ld [hl], e + inc hl + ld [hl], d + +; get Arena card's damage + ld e, PLAY_AREA_ARENA + call GetCardDamageAndMaxHP + pop de + or a + ret z ; return if no damage + +; load correct animation + push de + ld a, $79 + ld [wLoadedMoveAnimation], a + ld bc, $01 ; arrow + bank1call PlayMoveAnimation + +; compare HP to be restored with max HP +; if HP to be restored would cause HP to +; be larger than max HP, cap it accordingly + ld e, PLAY_AREA_ARENA + call GetCardDamageAndMaxHP + ld b, $00 + pop de + ld a, DUELVARS_ARENA_CARD_HP + call GetTurnDuelistVariable + add e + ld e, a + ld a, 0 + adc d + ld d, a + ; de = damage dealt + current HP + ; bc = max HP of card + call CompareDEtoBC + jr c, .skip_cap + ; cap de to value in bc + ld e, c + ld d, b + +.skip_cap + ld [hl], e ; apply new HP to arena card + bank1call WaitMoveAnimation + ret +; 0x2c25b + +; returns carry if Play Area has no damage counters. +CheckIfPlayAreaHasAnyDamage: ; 2c25b (b:425b) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ld d, a + ld e, PLAY_AREA_ARENA +.loop_play_area + call GetCardDamageAndMaxHP + or a + ret nz ; found damage + inc e + dec d + jr nz, .loop_play_area + ; no damage found + scf + ret +; 0x2c26e ; makes a list in wDuelTempList with the deck indices -; of all the energy cards found in opponent's Discard Pile. -; if (c == 0), all energy cards are allowed; -; if (c != 0), double colorless energy cards are not counted. -; returns carry if no energy cards were found. -CreateEnergyCardListFromOpponentDiscardPile: ; 2c2a4 (b:42a4) +; of Trainer cards found in Turn Duelist's Discard Pile. +; returns carry set if no Trainer cards found, and loads +; corresponding text to notify this. +CreateTrainerCardListFromDiscardPile: ; 2c26e (b:426e) +; get number of cards in Discard Pile +; and have hl point to the end of the +; Discard Pile list in wOpponentDeckCards. + ld a, DUELVARS_NUMBER_OF_CARDS_IN_DISCARD_PILE + call GetTurnDuelistVariable + ld b, a + add DUELVARS_DECK_CARDS + ld l, a + + ld de, wDuelTempList + inc b + jr .next_card + +.check_trainer + ld a, [hl] + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Type] + cp TYPE_TRAINER + jr nz, .next_card + + ld a, [hl] + ld [de], a + inc de + +.next_card + dec l + dec b + jr nz, .check_trainer + + ld a, $ff ; terminating byte + ld [de], a + ld a, [wDuelTempList] + cp $ff + jr z, .no_trainers + or a + ret +.no_trainers + ldtx hl, ThereAreNoTrainerCardsInDiscardPileText + scf + ret +; 0x2c2a0 + +; makes a list in wDuelTempList with the deck indices +; of all basic energy cards found in Turn Duelist's Discard Pile. +CreateEnergyCardListFromDiscardPile_OnlyBasic: ; 2c2a0 (b:42a0) + ld c, $01 + jr CreateEnergyCardListFromDiscardPile + +; makes a list in wDuelTempList with the deck indices +; of all energy cards (including Double Colorless) +; found in Turn Duelist's Discard Pile. +CreateEnergyCardListFromDiscardPile_AllEnergy: ; 2c2a4 (b:42a4) ld c, $00 +; fallthrough +; makes a list in wDuelTempList with the deck indices +; of energy cards found in Turn Duelist's Discard Pile. +; if (c == 0), all energy cards are allowed; +; if (c != 0), double colorless energy cards are not included. +; returns carry if no energy cards were found. +CreateEnergyCardListFromDiscardPile: ; 2c2a6 (b:42a6) ; get number of cards in Discard Pile ; and have hl point to the end of the ; Discard Pile list in wOpponentDeckCards. @@ -402,12 +654,359 @@ CreateEnergyCardListFromOpponentDiscardPile: ; 2c2a4 (b:42a4) ret ; 0x2c2e0 - INCROM $2c2e0, $2c487 +; returns carry if Deck is empty +CheckIfDeckIsEmpty: ; 2c2e0 (b:42e0) + ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK + call GetTurnDuelistVariable + ldtx hl, NoCardsLeftInTheDeckText + cp DECK_SIZE + ccf + ret +; 0x2c2ec + +; searches through Deck in wDuelTempList looking for +; a certain card or cards, and prints text depending +; on whether at least one was found. +; if none were found, asks the Player whether to look +; in the Deck anyway, and returns carry if No is selected. +; uses SEARCHEFFECT_* as input which determines what to search for: +; SEARCHEFFECT_CARD_ID = search for card ID in e +; SEARCHEFFECT_NIDORAN = search for either NidoranM or NidoranF +; SEARCHEFFECT_BASIC_FIGHTING = search for any Basic Fighting Pokemon +; SEARCHEFFECT_BASIC_ENERGY = search for any Basic Energy +; SEARCHEFFECT_POKEMON = search for any Pokemon card +; input: +; d = SEARCHEFFECT_* constant +; e = (optional) card ID to search for in deck +; hl = text to print if Deck has card(s) +; output: +; carry set if refused to look at deck +LookForCardsInDeck: ; 2c2ec (b:42ec) + push hl + push bc + ld a, [wDuelTempList] + cp $ff + jr z, .none_in_deck + ld a, d + ld hl, .search_table + call JumpToFunctionInTable + jr c, .none_in_deck + pop bc + pop hl + call DrawWideTextBox_WaitForInput + or a + ret + +.none_in_deck + pop hl + call LoadTxRam2 + pop hl + ldtx hl, ThereIsNoInTheDeckText + call DrawWideTextBox_WaitForInput + ldtx hl, WouldYouLikeToCheckTheDeckText + call YesOrNoMenuWithText_SetCursorToYes + ret +; 0x2c317 + +.search_table + dw .SearchDeckForCardID + dw .SearchDeckForNidoran + dw .SearchDeckForBasicFighting + dw .SearchDeckForBasicEnergy + dw .SearchDeckForPokemon + +.set_carry ; 2c321 (b:4321) + scf + ret +; 0x2c323 + +; returns carry if no card with +; same card ID as e is found in Deck +.SearchDeckForCardID ; 2c323 (b:4323) + ld hl, wDuelTempList +.loop_deck_e + ld a, [hli] + cp $ff + jr z, .set_carry + push de + call GetCardIDFromDeckIndex + ld a, e + pop de + cp e + jr nz, .loop_deck_e + or a + ret +; 0x2c336 + +; returns carry if no NidoranM or NidoranF card is found in Deck +.SearchDeckForNidoran ; 2c336 (b:4336) + ld hl, wDuelTempList +.loop_deck_nidoran + ld a, [hli] + cp $ff + jr z, .set_carry + call GetCardIDFromDeckIndex + ld a, e + cp NIDORANF + jr z, .found_nidoran + cp NIDORANM + jr nz, .loop_deck_nidoran +.found_nidoran + or a + ret +; 0x2c34c + +; returns carry if no Basic Fighting Pokemon is found in Deck +.SearchDeckForBasicFighting ; 2c34c (b:434c) + ld hl, wDuelTempList +.loop_deck_fighting + ld a, [hli] + cp $ff + jr z, .set_carry + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Type] + cp TYPE_PKMN_FIGHTING + jr nz, .loop_deck_fighting + ld a, [wLoadedCard2Stage] + or a ; BASIC + jr nz, .loop_deck_fighting + ret +; 0x2c365 + +; returns carry if no Basic Energy cards are found in Deck +.SearchDeckForBasicEnergy ; 2c365 (b:4365) + ld hl, wDuelTempList +.loop_deck_energy + ld a, [hli] + cp $ff + jr z, .set_carry + call GetCardIDFromDeckIndex + call GetCardType + cp TYPE_ENERGY_DOUBLE_COLORLESS + jr z, .loop_deck_energy + and TYPE_ENERGY + jr z, .loop_deck_energy + or a + ret +; 0x2c37d + +; returns carry if no Pokemon cards are found in Deck +.SearchDeckForPokemon ; 2c37d (b:437d) + ld hl, wDuelTempList +.loop_deck_pkmn + ld a, [hli] + cp $ff + jr z, .set_carry + call GetCardIDFromDeckIndex + call GetCardType + cp TYPE_ENERGY + jr nc, .loop_deck_pkmn + or a + ret +; 0x2c391 + +; handles the Player selection of attack +; to use, i.e. Amnesia or Metronome on. +; returns carry if none selected. +; outputs: +; d = card index of defending card +; e = attack index selected +HandleDefendingPokemonAttackSelection: ; 2c391 (b:4391) + bank1call DrawDuelMainScene + call SwapTurn + xor a + ldh [hCurSelectionItem], a + +.start + bank1call PrintAndLoadMovesToDuelTempList + push af + ldh a, [hCurSelectionItem] + ld hl, .menu_parameters + call InitializeMenuParameters + pop af + + ld [wNumMenuItems], a + call EnableLCD +.loop_input + call DoFrame + ldh a, [hKeysPressed] + bit B_BUTTON_F, a + jr nz, .set_carry + and START + jr nz, .open_move_page + call HandleMenuInput + jr nc, .loop_input + cp -1 + jr z, .loop_input + +; a move was selected + ldh a, [hCurMenuItem] + add a + ld e, a + ld d, $00 + ld hl, wDuelTempList + add hl, de + ld d, [hl] + inc hl + ld e, [hl] + call SwapTurn + or a + ret + +.set_carry + call SwapTurn + scf + ret -; handles the selection of a forced switch -; by link/AI opponent or by the player. -; outputs the Play Area location of the chosen -; bench card in hTempPlayAreaLocation_ff9d. +.open_move_page + ldh a, [hCurMenuItem] + ldh [hCurSelectionItem], a + ld a, DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + call LoadCardDataToBuffer1_FromDeckIndex + bank1call OpenMovePage + call SwapTurn + bank1call DrawDuelMainScene + call SwapTurn + jr .start +; 0x2c3f4 + +.menu_parameters + 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 $0000 ; function pointer if non-0 +; 0x2c3fc + +; loads in hl the pointer to attack's name. +; input: +; d = deck index of card +; e = attack index (0 = first attack, 1 = second attack) +GetAttackName: ; 2c3fc (b:43fc) + ld a, d + call LoadCardDataToBuffer1_FromDeckIndex + ld hl, wLoadedCard1Move1Name + inc e + dec e + jr z, .load_name + ld hl, wLoadedCard1Move2Name +.load_name + ld a, [hli] + ld h, [hl] + ld l, a + ret +; 0x2c40e + +; returns carry if Defending Pokemon +; doesn't have an attack. +CheckIfDefendingPokemonHasAnyAttack: ; 2c40e (b:440e) + call SwapTurn + ld a, DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Move1Category] + cp POKEMON_POWER + jr nz, .has_attack + ld hl, wLoadedCard2Move2Name + ld a, [hli] + or [hl] + jr nz, .has_attack + call SwapTurn + scf + ret +.has_attack + call SwapTurn + or a + ret +; 0x2c431 + +; overwrites HP and Stage data of the card that was +; devolved in the Play Area to the values of new card. +; if the damage exceeds HP of pre-evolution, +; then HP is set to zero. +; input: +; a = card index of pre-evolved card +UpdateDevolvedCardHPAndStage: ; 2c431 (b:4431) + push bc + push de + push af + ldh a, [hTempPlayAreaLocation_ff9d] + ld e, a + call GetCardDamageAndMaxHP + ld b, a ; store damage + ld a, e + add DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + pop af + + ld [hl], a + call LoadCardDataToBuffer2_FromDeckIndex + ld a, e + add DUELVARS_ARENA_CARD_HP + ld l, a + ld a, [wLoadedCard2HP] + sub b ; subtract damage from new HP + jr nc, .got_hp + ; damage exceeds HP + xor a ; 0 HP +.got_hp + ld [hl], a + ld a, e +; overwrite card stage + add DUELVARS_ARENA_CARD_STAGE + ld l, a + ld a, [wLoadedCard2Stage] + ld [hl], a + pop de + pop bc + ret +; 0x2c45d + +; reset various status after devolving card. +ResetDevolvedCardStatus: ; 2c45d (b:445d) +; if it's Arena card, clear status conditions + ldh a, [hTempPlayAreaLocation_ff9d] + or a + jr nz, .skip_clear_status + call ClearAllStatusConditions +.skip_clear_status +; reset changed color status + ldh a, [hTempPlayAreaLocation_ff9d] + add DUELVARS_ARENA_CARD_CHANGED_TYPE + call GetTurnDuelistVariable + ld [hl], $00 +; reset C2 flags + ldh a, [hTempPlayAreaLocation_ff9d] + add DUELVARS_ARENA_CARD_FLAGS + ld l, a + ld [hl], $00 + ret +; 0x2c476 + +; prompts the Player with a Yes/No question +; whether to quit the screen, even though +; they can select more cards from list. +; [hCurSelectionItem] holds number of cards +; that were already selected by the Player. +; input: +; - a = total number of cards that can be selected +; output: +; - carry set if "No" was selected +AskWhetherToQuitSelectingCards: ; 2c476 (b:4476) + ld hl, hCurSelectionItem + sub [hl] + ld l, a + ld h, $00 + call LoadTxRam3 + ldtx hl, YouCanSelectMoreCardsQuitText + call YesOrNoMenuWithText + ret +; 0x2c487 + +; handles the selection of a forced switch by link/AI opponent or by the player. +; outputs the Play Area location of the chosen bench card in hTempPlayAreaLocation_ff9d. DuelistSelectForcedSwitch: ; 2c487 (b:4487) ld a, DUELVARS_DUELIST_TYPE call GetNonTurnDuelistVariable @@ -459,12 +1058,403 @@ DuelistSelectForcedSwitch: ; 2c487 (b:4487) ret ; 0x2c4da - INCROM $2c4da, $2c6f0 +; returns in a the card index of energy card +; attached to Defending Pokemon +; that is to be discarded by the AI for an effect. +; outputs $ff is none was found. +; output: +; a = deck index of attached energy card chosen +AIPickEnergyCardToDiscardFromDefendingPokemon: ; 2c4da (b:44da) + call SwapTurn + ld e, PLAY_AREA_ARENA + call GetPlayAreaCardAttachedEnergies + + xor a + call CreateArenaOrBenchEnergyCardList + jr nc, .has_energy + ; no energy, return + ld a, $ff + jr .done + +.has_energy + ld a, DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + call LoadCardDataToBuffer1_FromDeckIndex + ld e, COLORLESS + ld a, [wAttachedEnergies + COLORLESS] + or a + jr nz, .pick_color ; has colorless attached? + + ; no colorless energy attached. + ; if it's colorless Pokemon, just + ; pick any energy card at random... + ld a, [wLoadedCard1Type] + cp COLORLESS + jr nc, .choose_random + + ; ...if not, check if it has its + ; own color energy attached. + ; if it doesn't, pick at random. + ld e, a + ld d, $00 + ld hl, wAttachedEnergies + add hl, de + ld a, [hl] + or a + jr z, .choose_random + +; pick attached card with same color as e +.pick_color + ld hl, wDuelTempList +.loop_energy + ld a, [hli] + cp $ff + jr z, .choose_random + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Type] + and TYPE_PKMN + cp e + jr nz, .loop_energy + dec hl + +.done_chosen + ld a, [hl] +.done + call SwapTurn + ret + +.choose_random + call CountCardsInDuelTempList + ld hl, wDuelTempList + call ShuffleCards + jr .done_chosen +; 0x2c532 + +; handles AI logic to pick attack for Amnesia +AIPickAttackForAmnesia: ; 2c532 (b:4532) +; load Defending Pokemon attacks + call SwapTurn + ld e, PLAY_AREA_ARENA + call GetPlayAreaCardAttachedEnergies + call HandleEnergyBurn + ld a, DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + ld d, a + call LoadCardDataToBuffer2_FromDeckIndex +; if has no attack 1 name, return + ld hl, wLoadedCard2Move1Name + ld a, [hli] + or [hl] + jr z, .chosen + +; if Defending Pokemon has enough energy for second attack, choose it + ld e, SECOND_ATTACK + bank1call _CheckIfEnoughEnergiesToMove + jr nc, .chosen +; otherwise if first attack isn't a Pkmn Power, choose it instead. + ld e, FIRST_ATTACK_OR_PKMN_POWER + ld a, [wLoadedCard2Move1Category] + cp POKEMON_POWER + jr nz, .chosen +; if it is a Pkmn Power, choose second attack. + ld e, SECOND_ATTACK +.chosen + ld a, e + call SwapTurn + ret +; 0x2c564 + +; Return in a the PLAY_AREA_* of the non-turn holder's Pokemon card in bench with the lowest (remaining) HP. +; if multiple cards are tied for the lowest HP, the one with the highest PLAY_AREA_* is returned. +GetBenchPokemonWithLowestHP: ; 2c564 (b:4564) + call SwapTurn + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ld c, a + lb de, PLAY_AREA_ARENA, $ff + ld b, d + ld a, DUELVARS_BENCH1_CARD_HP + call GetTurnDuelistVariable + jr .start +; find Play Area location with least amount of HP +.loop_bench + ld a, e + cp [hl] + jr c, .next ; skip if HP is higher + ld e, [hl] + ld d, b + +.next + inc hl +.start + inc b + dec c + jr nz, .loop_bench + + ld a, d + call SwapTurn + ret +; 0x2c588 + +; handles drawing and selection of screen for +; choosing a color (excluding colorless), for use +; of Shift Pkmn Power and Conversion attacks. +; outputs in a the color that was selected or, +; if B was pressed, returns carry. +; input: +; a = Play Area location (PLAY_AREA_*), with: +; bit 7 not set if it's applying to opponent's card +; bit 7 set if it's applying to player's card +; hl = text to be printed in the bottom box +; output: +; a = color that was selected +HandleColorChangeScreen: ; 2c588 (b:4588) + or a + call z, SwapTurn + push af + call .DrawScreen + pop af + call z, SwapTurn + + ld hl, .menu_params + xor a + call InitializeMenuParameters + call EnableLCD + +.loop_input + call DoFrame + call HandleMenuInput + jr nc, .loop_input + cp -1 ; b pressed? + jr z, .set_carry + ld e, a + ld d, $00 + ld hl, ShiftListItemToColor + add hl, de + ld a, [hl] + or a + ret +.set_carry + scf + ret + +.menu_params + db 1, 1 ; cursor x, cursor y + db 2 ; y displacement between items + db MAX_PLAY_AREA_POKEMON ; number of items + db SYM_CURSOR_R ; cursor tile number + db SYM_SPACE ; tile behind cursor + dw $0000 ; function pointer if non-0 +; 0x2c5be + +.DrawScreen: ; 2c5be (b:45be) + push hl + push af + call EmptyScreen + call ZeroObjectPositions + call LoadDuelCardSymbolTiles + +; load card data + pop af + and $7f + ld [wTempPlayAreaLocation_cceb], a + add DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + call LoadCardDataToBuffer1_FromDeckIndex + +; draw card gfx + ld de, v0Tiles1 + $20 tiles ; destination offset of loaded gfx + ld hl, wLoadedCard1Gfx + ld a, [hli] + ld h, [hl] + ld l, a + lb bc, $30, TILE_SIZE + call LoadCardGfx + bank1call SetBGP6OrSGB3ToCardPalette + bank1call FlushAllPalettesOrSendPal23Packet + ld a, $a0 + lb hl, 6, 1 + lb de, 9, 2 + lb bc, 8, 6 + call FillRectangle + bank1call ApplyBGP6OrSGB3ToCardImage + +; print card name and level at the top + ld a, 16 + call CopyCardNameAndLevel + ld [hl], $00 + lb de, 7, 0 + call InitTextPrinting + ld hl, wDefaultText + call ProcessText + +; list all the colors + ld hl, ShiftMenuData + call PlaceTextItems + +; print card's color, resistance and weakness + ld a, [wTempPlayAreaLocation_cceb] + call GetPlayAreaCardColor + inc a + lb bc, 15, 9 + call WriteByteToBGMap0 + ld a, [wTempPlayAreaLocation_cceb] + call GetPlayAreaCardWeakness + lb bc, 15, 10 + bank1call PrintCardPageWeaknessesOrResistances + ld a, [wTempPlayAreaLocation_cceb] + call GetPlayAreaCardResistance + lb bc, 15, 11 + bank1call PrintCardPageWeaknessesOrResistances + + call DrawWideTextBox + +; print list of color names on all list items + lb de, 4, 1 + ldtx hl, ColorListText + call InitTextPrinting_ProcessTextFromID + +; print input hl to text box + lb de, 1, 14 + pop hl + call InitTextPrinting_ProcessTextFromID + +; draw and apply palette to color icons + ld hl, ColorTileAndBGP + lb de, 2, 0 + ld c, NUM_COLORED_TYPES +.loop_colors + ld a, [hli] + push de + push bc + push hl + lb hl, 1, 2 + lb bc, 2, 2 + call FillRectangle + + ld a, [wConsole] + cp CONSOLE_CGB + jr nz, .skip_vram1 + pop hl ; unnecessary + push hl ; unnecessary + call BankswitchVRAM1 + ld a, [hl] + lb hl, 0, 0 + lb bc, 2, 2 + call FillRectangle + call BankswitchVRAM0 + +.skip_vram1 + pop hl + pop bc + pop de + inc hl + inc e + inc e + dec c + jr nz, .loop_colors + ret +; 0x2c686 + +; loads wTxRam2 and wTxRam2_b: +; [wTxRam2] <- wLoadedCard1Name +; [wTxRam2_b] <- input color as text symbol +; input: +; a = type (color) constant +LoadCardNameAndInputColor: ; 2c686 (b:4686) + add a + ld e, a + ld d, $00 + ld hl, ColorToTextSymbol + add hl, de + +; load wTxRam2 with card's name + ld de, wTxRam2 + ld a, [wLoadedCard1Name] + ld [de], a + inc de + ld a, [wLoadedCard1Name + 1] + ld [de], a + +; load wTxRam2_b with ColorToTextSymbol + inc de + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + ret +; 0x2c6a1 + +ShiftMenuData: ; 2c6a1 (b:46a1) + ; x, y, text id + textitem 10, 9, TypeText + textitem 10, 10, WeaknessText + textitem 10, 11, ResistanceText + db $ff + +ColorTileAndBGP: ; 2c6ae (b:46ae) + ; tile, BG + db $E4, $02 + db $E0, $01 + db $EC, $02 + db $E8, $01 + db $F0, $03 + db $F4, $03 + +ShiftListItemToColor: ; 2c6ba (b:46ba) + db GRASS + db FIRE + db WATER + db LIGHTNING + db FIGHTING + db PSYCHIC + +ColorToTextSymbol: ; 2c6c0 (b:46c0) + tx FireSymbolText + tx GrassSymbolText + tx LightningSymbolText + tx WaterSymbolText + tx FightingSymbolText + tx PsychicSymbolText + +DrawSymbolOnPlayAreaCursor: ; 2c6cc (b:46cc) + ld c, a + add a + add c + add 2 + ; a = 3*a + 2 + ld c, a + ld a, b + ld b, 0 + call WriteByteToBGMap0 + ret +; 0x2c6d9 + + INCROM $2c6d9, $2c6e0 + +PlayAreaSelectionMenuParameters: ; 2c6e0 (b:46e0) + db 0, 0 ; cursor x, cursor y + db 3 ; y displacement between items + db MAX_PLAY_AREA_POKEMON ; number of items + db SYM_CURSOR_R ; cursor tile number + db SYM_SPACE ; tile behind cursor + dw $0000 ; function pointer if non-0 +; 0x2c6e8 + +BenchSelectionMenuParameters: ; 2c6e8 (b:46e8) + db 0, 3 ; cursor x, cursor y + db 3 ; y displacement between items + db MAX_PLAY_AREA_POKEMON ; number of items + db SYM_CURSOR_R ; cursor tile number + db SYM_SPACE ; tile behind cursor + dw $0000 ; function pointer if non-0 +; 0x2c6f0 SpitPoison_AIEffect: ; 2c6f0 (b:46f0) - ld a, 5 + ld a, 10 / 2 lb de, 0, 10 - jp Func_2c0fb + jp SetExpectedAIDamage ; If heads, defending Pokemon becomes poisoned SpitPoison_Poison50PercentEffect: ; 2c6f8 (b:46f8) @@ -476,10 +1466,9 @@ SpitPoison_Poison50PercentEffect: ; 2c6f8 (b:46f8) call SetNoEffectFromStatus ret -; outputs in hTemp_ffa0 the result of the coin toss -; (0 = tails, 1 = heads) and, in case it was heads, -; stores in hTempPlayAreaLocation_ffa1 the location -; of the Bench Pokemon that was selected for switch. +; outputs in hTemp_ffa0 the result of the coin toss (0 = tails, 1 = heads). +; in case it was heads, stores in hTempPlayAreaLocation_ffa1 +; the PLAY_AREA_* location of the Bench Pokemon that was selected for switch. TerrorStrike_50PercentSelectSwitchPokemon: ; 2c70a (b:470a) xor a ldh [hTemp_ffa0], a @@ -490,8 +1479,7 @@ TerrorStrike_50PercentSelectSwitchPokemon: ; 2c70a (b:470a) cp 2 ret c -; toss coin and store whether it was tails (0) -; or heads (1) in hTemp_ffa0 +; toss coin and store whether it was tails (0) or heads (1) in hTemp_ffa0. ; return if it was tails. ldtx de, IfHeadsChangeOpponentsActivePokemonText call Func_2c08a @@ -503,8 +1491,8 @@ TerrorStrike_50PercentSelectSwitchPokemon: ; 2c70a (b:470a) ldh [hTempPlayAreaLocation_ffa1], a ret -; if coin toss was heads and it's possible, -; switch Defending Pokemon +; if coin toss at hTemp_ffa0 was heads and it's possible, +; switch the Defending Pokemon TerrorStrike_SwitchDefendingPokemon: ; 2c726 (b:4726) ldh a, [hTemp_ffa0] or a @@ -516,15 +1504,59 @@ TerrorStrike_SwitchDefendingPokemon: ; 2c726 (b:4726) PoisonFang_AIEffect: ; 2c730 (b:4730) ld a, 10 lb de, 10, 10 - jp Func_2c0d4 + jp UpdateExpectedAIDamage_AccountForPoison WeepinbellPoisonPowder_AIEffect: ; 2c738 (b:4738) ld a, 5 lb de, 0, 10 - jp Func_2c0d4 + jp UpdateExpectedAIDamage_AccountForPoison ; 0x2c740 - INCROM $2c740, $2c77e +; return carry if there are no Pokemon cards in the non-turn holder's bench +VictreebelLure_AssertPokemonInBench: ; 2c740 (b:4740) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetNonTurnDuelistVariable + ldtx hl, EffectNoPokemonOnTheBenchText + cp 2 + ret +; 0x2c74b + +; return in hTempPlayAreaLocation_ffa1 the PLAY_AREA_* location +; of the Bench Pokemon that was selected for switch +VictreebelLure_SelectSwitchPokemon: ; 2c74b (b:474b) + ldtx hl, SelectPkmnOnBenchToSwitchWithActiveText + call DrawWideTextBox_WaitForInput + call SwapTurn + bank1call HasAlivePokemonInBench +.select_pokemon + bank1call OpenPlayAreaScreenForSelection + jr c, .select_pokemon + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + call SwapTurn + ret +; 0x2c764 + +; Return in hTemp_ffa0 the PLAY_AREA_* of the non-turn holder's Pokemon card in bench with the lowest (remaining) HP. +; if multiple cards are tied for the lowest HP, the one with the highest PLAY_AREA_* is returned. +VictreebelLure_GetBenchPokemonWithLowestHP: ; 2c764 (b:4764) + call GetBenchPokemonWithLowestHP + ldh [hTemp_ffa0], a + ret +; 0x2c76a + +; Defending Pokemon is swapped out for the one with the PLAY_AREA_* at hTemp_ffa0 +; unless Mew's Neutralizing Shield or Haunter's Transparency prevents it. +VictreebelLure_SwitchDefendingPokemon: ; 2c76a (b:476a) + call SwapTurn + ldh a, [hTemp_ffa0] + ld e, a + call HandleNShieldAndTransparency + call nc, SwapArenaWithBenchPokemon + call SwapTurn + xor a + ld [wDuelDisplayedScreen], a + ret ; If heads, defending Pokemon can't retreat next turn AcidEffect: ; 2c77e (b:477e) @@ -538,7 +1570,7 @@ AcidEffect: ; 2c77e (b:477e) GloomPoisonPowder_AIEffect: ; 2c78b (b:478b) ld a, 10 lb de, 10, 10 - jp Func_2c0d4 + jp UpdateExpectedAIDamage_AccountForPoison ; Defending Pokemon and user become confused FoulOdorEffect: ; 2c793 (b:4793) @@ -562,10 +1594,26 @@ KakunaStiffenEffect: ; 2c7a0 (b:47a0) KakunaPoisonPowder_AIEffect: ; 2c7b4 (b:47b4) ld a, 5 lb de, 0, 10 - jp Func_2c0d4 + jp UpdateExpectedAIDamage_AccountForPoison ; 0x2c7bc - INCROM $2c7bc, $2c7d0 +GolbatLeechLifeEffect: ; 2c7bc (b:47bc) + ld hl, wDealtDamage + ld e, [hl] + inc hl ; wDamageEffectiveness + ld d, [hl] + call ApplyAndAnimateHPRecovery + ret +; 0x2c7c6 + +VenonatLeechLifeEffect: ; 2c7c6 (b:47c6) + ld hl, wDealtDamage + ld e, [hl] + inc hl ; wDamageEffectiveness + ld d, [hl] + call ApplyAndAnimateHPRecovery + ret +; 0x2c7d0 ; During your next turn, double damage SwordsDanceEffect: ; 2c7d0 (b:47d0) @@ -583,12 +1631,19 @@ ZubatSupersonicEffect: ; 2c7dc (b:47dc) ret ; 0x2c7e3 - INCROM $2c7e3, $2c7ed +ZubatLeechLifeEffect: ; 2c7e3 (b:47e3) + ld hl, wDealtDamage + ld e, [hl] + inc hl + ld d, [hl] + call ApplyAndAnimateHPRecovery + ret +; 0x2c7ed Twineedle_AIEffect: ; 2c7ed (b:47ed) - ld a, 30 + ld a, 60 / 2 lb de, 0, 60 - jp Func_2c0fb + jp SetExpectedAIDamage ; Flip 2 coins; deal 30x number of heads Twineedle_MultiplierEffect: ; 2c7f5 (b:47f5) @@ -601,16 +1656,30 @@ Twineedle_MultiplierEffect: ; 2c7f5 (b:47f5) add a add e call ATimes10 - call StoreDamageInfo + call SetDefiniteDamage ret ; 0x2c80d - INCROM $2c80d, $2c822 +BeedrillPoisonSting_AIEffect: ; 2c80d (b:480d) + ld a, 5 + lb de, 0, 10 + jp UpdateExpectedAIDamage_AccountForPoison +; 0x2c815 + +ExeggcuteLeechSeedEffect: ; 2c815 (b:4815) + ld hl, wDealtDamage + ld a, [hli] + or a + ret z ; return if no damage dealt + ld de, 10 + call ApplyAndAnimateHPRecovery + ret +; 0x2c822 FoulGas_AIEffect: ; 2c822 (b:4822) ld a, 5 lb de, 0, 10 - jp Func_2c0e9 + jp UpdateExpectedAIDamage ; If heads, defending Pokemon becomes poisoned. If tails, defending Pokemon becomes confused FoulGas_PoisonOrConfusionEffect: ; 2c82a (b:482a) @@ -632,7 +1701,154 @@ MetapodStiffenEffect: ; 2c836 (b:4836) ret ; 0x2c84a - INCROM $2c84a, $2c925 +; returns carry if no cards in Deck or if +; Play Area is full already. +Sprout_CheckDeckAndPlayArea: ; 2c84a (b:484a) + call CheckIfDeckIsEmpty + ret c ; return if no cards in deck + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ldtx hl, NoSpaceOnTheBenchText + cp MAX_PLAY_AREA_POKEMON + ccf + ret +; 0x2c85a + +Sprout_PlayerSelectEffect: ; 2c85a (b:485a) + ld a, $ff + ldh [hTemp_ffa0], a + + call CreateDeckCardList + ldtx hl, ChooseAnOddishFromDeckText + ldtx bc, OddishText + lb de, SEARCHEFFECT_CARD_ID, ODDISH + call LookForCardsInDeck + ret c + +; draw Deck list interface and print text + bank1call Func_5591 + ldtx hl, ChooseAnOddishText + ldtx de, DuelistDeckText + bank1call SetCardListHeaderText + +.loop + bank1call DisplayCardList + jr c, .pressed_b + call GetCardIDFromDeckIndex + ld bc, ODDISH + call CompareDEtoBC + jr nz, .play_sfx + +; Oddish was selected + ldh a, [hTempCardIndex_ff98] + ldh [hTemp_ffa0], a + or a + ret + +.play_sfx + ; play SFX and loop back + call Func_3794 + jr .loop + +.pressed_b +; figure if Player can exit the screen without selecting, +; that is, if the Deck has no Oddish card. + ld a, DUELVARS_CARD_LOCATIONS + call GetTurnDuelistVariable +.loop_b_press + ld a, [hl] + cp CARD_LOCATION_DECK + jr nz, .next + ld a, l + call GetCardIDFromDeckIndex + ld bc, ODDISH + call CompareDEtoBC + jr z, .play_sfx ; found Oddish, go back to top loop +.next + inc l + ld a, l + cp DECK_SIZE + jr c, .loop_b_press + +; no Oddish in Deck, can safely exit screen + ld a, $ff + ldh [hTemp_ffa0], a + or a + ret +; 0x2c8b7 + +Sprout_AISelectEffect: ; 2c8b7 (b:48b7) + call CreateDeckCardList + ld hl, wDuelTempList +.loop_deck + ld a, [hli] + ldh [hTemp_ffa0], a + cp $ff + ret z ; no Oddish + call GetCardIDFromDeckIndex + ld a, e + cp ODDISH + jr nz, .loop_deck + ret ; Oddish found +; 0x2c8cc + +Sprout_PutInPlayAreaEffect: ; 2c8cc (b:48cc) + ldh a, [hTemp_ffa0] + cp $ff + jr z, .shuffle + call SearchCardInDeckAndAddToHand + call AddCardToHand + call PutHandPokemonCardInPlayArea + call IsPlayerTurn + jr c, .shuffle + ; display card on screen + ldh a, [hTemp_ffa0] + ldtx hl, PlacedOnTheBenchText + bank1call DisplayCardDetailScreen +.shuffle + call Func_2c0bd + ret +; 0x2c8ec + +; returns carry if no Pokemon on Bench +Teleport_CheckBench: ; 2c8ec (b:48ec) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ldtx hl, ThereAreNoPokemonOnBenchText + cp 2 + ret +; 0x2c8f7 + +Teleport_PlayerSelectEffect: ; 2c8f7 (b:48f7) + ldtx hl, SelectPkmnOnBenchToSwitchWithActiveText + call DrawWideTextBox_WaitForInput + bank1call HasAlivePokemonInBench + ld a, $01 + ld [wcbd4], a +.loop + bank1call OpenPlayAreaScreenForSelection + jr c, .loop + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + ret +; 0x2c90f + +Teleport_AISelectEffect: ; 2c90f (b:490f) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + call Random + ldh [hTemp_ffa0], a + ret +; 0x2c91a + +Teleport_SwitchEffect: ; 2c91a (b:491a) + ldh a, [hTemp_ffa0] + ld e, a + call SwapArenaWithBenchPokemon + xor a + ld [wDuelDisplayedScreen], a + ret +; 0x2c925 BigEggsplosion_AIEffect: ; 2c925 (b:4925) ldh a, [hTempPlayAreaLocation_ff9d] @@ -681,9 +1897,9 @@ SetDamageToATimes20: ; 2c958 (b:4958) ret Thrash_AIEffect: ; 2c96b (b:496b) - ld a, 35 + ld a, (30 + 40) / 2 lb de, 30, 40 - jp Func_2c0fb + jp SetExpectedAIDamage ; If heads 10 more damage; if tails, 10 damage to itself Thrash_ModifierEffect: ; 2c973 (b:4973) @@ -695,28 +1911,442 @@ Thrash_ModifierEffect: ; 2c973 (b:4973) call AddToDamage ret -Func_2c982: ; 2c982 (b:4982) +Thrash_LowRecoilEffect: ; 2c982 (b:4982) ldh a, [hTemp_ffa0] or a ret nz ld a, 10 - call Func_1955 + call DealRecoilDamageToSelf ret Toxic_AIEffect: ; 2c98c (b:498c) ld a, 20 lb de, 20, 20 - jp Func_2c0e9 + jp UpdateExpectedAIDamage -; Defending Pokémon becomes poisoned, but takes 20 damage (double poisoned) +; Defending Pokémon becomes double poisoned (takes 20 damage per turn rather than 10) Toxic_DoublePoisonEffect: ; 2c994 (b:4994) call DoublePoisonEffect ret ; 0x2c998 - INCROM $2c998, $2cbfb +BoyfriendsEffect: ; 2c998 (b:4998) + ld a, DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + ld c, PLAY_AREA_ARENA +.loop + ld a, [hl] + cp $ff + jr z, .done + call GetCardIDFromDeckIndex + ld a, e + cp NIDOKING + jr nz, .next + ld a, d + cp $00 ; why check d? Card IDs are only 1 byte long + jr nz, .next + inc c +.next + inc hl + jr .loop +.done +; c holds number of Nidoking found in Play Area + ld a, c + add a + call ATimes10 + call AddToDamage ; adds 2 * 10 * c + ret +; 0x2c9be + +NidoranFFurySwipes_AIEffect: ; 2c9be (b:49be) + ld a, 30 / 2 + lb de, 0, 30 + jp SetExpectedAIDamage +; 0x2c9c6 + +NidoranFFurySwipes_MultiplierEffect: ; 2c9c6 (b:49c6) + ld hl, 10 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsXDamageText + ld a, 3 + call TossCoinATimes_BankB + call ATimes10 + call SetDefiniteDamage + ret +; 0x2c9db + +NidoranFCallForFamily_CheckDeckAndPlayArea: ; 2c9db (b:49db) + call CheckIfDeckIsEmpty + ret c ; return if no cards in deck + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ldtx hl, NoSpaceOnTheBenchText + cp MAX_PLAY_AREA_POKEMON + ccf + ret +; 0x2c9eb + +NidoranFCallForFamily_PlayerSelectEffect: ; 2c9eb (b:49eb) + ld a, $ff + ldh [hTemp_ffa0], a + + call CreateDeckCardList + ldtx hl, ChooseNidoranFromDeckText + ldtx bc, NidoranMNidoranFText + lb de, SEARCHEFFECT_NIDORAN, $00 + call LookForCardsInDeck + ret c + +; draw Deck list interface and print text + bank1call Func_5591 + ldtx hl, ChooseNidoranText + ldtx de, DuelistDeckText + bank1call SetCardListHeaderText + +.loop + bank1call DisplayCardList + jr c, .pressed_b + call GetCardIDFromDeckIndex + ld bc, NIDORANF + call CompareDEtoBC + jr z, .selected_nidoran + ld bc, NIDORANM + call CompareDEtoBC + jr nz, .loop ; .play_sfx would be more appropriate here + +.selected_nidoran + ldh a, [hTempCardIndex_ff98] + ldh [hTemp_ffa0], a + or a + ret + +.play_sfx + ; play SFX and loop back + call Func_3794 + jr .loop + +.pressed_b +; figure if Player can exit the screen without selecting, +; that is, if the Deck has no NidoranF or NidoranM card. + ld a, DUELVARS_CARD_LOCATIONS + call GetTurnDuelistVariable +.loop_b_press + ld a, [hl] + cp CARD_LOCATION_DECK + jr nz, .next + ld a, l + call GetCardIDFromDeckIndex + ld bc, NIDORANF + call CompareDEtoBC + jr z, .play_sfx ; found, go back to top loop + ld bc, NIDORANM + jr z, .play_sfx ; found, go back to top loop +.next + inc l + ld a, l + cp DECK_SIZE + jr c, .loop_b_press + +; no Nidoran in Deck, can safely exit screen + ld a, $ff + ldh [hTemp_ffa0], a + or a + ret +; 0x2ca55 + +NidoranFCallForFamily_AISelectEffect: ; 2ca55 (b:4a55) + call CreateDeckCardList + ld hl, wDuelTempList +.loop_deck + ld a, [hli] + ldh [hTemp_ffa0], a + cp $ff + ret z ; none found + call GetCardIDFromDeckIndex + ld a, e + cp NIDORANF + jr z, .found + cp NIDORANM + jr nz, .loop_deck +.found + ret +; 0x2ca6e + +NidoranFCallForFamily_PutInPlayAreaEffect: ; 2ca6e (b:4a6e) + ldh a, [hTemp_ffa0] + cp $ff + jr z, .shuffle + call SearchCardInDeckAndAddToHand + call AddCardToHand + call PutHandPokemonCardInPlayArea + call IsPlayerTurn + jr c, .shuffle + ; display card on screen + ldh a, [hTemp_ffa0] + ldtx hl, PlacedOnTheBenchText + bank1call DisplayCardDetailScreen +.shuffle + call Func_2c0bd + ret +; 0x2ca8e + +HornHazard_AIEffect: ; 2ca8e (b:4a8e) + ld a, 30 / 2 + lb de, 0, 30 + jp SetExpectedAIDamage +; 0x2ca96 + +HornHazard_NoDamage50PercentEffect: ; 2ca96 (b:4a96) + ldtx de, DamageCheckIfTailsNoDamageText + call TossCoin_BankB + jr c, .heads + xor a + call SetDefiniteDamage + call SetWasUnsuccessful + ret +.heads + ld a, $01 + ld [wLoadedMoveAnimation], a + ret +; 0x2caac + +NidorinaSupersonicEffect: ; 2caac (b:4aac) + call Confusion50PercentEffect + call nc, SetNoEffectFromStatus + ret +; 0x2cab3 + +NidorinaDoubleKick_AIEffect: ; 2cab3 (b:4ab3) + ld a, 60 / 2 + lb de, 0, 60 + jp SetExpectedAIDamage +; 0x2cabb + +NidorinaDoubleKick_MultiplierEffect: ; 2cabb (b:4abb) + ld hl, 30 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsXDamageText + ld a, 2 + call TossCoinATimes_BankB + ld e, a + add a + add e + call ATimes10 + call SetDefiniteDamage + ret +; 0x2cad3 + +NidorinoDoubleKick_AIEffect: ; 2cad3 (b:4ad3) + ld a, 60 / 2 + lb de, 0, 60 + jp SetExpectedAIDamage +; 0x2cadb + +NidorinoDoubleKick_MultiplierEffect: ; 2cabb (b:4abb) + ld hl, 30 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsXDamageText + ld a, 2 + call TossCoinATimes_BankB + ld e, a + add a + add e + call ATimes10 + call SetDefiniteDamage + ret +; 0x2caf3 + +ButterfreeWhirlwind_CheckBench: ; 2caf3 (b:4af3) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetNonTurnDuelistVariable + cp 2 + jr nc, .has_bench + ; no bench, do not do effect + ld a, $ff + ldh [hTemp_ffa0], a + ret +.has_bench + call DuelistSelectForcedSwitch + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + ret +; 0x2cb09 + +ButterfreeWhirlwind_SwitchEffect: ; 2cb09 (b:4b09) + ldh a, [hTemp_ffa0] + call HandleSwitchDefendingPokemonEffect + ret +; 0x2cb0f + +ButterfreeMegaDrainEffect: ; 2cb0f (b:4b0f) + ld hl, wDealtDamage + ld a, [hli] + ld h, [hl] + ld l, a + srl h + rr l + bit 0, l + jr z, .rounded + ; round up to nearest 10 + ld de, 10 / 2 + add hl, de +.rounded + ld e, l + ld d, h + call ApplyAndAnimateHPRecovery + ret +; 0x2cb27 + +WeedlePoisonSting_AIEffect: ; 2cb27 (b:4b27) + ld a, 5 + lb de, 0, 10 + jp UpdateExpectedAIDamage_AccountForPoison +; 0x2cb2f + +IvysaurPoisonPowder_AIEffect: ; 2cb2f (b:4b2f) + ld a, 10 + lb de, 10, 10 + jp UpdateExpectedAIDamage_AccountForPoison +; 0x2cb37 + +BulbasaurLeechSeedEffect: ; 2cb37 (b:4b37) + ld hl, wDealtDamage + ld a, [hli] + or [hl] + ret z ; return if no damage dealt + lb de, 0, 10 + call ApplyAndAnimateHPRecovery + ret +; 0x2cb44 + +; returns carry if no Grass Energy in Play Area +EnergyTrans_CheckPlayArea: ; 2cb44 (b:4b44) + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + ldh a, [hTempPlayAreaLocation_ff9d] + call CheckCannotUseDueToStatus_OnlyToxicGasIfANon0 + ret c ; cannot use Pkmn Power + +; search in Play Area for at least 1 Grass Energy type + ld a, DUELVARS_CARD_LOCATIONS + call GetTurnDuelistVariable +.loop_deck + ld a, [hl] + and CARD_LOCATION_PLAY_AREA + jr z, .next + push hl + ld a, l + call GetCardIDFromDeckIndex + call GetCardType + pop hl + cp TYPE_ENERGY_GRASS + ret z +.next + inc l + ld a, l + cp DECK_SIZE + jr c, .loop_deck + +; none found + ldtx hl, NoGrassEnergyText + scf + ret +; 0x2cb6f + +EnergyTrans_PrintProcedure: ; 2cb6f (b:4b6f) + ldtx hl, ProcedureForEnergyTransferText + bank1call DrawWholeScreenTextBox + or a + ret +; 0x2cb77 + +EnergyTrans_TransferEffect: ; 2cb77 (b:4b77) + ld a, DUELVARS_DUELIST_TYPE + call GetTurnDuelistVariable + cp DUELIST_TYPE_PLAYER + jr z, .player +; not player + bank1call Func_61a1 + bank1call PrintPlayAreaCardList_EnableLCD + ret + +.player + xor a + ldh [hCurSelectionItem], a + bank1call Func_61a1 -Func_2cbfb: ; 2cbfb (b:4bfb) +.draw_play_area + bank1call PrintPlayAreaCardList_EnableLCD + push af + ldh a, [hCurSelectionItem] + ld hl, PlayAreaSelectionMenuParameters + call InitializeMenuParameters + pop af + ld [wNumMenuItems], a + +; handle the action of taking a Grass Energy card +.loop_input_take + call DoFrame + call HandleMenuInput + jr nc, .loop_input_take + cp -1 ; b press? + ret z + +; a press + ldh [hAIPkmnPowerEffectParam], a + ldh [hCurSelectionItem], a + call CheckIfCardHasGrassEnergyAttached + jr c, .play_sfx ; no Grass attached + + ldh [hAIEnergyTransEnergyCard], a + ldh a, [hAIEnergyTransEnergyCard] ; useless + ; temporarily take card away to draw Play Area + call AddCardToHand + bank1call PrintPlayAreaCardList_EnableLCD + ldh a, [hAIPkmnPowerEffectParam] + ld e, a + ldh a, [hAIEnergyTransEnergyCard] + ; give card back + call PutHandCardInPlayArea + + ; draw Grass symbol near cursor + ldh a, [hAIPkmnPowerEffectParam] + ld b, SYM_GRASS + call DrawSymbolOnPlayAreaCursor + +; handle the action of placing a Grass Energy card +.loop_input_put + call DoFrame + call HandleMenuInput + jr nc, .loop_input_put + cp -1 ; b press? + jr z, .remove_symbol + +; a press + ldh [hCurSelectionItem], a + ldh [hAIEnergyTransPlayAreaLocation], a + ld a, OPPACTION_6B15 + call SetOppAction_SerialSendDuelData + ldh a, [hAIEnergyTransPlayAreaLocation] + ld e, a + ldh a, [hAIEnergyTransEnergyCard] + ; give card being held to this Pokemon + call AddCardToHand + call PutHandCardInPlayArea + +.remove_symbol + ldh a, [hAIPkmnPowerEffectParam] + ld b, SYM_SPACE + call DrawSymbolOnPlayAreaCursor + call EraseCursor + jr .draw_play_area + +.play_sfx + call Func_3794 + jr .loop_input_take +; 0x2cbfb + +EnergyTrans_AIEffect: ; 2cbfb (b:4bfb) ldh a, [hAIEnergyTransPlayAreaLocation] ld e, a ldh a, [hAIEnergyTransEnergyCard] @@ -726,34 +2356,9265 @@ Func_2cbfb: ; 2cbfb (b:4bfb) ret ; 0x2cc0a - INCROM $2cc0a, $2f4e1 +; returns carry if no Grass Energy cards +; attached to card in Play Area location of a. +; input: +; a = PLAY_AREA_* of location to check +CheckIfCardHasGrassEnergyAttached: ; 2cc0a (b:4c0a) + or CARD_LOCATION_PLAY_AREA + ld e, a -ImposterProfessorOakEffect: ; 2f4e1 (b:74e1) + ld a, DUELVARS_CARD_LOCATIONS + call GetTurnDuelistVariable +.loop + ld a, [hl] + cp e + jr nz, .next + push de + push hl + ld a, l + call GetCardIDFromDeckIndex + call GetCardType + pop hl + pop de + cp TYPE_ENERGY_GRASS + jr z, .no_carry +.next + inc l + ld a, l + cp DECK_SIZE + jr c, .loop + scf + ret +.no_carry + ld a, l + or a + ret +; 0x2cc30 + +GrimerMinimizeEffect: ; 2cc30 (b:4c30) + ld a, SUBSTATUS1_REDUCE_BY_20 + call ApplySubstatus1ToDefendingCard + ret +; 0x2cc36 + +ToxicGasEffect: ; 2cc36 (b:4c36) + scf + ret +; 0x2cc38 + +Sludge_AIEffect: ; 2cc38 (b:4c38) + ld a, 5 + lb de, 0, 10 + jp UpdateExpectedAIDamage_AccountForPoison +; 0x2cc40 + +; returns carry if no cards in Deck +; or if Play Area is full already. +BellsproutCallForFamily_CheckDeckAndPlayArea: ; 2cc40 (b:4c40) + call CheckIfDeckIsEmpty + ret c ; return if no cards in deck + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ldtx hl, NoSpaceOnTheBenchText + cp MAX_PLAY_AREA_POKEMON + ccf + ret +; 0x2cc50 + +BellsproutCallForFamily_PlayerSelectEffect: ; 2cc50 (b:4c50) + ld a, $ff + ldh [hTemp_ffa0], a + + call CreateDeckCardList + ldtx hl, ChooseABellsproutFromDeckText + ldtx bc, BellsproutText + lb de, SEARCHEFFECT_CARD_ID, BELLSPROUT + call LookForCardsInDeck + ret c + +; draw Deck list interface and print text + bank1call Func_5591 + ldtx hl, ChooseABellsproutText + ldtx de, DuelistDeckText + bank1call SetCardListHeaderText + +.loop + bank1call DisplayCardList + jr c, .pressed_b + call GetCardIDFromDeckIndex + ld bc, BELLSPROUT + call CompareDEtoBC + jr nz, .play_sfx + +; Bellsprout was selected + ldh a, [hTempCardIndex_ff98] + ldh [hTemp_ffa0], a + or a + ret + +.play_sfx + ; play SFX and loop back + call Func_3794 + jr .loop + +.pressed_b +; figure if Player can exit the screen without selecting, +; that is, if the Deck has no Bellsprout card. + ld a, DUELVARS_CARD_LOCATIONS + call GetTurnDuelistVariable +.loop_b_press + ld a, [hl] + cp CARD_LOCATION_DECK + jr nz, .next + ld a, l + call GetCardIDFromDeckIndex + ld bc, BELLSPROUT + call CompareDEtoBC + jr z, .play_sfx ; found Bellsprout, go back to top loop +.next + inc l + ld a, l + cp DECK_SIZE + jr c, .loop_b_press + +; no Bellsprout in Deck, can safely exit screen + ld a, $ff + ldh [hTemp_ffa0], a + or a + ret +; 0x2ccad + +BellsproutCallForFamily_AISelectEffect: ; 2ccad (b:4cad) + call CreateDeckCardList + ld hl, wDuelTempList +.loop_deck + ld a, [hli] + ldh [hTemp_ffa0], a + cp $ff + ret z ; no Bellsprout + call GetCardIDFromDeckIndex + ld a, e + cp BELLSPROUT + jr nz, .loop_deck + ret ; Bellsprout found +; 0x2ccc2 + +BellsproutCallForFamily_PutInPlayAreaEffect: ; 2ccc2 (b:4cc2) + ldh a, [hTemp_ffa0] + cp $ff + jr z, .shuffle + call SearchCardInDeckAndAddToHand + call AddCardToHand + call PutHandPokemonCardInPlayArea + call IsPlayerTurn + jr c, .shuffle + ldh a, [hTemp_ffa0] + ldtx hl, PlacedOnTheBenchText + bank1call DisplayCardDetailScreen +.shuffle + call Func_2c0bd + ret +; 0x2cce2 + +WeezingSmog_AIEffect: ; 2cce2 (b:4ce2) + ld a, 5 + lb de, 0, 10 + jp UpdateExpectedAIDamage_AccountForPoison +; 0x2ccea + +WeezingSelfdestructEffect: ; 2ccea (b:4cea) + ld a, 60 + call DealRecoilDamageToSelf + ld a, $01 + ld [wIsDamageToSelf], a + ld a, 10 + call DealDamageToAllBenchedPokemon + call SwapTurn + xor a + ld [wIsDamageToSelf], a + ld a, 10 + call DealDamageToAllBenchedPokemon + call SwapTurn + ret +; 0x2cd09 + +Shift_OncePerTurnCheck: ; 2cd09 (b:4d09) + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + add DUELVARS_ARENA_CARD_FLAGS + call GetTurnDuelistVariable + and USED_PKMN_POWER_THIS_TURN + jr nz, .already_used + ldh a, [hTempPlayAreaLocation_ff9d] + call CheckCannotUseDueToStatus_OnlyToxicGasIfANon0 + ret +.already_used + ldtx hl, OnlyOncePerTurnText + scf + ret +; 0x2cd21 + +Shift_PlayerSelectEffect: ; 2cd21 (b:4d21) + ldtx hl, ChoosePokemonWishToColorChangeText + ldh a, [hTemp_ffa0] + or $80 + call HandleColorChangeScreen + ldh [hAIPkmnPowerEffectParam], a + ret c ; cancelled + +; check whether the color selected is valid + ; look in Turn Duelist's Play Area + call .CheckColorInPlayArea + ret nc + ; look in NonTurn Duelist's Play Area + call SwapTurn + call .CheckColorInPlayArea + call SwapTurn + ret nc + ; not found in either Duelist's Play Area + ldtx hl, UnableToSelectText + call DrawWideTextBox_WaitForInput + jr Shift_PlayerSelectEffect ; loop back to start +; 0x2cd44 + +; checks in input color in a exists in Turn Duelist's Play Area +; returns carry if not found. +.CheckColorInPlayArea: ; 2cd44 (b:4d44) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ld c, a + ld b, PLAY_AREA_ARENA +.loop_play_area + push bc + ld a, b + call GetPlayAreaCardColor + pop bc + ld hl, hAIPkmnPowerEffectParam + cp [hl] + ret z ; found + inc b + dec c + jr nz, .loop_play_area + ; not found + scf + ret +; 0x2cd5d + +Shift_ChangeColorEffect: ; 2cd5d (b:4d5d) + ldh a, [hTemp_ffa0] + add DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + call LoadCardDataToBuffer1_FromDeckIndex + + ldh a, [hTemp_ffa0] + add DUELVARS_ARENA_CARD_FLAGS + call GetTurnDuelistVariable + set USED_PKMN_POWER_THIS_TURN_F, [hl] + + ldh a, [hTemp_ffa0] + add DUELVARS_ARENA_CARD_CHANGED_TYPE + ld l, a + ldh a, [hAIPkmnPowerEffectParam] + or HAS_CHANGED_COLOR + ld [hl], a + call LoadCardNameAndInputColor + ldtx hl, ChangedTheColorOfText + call DrawWideTextBox_WaitForInput + ret +; 0x2cd84 + +VenomPowder_AIEffect: ; 2cd84 (b:4d84) + ld a, 5 + lb de, 0, 10 + jp UpdateExpectedAIDamage +; 0x2cd8c + +VenomPowder_PoisonConfusion50PercentEffect: ; 2cd8c (b:4d8c) + ldtx de, VenomPowderCheckText + call TossCoin_BankB + ret nc ; return if tails + +; heads + call PoisonEffect + call ConfusionEffect + ret c + ld a, CONFUSED | POISONED + ld [wNoEffectFromWhichStatus], a + ret +; 0x2cda0 + +TangelaPoisonPowder_AIEffect: ; 2cda0 (b:4da0) + ld a, 5 + lb de, 0, 10 + jp UpdateExpectedAIDamage_AccountForPoison +; 0x2cda8 + +Heal_OncePerTurnCheck: ; 2cda8 (b:4da8) + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + add DUELVARS_ARENA_CARD_FLAGS + call GetTurnDuelistVariable + and USED_PKMN_POWER_THIS_TURN + jr nz, .already_used + + call CheckIfPlayAreaHasAnyDamage + ldtx hl, NoPokemonWithDamageCountersText + ret c ; no damage counters to heal + + ldh a, [hTempPlayAreaLocation_ff9d] + call CheckCannotUseDueToStatus_OnlyToxicGasIfANon0 + ret + +.already_used + ldtx hl, OnlyOncePerTurnText + scf + ret +; 0x2cdc7 + +Heal_RemoveDamageEffect: ; 2cdc7 (b:4dc7) + ldtx de, IfHeadsHealIsSuccessfulText + call TossCoin_BankB + ldh [hAIPkmnPowerEffectParam], a + jr nc, .done + + ld a, DUELVARS_DUELIST_TYPE + call GetTurnDuelistVariable + cp DUELIST_TYPE_LINK_OPP + jr z, .link_opp + and DUELIST_TYPE_AI_OPP + jr nz, .done + +; player + ldtx hl, ChoosePkmnToRemoveDamageCounterText + call DrawWideTextBox_WaitForInput + bank1call HasAlivePokemonInPlayArea +.loop_input + bank1call OpenPlayAreaScreenForSelection + jr c, .loop_input + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hPlayAreaEffectTarget], a + ld e, a + call GetCardDamageAndMaxHP + or a + jr z, .loop_input ; has no damage counters + ldh a, [hTempPlayAreaLocation_ff9d] + call SerialSend8Bytes + jr .done + +.link_opp + call SerialRecv8Bytes + ldh [hPlayAreaEffectTarget], a + ; fallthrough + +.done +; flag Pkmn Power as being used regardless of coin outcome + ldh a, [hTemp_ffa0] + add DUELVARS_ARENA_CARD_FLAGS + call GetTurnDuelistVariable + set USED_PKMN_POWER_THIS_TURN_F, [hl] + ldh a, [hAIPkmnPowerEffectParam] + or a + ret z ; return if coin was tails + + ldh a, [hPlayAreaEffectTarget] + add DUELVARS_ARENA_CARD_HP + call GetTurnDuelistVariable + add 10 ; remove 1 damage counter + ld [hl], a + ldh a, [hPlayAreaEffectTarget] + call Func_2c10b + call ExchangeRNG + ret +; 0x2ce23 + +PetalDance_AIEffect: ; 2ce23 (b:4e23) + ld a, 120 / 2 + lb de, 0, 120 + jp SetExpectedAIDamage +; 0x2ce2b + +PetalDance_MultiplierEffect: ; 2ce2b (b:4e2b) + ld hl, 40 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsXDamageText + ld a, 3 + call TossCoinATimes_BankB + add a + add a + call ATimes10 + ; a = 4 * 10 * heads + call SetDefiniteDamage + call SwapTurn + call ConfusionEffect + call SwapTurn + ret +; 0x2ce4b + +PoisonWhip_AIEffect: ; 2ce4b (b:4e4b) + ld a, 10 + lb de, 10, 10 + jp UpdateExpectedAIDamage_AccountForPoison +; 0x2ce53 + +SolarPower_CheckUse: ; 2ce53 (b:4e53) + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + add DUELVARS_ARENA_CARD_FLAGS + call GetTurnDuelistVariable + and USED_PKMN_POWER_THIS_TURN + jr nz, .already_used + + ldh a, [hTempPlayAreaLocation_ff9d] + call CheckCannotUseDueToStatus_OnlyToxicGasIfANon0 + ret c ; can't use PKMN due to status or Toxic Gas + +; return carry if none of the Arena cards have status conditions + ld a, DUELVARS_ARENA_CARD_STATUS + call GetTurnDuelistVariable + or a + jr nz, .has_status + ld a, DUELVARS_ARENA_CARD_STATUS + call GetNonTurnDuelistVariable + or a + jr z, .no_status +.has_status + or a + ret +.already_used + ldtx hl, OnlyOncePerTurnText + scf + ret +.no_status + ldtx hl, NotAffectedByPoisonSleepParalysisOrConfusionText + scf + ret +; 0x2ce82 + +SolarPower_RemoveStatusEffect: ; 2ce82 (b:4e82) + ld a, $8e + ld [wLoadedMoveAnimation], a + bank1call Func_7415 + ldh a, [hTempPlayAreaLocation_ff9d] + ld b, a + ld c, $00 + ldh a, [hWhoseTurn] + ld h, a + bank1call PlayMoveAnimation + bank1call WaitMoveAnimation + + ldh a, [hTemp_ffa0] + add DUELVARS_ARENA_CARD_FLAGS + call GetTurnDuelistVariable + set USED_PKMN_POWER_THIS_TURN_F, [hl] + ld l, DUELVARS_ARENA_CARD_STATUS + ld [hl], NO_STATUS + + ld a, DUELVARS_ARENA_CARD_STATUS + call GetNonTurnDuelistVariable + ld [hl], NO_STATUS + bank1call DrawDuelHUDs + ret +; 0x2ceb0 + +VenusaurMegaDrainEffect: ; 2ceb0 (b:4eb0) + ld hl, wDealtDamage + ld a, [hli] + ld h, [hl] + ld l, a + srl h + rr l + bit 0, l + jr z, .rounded + ; round up to nearest 10 + ld de, 10 / 2 + add hl, de +.rounded + ld e, l + ld d, h + call ApplyAndAnimateHPRecovery + ret +; 0x2cec8 + +; applies the damage bonus for attacks that get bonus +; from extra Water energy cards. +; this bonus is always 10 more damage for each extra Water energy +; and is always capped at a maximum of 20 damage. +; input: +; b = number of Water energy cards needed for paying Energy Cost +; c = number of colorless energy cards needed for paying Energy Cost +ApplyExtraWaterEnergyDamageBonus: ; 2cec8 (b:4ec8) + ld a, [wMetronomeEnergyCost] + or a + jr z, .not_metronome + ld c, a ; amount of colorless needed for Metronome + ld b, 0 ; no Water energy needed for Metronome + +.not_metronome + push bc + ldh a, [hTempPlayAreaLocation_ff9d] + ld e, a + call GetPlayAreaCardAttachedEnergies + pop bc + + ld hl, wAttachedEnergies + WATER + ld a, c + or a + jr z, .check_bonus ; is Energy cost all water energy? + + ; it's not, so we need to remove the + ; Water energy cards from calculations + ; if they pay for colorless instead. + ld a, [wTotalAttachedEnergies] + cp [hl] + jr nz, .check_bonus ; skip if at least 1 non-Water energy attached + + ; Water is the only energy color attached + ld a, c + add b + ld b, a + ; b += c + +.check_bonus + ld a, [hl] + sub b + jr c, .skip_bonus ; is water energy < b? + jr z, .skip_bonus ; is water energy == b? + +; a holds number of water energy not payed for energy cost + cp 3 + jr c, .less_than_3 + ld a, 2 ; cap this to 2 for bonus effect +.less_than_3 + call ATimes10 + call AddToDamage ; add 10 * a to damage + +.skip_bonus + ld a, [wDamage] + ld [wAIMinDamage], a + ld [wAIMaxDamage], a + ret +; 0x2cf05 + +OmastarWaterGunEffect: ; 2cf05 (b:4f05) + lb bc, 1, 1 + jr ApplyExtraWaterEnergyDamageBonus +; 0x2cf0a + +OmastarSpikeCannon_AIEffect: ; 2cf0a (b:4f0a) + ld a, 60 / 2 + lb de, 0, 60 + jp SetExpectedAIDamage +; 0x2cf12 + +OmastarSpikeCannon_MultiplierEffect: ; 2cf12 (b:4f12) + ld hl, 30 + call LoadTxRam3 + ld a, 2 + ldtx de, DamageCheckIfHeadsXDamageText + call TossCoinATimes_BankB + ld e, a + add a + add e + call ATimes10 + call SetDefiniteDamage ; 3 * 10 * heads + ret +; 0x2cf2a + +ClairvoyanceEffect: ; 2cf2a (b:4f2a) + scf + ret +; 0x2cf2c + +OmanyteWaterGunEffect: ; 2cf2c (b:4f2c) + lb bc, 1, 0 + jp ApplyExtraWaterEnergyDamageBonus +; 0x2cf32 + +WartortleWithdrawEffect: ; 2cf32 (b:4f32) + ldtx de, IfHeadsNoDamageNextTurnText + call TossCoin_BankB + jp nc, SetWasUnsuccessful + ld a, $4f + ld [wLoadedMoveAnimation], a + ld a, SUBSTATUS1_NO_DAMAGE_10 + call ApplySubstatus1ToDefendingCard + ret +; 0x2cf46 + +RainDanceEffect: ; 2cf46 (b:4f46) + scf + ret +; 0x2cf48 + +HydroPumpEffect: ; 2cf48 (b:4f48) + lb bc, 3, 0 + jp ApplyExtraWaterEnergyDamageBonus +; 0x2cf4e + +KinglerFlail_AIEffect: ; 2cf4e (b:4f4e) + call KinglerFlail_HPCheck + jp SetMinMaxDamageSameAsDamage +; 0x2cf54 + +KinglerFlail_HPCheck: ; 2cf54 (b:4f54) + ld e, PLAY_AREA_ARENA + call GetCardDamageAndMaxHP + call SetDefiniteDamage + ret +; 0x2cf5d + +; returns carry if no cards in Deck +; or if Play Area is full already. +KrabbyCallForFamily_CheckDeckAndPlayArea: ; 2cf5d (b:4f5d) + call CheckIfDeckIsEmpty + ret c ; return if no cards in deck + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ldtx hl, NoSpaceOnTheBenchText + cp MAX_PLAY_AREA_POKEMON + ccf + ret +; 0x2cf6d + +KrabbyCallForFamily_PlayerSelectEffect: ; 2cf6d (b:4f6d) + ld a, $ff + ldh [hTemp_ffa0], a + + call CreateDeckCardList + ldtx hl, ChooseAKrabbyFromDeckText + ldtx bc, KrabbyText + lb de, SEARCHEFFECT_CARD_ID, KRABBY + call LookForCardsInDeck + ret c + +; draw Deck list interface and print text + bank1call Func_5591 + ldtx hl, ChooseAKrabbyText + ldtx de, DuelistDeckText + bank1call SetCardListHeaderText + +.loop + bank1call DisplayCardList + jr c, .pressed_b + call GetCardIDFromDeckIndex + ld bc, KRABBY + call CompareDEtoBC + jr nz, .play_sfx + +; Krabby was selected + ldh a, [hTempCardIndex_ff98] + ldh [hTemp_ffa0], a + or a + ret + +.play_sfx + ; play SFX and loop back + call Func_3794 + jr .loop + +.pressed_b +; figure if Player can exit the screen without selecting, +; that is, if the Deck has no Krabby card. + ld a, DUELVARS_CARD_LOCATIONS + call GetTurnDuelistVariable +.loop_b_press + ld a, [hl] + cp CARD_LOCATION_DECK + jr nz, .next + ld a, l + call GetCardIDFromDeckIndex + ld bc, KRABBY + call CompareDEtoBC + jr z, .play_sfx ; found Krabby, go back to top loop +.next + inc l + ld a, l + cp DECK_SIZE + jr c, .loop_b_press + +; no Krabby in Deck, can safely exit screen + ld a, $ff + ldh [hTemp_ffa0], a + or a + ret +; 0x2cfdf + +KrabbyCallForFamily_AISelectEffect: ; 2cfdf (b:4fdf) + call CreateDeckCardList + ld hl, wDuelTempList +.loop_deck + ld a, [hli] + ldh [hTemp_ffa0], a + cp $ff + ret z ; no Krabby + call GetCardIDFromDeckIndex + ld a, e + cp KRABBY + jr nz, .loop_deck + ret ; Krabby found +; 0x2cfca + +KrabbyCallForFamily_PutInPlayAreaEffect: ; 2cfca (b:4fca) + ldh a, [hTemp_ffa0] + cp $ff + jr z, .shuffle + call SearchCardInDeckAndAddToHand + call AddCardToHand + call PutHandPokemonCardInPlayArea + call IsPlayerTurn + jr c, .shuffle + ldh a, [hTemp_ffa0] + ldtx hl, PlacedOnTheBenchText + bank1call DisplayCardDetailScreen +.shuffle + call Func_2c0bd + ret +; 0x2cfff + +MagikarpFlail_AIEffect: ; 2cfff (b:4fff) + call MagikarpFlail_HPCheck + jp SetMinMaxDamageSameAsDamage +; 0x2d005 + +MagikarpFlail_HPCheck: ; 2d005 (b:5005) + ld e, PLAY_AREA_ARENA + call GetCardDamageAndMaxHP + call SetDefiniteDamage + ret +; 0x2d00e + +HeadacheEffect: ; 2d00e (b:500e) + ld a, DUELVARS_ARENA_CARD_SUBSTATUS3 + call GetNonTurnDuelistVariable + set SUBSTATUS3_HEADACHE, [hl] + ret +; 0x2d016 + +PsyduckFurySwipes_AIEffect: ; 2d016 (b:5016) + ld a, 30 / 2 + lb de, 0, 30 + jp SetExpectedAIDamage +; 0x2d01e + +PsyduckFurySwipes_MultiplierEffect: ; 2d01e (b:501e) + ld hl, 10 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsXDamageText + ld a, 3 + call TossCoinATimes_BankB + call ATimes10 + call SetDefiniteDamage + ret +; 0x2d033 + +GolduckHyperBeam_PlayerSelectEffect: ; 2d033 (b:5033) + call SwapTurn + ld e, PLAY_AREA_ARENA + call GetPlayAreaCardAttachedEnergies + ld a, [wTotalAttachedEnergies] + or a + jr z, .no_energy + +; draw Energy Card list screen + ldtx hl, ChooseDiscardEnergyCardFromOpponentText + call DrawWideTextBox_WaitForInput + xor a ; PLAY_AREA_ARENA + call CreateArenaOrBenchEnergyCardList + xor a ; PLAY_AREA_ARENA + bank1call DisplayEnergyDiscardScreen + +.loop_input + bank1call HandleEnergyDiscardMenuInput + jr c, .loop_input + + call SwapTurn + ldh a, [hTempCardIndex_ff98] + ldh [hTemp_ffa0], a ; store selected card to discard + ret + +.no_energy + call SwapTurn + ld a, $ff + ldh [hTemp_ffa0], a + or a + ret +; 0x2d065 + +GolduckHyperBeam_AISelectEffect: ; 2d065 (b:5065) + call AIPickEnergyCardToDiscardFromDefendingPokemon + ldh [hTemp_ffa0], a + ret +; 0x2d06b + +GolduckHyperBeam_DiscardEffect: ; 2d06b (b:506b) + call HandleNoDamageOrEffect + ret c ; return if attack had no effect + + ; check if energy card was chosen to discard + ldh a, [hTemp_ffa0] + cp $ff + ret z ; return if none selected + + ; discard Defending card's energy + call SwapTurn + call PutCardInDiscardPile + ld a, DUELVARS_ARENA_CARD_LAST_TURN_EFFECT + call GetTurnDuelistVariable + ld [hl], LAST_TURN_EFFECT_DISCARD_ENERGY + call SwapTurn + ret +; 0x2d085 + +SeadraWaterGunEffect: ; 2d085 (b:5085) + lb bc, 1, 1 + jp ApplyExtraWaterEnergyDamageBonus +; 0x2d08b + +SeadraAgilityEffect: ; 2d08b (b:508b) + ldtx de, IfHeadsDoNotReceiveDamageOrEffectText + call TossCoin_BankB + ret nc ; return if tails + ld a, $52 + ld [wLoadedMoveAnimation], a + ld a, SUBSTATUS1_AGILITY + call ApplySubstatus1ToDefendingCard + ret +; 0x2d09d + +ShellderSupersonicEffect: ; 2d09d (b:509d) + call Confusion50PercentEffect + call nc, SetNoEffectFromStatus + ret +; 0x2d0a4 + +HideInShellEffect: ; 2d0a4 (b:50a4) + ldtx de, IfHeadsNoDamageNextTurnText + call TossCoin_BankB + jp nc, SetWasUnsuccessful + ld a, $4f + ld [wLoadedMoveAnimation], a + ld a, SUBSTATUS1_NO_DAMAGE_11 + call ApplySubstatus1ToDefendingCard + ret +; 0x2d0b8 + +VaporeonQuickAttack_AIEffect: ; 2d0b8 (b:50b8) + ld a, (10 + 30) / 2 + lb de, 10, 30 + jp SetExpectedAIDamage +; 0x2d0c0 + +VaporeonQuickAttack_DamageBoostEffect: ; 2d0c0 (b:50c0) + ld hl, 20 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsPlusDamageText + call TossCoin_BankB + ret nc ; return if tails + ld a, 20 + call AddToDamage + ret +; 0x2d0d3 + +VaporeonWaterGunEffect: ; 2d0d3 (b:50d3) + lb bc, 2, 1 + jp ApplyExtraWaterEnergyDamageBonus +; 0x2d0d9 + +; returns carry if Arena card has no Water Energy attached +; or if it doesn't have any damage counters. +StarmieRecover_CheckEnergyHP: ; 2d0d9 (b:50d9) + ld e, PLAY_AREA_ARENA + call GetPlayAreaCardAttachedEnergies + ld a, [wAttachedEnergies + WATER] + ldtx hl, NotEnoughWaterEnergyText + cp 1 + ret c ; return if not enough energy + call GetCardDamageAndMaxHP + ldtx hl, NoDamageCountersText + cp 10 + ret ; return carry if no damage +; 0x2d0f0 + +StarmieRecover_PlayerSelectEffect: ; 2d0f0 (b:50f0) + ld a, TYPE_ENERGY_WATER + call CreateListOfEnergyAttachedToArena + xor a ; PLAY_AREA_ARENA + bank1call DisplayEnergyDiscardScreen +.loop_input + bank1call HandleEnergyDiscardMenuInput + jr c, .loop_input + ldh a, [hTempCardIndex_ff98] + ldh [hTemp_ffa0], a ; store card chosen + ret +; 0x2d103 + +StarmieRecover_AISelectEffect: ; 2d103 (b:5103) + ld a, TYPE_ENERGY_WATER + call CreateListOfEnergyAttachedToArena + ld a, [wDuelTempList] ; pick first card + ldh [hTemp_ffa0], a + ret +; 0x2d10e + +StarmieRecover_DiscardEffect: ; 2d10e (b:510e) + ldh a, [hTemp_ffa0] + call PutCardInDiscardPile + ret +; 0x2d114 + +StarmieRecover_HealEffect: ; 2d114 (b:5114) + ld e, PLAY_AREA_ARENA + call GetCardDamageAndMaxHP + ld e, a ; all damage for recovery + ld d, 0 + call ApplyAndAnimateHPRecovery + ret +; 0x2d120 + +SquirtleWithdrawEffect: ; 2d120 (b:5120) + ldtx de, IfHeadsNoDamageNextTurnText + call TossCoin_BankB + jp nc, SetWasUnsuccessful + ld a, $4f + ld [wLoadedMoveAnimation], a + ld a, SUBSTATUS1_NO_DAMAGE_10 + call ApplySubstatus1ToDefendingCard + ret +; 0x2d134 + +HorseaSmokescreenEffect: ; 2d134 (b:5134) + ld a, SUBSTATUS2_SMOKESCREEN + call ApplySubstatus2ToDefendingCard + ret +; 0x2d13a + +TentacruelSupersonicEffect: ; 2d13a (b:513a) + call Confusion50PercentEffect + call nc, SetNoEffectFromStatus + ret +; 0x2d141 + +JellyfishSting_AIEffect: ; 2d141 (b:5141) + ld a, 10 + lb de, 10, 10 + jp UpdateExpectedAIDamage_AccountForPoison +; 0x2d149 + +; returns carry if Defending Pokemon has no attacks +PoliwhirlAmnesia_CheckAttacks: ; 2d149 (b:5149) + call SwapTurn + ld a, DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Move1Category] + cp POKEMON_POWER + jr nz, .has_attack + ld hl, wLoadedCard2Move2Name + ld a, [hli] + or [hl] + jr nz, .has_attack +; has no attack + call SwapTurn + ldtx hl, NoAttackMayBeChoosenText + scf + ret +.has_attack + call SwapTurn + or a + ret +; 0x2d16f + +PoliwhirlAmnesia_PlayerSelectEffect: ; 2d16f (b:516f) + call PlayerPickAttackForAmnesia + ret +; 0x2d173 + +PoliwhirlAmnesia_AISelectEffect: ; 2d173 (b:5173) + call AIPickAttackForAmnesia + ldh [hTemp_ffa0], a + ret +; 0x2d179 + +PoliwhirlAmnesia_DisableEffect: ; 2d179 (b:5179) + call ApplyAmnesiaToAttack + ret +; 0x2d17d + +PlayerPickAttackForAmnesia: ; 2d17d (b:517d) + ldtx hl, ChooseAttackOpponentWillNotBeAbleToUseText + call DrawWideTextBox_WaitForInput + call HandleDefendingPokemonAttackSelection + ld a, e + ldh [hTemp_ffa0], a + ret +; 0x2d18a + +; applies the Amnesia effect on the defending Pokemon, +; for the attack index in hTemp_ffa0. +ApplyAmnesiaToAttack: ; 2d18a (b:518a) + ld a, SUBSTATUS2_AMNESIA + call ApplySubstatus2ToDefendingCard + ld a, [wNoDamageOrEffect] + or a + ret nz ; no effect + +; set selected attack as disabled + ld a, DUELVARS_ARENA_CARD_DISABLED_MOVE_INDEX + call GetNonTurnDuelistVariable + ldh a, [hTemp_ffa0] + ld [hl], a + + ld l, DUELVARS_ARENA_CARD_LAST_TURN_EFFECT + ld [hl], LAST_TURN_EFFECT_AMNESIA + + call IsPlayerTurn + ret c ; return if Player + +; the rest of the routine if for Opponent +; to announce which move was used for Amnesia. + call SwapTurn + ld a, DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + ld d, a + ldh a, [hTemp_ffa0] + ld e, a + call GetAttackName + call LoadTxRam2 + ldtx hl, WasChosenForTheEffectOfAmnesiaText + call DrawWideTextBox_WaitForInput + call SwapTurn + ret +; 0x2d1c0 + +PoliwhirlDoubleslap_AIEffect: ; 2d1c0 (b:51c0) + ld a, 60 / 2 + lb de, 0, 60 + jp SetExpectedAIDamage +; 0x2d1c8 + +PoliwhirlDoubleslap_MultiplierEffect: ; 2d1c8 (b:51c8) + ld hl, 30 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsXDamageText + ld a, 2 + call TossCoinATimes_BankB + ld e, a + add a + add e + call ATimes10 + call SetDefiniteDamage + ret +; 0x2d1e0 + +PoliwrathWaterGunEffect: ; 2d1e0 (b:51e0) + lb bc, 2, 1 + jp ApplyExtraWaterEnergyDamageBonus +; 0x2d1e6 + +Whirlpool_PlayerSelectEffect: ; 2d1e6 (b:51e6) + call SwapTurn + xor a ; PLAY_AREA_ARENA + call CreateArenaOrBenchEnergyCardList + jr c, .no_energy + + ldtx hl, ChooseDiscardEnergyCardFromOpponentText + call DrawWideTextBox_WaitForInput + xor a ; PLAY_AREA_ARENA + bank1call DisplayEnergyDiscardScreen +.loop_input + bank1call HandleEnergyDiscardMenuInput + jr c, .loop_input + + call SwapTurn + ldh a, [hTempCardIndex_ff98] + ldh [hTemp_ffa0], a ; store selected card to discard + ret + +.no_energy + call SwapTurn + ld a, $ff + ldh [hTemp_ffa0], a + ret +; 0x2d20e + +Whirlpool_AISelectEffect: ; 2d20e (b:520e) + call AIPickEnergyCardToDiscardFromDefendingPokemon + ldh [hTemp_ffa0], a + ret +; 0x2d214 + +Whirlpool_DiscardEffect: ; 2d214 (b:5214) + call HandleNoDamageOrEffect + ret c ; return if attack had no effect + ldh a, [hTemp_ffa0] + cp $ff + ret z ; return if none selected + + ; discard Defending card's energy + ; this doesn't update DUELVARS_ARENA_CARD_LAST_TURN_EFFECT + call SwapTurn + call PutCardInDiscardPile + ; ld a, DUELVARS_ARENA_CARD_LAST_TURN_EFFECT + ; call GetTurnDuelistVariable + ; ld [hl], LAST_TURN_EFFECT_DISCARD_ENERGY + call SwapTurn + ret +; 0x2d227 + +PoliwagWaterGunEffect: ; 2d227 (b:5227) + lb bc, 1, 0 + jp ApplyExtraWaterEnergyDamageBonus +; 0x2d22d + +ClampEffect: ; 2d22d (b:522d) + ld a, $05 + ld [wLoadedMoveAnimation], a + ldtx de, SuccessCheckIfHeadsAttackIsSuccessfulText + call TossCoin_BankB + jp c, ParalysisEffect +; unsuccessful + xor a + ld [wLoadedMoveAnimation], a + call SetDefiniteDamage + call SetWasUnsuccessful + ret +; 0x2d246 + +CloysterSpikeCannon_AIEffect: ; 2d246 (b:5246) + ld a, 60 / 2 + lb de, 0, 60 + jp SetExpectedAIDamage +; 0x2d24e + +CloysterSpikeCannon_MultiplierEffect: ; 2d24e (b:524e) + ld hl, 30 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsXDamageText + ld a, 2 + call TossCoinATimes_BankB + ld e, a + add a + add e + call ATimes10 + call SetDefiniteDamage + ret +; 0x2d266 + +Blizzard_BenchDamage50PercentEffect: ; 2d266 (b:5266) + ldtx de, DamageToOppBenchIfHeadsDamageToYoursIfTailsText + call TossCoin_BankB + ldh [hTemp_ffa0], a ; store coin result + ret +; 0x2d26f + +Blizzard_BenchDamageEffect: ; 2d26f (b:526f) + ldh a, [hTemp_ffa0] + or a + jr nz, .opp_bench + +; own bench + ld a, $01 + ld [wIsDamageToSelf], a + ld a, 10 + call DealDamageToAllBenchedPokemon + ret + +.opp_bench + call SwapTurn + ld a, 10 + call DealDamageToAllBenchedPokemon + call SwapTurn + ret +; 0x2d28b + +; return carry if can use Cowardice +Cowardice_Check: ; 2d28b (b:528b) + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + call CheckCannotUseDueToStatus_OnlyToxicGasIfANon0 + ret c ; return if cannot use + + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ldtx hl, EffectNoPokemonOnTheBenchText + cp 2 + ret c ; return if no bench + + ldh a, [hTempPlayAreaLocation_ff9d] + add DUELVARS_ARENA_CARD_FLAGS + call GetTurnDuelistVariable + ldtx hl, CannotBeUsedInTurnWhichWasPlayedText + and CAN_EVOLVE_THIS_TURN + scf + ret z ; return if was played this turn + + or a + ret +; 0x2d2ae + +Cowardice_PlayerSelectEffect: ; 2d2ae (b:52ae) + ldh a, [hTemp_ffa0] + or a + ret nz ; return if not Arena card + ldtx hl, SelectPokemonToPlaceInTheArenaText + call DrawWideTextBox_WaitForInput + bank1call HasAlivePokemonInBench + bank1call OpenPlayAreaScreenForSelection + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hAIPkmnPowerEffectParam], a + ret +; 0x2d2c3 + +Cowardice_RemoveFromPlayAreaEffect: ; 2d2c3 (b:52c3) + ldh a, [hTemp_ffa0] + add DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + +; put card in Discard Pile temporarily, so that +; all cards attached are discarded as well. + push af + ldh a, [hTemp_ffa0] + ld e, a + call MovePlayAreaCardToDiscardPile + +; if card was in Arena, swap selected Bench +; Pokemon with Arena, otherwise skip. + ldh a, [hTemp_ffa0] + or a + jr nz, .skip_switch + ldh a, [hAIPkmnPowerEffectParam] + ld e, a + call SwapArenaWithBenchPokemon + +.skip_switch +; move card back to Hand from Discard Pile +; and adjust Play Area + pop af + call MoveDiscardPileCardToHand + call AddCardToHand + call ShiftAllPokemonToFirstPlayAreaSlots + + xor a + ld [wDuelDisplayedScreen], a + ret +; 0x2d2eb + +LaprasWaterGunEffect: ; 2d2eb (b:52eb) + lb bc, 1, 0 + jp ApplyExtraWaterEnergyDamageBonus +; 0x2d2f1 + +Quickfreeze_InitialEffect: ; 2d2f1 (b:52f1) + scf + ret +; 0x2d2f3 + +Quickfreeze_Paralysis50PercentEffect: ; 2d2f3 (b:52f3) + ldtx de, ParalysisCheckText + call TossCoin_BankB + jr c, .heads + +; tails + call SetWasUnsuccessful + bank1call DrawDuelMainScene + bank1call Func_1bca + call WaitForWideTextBoxInput + ret + +.heads + call ParalysisEffect + ldh a, [hTempPlayAreaLocation_ff9d] + ld b, a + ld c, $00 + ldh a, [hWhoseTurn] + ld h, a + bank1call PlayMoveAnimation + bank1call Func_741a + bank1call WaitMoveAnimation + bank1call Func_6df1 + bank1call DrawDuelHUDs + bank1call Func_1bca + call c, WaitForWideTextBoxInput + ret +; 0x2d329 + +IceBreath_ZeroDamage: ; 2d329 (b:5329) + xor a + call SetDefiniteDamage + ret +; 0x2d32e + +IceBreath_RandomPokemonDamageEffect: ; 2d32e (b:532e) + call SwapTurn + call PickRandomPlayAreaCard + ld b, a + ld de, 40 + call DealDamageToPlayAreaPokemon_RegularAnim + call SwapTurn + ret +; 0x2d33f + +FocusEnergyEffect: ; 2d33f (b:533f) + ld a, [wTempTurnDuelistCardID] + cp VAPOREON1 + ret nz ; return if no Vaporeon1 + ld a, SUBSTATUS1_NEXT_TURN_DOUBLE_DAMAGE + call ApplySubstatus1ToDefendingCard + ret +; 0x2d34b + +PlayerPickFireEnergyCardToDiscard: ; 2d34b (b:534b) + call CreateListOfFireEnergyAttachedToArena + xor a + bank1call DisplayEnergyDiscardScreen + bank1call HandleEnergyDiscardMenuInput + ldh a, [hTempCardIndex_ff98] + ldh [hTempList], a + ret +; 0x2d35a + +AIPickFireEnergyCardToDiscard: ; 2d35a (b:535a) + call CreateListOfFireEnergyAttachedToArena + ld a, [wDuelTempList] + ldh [hTempList], a ; pick first in list + ret +; 0x2d363 + +; returns carry if Arena card has no Fire Energy cards +ArcanineFlamethrower_CheckEnergy: ; 2d363 (b:5363) + ld e, PLAY_AREA_ARENA + call GetPlayAreaCardAttachedEnergies + ld a, [wAttachedEnergies] + ldtx hl, NotEnoughFireEnergyText + cp 1 + ret +; 0x2d371 + +ArcanineFlamethrower_PlayerSelectEffect: ; 2d371 (b:5371) + call PlayerPickFireEnergyCardToDiscard + ret +; 0x2d375 + +ArcanineFlamethrower_AISelectEffect: ; 2d375 (b:5375) + call AIPickFireEnergyCardToDiscard + ret +; 0x2d379 + +ArcanineFlamethrower_DiscardEffect: ; 2d379 (b:5379) + ldh a, [hTempList] + call PutCardInDiscardPile + ret +; 0x2d37f + +TakeDownEffect: ; 2d37f (b:537f) + ld a, 30 + call DealRecoilDamageToSelf + ret +; 0x2d385 + +ArcanineQuickAttack_AIEffect: ; 2d385 (b:5385) + ld a, (10 + 30) / 2 + lb de, 10, 30 + jp SetExpectedAIDamage +; 0x2d38d + +ArcanineQuickAttack_DamageBoostEffect: ; 2d38d (b:538d) + ld hl, 20 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsPlusDamageText + call TossCoin_BankB + ret nc ; return if tails + ld a, 20 + call AddToDamage + ret +; 0x2d3a0 + +; return carry if has less than 2 Fire Energy cards +FlamesOfRage_CheckEnergy: ; 2d3a0 (b:53a0) + ld e, PLAY_AREA_ARENA + call GetPlayAreaCardAttachedEnergies + ld a, [wAttachedEnergies] + ldtx hl, NotEnoughFireEnergyText + cp 2 + ret +; 0x2d3ae + +FlamesOfRage_PlayerSelectEffect: ; 2d3ae (b:53ae) + ldtx hl, ChooseAndDiscard2FireEnergyCardsText + call DrawWideTextBox_WaitForInput + + xor a + ldh [hCurSelectionItem], a + call CreateListOfFireEnergyAttachedToArena + xor a + bank1call DisplayEnergyDiscardScreen +.loop_input + bank1call HandleEnergyDiscardMenuInput + ret c + call GetNextPositionInTempList + ldh a, [hTempCardIndex_ff98] + ld [hl], a + call RemoveCardFromDuelTempList + ldh a, [hCurSelectionItem] + cp 2 + ret nc ; return when 2 have been chosen + bank1call DisplayEnergyDiscardMenu + jr .loop_input +; 0x2d3d5 + +FlamesOfRage_AISelectEffect: ; 2d3d5 (b:53d5) + call AIPickFireEnergyCardToDiscard + ld a, [wDuelTempList + 1] + ldh [hTempList + 1], a + ret +; 0x2d3de + +FlamesOfRage_DiscardEffect: ; 2d3de (b:53de) + ldh a, [hTempList] + call PutCardInDiscardPile + ldh a, [hTempList + 1] + call PutCardInDiscardPile + ret +; 0x2d3e9 + +FlamesOfRage_AIEffect: ; 2d3e9 (b:53e9) + call FlamesOfRage_DamageBoostEffect + jp SetMinMaxDamageSameAsDamage +; 0x2d3ef + +FlamesOfRage_DamageBoostEffect: ; 2d3ef (b:53ef) + ld e, PLAY_AREA_ARENA + call GetCardDamageAndMaxHP + call AddToDamage + ret +; 0x2d3f8 + +RapidashStomp_AIEffect: ; 2d3f8 (b:53f8) + ld a, (20 + 30) / 2 + lb de, 20, 30 + jp SetExpectedAIDamage +; 0x2d400 + +RapidashStomp_DamageBoostEffect: ; 2d400 (b:5400) + ld hl, 10 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsPlusDamageText + call TossCoin_BankB + ret nc ; return if tails + ld a, 10 + call AddToDamage + ret +; 0x2d413 + +RapidashAgilityEffect: ; 2d413 (b:5413) + ldtx de, IfHeadsDoNotReceiveDamageOrEffectText + call TossCoin_BankB + ret nc ; return if tails + ld a, $52 + ld [wLoadedMoveAnimation], a + ld a, SUBSTATUS1_AGILITY + call ApplySubstatus1ToDefendingCard + ret +; 0x2d425 + +; returns carry if Opponent has no Pokemon in bench +NinetailsLure_CheckBench: ; 2d425 (b:5425) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetNonTurnDuelistVariable + ldtx hl, EffectNoPokemonOnTheBenchText + cp 2 + ret +; 0x2d430 + +NinetailsLure_PlayerSelectEffect: ; 2d430 (b:5430) + ldtx hl, SelectPkmnOnBenchToSwitchWithActiveText + call DrawWideTextBox_WaitForInput + call SwapTurn + bank1call HasAlivePokemonInBench +.loop_input + bank1call OpenPlayAreaScreenForSelection + jr c, .loop_input + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + call SwapTurn + ret +; 0x2d449 + +NinetailsLure_AISelectEffect: ; 2d449 (b:5449) + call GetBenchPokemonWithLowestHP + ldh [hTemp_ffa0], a + ret +; 0x2d44f + +NinetailsLure_SwitchEffect: ; 2d44f (b:544f) + call SwapTurn + ldh a, [hTemp_ffa0] + ld e, a + call HandleNShieldAndTransparency + call nc, SwapArenaWithBenchPokemon + call SwapTurn + xor a + ld [wDuelDisplayedScreen], a + ret +; 0x2d463 + +; return carry if no Fire energy cards +FireBlast_CheckEnergy: ; 2d463 (b:5463) + ld e, PLAY_AREA_ARENA + call GetPlayAreaCardAttachedEnergies + ldtx hl, NotEnoughFireEnergyText + ld a, [wAttachedEnergies] + cp 1 + ret +; 0x2d471 + +FireBlast_PlayerSelectEffect: ; 2d471 (b:5471) + call PlayerPickFireEnergyCardToDiscard + ret +; 0x2d475 + +FireBlast_AISelectEffect: ; 2d475 (b:5475) + call AIPickFireEnergyCardToDiscard + ret +; 0x2d479 + +FireBlast_DiscardEffect: ; 2d479 (b:5479) + ldh a, [hTempList] + call PutCardInDiscardPile + ret +; 0x2d47f + +; return carry if no Fire energy cards +Ember_CheckEnergy: ; 2d47f (b:547f) + ld e, PLAY_AREA_ARENA + call GetPlayAreaCardAttachedEnergies + ldtx hl, NotEnoughFireEnergyText + ld a, [wAttachedEnergies] + cp 1 + ret +; 0x2d48d + +Ember_PlayerSelectEffect: ; 2d48d (b:548d) + call PlayerPickFireEnergyCardToDiscard + ret +; 0x2d491 + +Ember_AISelectEffect: ; 2d491 (b:5491) + call AIPickFireEnergyCardToDiscard + ret +; 0x2d495 + +Ember_DiscardEffect: ; 2d495 (b:5495) + ldh a, [hTempList] + call PutCardInDiscardPile + ret +; 0x2d49b + +; return carry if no Fire energy cards +Wildfire_CheckEnergy: ; 2d49b (b:549b) + ld e, PLAY_AREA_ARENA + call GetPlayAreaCardAttachedEnergies + ldtx hl, NotEnoughFireEnergyText + ld a, [wAttachedEnergies] + cp 1 + ret +; 0x2d4a9 + +Wildfire_PlayerSelectEffect: ; 2d4a9 (b:54a9) + ldtx hl, DiscardOppDeckAsManyFireEnergyCardsText + call DrawWideTextBox_WaitForInput + + xor a + ldh [hCurSelectionItem], a + call CreateListOfFireEnergyAttachedToArena + xor a + bank1call DisplayEnergyDiscardScreen + +; show list to Player and for each card selected to discard, +; just increase a counter and store it. +; this will be the output used by Wildfire_DiscardEnergyEffect. + xor a + ld [wcbfa], a +.loop + ldh a, [hCurSelectionItem] + ld [wcbfb], a + bank1call HandleEnergyDiscardMenuInput + jr c, .done + ld hl, hCurSelectionItem + inc [hl] + call RemoveCardFromDuelTempList + jr c, .done + bank1call DisplayEnergyDiscardMenu + jr .loop + +.done +; return carry if no cards were discarded +; output the result in hTemp_ffa0 + ldh a, [hCurSelectionItem] + ldh [hTemp_ffa0], a + or a + ret nz + scf + ret +; 0x2d4dd + +Wildfire_AISelectEffect: ; 2d4dd (b:54dd) +; AI always chooses 0 cards to discard + xor a + ldh [hTempList], a + ret +; 0x2d4e1 + +Wildfire_DiscardEnergyEffect: ; 2d4e1 (b:54e1) + call CreateListOfFireEnergyAttachedToArena + ldh a, [hTemp_ffa0] + or a + ret z ; no cards to discard + +; discard cards from wDuelTempList equal to the number +; of cards that were input in hTemp_ffa0. +; these are all the Fire Energy cards attached to Arena card +; so it will discard the cards in order, regardless +; of the actual order that was selected by Player. + ld c, a + ld hl, wDuelTempList +.loop_discard + ld a, [hli] + call PutCardInDiscardPile + dec c + jr nz, .loop_discard + ret +; 0x2d4f4 + +Wildfire_DiscardDeckEffect: ; 2d4f4 (b:54f4) + ldh a, [hTemp_ffa0] + ld c, a + ld b, $00 + call SwapTurn + ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK + call GetTurnDuelistVariable + ld a, DECK_SIZE + sub [hl] + cp c + jr nc, .start_discard + ; only discard number of cards that are left in deck + ld c, a + +.start_discard + push bc + inc c + jr .check_remaining + +.loop + ; discard top card from deck + call DrawCardFromDeck + call nc, PutCardInDiscardPile +.check_remaining + dec c + jr nz, .loop + + pop hl + call LoadTxRam3 + ldtx hl, DiscardedCardsFromDeckText + call DrawWideTextBox_PrintText + call SwapTurn + ret +; 0x2d523 + +Moltres1DiveBomb_AIEffect: ; 2d523 (b:5523) + ld a, 80 / 2 + lb de, 0, 80 + jp SetExpectedAIDamage +; 0x2d52b + +Moltres1DiveBomb_Success50PercentEffect: ; 2d52b (b:552b) + ldtx de, SuccessCheckIfHeadsAttackIsSuccessfulText + call TossCoin_BankB + jr c, .heads +; tails + xor a + call SetDefiniteDamage + call SetWasUnsuccessful + ret +.heads + ld a, $11 + ld [wLoadedMoveAnimation], a + ret +; 0x2d541 + +FlareonQuickAttack_AIEffect: ; 2d541 (b:5541) + ld a, (10 + 30) / 2 + lb de, 10, 30 + jp SetExpectedAIDamage +; 0x2d549 + +FlareonQuickAttack_DamageBoostEffect: ; 2d549 (b:5549) + ld hl, 20 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsPlusDamageText + call TossCoin_BankB + ret nc ; return if tails + ld a, 20 + call AddToDamage + ret +; 0x2d55c + +; return carry if no Fire Energy attached +FlareonFlamethrower_CheckEnergy: ; 2d55c (b:555c) + ld e, PLAY_AREA_ARENA + call GetPlayAreaCardAttachedEnergies + ldtx hl, NotEnoughFireEnergyText + ld a, [wAttachedEnergies] + cp 1 + ret +; 0x2d56a + +FlareonFlamethrower_PlayerSelectEffect: ; 2d56a (b:556a) + call PlayerPickFireEnergyCardToDiscard + ret +; 0x2d56e + +FlareonFlamethrower_AISelectEffect: ; 2d56e (b:556e) + call AIPickFireEnergyCardToDiscard + ret +; 0x2d572 + +FlareonFlamethrower_DiscardEffect: ; 2d572 (b:5572) + ldh a, [hTempList] + call PutCardInDiscardPile + ret +; 0x2d578 + +; return carry if no Fire Energy attached +MagmarFlamethrower_CheckEnergy: ; 2d578 (b:5578) + ld e, PLAY_AREA_ARENA + call GetPlayAreaCardAttachedEnergies + ldtx hl, NotEnoughFireEnergyText + ld a, [wAttachedEnergies] + cp 1 + ret +; 0x2d586 + +MagmarFlamethrower_PlayerSelectEffect: ; 2d586 (b:5586) + call PlayerPickFireEnergyCardToDiscard + ret +; 0x2d58a + +MagmarFlamethrower_AISelectEffect: ; 2d58a (b:558a) + call AIPickFireEnergyCardToDiscard + ret +; 0x2d58e + +MagmarFlamethrower_DiscardEffect: ; 2d58e (b:558e) + ldh a, [hTempList] + call PutCardInDiscardPile + ret +; 0x2d594 + +MagmarSmokescreenEffect: ; 2d594 (b:5594) + ld a, SUBSTATUS2_SMOKESCREEN + call ApplySubstatus2ToDefendingCard + ret +; 0x2d59a + +MagmarSmog_AIEffect: ; 2d59a (b:559a) + ld a, 5 + lb de, 0, 10 + jp UpdateExpectedAIDamage_AccountForPoison +; 0x2d5a2 + +; return carry if no Fire Energy attached +CharmeleonFlamethrower_CheckEnergy: ; 2d5a2 (b:55a2) + ld e, PLAY_AREA_ARENA + call GetPlayAreaCardAttachedEnergies + ldtx hl, NotEnoughFireEnergyText + ld a, [wAttachedEnergies] + cp 1 + ret +; 0x2d5b0 + +CharmeleonFlamethrower_PlayerSelectEffect: ; 2d5b0 (b:55b0) + call PlayerPickFireEnergyCardToDiscard + ret +; 0x2d5b4 + +CharmeleonFlamethrower_AISelectEffect: ; 2d5b4 (b:55b4) + call AIPickFireEnergyCardToDiscard + ret +; 0x2d5b8 + +CharmeleonFlamethrower_DiscardEffect: ; 2d5b8 (b:55b8) + ldh a, [hTempList] + call PutCardInDiscardPile + ret +; 0x2d5be + +EnergyBurnEffect: ; 2d5be (b:55be) + scf + ret +; 0x2d5c0 + +; return carry if has less than 2 Fire Energy cards +FireSpin_CheckEnergy: ; 2d5c0 (b:55c0) + xor a ; PLAY_AREA_ARENA + call CreateArenaOrBenchEnergyCardList + call CountCardsInDuelTempList + ldtx hl, NotEnoughEnergyCardsText + cp 2 + ret +; 0x2d5cd + +FireSpin_PlayerSelectEffect: ; 2d5cd (b:55cd) + ldtx hl, ChooseAndDiscard2EnergyCardsText + call DrawWideTextBox_WaitForInput + + xor a + ldh [hCurSelectionItem], a + xor a + call CreateArenaOrBenchEnergyCardList + call SortCardsInDuelTempListByID + xor a + bank1call DisplayEnergyDiscardScreen + + ld a, 2 + ld [wcbfa], a +.loop_input + bank1call HandleEnergyDiscardMenuInput + ret c + call GetNextPositionInTempList + ldh a, [hTempCardIndex_ff98] + ld [hl], a + ld hl, wcbfb + inc [hl] + ldh a, [hCurSelectionItem] + cp 2 + jr nc, .done + ldh a, [hTempCardIndex_ff98] + call RemoveCardFromDuelTempList + bank1call DisplayEnergyDiscardMenu + jr .loop_input +.done +; return when 2 have been chosen + or a + ret +; 0x2d606 + +FireSpin_AISelectEffect: ; 2d606 (b:5606) + xor a ; PLAY_AREA_ARENA + call CreateArenaOrBenchEnergyCardList + ld hl, wDuelTempList + ld a, [hli] + ldh [hTempList], a + ld a, [hl] + ldh [hTempList + 1], a + ret +; 0x2d614 + +FireSpin_DiscardEffect: ; 2d614 (b:5614) + ld hl, hTempList + ld a, [hli] + call PutCardInDiscardPile + ld a, [hli] + call PutCardInDiscardPile + ret +; 0x2d620 + +; returns carry if Pkmn Power cannot be used +; or if Arena card is not Charizard. +; this is unused. +EnergyBurnCheck_Unreferenced: ; 2d620 (b:5620) + xor a + bank1call CheckCannotUseDueToStatus_OnlyToxicGasIfANon0 + ret c + ld a, DUELVARS_ARENA_CARD + push de + call GetTurnDuelistVariable + call GetCardIDFromDeckIndex + ld a, e + pop de + cp CHARIZARD + jr nz, .not_charizard + or a + ret +.not_charizard + scf + ret +; 0x2d638 + +FlareonRage_AIEffect: ; 2d638 (b:5638) + call FlareonRage_DamageBoostEffect + jp SetMinMaxDamageSameAsDamage +; 0x2d63e + +FlareonRage_DamageBoostEffect: ; 2d63e (b:563e) + ld e, PLAY_AREA_ARENA + call GetCardDamageAndMaxHP + call AddToDamage + ret +; 0x2d647 + +MixUpEffect: ; 2d647 (b:5647) call SwapTurn call CreateHandCardList call SortCardsInDuelTempListByID + +; first go through Hand to place +; all Pkmn cards in it in the Deck. + ld hl, wDuelTempList + ld c, 0 +.loop_hand + ld a, [hl] + cp $ff + jr z, .done_hand + call .CheckIfCardIsPkmnCard + jr nc, .next_hand + ; found Pkmn card, place in deck + inc c + ld a, [hl] + call RemoveCardFromHand + call ReturnCardToDeck +.next_hand + inc hl + jr .loop_hand + +.done_hand + ld a, c + ldh [hCurSelectionItem], a + push bc + ldtx hl, ThePkmnCardsInHandAndDeckWereShuffledText + call DrawWideTextBox_WaitForInput + + call Func_2c0bd + call CreateDeckCardList + pop bc + ldh a, [hCurSelectionItem] + or a + jr z, .done ; if no cards were removed from Hand, return + +; c holds the number of cards that were placed in the Deck. +; now pick Pkmn cards from the Deck to place in Hand. + ld hl, wDuelTempList +.loop_deck + ld a, [hl] + call .CheckIfCardIsPkmnCard + jr nc, .next_deck + dec c + ld a, [hl] + call SearchCardInDeckAndAddToHand + call AddCardToHand +.next_deck + inc hl + ld a, c + or a + jr nz, .loop_deck +.done + call SwapTurn + ret +; 0x2d69a + +; returns carry if card index in a is Pkmn card +.CheckIfCardIsPkmnCard: ; 2d69a (b:569a) + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Type] + cp TYPE_ENERGY + ret +; 0x2d6a3 + +DancingEmbers_AIEffect: ; 2d6a3 (b:56a3) + ld a, 80 / 2 + lb de, 0, 80 + jp SetExpectedAIDamage +; 0x2d6ab + +DancingEmbers_MultiplierEffect: ; 2d6ab (b:56ab) + ld hl, 10 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsXDamageText + ld a, 8 + call TossCoinATimes_BankB + call ATimes10 + call SetDefiniteDamage + ret +; 0x2d6c0 + +Firegiver_InitialEffect: ; 2d6c0 (b:56c0) + scf + ret +; 0x2d6c2 + +Firegiver_AddToHandEffect: ; 2d6c2 (b:56c2) +; fill wDuelTempList with all Fire Energy card +; deck indices that are in the Deck. + ld a, DUELVARS_CARD_LOCATIONS + call GetTurnDuelistVariable + ld de, wDuelTempList + ld c, 0 +.loop_cards + ld a, [hl] + cp CARD_LOCATION_DECK + jr nz, .next + push hl + push de + ld a, l + call GetCardIDFromDeckIndex + call GetCardType + pop de + pop hl + cp TYPE_ENERGY_FIRE + jr nz, .next + ld a, l + ld [de], a + inc de + inc c +.next + inc l + ld a, l + cp DECK_SIZE + jr c, .loop_cards + ld a, $ff + ld [de], a + +; check how many were found + ld a, c + or a + jr nz, .found + ; return if none found + ldtx hl, ThereWasNoFireEnergyText + call DrawWideTextBox_WaitForInput + call Func_2c0bd + ret + +.found +; pick a random number between 1 and 4, +; up to the maximum number of Fire Energy +; cards that were found. + ld a, 4 + call Random + inc a + cp c + jr c, .ok + ld a, c + +.ok + ldh [hCurSelectionItem], a +; load correct Move animation depending +; on what side the effect is from. + ld d, $84 + ld a, [wDuelistType] + cp DUELIST_TYPE_PLAYER + jr z, .player_1 +; opponent + ld d, $85 +.player_1 + ld a, d + ld [wLoadedMoveAnimation], a + +; start loop for adding Energy cards to hand + ldh a, [hCurSelectionItem] + ld c, a + ld hl, wDuelTempList +.loop_energy + push hl + push bc + ld bc, $0 + ldh a, [hWhoseTurn] + ld h, a + bank1call PlayMoveAnimation + bank1call WaitMoveAnimation + +; load correct coordinates to update the number of cards +; in hand and deck during animation. + lb bc, 18, 7 ; x, y for hand number + ld e, 3 ; y for deck number + ld a, [wLoadedMoveAnimation] + cp $84 + jr z, .player_2 + lb bc, 4, 5 ; x, y for hand number + ld e, 10 ; y for deck number + +.player_2 +; update and print number of cards in hand + ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND + call GetTurnDuelistVariable + inc a + bank1call WriteTwoDigitNumberInTxSymbolFormat +; update and print number of cards in deck + ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK + call GetTurnDuelistVariable + ld a, DECK_SIZE - 1 + sub [hl] + ld c, e + bank1call WriteTwoDigitNumberInTxSymbolFormat + +; load Fire Energy card index and add to hand + pop bc + pop hl + ld a, [hli] + call SearchCardInDeckAndAddToHand + call AddCardToHand + dec c + jr nz, .loop_energy + +; load the number of cards added to hand and print text + ldh a, [hCurSelectionItem] + ld l, a + ld h, $00 + call LoadTxRam3 + ldtx hl, DrewFireEnergyFromTheHandText + call DrawWideTextBox_WaitForInput + call Func_2c0bd + ret +; 0x2d76e + +Moltres2DiveBomb_AIEffect: ; 2d76e (b:576e) + ld a, 70 / 2 + lb de, 0, 70 + jp SetExpectedAIDamage +; 0x2d776 + +Moltres2DiveBomb_Success50PercentEffect: ; 2d776 (b:5776) + ldtx de, SuccessCheckIfHeadsAttackIsSuccessfulText + call TossCoin_BankB + jr c, .heads +; tails + xor a + call SetDefiniteDamage + call SetWasUnsuccessful + ret +.heads + ld a, $11 + ld [wLoadedMoveAnimation], a + ret +; 0x2d78c + +; output in de the number of energy cards +; attached to the Defending Pokemon times 10. +; used for attacks that deal 10x number of energy +; cards attached to the Defending card. +GetEnergyAttachedMultiplierDamage: ; 2d78c (b:578c) + call SwapTurn + ld a, DUELVARS_CARD_LOCATIONS + call GetTurnDuelistVariable + + ld c, 0 +.loop + ld a, [hl] + cp CARD_LOCATION_ARENA + jr nz, .next + ; is in Arena + ld a, l + call GetCardIDFromDeckIndex + call GetCardType + and TYPE_ENERGY + jr z, .next + ; is Energy attached to Arena card + inc c +.next + inc l + ld a, l + cp DECK_SIZE + jr c, .loop + + call SwapTurn + ld l, c + ld h, $00 + ld b, $00 + add hl, hl ; hl = 2 * c + add hl, hl ; hl = 4 * c + add hl, bc ; hl = 5 * c + add hl, hl ; hl = 10 * c + ld e, l + ld d, h + ret +; 0x2d7bc + +; draws list of Energy Cards in Discard Pile +; for Player to select from. +; the Player can select up to 2 cards from the list. +; these cards are given in $ff-terminated list +; in hTempList. +HandleEnergyCardsInDiscardPileSelection: ; 2d7bc (b:57bc) + push hl + xor a + ldh [hCurSelectionItem], a + call CreateEnergyCardListFromDiscardPile_AllEnergy + pop hl + jr c, .finish + + call DrawWideTextBox_WaitForInput +.loop +; draws Discard Pile screen and textbox, +; and handles Player input + bank1call InitAndDrawCardListScreenLayout + ldtx hl, ChooseAnEnergyCardText + ldtx de, PlayerDiscardPileText + bank1call SetCardListHeaderText + bank1call DisplayCardList + jr nc, .selected + +; Player is trying to exit screen, +; but can select up to 2 cards total. +; prompt Player to confirm exiting screen. + ld a, 2 + call AskWhetherToQuitSelectingCards + jr c, .loop + jr .finish + +.selected +; a card was selected, so add it to list + call GetNextPositionInTempList + ldh a, [hTempCardIndex_ff98] + ld [hl], a + call RemoveCardFromDuelTempList + or a + jr z, .finish ; no more cards? + ldh a, [hCurSelectionItem] + cp 2 + jr c, .loop ; already selected 2 cards? + +.finish +; place terminating byte on list + call GetNextPositionInTempList + ld [hl], $ff + or a + ret +; 0x2d7fc + +; returns carry if Pkmn Power cannot be used, and +; sets the correct text in hl for failure. +Curse_CheckDamageAndBench: ; 2d7fc (b:57fc) + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + +; fail if Pkmn Power has already been used + add DUELVARS_ARENA_CARD_FLAGS + call GetTurnDuelistVariable + ldtx hl, OnlyOncePerTurnText + and USED_PKMN_POWER_THIS_TURN + jr nz, .set_carry + +; fail if Opponent only has 1 Pokemon in Play Area + call SwapTurn + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + call SwapTurn + ldtx hl, CannotUseSinceTheresOnly1PkmnText + cp 2 + jr c, .set_carry + +; fail if Opponent has no damage counters + call SwapTurn + call CheckIfPlayAreaHasAnyDamage + call SwapTurn + ldtx hl, NoPokemonWithDamageCountersText + jr c, .set_carry + +; return carry if Pkmn Power cannot be used due +; to Toxic Gas or status. + ldh a, [hTempPlayAreaLocation_ff9d] + call CheckCannotUseDueToStatus_OnlyToxicGasIfANon0 + ret + +.set_carry + scf + ret +; 0x2d834 + +Curse_PlayerSelectEffect: ; 2d834 (b:5834) + ldtx hl, ProcedureForCurseText + bank1call DrawWholeScreenTextBox + call SwapTurn + xor a + ldh [hCurSelectionItem], a + bank1call Func_61a1 +.start + bank1call PrintPlayAreaCardList_EnableLCD + push af + ldh a, [hCurSelectionItem] + ld hl, PlayAreaSelectionMenuParameters + call InitializeMenuParameters + pop af + ld [wNumMenuItems], a + +; first pick a target to take 1 damage counter from. +.loop_input_first + call DoFrame + call HandleMenuInput + jr nc, .loop_input_first + cp $ff + jr z, .cancel + ldh [hCurSelectionItem], a + ldh [hTempPlayAreaLocation_ffa1], a + call GetCardDamageAndMaxHP + or a + jr nz, .picked_first ; test if has damage + ; play sfx + call Func_3794 + jr .loop_input_first + +.picked_first +; give 10 HP to card selected, draw the scene, +; then immediately revert this. + ldh a, [hTempPlayAreaLocation_ffa1] + add DUELVARS_ARENA_CARD_HP + call GetTurnDuelistVariable + push af + push hl + add 10 + ld [hl], a + bank1call PrintPlayAreaCardList_EnableLCD + pop hl + pop af + ld [hl], a + +; draw damage counter on cursor + ldh a, [hTempPlayAreaLocation_ffa1] + ld b, SYM_HP_NOK + call DrawSymbolOnPlayAreaCursor + +; handle input to pick the target to receive the damage counter. +.loop_input_second + call DoFrame + call HandleMenuInput + jr nc, .loop_input_second + ldh [hPlayAreaEffectTarget], a + cp $ff + jr nz, .a_press ; was a pressed? + +; b press +; erase the damage counter symbol +; and loop back up again. + ldh a, [hTempPlayAreaLocation_ffa1] + ld b, SYM_SPACE + call DrawSymbolOnPlayAreaCursor + call EraseCursor + jr .start + +.a_press + ld hl, hTempPlayAreaLocation_ffa1 + cp [hl] + jr z, .loop_input_second ; same as first? +; a different Pokemon was picked, +; so store this Play Area location +; and erase the damage counter in the cursor. + ldh a, [hTempPlayAreaLocation_ffa1] + ld b, SYM_SPACE + call DrawSymbolOnPlayAreaCursor + call EraseCursor + call SwapTurn + or a + ret + +.cancel +; return carry if operation was cancelled. + call SwapTurn + scf + ret +; 0x2d8bb + +Curse_TransferDamageEffect: ; 2d8bb (b:58bb) +; set Pkmn Power as used + ldh a, [hTempList] + add DUELVARS_ARENA_CARD_FLAGS + call GetTurnDuelistVariable + set USED_PKMN_POWER_THIS_TURN_F, [hl] + +; figure out the type of duelist that used Curse. +; if it was the player, no need to draw the Play Area screen. + call SwapTurn + ld a, DUELVARS_DUELIST_TYPE + call GetNonTurnDuelistVariable + cp DUELIST_TYPE_PLAYER + jr z, .vs_player + +; vs. oppponent + bank1call Func_61a1 +.vs_player +; transfer the damage counter to the targets that were selected. + ldh a, [hPlayAreaEffectTarget] + add DUELVARS_ARENA_CARD_HP + call GetTurnDuelistVariable + sub 10 + ld [hl], a + ldh a, [hTempPlayAreaLocation_ffa1] + add DUELVARS_ARENA_CARD_HP + ld l, a + ld a, 10 + add [hl] + ld [hl], a + + bank1call PrintPlayAreaCardList_EnableLCD + ld a, DUELVARS_DUELIST_TYPE + call GetNonTurnDuelistVariable + cp DUELIST_TYPE_PLAYER + jr z, .done +; vs. opponent + ldh a, [hPlayAreaEffectTarget] + ldh [hTempPlayAreaLocation_ff9d], a + bank1call Func_6194 + +.done + call SwapTurn + call ExchangeRNG + bank1call Func_6e49 + ret +; 0x2d903 + +GengarDarkMind_PlayerSelectEffect: ; 2d903 (b:5903) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetNonTurnDuelistVariable + cp 2 + jr nc, .has_bench +; no bench Pokemon to damage. + ld a, $ff + ldh [hTemp_ffa0], a + ret + +.has_bench +; opens Play Area screen to select Bench Pokemon +; to damage, and store it before returning. + ldtx hl, ChoosePkmnInTheBenchToGiveDamageText + call DrawWideTextBox_WaitForInput + call SwapTurn + bank1call HasAlivePokemonInBench +.loop_input + bank1call OpenPlayAreaScreenForSelection + jr c, .loop_input + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + call SwapTurn + ret +; 0x2d92a + +GengarDarkMind_AISelectEffect: ; 2d92a (b:592a) + ld a, $ff + ldh [hTemp_ffa0], a + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetNonTurnDuelistVariable + cp 2 + ret c ; return if no Bench Pokemon +; just pick Pokemon with lowest remaining HP. + call GetBenchPokemonWithLowestHP + ldh [hTemp_ffa0], a + ret +; 0x2d93c + +GengarDarkMind_DamageBenchEffect: ; 2d93c (b:593c) + ldh a, [hTemp_ffa0] + cp $ff + ret z ; no target chosen + call SwapTurn + ld b, a + ld de, 10 + call DealDamageToPlayAreaPokemon_RegularAnim + call SwapTurn + ret +; 0x2d94f + +SleepingGasEffect: ; 2d94f (b:594f) + call Sleep50PercentEffect + call nc, SetNoEffectFromStatus + ret +; 0x2d956 + +DestinyBond_CheckEnergy: ; 2d956 (b:5956) + ld e, PLAY_AREA_ARENA + call GetPlayAreaCardAttachedEnergies + ld a, [wAttachedEnergies + PSYCHIC] + ldtx hl, NotEnoughPsychicEnergyText + cp 1 + ret +; 0x2d964 + +DestinyBond_PlayerSelectEffect: ; 2d964 (b:5964) +; handle input and display of Energy card list + ld a, TYPE_ENERGY_PSYCHIC + call CreateListOfEnergyAttachedToArena + xor a + bank1call DisplayEnergyDiscardScreen + bank1call HandleEnergyDiscardMenuInput + ret c + ldh a, [hTempCardIndex_ff98] + ldh [hTempList], a + ret +; 0x2d976 + +DestinyBond_AISelectEffect: ; 2d976 (b:5976) +; pick first card in list + ld a, TYPE_ENERGY_PSYCHIC + call CreateListOfEnergyAttachedToArena + ld a, [wDuelTempList] + ldh [hTempList], a + ret +; 0x2d981 + +DestinyBond_DiscardEffect: ; 2d981 (b:5981) + ldh a, [hTempList] + call PutCardInDiscardPile + ret +; 0x2d987 + +DestinyBond_DestinyBondEffect: ; 2d987 (b:5987) + ld a, SUBSTATUS1_DESTINY_BOND + call ApplySubstatus1ToDefendingCard + ret +; 0x2d98d + +; returns carry if no Energy cards in Discard Pile. +EnergyConversion_CheckEnergy: ; 2d98d (b:598d) + call CreateEnergyCardListFromDiscardPile_AllEnergy + ldtx hl, ThereAreNoEnergyCardsInDiscardPileText + ret +; 0x2d994 + +EnergyConversion_PlayerSelectEffect: ; 2d994 (b:5994) + ldtx hl, Choose2EnergyCardsFromDiscardPileForHandText + call HandleEnergyCardsInDiscardPileSelection + ret +; 0x2d99b + +EnergyConversion_AISelectEffect: ; 2d99b (b:599b) + call CreateEnergyCardListFromDiscardPile_AllEnergy ld hl, wDuelTempList -.return_hand_to_deck_loop + ld de, hTempList + ld c, 2 +; select the first two energy cards found in Discard Pile +.loop ld a, [hli] cp $ff + jr z, .done + ld [de], a + inc de + dec c + jr nz, .loop +.done + ld a, $ff + ld [de], a + ret +; 0x2d9b4 + +EnergyConversion_AddToHandEffect: ; 2d9b4 (b:59b4) +; damage itself + ld a, 10 + call DealRecoilDamageToSelf + +; loop cards that were chosen +; until $ff is reached, +; and move them to the hand. + ld hl, hTempList + ld de, wDuelTempList +.loop_cards + ld a, [hli] + ld [de], a + inc de + cp $ff + jr z, .done + call MoveDiscardPileCardToHand + call AddCardToHand + jr .loop_cards + +.done + call IsPlayerTurn + ret c + bank1call Func_4b38 + ret +; 0x2d9d6 + +; return carry if Defending Pokemon is not asleep +DreamEaterEffect: ; 2d9d6 (b:59d6) + ld a, DUELVARS_ARENA_CARD_STATUS + call GetNonTurnDuelistVariable + and CNF_SLP_PRZ + cp ASLEEP + ret z ; return if asleep +; not asleep, set carry and load text + ldtx hl, OpponentIsNotAsleepText + scf + ret +; 0x2d9e5 + +TransparencyEffect: ; 2d9e5 (b:59e5) + scf + ret +; 0x2d9e7 + +; returns carry if neither the Turn Duelist or +; the non-Turn Duelist have any deck cards. +Prophecy_CheckDeck: ; 2d9e7 (b:59e7) + ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK + call GetTurnDuelistVariable + cp DECK_SIZE + jr c, .no_carry + ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK + call GetNonTurnDuelistVariable + cp DECK_SIZE + jr c, .no_carry + ldtx hl, NoCardsLeftInTheDeckText + scf + ret +.no_carry + or a + ret +; 0x2da00 + +Prophecy_PlayerSelectEffect: ; 2da00 (b:5a00) + ldtx hl, ProcedureForProphecyText + bank1call DrawWholeScreenTextBox +.select_deck + bank1call DrawDuelMainScene + ldtx hl, PleaseSelectTheDeckText + call TwoItemHorizontalMenu + ldh a, [hKeysHeld] + and B_BUTTON + jr nz, Prophecy_PlayerSelectEffect ; loop back to start + + ldh a, [hCurMenuItem] + ldh [hTempList], a ; store selection in first position in list + or a + jr z, .turn_duelist + +; non-turn duelist + ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK + call GetNonTurnDuelistVariable + cp DECK_SIZE + jr nc, .select_deck ; no cards, go back to deck selection + call SwapTurn + call HandleProphecyScreen + call SwapTurn + ret + +.turn_duelist + ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK + call GetTurnDuelistVariable + cp DECK_SIZE + jr nc, .select_deck ; no cards, go back to deck selection + call HandleProphecyScreen + ret +; 0x2da3c + +Prophecy_AISelectEffect: ; 2da3c (b:5a3c) +; AI doesn't ever choose this attack +; so this it does no sorting. + ld a, $ff + ldh [hTemp_ffa0], a + ret +; 0x2da41 + +Prophecy_ReorderDeckEffect: ; 2da41 (b:5a41) + ld hl, hTempList + ld a, [hli] + or a + jr z, .ReorderCards ; turn duelist's deck + cp $ff + ret z + + ; non-turn duelist's deck + call SwapTurn + call .ReorderCards + call SwapTurn + ret + +.ReorderCards + ld c, 0 +; add selected cards to hand in the specified order +.loop_add_hand + ld a, [hli] + cp $ff + jr z, .dec_hl + call SearchCardInDeckAndAddToHand + inc c + jr .loop_add_hand + +.dec_hl +; go to last card that was in the list + dec hl + dec hl + +.loop_return_deck +; return the cards to the top of the deck + ld a, [hld] + call ReturnCardToDeck + dec c + jr nz, .loop_return_deck + call IsPlayerTurn + ret c + ; print text in case it was the opponent + ldtx hl, ExchangedCardsInDuelistsHandText + call DrawWideTextBox_WaitForInput + ret +; 0x2da76 + +; draw and handle Player selection for reordering +; the top 3 cards of Deck. +; the resulting list is output in order in hTempList. +HandleProphecyScreen: ; 2da76 (b:5a76) + ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK + call GetTurnDuelistVariable + ld b, a + ld a, DECK_SIZE + sub [hl] ; a = number of cards in deck + +; store in c the number of cards that will be reordered. +; this number is 3, unless the deck as fewer cards than +; that in which case it will be the number of cards remaining. + ld c, 3 + cp c + jr nc, .got_number_cards + ld c, a ; store number of remaining cards in c +.got_number_cards + ld a, c + inc a + ld [wNumberOfCardsToOrder], a + +; store in wDuelTempList the cards +; at top of Deck to be reordered. + ld a, b + add DUELVARS_DECK_CARDS + ld l, a + ld de, wDuelTempList +.loop_top_cards + ld a, [hli] + ld [de], a + inc de + dec c + jr nz, .loop_top_cards + ld a, $ff ; terminating byte + ld [de], a + +.start + call CountCardsInDuelTempList + ld b, a + ld a, 1 ; start at 1 + ldh [hCurSelectionItem], a + +; initialize buffer ahead in wDuelTempList. + ld hl, wDuelTempList + 10 + xor a +.loop_init_buffer + ld [hli], a + dec b + jr nz, .loop_init_buffer + ld [hl], $ff + + bank1call InitAndDrawCardListScreenLayout + ldtx hl, ChooseTheOrderOfTheCardsText + ldtx de, DuelistDeckText + bank1call SetCardListHeaderText + bank1call Func_5735 + +.loop_selection + bank1call DisplayCardList + jr c, .clear + +; first check if this card was already selected + ldh a, [hCurMenuItem] + ld e, a + ld d, $00 + ld hl, wDuelTempList + 10 + add hl, de + ld a, [hl] + or a + jr nz, .loop_selection ; already chosen + +; being here means card hasn't been selected yet, +; so add its order number to buffer and increment +; the sort number for the next card. + ldh a, [hCurSelectionItem] + ld [hl], a + inc a + ldh [hCurSelectionItem], a + bank1call Func_5744 + ldh a, [hCurSelectionItem] + ld hl, wNumberOfCardsToOrder + cp [hl] + jr c, .loop_selection ; still more cards + +; confirm that the ordering has been completed + call EraseCursor + ldtx hl, IsThisOKText + call YesOrNoMenuWithText_LeftAligned + jr c, .start ; if not, return back to beginning of selection + +; write in hTempList the card list +; in order that was selected. + ld hl, wDuelTempList + 10 + ld de, wDuelTempList + ld c, 0 +.loop_order + ld a, [hli] + cp $ff + jr z, .done + push hl + push bc + ld c, a + ld b, $00 + ld hl, hTempList + add hl, bc + ld a, [de] + ld [hl], a + pop bc + pop hl + inc de + inc c + jr .loop_order +; now hTempList has the list of card deck indices +; in the order selected to be place on top of the deck. + +.done + ld b, $00 + ld hl, hTempList + 1 + add hl, bc + ld [hl], $ff ; terminating byte + or a + ret + +.clear +; check if any reordering was done. + ld hl, hCurSelectionItem + ld a, [hl] + cp 1 + jr z, .loop_selection ; none done, go back +; clear the order that was selected thus far. + dec a + ld [hl], a + ld c, a + ld hl, wDuelTempList + 10 +.loop_clear + ld a, [hli] + cp c + jr nz, .loop_clear + ; clear this byte + dec hl + ld [hl], $00 + bank1call Func_5744 + jr .loop_selection +; 0x2db2b + +HypnoDarkMind_PlayerSelectEffect: ; 2db2b (b:5b2b) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetNonTurnDuelistVariable + cp 2 + jr nc, .has_bench +; no bench Pokemon to damage. + ld a, $ff + ldh [hTemp_ffa0], a + ret + +.has_bench +; opens Play Area screen to select Bench Pokemon +; to damage, and store it before returning. + ldtx hl, ChoosePkmnInTheBenchToGiveDamageText + call DrawWideTextBox_WaitForInput + call SwapTurn + bank1call HasAlivePokemonInBench +.loop_input + bank1call OpenPlayAreaScreenForSelection + jr c, .loop_input + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + call SwapTurn + ret +; 0x2db52 + +HypnoDarkMind_AISelectEffect: ; 2db52 (b:5b52) + ld a, $ff + ldh [hTemp_ffa0], a + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetNonTurnDuelistVariable + cp 2 + ret c ; return if no Bench Pokemon +; just pick Pokemon with lowest remaining HP. + call GetBenchPokemonWithLowestHP + ldh [hTemp_ffa0], a + ret +; 0x2db64 + +HypnoDarkMind_DamageBenchEffect: ; 2db64 (b:5b64) + ldh a, [hTemp_ffa0] + cp $ff + ret z ; no target chosen + call SwapTurn + ld b, a + ld de, 10 + call DealDamageToPlayAreaPokemon_RegularAnim + call SwapTurn + ret +; 0x2db77 + +InvisibleWallEffect: ; 2db77 (b:5b77) + scf + ret +; 0x2db79 + +MrMimeMeditate_AIEffect: ; 2db79 (b:5b79) + call MrMimeMeditate_DamageBoostEffect + jp SetMinMaxDamageSameAsDamage +; 0x2db7f + +MrMimeMeditate_DamageBoostEffect: ; 2db7f (b:5b7f) +; add damage counters of Defending card to damage + call SwapTurn + ld e, PLAY_AREA_ARENA + call GetCardDamageAndMaxHP + call SwapTurn + call AddToDamage + ret +; 0x2db8e + +; returns carry if Damage Swap cannot be used. +DamageSwap_CheckDamage: ; 2db8e (b:5b8e) + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + call CheckIfPlayAreaHasAnyDamage + jr c, .no_damage + ldh a, [hTempPlayAreaLocation_ff9d] + call CheckCannotUseDueToStatus_OnlyToxicGasIfANon0 + ret +.no_damage + ldtx hl, NoPokemonWithDamageCountersText + scf + ret +; 0x2dba2 + +DamageSwap_SelectAndSwapEffect: ; 2dba2 (b:5ba2) + ld a, DUELVARS_DUELIST_TYPE + call GetTurnDuelistVariable + cp DUELIST_TYPE_PLAYER + jr z, .player +; non-player + bank1call Func_61a1 + bank1call PrintPlayAreaCardList_EnableLCD + ret + +.player + ldtx hl, ProcedureForDamageSwapText + bank1call DrawWholeScreenTextBox + xor a + ldh [hCurSelectionItem], a + bank1call Func_61a1 + +.start + bank1call PrintPlayAreaCardList_EnableLCD + push af + ldh a, [hCurSelectionItem] + ld hl, PlayAreaSelectionMenuParameters + call InitializeMenuParameters + pop af + ld [wNumMenuItems], a + +; handle selection of Pokemon to take damage from +.loop_input_first + call DoFrame + call HandleMenuInput + jr nc, .loop_input_first + cp $ff + ret z ; quit when B button is pressed + + ldh [hTempPlayAreaLocation_ffa1], a + ldh [hCurSelectionItem], a + +; if card has no damage, play sfx and return to start + call GetCardDamageAndMaxHP + or a + jr z, .no_damage + +; take damage away temporarily to draw UI. + ldh a, [hTempPlayAreaLocation_ffa1] + add DUELVARS_ARENA_CARD_HP + call GetTurnDuelistVariable + push af + push hl + add 10 + ld [hl], a + bank1call PrintPlayAreaCardList_EnableLCD + pop hl + pop af + ld [hl], a + +; draw damage counter in cursor + ldh a, [hTempPlayAreaLocation_ffa1] + ld b, SYM_HP_NOK + call DrawSymbolOnPlayAreaCursor + +; handle selection of Pokemon to give damage to +.loop_input_second + call DoFrame + call HandleMenuInput + jr nc, .loop_input_second + ; if B is pressed, return damage counter + ; to card that it was taken from + cp $ff + jr z, .update_ui + +; try to give the card selected the damage counter +; if it would KO, ignore it. + ldh [hPlayAreaEffectTarget], a + ldh [hCurSelectionItem], a + call TryGiveDamageCounter_DamageSwap + jr c, .loop_input_second + + ld a, OPPACTION_6B15 + call SetOppAction_SerialSendDuelData + +.update_ui + ldh a, [hTempPlayAreaLocation_ffa1] + ld b, SYM_SPACE + call DrawSymbolOnPlayAreaCursor + call EraseCursor + jr .start + +.no_damage + call Func_3794 + jr .loop_input_first +; 0x2dc27 + +; tries to give damage counter to hPlayAreaEffectTarget, +; and if successful updates UI screen. +DamageSwap_SwapEffect: ; 2dc27 (b:5c27) + call TryGiveDamageCounter_DamageSwap + ret c + bank1call PrintPlayAreaCardList_EnableLCD + or a + ret +; 0x2dc30 + +; tries to give the damage counter to the target +; chosen by the Player (hPlayAreaEffectTarget). +; if the damage counter would KO card, then do +; not give the damage counter and return carry. +TryGiveDamageCounter_DamageSwap: ; 2dc30 (b:5c30) + ldh a, [hPlayAreaEffectTarget] + add DUELVARS_ARENA_CARD_HP + call GetTurnDuelistVariable + sub 10 + jr z, .set_carry ; would bring HP to zero? +; has enough HP to receive a damage counter + ld [hl], a + ldh a, [hTempPlayAreaLocation_ffa1] + add DUELVARS_ARENA_CARD_HP + ld l, a + ld a, 10 + add [hl] + ld [hl], a + or a + ret +.set_carry + scf + ret +; 0x2dc49 + +PsywaveEffect: ; 2dc49 (b:5c49) + call GetEnergyAttachedMultiplierDamage + ld hl, wDamage + ld [hl], e + inc hl + ld [hl], d + ret +; 0x2dc53 + +; returns carry if neither Duelist has evolved Pokemon. +DevolutionBeam_CheckPlayArea: ; 2dc53 (b:5c53) + call CheckIfTurnDuelistHasEvolvedCards + ret nc + call SwapTurn + call CheckIfTurnDuelistHasEvolvedCards + call SwapTurn + ldtx hl, ThereAreNoStage1PokemonText + ret +; 0x2dc64 + +; returns carry of Player cancelled selection. +; otherwise, output in hTemp_ffa0 which Play Area +; was selected ($0 = own Play Area, $1 = opp. Play Area) +; and in hTempPlayAreaLocation_ffa1 selected card. +DevolutionBeam_PlayerSelectEffect: ; 2dc64 (b:5c64) + ldtx hl, ProcedureForDevolutionBeamText + bank1call DrawWholeScreenTextBox + +.start + bank1call DrawDuelMainScene + ldtx hl, PleaseSelectThePlayAreaText + call TwoItemHorizontalMenu + ldh a, [hKeysHeld] + and B_BUTTON + jr nz, .set_carry + +; a Play Area was selected + ldh a, [hCurMenuItem] + or a + jr nz, .opp_chosen + +; player chosen + call HandleEvolvedCardSelection + jr c, .start + + xor a +.store_selection + ld hl, hTemp_ffa0 + ld [hli], a ; store which Duelist Play Area selected + ldh a, [hTempPlayAreaLocation_ff9d] + ld [hl], a ; store which card selected + or a + ret + +.opp_chosen + call SwapTurn + call HandleEvolvedCardSelection + call SwapTurn + jr c, .start + ld a, $01 + jr .store_selection + +.set_carry + scf + ret +; 0x2dc9e + +DevolutionBeam_AISelectEffect: ; 2dc9e (b:5c9e) + ld a, $01 + ldh [hTemp_ffa0], a + call SwapTurn + call FindFirstNonBasicCardInPlayArea + call SwapTurn + jr c, .found + xor a + ldh [hTemp_ffa0], a + call FindFirstNonBasicCardInPlayArea +.found + ldh [hTempPlayAreaLocation_ffa1], a + ret +; 0x2dcb6 + +DevolutionBeam_LoadAnimation: ; 2dcb6 (b:5cb6) + xor a + ld [wLoadedMoveAnimation], a + ret +; 0x2dcbb + +DevolutionBeam_DevolveEffect: ; 2dcbb (b:5cbb) + ldh a, [hTemp_ffa0] + or a + jr z, .DevolvePokemon + cp $ff + ret z + +; opponent's Play Area + call SwapTurn + ldh a, [hTempPlayAreaLocation_ffa1] + jr nz, .skip_handle_no_damage_effect + call HandleNoDamageOrEffect + jr c, .unaffected +.skip_handle_no_damage_effect + call .DevolvePokemon +.unaffected + call SwapTurn + ret + +.DevolvePokemon + ld a, $5d + ld [wLoadedMoveAnimation], a + ldh a, [hTempPlayAreaLocation_ffa1] + ld b, a + ld c, $00 + ldh a, [hWhoseTurn] + ld h, a + bank1call PlayMoveAnimation + bank1call WaitMoveAnimation + +; load selected card's data + ldh a, [hTempPlayAreaLocation_ffa1] + ldh [hTempPlayAreaLocation_ff9d], a + ld [wTempPlayAreaLocation_cceb], a + add DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + call LoadCardDataToBuffer1_FromDeckIndex + +; check if car is affected + ld a, [wLoadedCard1ID] + ld [wTempNonTurnDuelistCardID], a + ld de, $0 + ldh a, [hTempPlayAreaLocation_ff9d] + or a + jr nz, .skip_substatus_check + call HandleNoDamageOrEffectSubstatus + jr c, .check_no_damage_effect +.skip_substatus_check + call HandleDamageReductionOrNoDamageFromPkmnPowerEffects +.check_no_damage_effect + call CheckNoDamageOrEffect + jr nc, .devolve + call DrawWideTextBox_WaitForInput + ret + +.devolve + ldh a, [hTempPlayAreaLocation_ffa1] + ldh [hTempPlayAreaLocation_ff9d], a + add DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + bank1call GetCardOneStageBelow + call PrintDevolvedCardNameAndLevelText + + ld a, d + call UpdateDevolvedCardHPAndStage + call ResetDevolvedCardStatus + +; add the evolved card to the hand + ld a, e + call AddCardToHand + +; check if this devolution KO's card + ldh a, [hTempPlayAreaLocation_ffa1] + call PrintPlayAreaCardKnockedOutIfNoHP + + xor a + ld [wDuelDisplayedScreen], a + ret +; 0x2dd3b + +; returns carry if Turn Duelist +; has no Stage1 or Stage2 cards in Play Area. +CheckIfTurnDuelistHasEvolvedCards: ; 2dd3b (b:5d3b) + ld a, DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + ld d, h + ld e, DUELVARS_ARENA_CARD_STAGE +.loop + ld a, [hli] + cp $ff + jr z, .set_carry + ld a, [de] + inc de + or a + jr z, .loop ; is Basic Stage + ret +.set_carry + scf + ret +; 0x2dd50 + +; handles Player selection of an evolved card in Play Area. +; returns carry if Player cancelled operation. +HandleEvolvedCardSelection: ; 2dd50 (b:5d50) + bank1call HasAlivePokemonInPlayArea +.loop + bank1call OpenPlayAreaScreenForSelection + ret c + ldh a, [hTempPlayAreaLocation_ff9d] + add DUELVARS_ARENA_CARD_STAGE + call GetTurnDuelistVariable + or a + jr z, .loop ; if Basic, loop + ret +; 0x2dd62 + +; finds first occurence in Play Area +; of Stage 1 or 2 card, and outputs its +; Play Area location in a, with carry set. +; if none found, don't return carry set. +FindFirstNonBasicCardInPlayArea: ; 2dd62 (b:5d62) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ld c, a + + ld b, PLAY_AREA_ARENA + ld l, DUELVARS_ARENA_CARD_STAGE +.loop + ld a, [hli] + or a + jr nz, .not_basic + inc b + dec c + jr nz, .loop + or a + ret +.not_basic + ld a, b + scf + ret +; 0x2dd79 + +NeutralizingShieldEffect: ; 2dd79 (b:5d79) + scf + ret +; 0x2dd7b + +Psychic_AIEffect: ; 2dd7b (b:5d7b) + call Psychic_DamageBoostEffect + jp SetMinMaxDamageSameAsDamage +; 0x2dd81 + +Psychic_DamageBoostEffect: ; 2dd81 (b:5d81) + call GetEnergyAttachedMultiplierDamage + ld hl, wDamage + ld a, e + add [hl] + ld [hli], a + ld a, d + adc [hl] + ld [hl], a + ret +; 0x2dd8e + +; return carry if no Psychic Energy attached +Barrier_CheckEnergy: ; 2dd8e (b:5d8e) + ld e, PLAY_AREA_ARENA + call GetPlayAreaCardAttachedEnergies + ld a, [wAttachedEnergies + PSYCHIC] + ldtx hl, NotEnoughPsychicEnergyText + cp 1 + ret +; 0x2dd9c + +Barrier_PlayerSelectEffect: ; 2dd9c (b:5d9c) + ld a, TYPE_ENERGY_PSYCHIC + call CreateListOfEnergyAttachedToArena + xor a ; PLAY_AREA_ARENA + bank1call DisplayEnergyDiscardScreen + bank1call HandleEnergyDiscardMenuInput + ret c + ldh a, [hTempCardIndex_ff98] + ldh [hTemp_ffa0], a + ret +; 0x2ddae + +Barrier_AISelectEffect: ; 2ddae (b:5dae) +; AI picks the first energy in list + ld a, TYPE_ENERGY_PSYCHIC + call CreateListOfEnergyAttachedToArena + ld a, [wDuelTempList] + ldh [hTemp_ffa0], a + ret +; 0x2ddb9 + +Barrier_DiscardEffect: ; 2ddb9 (b:5db9) + ldh a, [hTemp_ffa0] + call PutCardInDiscardPile + ret +; 0x2ddbf + +Barrier_BarrierEffect: ; 2ddbf (b:5dbf) + ld a, SUBSTATUS1_BARRIER + call ApplySubstatus1ToDefendingCard + ret +; 0x2ddc5 + +Mewtwo3EnergyAbsorption_CheckDiscardPile: ; 2ddc5 (b:5dc5) + call CreateEnergyCardListFromDiscardPile_AllEnergy + ldtx hl, ThereAreNoEnergyCardsInDiscardPileText + ret +; 0x2ddcc + +Mewtwo3EnergyAbsorption_PlayerSelectEffect: ; 2ddcc (b:5dcc) + ldtx hl, Choose2EnergyCardsFromDiscardPileToAttachText + call HandleEnergyCardsInDiscardPileSelection + ret +; 0x2ddd3 + +Mewtwo3EnergyAbsorption_AISelectEffect: ; 2ddd3 (b:5dd3) +; AI picks first 2 energy cards + call CreateEnergyCardListFromDiscardPile_AllEnergy + ld hl, wDuelTempList + ld de, hTempList + ld c, 2 +.loop + ld a, [hli] + cp $ff + jr z, .done + ld [de], a + inc de + dec c + jr nz, .loop +.done + ld a, $ff ; terminating byte + ld [de], a + ret +; 0x2ddec + +Mewtwo3EnergyAbsorption_AddToHandEffect: ; 2ddec (b:5dec) + ld hl, hTempList +.loop + ld a, [hli] + cp $ff + ret z + push hl + call MoveDiscardPileCardToHand + call GetTurnDuelistVariable + ld [hl], CARD_LOCATION_ARENA + pop hl + jr .loop +; 0x2ddff + +Mewtwo2EnergyAbsorption_CheckDiscardPile: ; 2ddff (b:5dff) + call CreateEnergyCardListFromDiscardPile_AllEnergy + ldtx hl, ThereAreNoEnergyCardsInDiscardPileText + ret +; 0x2de06 + +Mewtwo2EnergyAbsorption_PlayerSelectEffect: ; 2de06 (b:5e06) + ldtx hl, Choose2EnergyCardsFromDiscardPileToAttachText + call HandleEnergyCardsInDiscardPileSelection + ret +; 0x2de0d + +Mewtwo2EnergyAbsorption_AISelectEffect: ; 2de0d (b:5e0d) +; AI picks first 2 energy cards + call CreateEnergyCardListFromDiscardPile_AllEnergy + ld hl, wDuelTempList + ld de, hTempList + ld c, 2 +.loop + ld a, [hli] + cp $ff + jr z, .done + ld [de], a + inc de + dec c + jr nz, .loop +.done + ld a, $ff ; terminating byte + ld [de], a + ret +; 0x2de26 + +Mewtwo2EnergyAbsorption_AddToHandEffect: ; 2de26 (b:5e26) + ld hl, hTempList +.loop + ld a, [hli] + cp $ff + ret z + push hl + call MoveDiscardPileCardToHand + call GetTurnDuelistVariable + ld [hl], CARD_LOCATION_ARENA + pop hl + jr .loop +; 0x2de39 + +; returns carry if Strange Behavior cannot be used. +StrangeBehavior_CheckDamage: ; 2de39 (b:5e39) +; does Play Area have any damage counters? + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + call CheckIfPlayAreaHasAnyDamage + ldtx hl, NoPokemonWithDamageCountersText + jr c, .set_carry +; can Slowbro receive any damage counters without KOing? + ldh a, [hTempPlayAreaLocation_ff9d] + add DUELVARS_ARENA_CARD_HP + call GetTurnDuelistVariable + ldtx hl, CannotUseBecauseItWillBeKnockedOutText + cp 10 + 10 + jr c, .set_carry +; can Pkmn Power be used? + ldh a, [hTempPlayAreaLocation_ff9d] + call CheckCannotUseDueToStatus_OnlyToxicGasIfANon0 + ret + +.set_carry + scf + ret +; 0x2de5b + +StrangeBehavior_SelectAndSwapEffect: ; 2de5b (b:5e5b) + ld a, DUELVARS_DUELIST_TYPE + call GetTurnDuelistVariable + cp DUELIST_TYPE_PLAYER + jr z, .player + +; not player + bank1call Func_61a1 + bank1call PrintPlayAreaCardList_EnableLCD + ret + +.player + ldtx hl, ProcedureForStrangeBehaviorText + bank1call DrawWholeScreenTextBox + + xor a + ldh [hCurSelectionItem], a + bank1call Func_61a1 +.start + bank1call PrintPlayAreaCardList_EnableLCD + push af + ldh a, [hCurSelectionItem] + ld hl, PlayAreaSelectionMenuParameters + call InitializeMenuParameters + pop af + + ld [wNumMenuItems], a +.loop_input + call DoFrame + call HandleMenuInput + jr nc, .loop_input + cp -1 + ret z ; return when B button is pressed + + ldh [hCurSelectionItem], a + ldh [hTempPlayAreaLocation_ffa1], a + ld hl, hTemp_ffa0 + cp [hl] + jr z, .play_sfx ; can't select Slowbro itself + + call GetCardDamageAndMaxHP + or a + jr z, .play_sfx ; can't select card without damage + + call TryGiveDamageCounter_StrangeBehavior + jr c, .play_sfx + ld a, OPPACTION_6B15 + call SetOppAction_SerialSendDuelData + jr .start + +.play_sfx + call Func_3794 + jr .loop_input +; 0x2deb3 + +StrangeBehavior_SwapEffect: ; 2deb3 (b:5eb3) + call TryGiveDamageCounter_StrangeBehavior + ret c + bank1call PrintPlayAreaCardList_EnableLCD + or a + ret +; 0x2debc + +; tries to give the damage counter to the target +; chosen by the Player (hTemp_ffa0). +; if the damage counter would KO card, then do +; not give the damage counter and return carry. +TryGiveDamageCounter_StrangeBehavior: ; 2debc (b:5ebc) + ldh a, [hTemp_ffa0] + add DUELVARS_ARENA_CARD_HP + call GetTurnDuelistVariable + sub 10 + jr z, .set_carry ; would bring HP to zero? +; has enough HP to receive a damage counter + ld [hl], a + ldh a, [hTempPlayAreaLocation_ffa1] + add DUELVARS_ARENA_CARD_HP + ld l, a + ld a, 10 + add [hl] + ld [hl], a + or a + ret +.set_carry + scf + ret +; 0x2ded5 + +; returns carry if has no damage counters. +SpacingOut_CheckDamage: ; 2ded5 (b:5ed5) + ld e, PLAY_AREA_ARENA + call GetCardDamageAndMaxHP + ldtx hl, NoDamageCountersText + cp 10 + ret +; 0x2dee0 + +SpacingOut_Success50PercentEffect: ; 2dee0 (b:5ee0) + ldtx de, SuccessCheckIfHeadsAttackIsSuccessfulText + call TossCoin_BankB + ldh [hTemp_ffa0], a + jp nc, SetWasUnsuccessful + ld a, $58 + ld [wLoadedMoveAnimation], a + ret +; 0x2def1 + +SpacingOut_HealEffect: ; 2def1 (b:5ef1) + ldh a, [hTemp_ffa0] + or a + ret z ; coin toss was tails + ld e, PLAY_AREA_ARENA + call GetCardDamageAndMaxHP + or a + ret z ; no damage counters + ld a, DUELVARS_ARENA_CARD_HP + call GetTurnDuelistVariable + add 10 + ld [hl], a + ret +; 0x2df05 + +; sets carry if no Trainer cards in the Discard Pile. +Scavenge_CheckDiscardPile: ; 2df05 (b:5f05) + ld e, PLAY_AREA_ARENA + call GetPlayAreaCardAttachedEnergies + ld a, [wAttachedEnergies + PSYCHIC] + ldtx hl, NotEnoughPsychicEnergyText + cp 1 + ret c ; return if no Psychic energy attached + call CreateTrainerCardListFromDiscardPile + ldtx hl, ThereAreNoTrainerCardsInDiscardPileText ; this is redundant + ret +; 0x2df1a + +Scavenge_PlayerSelectEnergyEffect: ; 2df1a (b:5f1a) + ld a, TYPE_ENERGY_PSYCHIC + call CreateListOfEnergyAttachedToArena + xor a ; PLAY_AREA_ARENA + bank1call DisplayEnergyDiscardScreen + bank1call HandleEnergyDiscardMenuInput + ret c + ldh a, [hTempCardIndex_ff98] + ldh [hTemp_ffa0], a + or a + ret +; 0x2df2d + +Scavenge_AISelectEffect: ; 2df2d (b:5f2d) +; AI picks first Energy card in list + ld a, TYPE_ENERGY_PSYCHIC + call CreateListOfEnergyAttachedToArena + ld a, [wDuelTempList] + ldh [hTemp_ffa0], a +; AI picks first Trainer card in list + call CreateTrainerCardListFromDiscardPile + ld a, [wDuelTempList] + ldh [hTempPlayAreaLocation_ffa1], a + ret +; 0x2df40 + +Scavenge_DiscardEffect: ; 2df40 (b:5f40) + ldh a, [hTemp_ffa0] + call PutCardInDiscardPile + ret +; 0x2df46 + +Scavenge_PlayerSelectTrainerEffect: ; 2df46 (b:5f46) + call CreateTrainerCardListFromDiscardPile + bank1call Func_5591 + ldtx hl, PleaseSelectCardText + ldtx de, PlayerDiscardPileText + bank1call SetCardListHeaderText +.loop_input + bank1call DisplayCardList + jr c, .loop_input + ldh a, [hTempCardIndex_ff98] + ldh [hTempPlayAreaLocation_ffa1], a + ret +; 0x2df5f + +Scavenge_AddToHandEffect: ; 2df5f (b:5f5f) + ldh a, [hTempPlayAreaLocation_ffa1] + call MoveDiscardPileCardToHand + call AddCardToHand + call IsPlayerTurn + ret c + ldh a, [hTempPlayAreaLocation_ffa1] + ldtx hl, WasPlacedInTheHandText + bank1call DisplayCardDetailScreen + ret +; 0x2df74 + +; returns carry if Defending Pokemon has no attacks +SlowpokeAmnesia_CheckAttacks: ; 2df74 (b:5f74) + call CheckIfDefendingPokemonHasAnyAttack + ldtx hl, NoAttackMayBeChoosenText + ret +; 0x2df7b + +SlowpokeAmnesia_PlayerSelectEffect: ; 2df7b (b:5f7b) + call PlayerPickAttackForAmnesia + ret +; 0x2df7f + +SlowpokeAmnesia_AISelectEffect: ; 2df7f (b:5f7f) + call AIPickAttackForAmnesia + ldh [hTemp_ffa0], a + ret +; 0x2df85 + +SlowpokeAmnesia_DisableEffect: ; 2df85 (b:5f85) + call ApplyAmnesiaToAttack + ret +; 0x2df89 + +; returns carry if Arena card has no Psychic Energy attached +; or if it doesn't have any damage counters. +KadabraRecover_CheckEnergyHP: ; 2df89 (b:5f89) + ld e, PLAY_AREA_ARENA + call GetPlayAreaCardAttachedEnergies + ld a, [wAttachedEnergies + PSYCHIC] + ldtx hl, NotEnoughPsychicEnergyText + cp 1 + ret c ; return if not enough energy + call GetCardDamageAndMaxHP + ldtx hl, NoDamageCountersText + cp 10 + ret ; return carry if no damage +; 0x2dfa0 + +KadabraRecover_PlayerSelectEffect: ; 2dfa0 (b:5fa0) + ld a, TYPE_ENERGY_PSYCHIC + call CreateListOfEnergyAttachedToArena + xor a ; PLAY_AREA_ARENA + bank1call DisplayEnergyDiscardScreen + bank1call HandleEnergyDiscardMenuInput + ret c + ldh a, [hTempCardIndex_ff98] + ldh [hTemp_ffa0], a ; store card chosen + ret +; 0x2dfb2 + +KadabraRecover_AISelectEffect: ; 2dfb2 (b:5fb2) + ld a, TYPE_ENERGY_PSYCHIC + call CreateListOfEnergyAttachedToArena + ld a, [wDuelTempList] ; pick first card + ldh [hTemp_ffa0], a + ret +; 0x2dfbd + +KadabraRecover_DiscardEffect: ; 2dfbd (b:5fbd) + ldh a, [hTemp_ffa0] + call PutCardInDiscardPile + ret +; 0x2dfc3 + +KadabraRecover_HealEffect: ; 2dfc3 (b:5fc3) + ld e, PLAY_AREA_ARENA + call GetCardDamageAndMaxHP + ld e, a ; all damage for recovery + ld d, 0 + call ApplyAndAnimateHPRecovery + ret +; 0x2dfd7 + +JynxDoubleslap_AIEffect: ; 2dfd7 (b:5fd7) + ld a, 20 / 2 + lb de, 0, 20 + jp SetExpectedAIDamage +; 0x2dfcf + +JynxDoubleslap_MultiplierEffect: ; 2dfcf (b:5fcf) + ld hl, 10 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsXDamageText + ld a, 2 + call TossCoinATimes_BankB + call ATimes10 + call SetDefiniteDamage + ret +; 0x2dff2 + +JynxMeditate_AIEffect: ; 2dff2 (b:5ff2) + call JynxMeditate_DamageBoostEffect + jp SetMinMaxDamageSameAsDamage +; 0x2dfec + +JynxMeditate_DamageBoostEffect: ; 2dfec (b:5fec) +; add damage counters of Defending card to damage + call SwapTurn + ld e, PLAY_AREA_ARENA + call GetCardDamageAndMaxHP + call SwapTurn + call AddToDamage + ret +; 0x2e001 + +MysteryAttack_AIEffect: ; 2e001 (b:6001) + ld a, 10 + lb de, 0, 20 + jp SetExpectedAIDamage +; 0x2e009 + +MysteryAttack_RandomEffect: ; 2e009 (b:6009) + ld a, 10 + call SetDefiniteDamage + +; chooses a random effect from 8 possible options. + call UpdateRNGSources + and %111 + ldh [hTemp_ffa0], a + ld hl, .random_effect + jp JumpToFunctionInTable + +.random_effect + dw ParalysisEffect + dw PoisonEffect + dw SleepEffect + dw ConfusionEffect + dw .no_effect ; this will actually activate recovery effect afterwards + dw .no_effect + dw .more_damage + dw .no_damage + +.more_damage + ld a, 20 + call SetDefiniteDamage + ret + +.no_damage + ld a, $5b + ld [wLoadedMoveAnimation], a + xor a + call SetDefiniteDamage + call SetNoEffectFromStatus +.no_effect + ret +; 0x2e03e + +MysteryAttack_RecoverEffect: ; 2e03e (b:603e) +; in case the 5th option was chosen for random effect, +; trigger recovery effect for 10 HP. + ldh a, [hTemp_ffa0] + cp 4 + ret nz + lb de, 0, 10 + call ApplyAndAnimateHPRecovery + ret +; 0x2e04a + +StoneBarrage_AIEffect: ; 2e04a (b:604a) + ld a, 10 + lb de, 0, 100 + jp SetExpectedAIDamage +; 0x2e052 + +StoneBarrage_MultiplierEffect: ; 2e052 (b:6052) + xor a + ldh [hTemp_ffa0], a +.loop_coin_toss + ldtx de, FlipUntilFailAppears10DamageForEachHeadsText + xor a + call TossCoinATimes_BankB + jr nc, .tails + ld hl, hTemp_ffa0 + inc [hl] ; increase heads count + jr .loop_coin_toss + +.tails +; store resulting damage + ldh a, [hTemp_ffa0] + ld l, a + ld h, 10 + call HtimesL + ld de, wDamage + ld a, l + ld [de], a + inc de + ld a, h + ld [de], a + ret +; 0x2e075 + +OnixHardenEffect: ; 2e075 (b:6075) + ld a, SUBSTATUS1_HARDEN + call ApplySubstatus1ToDefendingCard + ret +; 0x2e07b + +PrimeapeFurySwipes_AIEffect: ; 2e07b (b:607b) + ld a, 60 / 2 + lb de, 0, 60 + jp SetExpectedAIDamage +; 0x2e083 + +PrimeapeFurySwipes_MultiplierEffect: ; 2e083 (b:6083) + ld hl, 20 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsXDamageText + ld a, 3 + call TossCoinATimes_BankB + add a + call ATimes10 + call SetDefiniteDamage + ret +; 0x2e099 + +TantrumEffect: ; 2e099 (b:6099) + ldtx de, IfTailsYourPokemonBecomesConfusedText + call TossCoin_BankB + ret c ; return if heads +; confuse Pokemon + ld a, $29 + ld [wLoadedMoveAnimation], a + call SwapTurn + call ConfusionEffect + call SwapTurn + ret +; 0x2e0af + +StrikesBackEffect: ; 2e0af (b:60af) + scf + ret +; 0x2e0b1 + +KabutoArmorEffect: ; 2e0b1 (b:60b1) + scf + ret +; 0x2e0b3 + +AbsorbEffect: ; 2e0b3 (b:60b3) + ld hl, wDealtDamage + ld a, [hli] + ld h, [hl] + ld l, a + srl h + rr l + bit 0, l + jr z, .rounded + ; round up to nearest 10 + ld de, 5 + add hl, de +.rounded + ld e, l + ld d, h + call ApplyAndAnimateHPRecovery + ret +; 0x2e0cb + +SnivelEffect: ; 2e0cb (b:60cb) + ld a, SUBSTATUS2_REDUCE_BY_20 + call ApplySubstatus2ToDefendingCard + ret +; 0x2e0d1 + +CuboneRage_AIEffect: ; 2e0d1 (b:60d1) + call CuboneRage_DamageBoostEffect + jp SetMinMaxDamageSameAsDamage +; 0x2e0d7 + +CuboneRage_DamageBoostEffect: ; 2e0d7 (b:60d7) + ld e, PLAY_AREA_ARENA + call GetCardDamageAndMaxHP + call AddToDamage + ret +; 0x2e0e0 + +Bonemerang_AIEffect: ; 2e0e0 (b:60e0) + ld a, 60 / 2 + lb de, 0, 60 + jp SetExpectedAIDamage +; 0x2e0e8 + +Bonemerang_MultiplierEffect: ; 2e0e8 (b:60e8) + ld hl, 30 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsXDamageText + ld a, 2 + call TossCoinATimes_BankB + ld e, a + add a ; a = 2 * heads + add e ; a = 3 * heads + call ATimes10 + call SetDefiniteDamage + ret +; 0x2e100 + +; returns carry if can't add Pokemon from deck +MarowakCallForFamily_CheckDeckAndPlayArea: ; 2e100 (b:6100) + call CheckIfDeckIsEmpty + ret c ; no cards in deck + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ldtx hl, NoSpaceOnTheBenchText + cp MAX_PLAY_AREA_POKEMON + ccf + ret +; 0x2e110 + +MarowakCallForFamily_PlayerSelectEffect: ; 2e110 (b:6110) + ld a, $ff + ldh [hTemp_ffa0], a + + call CreateDeckCardList + ldtx hl, ChooseBasicFightingPokemonFromDeckText + ldtx bc, FightingPokemonDeckText + lb de, SEARCHEFFECT_BASIC_FIGHTING, $00 + call LookForCardsInDeck + ret c + +; draw Deck list interface and print text + bank1call Func_5591 + ldtx hl, ChooseBasicFightingPokemonText + ldtx de, DuelistDeckText + bank1call SetCardListHeaderText + +.loop + bank1call DisplayCardList + jr c, .pressed_b + + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Type] + cp FIGHTING + jr nz, .play_sfx ; is Fighting? + ld a, [wLoadedCard2Stage] + or a + jr nz, .play_sfx ; is Basic? + ldh a, [hTempCardIndex_ff98] + ldh [hTemp_ffa0], a + or a + ret + +.play_sfx + ; play SFX and loop back + call Func_3794 + jr .loop + +.pressed_b +; figure if Player can exit the screen without selecting, +; that is, if the Deck has no Basic Fighting Pokemon. + ld a, DUELVARS_CARD_LOCATIONS + call GetTurnDuelistVariable +.loop_b_press + ld a, [hl] + cp CARD_LOCATION_DECK + jr nz, .next + ld a, l + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard1Type] + cp FIGHTING + jr nz, .next ; found, go back to top loop + ld a, [wLoadedCard1Stage] + or a + jr z, .play_sfx ; found, go back to top loop +.next + inc l + ld a, l + cp DECK_SIZE + jr c, .loop_b_press + +; no valid card in Deck, can safely exit screen + ld a, $ff + ldh [hTemp_ffa0], a + or a + ret +; 0x2e177 + +MarowakCallForFamily_AISelectEffect: ; 2e177 (b:6177) + call CreateDeckCardList + ld hl, wDuelTempList +.loop_deck + ld a, [hli] + ldh [hTemp_ffa0], a + cp $ff + ret z ; none found + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Type] + cp FIGHTING + jr nz, .loop_deck + ld a, [wLoadedCard2Stage] + or a + jr nz, .loop_deck +; found + ret +; 0x2e194 + +MarowakCallForFamily_PutInPlayAreaEffect: ; 2e194 (b:6194) + ldh a, [hTemp_ffa0] + cp $ff jr z, .shuffle + call SearchCardInDeckAndAddToHand + call AddCardToHand + call PutHandPokemonCardInPlayArea + call IsPlayerTurn + jr c, .shuffle + ; display card on screen + ldh a, [hTemp_ffa0] + ldtx hl, PlacedOnTheBenchText + bank1call DisplayCardDetailScreen +.shuffle + call Func_2c0bd + ret +; 0x2c1b4 + +KarateChop_AIEffect: ; 2e1b4 (b:61b4) + call KarateChop_DamageSubtractionEffect + jp SetMinMaxDamageSameAsDamage +; 0x2e1ba + +KarateChop_DamageSubtractionEffect: ; 2e1ba (b:61ba) + ld e, PLAY_AREA_ARENA + call GetCardDamageAndMaxHP + ld e, a + ld hl, wDamage + ld a, [hl] + sub e + ld [hli], a + ld a, [hl] + sbc 0 + ld [hl], a + rla + ret nc +; cap it to 0 damage + xor a + call SetDefiniteDamage + ret +; 0x2e1d1 + +SubmissionEffect: ; 2e1d1 (b:61d1) + ld a, 20 + call DealRecoilDamageToSelf + ret +; 0x2e1d7 + +GolemSelfdestructEffect: ; 2e1d7 (b:61d7) + ld a, 100 + call DealRecoilDamageToSelf + ld a, $01 + ld [wIsDamageToSelf], a + ld a, 20 + call DealDamageToAllBenchedPokemon + call SwapTurn + xor a + ld [wIsDamageToSelf], a + ld a, 20 + call DealDamageToAllBenchedPokemon + call SwapTurn + ret +; 0x2e1f6 + +GravelerHardenEffect: ; 2e1f6 (b:61f6) + ld a, SUBSTATUS1_HARDEN + call ApplySubstatus1ToDefendingCard + ret +; 0x2e1fc + +Ram_SelectSwitchEffect: ; 2e1fc (b:61fc) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetNonTurnDuelistVariable + cp 2 + jr c, .no_bench + call DuelistSelectForcedSwitch + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + ret +.no_bench + ld a, $ff + ldh [hTemp_ffa0], a + ret +; 0x2e212 + +Ram_RecoilSwitchEffect: ; 2e212 (b:6212) + ld a, 20 + call DealRecoilDamageToSelf + ldh a, [hTemp_ffa0] + call HandleSwitchDefendingPokemonEffect + ret +; 0x2e21d + +LeerEffect: ; 2e21d (b:621d) + ldtx de, IfHeadsOpponentCannotAttackText + call TossCoin_BankB + jp nc, SetWasUnsuccessful + ld a, $74 + ld [wLoadedMoveAnimation], a + ld a, SUBSTATUS2_LEER + call ApplySubstatus2ToDefendingCard + ret +; 0x2e231 + +; return carry if opponent has no Bench Pokemon. +StretchKick_CheckBench: ; 2e231 (b:6231) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetNonTurnDuelistVariable + ldtx hl, EffectNoPokemonOnTheBenchText + cp 2 + ret +; 0x2e23c + +StretchKick_PlayerSelectEffect: ; 2e23c (b:623c) + ldtx hl, ChoosePkmnInTheBenchToGiveDamageText + call DrawWideTextBox_WaitForInput + call SwapTurn + bank1call HasAlivePokemonInBench +.loop_input + bank1call OpenPlayAreaScreenForSelection + jr c, .loop_input + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + call SwapTurn + ret +; 0x2e255 + +StretchKick_AISelectEffect: ; 2e255 (b:6255) +; chooses Bench Pokemon with least amount of remaining HP + call GetBenchPokemonWithLowestHP + ldh [hTemp_ffa0], a + ret +; 0x2e25b + +StretchKick_BenchDamageEffect: ; 2e25b (b:625b) + call SwapTurn + ldh a, [hTemp_ffa0] + ld b, a + ld de, 20 + call DealDamageToPlayAreaPokemon_RegularAnim + call SwapTurn + ret +; 0x2e26b + +SandAttackEffect: ; 2e26b (b:626b) + ld a, SUBSTATUS2_SAND_ATTACK + call ApplySubstatus2ToDefendingCard + ret +; 0x2e271 + +SandslashFurySwipes_AIEffect: ; 2e271 (b:6271) + ld a, 60 / 2 + lb de, 0, 60 + jp SetExpectedAIDamage +; 0x2e279 + +SandslashFurySwipes_MultiplierEffect: ; 2e279 (b:6279) + ld hl, 20 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsXDamageText + ld a, 3 + call TossCoinATimes_BankB + add a + call ATimes10 + call SetDefiniteDamage + ret +; 0x2e28f + +EarthquakeEffect: ; 2e28f (b:628f) + ld a, $01 + ld [wIsDamageToSelf], a + ld a, 10 + call DealDamageToAllBenchedPokemon + ret +; 0x2e29a + +PrehistoricPowerEffect: ; 2e29a (b:629a) + scf + ret +; 0x2e29c + +; returns carry if Pkmn Power can't be used. +Peek_OncePerTurnCheck: ; 2e29c (b:629c) + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + add DUELVARS_ARENA_CARD_FLAGS + call GetTurnDuelistVariable + and USED_PKMN_POWER_THIS_TURN + jr nz, .already_used + ldh a, [hTempPlayAreaLocation_ff9d] + call CheckCannotUseDueToStatus_OnlyToxicGasIfANon0 + ret +.already_used + ldtx hl, OnlyOncePerTurnText + scf + ret +; 0x2e2b4 + +Peek_SelectEffect: ; 2e2b4 (b:62b4) +; set Pkmn Power used flag + ldh a, [hTemp_ffa0] + add DUELVARS_ARENA_CARD_FLAGS + call GetTurnDuelistVariable + set USED_PKMN_POWER_THIS_TURN_F, [hl] + + ld a, DUELVARS_DUELIST_TYPE + call GetTurnDuelistVariable + cp DUELIST_TYPE_LINK_OPP + jr z, .link_opp + and DUELIST_TYPE_AI_OPP + jr nz, .ai_opp + +; player + call Func_3b31 + call Func_30e7 + ldh [hAIPkmnPowerEffectParam], a + call SerialSend8Bytes + ret + +.link_opp + call SerialRecv8Bytes + ldh [hAIPkmnPowerEffectParam], a + +.ai_opp + ldh a, [hAIPkmnPowerEffectParam] + bit AI_PEEK_TARGET_HAND_F, a + jr z, .prize_or_deck + and (~AI_PEEK_TARGET_HAND & $ff) ; unset bit to get deck index +; if masked value is higher than $40, then it means +; that AI chose to look at Player's deck. +; all deck indices will be smaller than $40. + cp $40 + jr c, .hand + ldh a, [hAIPkmnPowerEffectParam] + jr .prize_or_deck + +.hand +; AI chose to look at random card in hand, +; so display it to the Player on screen. + call SwapTurn + ldtx hl, PeekWasUsedToLookInYourHandText + bank1call DisplayCardDetailScreen + call SwapTurn + ret + +.prize_or_deck +; AI chose either a prize card or Player's top deck card, +; so show Play Area and draw cursor appropriately. + call Func_3b31 + call SwapTurn + ldh a, [hAIPkmnPowerEffectParam] + xor $80 + call Func_30f9 + call SwapTurn + ldtx hl, CardPeekWasUsedOnText + call DrawWideTextBox_WaitForInput + ret +; 0x2e30f + +BoneAttackEffect: ; 2e30f (b:630f) + ldtx de, IfHeadsOpponentCannotAttackText + call TossCoin_BankB + ret nc + ld a, SUBSTATUS2_BONE_ATTACK + call ApplySubstatus2ToDefendingCard + ret +; 0x2e31c + +; return carry if neither Play Area +; has room for more Bench Pokemon. +Wail_BenchCheck: ; 2e31c (b:631c) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + cp MAX_PLAY_AREA_POKEMON + jr c, .no_carry + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetNonTurnDuelistVariable + cp MAX_PLAY_AREA_POKEMON + jr c, .no_carry + ldtx hl, NoSpaceOnTheBenchText + scf + ret +.no_carry + or a + ret +; 0x2e335 + +Wail_FillBenchEffect: ; 2e335 (b:6335) + call SwapTurn + call .FillBench + call SwapTurn + call .FillBench + +; display both Play Areas + ldtx hl, BasicPokemonWasPlacedOnEachBenchText + call DrawWideTextBox_WaitForInput + bank1call HasAlivePokemonInPlayArea + bank1call OpenPlayAreaScreenForSelection + call SwapTurn + bank1call HasAlivePokemonInPlayArea + bank1call OpenPlayAreaScreenForSelection + call SwapTurn + ret + +.FillBench ; 2e35a (b:635a) + call CreateDeckCardList + ret c + ld hl, wDuelTempList + call ShuffleCards + +; if no more space in the Bench, then return. +.check_bench + push hl + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + pop hl + cp MAX_PLAY_AREA_POKEMON + jr nc, .done + +; there's still space, so look for the next +; Basic Pokemon card to put in the Bench. +.loop + ld a, [hli] + ldh [hTempCardIndex_ff98], a + cp $ff + jr z, .done + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Type] + cp TYPE_ENERGY + jr nc, .loop ; is Pokemon card? + ld a, [wLoadedCard2Stage] + or a + jr nz, .loop ; is Basic? +; place card in Bench + push hl + ldh a, [hTempCardIndex_ff98] + call SearchCardInDeckAndAddToHand + call AddCardToHand + call PutHandPokemonCardInPlayArea + pop hl + jr .check_bench + +.done + call Func_2c0bd + ret +; 0x2e399 + +Thunderpunch_AIEffect: ; 2e399 (b:6399) + ld a, (30 + 40) / 2 + lb de, 30, 40 + jp SetExpectedAIDamage +; 0x2e3a1 + +Thunderpunch_ModifierEffect: ; 2e3a1 (b:63a1) + ldtx de, IfHeadPlus10IfTails10ToYourselfText + call TossCoin_BankB + ldh [hTemp_ffa0], a + ret nc ; return if got tails + ld a, 10 + call AddToDamage + ret +; 0x2e3b0 + +Thunderpunch_RecoilEffect: ; 2e3b0 (b:63b0) + ldh a, [hTemp_ffa0] + or a + ret nz ; return if got heads + ld a, 10 + call DealRecoilDamageToSelf + ret +; 0x2e3ba + +LightScreenEffect: ; 2e3ba (b:63ba) + ld a, SUBSTATUS1_HALVE_DAMAGE + call ApplySubstatus1ToDefendingCard + ret +; 0x2e3c0 + +ElectabuzzQuickAttack_AIEffect: ; 2e3c0 (b:63c0) + ld a, (10 + 30) / 2 + lb de, 10, 30 + jp SetExpectedAIDamage +; 0x2e3c8 + +ElectabuzzQuickAttack_DamageBoostEffect: ; 2e3c8 (b:63c8) + ld hl, 20 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsPlusDamageText + call TossCoin_BankB + ret nc ; return if tails + ld a, 20 + call AddToDamage + ret +; 0x2e3db + +MagnemiteSelfdestructEffect: ; 2e3db (b:63db) + ld a, 40 + call DealRecoilDamageToSelf + + ld a, $01 + ld [wIsDamageToSelf], a + ld a, 10 + call DealDamageToAllBenchedPokemon + call SwapTurn + + xor a + ld [wIsDamageToSelf], a + ld a, 10 + call DealDamageToAllBenchedPokemon + call SwapTurn + ret +; 0x2e3fa + +ZapdosThunder_Recoil50PercentEffect: ; 2e3fa (b:63fa) + ld hl, 30 + call LoadTxRam3 + ldtx de, IfTailsDamageToYourselfTooText + call TossCoin_BankB + ldh [hTemp_ffa0], a + ret +; 0x2e409 + +ZapdosThunder_RecoilEffect: ; 2e409 (b:6409) + ld hl, 30 + call LoadTxRam3 + ldh a, [hTemp_ffa0] + or a + ret nz ; return if got heads + ld a, 30 + call DealRecoilDamageToSelf + ret +; 0x2e419 + +ThunderboltEffect: ; 2e419 (b:6419) + xor a + call CreateArenaOrBenchEnergyCardList + ld hl, wDuelTempList +; put all energy cards in Discard Pile +.loop + ld a, [hli] + cp $ff + ret z + call PutCardInDiscardPile + jr .loop +; 0x2e429 + +ThunderstormEffect: ; 2e429 (b:6429) + ld a, 1 + ldh [hCurSelectionItem], a + + call SwapTurn + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ld c, a + ld b, 0 + ld e, b + jr .next_pkmn + +.check_damage + push de + push bc + call .DisplayText + ld de, $0 + call SwapTurn + call TossCoin_BankB + call SwapTurn + push af + call GetNextPositionInTempList + pop af + ld [hl], a ; store result in list + pop bc + pop de + jr c, .next_pkmn + inc b ; increase number of tails + +.next_pkmn + inc e + dec c + jr nz, .check_damage + +; all coins were tossed for each Benched Pokemon + call GetNextPositionInTempList + ld [hl], $ff + ld a, b + ldh [hTemp_ffa0], a + call Func_3b21 + call SwapTurn + +; tally recoil damage + ldh a, [hTemp_ffa0] + or a + jr z, .skip_recoil + ; deal number of tails times 10 to self + call ATimes10 + call DealRecoilDamageToSelf +.skip_recoil + +; deal damage for Bench Pokemon that got heads + call SwapTurn + ld hl, hTempPlayAreaLocation_ffa1 + ld b, PLAY_AREA_BENCH_1 +.loop_bench + ld a, [hli] + cp $ff + jr z, .done + or a + jr z, .skip_damage ; skip if tails + ld de, 20 + call DealDamageToPlayAreaPokemon_RegularAnim +.skip_damage + inc b + jr .loop_bench + +.done + call SwapTurn + ret +; 0x2e491 + +; displays text for current Bench Pokemon, +; printing its Bench number and name. +.DisplayText ; 2e491 (b:6491) + ld b, e + ldtx hl, BenchText + ld de, wDefaultText + call CopyText + ld a, $30 ; 0 FW character + add b + ld [de], a + inc de + ld a, $20 ; space FW character + ld [de], a + inc de + + ld a, DUELVARS_ARENA_CARD + add b + call GetTurnDuelistVariable + call LoadCardDataToBuffer2_FromDeckIndex + ld hl, wLoadedCard2Name + ld a, [hli] + ld h, [hl] + ld l, a + call CopyText + + xor a + ld [wDuelDisplayedScreen], a + ret +; 0x2e4bb + +JolteonQuickAttack_AIEffect: ; 2e4bb (b:64bb) + ld a, (10 + 30) / 2 + lb de, 10, 30 + jp SetExpectedAIDamage +; 0x2e4c3 + +JolteonQuickAttack_DamageBoostEffect: ; 2e4c3 (b:64c3) + ld hl, 20 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsPlusDamageText + call TossCoin_BankB + ret nc ; return if tails + ld a, 20 + call AddToDamage + ret +; 0x2e3d6 + +PinMissile_AIEffect: ; 2e4d6 (b:64d6) + ld a, (20 * 4) / 2 + lb de, 0, 80 + jp SetExpectedAIDamage +; 0x2e4de + +PinMissile_MultiplierEffect: ; 2e4de (b:64de) + ld hl, 20 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsXDamageText + ld a, 4 + call TossCoinATimes_BankB + add a ; a = 2 * heads + call ATimes10 + call SetDefiniteDamage + ret +; 0x2e4f4 + +Fly_AIEffect: ; 2e4f4 (b:64f4) + ld a, 30 / 2 + lb de, 0, 30 + jp SetExpectedAIDamage +; 0x2e4fc + +Fly_Success50PercentEffect: ; 2e4fc (b:64fc) + ldtx de, SuccessCheckIfHeadsAttackIsSuccessfulText + call TossCoin_BankB + jr c, .heads + xor a + ld [wLoadedMoveAnimation], a + call SetDefiniteDamage + call SetWasUnsuccessful + ret +.heads + ld a, $52 + ld [wLoadedMoveAnimation], a + ld a, SUBSTATUS1_FLY + call ApplySubstatus1ToDefendingCard + ret +; 0x2e51a + +ThunderJolt_Recoil50PercentEffect: ; 2e51a (b:651a) + ld hl, 10 + call LoadTxRam3 + ldtx de, IfTailsDamageToYourselfTooText + call TossCoin_BankB + ldh [hTemp_ffa0], a + ret +; 0x2e529 + +ThunderJolt_RecoilEffect: ; 2e529 (b:6529) + ld hl, 10 + call LoadTxRam3 + ldh a, [hTemp_ffa0] + or a + ret nz ; return if was heads + ld a, 10 + call DealRecoilDamageToSelf + ret +; 0x2e539 + +Spark_PlayerSelectEffect: ; 2e539 (b:6539) + ld a, $ff + ldh [hTemp_ffa0], a + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetNonTurnDuelistVariable + cp 2 + ret c ; has no Bench Pokemon + + ldtx hl, ChoosePkmnInTheBenchToGiveDamageText + call DrawWideTextBox_WaitForInput + call SwapTurn + bank1call HasAlivePokemonInBench + + ; the following two instructions can be removed + ; since Player selection will overwrite it. + ld a, PLAY_AREA_BENCH_1 + ldh [hTempPlayAreaLocation_ff9d], a + +.loop_input + bank1call OpenPlayAreaScreenForSelection + jr c, .loop_input + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + call SwapTurn + ret +; 0x2e562 + +Spark_AISelectEffect: ; 2e562 (b:6562) + ld a, $ff + ldh [hTemp_ffa0], a + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetNonTurnDuelistVariable + cp 2 + ret c ; has no Bench Pokemon +; AI always picks Pokemon with lowest HP remaining + call GetBenchPokemonWithLowestHP + ldh [hTemp_ffa0], a + ret +; 0x2e574 + +Spark_BenchDamageEffect: ; 2e574 (b:6574) + ldh a, [hTemp_ffa0] + cp $ff + ret z + call SwapTurn + ldh a, [hTemp_ffa0] + ld b, a + ld de, 10 + call DealDamageToPlayAreaPokemon_RegularAnim + call SwapTurn + ret +; 0x2e589 + +Pikachu3GrowlEffect: ; 2e589 (b:6589) + ld a, SUBSTATUS2_GROWL + call ApplySubstatus2ToDefendingCard + ret +; 0x2e58f + +Pikachu4GrowlEffect: ; 2e58f (b:658f) + ld a, SUBSTATUS2_GROWL + call ApplySubstatus2ToDefendingCard + ret +; 0x2e595 + +ChainLightningEffect: ; 2e595 (b:6595) + ld a, 10 + call SetDefiniteDamage + call SwapTurn + call GetArenaCardColor + call SwapTurn + ldh [hCurSelectionItem], a + cp COLORLESS + ret z ; don't damage if colorless + +; opponent's Bench + call SwapTurn + call .DamageSameColorBench + call SwapTurn + +; own Bench + ld a, $01 + ld [wIsDamageToSelf], a + call .DamageSameColorBench + ret +; 0x2e5ba + +.DamageSameColorBench ; 2e5ba (b:65ba) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ld e, a + ld d, PLAY_AREA_ARENA + jr .next_bench + +.check_damage + ld a, d + call GetPlayAreaCardColor + ld c, a + ldh a, [hCurSelectionItem] + cp c + jr nz, .next_bench ; skip if not same color +; apply damage to this Bench card + push de + ld b, d + ld de, 10 + call DealDamageToPlayAreaPokemon_RegularAnim + pop de + +.next_bench + inc d + dec e + jr nz, .check_damage + ret +; 0x2e5dc + +RaichuAgilityEffect: ; 2e5dc (b:65dc) + ldtx de, IfHeadsDoNotReceiveDamageOrEffectText + call TossCoin_BankB + ret nc ; skip if got tails + ld a, $52 + ld [wLoadedMoveAnimation], a + ld a, SUBSTATUS1_AGILITY + call ApplySubstatus1ToDefendingCard + ret +; 0x2e5ee + +RaichuThunder_Recoil50PercentEffect: ; 2e5ee (b:65ee) + ld hl, 30 + call LoadTxRam3 + ldtx de, IfTailsDamageToYourselfTooText + call TossCoin_BankB + ldh [hTemp_ffa0], a + ret +; 0x2e5fd + +RaichuThunder_RecoilEffect: ; 2e5fd (b:65fd) + ld hl, 30 + call LoadTxRam3 + ldh a, [hTemp_ffa0] + or a + ret nz ; return if got heads + ld a, 30 + call DealRecoilDamageToSelf + ret +; 0x2e60d + +Gigashock_PlayerSelectEffect: ; 2e60d (b:660d) + call SwapTurn + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + cp 2 + jr nc, .has_bench + call SwapTurn + ld a, $ff + ldh [hTempList], a + ret + +.has_bench + ldtx hl, ChooseUpTo3PkmnOnBenchToGiveDamageText + call DrawWideTextBox_WaitForInput + +; init number of items in list and cursor position + xor a + ldh [hCurSelectionItem], a + ld [wce72], a + bank1call Func_61a1 +.start + bank1call PrintPlayAreaCardList_EnableLCD + push af + ld a, [wce72] + ld hl, BenchSelectionMenuParameters + call InitializeMenuParameters + pop af + +; exclude Arena Pokemon from number of items + dec a + ld [wNumMenuItems], a + +.loop_input + call DoFrame + call HandleMenuInput + jr nc, .loop_input + cp -1 + jr z, .try_cancel + + ld [wce72], a + call .CheckIfChosenAlready + jr nc, .not_chosen + ; play SFX + call Func_3794 + jr .loop_input + +.not_chosen +; mark this Play Area location + ldh a, [hCurMenuItem] + inc a + ld b, SYM_LIGHTNING + call DrawSymbolOnPlayAreaCursor +; store it in the list of chosen Bench Pokemon + call GetNextPositionInTempList + ldh a, [hCurMenuItem] + inc a + ld [hl], a + +; check if 3 were chosen already + ldh a, [hCurSelectionItem] + ld c, a + cp 3 + jr nc, .chosen ; check if already chose 3 + + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + dec a + cp c + jr nz, .start ; if sill more options available, loop back + ; fallthrough if no other options available to choose + +.chosen + ldh a, [hCurMenuItem] + inc a + call Func_2c10b + ldh a, [hKeysPressed] + and B_BUTTON + jr nz, .try_cancel + call SwapTurn + call GetNextPositionInTempList + ld [hl], $ff ; terminating byte + ret + +.try_cancel + ldh a, [hCurSelectionItem] + or a + jr z, .start ; none selected, can safely loop back to start + +; undo last selection made + dec a + ldh [hCurSelectionItem], a + ld e, a + ld d, $00 + ld hl, hTempList + add hl, de + ld a, [hl] + + push af + ld b, SYM_SPACE + call DrawSymbolOnPlayAreaCursor + call EraseCursor + pop af + + dec a + ld [wce72], a + jr .start +; 0x2e6af + +; returns carry if Bench Pokemon +; in register a was already chosen. +.CheckIfChosenAlready: ; 2e6af (b:66af) + inc a + ld c, a + ldh a, [hCurSelectionItem] + ld b, a + ld hl, hTempList + inc b + jr .next_check +.check_chosen + ld a, [hli] + cp c + scf + ret z ; return if chosen already +.next_check + dec b + jr nz, .check_chosen + or a + ret +; 0x2e6c3 + +Gigashock_AISelectEffect: ; 2e6c3 (b:66c3) +; if Bench has 3 Pokemon or less, no need for selection, +; since AI will choose them all. + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetNonTurnDuelistVariable + cp MAX_PLAY_AREA_POKEMON - 1 + jr nc, .start_selection + +; select them all + ld hl, hTempList + ld b, PLAY_AREA_ARENA + jr .next_bench +.select_bench + ld [hl], b + inc hl +.next_bench + inc b + dec a + jr nz, .select_bench + ld [hl], $ff ; terminating byte + ret + +.start_selection +; has more than 3 Bench cards,proceed to sort them +; by lowest remaining HP to highest, and pick first 3. + call SwapTurn + dec a + ld c, a + ld b, PLAY_AREA_BENCH_1 + +; first select all of the Bench Pokemon and write to list + ld hl, hTempList +.loop_all + ld [hl], b + inc hl + inc b + dec c + jr nz, .loop_all + ld [hl], $00 ; end list with $00 + +; then check each of the Bench Pokemon HP +; sort them from lowest remaining HP to highest. + ld de, hTempList +.loop_outer + ld a, [de] + add DUELVARS_ARENA_CARD_HP + call GetTurnDuelistVariable + ld c, a + ld l, e + ld h, d + inc hl + +.loop_inner + ld a, [hli] + or a + jr z, .next ; reaching $00 means it's end of list + + push hl + add DUELVARS_ARENA_CARD_HP + call GetTurnDuelistVariable + pop hl + cp c + jr c, .loop_inner + ; a Bench Pokemon was found with less HP + ld c, a ; store its HP + +; switch the two + dec hl + ld b, [hl] + ld a, [de] + ld [hli], a + ld a, b + ld [de], a + jr .loop_inner + +.next + inc de + ld a, [de] + or a + jr nz, .loop_outer + +; done + ld a, $ff ; terminating byte + ldh [hTempList + 3], a + call SwapTurn + ret +; 0x2e71f + +Gigashock_BenchDamageEffect: ; 2e71f (b:671f) + call SwapTurn + ld hl, hTempList +.loop_selection + ld a, [hli] + cp $ff + jr z, .done + push hl + ld b, a + ld de, 10 + call DealDamageToPlayAreaPokemon_RegularAnim + pop hl + jr .loop_selection +.done + call SwapTurn + ret +; 0x2e739 + +Magneton1SelfdestructEffect: ; 2e739 (b:6739) + ld a, 80 + call DealRecoilDamageToSelf + +; own bench + ld a, $01 + ld [wIsDamageToSelf], a + ld a, 20 + call DealDamageToAllBenchedPokemon + +; opponent's bench + call SwapTurn + xor a + ld [wIsDamageToSelf], a + ld a, 20 + call DealDamageToAllBenchedPokemon + call SwapTurn + ret +; 0x2e758 + +MagnetonSonicboom_UnaffectedByColorEffect: ; 2e758 (b:6758) + ld hl, wDamage + 1 + set UNAFFECTED_BY_WEAKNESS_RESISTANCE_F, [hl] + ret +; 0x2e75e + +MagnetonSonicboom_NullEffect: ; 2e75e (b:675e) + ret +; 0x2e75f + +Magneton2SelfdestructEffect: ; 2e75f (b:675f) + ld a, 100 + call DealRecoilDamageToSelf + +; own bench + ld a, $01 + ld [wIsDamageToSelf], a + ld a, 20 + call DealDamageToAllBenchedPokemon + +; opponent's bench + call SwapTurn + xor a + ld [wIsDamageToSelf], a + ld a, 20 + call DealDamageToAllBenchedPokemon + call SwapTurn + ret +; 0x2e77e + +PealOfThunder_InitialEffect: ; 2e77e (b:677e) + scf + ret +; 0x2e780 + +PealOfThunder_RandomlyDamageEffect: ; 2e780 (b:6780) + call ExchangeRNG + ld de, 30 ; damage to inflict + call RandomlyDamagePlayAreaPokemon + bank1call Func_6e49 + ret +; 0x2e78d + +; randomly damages a Pokemon in play, except +; card that is in [hTempPlayAreaLocation_ff9d]. +; plays thunder animation when Play Area is shown. +; input: +; de = amount of damage to deal +RandomlyDamagePlayAreaPokemon: ; 2e78d (b:678d) + xor a + ld [wNoDamageOrEffect], a + +; choose randomly which Play Area to attack + call UpdateRNGSources + and 1 + jr nz, .opp_play_area + +; own Play Area + ld a, $01 + ld [wIsDamageToSelf], a + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + call Random + ld b, a + ; can't select Zapdos + ldh a, [hTempPlayAreaLocation_ff9d] + cp b + jr z, RandomlyDamagePlayAreaPokemon ; re-roll Pokemon to attack + +.damage + ld a, $82 + ld [wLoadedMoveAnimation], a + call DealDamageToPlayAreaPokemon + ret + +.opp_play_area + xor a + ld [wIsDamageToSelf], a + call SwapTurn + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + call Random + ld b, a + call .damage + call SwapTurn + ret +; 0x2e7cb + +BigThunderEffect: ; 2e7cb (b:67cb) + call ExchangeRNG + ld de, 70 ; damage to inflict + call RandomlyDamagePlayAreaPokemon + ret +; 0x2e7d5 + +MagneticStormEffect: ; 2e7d5 (b:67d5) + ld a, DUELVARS_CARD_LOCATIONS + call GetTurnDuelistVariable + +; writes in wDuelTempList all deck indices +; of Energy cards attached to Pokemon +; in the Turn Duelist's Play Area. + ld de, wDuelTempList + ld c, 0 +.loop_card_locations + ld a, [hl] + and CARD_LOCATION_PLAY_AREA + jr z, .next_card_location + +; is a card that is in the Play Area + push hl + push de + push bc + ld a, l + call GetCardIDFromDeckIndex + call GetCardType + pop bc + pop de + pop hl + and TYPE_ENERGY + jr z, .next_card_location +; is an Energy card attached to Pokemon in Play Area + ld a, l + ld [de], a + inc de + inc c +.next_card_location + inc l + ld a, l + cp DECK_SIZE + jr c, .loop_card_locations + ld a, $ff ; terminating byte + ld [de], a + +; divide number of energy cards +; by number of Pokemon in Play Area + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ld b, a + ld a, c + ld c, -1 +.loop_division + inc c + sub b + jr nc, .loop_division + ; c = floor(a / b) + +; evenly divides the Energy cards randomly +; to every Pokemon in the Play Area. + push bc + ld hl, wDuelTempList + call CountCardsInDuelTempList + call ShuffleCards + ld d, c + ld e, PLAY_AREA_ARENA +.start_attach + ld c, d + inc c + jr .check_done +.attach_energy + ld a, [hli] + push hl + push de + push bc + call AddCardToHand + call PutHandCardInPlayArea + pop bc + pop de + pop hl +.check_done + dec c + jr nz, .attach_energy +; go to next Pokemon in Play Area + inc e ; next in Play Area + dec b + jr nz, .start_attach + pop bc + + push hl + ld hl, hTempList + +; fill hTempList with PLAY_AREA_* locations +; that have Pokemon in them. + push hl + xor a +.loop_init + ld [hli], a + inc a + cp b + jr nz, .loop_init + pop hl + +; shuffle them and distribute +; the remaining cards in random order. + ld a, b + call ShuffleCards + pop hl + ld de, hTempList +.next_random_pokemon + ld a, [hl] + cp $ff + jr z, .done + push hl + push de + ld a, [de] + ld e, a + ld a, [hl] + call AddCardToHand + call PutHandCardInPlayArea + pop de + pop hl + inc hl + inc de + jr .next_random_pokemon + +.done + bank1call DrawDuelMainScene + bank1call DrawDuelHUDs + ldtx hl, TheEnergyCardFromPlayAreaWasMovedText + call DrawWideTextBox_WaitForInput + xor a + call Func_2c10b + ret +; 0x2e870 + +ElectrodeSonicboom_UnaffectedByColorEffect: ; 2e870 (b:6870) + ld hl, wDamage + 1 + set UNAFFECTED_BY_WEAKNESS_RESISTANCE_F, [hl] + ret +; 0x2e876 + +ElectrodeSonicboom_NullEffect: ; 2e876 (b:6876) + ret +; 0x2e877 + +; return carry if no cards in Deck +EnergySpike_DeckCheck: ; 2e877 (b:6877) + call CheckIfDeckIsEmpty + ret +; 0x2e87b + +EnergySpike_PlayerSelectEffect: ; 2e87b (b:687b) + ld a, $ff + ldh [hTemp_ffa0], a + +; search cards in Deck + call CreateDeckCardList + ldtx hl, Choose1BasicEnergyCardFromDeckText + ldtx bc, BasicEnergyText + lb de, SEARCHEFFECT_BASIC_ENERGY, 0 + call LookForCardsInDeck + ret c + + bank1call Func_5591 + ldtx hl, ChooseBasicEnergyCardText + ldtx de, DuelistDeckText + bank1call SetCardListHeaderText +.select_card + bank1call DisplayCardList + jr c, .try_cancel + call GetCardIDFromDeckIndex + call GetCardType + cp TYPE_ENERGY_DOUBLE_COLORLESS + jr nc, .select_card ; not a Basic Energy card + and TYPE_ENERGY + jr z, .select_card ; not a Basic Energy card + ; Energy card selected + + ldh a, [hTempCardIndex_ff98] + ldh [hTemp_ffa0], a + call EmptyScreen + ldtx hl, ChoosePokemonToAttachEnergyCardText + call DrawWideTextBox_WaitForInput + +; choose a Pokemon in Play Area to attach card + bank1call HasAlivePokemonInPlayArea +.loop_input + bank1call OpenPlayAreaScreenForSelection + jr c, .loop_input + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTempPlayAreaLocation_ffa1], a + ret + +.play_sfx + call Func_3794 + jr .select_card + +.try_cancel +; Player tried exiting screen, if there are +; any Basic Energy cards, Player is forced to select them. +; otherwise, they can safely exit. + ld a, DUELVARS_CARD_LOCATIONS + call GetTurnDuelistVariable +.loop_deck + ld a, [hl] + cp CARD_LOCATION_DECK + jr nz, .next_card + ld a, l + call GetCardIDFromDeckIndex + call GetCardType + and TYPE_ENERGY + jr z, .next_card + cp TYPE_ENERGY_DOUBLE_COLORLESS + jr c, .play_sfx +.next_card + inc l + ld a, l + cp DECK_SIZE + jr c, .loop_deck + ; can exit + + ld a, $ff + ldh [hTemp_ffa0], a + ret +; 0x2e8f1 + +EnergySpike_AISelectEffect: ; 2e8f1 (b:68f1) +; AI doesn't select any card + ld a, $ff + ldh [hTemp_ffa0], a + ret +; 0x2e8f6 + +EnergySpike_AttachEnergyEffect: ; 2e8f6 (b:68f6) + ldh a, [hTemp_ffa0] + cp $ff + jr z, .done + +; add card to hand and attach it to the selected Pokemon + call SearchCardInDeckAndAddToHand + call AddCardToHand + ldh a, [hTempPlayAreaLocation_ffa1] + ld e, a + ldh a, [hTemp_ffa0] + call PutHandCardInPlayArea + call IsPlayerTurn + jr c, .done + +; not Player, so show detail screen +; and which Pokemon was chosen to attach Energy. + ldh a, [hTempPlayAreaLocation_ffa1] + add DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + call LoadCardDataToBuffer1_FromDeckIndex + ld hl, wLoadedCard1Name + ld de, wTxRam2_b + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + ldh a, [hTemp_ffa0] + ldtx hl, AttachedEnergyToPokemonText + bank1call DisplayCardDetailScreen + +.done + call Func_2c0bd + ret +; 0x2e930 + +JolteonDoubleKick_AIEffect: ; 2e930 (b:6930) + ld a, 40 / 2 + lb de, 0, 40 + jp SetExpectedAIDamage +; 0x2e938 + +JolteonDoubleKick_MultiplierEffect: ; 2e938 (b:6938) + ld hl, 20 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsXDamageText + ld a, 2 + call TossCoinATimes_BankB + add a ; a = 2 * heads + call ATimes10 + call SetDefiniteDamage + ret +; 0x2e94e + +TailWagEffect: ; 2e94e (b:694e) + ldtx de, IfHeadsOpponentCannotAttackText + call TossCoin_BankB + jp nc, SetWasUnsuccessful + ld a, $46 + ld [wLoadedMoveAnimation], a + ld a, SUBSTATUS2_TAIL_WAG + call ApplySubstatus2ToDefendingCard + ret +; 0x2e962 + +EeveeQuickAttack_AIEffect: ; 2e962 (b:5962) + ld a, (10 + 30) / 2 + lb de, 10, 30 + jp SetExpectedAIDamage +; 0x2e96a + +EeveeQuickAttack_DamageBoostEffect: ; 2e96a (b:596a) + ld hl, 20 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsPlusDamageText + call TossCoin_BankB + ret nc ; return if tails + ld a, 20 + call AddToDamage + ret +; 0x2e97d + +SpearowMirrorMove_AIEffect: ; 2e97d (b:697d) + jr MirrorMoveEffects.AIEffect +; 0x2e97f + +SpearowMirrorMove_InitialEffect1: ; 2e97f (b:697f) + jr MirrorMoveEffects.InitialEffect1 +; 0x2e981 + +SpearowMirrorMove_InitialEffect2: ; 2e981 (b:6981) + jr MirrorMoveEffects.InitialEffect2 +; 0x2e983 + +SpearowMirrorMove_PlayerSelection: ; 2e983 (b:6983) + jr MirrorMoveEffects.PlayerSelection +; 0x2e985 + +SpearowMirrorMove_AISelection: ; 2e985 (b:6985) + jr MirrorMoveEffects.AISelection +; 0x2e987 + +SpearowMirrorMove_BeforeDamage: ; 2e987 (b:6987) + jr MirrorMoveEffects.BeforeDamage +; 0x2e989 + +SpearowMirrorMove_AfterDamage: ; 2e989 (b:6989) + jp MirrorMoveEffects.AfterDamage +; 0x2e98c + +; these are effect commands that Mirror Move uses +; in order to mimic last turn's attack. +; it covers all possible effect steps to perform its commands +; (i.e. selection for Amnesia and Energy discarding attacks, etc) +MirrorMoveEffects: ; 2e98c (b:698c) +.AIEffect + ld a, DUELVARS_ARENA_CARD_LAST_TURN_DAMAGE + call GetTurnDuelistVariable + ld a, [hl] + ld [wAIMinDamage], a + ld [wAIMaxDamage], a + ret + +.InitialEffect1 + ld a, DUELVARS_ARENA_CARD_LAST_TURN_DAMAGE + call GetTurnDuelistVariable + ld a, [hli] + or [hl] + inc hl + or [hl] + inc hl + ret nz ; return if has last turn damage + ld a, [hli] + or a + ret nz ; return if has last turn status + ; no attack received last turn + ldtx hl, YouDidNotReceiveAnAttackToMirrorMoveText + scf + ret + +.InitialEffect2 + ld a, $ff + ldh [hTemp_ffa0], a + ld a, DUELVARS_ARENA_CARD_LAST_TURN_EFFECT + call GetTurnDuelistVariable + or a + ret z ; no effect + cp LAST_TURN_EFFECT_AMNESIA + jp z, PlayerPickAttackForAmnesia + or a + ret + +.PlayerSelection + ld a, DUELVARS_ARENA_CARD_LAST_TURN_EFFECT + call GetTurnDuelistVariable + or a + ret z ; no effect +; handle Energy card discard effect + cp LAST_TURN_EFFECT_DISCARD_ENERGY + jp z, HandleEnergyDiscardEffectSelection + ret + +.AISelection + ld a, $ff + ldh [hTemp_ffa0], a + ld a, DUELVARS_ARENA_CARD_LAST_TURN_EFFECT + call GetTurnDuelistVariable + or a + ret z ; no effect + cp LAST_TURN_EFFECT_DISCARD_ENERGY + jr z, .dicard_energy + cp LAST_TURN_EFFECT_AMNESIA + jr z, .pick_amnesia_attack + ret + +.dicard_energy + call AIPickEnergyCardToDiscardFromDefendingPokemon + ldh [hTemp_ffa0], a + ret + +.pick_amnesia_attack + call AIPickAttackForAmnesia + ldh [hTemp_ffa0], a + ret + +.BeforeDamage +; if was attacked with Amnesia, apply it to the selected attack + ld a, DUELVARS_ARENA_CARD_LAST_TURN_EFFECT + call GetTurnDuelistVariable + cp LAST_TURN_EFFECT_AMNESIA + jr z, .apply_amnesia + +; otherwise, check if there was last turn damage, +; and write it to wDamage. + ld a, DUELVARS_ARENA_CARD_LAST_TURN_DAMAGE + call GetTurnDuelistVariable + ld de, wDamage + ld a, [hli] + ld [de], a + inc de + ld a, [hld] + ld [de], a + or [hl] + jr z, .no_damage + ld a, $01 + ld [wLoadedMoveAnimation], a +.no_damage + inc hl + inc hl ; DUELVARS_ARENA_CARD_LAST_TURN_STATUS +; check if there was a status applied to Defending Pokemon +; from the attack it used. + push hl + ld a, DUELVARS_ARENA_CARD_STATUS + call GetNonTurnDuelistVariable + ld e, l + ld d, h + pop hl + ld a, [hli] + or a + jr z, .no_status + push hl + push de + call .ExecuteStatusEffect + pop de + pop hl +.no_status +; hl is at DUELVARS_ARENA_CARD_LAST_TURN_SUBSTATUS2 +; apply substatus2 to self + ld e, DUELVARS_ARENA_CARD_SUBSTATUS2 + ld a, [hli] + ld [de], a + ret + +.apply_amnesia + call ApplyAmnesiaToAttack + ret +; 0x2ea28 + +.AfterDamage: ; 2ea28 (b:6a28) + ld a, [wNoDamageOrEffect] + or a + ret nz ; is unaffected + ld a, DUELVARS_ARENA_CARD_LAST_TURN_EFFECT + call GetTurnDuelistVariable + cp LAST_TURN_EFFECT_DISCARD_ENERGY + jr nz, .change_weakness + +; execute Energy discard effect for card chosen + call SwapTurn + ldh a, [hTemp_ffa0] + call PutCardInDiscardPile + ld a, DUELVARS_ARENA_CARD_LAST_TURN_EFFECT + call GetTurnDuelistVariable + ld [hl], LAST_TURN_EFFECT_DISCARD_ENERGY + call SwapTurn + +.change_weakness + ld a, DUELVARS_ARENA_CARD_LAST_TURN_CHANGE_WEAK + call GetTurnDuelistVariable + ld a, [hl] + or a + ret z ; weakness wasn't changed last turn + + push hl + call SwapTurn + ld a, DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + call LoadCardDataToBuffer2_FromDeckIndex + call SwapTurn + pop hl + + ld a, [wLoadedCard2Weakness] + or a + ret z ; defending Pokemon has no weakness to change + +; apply same color weakness to Defending Pokemon + ld a, [hl] + push af + ld a, DUELVARS_ARENA_CARD_CHANGED_WEAKNESS + call GetNonTurnDuelistVariable + pop af + ld [hl], a + +; print message of weakness color change + ld c, -1 +.loop_color + inc c + rla + jr nc, .loop_color + ld a, c + call SwapTurn + push af + ld a, DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + call LoadCardDataToBuffer1_FromDeckIndex + pop af + call LoadCardNameAndInputColor + ldtx hl, ChangedTheWeaknessOfPokemonToColorText + call DrawWideTextBox_PrintText + call SwapTurn + ret +; 0x2ea8f + +.ExecuteStatusEffect: ; 2ea8f (b:6a8f) + ld c, a + and PSN_DBLPSN + jr z, .cnf_slp_prz + ld b, a + cp DOUBLE_POISONED + push bc + call z, DoublePoisonEffect + pop bc + ld a, b + cp POISONED + push bc + call z, PoisonEffect + pop bc +.cnf_slp_prz + ld a, c + and CNF_SLP_PRZ + ret z + cp CONFUSED + jp z, ConfusionEffect + cp ASLEEP + jp z, SleepEffect + cp PARALYZED + jp z, ParalysisEffect + ret +; 0x2eab8 + +FearowAgilityEffect: ; 2eab8 (b:6ab8) + ldtx de, IfHeadsDoNotReceiveDamageOrEffectText + call TossCoin_BankB + ret nc + ld a, $52 + ld [wLoadedMoveAnimation], a + ld a, SUBSTATUS1_AGILITY + call ApplySubstatus1ToDefendingCard + ret +; 0x2eaca + +; return carry if cannot use Step In +StepIn_BenchCheck: ; 2eaca (b:6aca) + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + ldtx hl, CanOnlyBeUsedOnTheBenchText + or a + jr z, .set_carry + + add DUELVARS_ARENA_CARD_FLAGS + call GetTurnDuelistVariable + ldtx hl, OnlyOncePerTurnText + and USED_PKMN_POWER_THIS_TURN + jr nz, .set_carry + + ldh a, [hTempPlayAreaLocation_ff9d] + call CheckCannotUseDueToStatus_OnlyToxicGasIfANon0 + ret + +.set_carry + scf + ret +; 0x2eae8 + +StepIn_SwitchEffect: ; 2eae8 (b:6ae8) + ldh a, [hTemp_ffa0] + ld e, a + call SwapArenaWithBenchPokemon + ld a, DUELVARS_ARENA_CARD_FLAGS + call GetTurnDuelistVariable + set USED_PKMN_POWER_THIS_TURN_F, [hl] + ret +; 0x2eaf6 + +Dragonite2Slam_AIEffect: ; 2eaf6 (b:6af6) + ld a, (40 * 2) / 2 + lb de, 0, 80 + jp SetExpectedAIDamage +; 0x2eafe + +Dragonite2Slam_MultiplierEffect: ; 2eafe (b:6afe) + ld hl, 40 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsXDamageText + ld a, 2 + call TossCoinATimes_BankB + add a + add a + call ATimes10 + call SetDefiniteDamage + ret +; 0x2eb15 + +ThickSkinnedEffect: ; 2eb15 (b:6b15) + scf + ret +; 0x2eb17 + +LeekSlap_AIEffect: ; 2eb17 (b:6b17) + ld a, 30 / 2 + lb de, 0, 30 + jp SetExpectedAIDamage +; 0x2eb1f + +; return carry if already used attack in this duel +LeekSlap_OncePerDuelCheck: ; 2eb1f (b:6b1f) +; can only use attack if it was never used before this duel + ld a, DUELVARS_ARENA_CARD_FLAGS + call GetTurnDuelistVariable + and USED_LEEK_SLAP_THIS_DUEL + ret z + ldtx hl, ThisAttackCannotBeUsedTwiceText + scf + ret +; 0x2eb2c + +LeekSlap_SetUsedThisDuelFlag: ; 2eb2c (b:6b2c) + ld a, DUELVARS_ARENA_CARD_FLAGS + call GetTurnDuelistVariable + set USED_LEEK_SLAP_THIS_DUEL_F, [hl] + ret +; 0x2eb34 + +LeekSlap_NoDamage50PercentEffect: ; 2eb34 (b:6b34) + ldtx de, DamageCheckIfTailsNoDamageText + call TossCoin_BankB + ret c + xor a ; 0 damage + call SetDefiniteDamage + ret +; 0x2eb40 + +FetchEffect: ; 2eb40 (b:6b40) + ldtx hl, Draw1CardFromTheDeckText + call DrawWideTextBox_WaitForInput + bank1call DisplayDrawOneCardScreen + call DrawCardFromDeck + ret c ; return if deck is empty + call AddCardToHand + call LoadCardDataToBuffer1_FromDeckIndex + ld a, [wDuelistType] + cp DUELIST_TYPE_PLAYER + ret nz + ; show card on screen if it was Player + bank1call OpenCardPage_FromHand + ret +; 0x2eb5d + +CometPunch_AIEffect: ; 2eb5d (b:6b5d) + ld a, (20 * 4) / 2 + lb de, 0, 80 + jp SetExpectedAIDamage +; 0x2eb65 + +CometPunch_MultiplerEffect: ; 2eb65 (b:6b65) + ld hl, 20 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsXDamageText + ld a, 4 + call TossCoinATimes_BankB + add a + call ATimes10 + call SetDefiniteDamage + ret +; 0x2eb7b + +TaurosStomp_AIEffect: ; 2eb7b (b:6b7b) + ld a, (20 + 30) / 2 + lb de, 20, 30 + jp SetExpectedAIDamage +; 0x2eb83 + +TaurosStomp_DamageBoostEffect: ; 2eb83 (b:6b83) + ld hl, 10 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsPlusDamageText + call TossCoin_BankB + ret nc ; tails + ld a, 10 + call AddToDamage + ret +; 0x2eb96 + +Rampage_AIEffect: ; 2eb96 (b:6b96) + ld e, PLAY_AREA_ARENA + call GetCardDamageAndMaxHP + call AddToDamage + jp SetMinMaxDamageSameAsDamage +; 0x2eba1 + +Rampage_Confusion50PercentEffect: ; 2eba1 (b:6ba1) + ld e, PLAY_AREA_ARENA + call GetCardDamageAndMaxHP + call AddToDamage + ldtx de, IfTailsYourPokemonBecomesConfusedText + call TossCoin_BankB + ret c ; heads + call SwapTurn + call ConfusionEffect + call SwapTurn + ret +; 0x2ebba + +FuryAttack_AIEffect: ; 2ebba (b:6bba) + ld a, (10 * 2) / 2 + lb de, 0, 20 + jp SetExpectedAIDamage +; 0x2ebc2 + +FuryAttack_MultiplerEffect: ; 2ebc2 (b:6bc2) + ld hl, 10 + call LoadTxRam3 + ld a, 2 + ldtx de, DamageCheckIfHeadsXDamageText + call TossCoinATimes_BankB + call ATimes10 + call SetDefiniteDamage + ret +; 0x2ebd7 + +RetreatAidEffect: ; 2ebd7 (b:6bd7) + scf + ret +; 0x2ebd9 + +DodrioRage_AIEffect: ; 2ebd9 (b:6bd9) + call DodrioRage_DamageBoostEffect + jp SetMinMaxDamageSameAsDamage +; 0x2ebdf + +DodrioRage_DamageBoostEffect: ; 2ebdf (b:6bdf) + ld e, PLAY_AREA_ARENA + call GetCardDamageAndMaxHP + call AddToDamage + ret +; 0x2ebe8 + +PayDayEffect: ; 2ebe8 (b:6be8) + ldtx de, IfHeadsDraw1CardFromDeckText + call TossCoin_BankB + ret nc ; tails + ldtx hl, Draw1CardFromTheDeckText + call DrawWideTextBox_WaitForInput + bank1call DisplayDrawOneCardScreen + call DrawCardFromDeck + ret c ; empty deck + call AddCardToHand + call LoadCardDataToBuffer1_FromDeckIndex + ld a, [wDuelistType] + cp DUELIST_TYPE_PLAYER + ret nz + ; show card on screen if it was Player + bank1call OpenCardPage_FromHand + ret +; 0x2ec0c + +DragonairSlam_AIEffect: ; 2ec0c (b:6c0c) + ld a, (30 * 2) / 2 + lb de, 0, 60 + jp SetExpectedAIDamage +; 0x2ec14 + +DragonairSlam_MultiplierEffect: ; 2ec14 (b:6c14) + ld hl, 30 + call LoadTxRam3 + ld a, 2 + ldtx de, DamageCheckIfHeadsXDamageText + call TossCoinATimes_BankB + ld e, a + add a + add e + call ATimes10 + call SetDefiniteDamage + ret +; 0x2ec2c + +DragonairHyperBeam_PlayerSelectEffect: ; 2ec2c (b:6c2c) + jp HandleEnergyDiscardEffectSelection +; 0x2ec2f + +DragonairHyperBeam_AISelectEffect: ; 2ec2f (b:6c2f) + call AIPickEnergyCardToDiscardFromDefendingPokemon + ldh [hTemp_ffa0], a + ret +; 0x2ec35 + +DragonairHyperBeam_DiscardEffect: ; 2ec35 (b:6c35) + call HandleNoDamageOrEffect + ret c ; is unaffected + ldh a, [hTemp_ffa0] + cp $ff + ret z ; no energy card chosen + call SwapTurn + call PutCardInDiscardPile + ld a, DUELVARS_ARENA_CARD_LAST_TURN_EFFECT + call GetTurnDuelistVariable + ld [hl], LAST_TURN_EFFECT_DISCARD_ENERGY + call SwapTurn + ret +; 0x2ec4f + +; handles screen for selecting an Energy card to discard +; that is attached to Defending Pokemon, +; and store the Player selection in [hTemp_ffa0]. +HandleEnergyDiscardEffectSelection: ; 2ec4f (b:6c4f) + call SwapTurn + xor a ; PLAY_AREA_ARENA + call CreateArenaOrBenchEnergyCardList + jr c, .no_energy + ldtx hl, ChooseDiscardEnergyCardFromOpponentText + call DrawWideTextBox_WaitForInput + xor a ; PLAY_AREA_ARENA + bank1call DisplayEnergyDiscardScreen + +.loop_input + bank1call HandleEnergyDiscardMenuInput + jr c, .loop_input + + call SwapTurn + ldh a, [hTempCardIndex_ff98] + ldh [hTemp_ffa0], a ; store selected card to discard + ret + +.no_energy + call SwapTurn + ld a, $ff + ldh [hTemp_ffa0], a + ret +; 0x2ec77 + +; return carry if Defending Pokemon has no attacks +ClefableMetronome_CheckAttacks: ; 2ec77 (b:6c77) + call CheckIfDefendingPokemonHasAnyAttack + ldtx hl, NoAttackMayBeChoosenText + ret +; 0x2ec7e + +ClefableMetronome_AISelectEffect: ; 2ec7e (b:6c7e) + call HandleAIMetronomeEffect + ret +; 0x2ec82 + +ClefableMetronome_UseAttackEffect: ; 2ec82 (b:6c82) + ld a, 1 ; energy cost of this attack + call HandlePlayerMetronomeEffect + ret +; 0x2ec88 + +ClefableMinimizeEffect: ; 2ec88 (b:6c88) + ld a, SUBSTATUS1_REDUCE_BY_20 + call ApplySubstatus1ToDefendingCard + ret +; 0x2ec8e + +HurricaneEffect: ; 2ec8e (b:6c8e) + call HandleNoDamageOrEffect + ret c ; is unaffected + + ld a, DUELVARS_ARENA_CARD_HP + call GetNonTurnDuelistVariable + or a + ret z ; return if Pokemon was KO'd + +; look at all the card locations and put all cards +; that are in the Arena in the hand. + call SwapTurn + ld a, DUELVARS_CARD_LOCATIONS + call GetTurnDuelistVariable +.loop_locations + ld a, [hl] + cp CARD_LOCATION_ARENA + jr nz, .next_card + ; card in Arena found, put in hand + ld a, l + call AddCardToHand +.next_card + inc l + ld a, l + cp DECK_SIZE + jr c, .loop_locations + +; empty the Arena card slot + ld l, DUELVARS_ARENA_CARD + ld a, [hl] + ld [hl], $ff + ld l, DUELVARS_ARENA_CARD_HP + ld [hl], 0 + call LoadCardDataToBuffer1_FromDeckIndex + ld hl, wLoadedCard1Name + ld a, [hli] + ld h, [hl] + ld l, a + call LoadTxRam2 + ldtx hl, PokemonAndAllAttachedCardsReturnedToHandText + call DrawWideTextBox_WaitForInput + xor a + ld [wDuelDisplayedScreen], a + call SwapTurn + ret +; 0x2ecd3 + +PidgeottoWhirlwind_SelectEffect: ; 2ecd3 (b:6cd3) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetNonTurnDuelistVariable + cp 2 + jr nc, .switch + ; no Bench Pokemon + ld a, $ff + ldh [hTemp_ffa0], a + ret +.switch + call DuelistSelectForcedSwitch + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + ret +; 0x2ece9 + +PidgeottoWhirlwind_SwitchEffect: ; 2ece9 (b:6ce9) + ldh a, [hTemp_ffa0] + call HandleSwitchDefendingPokemonEffect + ret +; 0x2ecef + +PidgeottoMirrorMove_AIEffect: ; 2ecef (b:6cef) + jp MirrorMoveEffects.AIEffect +; 0x2ecf2 + +PidgeottoMirrorMove_InitialEffect1: ; 2ecf2 (b:6cf2) + jp MirrorMoveEffects.InitialEffect1 +; 0x2ecf5 + +PidgeottoMirrorMove_InitialEffect2: ; 2ecf5 (b:6cf5) + jp MirrorMoveEffects.InitialEffect2 +; 0x2ecf8 + +PidgeottoMirrorMove_PlayerSelection: ; 2ecf8 (b:6cf8) + jp MirrorMoveEffects.PlayerSelection +; 0x2ecfb + +PidgeottoMirrorMove_AISelection: ; 2ecfb (b:6cfb) + jp MirrorMoveEffects.AISelection +; 0x2ecfe + +PidgeottoMirrorMove_BeforeDamage: ; 2ecfe (b:6cfe) + jp MirrorMoveEffects.BeforeDamage +; 0x2ed01 + +PidgeottoMirrorMove_AfterDamage: ; 2ed01 (b:6d01) + jp MirrorMoveEffects.AfterDamage +; 0x2ed04 + +SingEffect: ; 2ed04 (b:6d04) + call Sleep50PercentEffect + call nc, SetNoEffectFromStatus + ret +; 0x2ed0b + +; return carry if Defending Pokemon has no attacks +ClefairyMetronome_CheckAttacks: ; 2ed0b (b:6d0b) + call CheckIfDefendingPokemonHasAnyAttack + ldtx hl, NoAttackMayBeChoosenText + ret +; 0x2ed12 + +ClefairyMetronome_AISelectEffect: ; 2ed12 (b:6d12) + call HandleAIMetronomeEffect + ret +; 0x2ed16 + +ClefairyMetronome_UseAttackEffect: ; 2ed16 (b:6d16) + ld a, 3 ; energy cost of this attack +; fallthrough + +; handles Metronome selection, and validates +; whether it can use the selected attack. +; if unsuccessful, returns carry. +; input: +; a = amount of colorless energy needed for Metronome +HandlePlayerMetronomeEffect: ; 2ed18 (b:6d18) + ld [wMetronomeEnergyCost], a + ldtx hl, ChooseOppAttackToBeUsedWithMetronomeText + call DrawWideTextBox_WaitForInput + + call HandleDefendingPokemonAttackSelection + ret c ; return if operation cancelled + +; store this attack as selected attack to use + ld hl, wMetronomeSelectedAttack + ld [hl], d + inc hl + ld [hl], e + +; compare selected attack's name with +; the attack that is loaded, which is Metronome. +; if equal, then cannot select it. +; (i.e. cannot use Metronome with Metronome.) + ld hl, wLoadedMoveName + ld a, [hli] + ld h, [hl] + ld l, a + push hl + call SwapTurn + call CopyMoveDataAndDamage_FromDeckIndex + call SwapTurn + pop de + ld hl, wLoadedMoveName + ld a, e + cp [hl] + jr nz, .try_use + inc hl + ld a, d + cp [hl] + jr nz, .try_use + ; cannot select Metronome + ldtx hl, UnableToSelectText +.failed + call DrawWideTextBox_WaitForInput +.set_carry + scf + ret + +.try_use +; run the attack checks to determine +; whether it can be used. + ld a, EFFECTCMDTYPE_INITIAL_EFFECT_1 + call TryExecuteEffectCommandFunction + jr c, .failed + ld a, EFFECTCMDTYPE_INITIAL_EFFECT_2 + call TryExecuteEffectCommandFunction + jr c, .set_carry + ; successful + +; send data to link opponent + bank1call SendAttackDataToLinkOpponent + ld a, OPPACTION_USE_METRONOME_ATTACK + call SetOppAction_SerialSendDuelData + ld hl, wMetronomeSelectedAttack + ld d, [hl] + inc hl + ld e, [hl] + ld a, [wMetronomeEnergyCost] + ld c, a + call SerialSend8Bytes + + ldh a, [hTempCardIndex_ff9f] + ld [wPlayerAttackingCardIndex], a + ld a, [wSelectedAttack] + ld [wPlayerAttackingMoveIndex], a + ld a, [wTempCardID_ccc2] + ld [wPlayerAttackingCardID], a + or a + ret +; 0x2ed86 + +; does nothing for AI. +HandleAIMetronomeEffect: ; 2ed86 (b:6d86) + ret +; 0x2ed87 + +DoTheWaveEffect: ; 2ed87 (b:6d87) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + dec a ; don't count arena card + call ATimes10 + call AddToDamage + ret +; 0x2ed94 + +; return carry if no damage counters +FirstAid_DamageCheck: ; 2ed94 (b:6d94) + ld e, PLAY_AREA_ARENA + call GetCardDamageAndMaxHP + ldtx hl, NoDamageCountersText + cp 10 + ret +; 0x2ed9f + +FirstAid_HealEffect: ; 2ed9f (b:6d9f) + lb de, 0, 10 + call ApplyAndAnimateHPRecovery + ret +; 0x2eda6 + +JigglypuffDoubleEdgeEffect: ; 2eda6 (b:6da6) + ld a, 20 + call DealRecoilDamageToSelf + ret +; 0x2edac + +PounceEffect: ; 2edac (b:6dac) + ld a, SUBSTATUS2_POUNCE + call ApplySubstatus2ToDefendingCard + ret +; 0x2edb2 + +LickitungSupersonicEffect: ; 2edb2 (b:6db2) + call Confusion50PercentEffect + call nc, SetNoEffectFromStatus + ret +; 0x2edb9 + +PidgeyWhirlwind_SelectEffect: ; 2edb9 (b:6db9) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetNonTurnDuelistVariable + cp 2 + jr nc, .switch + ; no Bench Pokemon + ld a, $ff + ldh [hTemp_ffa0], a + ret +.switch + call DuelistSelectForcedSwitch + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + ret +; 0x2edcf + +PidgeyWhirlwind_SwitchEffect: ; 2edcf (b:6dcf) + ldh a, [hTemp_ffa0] + call HandleSwitchDefendingPokemonEffect + ret +; 0x2edd5 + +; return carry if Defending card has no weakness +Conversion1_WeaknessCheck: ; 2edd5 (b:6dd5) + call SwapTurn + ld a, DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + call LoadCardDataToBuffer2_FromDeckIndex + call SwapTurn + ld a, [wLoadedCard2Weakness] + or a + ret nz + ldtx hl, NoWeaknessText + scf + ret +; 0x2eded + +Conversion1_PlayerSelectEffect: ; 2eded (b:6ded) + ldtx hl, ChooseWeaknessYouWishToChangeText + xor a ; PLAY_AREA_ARENA + call HandleColorChangeScreen + ldh [hTemp_ffa0], a + ret +; 0x2edf7 + +Conversion1_AISelectEffect: ; 2edf7 (b:6df7) + call AISelectConversionColor + ret +; 0x2edfb + +Conversion1_ChangeWeaknessEffect: ; 2edfb (b:6dfb) + call HandleNoDamageOrEffect + ret c ; is unaffected + +; apply changed weakness + ld a, DUELVARS_ARENA_CARD_CHANGED_WEAKNESS + call GetNonTurnDuelistVariable + ldh a, [hTemp_ffa0] + call TranslateColorToWR + ld [hl], a + ld l, DUELVARS_ARENA_CARD_LAST_TURN_CHANGE_WEAK + ld [hl], a + +; print text box + call SwapTurn + ldtx hl, ChangedTheWeaknessOfPokemonToColorText + call PrintArenaCardNameAndColorText + call SwapTurn + +; apply substatus + ld a, SUBSTATUS2_CONVERSION2 + call ApplySubstatus2ToDefendingCard + ret +; 0x2ee1f + +; returns carry if Active Pokemon has no Resistance. +Conversion2_ResistanceCheck: ; 2ee1f (b:6e1f) + ld a, DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Resistance] + or a + ret nz + ldtx hl, NoResistanceText + scf + ret +; 0x2ee31 + +Conversion2_PlayerSelectEffect: ; 2ee31 (b:6e31) + ldtx hl, ChooseResistanceYouWishToChangeText + ld a, $80 + call HandleColorChangeScreen + ldh [hTemp_ffa0], a + ret +; 0x2ee3c + +Conversion2_AISelectEffect: ; 2ee3c (b:6e3c) +; AI will choose Defending Pokemon's color +; unless it is colorless. + call SwapTurn + ld a, DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + call LoadCardDataToBuffer1_FromDeckIndex + call SwapTurn + ld a, [wLoadedCard1Type] + cp COLORLESS + jr z, .is_colorless + ldh [hTemp_ffa0], a + ret + +.is_colorless + call SwapTurn + call AISelectConversionColor + call SwapTurn + ret +; 0x2ee5e + +Conversion2_ChangeResistanceEffect: ; 2ee5e (b:6e5e) +; apply changed resistance + ld a, DUELVARS_ARENA_CARD_CHANGED_RESISTANCE + call GetTurnDuelistVariable + ldh a, [hTemp_ffa0] + call TranslateColorToWR + ld [hl], a + ldtx hl, ChangedTheResistanceOfPokemonToColorText +; fallthrough + +; prints text that requires card name and color, +; with the card name of the Turn Duelist's Arena Pokemon +; and color in [hTemp_ffa0]. +; input: +; hl = text to print +PrintArenaCardNameAndColorText: ; 2ee6c (b:6e6c) + push hl + ld a, DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + call LoadCardDataToBuffer1_FromDeckIndex + ldh a, [hTemp_ffa0] + call LoadCardNameAndInputColor + pop hl + call DrawWideTextBox_PrintText + ret +; 0x2ee7f + +; handles AI logic for selecting a new color +; for weakness/resistance. +; - if within the context of Conversion1, looks +; in own Bench for a non-colorless card that can attack. +; - if within the context of Conversion2, looks +; in Player's Bench for a non-colorless card that can attack. +AISelectConversionColor: ; 2ee7f (b:6e7f) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ld d, a + ld e, PLAY_AREA_ARENA + jr .next_pkmn_atk + +; look for a non-colorless Bench Pokemon +; that has enough energy to use an attack. +.loop_atk + push de + call GetPlayAreaCardAttachedEnergies + ld a, e + add DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + ld d, a + call LoadCardDataToBuffer1_FromDeckIndex + ld a, [wLoadedCard1Type] + cp COLORLESS + jr z, .skip_pkmn_atk ; skip colorless Pokemon + ld e, FIRST_ATTACK_OR_PKMN_POWER + bank1call _CheckIfEnoughEnergiesToMove + jr nc, .found + ld e, SECOND_ATTACK + bank1call _CheckIfEnoughEnergiesToMove + jr nc, .found +.skip_pkmn_atk + pop de +.next_pkmn_atk + inc e + dec d + jr nz, .loop_atk + +; none found in Bench. +; next, look for a non-colorless Bench Pokemon +; that has any Energy cards attached. + ld d, e ; number of Play Area Pokemon + ld e, PLAY_AREA_ARENA + jr .next_pkmn_energy + +.loop_energy + push de + call GetPlayAreaCardAttachedEnergies + ld a, [wTotalAttachedEnergies] + or a + jr z, .skip_pkmn_energy + ld a, e + add DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + ld d, a + call LoadCardDataToBuffer1_FromDeckIndex + ld a, [wLoadedCard1Type] + cp COLORLESS + jr nz, .found +.skip_pkmn_energy + pop de +.next_pkmn_energy + inc e + dec d + jr nz, .loop_energy + +; otherwise, just select a random energy. + ld a, NUM_COLORED_TYPES + call Random + ldh [hTemp_ffa0], a + ret + +.found + pop de + ld a, [wLoadedCard1Type] + and TYPE_PKMN + ldh [hTemp_ffa0], a + ret +; 0x2eee7 + +ScrunchEffect: ; 2eee7 (b:6ee7) + ldtx de, IfHeadsNoDamageNextTurnText + call TossCoin_BankB + jp nc, SetWasUnsuccessful + ld a, $6b + ld [wLoadedMoveAnimation], a + ld a, SUBSTATUS1_NO_DAMAGE_17 + call ApplySubstatus1ToDefendingCard + ret +; 0x2eefb + +ChanseyDoubleEdgeEffect: ; 2eefb (b:6efb) + ld a, 80 + call DealRecoilDamageToSelf + ret +; 0x2ef01 + +SuperFang_AIEffect: ; 2ef01 (b:6f01) + call SuperFang_HalfHPEffect + jp SetMinMaxDamageSameAsDamage +; 0x2ef07 + +SuperFang_HalfHPEffect: ; 2ef07 (b:6f07) + ld a, DUELVARS_ARENA_CARD_HP + call GetNonTurnDuelistVariable + srl a + bit 0, a + jr z, .rounded + ; round up + add 5 +.rounded + call SetDefiniteDamage + ret +; 0x2ef18 + +; return carry if no Pokemon in Bench +TrainerCardAsPokemon_BenchCheck: ; 2ef18 (b:6f18) + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ldtx hl, EffectNoPokemonOnTheBenchText + cp 2 + ret +; 0x2ef27 + +TrainerCardAsPokemon_PlayerSelectSwitch: ; 2ef27 (b:6f27) + ldh a, [hTemp_ffa0] + or a + ret nz ; no need to switch if it's not Arena card + + ldtx hl, SelectPokemonToPlaceInTheArenaText + call DrawWideTextBox_WaitForInput + bank1call HasAlivePokemonInBench + bank1call OpenPlayAreaScreenForSelection + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTempPlayAreaLocation_ffa1], a + ret +; 0x2ef3c + +TrainerCardAsPokemon_DiscardEffect: ; 2ef3c (b:6f3c) + ldh a, [hTemp_ffa0] + ld e, a + call MovePlayAreaCardToDiscardPile + ldh a, [hTemp_ffa0] + or a + jr nz, .shift_cards + ldh a, [hTempPlayAreaLocation_ffa1] + ld e, a + call SwapArenaWithBenchPokemon +.shift_cards + call ShiftAllPokemonToFirstPlayAreaSlots + ret +; 0x2ef51 + +HealingWind_InitialEffect: ; 2ef51 (b:6f51) + scf + ret +; 0x2ef53 + +HealingWind_PlayAreaHealEffect: ; 2ef53 (b:6f53) +; play initial animation + ldh a, [hTempPlayAreaLocation_ff9d] + ld b, a + ld c, $00 + ldh a, [hWhoseTurn] + ld h, a + bank1call PlayMoveAnimation + bank1call WaitMoveAnimation + ld a, $86 + ld [wLoadedMoveAnimation], a + + + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ld d, a + ld e, PLAY_AREA_ARENA +.loop_play_area + push de + ld a, e + ldh [hTempPlayAreaLocation_ff9d], a + call GetCardDamageAndMaxHP + or a + jr z, .next_pkmn ; skip if no damage + +; if less than 20 damage, cap recovery at 10 damage + ld de, 20 + cp e + jr nc, .heal + ld e, a + +.heal +; add HP to this card + ldh a, [hTempPlayAreaLocation_ff9d] + add DUELVARS_ARENA_CARD_HP + call GetTurnDuelistVariable + add e + ld [hl], a + +; play heal animation + ldh a, [hTempPlayAreaLocation_ff9d] + ld b, a + ld c, $01 + ldh a, [hWhoseTurn] + ld h, a + bank1call PlayMoveAnimation + bank1call WaitMoveAnimation +.next_pkmn + pop de + inc e + dec d + jr nz, .loop_play_area + + ret +; 0x2ef9c + +Dragonite1Slam_AIEffect: ; 2ef9c (b:6f9c) + ld a, (30 * 2) / 2 + lb de, 0, 60 + jp SetExpectedAIDamage +; 0x2efa4 + +Dragonite1Slam_MultiplierEffect: ; 2efa4 (b:6fa4) + ld hl, 30 + call LoadTxRam3 + ldtx de, DamageCheckIfHeadsXDamageText + ld a, 2 + call TossCoinATimes_BankB + ld c, a + add a + add c + call ATimes10 + call SetDefiniteDamage + ret +; 0x2efbc + + INCROM $2efbc, $2efe0 + +CatPunchEffect: ; 2efe0 (b:6fe0) + call SwapTurn + call PickRandomPlayAreaCard + ld b, a + ld a, $83 + ld [wLoadedMoveAnimation], a + ld de, 20 + call DealDamageToPlayAreaPokemon + call SwapTurn + ret +; 0x2eff6 + +MorphEffect: ; 2eff6 (b:6ff6) + call ExchangeRNG + call .PickRandomBasicPokemonFromDeck + jr nc, .successful + ldtx hl, AttackUnsuccessfulText + call DrawWideTextBox_WaitForInput + ret + +.successful + ld a, DUELVARS_ARENA_CARD_STAGE + call GetTurnDuelistVariable + or a + jr z, .skip_discard_stage_below + +; if this is a stage 1 Pokemon (in case it's used +; by Clefable's Metronome attack) then first discard +; the lower stage card. + push hl + xor a + ldh [hTempPlayAreaLocation_ff9d], a + bank1call GetCardOneStageBelow + ld a, d + call PutCardInDiscardPile + pop hl + ld [hl], BASIC + +.skip_discard_stage_below +; overwrite card ID + ldh a, [hTempCardIndex_ff98] + call GetCardIDFromDeckIndex + ld a, DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + ldh [hTempCardIndex_ff98], a + call _GetCardIDFromDeckIndex + ld [hl], e + +; overwrite HP to new card's maximum HP + ld e, PLAY_AREA_ARENA + call GetCardDamageAndMaxHP + ld a, DUELVARS_ARENA_CARD_HP + call GetTurnDuelistVariable + ld [hl], c + +; clear changed color and status + ld l, DUELVARS_ARENA_CARD_CHANGED_TYPE + ld [hl], $00 + call ClearAllStatusConditions + +; load both card's names for printing text + ld a, [wTempTurnDuelistCardID] + ld e, a + ld d, $00 + call LoadCardDataToBuffer2_FromCardID + ld hl, wLoadedCard2Name + ld de, wTxRam2 + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + inc de + ldh a, [hTempCardIndex_ff98] + call LoadCardDataToBuffer2_FromDeckIndex + ld hl, wLoadedCard2Name + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + ldtx hl, MetamorphsToText + call DrawWideTextBox_WaitForInput + + xor a + ld [wDuelDisplayedScreen], a + ret +; 0x2f06a + +; picks a random Pokemon in the Deck to morph. +; needs to be a Basic Pokemon that doesn't have +; the same ID as the Arena card. +; returns carry if no Pokemon were found. +.PickRandomBasicPokemonFromDeck ; 2f06a (b:706a) + call CreateDeckCardList + ret c ; empty deck + ld hl, wDuelTempList + call ShuffleCards +.loop_deck + ld a, [hli] + ldh [hTempCardIndex_ff98], a + cp $ff + jr z, .set_carry + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Type] + cp TYPE_ENERGY + jr nc, .loop_deck ; skip non-Pokemon cards + ld a, [wLoadedCard2Stage] + or a + jr nz, .loop_deck ; skip non-Basic cards + ld a, [wLoadedCard2ID] + cp DUELVARS_ARENA_CARD + jr z, .loop_deck ; skip cards with same ID as Arena card + ldh a, [hTempCardIndex_ff98] + or a + ret +.set_carry + scf + ret +; 0x2f098 + +; returns in a and [hTempCardIndex_ff98] the deck index +; of random Basic Pokemon card in deck. +; if none are found, return carry. +PickRandomBasicCardFromDeck: ; 2f098 (b:7098) + call CreateDeckCardList + ret c ; return if empty deck + ld hl, wDuelTempList + call ShuffleCards +.loop_deck + ld a, [hli] + ldh [hTempCardIndex_ff98], a + cp $ff + jr z, .set_carry + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Type] + cp TYPE_ENERGY + jr nc, .loop_deck ; skip if not Pokemon card + ld a, [wLoadedCard2Stage] + or a + jr nz, .loop_deck ; skip if not Basic stage + ldh a, [hTempCardIndex_ff98] + or a + ret +.set_carry + scf + ret +; 0x2f0bf + +SlicingWindEffect: ; 2f0bf (b:70bf) + call SwapTurn + call PickRandomPlayAreaCard + ld b, a + ld de, 30 + call DealDamageToPlayAreaPokemon_RegularAnim + call SwapTurn + ret +; 0x2f0d0 + +Gale_LoadAnimation: ; 2f0d0 (b:70d0) + ld a, $87 + ld [wLoadedMoveAnimation], a + ret +; 0x2f0d6 + +Gale_SwitchEffect: ; 2f0d6 (b:70d6) +; if Defending card is unaffected by attack +; jump directly to switching this card only. + call HandleNoDamageOrEffect + jr c, .SwitchWithRandomBenchPokemon + +; handle switching Defending card + ld a, DUELVARS_ARENA_CARD_HP + call GetNonTurnDuelistVariable + or a + jr nz, .skip_destiny_bond + bank1call HandleDestinyBondSubstatus +.skip_destiny_bond + call SwapTurn + call .SwitchWithRandomBenchPokemon + jr c, .skip_clear_damage +; clear dealt damage because Pokemon was switched + xor a + ld hl, wDealtDamage + ld [hli], a + ld [hl], a +.skip_clear_damage + call SwapTurn +; fallthrough for attacking card switch + +.SwitchWithRandomBenchPokemon + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + cp 2 + ret c ; return if no Bench Pokemon + +; get random Bench location and swap + dec a + call Random + inc a + ld e, a + call SwapArenaWithBenchPokemon + + xor a + ld [wDuelDisplayedScreen], a + ret +; 0x2f10d + +; return carry if Bench is full +FriendshipSong_BenchCheck: ; 2f10d (b:710d) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ldtx hl, NoSpaceOnTheBenchText + cp MAX_PLAY_AREA_POKEMON + ccf + ret +; 0x2f119 + +FriendshipSong_AddToBench50PercentEffect: ; 2f119 (b:7119) + ldtx de, SuccessCheckIfHeadsAttackIsSuccessfulText + call TossCoin_BankB + jr c, .successful + +.none_came_text + ldtx hl, NoneCameText + call DrawWideTextBox_WaitForInput + ret + +.successful + call PickRandomBasicCardFromDeck + jr nc, .put_in_bench + ld a, $6a + call Func_2c12e + call .none_came_text + call Func_2c0bd + ret + +.put_in_bench + call SearchCardInDeckAndAddToHand + call AddCardToHand + call PutHandPokemonCardInPlayArea + ld a, $6a + call Func_2c12e + ldh a, [hTempCardIndex_ff98] + ldtx hl, CameToTheBenchText + bank1call DisplayCardDetailScreen + call Func_2c0bd + ret +; 0x2f153 + +ExpandEffect: ; 2f153 (b:7153) + ld a, SUBSTATUS1_REDUCE_BY_10 + call ApplySubstatus1ToDefendingCard + ret +; 0x2f159 + +; returns carry if either there are no damage counters +; or no Energy cards attached in the Play Area. +SuperPotion_DamageEnergyCheck: ; 2f159 (b:7159) + call CheckIfPlayAreaHasAnyDamage + ldtx hl, NoPokemonWithDamageCountersText + ret c ; no damage counters + call CheckIfThereAreAnyEnergyCardsAttached + ldtx hl, ThereIsNoEnergyCardAttachedText + ret +; 0x2f167 + +SuperPotion_PlayerSelectEffect: ; 2f167 (b:7167) + ldtx hl, ChoosePokemonToRemoveDamageCounterFromText + call DrawWideTextBox_WaitForInput +.start + bank1call HasAlivePokemonInPlayArea +.read_input + bank1call OpenPlayAreaScreenForSelection + ret c ; exit if B is pressed + ld e, a + call GetCardDamageAndMaxHP + or a + jr z, .read_input ; Pokemon has no damage? + ldh a, [hCurMenuItem] + ld e, a + call GetPlayAreaCardAttachedEnergies + ld a, [wTotalAttachedEnergies] + or a + jr nz, .got_pkmn + ; no energy cards attached + ldtx hl, NoEnergyCardsText + call DrawWideTextBox_WaitForInput + jr .start + +.got_pkmn +; Pokemon has damage and Energy cards attached, +; prompt the Player for Energy selection to discard. + ldh a, [hCurMenuItem] + bank1call CreateArenaOrBenchEnergyCardList + ldh a, [hCurMenuItem] + bank1call DisplayEnergyDiscardScreen + bank1call HandleEnergyDiscardMenuInput + ret c ; exit if B was pressed + + ldh a, [hTempCardIndex_ff98] + ldh [hTemp_ffa0], a + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTempPlayAreaLocation_ffa1], a + ld e, a + +; cap the healing damage if +; it would make it exceed max HP. + call GetCardDamageAndMaxHP + ld c, 40 + cp 40 + jr nc, .heal + ld c, a +.heal + ld a, c + ldh [hPlayAreaEffectTarget], a + or a + ret +; 0x2f1b5 + +SuperPotion_HealEffect: ; 2f1b5 (b:71b5) + ldh a, [hTemp_ffa0] + call PutCardInDiscardPile + ldh a, [hTempPlayAreaLocation_ffa1] + ldh [hTempPlayAreaLocation_ff9d], a + ldh a, [hPlayAreaEffectTarget] + call HealPlayAreaCardHP + ret +; 0x2f1c4 + +; checks if there is at least one Energy card +; attached to some card in the Turn Duelist's Play Area. +; return no carry if one is found, +; and returns carry set if none is found. +CheckIfThereAreAnyEnergyCardsAttached: ; 2f1c4 (b:71c4) + ld a, DUELVARS_CARD_LOCATIONS + call GetTurnDuelistVariable +.loop_deck + ld a, [hl] + bit CARD_LOCATION_PLAY_AREA_F, a + jr z, .next_card ; skip if not in Play Area + ld a, l + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Type] + cp TYPE_TRAINER + jr z, .next_card ; skip if it's a Trainer card + cp TYPE_ENERGY + jr nc, .found +.next_card + inc l + ld a, l + cp DECK_SIZE + jr c, .loop_deck + scf + ret +.found + or a + ret +; 0x2f1e7 + +; handles Player selection for Pokemon in Play Area, +; then opens screen to choose one of the energy cards +; attached to that selected Pokemon. +; outputs the selection in: +; [hTemp_ffa0] = play area location +; [hTempPlayAreaLocation_ffa1] = index of energy card +HandlePokemonAndEnergySelectionScreen: ; 2f1e7 (b:71e7) + bank1call HasAlivePokemonInPlayArea + bank1call OpenPlayAreaScreenForSelection + ret c ; exit if B is pressed + ld e, a + call GetPlayAreaCardAttachedEnergies + ld a, [wTotalAttachedEnergies] + or a + jr nz, .has_energy + ldtx hl, NoEnergyCardsText + call DrawWideTextBox_WaitForInput + jr HandlePokemonAndEnergySelectionScreen ; loop back to start + +.has_energy + ldh a, [hCurMenuItem] + bank1call CreateArenaOrBenchEnergyCardList + ldh a, [hCurMenuItem] + bank1call DisplayEnergyDiscardScreen + bank1call HandleEnergyDiscardMenuInput + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + ldh a, [hTempCardIndex_ff98] + ldh [hTempPlayAreaLocation_ffa1], a + ret +; 0x2f216 + +ImakuniEffect: ; 2f216 (b:7216) + ld a, DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + call LoadCardDataToBuffer1_FromDeckIndex + ld a, [wLoadedCard1ID] + +; cannot confuse Clefairy Doll and Mysterious Fossil + cp CLEFAIRY_DOLL + jr z, .failed + cp MYSTERIOUS_FOSSIL + jr z, .failed + +; cannot confuse Snorlax if its Pkmn Power is active + cp SNORLAX + jr nz, .success + xor a + call CheckCannotUseDueToStatus_OnlyToxicGasIfANon0 + jr c, .success + ; fallthrough if Thick Skinned is active + +.failed +; play confusion animation and print failure text + ld a, $7f + call Func_2fea9 + ldtx hl, ThereWasNoEffectText + call DrawWideTextBox_WaitForInput + ret + +.success +; play confusion animation and confuse card + ld a, $7f + call Func_2fea9 + ld a, DUELVARS_ARENA_CARD_STATUS + call GetTurnDuelistVariable + and PSN_DBLPSN + or CONFUSED + ld [hl], a + bank1call DrawDuelHUDs + ret +; 0x2f252 + +; returns carry if opponent has no energy cards attached +EnergyRemoval_EnergyCheck: ; 2f252 (b:7252) + call SwapTurn + call CheckIfThereAreAnyEnergyCardsAttached + ldtx hl, NoEnergyAttachedToOpponentsActiveText + call SwapTurn + ret +; 0x2f25f + +EnergyRemoval_PlayerSelection: ; 2f25f (b:725f) + ldtx hl, ChoosePokemonToRemoveEnergyFromText + call DrawWideTextBox_WaitForInput + call SwapTurn + call HandlePokemonAndEnergySelectionScreen + call SwapTurn + ret +; 0x2f26f + +EnergyRemoval_AISelection: ; 2f26f (b:726f) + call AIPickEnergyCardToDiscardFromDefendingPokemon + ret +; 0x2f273 + +EnergyRemoval_DiscardEffect: ; 2f273 (b:7273) + call SwapTurn + ldh a, [hTempPlayAreaLocation_ffa1] + call PutCardInDiscardPile + call SwapTurn + call IsPlayerTurn + ret c + +; show Player which Pokemon was affected + call SwapTurn + ldh a, [hTemp_ffa0] + call Func_2c10b + call SwapTurn + ret +; 0x2f28e + +; return carry if no other card in hand to discard +; or if there are no Basic Energy cards in Discard Pile. +EnergyRetrieval_HandEnergyCheck: ; 2f28e (b:728e) + ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND + call GetTurnDuelistVariable + cp 2 + ldtx hl, NotEnoughCardsInHandText + ret c ; return if doesn't have another card to discard + call CreateEnergyCardListFromDiscardPile_OnlyBasic + ldtx hl, ThereAreNoBasicEnergyCardsInDiscardPileText + ret +; 0x2f2a0 + +EnergyRetrieval_PlayerHandSelection: ; 2f2a0 (b:72a0) + ldtx hl, ChooseCardToDiscardFromHandText + call DrawWideTextBox_WaitForInput + call CreateHandCardList + ldh a, [hTempCardIndex_ff9f] + call RemoveCardFromDuelTempList + bank1call Func_5591 + bank1call DisplayCardList + ldh a, [hTempCardIndex_ff98] + ldh [hTempList], a + ret +; 0x2f2b9 + +EnergyRetrieval_PlayerDiscardPileSelection: ; 2f2b9 (b:72b9) + ld a, 1 ; start at 1 due to card selected from hand + ldh [hCurSelectionItem], a + ldtx hl, Choose2BasicEnergyCardsFromDiscardPileText + call DrawWideTextBox_WaitForInput + call CreateEnergyCardListFromDiscardPile_OnlyBasic + +.select_card + bank1call InitAndDrawCardListScreenLayout + ldtx hl, PleaseSelectCardText + ldtx de, PlayerDiscardPileText + bank1call SetCardListHeaderText + bank1call DisplayCardList + jr nc, .selected + ; B was pressed + ld a, 2 + 1 ; includes the card selected from hand + call AskWhetherToQuitSelectingCards + jr c, .select_card ; player selected No + jr .done + +.selected + call GetNextPositionInTempList_TrainerEffects + ldh a, [hTempCardIndex_ff98] + ld [hl], a + call RemoveCardFromDuelTempList + jr c, .done + ldh a, [hCurSelectionItem] + cp 2 + 1 ; includes the card selected from hand + jr c, .select_card + +.done + call GetNextPositionInTempList_TrainerEffects + ld [hl], $ff ; terminating byte + or a + ret +; 0x2f2f8 + +EnergyRetrieval_DiscardAndAddToHandEffect: ; 2f2f8 (b:72f8) + ld hl, hTempList + ld a, [hli] + call RemoveCardFromHand + call PutCardInDiscardPile + ld de, wDuelTempList +.loop + ld a, [hli] + ld [de], a + inc de + cp $ff + jr z, .done + call MoveDiscardPileCardToHand + call AddCardToHand + jr .loop +.done + call IsPlayerTurn + ret c + bank1call Func_4b38 + ret +; 0x2f31c + +; return carry if no cards left in Deck. +EnergySearch_DeckCheck: ; 2f31c (b:731c) + ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK + call GetTurnDuelistVariable + cp DECK_SIZE + ccf + ldtx hl, NoCardsLeftInTheDeckText + ret +; 0x2f328 + +EnergySearch_PlayerSelection: ; 2f328 (b:7328) + ld a, $ff + ldh [hTemp_ffa0], a + call CreateDeckCardList + ldtx hl, Choose1BasicEnergyCardFromDeckText + lb de, SEARCHEFFECT_BASIC_ENERGY, 0 + ldtx bc, BasicEnergyText + call LookForCardsInDeck + ret c ; skip showing deck + + bank1call Func_5591 + ldtx hl, ChooseBasicEnergyCardText + ldtx de, DuelistDeckText + bank1call SetCardListHeaderText +.read_input + bank1call DisplayCardList + jr c, .try_exit ; B pressed? + ldh a, [hTempCardIndex_ff98] + ldh [hTemp_ffa0], a + call CheckIfCardIsBasicEnergy + jr c, .play_sfx + or a + ret +.play_sfx + call Func_3794 + jr .read_input + +.try_exit +; check if Player can exit without selecting anything + ld hl, wDuelTempList +.next_card + ld a, [hli] + cp $ff + jr z, .exit + call CheckIfCardIsBasicEnergy + jr c, .next_card + jr .read_input ; no, has to select Energy card +.exit + ld a, $ff + ldh [hTemp_ffa0], a + or a + ret +; 0x2f372 + +EnergySearch_AddToHandEffect: ; 2f372 (b:7372) + ldh a, [hTemp_ffa0] + cp $ff + jr z, .done +; add to hand + call SearchCardInDeckAndAddToHand + call AddCardToHand + call IsPlayerTurn + jr c, .done ; done if Player played card +; display card in screen + ldh a, [hTemp_ffa0] + ldtx hl, WasPlacedInTheHandText + bank1call DisplayCardDetailScreen +.done + call Func_2c0bd + ret + +; check if card index in a is a Basic Energy card. +; returns carry in case it's not. +CheckIfCardIsBasicEnergy: ; 2f38f (b:738f) + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Type] + cp TYPE_ENERGY + jr c, .not_basic_energy + cp TYPE_ENERGY_DOUBLE_COLORLESS + jr nc, .not_basic_energy +; is basic energy + or a + ret +.not_basic_energy + scf + ret +; 0x2f3a1 + +ProfessorOakEffect: ; 2f3a1 (b:73a1) +; discard hand + call CreateHandCardList + call SortCardsInDuelTempListByID + ld hl, wDuelTempList +.discard_loop + ld a, [hli] + cp $ff + jr z, .draw_cards + call RemoveCardFromHand + call PutCardInDiscardPile + jr .discard_loop + +.draw_cards + ld a, 7 + bank1call DisplayDrawNCardsScreen + ld c, 7 +.draw_loop + call DrawCardFromDeck + jr c, .done + call AddCardToHand + dec c + jr nz, .draw_loop +.done + ret +; 0x2f3ca + +Potion_DamageCheck: ; 2f3ca (b:73ca) + call CheckIfPlayAreaHasAnyDamage + ldtx hl, NoPokemonWithDamageCountersText + ret +; 0x2f3d1 + +Potion_PlayerSelection: ; 2f3d1 (b:73d1) + bank1call HasAlivePokemonInPlayArea +.read_input + bank1call OpenPlayAreaScreenForSelection + ret c ; exit is B was pressed + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + ld e, a + call GetCardDamageAndMaxHP + or a + jr z, .read_input ; no damage, loop back to start +; cap damage + ld c, 20 + cp 20 + jr nc, .skip_cap + ld c, a +.skip_cap + ld a, c + ldh [hTempPlayAreaLocation_ffa1], a + or a + ret +; 0x2f3ef + +Potion_HealEffect: ; 2f3ef (b:73ef) + ldh a, [hTemp_ffa0] + ldh [hTempPlayAreaLocation_ff9d], a + ldh a, [hTempPlayAreaLocation_ffa1] + call HealPlayAreaCardHP + ret +; 0x2f3f9 + +GamblerEffect: ; 2f3f9 (b:73f9) + ldtx de, CardCheckIfHeads8CardsIfTails1CardText + call TossCoin_BankB + ldh [hTemp_ffa0], a +; discard Gambler card from hand + ldh a, [hTempCardIndex_ff9f] + call RemoveCardFromHand + call PutCardInDiscardPile + +; shuffle cards into deck + call CreateHandCardList + call SortCardsInDuelTempListByID + ld hl, wDuelTempList +.loop_return_deck + ld a, [hli] + cp $ff + jr z, .check_coin_toss call RemoveCardFromHand call ReturnCardToDeck - jr .return_hand_to_deck_loop -.shuffle + jr .loop_return_deck + +.check_coin_toss call Func_2c0bd - ld a, $07 - bank1call $4935 - ld c, $07 + ld c, 8 + ldh a, [hTemp_ffa0] + or a + jr nz, .draw_cards ; coin toss was heads? + ; if tails, number of cards to draw is 1 + ld c, 1 + +; correct number of cards to draw is in c +.draw_cards + ld a, c + bank1call DisplayDrawNCardsScreen .draw_loop call DrawCardFromDeck - jr c, .revert_turn_to_user + jr c, .done call AddCardToHand dec c jr nz, .draw_loop -.revert_turn_to_user +.done + ret +; 0x2f43b + +; return carry if not enough cards in hand to discard +; or if there are no cards in the Discard Pile +ItemFinder_HandDiscardPileCheck: ; 2f43b (b:743b) + ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND + call GetTurnDuelistVariable + ldtx hl, NotEnoughCardsInHandText + cp 3 + ret c + call CreateTrainerCardListFromDiscardPile + ret +; 0x2f44a + +ItemFinder_PlayerSelection: ; 2f44a (b:744a) + call HandlePlayerSelection2HandCardsToDiscard + ret c ; was operation cancelled? + +; cards were selected to discard from hand. +; now to choose a Trainer card from Discard Pile. + call CreateTrainerCardListFromDiscardPile + bank1call Func_5591 + ldtx hl, ChooseCardToPlaceInHandText + ldtx de, PlayerDiscardPileText + bank1call SetCardListHeaderText + bank1call DisplayCardList + ldh [hTempList + 2], a ; placed after the 2 cards selected to discard + ret +; 0x2f463 + +ItemFinder_DiscardAddToHandEffect: ; 2f463 (b:7463) +; discard cards from hand + ld hl, hTempList + ld a, [hli] + call RemoveCardFromHand + call PutCardInDiscardPile + ld a, [hli] + call RemoveCardFromHand + call PutCardInDiscardPile + +; place card from Discard Pile to hand + ld a, [hl] + call MoveDiscardPileCardToHand + call AddCardToHand + call IsPlayerTurn + ret c +; display card in screen + ldh a, [hTempList + 2] + ldtx hl, WasPlacedInTheHandText + bank1call DisplayCardDetailScreen + ret +; 0x2f488 + +Defender_PlayerSelection: ; 2f488 (b:7488) + ldtx hl, ChoosePokemonToAttachDefenderToText + call DrawWideTextBox_WaitForInput + bank1call HasAlivePokemonInPlayArea + bank1call OpenPlayAreaScreenForSelection + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + ret +; 0x2f499 + +Defender_AttachDefenderEffect: ; 2f499 (b:7499) +; attach Trainer card to Play Area Pokemon + ldh a, [hTemp_ffa0] + ld e, a + ldh a, [hTempCardIndex_ff9f] + call PutHandCardInPlayArea + +; increase number of Defender cards of this location by 1 + ldh a, [hTemp_ffa0] + add DUELVARS_ARENA_CARD_ATTACHED_DEFENDER + call GetTurnDuelistVariable + inc [hl] + call IsPlayerTurn + ret c + + ldh a, [hTemp_ffa0] + call Func_2c10b + ret +; 0x2f4b3 + +; return carry if Bench is full. +MysteriousFossil_BenchCheck: ; 2f4b3 (b:74b3) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + cp MAX_PLAY_AREA_POKEMON + ccf + ldtx hl, NoSpaceOnTheBenchText + ret +; 0x2f4bf + +MysteriousFossil_PlaceInPlayAreaEffect: ; 2f4bf (b:74bf) + ldh a, [hTempCardIndex_ff9f] + call PutHandPokemonCardInPlayArea + ret +; 0x2f4c5 + +; return carry if Arena card has no status to heal. +FullHeal_StatusCheck: ; 2f4c5 (b:74c5) + ld a, DUELVARS_ARENA_CARD_STATUS + call GetTurnDuelistVariable + or a + ret nz + ldtx hl, NotAffectedByPoisonSleepParalysisOrConfusionText + scf + ret +; 0x2f4d1 + +FullHeal_ClearStatusEffect: ; 2f4d1 (b:74d1) + ld a, $8a + call Func_2fea9 + ld a, DUELVARS_ARENA_CARD_STATUS + call GetTurnDuelistVariable + ld [hl], NO_STATUS + bank1call DrawDuelHUDs + ret +; 0x2f4e1 + +ImposterProfessorOakEffect: ; 2f4e1 (b:74e1) + call SwapTurn + call CreateHandCardList + call SortCardsInDuelTempListByID + +; first return all cards in hand to the deck. + ld hl, wDuelTempList +.loop_return_deck + ld a, [hli] + cp $ff + jr z, .done_return + call RemoveCardFromHand + call ReturnCardToDeck + jr .loop_return_deck + +; then draw 7 cards from the deck. +.done_return + call Func_2c0bd + ld a, 7 + bank1call DisplayDrawNCardsScreen + ld c, 7 +.loop_draw + call DrawCardFromDeck + jr c, .done + call AddCardToHand + dec c + jr nz, .loop_draw +.done call SwapTurn ret ; 0x2f513 - INCROM $2f513, $30000 +; return carry if not enough cards in hand to discard +; or if there are no cards left in the deck. +ComputerSearch_HandDeckCheck: ; 2f513 (b:7513) + ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND + call GetTurnDuelistVariable + ldtx hl, NotEnoughCardsInHandText + cp 3 + ret c + ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK + call GetTurnDuelistVariable + ldtx hl, NoCardsLeftInTheDeckText + cp DECK_SIZE + ccf + ret +; 0x2f52a + +ComputerSearch_PlayerDiscardHandSelection: ; 2f52a (b:752a) + call HandlePlayerSelection2HandCardsToDiscard + ret +; 0x2f52e + +ComputerSearch_PlayerDeckSelection: ; 2f52e (b:752e) + call CreateDeckCardList + bank1call Func_5591 + ldtx hl, ChooseCardToPlaceInHandText + ldtx de, DuelistDeckText + bank1call SetCardListHeaderText +.loop_input + bank1call DisplayCardList + jr c, .loop_input ; can't exit with B button + ldh [hTempList + 2], a + ret +; 0x2f545 + +ComputerSearch_DiscardAddToHandEfect: ; 2f545 (b:7545) +; discard cards from hand + ld hl, hTempList + ld a, [hli] + call RemoveCardFromHand + call PutCardInDiscardPile + ld a, [hli] + call RemoveCardFromHand + call PutCardInDiscardPile + +; add card from deck to hand + ld a, [hl] + call SearchCardInDeckAndAddToHand + call AddCardToHand + call Func_2c0bd + ret +; 0x2f561 + +; return carry if Bench is full. +ClefairyDoll_BenchCheck: ; 2f561 (b:7561) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ldtx hl, NoSpaceOnTheBenchText + cp MAX_PLAY_AREA_POKEMON + ccf + ret +; 0x2f56d + +ClefairyDoll_PlaceInPlayAreaEffect: ; 2f56d (b:756d) + ldh a, [hTempCardIndex_ff9f] + call PutHandPokemonCardInPlayArea + ret +; 0x2f573 + +; return carry if no Pokemon in the Bench. +MrFuji_BenchCheck: ; 2f573 (b:7573) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ldtx hl, EffectNoPokemonOnTheBenchText + cp 2 + ret +; 0x2f57e + +MrFuji_PlayerSelection: ; 2f57e (b:757e) + ldtx hl, ChoosePokemonToReturnToTheDeckText + call DrawWideTextBox_WaitForInput + bank1call HasAlivePokemonInBench + bank1call OpenPlayAreaScreenForSelection + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + ret +; 0x2f58f + +MrFuji_ReturnToDeckEffect: ; 2f58f (b:758f) +; get Play Area location's card index + ldh a, [hTemp_ffa0] + add DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + ldh [hTempCardIndex_ff98], a + +; find all cards that are in the same location +; (previous evolutions and energy cards attached) +; and return them all to the deck. + ldh a, [hTemp_ffa0] + or CARD_LOCATION_PLAY_AREA + ld e, a + ld a, DUELVARS_CARD_LOCATIONS + call GetTurnDuelistVariable +.loop_cards + push de + push hl + ld a, [hl] + cp e + jr nz, .next_card + ld a, l + call ReturnCardToDeck +.next_card + pop hl + pop de + inc l + ld a, l + cp DECK_SIZE + jr c, .loop_cards + +; clear Play Area location of card + ldh a, [hTemp_ffa0] + ld e, a + call EmptyPlayAreaSlot + ld l, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + dec [hl] + call ShiftAllPokemonToFirstPlayAreaSlots + +; if Trainer card wasn't played by the Player, +; print the selected Pokemon's name and show card on screen. + call IsPlayerTurn + jr c, .done + ldh a, [hTempCardIndex_ff98] + call LoadCardDataToBuffer1_FromDeckIndex + ld hl, wLoadedCard1Name + ld a, [hli] + ld h, [hl] + ld l, a + call LoadTxRam2 + bank1call DrawLargePictureOfCard + ldtx hl, PokemonAndAllAttachedCardsWereReturnedToDeckText + call DrawWideTextBox_WaitForInput +.done + call Func_2c0bd + ret +; 0x2f5e0 + +PlusPowerEffect: ; 2f5e0 (b:75e0) +; attach Trainer card to Arena Pokemon + ld e, PLAY_AREA_ARENA + ldh a, [hTempCardIndex_ff9f] + call PutHandCardInPlayArea + +; increase number of Defender cards of this location by 1 + ld a, DUELVARS_ARENA_CARD_ATTACHED_PLUSPOWER + call GetTurnDuelistVariable + inc [hl] + ret +; 0x2f5ee + +; return carry if no Pokemon in the Bench. +Switch_BenchCheck: ; 2f5ee (b:75ee) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ldtx hl, EffectNoPokemonOnTheBenchText + cp 2 + ret +; 0x2f5f9 + +Switch_PlayerSelection: ; 2f5f9 (b:75f9) + ldtx hl, SelectPkmnOnBenchToSwitchWithActiveText + call DrawWideTextBox_WaitForInput + bank1call HasAlivePokemonInBench + bank1call OpenPlayAreaScreenForSelection + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTemp_ffa0], a + ret +; 0x2f60a + +Switch_SwitchEffect: ; 2f60a (b:760a) + ldh a, [hTemp_ffa0] + ld e, a + call SwapArenaWithBenchPokemon + ret +; 0x2f611 + +PokemonCenter_DamageCheck: ; 2f611 (b:7611) + call CheckIfPlayAreaHasAnyDamage + ldtx hl, NoPokemonWithDamageCountersText + ret +; 0x2f618 + +PokemonCenter_HealDiscardEnergyEffect: ; 2f618 (b:7618) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ld d, a + ld e, PLAY_AREA_ARENA + +; go through every Pokemon in the Play Area +; and heal all damage & discard their Energy cards. +.loop_play_area +; check its damage + ld a, e + ldh [hTempPlayAreaLocation_ff9d], a + call GetCardDamageAndMaxHP + or a + jr z, .next_pkmn ; if no damage, skip Pokemon + +; heal all its damage + push de + ld e, a + ld d, $00 + call HealPlayAreaCardHP + +; loop all cards in deck and for all the Energy cards +; that are attached to this Play Area location Pokemon, +; place them in the Discard Pile. + ldh a, [hTempPlayAreaLocation_ff9d] + or CARD_LOCATION_PLAY_AREA + ld e, a + ld a, $00 + call GetTurnDuelistVariable +.loop_deck + ld a, [hl] + cp e + jr nz, .next_card_deck ; not attached to card, skip + ld a, l + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Type] + and TYPE_ENERGY + jr z, .next_card_deck ; not Energy, skip + ld a, l + call PutCardInDiscardPile +.next_card_deck + inc l + ld a, l + cp DECK_SIZE + jr c, .loop_deck + + pop de +.next_pkmn + inc e + dec d + jr nz, .loop_play_area + ret +; 0x2f659 + +; return carry if non-Turn Duelist has full Bench +; or if they have no Basic Pokemon cards in Discard Pile. +PokemonFlute_BenchCheck: ; 2f659 (b:7659) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetNonTurnDuelistVariable + ldtx hl, NoSpaceOnTheBenchText + cp MAX_PLAY_AREA_POKEMON + ccf + ret c ; not enough space in Bench + ; check Discard Pile + call SwapTurn + call CreateBasicPokemonCardListFromDiscardPile + ldtx hl, ThereAreNoPokemonInDiscardPileText + call SwapTurn + ret +; 0x2f672 + +PokemonFlute_PlayerSelection: ; 2f672 (b:7672) +; create Discard Pile list + call SwapTurn + call CreateBasicPokemonCardListFromDiscardPile + +; display selection screen and store Player's selection + bank1call Func_5591 + ldtx hl, ChoosePokemonToPlaceInPlayText + ldtx de, PlayerDiscardPileText + bank1call SetCardListHeaderText + bank1call DisplayCardList + call SwapTurn + ldh a, [hTempCardIndex_ff98] + ldh [hTemp_ffa0], a + ret +; 0x2f68f + +PokemonFlute_PlaceInPlayAreaText: ; 2f68f (b:768f) +; place selected card in non-Turn Duelist's Bench + call SwapTurn + ldh a, [hTemp_ffa0] + call MoveDiscardPileCardToHand + call AddCardToHand + call PutHandPokemonCardInPlayArea + call SwapTurn + +; unless it was the Player who played the card, +; display the Pokemon card on screen. + call IsPlayerTurn + ret c + call SwapTurn + ldh a, [hTemp_ffa0] + ldtx hl, CardWasChosenText + bank1call DisplayCardDetailScreen + call SwapTurn + ret +; 0x2f6b3 + +PokemonBreeder_HandPlayAreaCheck: ; 2f6b3 (b:76b3) + call CreatePlayableStage2PokemonCardListFromHand + jr c, .cannot_evolve + bank1call IsPrehistoricPowerActive + ret +.cannot_evolve + ldtx hl, ConditionsForEvolvingToStage2NotFulfilledText + scf + ret +; 0x2f6c1 + +PokemonBreeder_PlayerSelection: ; 2f6c1 (b:76c1) +; create hand list of playable Stage2 cards + call CreatePlayableStage2PokemonCardListFromHand + bank1call Func_5591 + +; handle Player selection of Stage2 card + ldtx hl, PleaseSelectCardText + ldtx de, DuelistHandText + bank1call SetCardListHeaderText + bank1call DisplayCardList + ret c ; exit if B was pressed + + ldh a, [hTempCardIndex_ff98] + ldh [hTemp_ffa0], a + ldtx hl, ChooseBasicPokemonToEvolveText + call DrawWideTextBox_WaitForInput + +; handle Player selection of Basic card to evolve + bank1call HasAlivePokemonInPlayArea +.read_input + bank1call OpenPlayAreaScreenForSelection + ret c ; exit if B was pressed + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTempPlayAreaLocation_ffa1], a + ld e, a + ldh a, [hTemp_ffa0] + ld d, a + call CheckIfCanEvolveInto_BasicToStage2 + jr c, .read_input ; loop back if cannot evolve this card + or a + ret +; 0x2f6f4 + +PokemonBreeder_EvolveEffect: ; 2f6f4 (b:76f4) + ldh a, [hTempCardIndex_ff9f] + push af + ld hl, hTemp_ffa0 + ld a, [hli] + ldh [hTempCardIndex_ff98], a + ld a, [hl] ; hTempPlayAreaLocation_ffa1 + ldh [hTempPlayAreaLocation_ff9d], a + +; load the Basic Pokemon card name to RAM + add DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + call LoadCardDataToBuffer1_FromDeckIndex + ld hl, wLoadedCard1Name + ld a, [hli] + ld h, [hl] + ld l, a + call LoadTxRam2 + +; evolve card and overwrite its stage as STAGE2_WITHOUT_STAGE1 + ldh a, [hTempCardIndex_ff98] + call EvolvePokemonCard + ld [hl], STAGE2_WITHOUT_STAGE1 + +; load Stage2 Pokemon card name to RAM + ldh a, [hTempCardIndex_ff98] + call LoadCardDataToBuffer1_FromDeckIndex + ld a, 18 + call CopyCardNameAndLevel + xor a + ld [hl], a ; $0 character + ld hl, wTxRam2_b + ld [hli], a + ld [hl], a + +; display Pokemon picture and play sfx, +; print the corresponding card names. + bank1call DrawLargePictureOfCard + ld a, $5e + call PlaySFX + ldtx hl, PokemonEvolvedIntoPokemonText + call DrawWideTextBox_WaitForInput + bank1call Func_161e + pop af + ldh [hTempCardIndex_ff9f], a + ret +; 0x2f73e + +; creates list in wDuelTempList of all Stage2 Pokemon cards +; in the hand that can evolve a Basic Pokemon card in Play Area +; through use of Pokemon Breeder. +; returns carry if that list is empty. +CreatePlayableStage2PokemonCardListFromHand: ; 2f73e (b:773e) + call CreateHandCardList + ret c ; return if no hand cards + +; check if hand Stage2 Pokemon cards can be made +; to evolve a Basic Pokemon in the Play Area and, if so, +; add it to the wDuelTempList. + ld hl, wDuelTempList + ld e, l + ld d, h +.loop_hand + ld a, [hl] + cp $ff + jr z, .done + call .CheckIfCanEvolveAnyPlayAreaBasicCard + jr c, .next_hand_card + ld a, [hl] + ld [de], a + inc de +.next_hand_card + inc hl + jr .loop_hand + +.done + ld a, $ff ; terminating byte + ld [de], a + ld a, [wDuelTempList] + cp $ff + scf + ret z ; return carry if empty + ; not empty + or a + ret + +; return carry if Stage2 card in a cannot evolve any +; of the Basic Pokemon in Play Area through Pokemon Breeder. +.CheckIfCanEvolveAnyPlayAreaBasicCard + push de + ld d, a + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Type] + cp TYPE_ENERGY + jr nc, .set_carry ; skip if not Pokemon card + ld a, [wLoadedCard2Stage] + cp STAGE2 + jr nz, .set_carry ; skip if not Stage2 + +; check if can evolve any Play Area cards + push hl + push bc + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ld c, a + ld e, PLAY_AREA_ARENA +.loop_play_area + push bc + push de + call CheckIfCanEvolveInto_BasicToStage2 + pop de + pop bc + jr nc, .done_play_area + inc e + dec c + jr nz, .loop_play_area +; set carry + scf +.done_play_area + pop bc + pop hl + pop de + ret +.set_carry + pop de + scf + ret +; 0x2f795 + +; return carry if no cards in the Bench. +ScoopUp_BenchCheck: ; 2f795 (b:7795) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ldtx hl, EffectNoPokemonOnTheBenchText + cp 2 + ret +; 0x2f7a0 + +ScoopUp_PlayerSelection: ; 2f7a0 (b:77a0) +; print text box + ldtx hl, ChoosePokemonToScoopUpText + call DrawWideTextBox_WaitForInput + +; handle Player selection + bank1call HasAlivePokemonInPlayArea + bank1call OpenPlayAreaScreenForSelection + ret c ; exit if B was pressed + + ldh [hTemp_ffa0], a + or a + ret nz ; if it wasn't the Active Pokemon, we are done + +; handle switching to a Pokemon in Bench and store location selected. + call EmptyScreen + ldtx hl, SelectPokemonToPlaceInTheArenaText + call DrawWideTextBox_WaitForInput + bank1call HasAlivePokemonInBench + bank1call OpenPlayAreaScreenForSelection + ldh [hTempPlayAreaLocation_ffa1], a + ret +; 0x2f7c3 + +ScoopUp_ReturnToHandEffect: ; 2f7c3 (b:77c3) +; store chosen card location to Scoop Up + ldh a, [hTemp_ffa0] + or CARD_LOCATION_PLAY_AREA + ld e, a + +; find Basic Pokemon card that is in the selected Play Area location +; and add it to the hand, discarding all cards attached. + ld a, DUELVARS_CARD_LOCATIONS + call GetTurnDuelistVariable +.loop + ld a, [hl] + cp e + jr nz, .next_card ; skip if not in selected location + ld a, l + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Type] + cp TYPE_ENERGY + jr nc, .next_card ; skip if not Pokemon card + ld a, [wLoadedCard2Stage] + or a + jr nz, .next_card ; skip if not Basic stage +; found + ld a, l + ldh [hTempCardIndex_ff98], a + call AddCardToHand + ; optimization: break loop here, since + ; no two Basic Pokemon cards may occupy + ; the same Play Area location. +.next_card + inc l + ld a, l + cp DECK_SIZE + jr c, .loop + +; since the card has been moved to hand, +; MovePlayAreaCardToDiscardPile will take care +; of discarding every higher stage cards and other cards attached. + ldh a, [hTemp_ffa0] + ld e, a + call MovePlayAreaCardToDiscardPile + +; if the Pokemon was in the Arena, clear status + ldh a, [hTemp_ffa0] + or a + jr nz, .skip_clear_status + call ClearAllStatusConditions +.skip_clear_status + +; if card was not played by Player, show detail screen +; and print corresponding text. + call IsPlayerTurn + jr c, .shift_or_switch + ldtx hl, PokemonWasReturnedFromArenaToHandText + ldh a, [hTemp_ffa0] + or a + jr z, .display_detail_screen + ldtx hl, PokemonWasReturnedFromBenchToHandText +.display_detail_screen + ldh a, [hTempCardIndex_ff98] + bank1call DisplayCardDetailScreen + +.shift_or_switch +; if card was in Bench, simply shift Pokemon slots... + ldh a, [hTemp_ffa0] + or a + jr z, .switch + call ShiftAllPokemonToFirstPlayAreaSlots + ret + +.switch +; ...if Pokemon was in Arena, then switch it with the selected Bench card. + ldh a, [hTempPlayAreaLocation_ffa1] + ld d, a + ld e, PLAY_AREA_ARENA + call SwapPlayAreaPokemon + call ShiftAllPokemonToFirstPlayAreaSlots + ret +; 0x2f826 + +; return carry if no other cards in hand, +; or if there are no Pokemon cards in hand. +PokemonTrader_HandDeckCheck: ; 2f826 (b:7826) + ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND + call GetTurnDuelistVariable + ldtx hl, ThereAreNoCardsInHandThatYouCanChangeText + cp 2 + ret c ; return if no other cards in hand + call CreatePokemonCardListFromHand + ldtx hl, ThereAreNoCardsInHandThatYouCanChangeText + ret +; 0x2f838 + +PokemonTrader_PlayerHandSelection: ; 2f838 (b:7838) +; print text box + ldtx hl, ChooseCardFromYourHandToSwitchText + call DrawWideTextBox_WaitForInput + +; create list with all Pokemon cards in hand + call CreatePokemonCardListFromHand + bank1call Func_5591 + +; handle Player selection + ldtx hl, ChooseCardToSwitchText + ldtx de, DuelistHandText + bank1call SetCardListHeaderText + bank1call DisplayCardList + ldh [hTemp_ffa0], a + ret +; 0x2f853 + +PokemonTrader_PlayerDeckSelection: ; 2f853 (b:7853) +; temporarily place chosen hand card in deck +; so it can be potentially chosen to be traded. + ldh a, [hTemp_ffa0] + call RemoveCardFromHand + call ReturnCardToDeck + +; display deck card list screen + ldtx hl, ChooseBasicOrEvolutionPokemonCardFromDeckText + call DrawWideTextBox_WaitForInput + call CreateDeckCardList + bank1call Func_5591 + ldtx hl, ChoosePokemonCardText + ldtx de, DuelistDeckText + bank1call SetCardListHeaderText + +; handle Player selection +.read_input + bank1call DisplayCardList + jr c, .read_input ; pressing B loops back to selection + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Type] + cp TYPE_ENERGY + jr nc, .read_input ; can't select non-Pokemon cards + +; a valid card was selected, store its card index and +; place the selected hand card back to the hand. + ldh a, [hTempCardIndex_ff98] + ldh [hTempPlayAreaLocation_ffa1], a + ldh a, [hTemp_ffa0] + call SearchCardInDeckAndAddToHand + call AddCardToHand + or a + ret +; 0x2f88d + +PokemonTrader_TradeCardsEffect: ; 2f88d (b:788d) +; place hand card in deck + ldh a, [hTemp_ffa0] + call RemoveCardFromHand + call ReturnCardToDeck + +; place deck card in hand + ldh a, [hTempPlayAreaLocation_ffa1] + call SearchCardInDeckAndAddToHand + call AddCardToHand + +; display cards if the Pokemon Trader wasn't played by Player + call IsPlayerTurn + jr c, .done + ldh a, [hTemp_ffa0] + ldtx hl, PokemonWasReturnedToDeckText + bank1call DisplayCardDetailScreen + ldh a, [hTempPlayAreaLocation_ffa1] + ldtx hl, WasPlacedInTheHandText + bank1call DisplayCardDetailScreen +.done + call Func_2c0bd + ret +; 0x2f8b6 + +; makes list in wDuelTempList with all Pokemon cards +; that are in Turn Duelist's hand. +; if list turns out empty, return carry. +CreatePokemonCardListFromHand: ; 2f8b6 (b:78b6) + ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND + call GetTurnDuelistVariable + ld c, a + ld l, DUELVARS_HAND + ld de, wDuelTempList +.loop + ld a, [hl] + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Type] + cp TYPE_ENERGY + jr nc, .next_hand_card + ld a, [hl] + ld [de], a + inc de +.next_hand_card + inc l + dec c + jr nz, .loop + ld a, $ff ; terminating byte + ld [de], a + ld a, [wDuelTempList] + cp $ff + jr z, .set_carry + or a + ret +.set_carry + scf + ret +; 0x2f8e1 + +; return carry if no cards in deck +Pokedex_DeckCheck: ; 2f8e1 (b:78e1) + ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK + call GetTurnDuelistVariable + ldtx hl, NoCardsLeftInTheDeckText + cp DECK_SIZE + ccf + ret +; 0x2f8ed + +Pokedex_PlayerSelection: ; 2f8ed (b:78ed) +; print text box + ldtx hl, RearrangeThe5CardsAtTopOfDeckText + call DrawWideTextBox_WaitForInput + +; cap the number of cards to reorder up to +; number of cards left in the deck (maximum of 5) + ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK + call GetTurnDuelistVariable + ld b, a + ld a, DECK_SIZE + sub [hl] + ld c, 5 + cp c + jr nc, .no_cap + ld c, a +.no_cap + +; fill wDuelTempList with cards that are going to be sorted + ld a, c + inc a + ld [wNumberOfCardsToOrder], a + ld a, b + add DUELVARS_DECK_CARDS + ld l, a + ld de, wDuelTempList +.loop_cards_to_order + ld a, [hli] + ld [de], a + inc de + dec c + jr nz, .loop_cards_to_order + ld a, $ff ; terminating byte + ld [de], a + +.clear_list +; wDuelTempList + 10 will be filled with numbers from 1 +; to 5 (or whatever the maximum order card is). +; so that the first item in that list corresponds to the first card +; the second item corresponds to the second card, etc. +; and the number in the list corresponds to the ordering number. + call CountCardsInDuelTempList + ld b, a + ld a, 1 +; fill order list with zeroes + ldh [hCurSelectionItem], a + ld hl, wDuelTempList + 10 + xor a +.loop_init + ld [hli], a + dec b + jr nz, .loop_init + ld [hl], $ff ; terminating byte + +; display card list to order + bank1call InitAndDrawCardListScreenLayout + ldtx hl, ChooseTheOrderOfTheCardsText + ldtx de, DuelistDeckText + bank1call SetCardListHeaderText + bank1call Func_5735 + +.read_input + bank1call DisplayCardList + jr c, .undo ; if B is pressed, undo last order selection + +; a card was selected, check if it's already been selected + ldh a, [hCurMenuItem] + ld e, a + ld d, $00 + ld hl, wDuelTempList + 10 + add hl, de + ld a, [hl] + or a + jr nz, .read_input ; already has an ordering number + +; hasn't been ordered yet, apply to it current ordering number +; and increase it by 1. + ldh a, [hCurSelectionItem] + ld [hl], a + inc a + ldh [hCurSelectionItem], a + +; refresh screen + push af + bank1call Func_5744 + pop af + +; check if we're done ordering + ldh a, [hCurSelectionItem] + ld hl, wNumberOfCardsToOrder + cp [hl] + jr c, .read_input ; if still more cards to select, loop back up + +; we're done selecting cards + call EraseCursor + ldtx hl, IsThisOKText + call YesOrNoMenuWithText_LeftAligned + jr c, .clear_list ; "No" was selected, start over + ; selection was confirmed + +; now wDuelTempList + 10 will be overwritten with the +; card indices in order of selection. + ld hl, wDuelTempList + 10 + ld de, wDuelTempList + ld c, 0 +.loop_write_indices + ld a, [hli] + cp $ff + jr z, .done_write_indices + push hl + push bc + ld c, a + ld b, $00 + ld hl, hTempCardIndex_ff9f + add hl, bc + ld a, [de] + ld [hl], a + pop bc + pop hl + inc de + inc c + jr .loop_write_indices + +.done_write_indices + ld b, $00 + ld hl, hTempList + add hl, bc + ld [hl], $ff ; terminating byte + or a + ret + +.undo +; undo last selection and get previous order number + ld hl, hCurSelectionItem + ld a, [hl] + cp 1 + jr z, .read_input ; already at first input, nothing to undo + dec a + ld [hl], a + ld c, a + ld hl, wDuelTempList + 10 +.asm_2f99e + ld a, [hli] + cp c + jr nz, .asm_2f99e + dec hl + ld [hl], $00 ; overwrite order number with 0 + bank1call Func_5744 + jr .read_input +; 0x2f9aa + +Pokedex_OrderDeckCardsEffect: ; 2f9aa (b:79aa) +; place cards in order to the hand. + ld hl, hTempList + ld c, 0 +.loop_place_hand + ld a, [hli] + cp $ff + jr z, .place_top_deck + call SearchCardInDeckAndAddToHand + inc c + jr .loop_place_hand + +.place_top_deck +; go to last card in list and iterate in decreasing order +; placing each card in top of deck. + dec hl + dec hl +.loop_place_deck + ld a, [hld] + call ReturnCardToDeck + dec c + jr nz, .loop_place_deck + ret +; 0x2f9c4 + +BillEffect: ; 2f9c4 (b:79c4) + ld a, 2 + bank1call DisplayDrawNCardsScreen + ld c, 2 +.loop_draw + call DrawCardFromDeck + jr c, .done + ldh [hTempCardIndex_ff98], a + call AddCardToHand + call IsPlayerTurn + jr nc, .skip_display_screen + push bc + bank1call DisplayPlayerDrawCardScreen + pop bc +.skip_display_screen + dec c + jr nz, .loop_draw +.done + ret +; 0x2f9e3 + +LassEffect: ; 2f9e3 (b:79e3) +; first discard Lass card that was used + ldh a, [hTempCardIndex_ff9f] + call RemoveCardFromHand + call PutCardInDiscardPile + + ldtx hl, PleaseCheckTheOpponentsHandText + call DrawWideTextBox_WaitForInput + + call .DisplayLinkOrCPUHand + ; do for non-Turn Duelist + call SwapTurn + call .ShuffleDuelistHandTrainerCardsInDeck + call SwapTurn + ; do for Turn Duelist +; fallthrough + +.ShuffleDuelistHandTrainerCardsInDeck + call CreateHandCardList + call SortCardsInDuelTempListByID + xor a + ldh [hCurSelectionItem], a + ld hl, wDuelTempList + +; go through all cards in hand +; and any Trainer card is returned to deck. +.loop_hand + ld a, [hli] + ldh [hTempCardIndex_ff98], a + cp $ff + jr z, .done + call GetCardIDFromDeckIndex + call GetCardType + cp TYPE_TRAINER + jr nz, .loop_hand + ldh a, [hTempCardIndex_ff98] + call RemoveCardFromHand + call ReturnCardToDeck + push hl + ld hl, hCurSelectionItem + inc [hl] + pop hl + jr .loop_hand +.done +; show card list + ldh a, [hCurSelectionItem] + or a + call nz, Func_2c0bd ; only show list if there were any Trainer cards + ret +; 0x2fa31 + +.DisplayLinkOrCPUHand ; 2fa31 (b:7a31) + ld a, [wDuelType] + or a + jr z, .cpu_opp + +; link duel + ldh a, [hWhoseTurn] + push af + ld a, OPPONENT_TURN + ldh [hWhoseTurn], a + call .DisplayOppHand + pop af + ldh [hWhoseTurn], a + ret + +.cpu_opp + call SwapTurn + call .DisplayOppHand + call SwapTurn + ret +; 0x2fa4f + +.DisplayOppHand ; 2fa4f (b:7a4f) + call CreateHandCardList + jr c, .no_cards + bank1call InitAndDrawCardListScreenLayout + ldtx hl, ChooseTheCardYouWishToExamineText + ldtx de, DuelistHandText + bank1call SetCardListHeaderText + ld a, A_BUTTON | START + ld [wNoItemSelectionMenuKeys], a + bank1call DisplayCardList + ret +.no_cards + ldtx hl, DuelistHasNoCardsInHandText + call DrawWideTextBox_WaitForInput + ret +; 0x2fa70 + +; return carry if not enough cards in hand for effect +Maintenance_HandCheck: ; 2fa70 (b:7a70) + ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND + call GetTurnDuelistVariable + ldtx hl, NotEnoughCardsInHandText + cp 3 + ret +; 0x2fa7b + +Maintenance_PlayerSelection: ; 2fa7b (b:7a7b) + ldtx hl, Choose2HandCardsFromHandToReturnToDeckText + ldtx de, ChooseTheCardToPutBackText + call HandlePlayerSelection2HandCards + ret +; 0x2fa85 + +Maintenance_ReturnToDeckAndDrawEffect: ; 2fa85 (b:7a85) +; return both selected cards to the deck + ldh a, [hTempList] + call RemoveCardFromHand + call ReturnCardToDeck + ldh a, [hTempList + 1] + call RemoveCardFromHand + call ReturnCardToDeck + call Func_2c0bd + +; draw one card + ld a, 1 + bank1call DisplayDrawNCardsScreen + call DrawCardFromDeck + ldh [hTempCardIndex_ff98], a + call AddCardToHand + call IsPlayerTurn + ret nc + ; show card on screen if played by Player + bank1call DisplayPlayerDrawCardScreen + ret +; 0x2faad + +; return carry if no cards in deck +PokeBall_DeckCheck: ; 2faad (b:7aad) + ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK + call GetTurnDuelistVariable + ldtx hl, NoCardsLeftInTheDeckText + cp DECK_SIZE + ccf + ret +; 0x2fab9 + +PokeBall_PlayerSelection: ; 2fab9 (b:7ab9) + ld de, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call Func_2c08a + ldh [hTempList], a ; store coin result + ret nc + +; create list of all Pokemon cards in deck to search for + call CreateDeckCardList + ldtx hl, ChooseBasicOrEvolutionPokemonCardFromDeckText + ldtx bc, EvolutionCardText + lb de, SEARCHEFFECT_POKEMON, 0 + call LookForCardsInDeck + jr c, .no_pkmn ; return if Player chose not to check deck + +; handle input + bank1call Func_5591 + ldtx hl, ChoosePokemonCardText + ldtx de, DuelistDeckText + bank1call SetCardListHeaderText +.read_input + bank1call DisplayCardList + jr c, .try_exit ; B was pressed, check if Player can cancel operation + ldh a, [hTempCardIndex_ff98] + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Type] + cp TYPE_ENERGY + jr nc, .play_sfx ; can't select non-Pokemon card + ldh a, [hTempCardIndex_ff98] + ldh [hTempList + 1], a + or a + ret + +.no_pkmn + ld a, $ff + ldh [hTempList + 1], a + or a + ret + +.play_sfx + call Func_3794 + jr .read_input + +.try_exit +; Player can only exit screen if there are no cards to choose + ld hl, wDuelTempList +.loop + ld a, [hli] + cp $ff + jr z, .no_pkmn + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Type] + cp TYPE_ENERGY + jr nc, .loop + jr .read_input +; 0x2fb15 + +PokeBall_AddToHandEffect: ; 2fb15 (b:7b15) + ldh a, [hTempList] + or a + ret z ; return if coin toss was tails + + ldh a, [hTempList + 1] + cp $ff + jr z, .done ; skip if no Pokemon was chosen + +; add Pokemon card to hand and show in screen if +; it wasn't the Player who played the Trainer card. + call SearchCardInDeckAndAddToHand + call AddCardToHand + call IsPlayerTurn + jr c, .done + ldh a, [hTempList + 1] + ldtx hl, WasPlacedInTheHandText + bank1call DisplayCardDetailScreen +.done + call Func_2c0bd + ret +; 0x2fb36 + +; return carry if no cards in the Discard Pile +Recycle_DiscardPileCheck: ; 2fb36 (b:7b36) + ld a, DUELVARS_NUMBER_OF_CARDS_IN_DISCARD_PILE + call GetTurnDuelistVariable + ldtx hl, ThereAreNoCardsInTheDiscardPileText + cp 1 + ret +; 0x2fb41 + +Recycle_PlayerSelection: ; 2fb41 (b:7b41) + ld de, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call Func_2c08a + jr nc, .tails + + call CreateDiscardPileCardList + bank1call Func_5591 + ldtx hl, PleaseSelectCardText + ldtx de, PlayerDiscardPileText + bank1call SetCardListHeaderText +.read_input + bank1call DisplayCardList + jr c, .read_input ; can't cancel with B button + +; Discard Pile card was chosen + ldh a, [hTempCardIndex_ff98] + ldh [hTempList], a + ret + +.tails + ld a, $ff + ldh [hTempList], a + or a + ret +; 0x2fb68 + +Recycle_AddToHandEffect: ; 2fb68 (b:7b68) + ldh a, [hTempList] + cp $ff + ret z ; return if no card was selected + +; add card to hand and show in screen if +; it wasn't the Player who played the Trainer card. + call MoveDiscardPileCardToHand + call ReturnCardToDeck + call IsPlayerTurn + ret c + ldh a, [hTempList] + ldtx hl, CardWasChosenText + bank1call DisplayCardDetailScreen + ret +; 0x2fb80 + +; return carry if Bench is full or +; if no Basic Pokemon cards in Discard Pile. +Revive_BenchCheck: ; 2fb80 (b:7b80) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ldtx hl, NoSpaceOnTheBenchText + cp MAX_PLAY_AREA_POKEMON + ccf + ret c + call CreateBasicPokemonCardListFromDiscardPile + ldtx hl, ThereAreNoPokemonInDiscardPileText + ret +; 0x2fb93 + +Revive_PlayerSelection: ; 2fb93 (b:7b93) +; create Basic Pokemon card list from Discard Pile + ldtx hl, ChooseBasicPokemonToPlaceOnBenchText + call DrawWideTextBox_WaitForInput + call CreateBasicPokemonCardListFromDiscardPile + bank1call Func_5591 + +; display screen to select Pokemon + ldtx hl, PleaseSelectCardText + ldtx de, PlayerDiscardPileText + bank1call SetCardListHeaderText + bank1call DisplayCardList + +; store selection + ldh a, [hTempCardIndex_ff98] + ldh [hTemp_ffa0], a + ret +; 0x2fbb0 + +Revive_PlaceInPlayAreaEffect: ; 2fbb0 (b:7bb0) +; place selected Pokemon in the Bench + ldh a, [hTemp_ffa0] + call MoveDiscardPileCardToHand + call AddCardToHand + call PutHandPokemonCardInPlayArea + +; set HP to half, rounded up + add DUELVARS_ARENA_CARD_HP + call GetTurnDuelistVariable + srl a + bit 0, a + jr z, .rounded + add 5 ; round up HP to nearest 10 +.rounded + ld [hl], a + call IsPlayerTurn + ret c ; done if Player played Revive + +; display card + ldh a, [hTemp_ffa0] + ldtx hl, PlacedOnTheBenchText + bank1call DisplayCardDetailScreen + ret +; 0x2fbd6 + +; makes list in wDuelTempList with all Basic Pokemon cards +; that are in Turn Duelist's Discard Pile. +; if list turns out empty, return carry. +CreateBasicPokemonCardListFromDiscardPile: ; 2fbd6 (b:7bd6) +; gets hl to point at end of Discard Pile cards +; and iterates the cards in reverse order. + ld a, DUELVARS_NUMBER_OF_CARDS_IN_DISCARD_PILE + call GetTurnDuelistVariable + ld b, a + add DUELVARS_DECK_CARDS + ld l, a + ld de, wDuelTempList + inc b + jr .next_discard_pile_card + +.check_card + ld a, [hl] + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Type] + cp TYPE_ENERGY + jr nc, .next_discard_pile_card ; if not Pokemon card, skip + ld a, [wLoadedCard2Stage] + or a + jr nz, .next_discard_pile_card ; if not Basic stage, skip + +; write this card'sindex to wDuelTempList + ld a, [hl] + ld [de], a + inc de +.next_discard_pile_card + dec l + dec b + jr nz, .check_card + +; done with the loop. + ld a, $ff ; terminating byte + ld [de], a + ld a, [wDuelTempList] + cp $ff + jr z, .set_carry + or a + ret +.set_carry + scf + ret +; 0x2fc0b + +; return carry if Turn Duelist has no Evolution cards in Play Area +DevolutionSpray_PlayAreaEvolutionCheck: ; 2fc0b (b:7c0b) + ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA + call GetTurnDuelistVariable + ld c, a + ld l, DUELVARS_ARENA_CARD +.loop + ld a, [hli] + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Stage] + or a + ret nz ; found an Evolution card + dec c + jr nz, .loop + + ldtx hl, ThereAreNoStage1PokemonText + scf + ret +; 0x2fc24 + +DevolutionSpray_PlayerSelection: ; 2fc24 (b:7c24) +; display textbox + ldtx hl, ChooseEvolutionCardAndPressAButtonToDevolveText + call DrawWideTextBox_WaitForInput + +; have Player select an Evolution card in Play Area + ld a, 1 + ldh [hCurSelectionItem], a + bank1call HasAlivePokemonInPlayArea +.read_input + bank1call OpenPlayAreaScreenForSelection + ret c ; exit if B was pressed + bank1call GetCardOneStageBelow + jr c, .read_input ; can't select Basic cards + +; get pre-evolution card data + ldh a, [hTempPlayAreaLocation_ff9d] + add DUELVARS_ARENA_CARD_HP + call GetTurnDuelistVariable + push hl + push af + ldh a, [hTempPlayAreaLocation_ff9d] + add DUELVARS_ARENA_CARD_STAGE + ld l, a + ld a, [hl] + push hl + push af + ldh a, [hTempPlayAreaLocation_ff9d] + add DUELVARS_ARENA_CARD + ld l, a + ld a, [hl] + push hl + push af + jr .update_data + +.repeat_devolution +; show Play Area screen with static cursor +; so that the Player either presses A to do one more devolution +; or presses B to finish selection. + bank1call Func_6194 + jr c, .done_selection ; if B pressed, end selection instead + ; do one more devolution + bank1call GetCardOneStageBelow + +.update_data +; overwrite the card data to new devolved stats + ld a, d + call UpdateDevolvedCardHPAndStage + call GetNextPositionInTempList_TrainerEffects + ld [hl], e + ld a, d + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Stage] + or a + jr nz, .repeat_devolution ; can do one more devolution + +.done_selection + call GetNextPositionInTempList_TrainerEffects + ld [hl], $ff ; terminating byte + +; store this Play Area location in first item of temp list + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hTempList], a + +; update Play Area location display of this Pokemon + call EmptyScreen + ldh a, [hTempPlayAreaLocation_ff9d] + ld hl, wHUDEnergyAndHPBarsX + ld [hli], a + ld [hl], $00 + bank1call PrintPlayAreaCardInformationAndLocation + call EnableLCD + pop bc + pop hl + +; rewrite all duelvars from before the selection was done +; this is so that if "No" is selected in confirmation menu, +; then the Pokemon isn't devolved and remains unchanged. + ld [hl], b + ldtx hl, IsThisOKText + call YesOrNoMenuWithText + pop bc + pop hl + + ld [hl], b + pop bc + pop hl + + ld [hl], b + ret +; 0x2fc99 + +DevolutionSpray_DevolutionEffect: ; 2fc99 (b:7c99) +; first byte in list is Play Area location chosen + ld hl, hTempList + ld a, [hli] + ldh [hTempPlayAreaLocation_ff9d], a + add DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + push hl + push af + +; loop through devolutions selected + ld hl, hTempList + 1 +.loop_devolutions + ld a, [hl] + cp $ff + jr z, .check_ko ; list is over + ; devolve card to its stage below + push hl + bank1call GetCardOneStageBelow + ld a, d + call UpdateDevolvedCardHPAndStage + call ResetDevolvedCardStatus + pop hl + ld a, [hli] + call PutCardInDiscardPile + jr .loop_devolutions + +.check_ko + pop af + ld e, a + pop hl + ld d, [hl] + call PrintDevolvedCardNameAndLevelText + ldh a, [hTempList] + call PrintPlayAreaCardKnockedOutIfNoHP + bank1call Func_6e49 + ret +; 0x2fcd0 + +Func_2fcd0: ; 2fcd0 (b:7cd0) + call CheckIfThereAreAnyEnergyCardsAttached + ldtx hl, NoEnergyCardsAttachedToPokemonInYourPlayAreaText + ret c + call SwapTurn + call CheckIfThereAreAnyEnergyCardsAttached + ldtx hl, NoEnergyCardsAttachedToPokemonInOppPlayAreaText + call SwapTurn + ret +; 0x2fce4 + +Func_2fce4: ; 2fce4 (b:7ce4) +; handle selection of Energy to discard in own Play Area + ldtx hl, ChoosePokemonInYourAreaThenPokemonInYourOppText + call DrawWideTextBox_WaitForInput + call HandlePokemonAndEnergySelectionScreen + ret c ; return if operation was cancelled + + ldtx hl, ChoosePokemonToRemoveEnergyFromText + call DrawWideTextBox_WaitForInput + + call SwapTurn + ld a, 3 + ldh [hCurSelectionItem], a +.select_opp_pkmn + bank1call HasAlivePokemonInPlayArea + bank1call OpenPlayAreaScreenForSelection + jr nc, .opp_pkmn_selected + ; B was pressed + call SwapTurn + ret ; return if operation was cancelled +.opp_pkmn_selected + ld e, a + call GetPlayAreaCardAttachedEnergies + ld a, [wTotalAttachedEnergies] + or a + jr nz, .has_energy ; has any energy cards attached? + ; no energy, loop back + ldtx hl, NoEnergyCardsText + call DrawWideTextBox_WaitForInput + jr .select_opp_pkmn + +.has_energy +; store this Pokemon's Play Area location + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hPlayAreaEffectTarget], a + + bank1call CreateArenaOrBenchEnergyCardList + ldh a, [hTempPlayAreaLocation_ff9d] + bank1call DisplayEnergyDiscardScreen + ld a, 2 + ld [wcbfa], a +.asm_2fd2a + bank1call HandleEnergyDiscardMenuInput + jr nc, .asm_2fd4a + ld a, 5 + call AskWhetherToQuitSelectingCards + jr nc, .asm_2fd69 + ld a, [wcbfb] + push af + ldh a, [hTempPlayAreaLocation_ff9d] + bank1call DisplayEnergyDiscardScreen + ld a, 2 + ld [wcbfa], a + pop af + ld [wcbfb], a + jr .asm_2fd2a +.asm_2fd4a + call GetNextPositionInTempList_TrainerEffects + ldh a, [hTempCardIndex_ff98] + ld [hl], a + call RemoveCardFromDuelTempList + ld hl, wcbfb + inc [hl] + ldh a, [hCurSelectionItem] + cp $05 + jr nc, .asm_2fd69 + ld a, [wDuelTempList] + cp $ff + jr z, .asm_2fd69 + bank1call DisplayEnergyDiscardMenu + jr .asm_2fd2a +.asm_2fd69 + call GetNextPositionInTempList_TrainerEffects + ld [hl], $ff + call SwapTurn + or a + ret +; 0x2fd73 + + INCROM $2fd73, $2fe25 + +; outputs in hl the next position +; in hTempList to place a new card, +; and increments hCurSelectionItem. +; identical to GetNextPositionInTempList. +GetNextPositionInTempList_TrainerEffects: ; 2fe25 (b:7e25) + push de + ld hl, hCurSelectionItem + ld a, [hl] + inc [hl] + ld e, a + ld d, $00 + ld hl, hTempList + add hl, de + pop de + ret +; 0x2fe34 + +; handles screen for Player to select 2 cards from the hand to discard. +; first prints text informing Player to choose cards to discard +; then runs HandlePlayerSelection2HandCards routine. +HandlePlayerSelection2HandCardsToDiscard: ; 2fe34 (b:7e34) + ldtx hl, Choose2CardsFromHandToDiscardText + ldtx de, ChooseTheCardToDiscardText +; fallthrough + +; handles screen for Player to select 2 cards from the hand +; to activate some Trainer card effect. +; assumes Trainer card index being used is in [hTempCardIndex_ff9f]. +; stores selection of cards in hTempList. +; returns carry if Player cancels operation. +; input: +; hl = text to print in text box; +; de = text to print in screen header. +HandlePlayerSelection2HandCards: ; 2fe3a (b:7e3a) + push de + call DrawWideTextBox_WaitForInput + +; remove the Trainer card being used from list +; of cards to select from hand. + call CreateHandCardList + ldh a, [hTempCardIndex_ff9f] + call RemoveCardFromDuelTempList + + xor a + ldh [hCurSelectionItem], a + pop hl +.loop + push hl + bank1call Func_5591 + pop hl + bank1call SetCardListInfoBoxText + push hl + bank1call DisplayCardList + pop hl + jr c, .set_carry ; was B pressed? + push hl + call GetNextPositionInTempList_TrainerEffects + ldh a, [hTempCardIndex_ff98] + ld [hl], a + call RemoveCardFromDuelTempList + pop hl + ldh a, [hCurSelectionItem] + cp 2 + jr c, .loop ; is selection over? + or a + ret +.set_carry + scf + ret +; 0x2fe6e + + INCROM $2fe6e, $2fea9 + +; input: +; a = move animation to play +Func_2fea9: ; 2fea9 (b:7ea9) + ld [wLoadedMoveAnimation], a + bank1call Func_7415 + ld bc, $0 + ldh a, [hWhoseTurn] + ld h, a + bank1call PlayMoveAnimation + bank1call WaitMoveAnimation + ret +; 0x2febc + +; heals amount of damage in register e for card in +; Play Area location in [hTempPlayAreaLocation_ff9d]. +; plays healing animation and prints text with card's name. +; input: +; e = amount of HP to heal +; [hTempPlayAreaLocation_ff9d] = Play Area location of card to heal +HealPlayAreaCardHP: ; 2febc (b:7ebc) + ld e, a + ld d, $00 + +; play heal animation + push de + bank1call Func_7415 + ld a, $86 + ld [wLoadedMoveAnimation], a + ldh a, [hTempPlayAreaLocation_ff9d] + ld b, a + ld c, $01 + ldh a, [hWhoseTurn] + ld h, a + bank1call PlayMoveAnimation + bank1call WaitMoveAnimation + pop hl + +; print Pokemon card name and damage healed + push hl + call LoadTxRam3 + ld hl, $0000 + call LoadTxRam2 + ldh a, [hTempPlayAreaLocation_ff9d] + add DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + call LoadCardDataToBuffer1_FromDeckIndex + ld a, 18 + call CopyCardNameAndLevel + ld [hl], $00 ; terminating character on end of the name + ldtx hl, PokemonHealedDamageText + call DrawWideTextBox_WaitForInput + pop de + +; heal the target Pokemon + ldh a, [hTempPlayAreaLocation_ff9d] + add DUELVARS_ARENA_CARD_HP + call GetTurnDuelistVariable + add e + ld [hl], a + ret +; 0x2ff03 + +rept $fd + db $ff +endr |