INCLUDE "data/ai_trainer_card_logic.asm" _AIProcessHandTrainerCards: ; 200e5 (8:40e5) ld [wAITrainerCardPhase], a ; create hand list in wDuelTempList and wTempHandCardList. call CreateHandCardList ld hl, wDuelTempList ld de, wTempHandCardList call CopyBuffer ld hl, wTempHandCardList .loop_hand ld a, [hli] ld [wAITrainerCardToPlay], a cp $ff ret z push hl ld a, [wAITrainerCardPhase] ld d, a ld hl, AITrainerCardLogic .loop_data xor a ld [wCurrentAIFlags], a ld a, [hli] cp $ff jp z, .pop_hl ; compare input to first byte in data and continue if equal. cp d jp nz, .inc_hl_by_5 ld a, [hli] ld [wce17], a ld a, [wAITrainerCardToPlay] call LoadCardDataToBuffer1_FromDeckIndex cp SWITCH jr nz, .skip_switch_check ld b, a ld a, [wPreviousAIFlags] and AI_FLAG_USED_SWITCH jr nz, .inc_hl_by_4 ld a, b .skip_switch_check ; compare hand card to second byte in data and continue if equal. ld b, a ld a, [wce17] cp b jr nz, .inc_hl_by_4 ; found Trainer card push hl push de ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ; if Headache effects prevent playing card ; move on to the next item in list. bank1call CheckCantUseTrainerDueToHeadache jp c, .next_in_data call LoadNonPokemonCardEffectCommands ld a, EFFECTCMDTYPE_INITIAL_EFFECT_1 call TryExecuteEffectCommandFunction jp c, .next_in_data ; AI can randomly choose not to play card. farcall AIChooseRandomlyNotToDoAction jr c, .next_in_data ; call routine to decide whether to play Trainer card pop de pop hl push hl call CallIndirect pop hl jr nc, .inc_hl_by_4 ; routine returned carry, which means ; this card should be played. inc hl inc hl ld [wAITrainerCardParameter], a ; show Play Trainer Card screen push de push hl ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, OPPACTION_PLAY_TRAINER bank1call AIMakeDecision pop hl pop de jr c, .inc_hl_by_2 ; execute the effects of the Trainer card push hl call CallIndirect pop hl inc hl inc hl ld a, [wPreviousAIFlags] ld b, a ld a, [wCurrentAIFlags] or b ld [wPreviousAIFlags], a pop hl and AI_FLAG_MODIFIED_HAND jp z, .loop_hand ; the hand was modified during the Trainer effect ; so it needs to be re-listed again and ; looped from the top. call CreateHandCardList ld hl, wDuelTempList ld de, wTempHandCardList call CopyBuffer ld hl, wTempHandCardList ; clear the AI_FLAG_MODIFIED_HAND flag ld a, [wPreviousAIFlags] and ~AI_FLAG_MODIFIED_HAND ld [wPreviousAIFlags], a jp .loop_hand .inc_hl_by_5 inc hl .inc_hl_by_4 inc hl inc hl .inc_hl_by_2 inc hl inc hl jp .loop_data .next_in_data pop de pop hl inc hl inc hl inc hl inc hl jp .loop_data .pop_hl pop hl jp .loop_hand ; makes AI use Potion card. AIPlay_Potion: ; 201b5 (8:41b5) ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, [wAITrainerCardParameter] ldh [hTemp_ffa0], a ld e, a call GetCardDamageAndMaxHP cp 20 jr c, .play_card ld a, 20 .play_card ldh [hTempPlayAreaLocation_ffa1], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret ; if AI doesn't decide to retreat this card, ; check if defending Pokémon can KO active card ; next turn after using Potion. ; if it cannot, return carry. ; also take into account whether attack is high recoil. AIDecide_Potion1: ; 201d1 (8:41d1) farcall AIDecideWhetherToRetreat jr c, .no_carry call AICheckIfAttackIsHighRecoil jr c, .no_carry xor a ; active card ldh [hTempPlayAreaLocation_ff9d], a farcall CheckIfDefendingPokemonCanKnockOut jr nc, .no_carry ld d, a ld a, DUELVARS_ARENA_CARD_HP call GetTurnDuelistVariable ld h, a ld e, PLAY_AREA_ARENA call GetCardDamageAndMaxHP cp 20 + 1 ; if damage <= 20 jr c, .calculate_hp ld a, 20 ; amount of Potion HP healing ; if damage done by defending Pokémon next turn will still ; KO this card after healing, return no carry. .calculate_hp ld l, a ld a, h add l sub d jr c, .no_carry jr z, .no_carry ; return carry. xor a scf ret .no_carry or a ret ; finds a card in Play Area to use Potion on. ; output: ; a = card to use Potion on; ; carry set if Potion should be used. AIDecide_Potion2: ; 20204 (8:4204) xor a ldh [hTempPlayAreaLocation_ff9d], a farcall CheckIfDefendingPokemonCanKnockOut jr nc, .start_from_active ; can KO ld d, a ld a, DUELVARS_ARENA_CARD_HP call GetTurnDuelistVariable ld h, a ld e, PLAY_AREA_ARENA call GetCardDamageAndMaxHP cp 20 + 1 ; if damage <= 20 jr c, .calculate_hp ld a, 20 ; return if using healing prevents KO. .calculate_hp ld l, a ld a, h add l sub d jr c, .count_prizes jr z, .count_prizes or a ret ; using Potion on active card does not prevent a KO. ; if player is at last prize, start loop with active card. ; otherwise start loop at first bench Pokémon. .count_prizes call SwapTurn call CountPrizes call SwapTurn dec a jr z, .start_from_active ld e, PLAY_AREA_BENCH_1 jr .loop ; find Play Area Pokémon with more than 10 damage. ; skip Pokémon if it has a BOOST_IF_TAKEN_DAMAGE attack. .start_from_active ld e, PLAY_AREA_ARENA .loop ld a, DUELVARS_ARENA_CARD add e call GetTurnDuelistVariable cp $ff ret z call .check_boost_if_taken_damage jr c, .has_boost_damage call GetCardDamageAndMaxHP cp 20 ; if damage >= 20 jr nc, .found .has_boost_damage inc e jr .loop ; a card was found, now to check if it's active or benched. .found ld a, e or a jr z, .active_card ; bench card push de call SwapTurn call CountPrizes call SwapTurn dec a or a jr z, .check_random ld a, 10 call Random cp 3 ; 7/10 chance of returning carry. .check_random pop de jr c, .no_carry ld a, e scf ret ; return carry for active card if not High Recoil. .active_card push de call AICheckIfAttackIsHighRecoil pop de jr c, .no_carry ld a, e scf ret .no_carry or a ret ; return carry if either of the attacks are usable ; and have the BOOST_IF_TAKEN_DAMAGE effect. .check_boost_if_taken_damage ; 2027e (8:427e) push de xor a ; FIRST_ATTACK_OR_PKMN_POWER ld [wSelectedAttack], a farcall CheckIfSelectedAttackIsUnusable jr c, .second_attack ld a, ATTACK_FLAG3_ADDRESS | BOOST_IF_TAKEN_DAMAGE_F call CheckLoadedAttackFlag jr c, .set_carry .second_attack ld a, SECOND_ATTACK ld [wSelectedAttack], a farcall CheckIfSelectedAttackIsUnusable jr c, .false ld a, ATTACK_FLAG3_ADDRESS | BOOST_IF_TAKEN_DAMAGE_F call CheckLoadedAttackFlag jr c, .set_carry .false pop de or a ret .set_carry pop de scf ret ; makes AI use Super Potion card. AIPlay_SuperPotion: ; 202a8 (8:42a8) ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, [wAITrainerCardParameter] ldh [hTempPlayAreaLocation_ffa1], a call AIPickEnergyCardToDiscard ldh [hTemp_ffa0], a ld a, [wAITrainerCardParameter] ld e, a call GetCardDamageAndMaxHP cp 40 jr c, .play_card ld a, 40 .play_card ldh [hTempRetreatCostCards], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret ; if AI doesn't decide to retreat this card and card has ; any energy cards attached, check if defending Pokémon can KO ; active card next turn after using Super Potion. ; if it cannot, return carry. ; also take into account whether attack is high recoil. AIDecide_SuperPotion1: ; 202cc (8:42cc) farcall AIDecideWhetherToRetreat jr c, .no_carry call AICheckIfAttackIsHighRecoil jr c, .no_carry xor a ldh [hTempPlayAreaLocation_ff9d], a ld e, a call .check_attached_energy ret nc farcall CheckIfDefendingPokemonCanKnockOut jr nc, .no_carry ld d, a ld d, a ld a, DUELVARS_ARENA_CARD_HP call GetTurnDuelistVariable ld h, a ld e, PLAY_AREA_ARENA call GetCardDamageAndMaxHP cp 40 + 1 ; if damage < 40 jr c, .calculate_hp ld a, 40 .calculate_hp ld l, a ld a, h add l sub d jr c, .no_carry jr z, .no_carry ; return carry ld a, e scf ret .no_carry or a ret ; returns carry if card has energies attached. .check_attached_energy ; 20305 (8:4305) call GetPlayAreaCardAttachedEnergies ld a, [wTotalAttachedEnergies] or a ret z scf ret ; finds a card in Play Area to use Super Potion on. ; output: ; a = card to use Super Potion on; ; carry set if Super Potion should be used. AIDecide_SuperPotion2: ; 2030f (8:430f) xor a ldh [hTempPlayAreaLocation_ff9d], a farcall CheckIfDefendingPokemonCanKnockOut jr nc, .start_from_active ; can KO ld d, a ld a, DUELVARS_ARENA_CARD_HP call GetTurnDuelistVariable ld h, a ld e, PLAY_AREA_ARENA call GetCardDamageAndMaxHP cp 40 + 1 ; if damage < 40 jr c, .calculate_hp ld a, 40 ; return if using healing prevents KO. .calculate_hp ld l, a ld a, h add l sub d jr c, .count_prizes jr z, .count_prizes or a ret ; using Super Potion on active card does not prevent a KO. ; if player is at last prize, start loop with active card. ; otherwise start loop at first bench Pokémon. .count_prizes call SwapTurn call CountPrizes call SwapTurn dec a jr z, .start_from_active ld e, PLAY_AREA_BENCH_1 jr .loop ; find Play Area Pokémon with more than 30 damage. ; skip Pokémon if it doesn't have any energy attached, ; has a BOOST_IF_TAKEN_DAMAGE attack, ; or if discarding makes any attack of its attacks unusable. .start_from_active ld e, PLAY_AREA_ARENA .loop ld a, DUELVARS_ARENA_CARD add e call GetTurnDuelistVariable cp $ff ret z ld d, a call .check_attached_energy jr nc, .next call .check_boost_if_taken_damage jr c, .next call .check_energy_cost jr c, .next call GetCardDamageAndMaxHP cp 40 ; if damage >= 40 jr nc, .found .next inc e jr .loop ; a card was found, now to check if it's active or benched. .found ld a, e or a jr z, .active_card ; bench card push de call SwapTurn call CountPrizes call SwapTurn dec a or a jr z, .check_random ld a, 10 call Random cp 3 ; 7/10 chance of returning carry. .check_random pop de jr c, .no_carry ld a, e scf ret ; return carry for active card if not Hgh Recoil. .active_card push de call AICheckIfAttackIsHighRecoil pop de jr c, .no_carry ld a, e scf ret .no_carry or a ret ; returns carry if card has energies attached. .check_attached_energy ; 20394 (8:4394) call GetPlayAreaCardAttachedEnergies ld a, [wTotalAttachedEnergies] or a ret z scf ret ; return carry if either of the attacks are usable ; and have the BOOST_IF_TAKEN_DAMAGE effect. .check_boost_if_taken_damage ; 2039e (8:439e) push de xor a ; FIRST_ATTACK_OR_PKMN_POWER ld [wSelectedAttack], a farcall CheckIfSelectedAttackIsUnusable jr c, .second_attack_1 ld a, ATTACK_FLAG3_ADDRESS | BOOST_IF_TAKEN_DAMAGE_F call CheckLoadedAttackFlag jr c, .true_1 .second_attack_1 ld a, SECOND_ATTACK ld [wSelectedAttack], a farcall CheckIfSelectedAttackIsUnusable jr c, .false_1 ld a, ATTACK_FLAG3_ADDRESS | BOOST_IF_TAKEN_DAMAGE_F call CheckLoadedAttackFlag jr c, .true_1 .false_1 pop de or a ret .true_1 pop de scf ret ; returns carry if discarding energy card renders any attack unusable, ; given that they have enough energy to be used before discarding. .check_energy_cost ; 203c8 (8:43c8) push de xor a ; FIRST_ATTACK_OR_PKMN_POWER ld [wSelectedAttack], a ld a, e ldh [hTempPlayAreaLocation_ff9d], a farcall CheckEnergyNeededForAttack jr c, .second_attack_2 farcall CheckEnergyNeededForAttackAfterDiscard jr c, .true_2 .second_attack_2 pop de push de ld a, SECOND_ATTACK ld [wSelectedAttack], a ld a, e ldh [hTempPlayAreaLocation_ff9d], a farcall CheckEnergyNeededForAttack jr c, .false_2 farcall CheckEnergyNeededForAttackAfterDiscard jr c, .true_2 .false_2 pop de or a ret .true_2 pop de scf ret AIPlay_Defender: ; 203f8 (8:43f8) ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a xor a ldh [hTemp_ffa0], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret ; returns carry if using Defender can prevent a KO ; by the defending Pokémon. ; this takes into account both attacks and whether they're useable. AIDecide_Defender1: ; 20406 (8:4406) xor a ; PLAY_AREA_ARENA ldh [hTempPlayAreaLocation_ff9d], a farcall CheckIfAnyAttackKnocksOutDefendingCard jr nc, .cannot_ko farcall CheckIfSelectedAttackIsUnusable jr nc, .no_carry farcall LookForEnergyNeededForAttackInHand jr c, .no_carry .cannot_ko ; check if any of the defending Pokémon's attacks deal ; damage exactly equal to current HP, and if so, ; only continue if that attack is useable. farcall CheckIfAnyDefendingPokemonAttackDealsSameDamageAsHP jr nc, .no_carry call SwapTurn farcall CheckIfSelectedAttackIsUnusable call SwapTurn jr c, .no_carry ld a, [wSelectedAttack] farcall EstimateDamage_FromDefendingPokemon ld a, [wDamage] ld [wce06], a ld d, a ; load in a the attack that was not selected, ; and check if it is useable. ld a, [wSelectedAttack] ld b, a ld a, $01 sub b ld [wSelectedAttack], a push de call SwapTurn farcall CheckIfSelectedAttackIsUnusable call SwapTurn pop de jr c, .switch_back ; the other attack is useable. ; compare its damage to the selected attack. ld a, [wSelectedAttack] push de farcall EstimateDamage_FromDefendingPokemon pop de ld a, [wDamage] cp d jr nc, .subtract ; in case the non-selected attack is useable ; and deals less damage than the selected attack, ; switch back to the other attack. .switch_back ld a, [wSelectedAttack] ld b, a ld a, $01 sub b ld [wSelectedAttack], a ld a, [wce06] ld [wDamage], a ; now the selected attack is the one that deals ; the most damage of the two (and is useable). ; if subtracting damage by using Defender ; still prevents a KO, return carry. .subtract ld a, [wDamage] sub 20 ld d, a ld a, DUELVARS_ARENA_CARD_HP call GetTurnDuelistVariable sub d jr c, .no_carry jr z, .no_carry scf ret .no_carry or a ret ; return carry if using Defender prevents Pokémon ; from being knocked out by an attack with recoil. AIDecide_Defender2: ; 20486 (8:4486) ld a, ATTACK_FLAG1_ADDRESS | HIGH_RECOIL_F call CheckLoadedAttackFlag jr c, .recoil ld a, ATTACK_FLAG1_ADDRESS | LOW_RECOIL_F call CheckLoadedAttackFlag jr c, .recoil or a ret .recoil ld a, DUELVARS_ARENA_CARD call GetTurnDuelistVariable call LoadCardDataToBuffer2_FromDeckIndex ld a, [wSelectedAttack] or a jr nz, .second_attack ; first attack ld a, [wLoadedCard2Atk1EffectParam] jr .check_weak .second_attack ld a, [wLoadedCard2Atk2EffectParam] ; double recoil damage if card is weak to its own color. .check_weak ld d, a push de call GetArenaCardColor call TranslateColorToWR ld b, a call GetArenaCardWeakness and b pop de jr z, .check_resist sla d ; subtract 30 from recoil damage if card resists its own color. ; if this yields a negative number, return no carry. .check_resist push de call GetArenaCardColor call TranslateColorToWR ld b, a call GetArenaCardResistance and b pop de jr z, .subtract ld a, d sub 30 jr c, .no_carry ld d, a ; subtract damage prevented by Defender. ; if damage still knocks out card, return no carry. ; if damage does not knock out, return carry. .subtract ld a, d or a jr z, .no_carry sub 20 ld d, a ld a, DUELVARS_ARENA_CARD_HP call GetTurnDuelistVariable sub d jr c, .no_carry jr z, .no_carry scf ret .no_carry or a ret AIPlay_Pluspower: ; 204e8 (8:44e8) ld a, [wCurrentAIFlags] or AI_FLAG_USED_PLUSPOWER ld [wCurrentAIFlags], a ld a, [wAITrainerCardParameter] ld [wAIPluspowerAttack], a ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret ; returns carry if using a Pluspower can KO defending Pokémon ; if active card cannot KO without the boost. ; outputs in a the attack to use. AIDecide_Pluspower1: ; 20501 (8:4501) ; this is mistakenly duplicated xor a ldh [hTempPlayAreaLocation_ff9d], a xor a ldh [hTempPlayAreaLocation_ff9d], a ; continue if no attack can knock out. ; if there's an attack that can, only continue ; if it's unusable and there's no card in hand ; to fulfill its energy cost. farcall CheckIfAnyAttackKnocksOutDefendingCard jr nc, .cannot_ko farcall CheckIfSelectedAttackIsUnusable jr nc, .no_carry farcall LookForEnergyNeededForAttackInHand jr c, .no_carry ; cannot use an attack that knocks out. .cannot_ko ; get active Pokémon's info. ld a, DUELVARS_ARENA_CARD call GetTurnDuelistVariable call GetCardIDFromDeckIndex ld a, e ld [wTempTurnDuelistCardID], a ; get defending Pokémon's info and check ; its No Damage or Effect substatus. ; if substatus is active, return. call SwapTurn ld a, DUELVARS_ARENA_CARD call GetTurnDuelistVariable call GetCardIDFromDeckIndex ld a, e ld [wTempNonTurnDuelistCardID], a bank1call HandleNoDamageOrEffectSubstatus call SwapTurn jr c, .no_carry ; check both attacks and decide which one ; can KO with Pluspower boost. ; if neither can KO, return no carry. xor a ; FIRST_ATTACK_OR_PKMN_POWER ld [wSelectedAttack], a call .check_ko_with_pluspower jr c, .kos_with_pluspower_1 ld a, SECOND_ATTACK ld [wSelectedAttack], a call .check_ko_with_pluspower jr c, .kos_with_pluspower_2 .no_carry or a ret ; first attack can KO with Pluspower. .kos_with_pluspower_1 call .check_mr_mime jr nc, .no_carry xor a ; FIRST_ATTACK_OR_PKMN_POWER scf ret ; second attack can KO with Pluspower. .kos_with_pluspower_2 call .check_mr_mime jr nc, .no_carry ld a, SECOND_ATTACK scf ret ; return carry if attack is useable and KOs ; defending Pokémon with Pluspower boost. .check_ko_with_pluspower ; 20562 (8:4562) farcall CheckIfSelectedAttackIsUnusable jr c, .unusable ld a, [wSelectedAttack] farcall EstimateDamage_VersusDefendingCard ld a, DUELVARS_ARENA_CARD_HP call GetNonTurnDuelistVariable ld b, a ld hl, wDamage sub [hl] jr c, .no_carry jr z, .no_carry ld a, [hl] add 10 ; add Pluspower boost ld c, a ld a, b sub c ret c ; return carry if damage > HP left ret nz ; does not KO scf ret ; KOs with Pluspower boost .unusable or a ret ; returns carry if Pluspower boost does ; not exceed 30 damage when facing Mr. Mime. .check_mr_mime ; 20589 (8:4589) ld a, [wDamage] add 10 ; add Pluspower boost cp 30 ; no danger in preventing damage ret c call SwapTurn ld a, DUELVARS_ARENA_CARD call GetTurnDuelistVariable call GetCardIDFromDeckIndex call SwapTurn ld a, e cp MR_MIME ret z ; damage is >= 30 but not Mr. Mime scf ret ; returns carry 7/10 of the time ; if selected attack is useable, can't KO without Pluspower boost ; can damage Mr. Mime even with Pluspower boost ; and has a minimum damage > 0. ; outputs in a the attack to use. AIDecide_Pluspower2: ; 205a5 (8:45a5) xor a ldh [hTempPlayAreaLocation_ff9d], a call .check_can_ko jr nc, .no_carry call .check_random jr nc, .no_carry call .check_mr_mime jr nc, .no_carry scf ret .no_carry or a ret ; returns carry if Pluspower boost does ; not exceed 30 damage when facing Mr. Mime. .check_mr_mime ; 205bb (8:45bb) ld a, [wDamage] add 10 ; add Pluspower boost cp 30 ; no danger in preventing damage ret c call SwapTurn ld a, DUELVARS_ARENA_CARD call GetTurnDuelistVariable call GetCardIDFromDeckIndex call SwapTurn ld a, e cp MR_MIME ret z ; damage is >= 30 but not Mr. Mime scf ret ; return carry if attack is useable but cannot KO. .check_can_ko ; 205d7 (8:45d7) farcall CheckIfSelectedAttackIsUnusable jr c, .unusable ld a, [wSelectedAttack] farcall EstimateDamage_VersusDefendingCard ld a, DUELVARS_ARENA_CARD_HP call GetNonTurnDuelistVariable ld b, a ld hl, wDamage sub [hl] jr c, .no_carry jr z, .no_carry ; can't KO. scf ret .unusable or a ret ; return carry 7/10 of the time if ; attack is useable and minimum damage > 0. .check_random ; 205f6 (8:45f6) farcall CheckIfSelectedAttackIsUnusable jr c, .unusable ld a, [wSelectedAttack] farcall EstimateDamage_VersusDefendingCard ld a, [wAIMinDamage] cp 10 jr c, .unusable ld a, 10 call Random cp 3 ret AIPlay_Switch: ; 20612 (8:4612) ld a, [wCurrentAIFlags] or AI_FLAG_USED_SWITCH ld [wCurrentAIFlags], a ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, [wAITrainerCardParameter] ldh [hTemp_ffa0], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision xor a ld [wcdb4], a ret ; returns carry if the active card has less energy cards ; than the retreat cost and if AI can't play an energy ; card from the hand to fulfill the cost AIDecide_Switch: ; 2062e (8:462e) ; check if AI can already play an energy card from hand to retreat ld a, [wAIPlayEnergyCardForRetreat] or a jr z, .check_cost_amount ; can't play energy card from hand to retreat ; compare number of energy cards attached to retreat cost xor a ; PLAY_AREA_ARENA ldh [hTempPlayAreaLocation_ff9d], a call GetPlayAreaCardRetreatCost push af ld e, PLAY_AREA_ARENA farcall CountNumberOfEnergyCardsAttached ld b, a pop af sub b ; jump if cards attached > retreat cost jr c, .check_cost_amount cp 2 ; jump if retreat cost is 2 more energy cards ; than the number of cards attached jr nc, .switch .check_cost_amount xor a ; PLAY_AREA_ARENA ldh [hTempPlayAreaLocation_ff9d], a call GetPlayAreaCardRetreatCost cp 3 ; jump if retreat cost >= 3 jr nc, .switch push af ld e, PLAY_AREA_ARENA farcall CountNumberOfEnergyCardsAttached pop bc cp b ; jump if energy cards attached < retreat cost jr c, .switch ret .switch farcall AIDecideBenchPokemonToSwitchTo ccf ret AIPlay_GustOfWind: ; 20666 (8:4666) ld a, [wCurrentAIFlags] or AI_FLAG_USED_GUST_OF_WIND ld [wCurrentAIFlags], a ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, [wAITrainerCardParameter] ldh [hTemp_ffa0], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret AIDecide_GustOfWind: ; 2067e (8:467e) ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetNonTurnDuelistVariable dec a or a ret z ; no bench cards ; if used Gust Of Wind already, ; do not use it again. ld a, [wPreviousAIFlags] and AI_FLAG_USED_GUST_OF_WIND ret nz farcall CheckIfActivePokemonCanUseAnyNonResidualAttack ret nc ; no non-residual attack can be used xor a ; PLAY_AREA_ARENA ldh [hTempPlayAreaLocation_ff9d], a farcall CheckIfAnyAttackKnocksOutDefendingCard jr nc, .check_id ; if can't KO farcall CheckIfSelectedAttackIsUnusable jr nc, .no_carry ; if KO attack is useable farcall LookForEnergyNeededForAttackInHand jr c, .no_carry ; if energy card is in hand .check_id ; skip if current active card is MEW3 or MEWTWO1 ld a, DUELVARS_ARENA_CARD call GetTurnDuelistVariable call GetCardIDFromDeckIndex ld a, e cp MEW3 jr z, .no_carry cp MEWTWO1 jr z, .no_carry call .FindBenchCardToKnockOut ret c xor a ; PLAY_AREA_ARENA ldh [hTempPlayAreaLocation_ff9d], a call .CheckIfNoAttackDealsDamage jr c, .check_bench_energy ; skip if current arena card's color is ; the defending card's weakness call GetArenaCardColor call TranslateColorToWR ld b, a call SwapTurn call GetArenaCardWeakness call SwapTurn and b jr nz, .no_carry ; check weakness call .FindBenchCardWithWeakness ret nc ; no bench card weak to arena card scf ret ; found bench card weak to arena card .no_carry or a ret ; being here means AI's arena card cannot damage player's arena card ; first check if there is a card in player's bench that ; has no attached energy cards and that the AI can damage .check_bench_energy ; return carry if there's a bench card with weakness call .FindBenchCardWithWeakness ret c ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetNonTurnDuelistVariable ld d, a ld e, PLAY_AREA_ARENA ; loop through bench and check attached energy cards .loop_1 inc e dec d jr z, .check_bench_hp call SwapTurn call GetPlayAreaCardAttachedEnergies call SwapTurn ld a, [wTotalAttachedEnergies] or a jr nz, .loop_1 ; skip if has energy attached call .CheckIfCanDamageBenchedCard jr nc, .loop_1 ld a, e scf ret .check_bench_hp ld a, $ff ld [wce06], a xor a ld [wce08], a ld e, a ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetNonTurnDuelistVariable ld d, a ; find bench card with least amount of available HP .loop_2 inc e dec d jr z, .check_found ld a, e add DUELVARS_ARENA_CARD_HP call GetNonTurnDuelistVariable ld b, a ld a, [wce06] inc b cp b jr c, .loop_2 call .CheckIfCanDamageBenchedCard jr nc, .loop_2 dec b ld a, b ld [wce06], a ld a, e ld [wce08], a jr .loop_2 .check_found ld a, [wce08] or a jr z, .no_carry ; a card was found .set_carry scf ret .check_can_damage push bc push hl xor a ; PLAY_AREA_ARENA farcall CheckIfCanDamageDefendingPokemon pop hl pop bc jr nc, .loop_3 ld a, c scf ret ; returns carry if any of the player's ; benched cards is weak to color in b ; and has a way to damage it .FindBenchCardWithWeakness ; 2074d (8:474d) ld a, DUELVARS_BENCH call GetNonTurnDuelistVariable ld c, PLAY_AREA_ARENA .loop_3 inc c ld a, [hli] cp $ff jr z, .no_carry call SwapTurn call LoadCardDataToBuffer1_FromDeckIndex call SwapTurn ld a, [wLoadedCard1Weakness] and b jr nz, .check_can_damage jr .loop_3 ; returns carry if neither attack can deal damage .CheckIfNoAttackDealsDamage ; 2076b (8:476b) xor a ; FIRST_ATTACK_OR_PKMN_POWER ld [wSelectedAttack], a call .CheckIfAttackDealsNoDamage jr c, .second_attack ret .second_attack ld a, SECOND_ATTACK ld [wSelectedAttack], a call .CheckIfAttackDealsNoDamage jr c, .true ret .true scf ret ; returns carry if attack is Pokemon Power ; or otherwise doesn't deal any damage .CheckIfAttackDealsNoDamage ; 20782 (8:4782) ld a, [wSelectedAttack] ld e, a ld a, DUELVARS_ARENA_CARD call GetTurnDuelistVariable ld d, a call CopyAttackDataAndDamage_FromDeckIndex ld a, [wLoadedAttackCategory] ; skip if attack is a Power or has 0 damage cp POKEMON_POWER jr z, .no_damage ld a, [wDamage] or a ret z ; check damage against defending card ld a, [wSelectedAttack] farcall EstimateDamage_VersusDefendingCard ld a, [wAIMaxDamage] or a ret nz .no_damage scf ret ; returns carry if there is a player's bench card that ; the opponent's current active card can KO .FindBenchCardToKnockOut ; 207a9 (8:47a9) ld a, DUELVARS_BENCH call GetNonTurnDuelistVariable ld e, PLAY_AREA_BENCH_1 .loop_4 ld a, [hli] cp $ff ret z ; overwrite the player's active card and its HP ; with the current bench card that is being checked push hl push de ld b, a ld a, DUELVARS_ARENA_CARD call GetNonTurnDuelistVariable push af ld [hl], b ld a, e add DUELVARS_ARENA_CARD_HP call GetNonTurnDuelistVariable ld b, a ld a, DUELVARS_ARENA_CARD_HP call GetNonTurnDuelistVariable push af ld [hl], b xor a ; PLAY_AREA_ARENA ldh [hTempPlayAreaLocation_ff9d], a call .CheckIfAnyAttackKnocksOut jr nc, .next farcall CheckIfSelectedAttackIsUnusable jr nc, .found farcall LookForEnergyNeededForAttackInHand jr c, .found ; the following two local routines can be condensed into one ; since they both revert the player's arena card .next ld a, DUELVARS_ARENA_CARD_HP call GetNonTurnDuelistVariable pop af ld [hl], a ld a, DUELVARS_ARENA_CARD call GetNonTurnDuelistVariable pop af ld [hl], a pop de inc e pop hl jr .loop_4 ; revert player's arena card and set carry .found ld a, DUELVARS_ARENA_CARD_HP call GetNonTurnDuelistVariable pop af ld [hl], a ld a, DUELVARS_ARENA_CARD call GetNonTurnDuelistVariable pop af ld [hl], a pop de ld a, e pop hl scf ret ; returns carry if any of arena card's attacks ; KOs player card in location stored in e .CheckIfAnyAttackKnocksOut ; 20806 (8:4806) xor a ; FIRST_ATTACK_OR_PKMN_POWER call .CheckIfAttackKnocksOut ret c ld a, SECOND_ATTACK ; returns carry if attack KOs player card ; in location stored in e .CheckIfAttackKnocksOut push de farcall EstimateDamage_VersusDefendingCard pop de ld a, DUELVARS_ARENA_CARD_HP add e call GetNonTurnDuelistVariable ld hl, wDamage sub [hl] ret c ret nz scf ret ; returns carry if opponent's arena card can damage ; this benched card if it were switched with ; the player's arena card .CheckIfCanDamageBenchedCard ; 20821 (8:4821) push bc push de push hl ; overwrite arena card data ld a, e add DUELVARS_ARENA_CARD call GetNonTurnDuelistVariable ld b, a ld a, DUELVARS_ARENA_CARD call GetNonTurnDuelistVariable push af ld [hl], b ; overwrite arena card HP ld a, e add DUELVARS_ARENA_CARD_HP call GetNonTurnDuelistVariable ld b, a ld a, DUELVARS_ARENA_CARD_HP call GetNonTurnDuelistVariable push af ld [hl], b xor a ; PLAY_AREA_ARENA farcall CheckIfCanDamageDefendingPokemon jr c, .can_damage ; the following two local routines can be condensed into one ; since they both revert the player's arena card ; can't damage ld a, DUELVARS_ARENA_CARD_HP call GetNonTurnDuelistVariable pop af ld [hl], a ld a, DUELVARS_ARENA_CARD call GetNonTurnDuelistVariable pop af ld [hl], a pop hl pop de pop bc or a ret .can_damage ld a, DUELVARS_ARENA_CARD_HP call GetNonTurnDuelistVariable pop af ld [hl], a ld a, DUELVARS_ARENA_CARD call GetNonTurnDuelistVariable pop af ld [hl], a pop hl pop de pop bc scf ret AIPlay_Bill: ; 2086d (8:486d) ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret ; return carry if cards in deck > 9 AIDecide_Bill: ; 20878 (8:4878) ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK call GetTurnDuelistVariable cp DECK_SIZE - 9 ret AIPlay_EnergyRemoval: ; 20880 (8:4880) ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, [wAITrainerCardParameter] ldh [hTemp_ffa0], a ld a, [wce1a] ldh [hTempPlayAreaLocation_ffa1], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret ; picks an energy card in the player's Play Area to remove AIDecide_EnergyRemoval: ; 20895 (8:4895) ; check if the current active card can KO player's card ; if it's possible to KO, then do not consider the player's ; active card to remove its attached energy xor a ; PLAY_AREA_ARENA ldh [hTempPlayAreaLocation_ff9d], a farcall CheckIfAnyAttackKnocksOutDefendingCard jr nc, .cannot_ko farcall CheckIfSelectedAttackIsUnusable jr nc, .can_ko farcall LookForEnergyNeededForAttackInHand jr nc, .cannot_ko .can_ko ; start checking from the bench ld a, PLAY_AREA_BENCH_1 ld [wce0f], a jr .check_bench_energy .cannot_ko ; start checking from the arena card xor a ; PLAY_AREA_ARENA ld [wce0f], a ; loop each card and check if it has enough energy to use any attack ; if it does, then proceed to pick an energy card to remove .check_bench_energy call SwapTurn ld a, [wce0f] ld e, a .loop_1 ld a, DUELVARS_ARENA_CARD add e call GetTurnDuelistVariable cp $ff jr z, .default ld d, a call .CheckIfCardHasEnergyAttached jr nc, .next_1 call .CheckIfNotEnoughEnergyToAttack jr nc, .pick_energy ; jump if enough energy to attack .next_1 inc e jr .loop_1 .pick_energy ; a play area card was picked to remove energy ; store the picked energy card to remove in wce1a ; and set carry ld a, e push af call PickAttachedEnergyCardToRemove ld [wce1a], a pop af call SwapTurn scf ret ; if no card in player's Play Area was found with enough energy ; to attack, just pick an energy card from player's active card ; (in case the AI cannot KO it this turn) .default ld a, [wce0f] or a jr nz, .check_bench_damage ; not active card call .CheckIfCardHasEnergyAttached jr c, .pick_energy ; lastly, check what attack on player's Play Area is highest damaging ; and pick an energy card attached to that Pokemon to remove .check_bench_damage xor a ld [wce06], a ld [wce08], a ld e, PLAY_AREA_BENCH_1 .loop_2 ld a, DUELVARS_ARENA_CARD add e call GetTurnDuelistVariable cp $ff jr z, .found_damage ld d, a call .CheckIfCardHasEnergyAttached jr nc, .next_2 call .FindHighestDamagingAttack .next_2 inc e jr .loop_2 .found_damage ld a, [wce08] or a jr z, .no_carry ; skip if none found ld e, a jr .pick_energy .no_carry call SwapTurn or a ret ; returns carry if this card has any energy cards attached .CheckIfCardHasEnergyAttached ; 2091a (8:491a) call GetPlayAreaCardAttachedEnergies ld a, [wTotalAttachedEnergies] or a ret z scf ret ; returns carry if this card does not ; have enough energy for either of its attacks .CheckIfNotEnoughEnergyToAttack ; 20924 (8:4924) push de xor a ; FIRST_ATTACK_OR_PKMN_POWER ld [wSelectedAttack], a ld a, e ldh [hTempPlayAreaLocation_ff9d], a farcall CheckEnergyNeededForAttack jr nc, .enough_energy pop de push de ld a, SECOND_ATTACK ld [wSelectedAttack], a ld a, e ldh [hTempPlayAreaLocation_ff9d], a farcall CheckEnergyNeededForAttack jr nc, .check_surplus pop de ; neither attack has enough energy scf ret .enough_energy pop de or a ret ; first attack doesn't have enough energy (or is just a Pokemon Power) ; but second attack has enough energy to be used ; check if there's surplus energy for attack and, if so, return carry .check_surplus farcall CheckIfNoSurplusEnergyForAttack pop de ccf ret ; stores in wce06 the highest damaging attack ; for the card in play area location in e ; and stores this card's location in wce08 .FindHighestDamagingAttack ; 2094f (8:494f) push de ld a, e ldh [hTempPlayAreaLocation_ff9d], a xor a ; FIRST_ATTACK_OR_PKMN_POWER farcall EstimateDamage_VersusDefendingCard ld a, [wDamage] or a jr z, .skip_1 ld e, a ld a, [wce06] cp e jr nc, .skip_1 ld a, e ld [wce06], a ; store this damage value pop de ld a, e ld [wce08], a ; store this location jr .second_attack .skip_1 pop de .second_attack push de ld a, e ldh [hTempPlayAreaLocation_ff9d], a ld a, SECOND_ATTACK farcall EstimateDamage_VersusDefendingCard ld a, [wDamage] or a jr z, .skip_2 ld e, a ld a, [wce06] cp e jr nc, .skip_2 ld a, e ld [wce06], a ; store this damage value pop de ld a, e ld [wce08], a ; store this location ret .skip_2 pop de ret AIPlay_SuperEnergyRemoval: ; 20994 (8:4994) ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, [wAITrainerCardParameter] ldh [hTemp_ffa0], a ld a, [wce1a] ldh [hTempPlayAreaLocation_ffa1], a ld a, [wce1b] ldh [hTempRetreatCostCards], a ld a, [wce1c] ldh [hTempRetreatCostCards + 1], a ld a, [wce1d] ldh [hTempRetreatCostCards + 2], a ld a, $ff ldh [hTempRetreatCostCards + 3], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret ; picks two energy cards in the player's Play Area to remove AIDecide_SuperEnergyRemoval: ; 209bc (8:49bc) ld e, PLAY_AREA_BENCH_1 .loop_1 ; first find an Arena card with a color energy card ; to discard for card effect ; return immediately if no Arena cards ld a, DUELVARS_ARENA_CARD add e call GetTurnDuelistVariable cp $ff jr z, .exit ld d, a push de call .LookForNonDoubleColorless pop de jr c, .not_double_colorless inc e jr .loop_1 ; returns carry if an energy card other than double colorless ; is found attached to the card in play area location e .LookForNonDoubleColorless ld a, e call CreateArenaOrBenchEnergyCardList ld hl, wDuelTempList .loop_2 ld a, [hli] cp $ff ret z call LoadCardDataToBuffer1_FromDeckIndex cp DOUBLE_COLORLESS_ENERGY ; any basic energy card ; will set carry flag here jr nc, .loop_2 ret .exit or a ret ; card in Play Area location e was found with ; a basic energy card .not_double_colorless ld a, e ld [wce0f], a ; check if the current active card can KO player's card ; if it's possible to KO, then do not consider the player's ; active card to remove its attached energy xor a ; PLAY_AREA_ARENA ldh [hTempPlayAreaLocation_ff9d], a farcall CheckIfAnyAttackKnocksOutDefendingCard jr nc, .cannot_ko farcall CheckIfSelectedAttackIsUnusable jr nc, .can_ko farcall LookForEnergyNeededForAttackInHand jr nc, .cannot_ko .can_ko ; start checking from the bench call SwapTurn ld e, PLAY_AREA_BENCH_1 jr .loop_3 .cannot_ko ; start checking from the arena card call SwapTurn ld e, PLAY_AREA_ARENA ; loop each card and check if it has enough energy to use any attack ; if it does, then proceed to pick energy cards to remove .loop_3 ld a, DUELVARS_ARENA_CARD add e call GetTurnDuelistVariable cp $ff jr z, .no_carry ld d, a call .CheckIfFewerThanTwoEnergyCards jr c, .next_1 call .CheckIfNotEnoughEnergyToAttack jr nc, .found_card ; jump if enough energy to attack .next_1 inc e jr .loop_3 .found_card ; a play area card was picked to remove energy ; if this is not the Arena Card, then check ; entire bench to pick the highest damage ld a, e or a jr nz, .check_bench_damage ; store the picked energy card to remove in wce1a ; and set carry .pick_energy ld [wce1b], a call PickTwoAttachedEnergyCards ld [wce1c], a ld a, b ld [wce1d], a call SwapTurn ld a, [wce0f] push af call AIPickEnergyCardToDiscard ld [wce1a], a pop af scf ret ; check what attack on player's Play Area is highest damaging ; and pick an energy card attached to that Pokemon to remove .check_bench_damage xor a ld [wce06], a ld [wce08], a ld e, PLAY_AREA_BENCH_1 .loop_4 ld a, DUELVARS_ARENA_CARD add e call GetTurnDuelistVariable cp $ff jr z, .found_damage ld d, a call .CheckIfFewerThanTwoEnergyCards jr c, .next_2 call .CheckIfNotEnoughEnergyToAttack jr c, .next_2 call .FindHighestDamagingAttack .next_2 inc e jr .loop_4 .found_damage ld a, [wce08] or a jr z, .no_carry jr .pick_energy .no_carry call SwapTurn or a ret ; returns carry if the number of energy cards attached ; is fewer than 2, or if all energy combined yields ; fewer than 2 energy .CheckIfFewerThanTwoEnergyCards ; 20a77 (8:4a77) call GetPlayAreaCardAttachedEnergies ld a, [wTotalAttachedEnergies] cp 2 ret c ; return if fewer than 2 attached cards ; count all energy attached ; i.e. colored energy card = 1 ; and double colorless energy card = 2 xor a ld b, NUM_COLORED_TYPES ld hl, wAttachedEnergies .loop_5 add [hl] inc hl dec b jr nz, .loop_5 ld b, [hl] srl b add b cp 2 ret ; returns carry if this card does not ; have enough energy for either of its attacks .CheckIfNotEnoughEnergyToAttack ; 20a92 (8:4a92) push de xor a ; FIRST_ATTACK_OR_PKMN_POWER ld [wSelectedAttack], a ld a, e ldh [hTempPlayAreaLocation_ff9d], a farcall CheckEnergyNeededForAttack jr nc, .enough_energy pop de push de ld a, SECOND_ATTACK ld [wSelectedAttack], a ld a, e ldh [hTempPlayAreaLocation_ff9d], a farcall CheckEnergyNeededForAttack jr nc, .check_surplus pop de ; neither attack has enough energy scf ret .enough_energy pop de or a ret ; first attack doesn't have enough energy (or is just a Pokemon Power) ; but second attack has enough energy to be used ; check if there's surplus energy for attack and, if so, ; return carry if this surplus energy is at least 2 .check_surplus farcall CheckIfNoSurplusEnergyForAttack cp 2 jr c, .enough_energy pop de scf ret ; stores in wce06 the highest damaging attack ; for the card in play area location in e ; and stores this card's location in wce08 .FindHighestDamagingAttack ; 20ac1 (8:4ac1) push de ld a, e ldh [hTempPlayAreaLocation_ff9d], a xor a ; FIRST_ATTACK_OR_PKMN_POWER farcall EstimateDamage_VersusDefendingCard ld a, [wDamage] or a jr z, .skip_1 ld e, a ld a, [wce06] cp e jr nc, .skip_1 ld a, e ld [wce06], a ; store this damage value pop de ld a, e ld [wce08], a ; store this location jr .second_attack .skip_1 pop de .second_attack push de ld a, e ldh [hTempPlayAreaLocation_ff9d], a ld a, SECOND_ATTACK farcall EstimateDamage_VersusDefendingCard ld a, [wDamage] or a jr z, .skip_2 ld e, a ld a, [wce06] cp e jr nc, .skip_2 ld a, e ld [wce06], a ; store this damage value pop de ld a, e ld [wce08], a ; store this location ret .skip_2 pop de ret AIPlay_PokemonBreeder: ; 20b06 (8:4b06) ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, [wAITrainerCardParameter] ldh [hTempPlayAreaLocation_ffa1], a ld a, [wce1a] ldh [hTemp_ffa0], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret AIDecide_PokemonBreeder: ; 20b1b (8:4b1b) call IsPrehistoricPowerActive jp c, .done ld a, 7 ld hl, wce08 call ClearMemory_Bank8 xor a ld [wce06], a call CreateHandCardList ld hl, wDuelTempList .loop_hand_1 ld a, [hli] cp $ff jr z, .not_found_in_hand ; check if card in hand is any of the following ; stage 2 Pokemon cards ld d, a call LoadCardDataToBuffer1_FromDeckIndex cp VENUSAUR1 jr z, .found cp VENUSAUR2 jr z, .found cp BLASTOISE jr z, .found cp VILEPLUME jr z, .found cp ALAKAZAM jr z, .found cp GENGAR jr nz, .loop_hand_1 .found ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA push hl call GetTurnDuelistVariable pop hl ld c, a ld e, PLAY_AREA_ARENA ; check Play Area for card that can evolve into ; the picked stage 2 Pokemon .loop_play_area_1 push hl push bc push de call CheckIfCanEvolveInto_BasicToStage2 pop de call nc, .can_evolve pop bc pop hl inc e dec c jr nz, .loop_play_area_1 jr .loop_hand_1 .can_evolve ld a, DUELVARS_ARENA_CARD_HP add e call GetTurnDuelistVariable call ConvertHPToCounters swap a ld b, a ; count number of energy cards attached and keep ; the lowest 4 bits (capped at $0f) call GetPlayAreaCardAttachedEnergies ld a, [wTotalAttachedEnergies] cp $10 jr c, .not_maxed_out ld a, %00001111 .not_maxed_out or b ; 4 high bits of a = HP counters Pokemon still has ; 4 low bits of a = number of energy cards attached ; store this score in wce08 + PLAY_AREA* ld hl, wce08 ld c, e ld b, $00 add hl, bc ld [hl], a ; store the deck index of stage 2 Pokemon in wce0f + PLAY_AREA* ld hl, wce0f add hl, bc ld [hl], d ; increase wce06 by one ld hl, wce06 inc [hl] ret .not_found_in_hand ld a, [wce06] or a jr z, .check_evolution_and_dragonite ; an evolution has been found before xor a ld [wce06], a ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetTurnDuelistVariable ld c, a ld e, $00 ld d, $00 ; find highest score in wce08 .loop_score_1 ld hl, wce08 add hl, de ld a, [wce06] cp [hl] jr nc, .not_higher ; store this score to wce06 ld a, [hl] ld [wce06], a ; store this PLay Area location to wce07 ld a, e ld [wce07], a .not_higher inc e dec c jr nz, .loop_score_1 ; store the deck index of the stage 2 card ; that has been decided in wce1a, ; return the Play Area location of card ; to evolve in a and return carry ld a, [wce07] ld e, a ld hl, wce0f add hl, de ld a, [hl] ld [wce1a], a ld a, [wce07] scf ret .check_evolution_and_dragonite ld a, 7 ld hl, wce08 call ClearMemory_Bank8 xor a ld [wce06], a call CreateHandCardList ld hl, wDuelTempList push hl .loop_hand_2 pop hl ld a, [hli] cp $ff jr z, .check_evolution_found push hl ld d, a ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetTurnDuelistVariable ld c, a ld e, PLAY_AREA_ARENA .loop_play_area_2 ; check if evolution is possible push bc push de call CheckIfCanEvolveInto_BasicToStage2 pop de call nc, .HandleDragonite1Evolution call nc, .can_evolve ; not possible to evolve or returned carry ; when handling Dragonite1 evolution pop bc inc e dec c jr nz, .loop_play_area_2 jr .loop_hand_2 .check_evolution_found ld a, [wce06] or a jr nz, .evolution_was_found ; no evolution was found before or a ret .evolution_was_found xor a ld [wce06], a ld a, $ff ld [wce07], a ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetTurnDuelistVariable ld c, a ld e, $00 ld d, $00 ; find highest score in wce08 with at least ; 2 energy cards attached .loop_score_2 ld hl, wce08 add hl, de ld a, [wce06] cp [hl] jr nc, .next_score ; take the lower 4 bits (total energy cards) ; and skip if less than 2 ld a, [hl] ld b, a and %00001111 cp 2 jr c, .next_score ; has at least 2 energy cards ; store the score in wce06 ld a, b ld [wce06], a ; store this PLay Area location to wce07 ld a, e ld [wce07], a .next_score inc e dec c jr nz, .loop_score_2 ld a, [wce07] cp $ff jr z, .done ; a card to evolve was found ; store the deck index of the stage 2 card ; that has been decided in wce1a, ; return the Play Area location of card ; to evolve in a and return carry ld e, a ld hl, wce0f add hl, de ld a, [hl] ld [wce1a], a ld a, [wce07] scf ret .done or a ret ; return carry if card is evolving to Dragonite1 and if ; - the card that is evolving is not Arena card and ; number of damage counters in Play Area is under 8; ; - the card that is evolving is Arena card and has under 5 ; damage counters or has less than 3 energy cards attached. .HandleDragonite1Evolution ; 20c5c (8:4c5c) push af push bc push de push hl push de ; check card ID ld a, d call GetCardIDFromDeckIndex ld a, e pop de cp DRAGONITE1 jr nz, .no_carry ; check card Play Area location ld a, e or a jr z, .active_card_dragonite ; the card that is evolving is not active card ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetTurnDuelistVariable ld b, a ld c, 0 ; count damage counters in Play Area .loop_play_area_damage dec b ld e, b push bc call GetCardDamageAndMaxHP pop bc call ConvertHPToCounters add c ld c, a ld a, b or a jr nz, .loop_play_area_damage ; compare number of total damage counters ; with 7, if less or equal to that, set carry ld a, 7 cp c jr c, .no_carry jr .set_carry .active_card_dragonite ; the card that is evolving is active card ; compare number of this card's damage counters ; with 5, if less than that, set carry ld e, PLAY_AREA_ARENA call GetCardDamageAndMaxHP cp 5 jr c, .set_carry ; compare number of this card's attached energy cards ; with 3, if less than that, set carry ld e, PLAY_AREA_ARENA farcall CountNumberOfEnergyCardsAttached cp 3 jr c, .set_carry jr .no_carry .no_carry pop hl pop de pop bc pop af ret .set_carry pop hl pop de pop bc pop af scf ret AIPlay_ProfessorOak: ; 20cae (8:4cae) ld a, [wCurrentAIFlags] or AI_FLAG_USED_PROFESSOR_OAK | AI_FLAG_MODIFIED_HAND ld [wCurrentAIFlags], a ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret ; sets carry if AI determines a score of playing ; Professor Oak is over a certain threshold. AIDecide_ProfessorOak: ; 20cc1 (8:4cc1) ; return if cards in deck <= 6 ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK call GetTurnDuelistVariable cp DECK_SIZE - 6 ret nc ld a, [wOpponentDeckID] cp LEGENDARY_ARTICUNO_DECK_ID jp z, .HandleLegendaryArticunoDeck cp EXCAVATION_DECK_ID jp z, .HandleExcavationDeck cp WONDERS_OF_SCIENCE_DECK_ID jp z, .HandleWondersOfScienceDeck ; return if cards in deck <= 14 .check_cards_deck ld a, [hl] cp DECK_SIZE - 14 ret nc ; initialize score ld a, $1e ld [wce06], a ; check number of cards in hand .check_cards_hand ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND call GetTurnDuelistVariable cp 4 jr nc, .more_than_3_cards ; less than 4 cards in hand ld a, [wce06] add $32 ld [wce06], a jr .check_energy_cards .more_than_3_cards cp 9 jr c, .check_energy_cards ; more than 8 cards ld a, [wce06] sub $1e ld [wce06], a .check_energy_cards farcall CreateEnergyCardListFromHand jr nc, .handle_blastoise ; no energy cards in hand ld a, [wce06] add $28 ld [wce06], a .handle_blastoise ld a, MUK call CountPokemonIDInBothPlayAreas jr c, .check_hand ; no Muk in Play Area ld a, BLASTOISE call CountPokemonIDInPlayArea jr nc, .check_hand ; at least one Blastoise in AI Play Area ld a, WATER_ENERGY farcall LookForCardIDInHand jr nc, .check_hand ; no Water energy in hand ld a, [wce06] add $0a ld [wce06], a ; this part seems buggy ; the AI loops through all the cards in hand and checks ; if any of them is not a Pokemon card and has Basic stage. ; it seems like the intention was that if there was ; any Basic Pokemon still in hand, the AI would add to the score. .check_hand call CreateHandCardList ld hl, wDuelTempList .loop_hand ld a, [hli] cp $ff jr z, .check_evolution call LoadCardDataToBuffer1_FromDeckIndex ld a, [wLoadedCard1Type] cp TYPE_ENERGY jr c, .loop_hand ; bug, should be jr nc ld a, [wLoadedCard1Stage] or a jr nz, .loop_hand ld a, [wce06] add $0a ld [wce06], a .check_evolution xor a ld [wce0f], a ld [wce0f + 1], 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 call .LookForEvolution pop de jr nc, .not_in_hand ; there's a card in hand that can evolve ld a, $01 ld [wce0f], a .not_in_hand ; check if a card that can evolve was found at all ; if not, go to the next card in the Play Area ld a, [wce08] cp $01 jr nz, .next_play_area ; if it was found, set wce0f + 1 to $01 ld a, $01 ld [wce0f + 1], a .next_play_area inc e dec d jr nz, .loop_play_area ; if a card was found that evolves... ld a, [wce0f + 1] or a jr z, .check_score ; ...but that card is not in the hand... ld a, [wce0f] or a jr nz, .check_score ; ...add to the score ld a, [wce06] add $0a ld [wce06], a ; only return carry if score > $3c .check_score ld a, [wce06] ld b, $3c cp b jr nc, .set_carry or a ret .set_carry scf ret ; return carry if there's a card in the hand that ; can evolve the card in Play Area location in e. ; sets wce08 to $01 if any card is found that can ; evolve regardless of card location. .LookForEvolution ; 20d9d (8:4d9d) xor a ld [wce08], a ld d, 0 ; loop through the whole deck to check if there's ; a card that can evolve this Pokemon. .loop_deck_evolution push de call CheckIfCanEvolveInto pop de jr nc, .can_evolve .evolution_not_in_hand inc d ld a, DECK_SIZE cp d jr nz, .loop_deck_evolution or a ret ; a card was found that can evolve, set wce08 to $01 ; and if the card is in the hand, return carry. ; otherwise resume looping through deck. .can_evolve ld a, $01 ld [wce08], a ld a, DUELVARS_CARD_LOCATIONS add d call GetTurnDuelistVariable cp CARD_LOCATION_HAND jr nz, .evolution_not_in_hand scf ret ; handles Legendary Articuno Deck AI logic. .HandleLegendaryArticunoDeck ; 20dc3 (8:4dc3) ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetTurnDuelistVariable cp 3 jr nc, .check_playable_cards ; has less than 3 Pokemon in Play Area. push af call CreateHandCardList pop af ld d, a ld e, PLAY_AREA_ARENA ; if no cards in hand evolve cards in Play Area, ; returns carry. .loop_play_area_articuno ld a, DUELVARS_ARENA_CARD add e push de call GetTurnDuelistVariable farcall CheckForEvolutionInList pop de jr c, .check_playable_cards inc e ld a, d cp e jr nz, .loop_play_area_articuno .set_carry_articuno scf ret ; if there are more than 3 energy cards in hand, ; return no carry, otherwise check for playable cards. .check_playable_cards call CountOppEnergyCardsInHand cp 4 jr nc, .no_carry_articuno ; remove both Professor Oak cards from list ; before checking for playable cards call CreateHandCardList ld hl, wDuelTempList ld e, PROFESSOR_OAK farcall RemoveCardIDInList ld e, PROFESSOR_OAK farcall RemoveCardIDInList ; look in hand for cards that can be played. ; if a card that cannot be played is found, return no carry. ; otherwise return carry. .loop_hand_articuno ld a, [hli] cp $ff jr z, .set_carry_articuno push hl farcall CheckIfCardCanBePlayed pop hl jr c, .loop_hand_articuno .no_carry_articuno or a ret ; handles Excavation deck AI logic. ; sets score depending on whether there's no ; Mysterious Fossil in play and in hand. .HandleExcavationDeck ; 20e11 (8:4e11) ; return no carry if cards in deck < 15 ld a, [hl] cp 46 ret nc ; look for Mysterious Fossil ld a, MYSTERIOUS_FOSSIL call LookForCardIDInHandAndPlayArea jr c, .found_mysterious_fossil ld a, $50 ld [wce06], a jp .check_cards_hand .found_mysterious_fossil ld a, $1e ld [wce06], a jp .check_cards_hand ; handles Wonders of Science AI logic. ; if there's either Grimer or Muk in hand, ; do not play Professor Oak. .HandleWondersOfScienceDeck ; 20e2c (8:4e2c) ld a, GRIMER call LookForCardIDInHandList_Bank8 jr c, .found_grimer_or_muk ld a, MUK call LookForCardIDInHandList_Bank8 jr c, .found_grimer_or_muk ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK call GetTurnDuelistVariable jp .check_cards_deck .found_grimer_or_muk or a ret AIPlay_EnergyRetrieval: ; 20e44 (8:4e44) ld a, [wCurrentAIFlags] or AI_FLAG_MODIFIED_HAND ld [wCurrentAIFlags], a ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, [wAITrainerCardParameter] ldh [hTemp_ffa0], a ld a, [wce1a] ldh [hTempPlayAreaLocation_ffa1], a ld a, [wce1b] ldh [hTempRetreatCostCards], a cp $ff jr z, .asm_20e68 ld a, $ff ldh [$ffa3], a .asm_20e68 ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret ; checks whether AI can play Energy Retrieval and ; picks the energy cards from the discard pile, ; and duplicate cards in hand to discard. AIDecide_EnergyRetrieval: ; 20e6e (8:4e6e) ; return no carry if no cards in hand farcall CreateEnergyCardListFromHand jp nc, .no_carry ; handle Go Go Rain Dance deck ; return no carry if there's no Muk card in play and ; if there's no Blastoise card in Play Area ; if there's a Muk in play, continue as normal ld a, [wOpponentDeckID] cp GO_GO_RAIN_DANCE_DECK_ID jr nz, .start ld a, MUK call CountPokemonIDInBothPlayAreas jr c, .start ld a, BLASTOISE call CountPokemonIDInPlayArea jp nc, .no_carry .start ; find duplicate cards in hand call CreateHandCardList ld hl, wDuelTempList call FindDuplicateCards jp c, .no_carry ld [wce06], a ld a, CARD_LOCATION_DISCARD_PILE call FindBasicEnergyCardsInLocation jp c, .no_carry ; some basic energy cards were found in Discard Pile ld a, $ff ld [wce1a], a ld [wce1b], a ld [wce1c], a ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetTurnDuelistVariable ld d, a ld e, PLAY_AREA_ARENA ; first check if there are useful energy cards in the list ; and choose them for retrieval first .loop_play_area ld a, DUELVARS_ARENA_CARD add e push de ; load this card's ID in wTempCardID ; and this card's Type in wTempCardType call GetTurnDuelistVariable call GetCardIDFromDeckIndex ld a, e ld [wTempCardID], a call LoadCardDataToBuffer1_FromCardID pop de ld a, [wLoadedCard1Type] or TYPE_ENERGY ld [wTempCardType], a ; loop the energy cards in the Discard Pile ; and check if they are useful for this Pokemon ld hl, wDuelTempList .loop_energy_cards_1 ld a, [hli] cp $ff jr z, .next_play_area ld b, a push hl farcall CheckIfEnergyIsUseful pop hl jr nc, .loop_energy_cards_1 ld a, [wce1a] cp $ff jr nz, .second_energy_1 ; check if there were already chosen cards, ; if this is the second chosen card, return carry ; first energy card found ld a, b ld [wce1a], a call RemoveCardFromList jr .next_play_area .second_energy_1 ld a, b ld [wce1b], a jr .set_carry .next_play_area inc e dec d jr nz, .loop_play_area ; next, if there are still energy cards left to choose, ; loop through the energy cards again and select ; them in order. ld hl, wDuelTempList .loop_energy_cards_2 ld a, [hli] cp $ff jr z, .check_chosen ld b, a ld a, [wce1a] cp $ff jr nz, .second_energy_2 ld a, b ld [wce1a], a call RemoveCardFromList jr .loop_energy_cards_2 .second_energy_2 ld a, b ld [wce1b], a jr .set_carry ; will set carry if at least one has been chosen .check_chosen ld a, [wce1a] cp $ff jr nz, .set_carry .no_carry or a ret .set_carry ld a, [wce06] scf ret ; remove an element from the list ; and shortens it accordingly ; input: ; hl = pointer to element after the one to remove RemoveCardFromList: ; 20f27 (8:4f27) push de ld d, h ld e, l dec hl push hl .loop_remove ld a, [de] ld [hli], a cp $ff jr z, .done_remove inc de jr .loop_remove .done_remove pop hl pop de ret ; finds duplicates in card list in hl. ; if a duplicate of Pokemon cards are found, return in ; a the deck index of the second one. ; otherwise, if a duplicate of non-Pokemon cards are found ; return in a the deck index of the second one. ; if no duplicates found, return carry. ; input: ; hl = list to look in ; output: ; a = deck index of duplicate card FindDuplicateCards: ; 20f38 (8:4f38) ld a, $ff ld [wce0f], a ld [wce0f + 1], a push hl .loop_outer ; get ID of current card pop hl ld a, [hli] cp $ff jr z, .check_found call GetCardIDFromDeckIndex ld b, e push hl ; loop the rest of the list to find ; another card with the same ID .loop_inner ld a, [hli] cp $ff jr z, .loop_outer ld c, a call GetCardIDFromDeckIndex ld a, e cp b jr nz, .loop_inner ; found two cards with same ID push bc call GetCardType pop bc cp TYPE_ENERGY jr c, .not_energy ; they are energy or trainer cards ; loads wce0f+1 with this card deck index ld a, c ld [wce0f + 1], a jr .loop_outer .not_energy ; they are Pokemon cards ; loads wce0f with this card deck index ld a, c ld [wce0f], a jr .loop_outer .check_found ld a, [wce0f] cp $ff jr nz, .no_carry ld a, [wce0f + 1] cp $ff jr nz, .no_carry ; only set carry if duplicate cards were not found scf ret .no_carry ; two cards with the same ID were found ; of either Pokemon or Non-Pokemon cards or a ret AIPlay_SuperEnergyRetrieval: ; 20f80 (8:4f80) ld a, [wCurrentAIFlags] or AI_FLAG_MODIFIED_HAND ld [wCurrentAIFlags], a ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, [wAITrainerCardParameter] ldh [hTemp_ffa0], a ld a, [wce1a] ldh [hTempPlayAreaLocation_ffa1], a ld a, [wce1b] ldh [hTempRetreatCostCards], a ld a, [wce1c] ldh [$ffa3], a cp $ff jr z, .asm_20fbb ld a, [wce1d] ldh [$ffa4], a cp $ff jr z, .asm_20fbb ld a, [wce1e] ldh [$ffa5], a cp $ff jr z, .asm_20fbb ld a, $ff ldh [$ffa6], a .asm_20fbb ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret AIDecide_SuperEnergyRetrieval: ; 20fc1 (8:4fc1) ; return no carry if no cards in hand farcall CreateEnergyCardListFromHand jp nc, .no_carry ; handle Go Go Rain Dance deck ; return no carry if there's no Muk card in play and ; if there's no Blastoise card in Play Area ; if there's a Muk in play, continue as normal ld a, [wOpponentDeckID] cp GO_GO_RAIN_DANCE_DECK_ID jr nz, .start ld a, MUK call CountPokemonIDInBothPlayAreas jr c, .start ld a, BLASTOISE call CountPokemonIDInPlayArea jp nc, .no_carry .start ; find duplicate cards in hand call CreateHandCardList ld hl, wDuelTempList call FindDuplicateCards jp c, .no_carry ; remove the duplicate card in hand ; and run the hand check again ld [wce06], a ld hl, wDuelTempList call FindAndRemoveCardFromList call FindDuplicateCards jp c, .no_carry ld [wce08], a ld a, CARD_LOCATION_DISCARD_PILE call FindBasicEnergyCardsInLocation jp c, .no_carry ; some basic energy cards were found in Discard Pile ld a, $ff ld [wce1b], a ld [wce1c], a ld [wce1d], a ld [wce1e], a ld [wce1f], a ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetTurnDuelistVariable ld d, a ld e, PLAY_AREA_ARENA ; first check if there are useful energy cards in the list ; and choose them for retrieval first .loop_play_area ld a, DUELVARS_ARENA_CARD add e push de ; load this card's ID in wTempCardID ; and this card's Type in wTempCardType call GetTurnDuelistVariable call GetCardIDFromDeckIndex ld a, e ld [wTempCardID], a call LoadCardDataToBuffer1_FromCardID pop de ld a, [wLoadedCard1Type] or TYPE_ENERGY ld [wTempCardType], a ; loop the energy cards in the Discard Pile ; and check if they are useful for this Pokemon ld hl, wDuelTempList .loop_energy_cards_1 ld a, [hli] cp $ff jr z, .next_play_area ld b, a push hl farcall CheckIfEnergyIsUseful pop hl jr nc, .loop_energy_cards_1 ; first energy ld a, [wce1b] cp $ff jr nz, .second_energy_1 ld a, b ld [wce1b], a call RemoveCardFromList jr .next_play_area .second_energy_1 ld a, [wce1c] cp $ff jr nz, .third_energy_1 ld a, b ld [wce1c], a call RemoveCardFromList jr .next_play_area .third_energy_1 ld a, [wce1d] cp $ff jr nz, .fourth_energy_1 ld a, b ld [wce1d], a call RemoveCardFromList jr .next_play_area .fourth_energy_1 ld a, b ld [wce1e], a jr .set_carry .next_play_area inc e dec d jr nz, .loop_play_area ; next, if there are still energy cards left to choose, ; loop through the energy cards again and select ; them in order. ld hl, wDuelTempList .loop_energy_cards_2 ld a, [hli] cp $ff jr z, .check_chosen ld b, a ld a, [wce1b] cp $ff jr nz, .second_energy_2 ld a, b ; first energy ld [wce1b], a call RemoveCardFromList jr .loop_energy_cards_2 .second_energy_2 ld a, [wce1c] cp $ff jr nz, .third_energy_2 ld a, b ld [wce1c], a call RemoveCardFromList jr .loop_energy_cards_2 .third_energy_2 ld a, [wce1d] cp $ff jr nz, .fourth_energy ld a, b ld [wce1d], a call RemoveCardFromList jr .loop_energy_cards_2 .fourth_energy ld a, b ld [wce1e], a jr .set_carry ; will set carry if at least one has been chosen .check_chosen ld a, [wce1b] cp $ff jr nz, .set_carry .no_carry or a ret .set_carry ld a, [wce08] ld [wce1a], a ld a, [wce06] scf ret ; finds the card with deck index a in list hl, ; and removes it from the list. ; the card HAS to exist in the list, since this ; routine does not check for the terminating byte $ff! ; input: ; a = card deck index to look ; hl = pointer to list of cards FindAndRemoveCardFromList: ; 210d5 (8:50d5) push hl ld b, a .loop_duplicate ld a, [hli] cp b jr nz, .loop_duplicate call RemoveCardFromList pop hl ret AIPlay_PokemonCenter: ; 210e0 (8:50e0) ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret AIDecide_PokemonCenter: ; 210eb (8:50eb) xor a ldh [hTempPlayAreaLocation_ff9d], a ; return if active Pokemon can KO player's card. farcall CheckIfAnyAttackKnocksOutDefendingCard jr nc, .start farcall CheckIfSelectedAttackIsUnusable jr nc, .no_carry farcall LookForEnergyNeededForAttackInHand jr c, .no_carry .start xor a ld [wce06], a ld [wce08], a ld [wce0f], a ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetTurnDuelistVariable ld d, a ld e, PLAY_AREA_ARENA .loop_play_area ld a, DUELVARS_ARENA_CARD add e push de call GetTurnDuelistVariable call LoadCardDataToBuffer1_FromDeckIndex ld a, e ; useless instruction pop de ; get this Pokemon's current HP in number of counters ; and add it to the total. ld a, [wLoadedCard1HP] call ConvertHPToCounters ld b, a ld a, [wce06] add b ld [wce06], a ; get this Pokemon's current damage counters ; and add it to the total. call GetCardDamageAndMaxHP call ConvertHPToCounters ld b, a ld a, [wce08] add b ld [wce08], a ; get this Pokemon's number of attached energy cards ; and add it to the total. ; if there's overflow, return no carry. call GetPlayAreaCardAttachedEnergies ld a, [wTotalAttachedEnergies] ld b, a ld a, [wce0f] add b jr c, .no_carry ld [wce0f], a inc e dec d jr nz, .loop_play_area ; if (number of damage counters / 2) < (total energy cards attached) ; return no carry. ld a, [wce08] srl a ld hl, wce0f cp [hl] jr c, .no_carry ; if (number of HP counters * 6 / 10) >= (number of damage counters) ; return no carry. ld a, [wce06] ld l, a ld h, 6 call HtimesL call CalculateWordTensDigit ld a, l ld hl, wce08 cp [hl] jr nc, .no_carry scf ret .no_carry or a ret AIPlay_ImposterProfessorOak: ; 21170 (8:5170) ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret ; sets carry depending on player's number of cards ; in deck in in hand. AIDecide_ImposterProfessorOak: ; 2117b (8:517b) ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK call GetNonTurnDuelistVariable cp DECK_SIZE - 14 jr c, .more_than_14_cards ; if player has less than 14 cards in deck, only ; set carry if number of cards in their hands < 6 ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND call GetNonTurnDuelistVariable cp 6 jr c, .set_carry .no_carry or a ret ; if player has more than 14 cards in deck, only ; set carry if number of cards in their hands >= 9 .more_than_14_cards ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND call GetNonTurnDuelistVariable cp 9 jr c, .no_carry .set_carry scf ret AIPlay_EnergySearch: ; 2119a (8:519a) ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, [wAITrainerCardParameter] ldh [hTemp_ffa0], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret ; AI checks for playing Energy Search AIDecide_EnergySearch: ; 211aa (8:51aa) farcall CreateEnergyCardListFromHand jr c, .start call .CheckForUsefulEnergyCards jr c, .start ; there are energy cards in hand and at least ; one of them is useful to a card in Play Area .no_carry or a ret .start ld a, [wOpponentDeckID] cp HEATED_BATTLE_DECK_ID jr z, .heated_battle cp WONDERS_OF_SCIENCE_DECK_ID jr z, .wonders_of_science ; if no energy cards in deck, return no carry ld a, CARD_LOCATION_DECK call FindBasicEnergyCardsInLocation jr c, .no_carry ; if any of the energy cards in deck is useful ; return carry right away... call .CheckForUsefulEnergyCards jr c, .no_useful scf ret ; ...otherwise save the list in a before return carry. .no_useful ld a, [wDuelTempList] scf ret ; Heated Battle deck only searches for Fire and Lightning ; if they are found to be useful to some card in Play Area .heated_battle ld a, CARD_LOCATION_DECK call FindBasicEnergyCardsInLocation jr c, .no_carry call .CheckUsefulFireOrLightningEnergy jr c, .no_carry scf ret ; this subroutine has a bug. ; it was supposed to use the .CheckUsefulGrassEnergy subroutine ; but uses .CheckUsefulFireOrLightningEnergy instead. .wonders_of_science ld a, CARD_LOCATION_DECK call FindBasicEnergyCardsInLocation jr c, .no_carry call .CheckUsefulFireOrLightningEnergy jr c, .no_carry scf ret ; return carry if cards in wDuelTempList are not ; useful to any of the Play Area Pokemon .CheckForUsefulEnergyCards ; 211f1 (8:51f1) ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetTurnDuelistVariable ld d, a ld e, PLAY_AREA_ARENA .loop_play_area_1 ld a, DUELVARS_ARENA_CARD add e push de call GetTurnDuelistVariable ; store ID and type of card call GetCardIDFromDeckIndex ld a, e ld [wTempCardID], a call LoadCardDataToBuffer1_FromCardID pop de ld a, [wLoadedCard1Type] or TYPE_ENERGY ld [wTempCardType], a ; look in list for a useful energy, ; is any is found return no carry. ld hl, wDuelTempList .loop_energy_1 ld a, [hli] cp $ff jr z, .none_found ld b, a push hl farcall CheckIfEnergyIsUseful pop hl jr nc, .loop_energy_1 ld a, b or a ret .none_found inc e ld a, e cp d jr nz, .loop_play_area_1 scf ret ; checks whether there are useful energies ; only for Fire and Lightning type Pokemon cards ; in Play Area. If none found, return carry. .CheckUsefulFireOrLightningEnergy ; 2122e (8:522e) ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetTurnDuelistVariable ld d, a ld e, PLAY_AREA_ARENA .loop_play_area_2 ld a, DUELVARS_ARENA_CARD add e push de call GetTurnDuelistVariable ; get card's ID and Type call GetCardIDFromDeckIndex ld a, e ld [wTempCardID], a call LoadCardDataToBuffer1_FromCardID pop de ld a, [wLoadedCard1Type] or TYPE_ENERGY ; only do check if the Pokemon's type ; is either Fire or Lightning cp TYPE_ENERGY_FIRE jr z, .fire_or_lightning cp TYPE_ENERGY_LIGHTNING jr nz, .next_play_area ; loop each energy card in list .fire_or_lightning ld [wTempCardType], a ld hl, wDuelTempList .loop_energy_2 ld a, [hli] cp $ff jr z, .next_play_area ; if this energy card is useful, ; return no carry. ld b, a push hl farcall CheckIfEnergyIsUseful pop hl jr nc, .loop_energy_2 ld a, b or a ret .next_play_area inc e ld a, e cp d jr nz, .loop_play_area_2 ; no card was found to be useful ; for Fire/Lightning type Pokemon card. scf ret ; checks whether there are useful energies ; only for Grass type Pokemon cards ; in Play Area. If none found, return carry. .CheckUsefulGrassEnergy ; 21273 (8:5273) ; unreferenced ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetTurnDuelistVariable ld d, a ld e, PLAY_AREA_ARENA .loop_play_area_3 ld a, DUELVARS_ARENA_CARD add e push de call GetTurnDuelistVariable ; get card's ID and Type call GetCardIDFromDeckIndex ld a, e ld [wTempCardID], a call LoadCardDataToBuffer1_FromCardID pop de ld a, [wLoadedCard1Type] or TYPE_ENERGY ; only do check if the Pokemon's type is Grass cp TYPE_ENERGY_GRASS jr nz, .next_play_area_3 ; loop each energy card in list ld [wTempCardType], a ld hl, wDuelTempList .loop_energy_3 ld a, [hli] cp $ff jr z, .next_play_area_3 ; if this energy card is useful, ; return no carry. ld b, a push hl farcall CheckIfEnergyIsUseful pop hl jr nc, .loop_energy_3 ld a, b or a ret .next_play_area_3 inc e ld a, e cp d jr nz, .loop_play_area_3 ; no card was found to be useful ; for Grass type Pokemon card. scf ret AIPlay_Pokedex: ; 212b4 (8:52b4) ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, [wce1a] ldh [hTemp_ffa0], a ld a, [wce1b] ldh [hTempPlayAreaLocation_ffa1], a ld a, [wce1c] ldh [hTempRetreatCostCards], a ld a, [wce1d] ldh [$ffa3], a ld a, [wce1e] ldh [$ffa4], a ld a, $ff ldh [$ffa5], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret AIDecide_Pokedex: ; 212dc (8:52dc) ld a, [wAIPokedexCounter] cp 5 + 1 jr c, .no_carry ; return if counter hasn't reached 6 yet ; return no carry if number of cards in deck <= 4 ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK call GetTurnDuelistVariable cp DECK_SIZE - 4 jr nc, .no_carry ; has a 3 in 10 chance of actually playing card ld a, 10 call Random cp 3 jr c, .pick_cards .no_carry or a ret .pick_cards ; the following comparison is disregarded ; the Wonders of Science deck was probably intended ; to use PickPokedexCards_Unreferenced instead ld a, [wOpponentDeckID] cp WONDERS_OF_SCIENCE_DECK_ID jp PickPokedexCards ; bug, should be jp nz ; picks order of the cards in deck from the effects of Pokedex. ; prioritizes Pokemon cards, then Trainer cards, then energy cards. ; stores the resulting order in wce1a. PickPokedexCards_Unreferenced: ; 212ff (8:52ff) ; unreferenced xor a ld [wAIPokedexCounter], a ; reset counter ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK call GetTurnDuelistVariable add DUELVARS_DECK_CARDS ld l, a lb de, $00, $00 ld b, 5 ; run through 5 of the remaining cards in deck .next_card ld a, [hli] ld c, a call .GetCardType ; load this card's deck index and type in memory ; wce08 = card types ; wce0f = card deck indices push hl ld hl, wce08 add hl, de ld [hl], a ld hl, wce0f add hl, de ld [hl], c pop hl inc e dec b jr nz, .next_card ; terminate the wce08 list ld a, $ff ld [wce08 + 5], a ld de, wce1a ; find Pokemon ld hl, wce08 ld c, -1 ld b, $00 ; run through the stored cards ; and look for any Pokemon cards. .loop_pokemon inc c ld a, [hli] cp $ff jr z, .find_trainers cp TYPE_ENERGY jr nc, .loop_pokemon ; found a Pokemon card ; store it in wce1a list push hl ld hl, wce0f add hl, bc ld a, [hl] pop hl ld [de], a inc de jr .loop_pokemon ; run through the stored cards ; and look for any Trainer cards. .find_trainers ld hl, wce08 ld c, -1 ld b, $00 .loop_trainers inc c ld a, [hli] cp $ff jr z, .find_energy cp TYPE_TRAINER jr nz, .loop_trainers ; found a Trainer card ; store it in wce1a list push hl ld hl, wce0f add hl, bc ld a, [hl] pop hl ld [de], a inc de jr .loop_trainers .find_energy ld hl, wce08 ld c, -1 ld b, $00 ; run through the stored cards ; and look for any energy cards. .loop_energy inc c ld a, [hli] cp $ff jr z, .done and TYPE_ENERGY jr z, .loop_energy ; found an energy card ; store it in wce1a list push hl ld hl, wce0f add hl, bc ld a, [hl] pop hl ld [de], a inc de jr .loop_energy .done scf ret .GetCardType ; 21383 (8:5383) push bc push de call GetCardIDFromDeckIndex call GetCardType pop de pop bc ret ; picks order of the cards in deck from the effects of Pokedex. ; prioritizes energy cards, then Pokemon cards, then Trainer cards. ; stores the resulting order in wce1a. PickPokedexCards: ; 2138e (8:538e) xor a ld [wAIPokedexCounter], a ; reset counter ; reset counter ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK call GetTurnDuelistVariable add DUELVARS_DECK_CARDS ld l, a lb de, $00, $00 ld b, 5 ; run through 5 of the remaining cards in deck .next_card ld a, [hli] ld c, a call .GetCardType ; load this card's deck index and type in memory ; wce08 = card types ; wce0f = card deck indices push hl ld hl, wce08 add hl, de ld [hl], a ld hl, wce0f add hl, de ld [hl], c pop hl inc e dec b jr nz, .next_card ; terminate the wce08 list ld a, $ff ld [wce08 + 5], a ld de, wce1a ; find energy ld hl, wce08 ld c, -1 ld b, $00 ; run through the stored cards ; and look for any energy cards. .loop_energy inc c ld a, [hli] cp $ff jr z, .find_pokemon and TYPE_ENERGY jr z, .loop_energy ; found an energy card ; store it in wce1a list push hl ld hl, wce0f add hl, bc ld a, [hl] pop hl ld [de], a inc de jr .loop_energy .find_pokemon ld hl, wce08 ld c, -1 ld b, $00 ; run through the stored cards ; and look for any Pokemon cards. .loop_pokemon inc c ld a, [hli] cp $ff jr z, .find_trainers cp TYPE_ENERGY jr nc, .loop_pokemon ; found a Pokemon card ; store it in wce1a list push hl ld hl, wce0f add hl, bc ld a, [hl] pop hl ld [de], a inc de jr .loop_pokemon ; run through the stored cards ; and look for any Trainer cards. .find_trainers ld hl, wce08 ld c, -1 ld b, $00 .loop_trainers inc c ld a, [hli] cp $ff jr z, .done cp TYPE_TRAINER jr nz, .loop_trainers ; found a Trainer card ; store it in wce1a list push hl ld hl, wce0f add hl, bc ld a, [hl] pop hl ld [de], a inc de jr .loop_trainers .done scf ret .GetCardType ; 21412 (8:5412) push bc push de call GetCardIDFromDeckIndex call GetCardType pop de pop bc ret AIPlay_FullHeal: ; 2141d (8:541d) ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret AIDecide_FullHeal: ; 21428 (8:5428) ld a, DUELVARS_ARENA_CARD_STATUS call GetTurnDuelistVariable ; skip if no status on arena card or a ; NO_STATUS jr z, .no_carry and CNF_SLP_PRZ cp PARALYZED jr z, .paralyzed cp ASLEEP jr z, .asleep cp CONFUSED jr z, .confused ; if either PSN or DBLPSN, fallthrough .set_carry scf ret .asleep ; set carry if any of the following ; cards are in the Play Area. ld a, GASTLY1 ld b, PLAY_AREA_ARENA call LookForCardIDInPlayArea_Bank8 jr c, .set_carry ld a, GASTLY2 ld b, PLAY_AREA_ARENA call LookForCardIDInPlayArea_Bank8 jr c, .set_carry ld a, HAUNTER2 ld b, PLAY_AREA_ARENA call LookForCardIDInPlayArea_Bank8 jr c, .set_carry ; otherwise fallthrough .paralyzed ; if Scoop Up is in hand and decided to be played, skip. ld a, SCOOP_UP call LookForCardIDInHandList_Bank8 jr nc, .no_scoop_up_prz call AIDecide_ScoopUp jr c, .no_carry .no_scoop_up_prz ; if card can damage defending Pokemon... xor a ; PLAY_AREA_ARENA farcall CheckIfCanDamageDefendingPokemon jr nc, .no_carry ; ...and can play an energy card to retreat, set carry. ld a, [wAIPlayEnergyCardForRetreat] or a jr nz, .set_carry ; if not, check whether it's a card it would rather retreat, ; and if it isn't, set carry. farcall AIDecideWhetherToRetreat jr nc, .set_carry .no_carry or a ret .confused ; if Scoop Up is in hand and decided to be played, skip. ld a, SCOOP_UP call LookForCardIDInHandList_Bank8 jr nc, .no_scoop_up_cnf call AIDecide_ScoopUp jr c, .no_carry .no_scoop_up_cnf ; if card can damage defending Pokemon... xor a ; PLAY_AREA_ARENA farcall CheckIfCanDamageDefendingPokemon jr nc, .no_carry ; ...and can play an energy card to retreat, set carry. ld a, [wAIPlayEnergyCardForRetreat] or a jr nz, .set_carry ; if not, return no carry. jr .no_carry AIPlay_MrFuji: ; 21497 (8:5497) ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, [wAITrainerCardParameter] ldh [hTemp_ffa0], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret ; AI logic for playing Mr Fuji AIDecide_MrFuji: ; 214a7 (8:54a7) ld a, $ff ld [wce06], a ld [wce08], a ; if just one Pokemon in Play Area, skip. ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetTurnDuelistVariable cp 1 ret z dec a ld d, a ld e, PLAY_AREA_BENCH_1 ; find a Pokemon in the bench that has damage counters. .loop_bench ld a, DUELVARS_ARENA_CARD add e push de call GetTurnDuelistVariable call LoadCardDataToBuffer1_FromDeckIndex pop de ld a, [wLoadedCard1HP] ld b, a ; skip if zero damage counters call GetCardDamageAndMaxHP call ConvertHPToCounters or a jr z, .next ; a = damage counters ; b = hp left call CalculateBDividedByA_Bank8 cp 20 jr nc, .next ; here, HP left in counters is less than twice ; the number of damage counters, that is: ; HP < 1/3 max HP ; if value is less than the one found before, store this one. ld hl, wce08 cp [hl] jr nc, .next ld [hl], a ld a, e ld [wce06], a .next inc e dec d jr nz, .loop_bench ld a, [wce06] cp $ff ret z scf ret AIPlay_ScoopUp: ; 214f1 (8:54f1) ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, [wAITrainerCardParameter] ldh [hTemp_ffa0], a ld a, [wce1a] ldh [hTempPlayAreaLocation_ffa1], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret AIDecide_ScoopUp: ; 21506 (8:5506) xor a ldh [hTempPlayAreaLocation_ff9d], a ; if only one Pokemon in Play Area, skip. ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetTurnDuelistVariable cp 2 jr c, .no_carry ; handle some decks differently ld a, [wOpponentDeckID] cp LEGENDARY_ARTICUNO_DECK_ID jr z, .HandleLegendaryArticuno cp LEGENDARY_RONALD_DECK_ID jp z, .HandleLegendaryRonald ; if can't KO defending Pokemon, check if defending Pokemon ; can KO this card. If so, then continue. ; If not, return no carry. ; if it can KO the defending Pokemon this turn, ; return no carry. farcall CheckIfAnyAttackKnocksOutDefendingCard jr nc, .cannot_ko farcall CheckIfSelectedAttackIsUnusable jr nc, .no_carry farcall LookForEnergyNeededForAttackInHand jr c, .no_carry .cannot_ko ld a, DUELVARS_ARENA_CARD_STATUS call GetTurnDuelistVariable and CNF_SLP_PRZ cp PARALYZED jr z, .cannot_retreat cp ASLEEP jr z, .cannot_retreat ; doesn't have a status that prevents retreat. ; so check if it has enough energy to retreat. ; if not, return no carry. xor a ldh [hTempPlayAreaLocation_ff9d], a call GetPlayAreaCardRetreatCost ld b, a ld e, PLAY_AREA_ARENA farcall CountNumberOfEnergyCardsAttached cp b jr c, .cannot_retreat .no_carry or a ret .cannot_retreat ; store damage and total HP left ld a, DUELVARS_ARENA_CARD call GetTurnDuelistVariable call LoadCardDataToBuffer1_FromDeckIndex ld a, [wLoadedCard1HP] call ConvertHPToCounters ld d, a ; skip if card has no damage counters. ld e, PLAY_AREA_ARENA call GetCardDamageAndMaxHP or a jr z, .no_carry ; if (total damage / total HP counters) < 7 ; return carry. ; (this corresponds to damage counters ; being under 70% of the max HP) ld b, a ld a, d call CalculateBDividedByA_Bank8 cp 7 jr c, .no_carry ; store Pokemon to switch to in wce1a and set carry. .decide_switch farcall AIDecideBenchPokemonToSwitchTo jr c, .no_carry ld [wce1a], a xor a scf ret ; this deck will use Scoop Up on a benched Articuno2. ; it checks if the defending Pokemon is a Snorlax, ; but interestingly does not check for Muk in both Play Areas. ; will also use Scoop Up on .HandleLegendaryArticuno ; if less than 3 Play Area Pokemon cards, skip. ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetTurnDuelistVariable cp 3 jr c, .no_carry ; look for Articuno2 in bench ld a, ARTICUNO2 ld b, PLAY_AREA_BENCH_1 call LookForCardIDInPlayArea_Bank8 jr c, .articuno_bench ; check Arena card ld a, DUELVARS_ARENA_CARD call GetTurnDuelistVariable call GetCardIDFromDeckIndex ld a, e cp ARTICUNO2 jr z, .articuno_or_chansey cp CHANSEY jr nz, .no_carry ; here either Articuno2 or Chansey ; is the Arena Card. .articuno_or_chansey ; if can't KO defending Pokemon, check if defending Pokemon ; can KO this card. If so, then continue. ; If not, return no carry. ; if it can KO the defending Pokemon this turn, ; return no carry. farcall CheckIfAnyAttackKnocksOutDefendingCard jr nc, .check_ko farcall CheckIfSelectedAttackIsUnusable jr nc, .no_carry farcall LookForEnergyNeededForAttackInHand jr c, .no_carry .check_ko farcall CheckIfDefendingPokemonCanKnockOut jr nc, .no_carry jr .decide_switch .articuno_bench ; skip if the defending card is Snorlax push af ld a, DUELVARS_ARENA_CARD call GetNonTurnDuelistVariable call SwapTurn call GetCardIDFromDeckIndex call SwapTurn ld a, e cp SNORLAX pop bc jr z, .no_carry ; check attached energy cards. ; if it has any, return no carry. ld a, b .check_attached_energy ld e, a push af farcall CountNumberOfEnergyCardsAttached or a pop bc ld a, b jr z, .no_energy jp .no_carry .no_energy ; has decided to Scoop Up benched card, ; store $ff as the Pokemon card to switch to ; because there's no need to switch. push af ld a, $ff ld [wce1a], a pop af scf ret ; this deck will use Scoop Up on a benched Articuno2, Zapdos3 or Moltres2. ; interestingly, does not check for Muk in both Play Areas. .HandleLegendaryRonald ; 215e7 (8:55e7) ; if less than 3 Play Area Pokemon cards, skip. ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetTurnDuelistVariable cp 3 jp c, .no_carry ld a, ARTICUNO2 ld b, PLAY_AREA_BENCH_1 call LookForCardIDInPlayArea_Bank8 jr c, .articuno_bench ld a, ZAPDOS3 ld b, PLAY_AREA_BENCH_1 call LookForCardIDInPlayArea_Bank8 jr c, .check_attached_energy ld a, MOLTRES2 ld b, PLAY_AREA_BENCH_1 call LookForCardIDInPlayArea_Bank8 jr c, .check_attached_energy jp .no_carry AIPlay_Maintenance: ; 2160f (8:560f) ld a, [wCurrentAIFlags] or AI_FLAG_MODIFIED_HAND ld [wCurrentAIFlags], a ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, [wce1a] ldh [hTemp_ffa0], a ld a, [wce1b] ldh [hTempPlayAreaLocation_ffa1], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret ; AI logic for playing Maintenance AIDecide_Maintenance: ; 2162c (8:562c) ; Imakuni? has his own thing ld a, [wOpponentDeckID] cp IMAKUNI_DECK_ID jr z, .imakuni ; skip if number of cars in hand < 4. ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND call GetTurnDuelistVariable cp 4 jr c, .no_carry ; list out all the hand cards and remove ; wAITrainerCardToPlay from list.Then find any duplicate cards. call CreateHandCardList ld hl, wDuelTempList ld a, [wAITrainerCardToPlay] call FindAndRemoveCardFromList ; if duplicates are not found, return no carry. call FindDuplicateCards jp c, .no_carry ; store the first duplicate card and remove it from the list. ; run duplicate check again. ld [wce1a], a ld hl, wDuelTempList call FindAndRemoveCardFromList ; if duplicates are not found, return no carry. call FindDuplicateCards jp c, .no_carry ; store the second duplicate card and return carry. ld [wce1b], a scf ret .no_carry or a ret .imakuni ; has a 2 in 10 chance of not skipping. ld a, 10 call Random cp 2 jr nc, .no_carry ; skip if number of cards in hand < 3. ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND call GetTurnDuelistVariable cp 3 jr c, .no_carry ; shuffle hand cards call CreateHandCardList ld hl, wDuelTempList call CountCardsInDuelTempList call ShuffleCards ; go through each card and find ; cards that are different from wAITrainerCardToPlay. ; if found, add those cards to wce1a and wce1a+1. ld a, [wAITrainerCardToPlay] ld b, a ld c, 2 ld de, wce1a .loop ld a, [hli] cp $ff jr z, .no_carry cp b jr z, .loop ld [de], a inc de dec c jr nz, .loop ; two cards were found, return carry. scf ret AIPlay_Recycle: ; 2169a (8:569a) ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ldtx de, TrainerCardSuccessCheckText bank1call TossCoin jr nc, .asm_216ae ld a, [wAITrainerCardParameter] ldh [hTemp_ffa0], a jr .asm_216b2 .asm_216ae ld a, $ff ldh [hTemp_ffa0], a .asm_216b2 ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret ; lists cards to look for in the Discard Pile. ; has priorities for Ghost Deck, and a "default" priority list ; (which is the Fire Charge deck, since it's the only other ; deck that runs a Recycle card in it.) AIDecide_Recycle: ; 216b8 (8:56b8) ; no use checking if no cards in Discard Pile call CreateDiscardPileCardList jr c, .no_carry ld a, $ff ld [wce08], a ld [wce08 + 1], a ld [wce08 + 2], a ld [wce08 + 3], a ld [wce08 + 4], a ; handle Ghost deck differently ld hl, wDuelTempList ld a, [wOpponentDeckID] cp GHOST_DECK_ID jr z, .loop_2 ; priority list for Fire Charge deck .loop_1 ld a, [hli] cp $ff jr z, .done ld b, a call LoadCardDataToBuffer1_FromDeckIndex ; double colorless cp DOUBLE_COLORLESS_ENERGY jr nz, .chansey ld a, b ld [wce08], a jr .loop_1 .chansey cp CHANSEY jr nz, .tauros ld a, b ld [wce08 + 1], a jr .loop_1 .tauros cp TAUROS jr nz, .jigglypuff ld a, b ld [wce08 + 2], a jr .loop_1 .jigglypuff cp JIGGLYPUFF1 jr nz, .loop_1 ld a, b ld [wce08 + 3], a jr .loop_1 ; loop through wce08 and set carry ; on the first that was found in Discard Pile. ; if none were found, return no carry. .done ld hl, wce08 ld b, 5 .loop_found ld a, [hli] cp $ff jr nz, .set_carry dec b jr nz, .loop_found .no_carry or a ret .set_carry scf ret ; priority list for Ghost deck .loop_2 ld a, [hli] cp $ff jr z, .done ld b, a call LoadCardDataToBuffer1_FromDeckIndex ; gastly2 cp GASTLY2 jr nz, .gastly1 ld a, b ld [wce08], a jr .loop_2 .gastly1 cp GASTLY1 jr nz, .zubat ld a, b ld [wce08 + 1], a jr .loop_2 .zubat cp ZUBAT jr nz, .ditto ld a, b ld [wce08 + 2], a jr .loop_2 .ditto cp DITTO jr nz, .meowth ld a, b ld [wce08 + 3], a jr .loop_2 .meowth cp MEOWTH2 jr nz, .loop_2 ld a, b ld [wce08 + 4], a jr .loop_2 AIPlay_Lass: ; 21755 (8:5755) ld a, [wCurrentAIFlags] or AI_FLAG_MODIFIED_HAND ld [wCurrentAIFlags], a ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret AIDecide_Lass: ; 21768 (8:5768) ; skip if player has less than 7 cards in hand ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND call GetNonTurnDuelistVariable cp 7 jr c, .no_carry ; look for Trainer cards in hand (except for Lass) ; if any is found, return no carry. ; otherwise, return carry. call CreateHandCardList ld hl, wDuelTempList .loop ld a, [hli] cp $ff jr z, .set_carry ld b, a call LoadCardDataToBuffer1_FromDeckIndex cp LASS jr z, .loop ld a, [wLoadedCard1Type] cp TYPE_TRAINER jr nz, .loop .no_carry or a ret .set_carry scf ret AIPlay_ItemFinder: ; 2178f (8:578f) ld a, [wCurrentAIFlags] or AI_FLAG_MODIFIED_HAND ld [wCurrentAIFlags], a ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, [wce1a] ldh [hTemp_ffa0], a ld a, [wce1b] ldh [hTempPlayAreaLocation_ffa1], a ld a, [wAITrainerCardParameter] ldh [hTempRetreatCostCards], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret ; checks whether there's Energy Removal in Discard Pile. ; if so, find duplicate cards in hand to discard ; that are not Mr Mime and Pokemon Trader cards. ; this logic is suitable only for Strange Psyshock deck. AIDecide_ItemFinder: ; 217b1 (8:57b1) ; skip if no Discard Pile. call CreateDiscardPileCardList jr c, .no_carry ; look for Energy Removal in Discard Pile ld hl, wDuelTempList .loop_discard_pile ld a, [hli] cp $ff jr z, .no_carry ld b, a call LoadCardDataToBuffer1_FromDeckIndex cp ENERGY_REMOVAL jr nz, .loop_discard_pile ; found, store this deck index ld a, b ld [wce06], a ; before looking for cards to discard in hand, ; remove any Mr Mime and Pokemon Trader cards. ; this way these are guaranteed to not be discarded. call CreateHandCardList ld hl, wDuelTempList .loop_hand ld a, [hli] cp $ff jr z, .choose_discard ld b, a call LoadCardDataToBuffer1_FromDeckIndex cp MR_MIME jr nz, .pkmn_trader call RemoveCardFromList jr .loop_hand .pkmn_trader cp POKEMON_TRADER jr nz, .loop_hand call RemoveCardFromList jr .loop_hand ; choose cards to discard from hand. .choose_discard ld hl, wDuelTempList ; do not discard wAITrainerCardToPlay ld a, [wAITrainerCardToPlay] call FindAndRemoveCardFromList ; find any duplicates, if not found, return no carry. call FindDuplicateCards jp c, .no_carry ; store the duplicate found in wce1a and ; remove it from the hand list. ld [wce1a], a ld hl, wDuelTempList call FindAndRemoveCardFromList ; find duplicates again, if not found, return no carry. call FindDuplicateCards jp c, .no_carry ; store the duplicate found in wce1b. ; output the card to be recovered from the Discard Pile. ld [wce1b], a ld a, [wce06] scf ret .no_carry or a ret AIPlay_Imakuni: ; 21813 (8:5813) ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret ; only sets carry if Active card is not confused. AIDecide_Imakuni: ; 2181e (8:581e) ld a, DUELVARS_ARENA_CARD_STATUS call GetTurnDuelistVariable and CNF_SLP_PRZ cp CONFUSED jr z, .confused scf ret .confused or a ret AIPlay_Gambler: ; 2182d (8:582d) ld a, [wCurrentAIFlags] or AI_FLAG_MODIFIED_HAND ld [wCurrentAIFlags], a ld a, [wOpponentDeckID] cp IMAKUNI_DECK_ID jr z, .asm_2186a ld hl, wRNG1 ld a, [hli] ld [wce06], a ld a, [hli] ld [wce08], a ld a, [hl] ld [wce0f], a ld a, $50 ld [hld], a ld [hld], a ld [hl], a ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ld hl, wRNG1 ld a, [wce06] ld [hli], a ld a, [wce08] ld [hli], a ld a, [wce0f] ld [hl], a ret .asm_2186a ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret ; checks whether to play Gambler. ; aside from Imakuni?, all other opponents only ; play this card if Player is running Mewtwo1-only deck. AIDecide_Gambler: ; 21875 (8:5875) ; Imakuni? has his own routine ld a, [wOpponentDeckID] cp IMAKUNI_DECK_ID jr z, .imakuni ; check if flag is set for Player using Mewtwo1 only deck ld a, [wAIBarrierFlagCounter] and AI_MEWTWO_MILL jr z, .no_carry ; set carry if number of cards in deck <= 4. ; this is done to counteract the deck out strategy ; of Mewtwo1 deck, by replenishing the deck with hand cards. ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK call GetTurnDuelistVariable cp DECK_SIZE - 4 jr nc, .set_carry .no_carry or a ret .imakuni ; has a 2 in 10 chance of returning carry ld a, 10 call Random cp 2 jr nc, .no_carry .set_carry scf ret AIPlay_Revive: ; 21899 (8:5899) ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, [wAITrainerCardParameter] ldh [hTemp_ffa0], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret ; checks certain cards in Discard Pile to use Revive on. ; suitable for Muscle For Brains deck only. AIDecide_Revive: ; 218a9 (8:58a9) ; skip if no cards in Discard Pile call CreateDiscardPileCardList jr c, .no_carry ; skip if number of Pokemon cards in Play Area >= 4 ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetTurnDuelistVariable cp 4 jr nc, .no_carry ; look in Discard Pile for specific cards. ld hl, wDuelTempList .loop_discard_pile ld a, [hli] cp $ff jr z, .no_carry ld b, a call LoadCardDataToBuffer1_FromDeckIndex ; these checks have a bug. ; it works fine for Hitmonchan and Hitmonlee, ; but in case it's a Tauros card, the routine will fallthrough ; into the Kangaskhan check. since it will never be equal to Kangaskhan, ; it will fallthrough into the set carry branch. ; in case it's a Kangaskhan card, the check will fail in the Tauros check ; and jump back into the loop. so just by accident the Tauros check works, ; but Kangaskhan will never be correctly checked because of this. cp HITMONCHAN jr z, .set_carry cp HITMONLEE jr z, .set_carry cp TAUROS jr nz, .loop_discard_pile ; bug, these two lines should be swapped cp KANGASKHAN jr z, .set_carry ; bug, these two lines should be swapped .set_carry ld a, b scf ret .no_carry or a ret AIPlay_PokemonFlute: ; 218d8 (8:58d8) ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, [wAITrainerCardParameter] ldh [hTemp_ffa0], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret AIDecide_PokemonFlute: ; 218e8 (8:58e8) ; if player has no Discard Pile, skip. call SwapTurn call CreateDiscardPileCardList call SwapTurn jr c, .no_carry ; if player's Play Area is already full, skip. ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetNonTurnDuelistVariable cp MAX_PLAY_AREA_POKEMON jr nc, .no_carry ld a, [wOpponentDeckID] cp IMAKUNI_DECK_ID jr z, .imakuni ld a, $ff ld [wce06], a ld [wce08], a ; find Basic stage Pokemon with lowest HP in Discard Pile ld hl, wDuelTempList .loop_1 ld a, [hli] cp $ff jr z, .done ld b, a call SwapTurn call LoadCardDataToBuffer1_FromDeckIndex call SwapTurn ; skip this card if it's not Pokemon card ld a, [wLoadedCard1Type] cp TYPE_ENERGY jr nc, .loop_1 ; skip this card if it's not Basic Stage ld a, [wLoadedCard1Stage] or a ; BASIC jr nz, .loop_1 ; compare this HP with one stored ld a, [wLoadedCard1HP] push hl ld hl, wce06 cp [hl] pop hl jr nc, .loop_1 ; if lower, store this one ld [wce06], a ld a, b ld [wce08], a jr .loop_1 .done ; if lowest HP found >= 50, return no carry ld a, [wce06] cp 50 jr nc, .no_carry ; otherwise output its deck index in a and set carry. ld a, [wce08] scf ret .no_carry or a ret .imakuni ; has 2 in 10 chance of not skipping ld a, 10 call Random cp 2 jr nc, .no_carry ; look for any Basic Pokemon card ld hl, wDuelTempList .loop_2 ld a, [hli] cp $ff jr z, .no_carry ld b, a call SwapTurn call LoadCardDataToBuffer1_FromDeckIndex call SwapTurn ld a, [wLoadedCard1Type] cp TYPE_ENERGY jr nc, .loop_2 ld a, [wLoadedCard1Stage] or a ; BASIC jr nz, .loop_2 ; a Basic stage Pokemon was found, return carry ld a, b scf ret AIPlay_ClefairyDollOrMysteriousFossil: ; 21977 (8:5977) ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret ; AI logic for playing Clefairy Doll AIDecide_ClefairyDollOrMysteriousFossil: ; 21982 (8:5982) ; if has max number of Play Area Pokemon, skip ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetTurnDuelistVariable cp MAX_PLAY_AREA_POKEMON jr nc, .no_carry ; store number of Play Area Pokemon cards ld [wce06], a ; if the Arena card is Wigglytuff, return carry ld a, DUELVARS_ARENA_CARD call GetTurnDuelistVariable call GetCardIDFromDeckIndex ld a, e cp WIGGLYTUFF jr z, .set_carry ; if number of Play Area Pokemon >= 4, return no carry ld a, [wce06] cp 4 jr nc, .no_carry .set_carry scf ret .no_carry or a ret AIPlay_Pokeball: ; 219a6 (8:59a6) ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ldtx de, TrainerCardSuccessCheckText bank1call TossCoin ldh [hTemp_ffa0], a jr nc, .asm_219bc ld a, [wAITrainerCardParameter] ldh [hTempPlayAreaLocation_ffa1], a jr .asm_219c0 .asm_219bc ld a, $ff ldh [hTempPlayAreaLocation_ffa1], a .asm_219c0 ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret AIDecide_Pokeball: ; 219c6 (8:59c6) ; go to the routines associated with deck ID ld a, [wOpponentDeckID] cp FIRE_CHARGE_DECK_ID jr z, .fire_charge cp HARD_POKEMON_DECK_ID jr z, .hard_pokemon cp PIKACHU_DECK_ID jr z, .pikachu cp ETCETERA_DECK_ID jr z, .etcetera cp LOVELY_NIDORAN_DECK_ID jp z, .lovely_nidoran or a ret ; this deck runs a deck check for specific ; card IDs in order of decreasing priority .fire_charge ld e, CHANSEY ld a, CARD_LOCATION_DECK call LookForCardIDInLocation ret c ld e, TAUROS ld a, CARD_LOCATION_DECK call LookForCardIDInLocation ret c ld e, JIGGLYPUFF1 ld a, CARD_LOCATION_DECK call LookForCardIDInLocation ret c ret ; this deck runs a deck check for specific ; card IDs in order of decreasing priority .hard_pokemon ld e, RHYHORN ld a, CARD_LOCATION_DECK call LookForCardIDInLocation ret c ld e, RHYDON ld a, CARD_LOCATION_DECK call LookForCardIDInLocation ret c ld e, ONIX ld a, CARD_LOCATION_DECK call LookForCardIDInLocation ret c ret ; this deck runs a deck check for specific ; card IDs in order of decreasing priority .pikachu ld e, PIKACHU2 ld a, CARD_LOCATION_DECK call LookForCardIDInLocation ret c ld e, PIKACHU3 ld a, CARD_LOCATION_DECK call LookForCardIDInLocation ret c ld e, PIKACHU4 ld a, CARD_LOCATION_DECK call LookForCardIDInLocation ret c ld e, PIKACHU1 ld a, CARD_LOCATION_DECK call LookForCardIDInLocation ret c ld e, FLYING_PIKACHU ld a, CARD_LOCATION_DECK call LookForCardIDInLocation ret c ret ; this deck runs a deck check for specific ; card IDs in order of decreasing priority ; given a specific energy card in hand. ; also it avoids redundancy, so if it already ; has that card ID in the hand, it is skipped. .etcetera ; fire ld a, FIRE_ENERGY call LookForCardIDInHandList_Bank8 jr nc, .lightning ld a, CHARMANDER call LookForCardIDInHandList_Bank8 jr c, .lightning ld a, MAGMAR2 call LookForCardIDInHandList_Bank8 jr c, .lightning ld e, CHARMANDER ld a, CARD_LOCATION_DECK call LookForCardIDInLocation ret c ld e, MAGMAR2 ld a, CARD_LOCATION_DECK call LookForCardIDInLocation ret c .lightning ld a, LIGHTNING_ENERGY call LookForCardIDInHandList_Bank8 jr nc, .fighting ld a, PIKACHU1 call LookForCardIDInHandList_Bank8 jr c, .fighting ld a, MAGNEMITE1 call LookForCardIDInHandList_Bank8 jr c, .fighting ld e, PIKACHU1 ld a, CARD_LOCATION_DECK call LookForCardIDInLocation ret c ld e, MAGNEMITE1 ld a, CARD_LOCATION_DECK call LookForCardIDInLocation ret c .fighting ld a, FIGHTING_ENERGY call LookForCardIDInHandList_Bank8 jr nc, .psychic ld a, DIGLETT call LookForCardIDInHandList_Bank8 jr c, .psychic ld a, MACHOP call LookForCardIDInHandList_Bank8 jr c, .psychic ld e, DIGLETT ld a, CARD_LOCATION_DECK call LookForCardIDInLocation ret c ld e, MACHOP ld a, CARD_LOCATION_DECK call LookForCardIDInLocation ret c .psychic ld a, PSYCHIC_ENERGY call LookForCardIDInHandList_Bank8 jr nc, .done_etcetera ld a, GASTLY1 call LookForCardIDInHandList_Bank8 jr c, .done_etcetera ld a, JYNX call LookForCardIDInHandList_Bank8 jr c, .done_etcetera ld e, GASTLY1 ld a, CARD_LOCATION_DECK call LookForCardIDInLocation ret c ld e, JYNX ld a, CARD_LOCATION_DECK call LookForCardIDInLocation ret c .done_etcetera or a ret ; this deck looks for card evolutions if ; its pre-evolution is in hand or in Play Area. ; if none of these are found, it looks for pre-evolutions ; of cards it has in hand. ; it does this for both the NidoranM (first) ; and NidoranF (second) families. .lovely_nidoran ld b, NIDORANM ld a, NIDORINO call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea ret c ld b, NIDORINO ld a, NIDOKING call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea ret c ld a, NIDORANM ld b, NIDORINO call LookForCardIDInDeck_GivenCardIDInHand ret c ld a, NIDORINO ld b, NIDOKING call LookForCardIDInDeck_GivenCardIDInHand ret c ld b, NIDORANF ld a, NIDORINA call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea ret c ld b, NIDORINA ld a, NIDOQUEEN call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea ret c ld a, NIDORANF ld b, NIDORINA call LookForCardIDInDeck_GivenCardIDInHand ret c ld a, NIDORINA ld b, NIDOQUEEN call LookForCardIDInDeck_GivenCardIDInHand ret c ret AIPlay_ComputerSearch: ; 21b12 (8:5b12) ld a, [wCurrentAIFlags] or AI_FLAG_MODIFIED_HAND ld [wCurrentAIFlags], a ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, [wAITrainerCardParameter] ldh [hTempRetreatCostCards], a ld a, [wce1a] ldh [hTemp_ffa0], a ld a, [wce1b] ldh [hTempPlayAreaLocation_ffa1], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret ; checks what Deck ID AI is playing and handle ; them in their own routine. AIDecide_ComputerSearch: ; 21b34 (8:5b34) ; skip if number of cards in hand < 3 ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND call GetTurnDuelistVariable cp 3 jr c, .no_carry ld a, [wOpponentDeckID] cp ROCK_CRUSHER_DECK_ID jr z, AIDecide_ComputerSearch_RockCrusher cp WONDERS_OF_SCIENCE_DECK_ID jp z, AIDecide_ComputerSearch_WondersOfScience cp FIRE_CHARGE_DECK_ID jp z, AIDecide_ComputerSearch_FireCharge cp ANGER_DECK_ID jp z, AIDecide_ComputerSearch_Anger .no_carry or a ret AIDecide_ComputerSearch_RockCrusher: ; 21b55 (8:5b55) ; if number of cards in hand is equal to 3, ; target Professor Oak in deck ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND call GetTurnDuelistVariable cp 3 jr nz, .graveler ld e, PROFESSOR_OAK ld a, CARD_LOCATION_DECK call LookForCardIDInLocation jr c, .find_discard_cards_1 ; no Professor Oak in deck, fallthrough .no_carry or a ret .find_discard_cards_1 ld [wce06], a ld a, $ff ld [wce1a], a ld [wce1b], a call CreateHandCardList ld hl, wDuelTempList ld de, wce1a .loop_hand_1 ld a, [hli] cp $ff jr z, .check_discard_cards ld c, a call LoadCardDataToBuffer1_FromDeckIndex ; if any of the following cards are in the hand, ; return no carry. cp PROFESSOR_OAK jr z, .no_carry cp FIGHTING_ENERGY jr z, .no_carry cp DOUBLE_COLORLESS_ENERGY jr z, .no_carry cp DIGLETT jr z, .no_carry cp GEODUDE jr z, .no_carry cp ONIX jr z, .no_carry cp RHYHORN jr z, .no_carry ; if it's same as wAITrainerCardToPlay, skip this card. ld a, [wAITrainerCardToPlay] ld b, a ld a, c cp b jr z, .loop_hand_1 ; store this card index in memory ld [de], a inc de jr .loop_hand_1 .check_discard_cards ; check if two cards were found ; if so, output in a the deck index ; of Professor Oak card found in deck and set carry. ld a, [wce1b] cp $ff jr z, .no_carry ld a, [wce06] scf ret ; more than 3 cards in hand, so look for ; specific evolution cards. ; checks if there is a Graveler card in the deck to target. ; if so, check if there's Geodude in hand or Play Area, ; and if there's no Graveler card in hand, proceed. ; also removes Geodude from hand list so that it is not discarded. .graveler ld e, GRAVELER ld a, CARD_LOCATION_DECK call LookForCardIDInLocation jr nc, .golem ld [wce06], a ld a, GEODUDE call LookForCardIDInHandAndPlayArea jr nc, .golem ld a, GRAVELER call LookForCardIDInHandList_Bank8 jr c, .golem call CreateHandCardList ld hl, wDuelTempList ld e, GEODUDE farcall RemoveCardIDInList jr .find_discard_cards_2 ; checks if there is a Golem card in the deck to target. ; if so, check if there's Graveler in Play Area, ; and if there's no Golem card in hand, proceed. .golem ld e, GOLEM ld a, CARD_LOCATION_DECK call LookForCardIDInLocation jr nc, .dugtrio ld [wce06], a ld a, GRAVELER call LookForCardIDInPlayArea_Bank8 jr nc, .dugtrio ld a, GOLEM call LookForCardIDInHandList_Bank8 jr c, .dugtrio call CreateHandCardList ld hl, wDuelTempList jr .find_discard_cards_2 ; checks if there is a Dugtrio card in the deck to target. ; if so, check if there's Diglett in Play Area, ; and if there's no Dugtrio card in hand, proceed. .dugtrio ld e, DUGTRIO ld a, CARD_LOCATION_DECK call LookForCardIDInLocation jp nc, .no_carry ld [wce06], a ld a, DIGLETT call LookForCardIDInPlayArea_Bank8 jp nc, .no_carry ld a, DUGTRIO call LookForCardIDInHandList_Bank8 jp c, .no_carry call CreateHandCardList ld hl, wDuelTempList jr .find_discard_cards_2 .find_discard_cards_2 ld a, $ff ld [wce1a], a ld [wce1b], a ld bc, wce1a ld d, $00 ; start considering Trainer cards only ; stores wAITrainerCardToPlay in e so that ; all routines ignore it for the discard effects. ld a, [wAITrainerCardToPlay] ld e, a ; this loop will store in wce1a cards to discard from hand. ; at the start it will only consider Trainer cards, ; then if there are still needed to discard, ; move on to Pokemon cards, and finally to Energy cards. .loop_hand_2 call RemoveFromListDifferentCardOfGivenType jr c, .found inc d ; move on to next type (Pokemon, then Energy) ld a, $03 cp d jp z, .no_carry ; no more types to look jr .loop_hand_2 .found ; store this card in memory, ; and if there's still one more card to search for, ; jump back into the loop. ld [bc], a inc bc ld a, [wce1b] cp $ff jr z, .loop_hand_2 ; output in a Computer Search target and set carry. ld a, [wce06] scf ret AIDecide_ComputerSearch_WondersOfScience: ; 21c56 (8:5c56) ; if number of cards in hand < 5, target Professor Oak in deck ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND call GetTurnDuelistVariable cp 5 jr nc, .look_in_hand ; target Professor Oak for Computer Search ld e, PROFESSOR_OAK ld a, CARD_LOCATION_DECK call LookForCardIDInLocation jp nc, .look_in_hand ; can be a jr ld [wce06], a jr .find_discard_cards ; Professor Oak not in deck, move on to ; look for other cards instead. ; if Grimer or Muk are not in hand, ; check whether to use Computer Search on them. .look_in_hand ld a, GRIMER call LookForCardIDInHandList_Bank8 jr nc, .target_grimer ld a, MUK call LookForCardIDInHandList_Bank8 jr nc, .target_muk .no_carry or a ret ; first check Grimer ; if in deck, check cards to discard. .target_grimer ld e, GRIMER ld a, CARD_LOCATION_DECK call LookForCardIDInLocation jp nc, .no_carry ; can be a jr ld [wce06], a jr .find_discard_cards ; first check Muk ; if in deck, check cards to discard. .target_muk ld e, MUK ld a, CARD_LOCATION_DECK call LookForCardIDInLocation jp nc, .no_carry ; can be a jr ld [wce06], a ; only discard Trainer cards from hand. ; if there are less than 2 Trainer cards to discard, ; then return with no carry. ; else, store the cards to discard and the ; target card deck index, and return carry. .find_discard_cards call CreateHandCardList ld hl, wDuelTempList ld d, $00 ; first consider Trainer cards ; ignore wAITrainerCardToPlay for the discard effects. ld a, [wAITrainerCardToPlay] ld e, a call RemoveFromListDifferentCardOfGivenType jr nc, .no_carry ld [wce1a], a call RemoveFromListDifferentCardOfGivenType jr nc, .no_carry ld [wce1b], a ld a, [wce06] scf ret AIDecide_ComputerSearch_FireCharge: ; 21cbb (8:5cbb) ; pick target card in deck from highest to lowest priority. ; if not found in hand, go to corresponding branch. ld a, CHANSEY call LookForCardIDInHandList_Bank8 jr nc, .chansey ld a, TAUROS call LookForCardIDInHandList_Bank8 jr nc, .tauros ld a, JIGGLYPUFF1 call LookForCardIDInHandList_Bank8 jr nc, .jigglypuff ; fallthrough .no_carry or a ret ; for each card targeted, check if it's in deck and, ; if not, then return no carry. ; else, look for cards to discard. .chansey ld e, CHANSEY ld a, CARD_LOCATION_DECK call LookForCardIDInLocation jp nc, .no_carry ld [wce06], a jr .find_discard_cards .tauros ld e, TAUROS ld a, CARD_LOCATION_DECK call LookForCardIDInLocation jp nc, .no_carry ld [wce06], a jr .find_discard_cards .jigglypuff ld e, JIGGLYPUFF1 ld a, CARD_LOCATION_DECK call LookForCardIDInLocation jp nc, .no_carry ld [wce06], a ; only discard Trainer cards from hand. ; if there are less than 2 Trainer cards to discard, ; then return with no carry. ; else, store the cards to discard and the ; target card deck index, and return carry. .find_discard_cards call CreateHandCardList ld hl, wDuelTempList ld d, $00 ; first consider Trainer cards ; ignore wAITrainerCardToPlay for the discard effects. ld a, [wAITrainerCardToPlay] ld e, a call RemoveFromListDifferentCardOfGivenType jr nc, .no_carry ld [wce1a], a call RemoveFromListDifferentCardOfGivenType jr nc, .no_carry ld [wce1b], a ld a, [wce06] scf ret AIDecide_ComputerSearch_Anger: ; 21d1e (8:5d1e) ; for each of the following cards, ; first run a check if there's a pre-evolution in ; Play Area or in the hand. If there is, choose it as target. ; otherwise, check if the evolution card is in ; hand and if so, choose it as target instead. ld b, RATTATA ld a, RATICATE call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .find_discard_cards ld a, RATTATA ld b, RATICATE call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_discard_cards ld b, GROWLITHE ld a, ARCANINE1 call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .find_discard_cards ld a, GROWLITHE ld b, ARCANINE1 call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_discard_cards ld b, DODUO ld a, DODRIO call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .find_discard_cards ld a, DODUO ld b, DODRIO call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_discard_cards ; fallthrough .no_carry or a ret ; only discard Trainer cards from hand. ; if there are less than 2 Trainer cards to discard, ; then return with no carry. ; else, store the cards to discard and the ; target card deck index, and return carry. .find_discard_cards ld [wce06], a call CreateHandCardList ld hl, wDuelTempList ld d, $00 ; first consider Trainer cards ; ignore wAITrainerCardToPlay for the discard effects. ld a, [wAITrainerCardToPlay] ld e, a call RemoveFromListDifferentCardOfGivenType jr nc, .no_carry ld [wce1a], a call RemoveFromListDifferentCardOfGivenType jr nc, .no_carry ld [wce1b], a ld a, [wce06] scf ret AIPlay_PokemonTrader: ; 21d7a (8:5d7a) ld a, [wAITrainerCardToPlay] ldh [hTempCardIndex_ff9f], a ld a, [wAITrainerCardParameter] ldh [hTemp_ffa0], a ld a, [wce1a] ldh [hTempPlayAreaLocation_ffa1], a ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS bank1call AIMakeDecision ret AIDecide_PokemonTrader: ; 21d8f (8:5d8f) ; each deck has their own routine for picking ; what Pokemon to look for. ld a, [wOpponentDeckID] cp LEGENDARY_MOLTRES_DECK_ID jr z, AIDecide_PokemonTrader_LegendaryMoltres cp LEGENDARY_ARTICUNO_DECK_ID jr z, AIDecide_PokemonTrader_LegendaryArticuno cp LEGENDARY_DRAGONITE_DECK_ID jp z, AIDecide_PokemonTrader_LegendaryDragonite cp LEGENDARY_RONALD_DECK_ID jp z, AIDecide_PokemonTrader_LegendaryRonald cp BLISTERING_POKEMON_DECK_ID jp z, AIDecide_PokemonTrader_BlisteringPokemon cp SOUND_OF_THE_WAVES_DECK_ID jp z, AIDecide_PokemonTrader_SoundOfTheWaves cp POWER_GENERATOR_DECK_ID jp z, AIDecide_PokemonTrader_PowerGenerator cp FLOWER_GARDEN_DECK_ID jp z, AIDecide_PokemonTrader_FlowerGarden cp STRANGE_POWER_DECK_ID jp z, AIDecide_PokemonTrader_StrangePower cp FLAMETHROWER_DECK_ID jp z, AIDecide_PokemonTrader_Flamethrower or a ret AIDecide_PokemonTrader_LegendaryMoltres: ; 21dc4 (8:5dc4) ; look for Moltres2 card in deck to trade with a ; card in hand different from Moltres1. ld a, MOLTRES2 ld e, MOLTRES1 call LookForCardIDToTradeWithDifferentHandCard jr nc, .no_carry ; success ld [wce1a], a ld a, e scf ret .no_carry or a ret AIDecide_PokemonTrader_LegendaryArticuno: ; 21dd5 (8:5dd5) ; if has none of these cards in Hand or Play Area, proceed ld a, ARTICUNO1 call LookForCardIDInHandAndPlayArea jr c, .no_carry ld a, LAPRAS call LookForCardIDInHandAndPlayArea jr c, .no_carry ; if doesn't have Seel in Hand or Play Area, ; look for it in the deck. ; otherwise, look for Dewgong instead. ld a, SEEL call LookForCardIDInHandAndPlayArea jr c, .dewgong ld e, SEEL ld a, CARD_LOCATION_DECK call LookForCardIDInLocation jr nc, .dewgong ld [wce1a], a jr .check_hand .dewgong ld a, DEWGONG call LookForCardIDInHandAndPlayArea jr c, .no_carry ld e, DEWGONG ld a, CARD_LOCATION_DECK call LookForCardIDInLocation jr nc, .no_carry ld [wce1a], a ; a Seel or Dewgong was found in deck, ; check hand for card to trade for .check_hand ld a, CHANSEY call CheckIfHasCardIDInHand jr c, .set_carry ld a, DITTO call CheckIfHasCardIDInHand jr c, .set_carry ld a, ARTICUNO2 call CheckIfHasCardIDInHand jr c, .set_carry ; doesn't have any of the cards in hand .no_carry or a ret .set_carry scf ret AIDecide_PokemonTrader_LegendaryDragonite: ; 21e24 (8:5e24) ; if has less than 5 cards of energy ; and of Pokemon in hand/Play Area, ; target a Kangaskhan in deck. farcall CountOppEnergyCardsInHandAndAttached cp 5 jr c, .kangaskhan call CountPokemonCardsInHandAndInPlayArea cp 5 jr c, .kangaskhan ; total number of energy cards >= 5 ; total number of Pokemon cards >= 5 ; for each of the following cards, ; first run a check if there's a pre-evolution in ; Play Area or in the hand. If there is, choose it as target. ; otherwise, check if the evolution card is in ; hand and if so, choose it as target instead. ld b, MAGIKARP ld a, GYARADOS call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .choose_hand ld a, MAGIKARP ld b, GYARADOS call LookForCardIDInDeck_GivenCardIDInHand jr c, .choose_hand ld b, DRATINI ld a, DRAGONAIR call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .choose_hand ld b, DRAGONAIR ld a, DRAGONITE1 call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .choose_hand ld a, DRATINI ld b, DRAGONAIR call LookForCardIDInDeck_GivenCardIDInHand jr c, .choose_hand ld a, DRAGONAIR ld b, DRAGONITE1 call LookForCardIDInDeck_GivenCardIDInHand jr c, .choose_hand ld b, CHARMANDER ld a, CHARMELEON call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .choose_hand ld b, CHARMELEON ld a, CHARIZARD call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .choose_hand ld a, CHARMANDER ld b, CHARMELEON call LookForCardIDInDeck_GivenCardIDInHand jr c, .choose_hand ld a, CHARMELEON ld b, CHARIZARD call LookForCardIDInDeck_GivenCardIDInHand jr c, .choose_hand jr .no_carry .kangaskhan ld e, KANGASKHAN ld a, CARD_LOCATION_DECK call LookForCardIDInLocation jr nc, .no_carry ; card was found as target in deck, ; look for card in hand to trade with .choose_hand ld [wce1a], a ld a, DRAGONAIR call CheckIfHasCardIDInHand jr c, .set_carry ld a, CHARMELEON call CheckIfHasCardIDInHand jr c, .set_carry ld a, GYARADOS call CheckIfHasCardIDInHand jr c, .set_carry ld a, MAGIKARP call CheckIfHasCardIDInHand jr c, .set_carry ld a, CHARMANDER call CheckIfHasCardIDInHand jr c, .set_carry ld a, DRATINI call CheckIfHasCardIDInHand jr c, .set_carry ; non found .no_carry or a ret .set_carry scf ret AIDecide_PokemonTrader_LegendaryRonald: ; 21ec9 (8:5ec9) ; for each of the following cards, ; first run a check if there's a pre-evolution in ; Play Area or in the hand. If there is, choose it as target. ; otherwise, check if the evolution card is in ; hand and if so, choose it as target instead. ld b, EEVEE ld a, FLAREON1 call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .choose_hand ld b, EEVEE ld a, VAPOREON1 call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .choose_hand ld b, EEVEE ld a, JOLTEON1 call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .choose_hand ld a, EEVEE ld b, FLAREON1 call LookForCardIDInDeck_GivenCardIDInHand jr c, .choose_hand ld a, EEVEE ld b, VAPOREON1 call LookForCardIDInDeck_GivenCardIDInHand jr c, .choose_hand ld a, EEVEE ld b, JOLTEON1 call LookForCardIDInDeck_GivenCardIDInHand jr c, .choose_hand ld b, DRATINI ld a, DRAGONAIR call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .choose_hand ld b, DRAGONAIR ld a, DRAGONITE1 call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .choose_hand ld a, DRATINI ld b, DRAGONAIR call LookForCardIDInDeck_GivenCardIDInHand jr c, .choose_hand ld a, DRAGONAIR ld b, DRAGONITE1 call LookForCardIDInDeck_GivenCardIDInHand jr c, .choose_hand jr .no_carry ; card was found as target in deck, ; look for card in hand to trade with .choose_hand ld [wce1a], a ld a, ZAPDOS3 call LookForCardIDInHandList_Bank8 jr c, .set_carry ld a, ARTICUNO2 call LookForCardIDInHandList_Bank8 jr c, .set_carry ld a, MOLTRES2 call LookForCardIDInHandList_Bank8 jr c, .set_carry ; none found .no_carry or a ret .set_carry scf ret AIDecide_PokemonTrader_BlisteringPokemon: ; 21f41 (8:5f41) ; for each of the following cards, ; first run a check if there's a pre-evolution in ; Play Area or in the hand. If there is, choose it as target. ; otherwise, check if the evolution card is in ; hand and if so, choose it as target instead. ld b, RHYHORN ld a, RHYDON call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .find_duplicates ld a, RHYHORN ld b, RHYDON call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_duplicates ld b, CUBONE ld a, MAROWAK1 call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .find_duplicates ld a, CUBONE ld b, MAROWAK1 call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_duplicates ld b, PONYTA ld a, RAPIDASH call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .find_duplicates ld a, PONYTA ld b, RAPIDASH call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_duplicates jr .no_carry ; a card in deck was found to look for, ; check if there are duplicates in hand to trade with. .find_duplicates ld [wce1a], a call FindDuplicatePokemonCards jr c, .set_carry .no_carry or a ret .set_carry scf ret AIDecide_PokemonTrader_SoundOfTheWaves: ; 21f85 (8:5f85) ; for each of the following cards, ; first run a check if there's a pre-evolution in ; Play Area or in the hand. If there is, choose it as target. ; otherwise, check if the evolution card is in ; hand and if so, choose it as target instead. ld b, SEEL ld a, DEWGONG call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .choose_hand ld a, SEEL ld b, DEWGONG call LookForCardIDInDeck_GivenCardIDInHand jr c, .choose_hand ld b, KRABBY ld a, KINGLER call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .choose_hand ld a, KRABBY ld b, KINGLER call LookForCardIDInDeck_GivenCardIDInHand jr c, .choose_hand ld b, SHELLDER ld a, CLOYSTER call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .choose_hand ld a, SHELLDER ld b, CLOYSTER call LookForCardIDInDeck_GivenCardIDInHand jr c, .choose_hand ld b, HORSEA ld a, SEADRA call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .choose_hand ld a, HORSEA ld b, SEADRA call LookForCardIDInDeck_GivenCardIDInHand jr c, .choose_hand ld b, TENTACOOL ld a, TENTACRUEL call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .choose_hand ld a, TENTACOOL ld b, TENTACRUEL call LookForCardIDInDeck_GivenCardIDInHand jr c, .choose_hand jr .no_carry ; card was found as target in deck, ; look for card in hand to trade with .choose_hand ld [wce1a], a ld a, SEEL call CheckIfHasCardIDInHand jr c, .set_carry ld a, KRABBY call CheckIfHasCardIDInHand jr c, .set_carry ld a, HORSEA call CheckIfHasCardIDInHand jr c, .set_carry ld a, SHELLDER call CheckIfHasCardIDInHand jr c, .set_carry ld a, TENTACOOL call CheckIfHasCardIDInHand jr c, .set_carry ; none found .no_carry or a ret .set_carry scf ret AIDecide_PokemonTrader_PowerGenerator: ; 2200b (8:600b) ; for each of the following cards, ; first run a check if there's a pre-evolution in ; Play Area or in the hand. If there is, choose it as target. ; otherwise, check if the evolution card is in ; hand and if so, choose it as target instead. ld b, PIKACHU2 ld a, RAICHU1 call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jp c, .find_duplicates ld b, PIKACHU1 ld a, RAICHU1 call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .find_duplicates ld a, PIKACHU2 ld b, RAICHU1 call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_duplicates ld a, PIKACHU1 ld b, RAICHU1 call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_duplicates ld b, VOLTORB ld a, ELECTRODE2 call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .find_duplicates ld b, VOLTORB ld a, ELECTRODE1 call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .find_duplicates ld a, VOLTORB ld b, ELECTRODE2 call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_duplicates ld a, VOLTORB ld b, ELECTRODE1 call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_duplicates ld b, MAGNEMITE1 ld a, MAGNETON2 call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .find_duplicates ld b, MAGNEMITE2 ld a, MAGNETON2 call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .find_duplicates ld b, MAGNEMITE1 ld a, MAGNETON1 call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .find_duplicates ld b, MAGNEMITE2 ld a, MAGNETON1 call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .find_duplicates ld a, MAGNEMITE2 ld b, MAGNETON2 call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_duplicates ld a, MAGNEMITE1 ld b, MAGNETON2 call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_duplicates ld a, MAGNEMITE2 ld b, MAGNETON1 call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_duplicates ld a, MAGNEMITE1 ld b, MAGNETON1 call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_duplicates ; bug, missing jr .no_carry ; since this last check falls through regardless of result, ; register a might hold an invalid deck index, ; which might lead to hilarious results like Brandon ; trading a Pikachu with a Grass Energy from the deck. ; however, since it's deep in a tower of conditionals, ; reaching here is extremely unlikely. ; a card in deck was found to look for, ; check if there are duplicates in hand to trade with. .find_duplicates ld [wce1a], a call FindDuplicatePokemonCards jr c, .set_carry or a ret .set_carry scf ret AIDecide_PokemonTrader_FlowerGarden: ; 220a8 (8:60a8) ; for each of the following cards, ; first run a check if there's a pre-evolution in ; Play Area or in the hand. If there is, choose it as target. ; otherwise, check if the evolution card is in ; hand and if so, choose it as target instead. ld b, BULBASAUR ld a, IVYSAUR call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .find_duplicates ld b, IVYSAUR ld a, VENUSAUR2 call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .find_duplicates ld a, BULBASAUR ld b, IVYSAUR call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_duplicates ld a, IVYSAUR ld b, VENUSAUR2 call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_duplicates ld b, BELLSPROUT ld a, WEEPINBELL call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .find_duplicates ld b, WEEPINBELL ld a, VICTREEBEL call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .find_duplicates ld a, BELLSPROUT ld b, WEEPINBELL call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_duplicates ld a, WEEPINBELL ld b, VICTREEBEL call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_duplicates ld b, ODDISH ld a, GLOOM call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .find_duplicates ld b, GLOOM ld a, VILEPLUME call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .find_duplicates ld a, ODDISH ld b, GLOOM call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_duplicates ld a, GLOOM ld b, VILEPLUME call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_duplicates jr .no_carry ; a card in deck was found to look for, ; check if there are duplicates in hand to trade with. .find_duplicates ld [wce1a], a call FindDuplicatePokemonCards jr c, .found .no_carry or a ret .found scf ret AIDecide_PokemonTrader_StrangePower: ; 22122 (8:6122) ; looks for a Pokemon in hand to trade with Mr Mime in deck. ; inputting Mr Mime in register e for the function is redundant ; since it already checks whether a Mr Mime exists in the hand. ld a, MR_MIME ld e, MR_MIME call LookForCardIDToTradeWithDifferentHandCard jr nc, .no_carry ; found ld [wce1a], a ld a, e scf ret .no_carry or a ret AIDecide_PokemonTrader_Flamethrower: ; 22133 (8:6133) ; for each of the following cards, ; first run a check if there's a pre-evolution in ; Play Area or in the hand. If there is, choose it as target. ; otherwise, check if the evolution card is in ; hand and if so, choose it as target instead. ld b, CHARMANDER ld a, CHARMELEON call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .find_duplicates ld b, CHARMELEON ld a, CHARIZARD call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .find_duplicates ld a, CHARMANDER ld b, CHARMELEON call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_duplicates ld a, CHARMELEON ld b, CHARIZARD call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_duplicates ld b, VULPIX ld a, NINETALES1 call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .find_duplicates ld a, VULPIX ld b, NINETALES1 call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_duplicates ld b, GROWLITHE ld a, ARCANINE2 call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .find_duplicates ld a, GROWLITHE ld b, ARCANINE2 call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_duplicates ld b, EEVEE ld a, FLAREON2 call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea jr c, .find_duplicates ld a, EEVEE ld b, FLAREON2 call LookForCardIDInDeck_GivenCardIDInHand jr c, .find_duplicates jr .no_carry ; a card in deck was found to look for, ; check if there are duplicates in hand to trade with. .find_duplicates ld [wce1a], a call FindDuplicatePokemonCards jr c, .set_carry .no_carry or a ret .set_carry scf ret