; this function handles attacks with the SPECIAL_AI_HANDLING set, ; and makes specific checks in each of these attacks ; to either return a positive score (value above $80) ; or a negative score (value below $80). ; input: ; hTempPlayAreaLocation_ff9d = location of card with attack. HandleSpecialAIAttacks: ldh a, [hTempPlayAreaLocation_ff9d] add DUELVARS_ARENA_CARD call GetTurnDuelistVariable call GetCardIDFromDeckIndex ld a, e cp NIDORANF jr z, .NidoranFCallForFamily cp ODDISH jr z, .CallForFamily cp BELLSPROUT jr z, .CallForFamily cp EXEGGUTOR jp z, .Teleport cp SCYTHER jp z, .SwordsDanceAndFocusEnergy cp KRABBY jr z, .CallForFamily cp VAPOREON1 jp z, .SwordsDanceAndFocusEnergy cp ELECTRODE2 jp z, .ChainLightning cp MAROWAK1 jr z, .CallForFriend cp MEW3 jp z, .DevolutionBeam cp JIGGLYPUFF2 jp z, .FriendshipSong cp PORYGON jp z, .Conversion cp MEWTWO3 jp z, .EnergyAbsorption cp MEWTWO2 jp z, .EnergyAbsorption cp NINETALES2 jp z, .MixUp cp ZAPDOS3 jp z, .BigThunder cp KANGASKHAN jp z, .Fetch cp DUGTRIO jp z, .Earthquake cp ELECTRODE1 jp z, .EnergySpike cp GOLDUCK jp z, .HyperBeam cp DRAGONAIR jp z, .HyperBeam ; return zero score. .zero_score xor a ret ; if any of card ID in a is found in deck, ; return a score of $80 + slots available in bench. .CallForFamily: ld a, CARD_LOCATION_DECK call CheckIfAnyCardIDinLocation jr nc, .zero_score ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetTurnDuelistVariable cp MAX_BENCH_POKEMON jr nc, .zero_score ld b, a ld a, MAX_BENCH_POKEMON sub b add $80 ret ; if any of NidoranM or NidoranF is found in deck, ; return a score of $80 + slots available in bench. .NidoranFCallForFamily: ld e, NIDORANM ld a, CARD_LOCATION_DECK call CheckIfAnyCardIDinLocation jr c, .found_nidoran ld e, NIDORANF ld a, CARD_LOCATION_DECK call CheckIfAnyCardIDinLocation jr nc, .zero_score .found_nidoran ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetTurnDuelistVariable cp MAX_PLAY_AREA_POKEMON jr nc, .zero_score ld b, a ld a, MAX_PLAY_AREA_POKEMON sub b add $80 ret ; checks for certain card IDs of Fighting color in deck. ; if any of them are found, return a score of ; $80 + slots available in bench. .CallForFriend: ld e, GEODUDE ld a, CARD_LOCATION_DECK call CheckIfAnyCardIDinLocation jr c, .found_fighting_card ld e, ONIX ld a, CARD_LOCATION_DECK call CheckIfAnyCardIDinLocation jr c, .found_fighting_card ld e, CUBONE ld a, CARD_LOCATION_DECK call CheckIfAnyCardIDinLocation jr c, .found_fighting_card ld e, RHYHORN ld a, CARD_LOCATION_DECK call CheckIfAnyCardIDinLocation jr c, .found_fighting_card jr .zero_score .found_fighting_card ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetTurnDuelistVariable cp MAX_BENCH_POKEMON jr nc, .zero_score ld b, a ld a, MAX_BENCH_POKEMON sub b add $80 ret ; if any basic cards are found in deck, ; return a score of $80 + slots available in bench. .FriendshipSong: call CheckIfAnyBasicPokemonInDeck jr nc, .zero_score ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetTurnDuelistVariable cp MAX_PLAY_AREA_POKEMON jr nc, .zero_score ld b, a ld a, MAX_PLAY_AREA_POKEMON sub b add $80 ret ; if AI decides to retreat, return a score of $80 + 10. .Teleport: call AIDecideWhetherToRetreat jp nc, .zero_score ld a, $8a ret ; tests for the following conditions: ; - player is under No Damage substatus; ; - second attack is unusable; ; - second attack deals no damage; ; if any are true, returns score of $80 + 5. .SwordsDanceAndFocusEnergy: ld a, [wAICannotDamage] or a jr nz, .swords_dance_focus_energy_success ld a, SECOND_ATTACK ld [wSelectedAttack], a call CheckIfSelectedAttackIsUnusable jr c, .swords_dance_focus_energy_success ld a, SECOND_ATTACK call EstimateDamage_VersusDefendingCard ld a, [wDamage] or a jp nz, .zero_score .swords_dance_focus_energy_success ld a, $85 ret ; checks player's active card color, then ; loops through bench looking for a Pokémon ; with that same color. ; if none are found, returns score of $80 + 2. .ChainLightning: call SwapTurn call GetArenaCardColor call SwapTurn ld b, a ld a, DUELVARS_BENCH call GetTurnDuelistVariable .loop_chain_lightning_bench ld a, [hli] cp $ff jr z, .chain_lightning_success push bc call GetCardIDFromDeckIndex call GetCardType pop bc cp b jr nz, .loop_chain_lightning_bench jp .zero_score .chain_lightning_success ld a, $82 ret .DevolutionBeam: call LookForCardThatIsKnockedOutOnDevolution jp nc, .zero_score ld a, $85 ret ; first checks if card is confused, and if so return 0. ; then checks number of Pokémon in bench that are viable to use: ; - if that number is < 2 and this attack is Conversion 1 OR ; - if that number is >= 2 and this attack is Conversion 2 ; then return score of $80 + 2. ; otherwise return score of $80 + 1. .Conversion: ld a, DUELVARS_ARENA_CARD_STATUS call GetTurnDuelistVariable and CNF_SLP_PRZ cp CONFUSED jp z, .zero_score ld a, [wSelectedAttack] or a jr nz, .conversion_2 ; conversion 1 call CountNumberOfSetUpBenchPokemon cp 2 jr c, .low_conversion_score ld a, $82 ret .conversion_2 call CountNumberOfSetUpBenchPokemon cp 2 jr nc, .low_conversion_score ld a, $82 ret .low_conversion_score ld a, $81 ret ; if any Psychic Energy is found in the Discard Pile, ; return a score of $80 + 2. .EnergyAbsorption: ld e, PSYCHIC_ENERGY ld a, CARD_LOCATION_DISCARD_PILE call CheckIfAnyCardIDinLocation jp nc, .zero_score ld a, $82 ret ; if player has cards in hand, AI calls Random: ; - 1/3 chance to encourage attack regardless; ; - 1/3 chance to dismiss attack regardless; ; - 1/3 change to make some checks to player's hand. ; AI tallies number of basic cards in hand, and if this ; number is >= 2, encourage attack. ; otherwise, if it finds an evolution card in hand that ; can evolve a card in player's deck, encourage. ; if encouraged, returns a score of $80 + 3. .MixUp: ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND call GetNonTurnDuelistVariable or a ret z ld a, 3 call Random or a jr z, .encourage_mix_up dec a ret z call SwapTurn call CreateHandCardList call SwapTurn or a ret z ; return if no hand cards (again) ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetNonTurnDuelistVariable cp 3 jr nc, .mix_up_check_play_area ld hl, wDuelTempList ld b, 0 .loop_mix_up_hand ld a, [hli] cp $ff jr z, .tally_basic_cards push bc call SwapTurn call LoadCardDataToBuffer2_FromDeckIndex call SwapTurn pop bc ld a, [wLoadedCard2Type] cp TYPE_ENERGY jr nc, .loop_mix_up_hand ld a, [wLoadedCard2Stage] or a jr nz, .loop_mix_up_hand ; is a basic Pokémon card inc b jr .loop_mix_up_hand .tally_basic_cards ld a, b cp 2 jr nc, .encourage_mix_up ; less than 2 basic cards in hand .mix_up_check_play_area ld a, DUELVARS_ARENA_CARD call GetNonTurnDuelistVariable .loop_mix_up_play_area ld a, [hli] cp $ff jp z, .zero_score push hl call SwapTurn call CheckForEvolutionInList call SwapTurn pop hl jr nc, .loop_mix_up_play_area .encourage_mix_up ld a, $83 ret ; return score of $80 + 3. .BigThunder: ld a, $83 ret ; dismiss attack if cards in deck <= 20. ; otherwise return a score of $80 + 0. .Fetch: ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK call GetTurnDuelistVariable cp 41 jp nc, .zero_score ld a, $80 ret ; dismiss attack if number of own benched cards which would ; be KOd is greater than or equal to the number ; of prize cards left for player. .Earthquake: ld a, DUELVARS_BENCH call GetTurnDuelistVariable lb de, 0, 0 .loop_earthquake inc e ld a, [hli] cp $ff jr z, .count_prizes ld a, e add DUELVARS_ARENA_CARD_HP call GetTurnDuelistVariable cp 20 jr nc, .loop_earthquake inc d jr .loop_earthquake .count_prizes push de call CountPrizes pop de cp d jp c, .zero_score jp z, .zero_score ld a, $80 ret ; if there's any lightning energy cards in deck, ; return a score of $80 + 3. .EnergySpike: ld a, CARD_LOCATION_DECK ld e, LIGHTNING_ENERGY call CheckIfAnyCardIDinLocation jp nc, .zero_score call AIProcessButDontPlayEnergy_SkipEvolution jp nc, .zero_score ld a, $83 ret ; only incentivize attack if player's active card, ; has any energy cards attached, and if so, ; return a score of $80 + 3. .HyperBeam: call SwapTurn ld e, PLAY_AREA_ARENA call CountNumberOfEnergyCardsAttached call SwapTurn or a jr z, .hyper_beam_neutral ld a, $83 ret .hyper_beam_neutral ld a, $80 ret ; called when second attack is determined by AI to have ; more AI score than the first attack, so that it checks ; whether the first attack is a better alternative. CheckWhetherToSwitchToFirstAttack: ; this checks whether the first attack is also viable ; (has more than minimum score to be used) ld a, [wFirstAttackAIScore] cp $50 jr c, .keep_second_attack ; first attack has more than minimum score to be used. ; check if second attack can KO. ; in case it can't, the AI keeps it as the attack to be used. ; (possibly due to the assumption that if the ; second attack cannot KO, the first attack can't KO as well.) xor a ldh [hTempPlayAreaLocation_ff9d], a call EstimateDamage_VersusDefendingCard ld a, DUELVARS_ARENA_CARD_HP call GetNonTurnDuelistVariable ld hl, wDamage sub [hl] jr z, .check_flag jr nc, .keep_second_attack ; second attack can ko, check its flag. ; in case its effect is to heal user or nullify/weaken damage ; next turn, keep second attack as the option. ; otherwise switch to the first attack. .check_flag ld a, DUELVARS_ARENA_CARD call GetTurnDuelistVariable ld d, a ld e, SECOND_ATTACK call CopyAttackDataAndDamage_FromDeckIndex ld a, ATTACK_FLAG2_ADDRESS | HEAL_USER_F call CheckLoadedAttackFlag jr c, .keep_second_attack ld a, ATTACK_FLAG2_ADDRESS | NULLIFY_OR_WEAKEN_ATTACK_F call CheckLoadedAttackFlag jr c, .keep_second_attack ; switch to first attack xor a ld [wSelectedAttack], a ret .keep_second_attack ld a, $01 ld [wSelectedAttack], a ret ; returns carry if there are ; any basic Pokémon cards in deck. CheckIfAnyBasicPokemonInDeck: ld e, 0 .loop ld a, DUELVARS_CARD_LOCATIONS add e call GetTurnDuelistVariable cp CARD_LOCATION_DECK jr nz, .next push de ld a, e call LoadCardDataToBuffer2_FromDeckIndex pop de ld a, [wLoadedCard2Type] cp TYPE_ENERGY jr nc, .next ld a, [wLoadedCard2Stage] or a jr z, .set_carry .next inc e ld a, DECK_SIZE cp e jr nz, .loop or a ret .set_carry scf ret