diff options
author | ElectroDeoxys <ElectroDeoxys@gmail.com> | 2021-09-29 09:02:02 +0100 |
---|---|---|
committer | ElectroDeoxys <ElectroDeoxys@gmail.com> | 2021-09-29 09:02:02 +0100 |
commit | bae47106f18266d2c3b97b6d954b91d9b16c0ccf (patch) | |
tree | 4d1a24de37ddb1b22ff22991a275fca351a3651d /src/engine/ai | |
parent | b0487fa979d0b5f3241e9e0659dd4b29a7e38f18 (diff) |
Reorganise some folders in engine/
Diffstat (limited to 'src/engine/ai')
33 files changed, 0 insertions, 18079 deletions
diff --git a/src/engine/ai/attacks.asm b/src/engine/ai/attacks.asm deleted file mode 100644 index 69ae2e1..0000000 --- a/src/engine/ai/attacks.asm +++ /dev/null @@ -1,721 +0,0 @@ -; have AI choose an attack to use, but do not execute it. -; return carry if an attack is chosen. -AIProcessButDontUseAttack: ; 169ca (5:69ca) - ld a, $01 - ld [wAIExecuteProcessedAttack], a - -; backup wPlayAreaAIScore in wTempPlayAreaAIScore. - ld de, wTempPlayAreaAIScore - ld hl, wPlayAreaAIScore - ld b, MAX_PLAY_AREA_POKEMON -.loop - ld a, [hli] - ld [de], a - inc de - dec b - jr nz, .loop - -; copies wAIScore to wTempAIScore - ld a, [wAIScore] - ld [de], a - jr AIProcessAttacks - -; copies wTempPlayAreaAIScore to wPlayAreaAIScore -; and loads wAIScore with value in wTempAIScore. -; identical to RetrievePlayAreaAIScoreFromBackup1. -RetrievePlayAreaAIScoreFromBackup2: ; 169e3 (5:69e3) - push af - ld de, wPlayAreaAIScore - ld hl, wTempPlayAreaAIScore - ld b, MAX_PLAY_AREA_POKEMON -.loop - ld a, [hli] - ld [de], a - inc de - dec b - jr nz, .loop - - ld a, [hl] - ld [wAIScore], a - pop af - ret - -; have AI choose and execute an attack. -; return carry if an attack was chosen and attempted. -AIProcessAndTryToUseAttack: ; 169f8 (5:69f8) - xor a - ld [wAIExecuteProcessedAttack], a - ; fallthrough - -; checks which of the Active card's attacks for AI to use. -; If any of the attacks has enough AI score to be used, -; AI will use it if wAIExecuteProcessedAttack is 0. -; in either case, return carry if an attack is chosen to be used. -AIProcessAttacks: ; 169fc (5:69fc) -; if AI used Pluspower, load its attack index - ld a, [wPreviousAIFlags] - and AI_FLAG_USED_PLUSPOWER - jr z, .no_pluspower - ld a, [wAIPluspowerAttack] - ld [wSelectedAttack], a - jr .attack_chosen - -.no_pluspower -; if Player is running Mewtwo1 mill deck, -; skip attack if Barrier counter is 0. - ld a, [wAIBarrierFlagCounter] - cp AI_MEWTWO_MILL + 0 - jp z, .dont_attack - -; determine AI score of both attacks. - xor a ; FIRST_ATTACK_OR_PKMN_POWER - call GetAIScoreOfAttack - ld a, [wAIScore] - ld [wFirstAttackAIScore], a - ld a, SECOND_ATTACK - call GetAIScoreOfAttack - -; compare both attack scores - ld c, SECOND_ATTACK - ld a, [wFirstAttackAIScore] - ld b, a - ld a, [wAIScore] - cp b - jr nc, .check_score - ; first attack has higher score - dec c - ld a, b - -; c holds the attack index chosen by AI, -; and a holds its AI score. -; first check if chosen attack has at least minimum score. -; then check if first attack is better than second attack -; in case the second one was chosen. -.check_score - cp $50 ; minimum score to use attack - jr c, .dont_attack - ; enough score, proceed - - ld a, c - ld [wSelectedAttack], a - or a - jr z, .attack_chosen - call CheckWhetherToSwitchToFirstAttack - -.attack_chosen -; check whether to execute the attack chosen - ld a, [wAIExecuteProcessedAttack] - or a - jr z, .execute - -; set carry and reset Play Area AI score -; to the previous values. - scf - jp RetrievePlayAreaAIScoreFromBackup2 - -.execute - ld a, AI_TRAINER_CARD_PHASE_14 - call AIProcessHandTrainerCards - -; load this attack's damage output against -; the current Defending Pokemon. - xor a ; PLAY_AREA_ARENA - ldh [hTempPlayAreaLocation_ff9d], a - ld a, [wSelectedAttack] - call EstimateDamage_VersusDefendingCard - ld a, [wDamage] - - or a - jr z, .check_damage_bench - ; if damage is not 0, fallthrough - -.can_damage - xor a - ld [wcdb4], a - jr .use_attack - -.check_damage_bench -; check if it can otherwise damage player's bench - ld a, ATTACK_FLAG1_ADDRESS | DAMAGE_TO_OPPONENT_BENCH_F - call CheckLoadedAttackFlag - jr c, .can_damage - -; cannot damage either Defending Pokemon or Bench - ld hl, wcdb4 - inc [hl] - -; return carry if attack is chosen -; and AI tries to use it. -.use_attack - ld a, TRUE - ld [wAITriedAttack], a - call AITryUseAttack - scf - ret - -.dont_attack - ld a, [wAIExecuteProcessedAttack] - or a - jr z, .failed_to_use - -; reset Play Area AI score -; to the previous values. - jp RetrievePlayAreaAIScoreFromBackup2 - -; return no carry if no viable attack. -.failed_to_use - ld hl, wcdb4 - inc [hl] - or a - ret - -; determines the AI score of attack index in a -; of card in Play Area location hTempPlayAreaLocation_ff9d. -GetAIScoreOfAttack: ; 16a86 (5:6a86) -; initialize AI score. - ld [wSelectedAttack], a - ld a, $50 - ld [wAIScore], a - - xor a - ldh [hTempPlayAreaLocation_ff9d], a - call CheckIfSelectedAttackIsUnusable - jr nc, .usable - -; return zero AI score. -.unusable - xor a - ld [wAIScore], a - jp .done - -; load arena card IDs -.usable - xor a - ld [wAICannotDamage], a - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call GetCardIDFromDeckIndex - ld a, e - ld [wTempTurnDuelistCardID], a - call SwapTurn - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call GetCardIDFromDeckIndex - ld a, e - ld [wTempNonTurnDuelistCardID], a - -; handle the case where the player has No Damage substatus. -; in the case the player does, check if this attack -; has a residual effect, or if it can damage the opposing bench. -; If none of those are true, render the attack unusable. -; also if it's a PKMN power, consider it unusable as well. - bank1call HandleNoDamageOrEffectSubstatus - call SwapTurn - jr nc, .check_if_can_ko - - ; player is under No Damage substatus - ld a, $01 - ld [wAICannotDamage], a - ld a, [wSelectedAttack] - call EstimateDamage_VersusDefendingCard - ld a, [wLoadedAttackCategory] - cp POKEMON_POWER - jr z, .unusable - and RESIDUAL - jr nz, .check_if_can_ko - ld a, ATTACK_FLAG1_ADDRESS | DAMAGE_TO_OPPONENT_BENCH_F - call CheckLoadedAttackFlag - jr nc, .unusable - -; calculate damage to player to check if attack can KO. -; encourage attack if it's able to KO. -.check_if_can_ko - ld a, [wSelectedAttack] - call EstimateDamage_VersusDefendingCard - ld a, DUELVARS_ARENA_CARD_HP - call GetNonTurnDuelistVariable - ld hl, wDamage - sub [hl] - jr c, .can_ko - jr z, .can_ko - jr .check_damage -.can_ko - ld a, 20 - call AddToAIScore - -; raise AI score by the number of damage counters that this attack deals. -; if no damage is dealt, subtract AI score. in case wDamage is zero -; but wMaxDamage is not, then encourage attack afterwards. -; otherwise, if wMaxDamage is also zero, check for damage against -; player's bench, and encourage attack in case there is. -.check_damage - xor a - ld [wAIAttackIsNonDamaging], a - ld a, [wDamage] - ld [wTempAI], a - or a - jr z, .no_damage - call CalculateByteTensDigit - call AddToAIScore - jr .check_recoil -.no_damage - ld a, $01 - ld [wAIAttackIsNonDamaging], a - call SubFromAIScore - ld a, [wAIMaxDamage] - or a - jr z, .no_max_damage - ld a, 2 - call AddToAIScore - xor a - ld [wAIAttackIsNonDamaging], a -.no_max_damage - ld a, ATTACK_FLAG1_ADDRESS | DAMAGE_TO_OPPONENT_BENCH_F - call CheckLoadedAttackFlag - jr nc, .check_recoil - ld a, 2 - call AddToAIScore - -; handle recoil attacks (low and high recoil). -.check_recoil - ld a, ATTACK_FLAG1_ADDRESS | LOW_RECOIL_F - call CheckLoadedAttackFlag - jr c, .is_recoil - ld a, ATTACK_FLAG1_ADDRESS | HIGH_RECOIL_F - call CheckLoadedAttackFlag - jp nc, .check_defending_can_ko -.is_recoil - ; sub from AI score number of damage counters - ; that attack deals to itself. - ld a, [wLoadedAttackEffectParam] - or a - jp z, .check_defending_can_ko - ld [wDamage], a - call ApplyDamageModifiers_DamageToSelf - ld a, e - call CalculateByteTensDigit - call SubFromAIScore - - push de - ld a, ATTACK_FLAG1_ADDRESS | HIGH_RECOIL_F - call CheckLoadedAttackFlag - pop de - jr c, .high_recoil - - ; if LOW_RECOIL KOs self, decrease AI score - ld a, DUELVARS_ARENA_CARD_HP - call GetTurnDuelistVariable - cp e - jr c, .kos_self - jp nz, .check_defending_can_ko -.kos_self - ld a, 10 - call SubFromAIScore - -.high_recoil - ; dismiss this attack if no benched Pokémon - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - cp 2 - jr c, .dismiss_high_recoil_atk - ; has benched Pokémon - -; here the AI handles high recoil attacks differently -; depending on what deck it's playing. - ld a, [wOpponentDeckID] - cp ROCK_CRUSHER_DECK_ID - jr z, .rock_crusher_deck - cp ZAPPING_SELFDESTRUCT_DECK_ID - jr z, .zapping_selfdestruct_deck - cp BOOM_BOOM_SELFDESTRUCT_DECK_ID - jr z, .encourage_high_recoil_atk - ; Boom Boom Selfdestruct deck always encourages - cp POWER_GENERATOR_DECK_ID - jr nz, .high_recoil_generic_checks - ; Power Generator deck always dismisses - -.dismiss_high_recoil_atk - xor a - ld [wAIScore], a - jp .done - -.encourage_high_recoil_atk - ld a, 20 - call AddToAIScore - jp .done - -; Zapping Selfdestruct deck only uses this attack -; if number of cards in deck >= 30 and -; HP of active card is < half max HP. -.zapping_selfdestruct_deck - ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK - call GetTurnDuelistVariable - cp 31 - jr nc, .high_recoil_generic_checks - ld e, PLAY_AREA_ARENA - call GetCardDamageAndMaxHP - sla a - cp c - jr c, .high_recoil_generic_checks - ld b, 0 - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call GetCardIDFromDeckIndex - ld a, e - cp MAGNEMITE1 - jr z, .magnemite1 - ld b, 10 ; bench damage -.magnemite1 - ld a, 10 - add b - ld b, a ; 20 bench damage if not Magnemite1 - -; if this attack causes player to win the duel by -; knocking out own Pokémon, dismiss attack. - ld a, 1 ; count active Pokémon as KO'd - call .check_if_kos_bench - jr c, .dismiss_high_recoil_atk - jr .encourage_high_recoil_atk - -; Rock Crusher Deck only uses this attack if -; prize count is below 4 and attack wins (or potentially draws) the duel, -; (i.e. at least gets KOs equal to prize cards left). -.rock_crusher_deck - call CountPrizes - cp 4 - jr nc, .dismiss_high_recoil_atk - ; prize count < 4 - ld b, 20 ; damage dealt to bench - call SwapTurn - xor a - call .check_if_kos_bench - call SwapTurn - jr c, .encourage_high_recoil_atk - -; generic checks for all other deck IDs. -; encourage attack if it wins (or potentially draws) the duel, -; (i.e. at least gets KOs equal to prize cards left). -; dismiss it if it causes the player to win. -.high_recoil_generic_checks - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call GetCardIDFromDeckIndex - ld a, e - cp CHANSEY - jr z, .chansey - cp MAGNEMITE1 - jr z, .magnemite1_or_weezing - cp WEEZING - jr z, .magnemite1_or_weezing - ld b, 20 ; bench damage - jr .check_bench_kos -.magnemite1_or_weezing - ld b, 10 ; bench damage - jr .check_bench_kos -.chansey - ld b, 0 ; no bench damage - -.check_bench_kos - push bc - call SwapTurn - xor a - call .check_if_kos_bench - call SwapTurn - pop bc - jr c, .wins_the_duel - push de - ld a, 1 - call .check_if_kos_bench - pop bc - jr nc, .count_own_ko_bench - -; attack causes player to draw all prize cards - xor a - ld [wAIScore], a - jp .done - -; attack causes CPU to draw all prize cards -.wins_the_duel - ld a, 20 - call AddToAIScore - jp .done - -; subtract from AI score number of own benched Pokémon KO'd -.count_own_ko_bench - push bc - ld a, d - or a - jr z, .count_player_ko_bench - dec a - call SubFromAIScore - -; add to AI score number of player benched Pokémon KO'd -.count_player_ko_bench - pop bc - ld a, b - call AddToAIScore - jr .check_defending_can_ko - -; local function that gets called to determine damage to -; benched Pokémon caused by a HIGH_RECOIL attack. -; return carry if using attack causes number of benched Pokémon KOs -; equal to or larger than remaining prize cards. -; this function is independent on duelist turn, so whatever -; turn it is when this is called, it's that duelist's -; bench/prize cards that get checked. -; input: -; a = initial number of KO's beside benched Pokémon, -; so that if the active Pokémon is KO'd by the attack, -; this counts towards the prize cards collected -; b = damage dealt to bench Pokémon -.check_if_kos_bench - ld d, a - ld a, DUELVARS_BENCH - call GetTurnDuelistVariable - ld e, PLAY_AREA_ARENA -.loop - inc e - ld a, [hli] - cp $ff - jr z, .exit_loop - ld a, e - add DUELVARS_ARENA_CARD_HP - push hl - call GetTurnDuelistVariable - pop hl - cp b - jr z, .increase_count - jr nc, .loop -.increase_count - ; increase d if damage dealt KOs - inc d - jr .loop -.exit_loop - push de - call SwapTurn - call CountPrizes - call SwapTurn - pop de - cp d - jp c, .set_carry - jp z, .set_carry - or a - ret -.set_carry - scf - ret - -; if defending card can KO, encourage attack -; unless attack is non-damaging. -.check_defending_can_ko - ld a, [wSelectedAttack] - push af - call CheckIfDefendingPokemonCanKnockOut - pop bc - ld a, b - ld [wSelectedAttack], a - jr nc, .check_discard - ld a, 5 - call AddToAIScore - ld a, [wAIAttackIsNonDamaging] - or a - jr z, .check_discard - ld a, 5 - call SubFromAIScore - -; subtract from AI score if this attack requires -; discarding any energy cards. -.check_discard - ld a, [wSelectedAttack] - ld e, a - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - ld d, a - call CopyAttackDataAndDamage_FromDeckIndex - ld a, ATTACK_FLAG2_ADDRESS | DISCARD_ENERGY_F - call CheckLoadedAttackFlag - jr nc, .asm_16ca6 - ld a, 1 - call SubFromAIScore - ld a, [wLoadedAttackEffectParam] - call SubFromAIScore - -.asm_16ca6 - ld a, ATTACK_FLAG2_ADDRESS | FLAG_2_BIT_6_F - call CheckLoadedAttackFlag - jr nc, .check_nullify_flag - ld a, [wLoadedAttackEffectParam] - call AddToAIScore - -; encourage attack if it has a nullify or weaken attack effect. -.check_nullify_flag - ld a, ATTACK_FLAG2_ADDRESS | NULLIFY_OR_WEAKEN_ATTACK_F - call CheckLoadedAttackFlag - jr nc, .check_draw_flag - ld a, 1 - call AddToAIScore - -; encourage attack if it has an effect to draw a card. -.check_draw_flag - ld a, ATTACK_FLAG1_ADDRESS | DRAW_CARD_F - call CheckLoadedAttackFlag - jr nc, .check_heal_flag - ld a, 1 - call AddToAIScore - -.check_heal_flag - ld a, ATTACK_FLAG2_ADDRESS | HEAL_USER_F - call CheckLoadedAttackFlag - jr nc, .check_status_effect - ld a, [wLoadedAttackEffectParam] - cp 1 - jr z, .tally_heal_score - ld a, [wTempAI] - call CalculateByteTensDigit - ld b, a - ld a, [wLoadedAttackEffectParam] - cp 3 - jr z, .asm_16cec - srl b - jr nc, .asm_16cec - inc b -.asm_16cec - ld a, DUELVARS_ARENA_CARD_HP - call GetTurnDuelistVariable - call CalculateByteTensDigit - cp b - jr c, .tally_heal_score - ld a, b -.tally_heal_score - push af - ld e, PLAY_AREA_ARENA - call GetCardDamageAndMaxHP - call CalculateByteTensDigit - pop bc - cp b ; wLoadedAttackEffectParam - jr c, .add_heal_score - ld a, b -.add_heal_score - call AddToAIScore - -.check_status_effect - ld a, DUELVARS_ARENA_CARD - call GetNonTurnDuelistVariable - call SwapTurn - call GetCardIDFromDeckIndex - call SwapTurn - ld a, e - ; skip if player has Snorlax - cp SNORLAX - jp z, .handle_special_atks - - ld a, DUELVARS_ARENA_CARD_STATUS - call GetNonTurnDuelistVariable - ld [wTempAI], a - -; encourage a poison inflicting attack if opposing Pokémon -; isn't (doubly) poisoned already. -; if opposing Pokémon is only poisoned and not double poisoned, -; and this attack has FLAG_2_BIT_6 set, discourage it -; (possibly to make Nidoking's Toxic attack less likely to be chosen -; if the other Pokémon is poisoned.) - ld a, ATTACK_FLAG1_ADDRESS | INFLICT_POISON_F - call CheckLoadedAttackFlag - jr nc, .check_sleep - ld a, [wTempAI] - and DOUBLE_POISONED - jr z, .add_poison_score - and $40 ; only double poisoned? - jr z, .check_sleep - ld a, ATTACK_FLAG2_ADDRESS | FLAG_2_BIT_6_F - call CheckLoadedAttackFlag - jr nc, .check_sleep - ld a, 2 - call SubFromAIScore - jr .check_sleep -.add_poison_score - ld a, 2 - call AddToAIScore - -; encourage sleep-inducing attack if other Pokémon isn't asleep. -.check_sleep - ld a, ATTACK_FLAG1_ADDRESS | INFLICT_SLEEP_F - call CheckLoadedAttackFlag - jr nc, .check_paralysis - ld a, [wTempAI] - and CNF_SLP_PRZ - cp ASLEEP - jr z, .check_paralysis - ld a, 1 - call AddToAIScore - -; encourage paralysis-inducing attack if other Pokémon isn't asleep. -; otherwise, if other Pokémon is asleep, discourage attack. -.check_paralysis - ld a, ATTACK_FLAG1_ADDRESS | INFLICT_PARALYSIS_F - call CheckLoadedAttackFlag - jr nc, .check_confusion - ld a, [wTempAI] - and CNF_SLP_PRZ - cp ASLEEP - jr z, .sub_prz_score - ld a, 1 - call AddToAIScore - jr .check_confusion -.sub_prz_score - ld a, 1 - call SubFromAIScore - -; encourage confuse-inducing attack if other Pokémon isn't asleep -; or confused already. -; otherwise, if other Pokémon is asleep or confused, -; discourage attack instead. -.check_confusion - ld a, ATTACK_FLAG1_ADDRESS | INFLICT_CONFUSION_F - call CheckLoadedAttackFlag - jr nc, .check_if_confused - ld a, [wTempAI] - and CNF_SLP_PRZ - cp ASLEEP - jr z, .sub_cnf_score - ld a, [wTempAI] - and CNF_SLP_PRZ - cp CONFUSED - jr z, .check_if_confused - ld a, 1 - call AddToAIScore - jr .check_if_confused -.sub_cnf_score - ld a, 1 - call SubFromAIScore - -; if this Pokémon is confused, subtract from score. -.check_if_confused - ld a, DUELVARS_ARENA_CARD_STATUS - call GetTurnDuelistVariable - and CNF_SLP_PRZ - cp CONFUSED - jr nz, .handle_special_atks - ld a, 1 - call SubFromAIScore - -; SPECIAL_AI_HANDLING marks attacks that the AI handles individually. -; each attack has its own checks and modifies AI score accordingly. -.handle_special_atks - ld a, ATTACK_FLAG3_ADDRESS | SPECIAL_AI_HANDLING_F - call CheckLoadedAttackFlag - jr nc, .done - call HandleSpecialAIAttacks - cp $80 - jr c, .negative_score - sub $80 - call AddToAIScore - jr .done -.negative_score - ld b, a - ld a, $80 - sub b - call SubFromAIScore - -.done - ret diff --git a/src/engine/ai/boss_deck_set_up.asm b/src/engine/ai/boss_deck_set_up.asm deleted file mode 100644 index ebcd2ea..0000000 --- a/src/engine/ai/boss_deck_set_up.asm +++ /dev/null @@ -1,167 +0,0 @@ -; sets up the initial hand of boss deck. -; always draws at least 2 Basic Pokemon cards and 2 Energy cards. -; also sets up so that the next cards to be drawn have -; some minimum number of Basic Pokemon and Energy cards. -SetUpBossStartingHandAndDeck: ; 172af (5:72af) -; shuffle all hand cards in deck - ld a, DUELVARS_HAND - call GetTurnDuelistVariable - ld b, STARTING_HAND_SIZE -.loop_hand - ld a, [hl] - call RemoveCardFromHand - call ReturnCardToDeck - dec b - jr nz, .loop_hand - jr .count_energy_basic - -.shuffle_deck - call ShuffleDeck - -; count number of Energy and basic Pokemon cards -; in the first STARTING_HAND_SIZE in deck. -.count_energy_basic - xor a - ld [wce06], a - ld [wce08], a - - ld a, DUELVARS_DECK_CARDS - call GetTurnDuelistVariable - ld b, STARTING_HAND_SIZE -.loop_deck_1 - ld a, [hli] - push bc - call LoadCardDataToBuffer1_FromDeckIndex - pop bc - ld a, [wLoadedCard1Type] - cp TYPE_ENERGY - jr c, .pokemon_card_1 - cp TYPE_TRAINER - jr z, .next_card_deck_1 - -; energy card - ld a, [wce08] - inc a - ld [wce08], a - jr .next_card_deck_1 - -.pokemon_card_1 - ld a, [wLoadedCard1Stage] - or a - jr nz, .next_card_deck_1 ; not basic - ld a, [wce06] - inc a - ld [wce06], a - -.next_card_deck_1 - dec b - jr nz, .loop_deck_1 - -; tally the number of Energy and basic Pokemon cards -; and if any of them is smaller than 2, re-shuffle deck. - ld a, [wce06] - cp 2 - jr c, .shuffle_deck - ld a, [wce08] - cp 2 - jr c, .shuffle_deck - -; now check the following 6 cards (prize cards). -; re-shuffle deck if any of these cards is listed in wAICardListAvoidPrize. - ld b, 6 -.check_card_ids - ld a, [hli] - push bc - call .CheckIfIDIsInList - pop bc - jr c, .shuffle_deck - dec b - jr nz, .check_card_ids - -; finally, check 6 cards after that. -; if Energy or Basic Pokemon counter is below 4 -; (counting with the ones found in the initial hand) -; then re-shuffle deck. - ld b, 6 -.loop_deck_2 - ld a, [hli] - push bc - call LoadCardDataToBuffer1_FromDeckIndex - pop bc - ld a, [wLoadedCard1Type] - cp TYPE_ENERGY - jr c, .pokemon_card_2 - cp TYPE_TRAINER - jr z, .next_card_deck_2 - -; energy card - ld a, [wce08] - inc a - ld [wce08], a - jr .next_card_deck_2 - -.pokemon_card_2 - ld a, [wLoadedCard1Stage] - or a - jr nz, .next_card_deck_2 - ld a, [wce06] - inc a - ld [wce06], a - -.next_card_deck_2 - dec b - jr nz, .loop_deck_2 - - ld a, [wce06] - cp 4 - jp c, .shuffle_deck - ld a, [wce08] - cp 4 - jp c, .shuffle_deck - -; draw new set of hand cards - ld a, DUELVARS_DECK_CARDS - call GetTurnDuelistVariable - ld b, STARTING_HAND_SIZE -.draw_loop - ld a, [hli] - call SearchCardInDeckAndAddToHand - call AddCardToHand - dec b - jr nz, .draw_loop - ret - -; expectation: return carry if card ID corresponding -; to the input deck index is listed in wAICardListAvoidPrize; -; reality: always returns no carry because when checking terminating -; byte in wAICardListAvoidPrize ($00), it wrongfully uses 'cp a' instead of 'or a', -; so it always ends up returning in the first item in list. -; input: -; - a = deck index of card to check -.CheckIfIDIsInList ; 17366 (5:7366) - ld b, a - ld a, [wAICardListAvoidPrize + 1] - or a - ret z ; null - push hl - ld h, a - ld a, [wAICardListAvoidPrize] - ld l, a - - ld a, b - call GetCardIDFromDeckIndex -.loop_id_list - ld a, [hli] - cp a ; bug, should be 'or a' - jr z, .false - cp e - jr nz, .loop_id_list - -; true - pop hl - scf - ret -.false - pop hl - or a - ret diff --git a/src/engine/ai/common.asm b/src/engine/ai/common.asm deleted file mode 100644 index d4f1da4..0000000 --- a/src/engine/ai/common.asm +++ /dev/null @@ -1,970 +0,0 @@ -; runs through Player's whole deck and -; sets carry if there's any Pokemon other -; than Mewtwo1. -CheckIfPlayerHasPokemonOtherThanMewtwo1: ; 227a9 (8:67a9) - call SwapTurn - ld e, 0 -.loop_deck - ld a, e - push de - call LoadCardDataToBuffer2_FromDeckIndex - pop de - ld a, [wLoadedCard2Type] - cp TYPE_ENERGY - jp nc, .next ; can be a jr - ld a, [wLoadedCard2ID] - cp MEWTWO1 - jr nz, .not_mewtwo1 -.next - inc e - ld a, DECK_SIZE - cp e - jr nz, .loop_deck - -; no carry - call SwapTurn - or a - ret - -.not_mewtwo1 - call SwapTurn - scf - ret - -; returns no carry if, given the Player is using a Mewtwo1 mill deck, -; the AI already has a Bench fully set up, in which case it -; will process some Trainer cards in hand (namely Energy Removals). -; this is used to check whether to skip some normal AI routines -; this turn and jump right to the attacking phase. -HandleAIAntiMewtwoDeckStrategy: ; 227d3 (8:67d3) -; return carry if Player is not playing Mewtwo1 mill deck - ld a, [wAIBarrierFlagCounter] - bit AI_MEWTWO_MILL_F, a - jr z, .set_carry - -; else, check if there's been less than 2 turns -; without the Player using Barrier. - cp AI_MEWTWO_MILL + 2 - jr c, .count_bench - -; if there has been, reset wAIBarrierFlagCounter -; and return carry. - xor a - ld [wAIBarrierFlagCounter], a - jr .set_carry - -; else, check number of Pokemon that are set up in Bench -; if less than 4, return carry. -.count_bench - farcall CountNumberOfSetUpBenchPokemon - cp 4 - jr c, .set_carry - -; if there's at least 4 Pokemon in the Bench set up, -; process Trainer hand cards of AI_TRAINER_CARD_PHASE_05 - ld a, AI_TRAINER_CARD_PHASE_05 - farcall AIProcessHandTrainerCards - or a - ret - -.set_carry - scf - ret - -; lists in wDuelTempList all the basic energy cards -; in card location of a. -; outputs in a number of cards found. -; returns carry if none were found. -; input: -; a = CARD_LOCATION_* to look -; output: -; a = number of cards found -FindBasicEnergyCardsInLocation: ; 227f6 (8:67f6) - ld [wTempAI], a - lb de, 0, 0 - ld hl, wDuelTempList - -; d = number of basic energy cards found -; e = current card in deck -; loop entire deck -.loop - ld a, DUELVARS_CARD_LOCATIONS - add e - push hl - call GetTurnDuelistVariable - ld hl, wTempAI - cp [hl] - pop hl - jr nz, .next_card - -; is in the card location we're looking for - ld a, e - push de - push hl - call GetCardIDFromDeckIndex - pop hl - ld a, e - pop de - cp DOUBLE_COLORLESS_ENERGY - ; only basic energy cards - ; will set carry here - jr nc, .next_card - -; is a basic energy card -; add this card to the TempList - ld a, e - ld [hli], a - inc d -.next_card - inc e - ld a, DECK_SIZE - cp e - jr nz, .loop - -; check if any were found - ld a, d - or a - jr z, .set_carry - -; some were found, add the termination byte on TempList - ld a, $ff - ld [hl], a - ld a, d - ret - -.set_carry - scf - ret - -; returns in a the card index of energy card -; attached to Pokémon in Play Area location a, -; that is to be discarded by the AI for an effect. -; outputs $ff is none was found. -; input: -; a = PLAY_AREA_* constant of card -; output: -; a = deck index of attached energy card chosen -AIPickEnergyCardToDiscard: ; 2282e (8:682e) -; load Pokémon's attached energy cards. - ldh [hTempPlayAreaLocation_ff9d], a - call CreateArenaOrBenchEnergyCardList - ldh a, [hTempPlayAreaLocation_ff9d] - ld e, a - call GetPlayAreaCardAttachedEnergies - ld a, [wTotalAttachedEnergies] - or a - jr z, .no_energy - -; load card's ID and type. - ldh a, [hTempPlayAreaLocation_ff9d] - ld b, a - ld a, DUELVARS_ARENA_CARD - add b - call GetTurnDuelistVariable - call GetCardIDFromDeckIndex - ld a, e - ld [wTempCardID], a - call LoadCardDataToBuffer1_FromCardID - ld a, [wLoadedCard1Type] - or TYPE_ENERGY - ld [wTempCardType], a - -; find a card that is not useful. -; if none is found, just return the first energy card attached. - ld hl, wDuelTempList -.loop - ld a, [hl] - cp $ff - jr z, .not_found - farcall CheckIfEnergyIsUseful - jr nc, .found - inc hl - jr .loop - -.found - ld a, [hl] - ret -.not_found - ld hl, wDuelTempList - ld a, [hl] - ret -.no_energy - ld a, $ff - ret - -; returns in a the deck index of an energy card attached to card -; in player's Play Area location a to remove. -; prioritizes double colorless energy, then any useful energy, -; then defaults to the first energy card attached if neither -; of those are found. -; returns $ff in a if there are no energy cards attached. -; input: -; a = Play Area location to check -; output: -; a = deck index of attached energy card -PickAttachedEnergyCardToRemove: ; 22875 (8:6875) -; construct energy list and check if there are any energy cards attached - ldh [hTempPlayAreaLocation_ff9d], a - call CreateArenaOrBenchEnergyCardList - ldh a, [hTempPlayAreaLocation_ff9d] - ld e, a - call GetPlayAreaCardAttachedEnergies - ld a, [wTotalAttachedEnergies] - or a - jr z, .no_energy - -; load card data and store its type - ldh a, [hTempPlayAreaLocation_ff9d] - ld b, a - ld a, DUELVARS_ARENA_CARD - add b - call GetTurnDuelistVariable - call GetCardIDFromDeckIndex - ld a, e - ld [wTempCardID], a - call LoadCardDataToBuffer1_FromCardID - ld a, [wLoadedCard1Type] - or TYPE_ENERGY - ld [wTempCardType], a - -; first look for any double colorless energy - ld hl, wDuelTempList -.loop_1 - ld a, [hl] - cp $ff - jr z, .check_useful - push hl - call GetCardIDFromDeckIndex - ld a, e - cp DOUBLE_COLORLESS_ENERGY - pop hl - jr z, .found - inc hl - jr .loop_1 - -; then look for any energy cards that are useful -.check_useful - ld hl, wDuelTempList -.loop_2 - ld a, [hl] - cp $ff - jr z, .default - farcall CheckIfEnergyIsUseful - jr c, .found - inc hl - jr .loop_2 - -; return the energy card that was found -.found - ld a, [hl] - ret - -; if none were found with the above criteria, -; just return the first option -.default - ld hl, wDuelTempList - ld a, [hl] - ret - -; return $ff if no energy cards attached -.no_energy - ld a, $ff - ret - -; stores in wTempAI and wCurCardCanAttack the deck indices -; of energy cards attached to card in Play Area location a. -; prioritizes double colorless energy, then any useful energy, -; then defaults to the first two energy cards attached if neither -; of those are found. -; returns $ff in a if there are no energy cards attached. -; input: -; a = Play Area location to check -; output: -; [wTempAI] = deck index of attached energy card -; [wCurCardCanAttack] = deck index of attached energy card -PickTwoAttachedEnergyCards: ; 228d1 (8:68d1) - ldh [hTempPlayAreaLocation_ff9d], a - call CreateArenaOrBenchEnergyCardList - ldh a, [hTempPlayAreaLocation_ff9d] - ld e, a - farcall CountNumberOfEnergyCardsAttached - cp 2 - jp c, .not_enough - -; load card data and store its type - ldh a, [hTempPlayAreaLocation_ff9d] - ld b, a - ld a, DUELVARS_ARENA_CARD - add b - call GetTurnDuelistVariable - call GetCardIDFromDeckIndex - ld a, e - ld [wTempCardID], a - call LoadCardDataToBuffer1_FromCardID - ld a, [wLoadedCard1Type] - or TYPE_ENERGY - ld [wTempCardType], a - ld a, $ff - ld [wTempAI], a - ld [wCurCardCanAttack], a - -; first look for any double colorless energy - ld hl, wDuelTempList -.loop_1 - ld a, [hl] - cp $ff - jr z, .check_useful - push hl - call GetCardIDFromDeckIndex - ld a, e - cp DOUBLE_COLORLESS_ENERGY - pop hl - jr z, .found_double_colorless - inc hl - jr .loop_1 -.found_double_colorless - ld a, [wTempAI] - cp $ff - jr nz, .already_chosen_1 - ld a, [hli] - ld [wTempAI], a - jr .loop_1 -.already_chosen_1 - ld a, [hl] - ld [wCurCardCanAttack], a - jr .done - -; then look for any energy cards that are useful -.check_useful - ld hl, wDuelTempList -.loop_2 - ld a, [hl] - cp $ff - jr z, .default - farcall CheckIfEnergyIsUseful - jr c, .found_useful - inc hl - jr .loop_2 -.found_useful - ld a, [wTempAI] - cp $ff - jr nz, .already_chosen_2 - ld a, [hli] - ld [wTempAI], a - jr .loop_2 -.already_chosen_2 - ld a, [hl] - ld [wCurCardCanAttack], a - jr .done - -; if none were found with the above criteria, -; just return the first 2 options -.default - ld hl, wDuelTempList - ld a, [wTempAI] - cp $ff - jr nz, .pick_one_card - -; pick 2 cards - ld a, [hli] - ld [wTempAI], a - ld a, [hl] - ld [wCurCardCanAttack], a - jr .done -.pick_one_card - ld a, [wTempAI] - ld b, a -.loop_3 - ld a, [hli] - cp b - jr z, .loop_3 ; already picked - ld [wCurCardCanAttack], a - -.done - ld a, [wCurCardCanAttack] - ld b, a - ld a, [wTempAI] - ret - -; return $ff if no energy cards attached -.not_enough - ld a, $ff - ret - -; copies $ff terminated buffer from hl to de -CopyBuffer: ; 2297b (8:697b) - ld a, [hli] - ld [de], a - cp $ff - ret z - inc de - jr CopyBuffer - -; zeroes a bytes starting at hl -ClearMemory_Bank8: ; 22983 (8:6983) - push af - push bc - push hl - ld b, a - xor a -.loop - ld [hli], a - dec b - jr nz, .loop - pop hl - pop bc - pop af - ret - -; counts number of energy cards found in hand -; and outputs result in a -; sets carry if none are found -; output: -; a = number of energy cards found -CountOppEnergyCardsInHand: ; 22990 (8:6990) - farcall CreateEnergyCardListFromHand - ret c - ld b, -1 - ld hl, wDuelTempList -.loop - inc b - ld a, [hli] - cp $ff - jr nz, .loop - ld a, b - or a - ret - -; converts HP in a to number of equivalent damage counters -; input: -; a = HP -; output: -; a = number of damage counters -ConvertHPToCounters: ; 229a3 (8:69a3) - push bc - ld c, 0 -.loop - sub 10 - jr c, .carry - inc c - jr .loop -.carry - ld a, c - pop bc - ret - -; calculates floor(hl / 10) -CalculateWordTensDigit: ; 229b0 (8:69b0) - push bc - push de - lb bc, $ff, -10 - lb de, $ff, -1 -.asm_229b8 - inc de - add hl, bc - jr c, .asm_229b8 - ld h, d - ld l, e - pop de - pop bc - ret - -; returns in a division of b by a -CalculateBDividedByA_Bank8: ; 229c1 (8:69c1) - push bc - ld c, a - ld a, b - ld b, c - ld c, 0 -.loop - sub b - jr c, .done - inc c - jr .loop -.done - ld a, c - pop bc - ret - -; returns in a the deck index of the first -; instance of card with ID equal to the ID in e -; in card location a. -; returns carry if found. -; input: -; a = CARD_LOCATION_* -; e = card ID to look for -LookForCardIDInLocation: ; 229d0 (8:69d0) - ld b, a - ld c, e - lb de, $00, 0 ; d is never used -.loop - ld a, DUELVARS_CARD_LOCATIONS - add e - call GetTurnDuelistVariable - cp b - jr nz, .next - ld a, e - push de - call GetCardIDFromDeckIndex - ld a, e - pop de - cp c - jr z, .found -.next - inc e - ld a, DECK_SIZE - cp e - jr nz, .loop - -; not found - or a - ret -.found - ld a, e - scf - ret - -; return carry if card ID loaded in a is found in hand -; and outputs in a the deck index of that card -; input: -; a = card ID -; output: -; a = card deck index, if found -; carry set if found -LookForCardIDInHandList_Bank8: ; 229f3 (8:69f3) - ld [wTempCardIDToLook], a - call CreateHandCardList - ld hl, wDuelTempList - -.loop - ld a, [hli] - cp $ff - ret z - - ldh [hTempCardIndex_ff98], a - call LoadCardDataToBuffer1_FromDeckIndex - ld b, a - ld a, [wTempCardIDToLook] - cp b - jr nz, .loop - - ldh a, [hTempCardIndex_ff98] - scf - ret - -; searches in deck for card ID 1 in a, and -; if found, searches in Hand/Play Area for card ID 2 in b, and -; if found, searches for card ID 1 in Hand/Play Area, and -; if none found, return carry and output deck index -; of the card ID 1 in deck. -; input: -; a = card ID 1 -; b = card ID 2 -; output: -; a = index of card ID 1 in deck -LookForCardIDInDeck_GivenCardIDInHandAndPlayArea: ; 22a10 (8:6a10) -; store a in wCurCardCanAttack -; and b in wTempAI - ld c, a - ld a, b - ld [wTempAI], a - ld a, c - ld [wCurCardCanAttack], a - -; look for the card ID 1 in deck - ld e, a - ld a, CARD_LOCATION_DECK - call LookForCardIDInLocation - ret nc - -; was found, store its deck index in memory - ld [wTempAIPokemonCard], a - -; look for the card ID 2 -; in Hand and Play Area, return if not found. - ld a, [wTempAI] - call LookForCardIDInHandAndPlayArea - ret nc - -; look for the card ID 1 in the Hand and Play Area -; if any card is found, return no carry. - ld a, [wCurCardCanAttack] - call LookForCardIDInHandAndPlayArea - jr c, .no_carry -; none found - - ld a, [wTempAIPokemonCard] - scf - ret - -.no_carry - or a - ret - -; returns carry if card ID in a -; is found in Play Area or in hand -; input: -; a = card ID -LookForCardIDInHandAndPlayArea: ; 22a39 (8:6a39) - ld b, a - push bc - call LookForCardIDInHandList_Bank8 - pop bc - ret c - - ld a, b - ld b, PLAY_AREA_ARENA - call LookForCardIDInPlayArea_Bank8 - ret c - or a - ret - -; searches in deck for card ID 1 in a, and -; if found, searches in Hand Area for card ID 2 in b, and -; if found, searches for card ID 1 in Hand/Play Area, and -; if none found, return carry and output deck index -; of the card ID 1 in deck. -; input: -; a = card ID 1 -; b = card ID 2 -; output: -; a = index of card ID 1 in deck -LookForCardIDInDeck_GivenCardIDInHand: ; 22a49 (8:6a49) -; store a in wCurCardCanAttack -; and b in wTempAI - ld c, a - ld a, b - ld [wTempAI], a - ld a, c - ld [wCurCardCanAttack], a - -; look for the card ID 1 in deck - ld e, a - ld a, CARD_LOCATION_DECK - call LookForCardIDInLocation - ret nc - -; was found, store its deck index in memory - ld [wTempAIPokemonCard], a - -; look for the card ID 2 in hand, return if not found. - ld a, [wTempAI] - call LookForCardIDInHandList_Bank8 - ret nc - -; look for the card ID 1 in the Hand and Play Area -; if any card is found, return no carry. - ld a, [wCurCardCanAttack] - call LookForCardIDInHandAndPlayArea - jr c, .no_carry -; none found - - ld a, [wTempAIPokemonCard] - scf - ret - -.no_carry - or a - ret - -; returns carry if card ID in a -; is found in Play Area, starting with -; location in b -; input: -; a = card ID -; b = PLAY_AREA_* to start with -; output: -; a = PLAY_AREA_* of found card -; carry set if found -LookForCardIDInPlayArea_Bank8: ; 22a72 (8:6a72) - ld [wTempCardIDToLook], a -.loop - ld a, DUELVARS_ARENA_CARD - add b - call GetTurnDuelistVariable - cp $ff - ret z - - call LoadCardDataToBuffer1_FromDeckIndex - ld c, a - ld a, [wTempCardIDToLook] - cp c - jr z, .is_same - - inc b - ld a, MAX_PLAY_AREA_POKEMON - cp b - jr nz, .loop - ld b, $ff - or a - ret - -.is_same - ld a, b - scf - ret - -; runs through list avoiding card in e. -; removes first card in list not equal to e -; and that has a type allowed to be removed, in d. -; returns carry if successful in finding a card. -; input: -; d = type of card allowed to be removed -; ($00 = Trainer, $01 = Pokemon, $02 = Energy) -; e = card deck index to avoid removing -; output: -; a = card index of removed card -RemoveFromListDifferentCardOfGivenType: ; 22a95 (8:6a95) - push hl - push de - push bc - call CountCardsInDuelTempList - call ShuffleCards - -; loop list until a card with -; deck index different from e is found. -.loop_list - ld a, [hli] - cp $ff - jr z, .no_carry - cp e - jr z, .loop_list - -; get this card's type - ldh [hTempCardIndex_ff98], a - push de - call GetCardIDFromDeckIndex - call GetCardType - pop de - cp TYPE_ENERGY - jr c, .pkmn_card - cp TYPE_TRAINER - jr nz, .energy - -; only remove from list specific type. - -; trainer - ld a, d - or a - jr nz, .loop_list - jr .remove_card -.energy - ld a, d - cp $02 - jr nz, .loop_list - jr .remove_card -.pkmn_card - ld a, d - cp $01 - jr nz, .loop_list - ; fallthrough - -.remove_card - ld d, h - ld e, l - dec hl -.loop_remove - ld a, [de] - inc de - ld [hli], a - cp $ff - jr nz, .loop_remove - -; success - ldh a, [hTempCardIndex_ff98] - pop bc - pop de - pop hl - scf - ret -.no_carry - pop bc - pop de - pop hl - or a - ret - -; used in Pokemon Trader checks to look for a specific -; card in the deck to trade with a card in hand that -; has a card ID different from e. -; returns carry if successful. -; input: -; a = card ID 1 -; e = card ID 2 -; output: -; a = deck index of card ID 1 found in deck -; e = deck index of Pokemon card in hand different than card ID 2 -LookForCardIDToTradeWithDifferentHandCard: ; 22ae0 (8:6ae0) - ld hl, wCurCardCanAttack - ld [hl], e - ld [wTempAI], a - -; if card ID 1 is in hand, return no carry. - call LookForCardIDInHandList_Bank8 - jr c, .no_carry - -; if card ID 1 is not in deck, return no carry. - ld a, [wTempAI] - ld e, a - ld a, CARD_LOCATION_DECK - call LookForCardIDInLocation - jr nc, .no_carry - -; store its deck index - ld [wTempAI], a - -; look in hand for Pokemon card ID that -; is different from card ID 2. - ld a, [wCurCardCanAttack] - ld c, a - call CreateHandCardList - ld hl, wDuelTempList - -.loop_hand - ld a, [hli] - cp $ff - jr z, .no_carry - ld b, a - call LoadCardDataToBuffer1_FromDeckIndex - cp c - jr z, .loop_hand - ld a, [wLoadedCard1Type] - cp TYPE_ENERGY - jr nc, .loop_hand - -; found, output deck index of card ID 1 in deck -; and deck index of card found in hand, and set carry - ld e, b - ld a, [wTempAI] - scf - ret - -.no_carry - or a - ret - -; returns carry if at least one card in the hand -; has the card ID of input. Outputs its index. -; input: -; a = card ID to look for -; output: -; a = deck index of card in hand found -CheckIfHasCardIDInHand: ; 22b1f (8:6b1f) - ld [wTempCardIDToLook], a - call CreateHandCardList - ld hl, wDuelTempList - ld c, 0 - -.loop_hand - ld a, [hli] - cp $ff - ret z - ldh [hTempCardIndex_ff98], a - call LoadCardDataToBuffer1_FromDeckIndex - ld b, a - ld a, [wTempCardIDToLook] - cp b - jr nz, .loop_hand - ld a, c - or a - jr nz, .set_carry - inc c - jr nz, .loop_hand - -.set_carry - ldh a, [hTempCardIndex_ff98] - scf - ret - -; outputs in a total number of Pokemon cards in hand -; plus Pokemon in Turn Duelist's Play Area. -CountPokemonCardsInHandAndInPlayArea: ; 22b45 (8:6b45) - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - ld [wTempAI], a - call CreateHandCardList - ld hl, wDuelTempList -.loop_hand - ld a, [hli] - cp $ff - jr z, .done - call GetCardIDFromDeckIndex - call GetCardType - cp TYPE_ENERGY - jr nc, .loop_hand - ld a, [wTempAI] - inc a - ld [wTempAI], a - jr .loop_hand -.done - ld a, [wTempAI] - ret - -; returns carry if a duplicate Pokemon card is found in hand. -; outputs in a the deck index of one of them. -FindDuplicatePokemonCards: ; 22b6f (8:6b6f) - ld a, $ff - ld [wTempAI], a - call CreateHandCardList - ld hl, wDuelTempList - push hl - -.loop_hand_outer - pop hl - ld a, [hli] - cp $ff - jr z, .done - call GetCardIDFromDeckIndex - ld b, e - push hl - -.loop_hand_inner - ld a, [hli] - cp $ff - jr z, .loop_hand_outer - ld c, a - call GetCardIDFromDeckIndex - ld a, e - cp b - jr nz, .loop_hand_inner - -; found two cards with same ID, -; if they are Pokemon cards, store its deck index. - push bc - call GetCardType - pop bc - cp TYPE_ENERGY - jr nc, .loop_hand_outer - ld a, c - ld [wTempAI], a - ; for some reason loop still continues - ; even though if some other duplicate - ; cards are found, it overwrites the result. - jr .loop_hand_outer - -.done - ld a, [wTempAI] - cp $ff - jr z, .no_carry - -; found - scf - ret -.no_carry - or a - ret - -; return carry flag if attack is not high recoil. -AICheckIfAttackIsHighRecoil: ; 22bad (8:6bad) - farcall AIProcessButDontUseAttack - ret nc - ld a, [wSelectedAttack] - ld e, a - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - ld d, a - call CopyAttackDataAndDamage_FromDeckIndex - ld a, ATTACK_FLAG1_ADDRESS | HIGH_RECOIL_F - call CheckLoadedAttackFlag - ccf - ret diff --git a/src/engine/ai/core.asm b/src/engine/ai/core.asm deleted file mode 100644 index f182375..0000000 --- a/src/engine/ai/core.asm +++ /dev/null @@ -1,2770 +0,0 @@ -INCLUDE "engine/ai/decks/unreferenced.asm" - -; returns carry if damage dealt from any of -; a card's attacks KOs defending Pokémon -; outputs index of the attack that KOs -; input: -; [hTempPlayAreaLocation_ff9d] = location of attacking card to consider -; output: -; [wSelectedAttack] = attack index that KOs -CheckIfAnyAttackKnocksOutDefendingCard: ; 140ae (5:40ae) - xor a ; first attack - call CheckIfAttackKnocksOutDefendingCard - ret c - ld a, SECOND_ATTACK -; fallthrough - -CheckIfAttackKnocksOutDefendingCard: ; 140b5 (5:40b5) - call EstimateDamage_VersusDefendingCard - ld a, DUELVARS_ARENA_CARD_HP - call GetNonTurnDuelistVariable - ld hl, wDamage - sub [hl] - ret c - ret nz - scf - ret - -; returns carry if any of the defending Pokémon's attacks -; brings card at hTempPlayAreaLocation_ff9d down -; to exactly 0 HP. -; outputs that attack index in wSelectedAttack. -CheckIfAnyDefendingPokemonAttackDealsSameDamageAsHP: ; 140c5 (5:40c5) - xor a ; FIRST_ATTACK_OR_PKMN_POWER - call .check_damage - ret c - ld a, SECOND_ATTACK - -.check_damage - call EstimateDamage_FromDefendingPokemon - ldh a, [hTempPlayAreaLocation_ff9d] - add DUELVARS_ARENA_CARD_HP - call GetTurnDuelistVariable - ld hl, wDamage - sub [hl] - jr z, .true - ret -.true - scf - ret - -; checks AI scores for all benched Pokémon -; returns the location of the card with highest score -; in a and [hTempPlayAreaLocation_ff9d] -FindHighestBenchScore: ; 140df (5:40df) - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - ld b, a - ld c, 0 - ld e, c - ld d, c - ld hl, wPlayAreaAIScore + 1 - jp .next - -.loop - ld a, [hli] - cp e - jr c, .next - ld e, a - ld d, c -.next - inc c - dec b - jr nz, .loop - - ld a, d - ldh [hTempPlayAreaLocation_ff9d], a - or a - ret - -; adds a to wAIScore -; if there's overflow, it's capped at $ff -; output: -; a = a + wAIScore (capped at $ff) -AddToAIScore: ; 140fe (5:40fe) - push hl - ld hl, wAIScore - add [hl] - jr nc, .no_cap - ld a, $ff -.no_cap - ld [hl], a - pop hl - ret - -; subs a from wAIScore -; if there's underflow, it's capped at $00 -SubFromAIScore: ; 1410a (5:410a) - push hl - push de - ld e, a - ld hl, wAIScore - ld a, [hl] - or a - jr z, .done - sub e - ld [hl], a - jr nc, .done - ld [hl], $00 -.done - pop de - pop hl - ret - -; loads defending Pokémon's weakness/resistance -; and the number of prize cards in both sides -LoadDefendingPokemonColorWRAndPrizeCards: ; 1411d (5:411d) - call SwapTurn - call GetArenaCardColor - call TranslateColorToWR - ld [wAIPlayerColor], a - call GetArenaCardWeakness - ld [wAIPlayerWeakness], a - call GetArenaCardResistance - ld [wAIPlayerResistance], a - call CountPrizes - ld [wAIPlayerPrizeCount], a - call SwapTurn - call CountPrizes - ld [wAIOpponentPrizeCount], a - ret - -; called when AI has chosen its attack. -; executes all effects and damage. -; handles AI choosing parameters for certain attacks as well. -AITryUseAttack: ; 14145 (5:4145) - ld a, [wSelectedAttack] - ldh [hTemp_ffa0], a - ld e, a - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - ldh [hTempCardIndex_ff9f], a - ld d, a - call CopyAttackDataAndDamage_FromDeckIndex - ld a, OPPACTION_BEGIN_ATTACK - bank1call AIMakeDecision - ret c - - call AISelectSpecialAttackParameters - jr c, .use_attack - ld a, EFFECTCMDTYPE_AI_SELECTION - call TryExecuteEffectCommandFunction - -.use_attack - ld a, [wSelectedAttack] - ld e, a - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - ld d, a - call CopyAttackDataAndDamage_FromDeckIndex - ld a, OPPACTION_USE_ATTACK - bank1call AIMakeDecision - ret c - - ld a, EFFECTCMDTYPE_AI_SWITCH_DEFENDING_PKMN - call TryExecuteEffectCommandFunction - ld a, OPPACTION_ATTACK_ANIM_AND_DAMAGE - bank1call AIMakeDecision - ret - -; return carry if any of the following is satisfied: -; - deck index in a corresponds to a double colorless energy card; -; - card type in wTempCardType is colorless; -; - card ID in wTempCardID is a Pokémon card that has -; attacks that require energy other than its color and -; the deck index in a corresponds to that energy type; -; - card ID is Eevee and a corresponds to an energy type -; of water, fire or lightning; -; - type of card in register a is the same as wTempCardType. -; used for knowing if a given energy card can be discarded -; from a given Pokémon card -; input: -; a = energy card attached to Pokémon to check -; [wTempCardType] = TYPE_ENERGY_* of given Pokémon -; [wTempCardID] = card index of Pokémon card to check -CheckIfEnergyIsUseful: ; 14184 (5:4184) - push de - call GetCardIDFromDeckIndex - ld a, e - cp DOUBLE_COLORLESS_ENERGY - jr z, .set_carry - ld a, [wTempCardType] - cp TYPE_ENERGY_DOUBLE_COLORLESS - jr z, .set_carry - ld a, [wTempCardID] - - ld d, PSYCHIC_ENERGY - cp EXEGGCUTE - jr z, .check_energy - cp EXEGGUTOR - jr z, .check_energy - cp PSYDUCK - jr z, .check_energy - cp GOLDUCK - jr z, .check_energy - - ld d, WATER_ENERGY - cp SURFING_PIKACHU1 - jr z, .check_energy - cp SURFING_PIKACHU2 - jr z, .check_energy - - cp EEVEE - jr nz, .check_type - ld a, e - cp WATER_ENERGY - jr z, .set_carry - cp FIRE_ENERGY - jr z, .set_carry - cp LIGHTNING_ENERGY - jr z, .set_carry - -.check_type - ld d, $00 ; unnecessary? - call GetCardType - ld d, a - ld a, [wTempCardType] - cp d - jr z, .set_carry - pop de - or a - ret - -.check_energy - ld a, d - cp e - jr nz, .check_type -.set_carry - pop de - scf - ret - -; pick a random Pokemon in the bench. -; output: -; - a = PLAY_AREA_* of Bench Pokemon picked. -PickRandomBenchPokemon: ; 141da (5:41da) - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - dec a - call Random - inc a - ret - -AIPickPrizeCards: ; 141e5 (5:41e5) - ld a, [wNumberPrizeCardsToTake] - ld b, a -.loop - call .PickPrizeCard - ld a, DUELVARS_PRIZES - call GetTurnDuelistVariable - or a - jr z, .done - dec b - jr nz, .loop -.done - ret - -; picks a prize card at random -; and adds it to the hand. -.PickPrizeCard: ; 141f8 (5:41f8) - ld a, DUELVARS_PRIZES - call GetTurnDuelistVariable - push hl - ld c, a - -; choose a random prize card until -; one is found that isn't taken already. -.loop_pick_prize - ld a, 6 - call Random - ld e, a - ld d, $00 - ld hl, .prize_flags - add hl, de - ld a, [hl] - and c - jr z, .loop_pick_prize ; no prize - -; prize card was found -; remove this prize from wOpponentPrizes - ld a, [hl] - pop hl - cpl - and [hl] - ld [hl], a - -; add this prize card to the hand - ld a, e - add DUELVARS_PRIZE_CARDS - call GetTurnDuelistVariable - call AddCardToHand - ret - -.prize_flags ; 1421e (5:421e) - db $1 << 0 - db $1 << 1 - db $1 << 2 - db $1 << 3 - db $1 << 4 - db $1 << 5 - db $1 << 6 - db $1 << 7 - -; routine for AI to play all Basic cards from its hand -; in the beginning of the Duel. -AIPlayInitialBasicCards: ; 14226 (5:4226) - call CreateHandCardList - ld hl, wDuelTempList -.check_for_next_card - ld a, [hli] - ldh [hTempCardIndex_ff98], a - cp $ff - ret z ; return when done - - call LoadCardDataToBuffer1_FromDeckIndex - ld a, [wLoadedCard1Type] - cp TYPE_ENERGY - jr nc, .check_for_next_card ; skip if not Pokemon card - ld a, [wLoadedCard1Stage] - or a - jr nz, .check_for_next_card ; skip if not Basic Stage - -; play Basic card from hand - push hl - ldh a, [hTempCardIndex_ff98] - call PutHandPokemonCardInPlayArea - pop hl - jr .check_for_next_card - -; returns carry if Pokémon at hTempPlayAreaLocation_ff9d -; can't use an attack or if that selected attack doesn't have enough energy -; input: -; [hTempPlayAreaLocation_ff9d] = location of Pokémon card -; [wSelectedAttack] = selected attack to examine -CheckIfSelectedAttackIsUnusable: ; 1424b (5:424b) - ldh a, [hTempPlayAreaLocation_ff9d] - or a - jr nz, .bench - - bank1call HandleCantAttackSubstatus - ret c - bank1call CheckIfActiveCardParalyzedOrAsleep - ret c - - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - ld d, a - ld a, [wSelectedAttack] - ld e, a - call CopyAttackDataAndDamage_FromDeckIndex - call HandleAmnesiaSubstatus - ret c - ld a, EFFECTCMDTYPE_INITIAL_EFFECT_1 - call TryExecuteEffectCommandFunction - ret c - -.bench - call CheckEnergyNeededForAttack - ret c ; can't be used - ld a, ATTACK_FLAG2_ADDRESS | FLAG_2_BIT_5_F - call CheckLoadedAttackFlag - ret - -; load selected attack from Pokémon in hTempPlayAreaLocation_ff9d -; and checks if there is enough energy to execute the selected attack -; input: -; [hTempPlayAreaLocation_ff9d] = location of Pokémon card -; [wSelectedAttack] = selected attack to examine -; output: -; b = basic energy still needed -; c = colorless energy still needed -; e = output of ConvertColorToEnergyCardID, or $0 if not an attack -; carry set if no attack -; OR if it's a Pokémon Power -; OR if not enough energy for attack -CheckEnergyNeededForAttack: ; 14279 (5:4279) - ldh a, [hTempPlayAreaLocation_ff9d] - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - ld d, a - ld a, [wSelectedAttack] - ld e, a - call CopyAttackDataAndDamage_FromDeckIndex - ld hl, wLoadedAttackName - ld a, [hli] - or [hl] - jr z, .no_attack - ld a, [wLoadedAttackCategory] - cp POKEMON_POWER - jr nz, .is_attack -.no_attack - lb bc, 0, 0 - ld e, c - scf - ret - -.is_attack - ldh a, [hTempPlayAreaLocation_ff9d] - ld e, a - call GetPlayAreaCardAttachedEnergies - bank1call HandleEnergyBurn - - xor a - ld [wTempLoadedAttackEnergyCost], a - ld [wTempLoadedAttackEnergyNeededAmount], a - ld [wTempLoadedAttackEnergyNeededType], a - - ld hl, wAttachedEnergies - ld de, wLoadedAttackEnergyCost - ld b, 0 - ld c, (NUM_TYPES / 2) - 1 - -.loop - ; check all basic energy cards except colorless - ld a, [de] - swap a - call CheckIfEnoughParticularAttachedEnergy - ld a, [de] - call CheckIfEnoughParticularAttachedEnergy - inc de - dec c - jr nz, .loop - -; running CheckIfEnoughParticularAttachedEnergy back to back like this -; overwrites the results of a previous call of this function, -; however, no attack in the game has energy requirements for two -; different energy types (excluding colorless), so this routine -; will always just return the result for one type of basic energy, -; while all others will necessarily have an energy cost of 0 -; if attacks are added to the game with energy requirements of -; two different basic energy types, then this routine only accounts -; for the type with the highest index - - ; colorless - ld a, [de] - swap a - and %00001111 - ld b, a ; colorless energy still needed - ld a, [wTempLoadedAttackEnergyCost] - ld hl, wTempLoadedAttackEnergyNeededAmount - sub [hl] - ld c, a ; basic energy still needed - ld a, [wTotalAttachedEnergies] - sub c - sub b - jr c, .not_enough - - ld a, [wTempLoadedAttackEnergyNeededAmount] - or a - ret z - -; being here means the energy cost isn't satisfied, -; including with colorless energy - xor a -.not_enough - cpl - inc a - ld c, a ; colorless energy still needed - ld a, [wTempLoadedAttackEnergyNeededAmount] - ld b, a ; basic energy still needed - ld a, [wTempLoadedAttackEnergyNeededType] - call ConvertColorToEnergyCardID - ld e, a - ld d, 0 - scf - ret - -; takes as input the energy cost of an attack for a -; particular energy, stored in the lower nibble of a -; if the attack costs some amount of this energy, the lower nibble of a != 0, -; and this amount is stored in wTempLoadedAttackEnergyCost -; sets carry flag if not enough energy of this type attached -; input: -; a = this energy cost of attack (lower nibble) -; [hl] = attached energy -; output: -; carry set if not enough of this energy type attached -CheckIfEnoughParticularAttachedEnergy: ; 142f4 (5:42f4) - and %00001111 - jr nz, .check -.has_enough - inc hl - inc b - or a - ret - -.check - ld [wTempLoadedAttackEnergyCost], a - sub [hl] - jr z, .has_enough - jr c, .has_enough - - ; not enough energy - ld [wTempLoadedAttackEnergyNeededAmount], a - ld a, b - ld [wTempLoadedAttackEnergyNeededType], a - inc hl - inc b - scf - ret - -; input: -; a = energy type -; output: -; a = energy card ID -ConvertColorToEnergyCardID: ; 1430f (5:430f) - push hl - push de - ld e, a - ld d, 0 - ld hl, .card_id - add hl, de - ld a, [hl] - pop de - pop hl - ret - -.card_id - db FIRE_ENERGY - db GRASS_ENERGY - db LIGHTNING_ENERGY - db WATER_ENERGY - db FIGHTING_ENERGY - db PSYCHIC_ENERGY - db DOUBLE_COLORLESS_ENERGY - -; returns carry if loaded attack effect has -; an "initial effect 2" or "require selection" command type -; unreferenced -Func_14323: ; 14323 (5:4323) - ld hl, wLoadedAttackEffectCommands - ld a, [hli] - ld h, [hl] - ld l, a - ld a, EFFECTCMDTYPE_INITIAL_EFFECT_2 - push hl - call CheckMatchingCommand - pop hl - jr nc, .set_carry - ld a, EFFECTCMDTYPE_REQUIRE_SELECTION - call CheckMatchingCommand - jr nc, .set_carry - or a - ret -.set_carry - scf - ret - -; return carry depending on card index in a: -; - if energy card, return carry if no energy card has been played yet -; - if basic Pokémon card, return carry if there's space in bench -; - if evolution card, return carry if there's a Pokémon -; in Play Area it can evolve -; - if trainer card, return carry if it can be used -; input: -; a = card index to check -CheckIfCardCanBePlayed: ; 1433d (5:433d) - ldh [hTempCardIndex_ff9f], a - call LoadCardDataToBuffer1_FromDeckIndex - ld a, [wLoadedCard1Type] - cp TYPE_ENERGY - jr c, .pokemon_card - cp TYPE_TRAINER - jr z, .trainer_card - -; energy card - ld a, [wAlreadyPlayedEnergy] - or a - ret z - scf - ret - -.pokemon_card - ld a, [wLoadedCard1Stage] - or a - jr nz, .evolution_card - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - cp MAX_PLAY_AREA_POKEMON - ccf - ret - -.evolution_card - bank1call IsPrehistoricPowerActive - ret c - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - ld c, a - ld b, 0 -.loop - push bc - ld e, b - ldh a, [hTempCardIndex_ff9f] - ld d, a - call CheckIfCanEvolveInto - pop bc - ret nc - inc b - dec c - jr nz, .loop - scf - ret - -.trainer_card - bank1call CheckCantUseTrainerDueToHeadache - ret c - call LoadNonPokemonCardEffectCommands - ld a, EFFECTCMDTYPE_INITIAL_EFFECT_1 - call TryExecuteEffectCommandFunction - ret - -; loads all the energy cards -; in hand in wDuelTempList -; return carry if no energy cards found -CreateEnergyCardListFromHand: ; 1438c (5:438c) - push hl - push de - push bc - ld de, wDuelTempList - ld b, a - ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND - call GetTurnDuelistVariable - ld c, a - inc c - ld l, LOW(wOpponentHand) - jr .decrease - -.loop - ld a, [hli] - push de - call GetCardIDFromDeckIndex - call GetCardType - pop de - and TYPE_ENERGY - jr z, .decrease - dec hl - ld a, [hli] - ld [de], a - inc de -.decrease - dec c - jr nz, .loop - - ld a, $ff - ld [de], a - pop bc - pop de - pop hl - ld a, [wDuelTempList] - cp $ff - ccf - ret - -; looks for card ID in hand and -; sets carry if a card wasn't found -; as opposed to LookForCardIDInHandList_Bank5 -; this function doesn't create a list -; and preserves hl, de and bc -; input: -; a = card ID -; output: -; a = card deck index, if found -; carry set if NOT found -LookForCardIDInHand: ; 143bf (5:43bf) - push hl - push de - push bc - ld b, a - ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND - call GetTurnDuelistVariable - ld c, a - inc c - ld l, DUELVARS_HAND - jr .next - -.loop - ld a, [hli] - call GetCardIDFromDeckIndex - ld a, e - cp b - jr z, .no_carry -.next - dec c - jr nz, .loop - - pop bc - pop de - pop hl - scf - ret - -.no_carry - dec hl - ld a, [hl] - pop bc - pop de - pop hl - or a - ret - -INCLUDE "engine/ai/damage_calculation.asm" - -AIProcessHandTrainerCards: ; 14663 (5:4663) - farcall _AIProcessHandTrainerCards - ret - -INCLUDE "engine/ai/deck_ai.asm" - -; return carry if card ID loaded in a is found in hand -; and outputs in a the deck index of that card -; as opposed to LookForCardIDInHand, this function -; creates a list in wDuelTempList -; input: -; a = card ID -; output: -; a = card deck index, if found -; carry set if found -LookForCardIDInHandList_Bank5: ; 155d2 (5:55d2) - ld [wTempCardIDToLook], a - call CreateHandCardList - ld hl, wDuelTempList - -.loop - ld a, [hli] - cp $ff - ret z - ldh [hTempCardIndex_ff98], a - call LoadCardDataToBuffer1_FromDeckIndex - ld b, a - ld a, [wTempCardIDToLook] - cp b - jr nz, .loop - - ldh a, [hTempCardIndex_ff98] - scf - ret - -; returns carry if card ID in a -; is found in Play Area, starting with -; location in b -; input: -; a = card ID -; b = PLAY_AREA_* to start with -; output: -; a = PLAY_AREA_* of found card -; carry set if found -LookForCardIDInPlayArea_Bank5: ; 155ef (5:55ef) - ld [wTempCardIDToLook], a - -.loop - ld a, DUELVARS_ARENA_CARD - add b - call GetTurnDuelistVariable - cp $ff - ret z - call LoadCardDataToBuffer1_FromDeckIndex - ld c, a - ld a, [wTempCardIDToLook] - cp c - jr z, .found - inc b - ld a, MAX_PLAY_AREA_POKEMON - cp b - jr nz, .loop - - ld b, $ff - or a - ret -.found - ld a, b - scf - ret - -; check if energy card ID in e is in AI hand and, -; if so, attaches it to card ID in d in Play Area. -; input: -; e = Energy card ID -; d = Pokemon card ID -AIAttachEnergyInHandToCardInPlayArea: ; 15612 (5:5612) - ld a, e - push de - call LookForCardIDInHandList_Bank5 - pop de - ret nc ; not in hand - ld b, PLAY_AREA_ARENA - -.attach - ld e, a - ld a, d - call LookForCardIDInPlayArea_Bank5 - ldh [hTempPlayAreaLocation_ffa1], a - ld a, e - ldh [hTemp_ffa0], a - ld a, OPPACTION_PLAY_ENERGY - bank1call AIMakeDecision - ret - -; same as AIAttachEnergyInHandToCardInPlayArea but -; only look for card ID in the Bench. -AIAttachEnergyInHandToCardInBench: ; 1562b (5:562b) - ld a, e - push de - call LookForCardIDInHandList_Bank5 - pop de - ret nc - ld b, PLAY_AREA_BENCH_1 - jr AIAttachEnergyInHandToCardInPlayArea.attach - -INCLUDE "engine/ai/init.asm" - -; load selected attack from Pokémon in hTempPlayAreaLocation_ff9d, -; gets an energy card to discard and subsequently -; check if there is enough energy to execute the selected attack -; after removing that attached energy card. -; input: -; [hTempPlayAreaLocation_ff9d] = location of Pokémon card -; [wSelectedAttack] = selected attack to examine -; output: -; b = basic energy still needed -; c = colorless energy still needed -; e = output of ConvertColorToEnergyCardID, or $0 if not an attack -; carry set if no attack -; OR if it's a Pokémon Power -; OR if not enough energy for attack -CheckEnergyNeededForAttackAfterDiscard: ; 156c3 (5:56c3) - ldh a, [hTempPlayAreaLocation_ff9d] - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - ld d, a - ld a, [wSelectedAttack] - ld e, a - call CopyAttackDataAndDamage_FromDeckIndex - ld hl, wLoadedAttackName - ld a, [hli] - or [hl] - jr z, .no_attack - ld a, [wLoadedAttackCategory] - cp POKEMON_POWER - jr nz, .is_attack -.no_attack - lb bc, 0, 0 - ld e, c - scf - ret - -.is_attack - ldh a, [hTempPlayAreaLocation_ff9d] - farcall AIPickEnergyCardToDiscard - call LoadCardDataToBuffer1_FromDeckIndex - cp DOUBLE_COLORLESS_ENERGY - jr z, .colorless - -; color energy -; decrease respective attached energy by 1. - ld hl, wAttachedEnergies - dec a - ld c, a - ld b, $00 - add hl, bc - dec [hl] - ld hl, wTotalAttachedEnergies - dec [hl] - jr .asm_1570c -; decrease attached colorless by 2. -.colorless - ld hl, wAttachedEnergies + COLORLESS - dec [hl] - dec [hl] - ld hl, wTotalAttachedEnergies - dec [hl] - dec [hl] - -.asm_1570c - bank1call HandleEnergyBurn - xor a - ld [wTempLoadedAttackEnergyCost], a - ld [wTempLoadedAttackEnergyNeededAmount], a - ld [wTempLoadedAttackEnergyNeededType], a - ld hl, wAttachedEnergies - ld de, wLoadedAttackEnergyCost - ld b, 0 - ld c, (NUM_TYPES / 2) - 1 -.loop - ; check all basic energy cards except colorless - ld a, [de] - swap a - call CheckIfEnoughParticularAttachedEnergy - ld a, [de] - call CheckIfEnoughParticularAttachedEnergy - inc de - dec c - jr nz, .loop - - ld a, [de] - swap a - and $0f - ld b, a ; colorless energy still needed - ld a, [wTempLoadedAttackEnergyCost] - ld hl, wTempLoadedAttackEnergyNeededAmount - sub [hl] - ld c, a ; basic energy still needed - ld a, [wTotalAttachedEnergies] - sub c - sub b - jr c, .not_enough_energy - - ld a, [wTempLoadedAttackEnergyNeededAmount] - or a - ret z - -; being here means the energy cost isn't satisfied, -; including with colorless energy - xor a -.not_enough_energy - cpl - inc a - ld c, a ; colorless energy still needed - ld a, [wTempLoadedAttackEnergyNeededAmount] - ld b, a ; basic energy still needed - ld a, [wTempLoadedAttackEnergyNeededType] - call ConvertColorToEnergyCardID - ld e, a - ld d, 0 - scf - ret - -; zeroes a bytes starting at hl -ClearMemory_Bank5: ; 1575e (5:575e) - push af - push bc - push hl - ld b, a - xor a -.clear_loop - ld [hli], a - dec b - jr nz, .clear_loop - pop hl - pop bc - pop af - ret - -; returns in a the tens digit of value in a -CalculateByteTensDigit: ; 1576b (5:576b) - push bc - ld c, 0 -.loop - sub 10 - jr c, .done - inc c - jr .loop -.done - ld a, c - pop bc - ret - -; returns in a the result of -; dividing b by a, rounded down -; input: -; a = divisor -; b = dividend -CalculateBDividedByA_Bank5: ; 15778 (5:5778) - push bc - ld c, a - ld a, b - ld b, c - ld c, 0 -.loop - sub b - jr c, .done - inc c - jr .loop -.done - ld a, c - pop bc - ret - -; returns in a the number of energy cards attached -; to Pokémon in location held by e -; this assumes that colorless are paired so -; that one colorless energy card provides 2 colorless energy -; input: -; e = location to check, i.e. PLAY_AREA_* -; output: -; a = number of energy cards attached -CountNumberOfEnergyCardsAttached: ; 15787 (5:5787) - call GetPlayAreaCardAttachedEnergies - ld a, [wTotalAttachedEnergies] - or a - ret z - - xor a - push hl - push bc - ld b, NUM_COLORED_TYPES - ld hl, wAttachedEnergies -; sum all the attached energies -.loop - add [hl] - inc hl - dec b - jr nz, .loop - - ld b, [hl] - srl b -; counts colorless ad halves it - add b - pop bc - pop hl - ret - -; returns carry if any card with ID in e is found -; in card location in a -; input: -; a = card location to look in; -; e = card ID to look for. -; output: -; a = deck index of card found, if any -CheckIfAnyCardIDinLocation: ; 157a3 (5:57a3) - ld b, a - ld c, e - lb de, 0, 0 -.loop - ld a, DUELVARS_CARD_LOCATIONS - add e - call GetTurnDuelistVariable - cp b - jr nz, .next - ld a, e - push de - call GetCardIDFromDeckIndex - ld a, e - pop de - cp c - jr z, .set_carry -.next - inc e - ld a, DECK_SIZE - cp e - jr nz, .loop - or a - ret -.set_carry - ld a, e - scf - ret - -; counts total number of energy cards in opponent's hand -; plus all the cards attached in Turn Duelist's Play Area. -; output: -; a and wTempAI = total number of energy cards. -CountOppEnergyCardsInHandAndAttached: ; 157c6 (5:57c6) - xor a - ld [wTempAI], a - call CreateEnergyCardListFromHand - jr c, .attached - -; counts number of energy cards in hand - ld b, -1 - ld hl, wDuelTempList -.loop_hand - inc b - ld a, [hli] - cp $ff - jr nz, .loop_hand - ld a, b - ld [wTempAI], a - -; counts number of energy cards -; that are attached in Play Area -.attached - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - ld d, a - ld e, PLAY_AREA_ARENA -.loop_play_area - call CountNumberOfEnergyCardsAttached - ld hl, wTempAI - add [hl] - ld [hl], a - inc e - dec d - jr nz, .loop_play_area - ret - -; returns carry if any card with ID in e is found -; in the list that is pointed by hl. -; if one is found, it is removed from the list. -; input: -; e = card ID to look for. -; hl = list to look in -RemoveCardIDInList: ; 157f3 (5:57f3) - push hl - push de - push bc - ld c, e - -.loop_1 - ld a, [hli] - cp $ff - jr z, .no_carry - - ldh [hTempCardIndex_ff98], a - call GetCardIDFromDeckIndex - ld a, c - cp e - jr nz, .loop_1 - -; found - ld d, h - ld e, l - dec hl - -; remove this index from the list -; and reposition the rest of the list ahead. -.loop_2 - ld a, [de] - inc de - ld [hli], a - cp $ff - jr nz, .loop_2 - - ldh a, [hTempCardIndex_ff98] - pop bc - pop de - pop hl - scf - ret - -.no_carry - pop bc - pop de - pop hl - or a - ret - -; play Pokemon cards from the hand to set the starting -; Play Area of Boss decks. -; each Boss deck has two ID lists in order of preference. -; one list is for the Arena card is the other is for the Bench cards. -; if Arena card could not be set (due to hand not having any card in its list) -; or if list is null, return carry and do not play any cards. -TrySetUpBossStartingPlayArea: ; 1581b (5:581b) - ld de, wAICardListArenaPriority - ld a, d - or a - jr z, .set_carry ; return if null - -; pick Arena card - call CreateHandCardList - ld hl, wDuelTempList - ld de, wAICardListArenaPriority - call .PlayPokemonCardInOrder - ret c - -; play Pokemon cards to Bench until there are -; a maximum of 3 cards in Play Area. -.loop - ld de, wAICardListBenchPriority - call .PlayPokemonCardInOrder - jr c, .done - cp 3 - jr c, .loop - -.done - or a - ret -.set_carry - scf - ret - -; runs through input card ID list in de. -; plays to Play Area first card that is found in hand. -; returns carry if none of the cards in the list are found. -; returns number of Pokemon in Play Area in a. -.PlayPokemonCardInOrder ; 1583f (5:583f) - ld a, [de] - ld c, a - inc de - ld a, [de] - ld d, a - ld e, c - -; go in order of the list in de and -; add first card that matches ID. -; returns carry if hand doesn't have any card in list. -.loop_id_list - ld a, [de] - inc de - or a - jr z, .not_found - push de - ld e, a - call RemoveCardIDInList - pop de - jr nc, .loop_id_list - - ; play this card to Play Area and return - push hl - call PutHandPokemonCardInPlayArea - pop hl - or a - ret - -.not_found - scf - ret - -; expects a $00-terminated list of 3-byte data with the following: -; - non-zero value (anything but $1 is ignored) -; - card ID to look for in Play Area -; - number of energy cards -; returns carry if a card ID is found in bench with at least the -; listed number of energy cards -; unreferenced -Func_1585b: ; 1585b (5:585b) - ld a, [hli] - or a - jr z, .no_carry - dec a - jr nz, .next_1 - ld a, [hli] - ld b, PLAY_AREA_BENCH_1 - push hl - call LookForCardIDInPlayArea_Bank5 - jr nc, .next_2 - ld e, a - push de - call CountNumberOfEnergyCardsAttached - pop de - pop hl - ld b, [hl] - cp b - jr nc, .set_carry - inc hl - jr Func_1585b - -.next_1 - inc hl - inc hl - jr Func_1585b - -.next_2 - pop hl - inc hl - jr Func_1585b - -.no_carry - or a - ret - -.set_carry - ld a, e - scf - ret - -; expects a $00-terminated list of 3-byte data with the following: -; - non-zero value -; - card ID -; - number of energy cards -; goes through the given list and if a card with a listed ID is found -; with less than the number of energy cards corresponding to its entry -; then have AI try to play an energy card from the hand to it -; unreferenced -Func_15886: ; 15886 (5:5886) - push hl - call CreateEnergyCardListFromHand - pop hl - ret c ; quit if no energy cards in hand - -.loop_energy_cards - ld a, [hli] - or a - ret z ; done - ld a, [hli] - ld b, PLAY_AREA_ARENA - push hl - call LookForCardIDInPlayArea_Bank5 - jr nc, .next ; skip if not found in Play Area - ld e, a - push de - call CountNumberOfEnergyCardsAttached - pop de - pop hl - cp [hl] - inc hl - jr nc, .loop_energy_cards - ld a, e - ldh [hTempPlayAreaLocation_ff9d], a - push hl - call AITryToPlayEnergyCard - pop hl - ret c - jr .loop_energy_cards -.next - pop hl - inc hl - jr .loop_energy_cards - -INCLUDE "engine/ai/retreat.asm" - -; Copy cards from wDuelTempList in hl to wHandTempList in de -CopyHandCardList: ; 15ea6 (5:5ea6) - ld a, [hli] - ld [de], a - cp $ff - ret z - inc de - jr CopyHandCardList - -INCLUDE "engine/ai/hand_pokemon.asm" - -; check if player's active Pokémon is Mr Mime -; if it isn't, set carry -; if it is, check if Pokémon at a -; can damage it, and if it can, set carry -; input: -; a = location of Pokémon card -CheckDamageToMrMime: ; 16270 (5:6270) - push af - ld a, DUELVARS_ARENA_CARD - call GetNonTurnDuelistVariable - call SwapTurn - call GetCardIDFromDeckIndex - call SwapTurn - ld a, e - cp MR_MIME - pop bc - jr nz, .set_carry - ld a, b - call CheckIfCanDamageDefendingPokemon - jr c, .set_carry - or a - ret -.set_carry - scf - ret - -; returns carry if arena card -; can knock out defending Pokémon -CheckIfActiveCardCanKnockOut: ; 1628f (5:628f) - xor a - ldh [hTempPlayAreaLocation_ff9d], a - call CheckIfAnyAttackKnocksOutDefendingCard - jr nc, .fail - call CheckIfSelectedAttackIsUnusable - jp c, .fail - scf - ret - -.fail - or a - ret - -; outputs carry if any of the active Pokémon attacks -; can be used and are not residual -CheckIfActivePokemonCanUseAnyNonResidualAttack: ; 162a1 (5:62a1) - xor a ; active card - ldh [hTempPlayAreaLocation_ff9d], a -; first atk - ld [wSelectedAttack], a - call CheckIfSelectedAttackIsUnusable - jr c, .next_atk - ld a, [wLoadedAttackCategory] - and RESIDUAL - jr z, .ok - -.next_atk -; second atk - ld a, $01 - ld [wSelectedAttack], a - call CheckIfSelectedAttackIsUnusable - jr c, .fail - ld a, [wLoadedAttackCategory] - and RESIDUAL - jr z, .ok -.fail - or a - ret - -.ok - scf - ret - -; looks for energy card(s) in hand depending on -; what is needed for selected card, for both attacks -; - if one basic energy is required, look for that energy; -; - if one colorless is required, create a list at wDuelTempList -; of all energy cards; -; - if two colorless are required, look for double colorless; -; return carry if successful in finding card -; input: -; [hTempPlayAreaLocation_ff9d] = location of Pokémon card -LookForEnergyNeededInHand: ; 162c8 (5:62c8) - xor a ; first attack - ld [wSelectedAttack], a - call CheckEnergyNeededForAttack - ld a, b - add c - cp 1 - jr z, .one_energy - cp 2 - jr nz, .second_attack - ld a, c - cp 2 - jr z, .two_colorless - -.second_attack - ld a, SECOND_ATTACK - ld [wSelectedAttack], a - call CheckEnergyNeededForAttack - ld a, b - add c - cp 1 - jr z, .one_energy - cp 2 - jr nz, .no_carry - ld a, c - cp 2 - jr z, .two_colorless -.no_carry - or a - ret - -.one_energy - ld a, b - or a - jr z, .one_colorless - ld a, e - call LookForCardIDInHandList_Bank5 - ret c - jr .no_carry - -.one_colorless - call CreateEnergyCardListFromHand - jr c, .no_carry - scf - ret - -.two_colorless - ld a, DOUBLE_COLORLESS_ENERGY - call LookForCardIDInHandList_Bank5 - ret c - jr .no_carry - -; looks for energy card(s) in hand depending on -; what is needed for selected card and attack -; - if one basic energy is required, look for that energy; -; - if one colorless is required, create a list at wDuelTempList -; of all energy cards; -; - if two colorless are required, look for double colorless; -; return carry if successful in finding card -; input: -; [hTempPlayAreaLocation_ff9d] = location of Pokémon card -; [wSelectedAttack] = selected attack to examine -LookForEnergyNeededForAttackInHand: ; 16311 (5:6311) - call CheckEnergyNeededForAttack - ld a, b - add c - cp 1 - jr z, .one_energy - cp 2 - jr nz, .done - ld a, c - cp 2 - jr z, .two_colorless -.done - or a - ret - -.one_energy - ld a, b - or a - jr z, .one_colorless - ld a, e - call LookForCardIDInHandList_Bank5 - ret c - jr .done - -.one_colorless - call CreateEnergyCardListFromHand - jr c, .done - scf - ret - -.two_colorless - ld a, DOUBLE_COLORLESS_ENERGY - call LookForCardIDInHandList_Bank5 - ret c - jr .done - -; goes through $00 terminated list pointed -; by wAICardListPlayFromHandPriority and compares it to each card in hand. -; Sorts the hand in wDuelTempList so that the found card IDs -; are in the same order as the list pointed by de. -SortTempHandByIDList: ; 1633f (5:633f) - ld a, [wAICardListPlayFromHandPriority+1] - or a - ret z ; return if list is empty - -; start going down the ID list - ld d, a - ld a, [wAICardListPlayFromHandPriority] - ld e, a - ld c, 0 -.loop_list_id -; get this item's ID -; if $00, list has ended - ld a, [de] - or a - ret z ; return when list is over - inc de - ld hl, wDuelTempList - ld b, 0 - add hl, bc - ld b, a - -; search in the hand card list -.next_hand_card - ld a, [hl] - ldh [hTempCardIndex_ff98], a - cp -1 - jr z, .loop_list_id - push bc - push de - call GetCardIDFromDeckIndex - ld a, e - pop de - pop bc - cp b - jr nz, .not_same - -; found -; swap this hand card with the spot -; in hand corresponding to c - push bc - push hl - ld b, 0 - ld hl, wDuelTempList - add hl, bc - ld b, [hl] - ldh a, [hTempCardIndex_ff98] - ld [hl], a - pop hl - ld [hl], b - pop bc - inc c -.not_same - inc hl - jr .next_hand_card - -; looks for energy card(s) in list at wDuelTempList -; depending on energy flags set in a -; return carry if successful in finding card -; input: -; a = energy flags needed -CheckEnergyFlagsNeededInList: ; 1637b (5:637b) - ld e, a - ld hl, wDuelTempList -.next_card - ld a, [hli] - cp $ff - jr z, .no_carry - push de - call GetCardIDFromDeckIndex - ld a, e - pop de - -; fire - cp FIRE_ENERGY - jr nz, .grass - ld a, FIRE_F - jr .check_energy -.grass - cp GRASS_ENERGY - jr nz, .lightning - ld a, GRASS_F - jr .check_energy -.lightning - cp LIGHTNING_ENERGY - jr nz, .water - ld a, LIGHTNING_F - jr .check_energy -.water - cp WATER_ENERGY - jr nz, .fighting - ld a, WATER_F - jr .check_energy -.fighting - cp FIGHTING_ENERGY - jr nz, .psychic - ld a, FIGHTING_F - jr .check_energy -.psychic - cp PSYCHIC_ENERGY - jr nz, .colorless - ld a, PSYCHIC_F - jr .check_energy -.colorless - cp DOUBLE_COLORLESS_ENERGY - jr nz, .next_card - ld a, COLORLESS_F - -; if energy card matches required energy, return carry -.check_energy - ld d, e - and e - ld e, d - jr z, .next_card - scf - ret -.no_carry - or a - ret - -; returns in a the energy cost of both attacks from card index in a -; represented by energy flags -; i.e. each bit represents a different energy type cost -; if any colorless energy is required, all bits are set -; input: -; a = card index -; output: -; a = bits of each energy requirement -GetAttacksEnergyCostBits: ; 163c9 (5:63c9) - call LoadCardDataToBuffer2_FromDeckIndex - ld hl, wLoadedCard2Atk1EnergyCost - call GetEnergyCostBits - ld b, a - - push bc - ld hl, wLoadedCard2Atk2EnergyCost - call GetEnergyCostBits - pop bc - or b - ret - -; returns in a the energy cost of an attack in [hl] -; represented by energy flags -; i.e. each bit represents a different energy type cost -; if any colorless energy is required, all bits are set -; input: -; [hl] = Loaded card attack energy cost -; output: -; a = bits of each energy requirement -GetEnergyCostBits: ; 163dd (5:63dd) - ld c, $00 - ld a, [hli] - ld b, a - -; fire - and $f0 - jr z, .grass - ld c, FIRE_F -.grass - ld a, b - and $0f - jr z, .lightning - ld a, GRASS_F - or c - ld c, a -.lightning - ld a, [hli] - ld b, a - and $f0 - jr z, .water - ld a, LIGHTNING_F - or c - ld c, a -.water - ld a, b - and $0f - jr z, .fighting - ld a, WATER_F - or c - ld c, a -.fighting - ld a, [hli] - ld b, a - and $f0 - jr z, .psychic - ld a, FIGHTING_F - or c - ld c, a -.psychic - ld a, b - and $0f - jr z, .colorless - ld a, PSYCHIC_F - or c - ld c, a -.colorless - ld a, [hli] - ld b, a - and $f0 - jr z, .done - ld a, %11111111 - or c ; unnecessary - ld c, a -.done - ld a, c - ret - -; set carry flag if any card in -; wDuelTempList evolves card index in a -; if found, the evolution card index is returned in a -; input: -; a = card index to check evolution -; output: -; a = card index of evolution found -CheckForEvolutionInList: ; 16422 (5:6422) - ld b, a - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - - push af - ld [hl], b - ld hl, wDuelTempList -.loop - ld a, [hli] - cp $ff - jr z, .no_carry - ld d, a - ld e, PLAY_AREA_ARENA - push de - push hl - call CheckIfCanEvolveInto - pop hl - pop de - jr c, .loop - - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - pop af - ld [hl], a - ld a, d - scf - ret - -.no_carry - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - pop af - ld [hl], a - or a - ret - -; set carry if it finds an evolution for -; the card index in a in the deck -; if found, return that evolution card index in a -; input: -; a = card index to check evolution -; output: -; a = card index of evolution found -CheckForEvolutionInDeck: ; 16451 (5:6451) - ld b, a - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - - push af - ld [hl], b - ld e, 0 -.loop - ld a, DUELVARS_CARD_LOCATIONS - add e - call GetTurnDuelistVariable - cp CARD_LOCATION_DECK - jr nz, .not_in_deck - push de - ld d, e - ld e, PLAY_AREA_ARENA - call CheckIfCanEvolveInto - pop de - jr nc, .set_carry - -; exit when it gets to the prize cards -.not_in_deck - inc e - ld a, DUELVARS_PRIZE_CARDS - cp e - jr nz, .loop - - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - pop af - ld [hl], a - or a - ret - -.set_carry - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - pop af - ld [hl], a - ld a, e - scf - ret - -INCLUDE "engine/ai/energy.asm" - -INCLUDE "engine/ai/attacks.asm" - -INCLUDE "engine/ai/special_attacks.asm" - -; checks in other Play Area for non-basic cards. -; afterwards, that card is checked for damage, -; and if the damage counters it has is greater than or equal -; to the max HP of the card stage below it, -; return carry and that card's Play Area location in a. -; output: -; a = card location of Pokémon card, if found; -; carry set if such a card is found. -LookForCardThatIsKnockedOutOnDevolution: ; 17080 (5:7080) - ldh a, [hTempPlayAreaLocation_ff9d] - push af - call SwapTurn - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - ld b, a - ld c, PLAY_AREA_ARENA - -.loop - ld a, c - ldh [hTempPlayAreaLocation_ff9d], a - push bc - bank1call GetCardOneStageBelow - pop bc - jr c, .next - ; is not a basic card - ; compare its HP with current damage - ld a, d - push bc - call LoadCardDataToBuffer2_FromDeckIndex - pop bc - ld a, [wLoadedCard2HP] - ld [wTempAI], a - ld e, c - push bc - call GetCardDamageAndMaxHP - pop bc - ld e, a - ld a, [wTempAI] - cp e - jr c, .set_carry - jr z, .set_carry -.next - inc c - ld a, c - cp b - jr nz, .loop - - call SwapTurn - pop af - ldh [hTempPlayAreaLocation_ff9d], a - or a - ret - -.set_carry - call SwapTurn - pop af - ldh [hTempPlayAreaLocation_ff9d], a - ld a, c - scf - ret - -; returns carry if the following conditions are met: -; - arena card HP >= half max HP -; - arena card Unknown2's 4 bit is not set or -; is set but there's no evolution of card in hand/deck -; - arena card can use second attack -CheckIfArenaCardIsAtHalfHPCanEvolveAndUseSecondAttack: ; 170c9 (5:70c9) - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - ld d, a - push de - call LoadCardDataToBuffer1_FromDeckIndex - ld a, DUELVARS_ARENA_CARD_HP - call GetTurnDuelistVariable - ld d, a - ld a, [wLoadedCard1HP] - rrca - cp d - pop de - jr nc, .no_carry - - ld a, [wLoadedCard1Unknown2] - and %00010000 - jr z, .check_second_attack - ld a, d - call CheckCardEvolutionInHandOrDeck - jr c, .no_carry - -.check_second_attack - xor a ; active card - ldh [hTempPlayAreaLocation_ff9d], a - ld a, SECOND_ATTACK - ld [wSelectedAttack], a - push hl - call CheckIfSelectedAttackIsUnusable - pop hl - jr c, .no_carry - scf - ret -.no_carry - or a - ret - -; count Pokemon in the Bench that -; meet the following conditions: -; - card HP > half max HP -; - card Unknown2's 4 bit is not set or -; is set but there's no evolution of card in hand/deck -; - card can use second attack -; Outputs the number of Pokémon in bench -; that meet these requirements in a -; and returns carry if at least one is found -CountNumberOfSetUpBenchPokemon: ; 17101 (5:7101) - ldh a, [hTempPlayAreaLocation_ff9d] - ld d, a - ld a, [wSelectedAttack] - ld e, a - push de - ld a, DUELVARS_BENCH - call GetTurnDuelistVariable - lb bc, 0, 0 - push hl - -.next - inc c - pop hl - ld a, [hli] - push hl - cp $ff - jr z, .done - - ld d, a - push de - push bc - call LoadCardDataToBuffer1_FromDeckIndex - pop bc - -; compares card's current HP with max HP - ld a, c - add DUELVARS_ARENA_CARD_HP - call GetTurnDuelistVariable - ld d, a - ld a, [wLoadedCard1HP] - rrca - -; a = max HP / 2 -; d = current HP -; jumps if (current HP) <= (max HP / 2) - cp d - pop de - jr nc, .next - - ld a, [wLoadedCard1Unknown2] - and $10 - jr z, .check_second_attack - - ld a, d - push bc - call CheckCardEvolutionInHandOrDeck - pop bc - jr c, .next - -.check_second_attack - ld a, c - ldh [hTempPlayAreaLocation_ff9d], a - ld a, SECOND_ATTACK - ld [wSelectedAttack], a - push bc - push hl - call CheckIfSelectedAttackIsUnusable - pop hl - pop bc - jr c, .next - inc b - jr .next - -.done - pop hl - pop de - ld a, e - ld [wSelectedAttack], a - ld a, d - ldh [hTempPlayAreaLocation_ff9d], a - ld a, b - or a - ret z - scf - ret - -; handles AI logic to determine some selections regarding certain attacks, -; if any of these attacks were chosen to be used. -; returns carry if selection was successful, -; and no carry if unable to make one. -; outputs in hTempPlayAreaLocation_ffa1 the chosen parameter. -AISelectSpecialAttackParameters: ; 17161 (5:7161) - ld a, [wSelectedAttack] - push af - call .SelectAttackParameters - pop bc - ld a, b - ld [wSelectedAttack], a - ret - -.SelectAttackParameters: ; 1716e (5:716e) - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call GetCardIDFromDeckIndex - ld a, e - cp MEW3 - jr z, .DevolutionBeam - cp MEWTWO3 - jr z, .EnergyAbsorption - cp MEWTWO2 - jr z, .EnergyAbsorption - cp EXEGGUTOR - jr z, .Teleport - cp ELECTRODE1 - jr z, .EnergySpike - ; fallthrough - -.no_carry - or a - ret - -.DevolutionBeam -; in case selected attack is Devolution Beam -; store in hTempPlayAreaLocation_ffa1 -; the location of card to select to devolve - ld a, [wSelectedAttack] - or a - jp z, .no_carry ; can be jr - - ld a, $01 - ldh [hTemp_ffa0], a - call LookForCardThatIsKnockedOutOnDevolution - ldh [hTempPlayAreaLocation_ffa1], a - -.set_carry_1 - scf - ret - -.EnergyAbsorption -; in case selected attack is Energy Absorption -; make list from energy cards in Discard Pile - ld a, [wSelectedAttack] - or a - jp nz, .no_carry ; can be jr - - ld a, $ff - ldh [hTempPlayAreaLocation_ffa1], a - ldh [hTempRetreatCostCards], a - -; search for Psychic energy cards in Discard Pile - ld e, PSYCHIC_ENERGY - ld a, CARD_LOCATION_DISCARD_PILE - call CheckIfAnyCardIDinLocation - ldh [hTemp_ffa0], a - farcall CreateEnergyCardListFromDiscardPile_AllEnergy - -; find any energy card different from -; the one found by CheckIfAnyCardIDinLocation. -; since using this attack requires a Psychic energy card, -; and another one is in hTemp_ffa0, -; then any other energy card would account -; for the Energy Cost of Psyburn. - ld hl, wDuelTempList -.loop_energy_cards - ld a, [hli] - cp $ff - jr z, .set_carry_2 - ld b, a - ldh a, [hTemp_ffa0] - cp b - jr z, .loop_energy_cards ; same card, keep looking - -; store the deck index of energy card found - ld a, b - ldh [hTempPlayAreaLocation_ffa1], a - ; fallthrough - -.set_carry_2 - scf - ret - -.Teleport -; in case selected attack is Teleport -; decide Bench card to switch to. - ld a, [wSelectedAttack] - or a - jp nz, .no_carry ; can be jr - call AIDecideBenchPokemonToSwitchTo - jr c, .no_carry - ldh [hTemp_ffa0], a - scf - ret - -.EnergySpike -; in case selected attack is Energy Spike -; decide basic energy card to fetch from Deck. - ld a, [wSelectedAttack] - or a - jp z, .no_carry ; can be jr - - ld a, CARD_LOCATION_DECK - ld e, LIGHTNING_ENERGY - -; if none were found in Deck, return carry... - call CheckIfAnyCardIDinLocation - ldh [hTemp_ffa0], a - jp nc, .no_carry ; can be jr - -; ...else find a suitable Play Area Pokemon to -; attach the energy card to. - call AIProcessButDontPlayEnergy_SkipEvolution - jp nc, .no_carry ; can be jr - ldh a, [hTempPlayAreaLocation_ff9d] - ldh [hTempPlayAreaLocation_ffa1], a - scf - ret - -; return carry if Pokémon at play area location -; in hTempPlayAreaLocation_ff9d does not have -; energy required for the attack index in wSelectedAttack -; or has exactly the same amount of energy needed -; input: -; [hTempPlayAreaLocation_ff9d] = play area location -; [wSelectedAttack] = attack index to check -; output: -; a = number of extra energy cards attached -CheckIfNoSurplusEnergyForAttack: ; 171fb (5:71fb) - ldh a, [hTempPlayAreaLocation_ff9d] - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - ld d, a - ld a, [wSelectedAttack] - ld e, a - call CopyAttackDataAndDamage_FromDeckIndex - ld hl, wLoadedAttackName - ld a, [hli] - or [hl] - jr z, .not_attack - ld a, [wLoadedAttackCategory] - cp POKEMON_POWER - jr nz, .is_attack -.not_attack - scf - ret - -.is_attack - ldh a, [hTempPlayAreaLocation_ff9d] - ld e, a - call GetPlayAreaCardAttachedEnergies - bank1call HandleEnergyBurn - xor a - ld [wTempLoadedAttackEnergyCost], a - ld [wTempLoadedAttackEnergyNeededAmount], a - ld [wTempLoadedAttackEnergyNeededType], a - ld hl, wAttachedEnergies - ld de, wLoadedAttackEnergyCost - ld b, 0 - ld c, (NUM_TYPES / 2) - 1 -.loop - ; check all basic energy cards except colorless - ld a, [de] - swap a - call CalculateParticularAttachedEnergyNeeded - ld a, [de] - call CalculateParticularAttachedEnergyNeeded - inc de - dec c - jr nz, .loop - - ; colorless - ld a, [de] - swap a - and %00001111 - ld b, a - ld hl, wTempLoadedAttackEnergyCost - ld a, [wTotalAttachedEnergies] - sub [hl] - sub b - ret c ; return if not enough energy - - or a - ret nz ; return if surplus energy - - ; exactly the amount of energy needed - scf - ret - -; takes as input the energy cost of an attack for a -; particular energy, stored in the lower nibble of a -; if the attack costs some amount of this energy, the lower nibble of a != 0, -; and this amount is stored in wTempLoadedAttackEnergyCost -; also adds the amount of energy still needed -; to wTempLoadedAttackEnergyNeededAmount -; input: -; a = this energy cost of attack (lower nibble) -; [hl] = attached energy -; output: -; carry set if not enough of this energy type attached -CalculateParticularAttachedEnergyNeeded: ; 17258 (5:7258) - and %00001111 - jr nz, .check -.done - inc hl - inc b - ret - -.check - ld [wTempLoadedAttackEnergyCost], a - sub [hl] - jr z, .done - jr nc, .done - push bc - ld a, [wTempLoadedAttackEnergyCost] - ld b, a - ld a, [hl] - sub b - pop bc - ld [wTempLoadedAttackEnergyNeededAmount], a - jr .done - -; return carry if there is a card that -; can evolve a Pokémon in hand or deck. -; input: -; a = deck index of card to check; -; output: -; a = deck index of evolution in hand, if found; -; carry set if there's a card in hand that can evolve. -CheckCardEvolutionInHandOrDeck: ; 17274 (5:7274) - ld b, a - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - push af - ld [hl], b - ld e, 0 - -.loop - ld a, DUELVARS_CARD_LOCATIONS - add e - call GetTurnDuelistVariable - cp CARD_LOCATION_DECK - jr z, .deck_or_hand - cp CARD_LOCATION_HAND - jr nz, .next -.deck_or_hand - push de - ld d, e - ld e, PLAY_AREA_ARENA - call CheckIfCanEvolveInto - pop de - jr nc, .set_carry -.next - inc e - ld a, DECK_SIZE - cp e - jr nz, .loop - - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - pop af - ld [hl], a - or a - ret - -.set_carry - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - pop af - ld [hl], a - ld a, e - scf - ret - -INCLUDE "engine/ai/boss_deck_set_up.asm" - -; returns carry if Pokemon at PLAY_AREA* in a -; can damage defending Pokémon with any of its attacks -; input: -; a = location of card to check -CheckIfCanDamageDefendingPokemon: ; 17383 (5:7383) - ldh [hTempPlayAreaLocation_ff9d], a - xor a ; first attack - ld [wSelectedAttack], a - call CheckIfSelectedAttackIsUnusable - jr c, .second_attack - xor a - call EstimateDamage_VersusDefendingCard - ld a, [wDamage] - or a - jr nz, .set_carry - -.second_attack - ld a, SECOND_ATTACK - ld [wSelectedAttack], a - call CheckIfSelectedAttackIsUnusable - jr c, .no_carry - ld a, $01 - call EstimateDamage_VersusDefendingCard - ld a, [wDamage] - or a - jr nz, .set_carry - -.no_carry - or a - ret -.set_carry - scf - ret - -; checks if defending Pokémon can knock out -; card at hTempPlayAreaLocation_ff9d with any of its attacks -; and if so, stores the damage to wce00 and wce01 -; sets carry if any on the attacks knocks out -; also outputs the largest damage dealt in a -; input: -; [hTempPlayAreaLocation_ff9d] = location of card to check -; output: -; a = largest damage of both attacks -; carry set if can knock out -CheckIfDefendingPokemonCanKnockOut: ; 173b1 (5:73b1) - xor a ; first attack - ld [wce00], a - ld [wce01], a - call CheckIfDefendingPokemonCanKnockOutWithAttack - jr nc, .second_attack - ld a, [wDamage] - ld [wce00], a - -.second_attack - ld a, SECOND_ATTACK - call CheckIfDefendingPokemonCanKnockOutWithAttack - jr nc, .return_if_neither_kos - ld a, [wDamage] - ld [wce01], a - jr .compare - -.return_if_neither_kos - ld a, [wce00] - or a - ret z - -.compare - ld a, [wce00] - ld b, a - ld a, [wce01] - cp b - jr nc, .set_carry - ld a, b -.set_carry - scf - ret - -; return carry if defending Pokémon can knock out -; card at hTempPlayAreaLocation_ff9d -; input: -; a = attack index -; [hTempPlayAreaLocation_ff9d] = location of card to check -CheckIfDefendingPokemonCanKnockOutWithAttack: ; 173e4 (5:73e4) - ld [wSelectedAttack], a - ldh a, [hTempPlayAreaLocation_ff9d] - push af - xor a - ldh [hTempPlayAreaLocation_ff9d], a - call SwapTurn - call CheckIfSelectedAttackIsUnusable - call SwapTurn - pop bc - ld a, b - ldh [hTempPlayAreaLocation_ff9d], a - jr c, .done - -; player's active Pokémon can use attack - ld a, [wSelectedAttack] - call EstimateDamage_FromDefendingPokemon - ldh a, [hTempPlayAreaLocation_ff9d] - add DUELVARS_ARENA_CARD_HP - call GetTurnDuelistVariable - ld hl, wDamage - sub [hl] - jr z, .set_carry - ret - -.set_carry - scf - ret - -.done - or a - ret - -; sets carry if Opponent's deck ID -; is between LEGENDARY_MOLTRES_DECK_ID (inclusive) -; and MUSCLES_FOR_BRAINS_DECK_ID (exclusive) -; these are the decks for Grandmaster/Club Master/Ronald -CheckIfOpponentHasBossDeckID: ; 17414 (5:7414) - push af - ld a, [wOpponentDeckID] - cp LEGENDARY_MOLTRES_DECK_ID - jr c, .no_carry - cp MUSCLES_FOR_BRAINS_DECK_ID - jr nc, .no_carry - pop af - scf - ret - -.no_carry - pop af - or a - ret - -; sets carry if not a boss fight -; and if hasn't received legendary cards yet -CheckIfNotABossDeckID: ; 17426 (5:7426) - call EnableSRAM - ld a, [sReceivedLegendaryCards] - call DisableSRAM - or a - jr nz, .no_carry - call CheckIfOpponentHasBossDeckID - jr nc, .set_carry -.no_carry - or a - ret - -.set_carry - scf - ret - -; probability to return carry: -; - 50% if deck AI is playing is on the list; -; - 25% for all other decks; -; - 0% for boss decks. -; used for certain decks to randomly choose -; not to play Trainer card or use PKMN Power -AIChooseRandomlyNotToDoAction: ; 1743b (5:743b) -; boss decks always use Trainer cards. - push hl - push de - call CheckIfNotABossDeckID - jr c, .check_deck - pop de - pop hl - ret - -.check_deck - ld a, [wOpponentDeckID] - cp MUSCLES_FOR_BRAINS_DECK_ID - jr z, .carry_50_percent - cp BLISTERING_POKEMON_DECK_ID - jr z, .carry_50_percent - cp WATERFRONT_POKEMON_DECK_ID - jr z, .carry_50_percent - cp BOOM_BOOM_SELFDESTRUCT_DECK_ID - jr z, .carry_50_percent - cp KALEIDOSCOPE_DECK_ID - jr z, .carry_50_percent - cp RESHUFFLE_DECK_ID - jr z, .carry_50_percent - -; carry 25 percent - ld a, 4 - call Random - cp 1 - pop de - pop hl - ret - -.carry_50_percent - ld a, 4 - call Random - cp 2 - pop de - pop hl - ret - -; checks if any bench Pokémon has same ID -; as input, and sets carry if it has more than -; half health and can use its second attack -; input: -; a = card ID to check for -; output: -; carry set if the above requirements are met -CheckForBenchIDAtHalfHPAndCanUseSecondAttack: ; 17474 (5:7474) - ld [wcdf9], a - ldh a, [hTempPlayAreaLocation_ff9d] - ld d, a - ld a, [wSelectedAttack] - ld e, a - push de - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - lb bc, 0, PLAY_AREA_ARENA - push hl - -.loop - inc c - pop hl - ld a, [hli] - push hl - cp $ff - jr z, .done - ld d, a - push de - push bc - call LoadCardDataToBuffer1_FromDeckIndex - pop bc - ld a, c - add DUELVARS_ARENA_CARD_HP - call GetTurnDuelistVariable - ld d, a - ld a, [wLoadedCard1HP] - rrca - cp d - pop de - jr nc, .loop - ; half max HP < current HP - ld a, [wLoadedCard1ID] - ld hl, wcdf9 - cp [hl] - jr nz, .loop - - ld a, c - ldh [hTempPlayAreaLocation_ff9d], a - ld a, SECOND_ATTACK - ld [wSelectedAttack], a - push bc - call CheckIfSelectedAttackIsUnusable - pop bc - jr c, .loop - inc b -.done - pop hl - pop de - ld a, e - ld [wSelectedAttack], a - ld a, d - ldh [hTempPlayAreaLocation_ff9d], a - ld a, b - or a - ret z - scf - ret - -; add 5 to wPlayAreaEnergyAIScore AI score corresponding to all cards -; in bench that have same ID as register a -; input: -; a = card ID to look for -RaiseAIScoreToAllMatchingIDsInBench: ; 174cd (5:74cd) - ld d, a - ld a, DUELVARS_BENCH - call GetTurnDuelistVariable - ld e, 0 -.loop - inc e - ld a, [hli] - cp $ff - ret z - push de - call GetCardIDFromDeckIndex - ld a, e - pop de - cp d - jr nz, .loop - ld c, e - ld b, $00 - push hl - ld hl, wPlayAreaEnergyAIScore - add hl, bc - ld a, 5 - add [hl] - ld [hl], a - pop hl - jr .loop - -; goes through each play area Pokémon, and -; for all cards of the same ID, determine which -; card has highest value calculated from Func_17583 -; the card with highest value gets increased wPlayAreaEnergyAIScore -; while all others get decreased wPlayAreaEnergyAIScore -Func_174f2: ; 174f2 (5:74f2) - ld a, MAX_PLAY_AREA_POKEMON - ld hl, wcdfa - call ClearMemory_Bank5 - ld a, DUELVARS_BENCH - call GetTurnDuelistVariable - ld e, 0 - -.loop_play_area - push hl - ld a, MAX_PLAY_AREA_POKEMON - ld hl, wcdea - call ClearMemory_Bank5 - pop hl - inc e - ld a, [hli] - cp $ff - ret z - - ld [wcdf9], a - push de - push hl - -; checks wcdfa + play area location in e -; if != 0, go to next in play area - ld d, $00 - ld hl, wcdfa - add hl, de - ld a, [hl] - or a - pop hl - pop de - jr nz, .loop_play_area - -; loads wcdf9 with card ID -; and call Func_17583 - push de - ld a, [wcdf9] - call GetCardIDFromDeckIndex - ld a, e - ld [wcdf9], a - pop de - push hl - push de - call Func_17583 - -; check play area Pokémon ahead -; if there is a card with the same ID, -; call Func_17583 for it as well -.loop_1 - inc e - ld a, [hli] - cp $ff - jr z, .check_if_repeated_id - push de - call GetCardIDFromDeckIndex - ld a, [wcdf9] - cp e - pop de - jr nz, .loop_1 - call Func_17583 - jr .loop_1 - -; if there are more than 1 of the same ID -; in play area, iterate bench backwards -; and determines which card has highest -; score in wcdea -.check_if_repeated_id - call Func_175a8 - jr c, .next - lb bc, 0, 0 - ld hl, wcdea + MAX_BENCH_POKEMON - ld d, MAX_PLAY_AREA_POKEMON -.loop_2 - dec d - jr z, .asm_17560 - ld a, [hld] - cp b - jr c, .loop_2 - ld b, a - ld c, d - jr .loop_2 - -; c = play area location of highest score -; decrease wPlayAreaEnergyAIScore score for all cards with same ID -; except for the one with highest score -; increase wPlayAreaEnergyAIScore score for card with highest ID -.asm_17560 - ld hl, wPlayAreaEnergyAIScore - ld de, wcdea - ld b, PLAY_AREA_ARENA -.loop_3 - ld a, c - cp b - jr z, .card_with_highest - ld a, [de] - or a - jr z, .check_next -; decrease score - dec [hl] - jr .check_next -.card_with_highest -; increase score - inc [hl] -.check_next - inc b - ld a, MAX_PLAY_AREA_POKEMON - cp b - jr z, .next - inc de - inc hl - jr .loop_3 - -.next - pop de - pop hl - jp .loop_play_area - -; loads wcdea + play area location in e -; with energy * 2 + $80 - floor(dam / 10) -; loads wcdfa + play area location in e -; with $01 -Func_17583: ; 17583 (5:7583) - push hl - push de - call GetCardDamageAndMaxHP - call CalculateByteTensDigit - ld b, a - push bc - call CountNumberOfEnergyCardsAttached - pop bc - sla a - add $80 - sub b - pop de - push de - ld d, $00 - ld hl, wcdea - add hl, de - ld [hl], a - ld hl, wcdfa - add hl, de - ld [hl], $01 - pop de - pop hl - ret - -; counts how many play area locations in wcdea -; are != 0, and outputs result in a -; also returns carry if result is < 2 -Func_175a8: ; 175a8 (5:75a8) - ld hl, wcdea - ld d, $00 - ld e, MAX_PLAY_AREA_POKEMON + 1 -.loop - dec e - jr z, .done - ld a, [hli] - or a - jr z, .loop - inc d - jr .loop -.done - ld a, d - cp 2 - ret - -; handle how AI scores giving out Energy Cards -; when using Legendary Articuno deck -HandleLegendaryArticunoEnergyScoring: ; 175bd (5:75bd) - ld a, [wOpponentDeckID] - cp LEGENDARY_ARTICUNO_DECK_ID - jr z, .articuno_deck - ret -.articuno_deck - call ScoreLegendaryArticunoCards - ret diff --git a/src/engine/ai/damage_calculation.asm b/src/engine/ai/damage_calculation.asm deleted file mode 100644 index 97c24b6..0000000 --- a/src/engine/ai/damage_calculation.asm +++ /dev/null @@ -1,450 +0,0 @@ -; stores in wDamage, wAIMinDamage and wAIMaxDamage the calculated damage -; done to the defending Pokémon by a given card and attack -; input: -; a = attack index to take into account -; [hTempPlayAreaLocation_ff9d] = location of attacking card to consider -EstimateDamage_VersusDefendingCard: ; 143e5 (5:43e5) - ld [wSelectedAttack], a - ld e, a - ldh a, [hTempPlayAreaLocation_ff9d] - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - ld d, a - call CopyAttackDataAndDamage_FromDeckIndex - ld a, [wLoadedAttackCategory] - cp POKEMON_POWER - jr nz, .is_attack - -; is a Pokémon Power -; set wDamage, wAIMinDamage and wAIMaxDamage to zero - ld hl, wDamage - xor a - ld [hli], a - ld [hl], a - ld [wAIMinDamage], a - ld [wAIMaxDamage], a - ld e, a - ld d, a - ret - -.is_attack -; set wAIMinDamage and wAIMaxDamage to damage of attack -; these values take into account the range of damage -; that the attack can span (e.g. min and max number of hits) - ld a, [wDamage] - ld [wAIMinDamage], a - ld [wAIMaxDamage], a - ld a, EFFECTCMDTYPE_AI - call TryExecuteEffectCommandFunction - ld a, [wAIMinDamage] - ld hl, wAIMaxDamage - or [hl] - jr nz, .calculation - ld a, [wDamage] - ld [wAIMinDamage], a - ld [wAIMaxDamage], a - -.calculation -; if temp. location is active, damage calculation can be done directly... - ldh a, [hTempPlayAreaLocation_ff9d] - or a - jr z, CalculateDamage_VersusDefendingPokemon - -; ...otherwise substatuses need to be temporarily reset to account -; for the switching, to obtain the right damage calculation... - ; reset substatus1 - ld a, DUELVARS_ARENA_CARD_SUBSTATUS1 - call GetTurnDuelistVariable - push af - push hl - ld [hl], $00 - ; reset substatus2 - ld l, DUELVARS_ARENA_CARD_SUBSTATUS2 - ld a, [hl] - push af - push hl - ld [hl], $00 - ; reset changed resistance - ld l, DUELVARS_ARENA_CARD_CHANGED_RESISTANCE - ld a, [hl] - push af - push hl - ld [hl], $00 - call CalculateDamage_VersusDefendingPokemon -; ...and subsequently recovered to continue the duel normally - pop hl - pop af - ld [hl], a - pop hl - pop af - ld [hl], a - pop hl - pop af - ld [hl], a - ret - -; calculates the damage that will be dealt to the player's active card -; using the card that is located in hTempPlayAreaLocation_ff9d -; taking into account weakness/resistance/pluspowers/defenders/etc -; and outputs the result capped at a max of $ff -; input: -; [wAIMinDamage] = base damage -; [wAIMaxDamage] = base damage -; [wDamage] = base damage -; [hTempPlayAreaLocation_ff9d] = turn holder's card location as the attacker -CalculateDamage_VersusDefendingPokemon: ; 14453 (5:4453) - ld hl, wAIMinDamage - call _CalculateDamage_VersusDefendingPokemon - ld hl, wAIMaxDamage - call _CalculateDamage_VersusDefendingPokemon - ld hl, wDamage -; fallthrough - -_CalculateDamage_VersusDefendingPokemon: ; 14462 (5:4462) - ld e, [hl] - ld d, $00 - push hl - - ; load this card's data - ldh a, [hTempPlayAreaLocation_ff9d] - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call LoadCardDataToBuffer2_FromDeckIndex - ld a, [wLoadedCard2ID] - ld [wTempTurnDuelistCardID], a - - ; load player's arena card data - call SwapTurn - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call LoadCardDataToBuffer2_FromDeckIndex - ld a, [wLoadedCard2ID] - ld [wTempNonTurnDuelistCardID], a - call SwapTurn - - push de - call HandleNoDamageOrEffectSubstatus - pop de - jr nc, .vulnerable - ; invulnerable to damage - ld de, $0 - jr .done -.vulnerable - ldh a, [hTempPlayAreaLocation_ff9d] - or a - call z, HandleDoubleDamageSubstatus - ; skips the weak/res checks if unaffected. - bit UNAFFECTED_BY_WEAKNESS_RESISTANCE_F, d - res UNAFFECTED_BY_WEAKNESS_RESISTANCE_F, d - jr nz, .not_resistant - -; handle weakness - ldh a, [hTempPlayAreaLocation_ff9d] - call GetPlayAreaCardColor - call TranslateColorToWR - ld b, a - call SwapTurn - call GetArenaCardWeakness - call SwapTurn - and b - jr z, .not_weak - ; double de - sla e - rl d - -.not_weak -; handle resistance - call SwapTurn - call GetArenaCardResistance - call SwapTurn - and b - jr z, .not_resistant - ld hl, -30 - add hl, de - ld e, l - ld d, h - -.not_resistant - ; apply pluspower and defender boosts - ldh a, [hTempPlayAreaLocation_ff9d] - add CARD_LOCATION_ARENA - ld b, a - call ApplyAttachedPluspower - call SwapTurn - ld b, CARD_LOCATION_ARENA - call ApplyAttachedDefender - call HandleDamageReduction - ; test if de underflowed - bit 7, d - jr z, .no_underflow - ld de, $0 - -.no_underflow - ld a, DUELVARS_ARENA_CARD_STATUS - call GetTurnDuelistVariable - and DOUBLE_POISONED - jr z, .not_poisoned - ld c, 20 - and DOUBLE_POISONED & (POISONED ^ $ff) - jr nz, .add_poison - ld c, 10 -.add_poison - ld a, c - add e - ld e, a - ld a, $00 - adc d - ld d, a -.not_poisoned - call SwapTurn - -.done - pop hl - ld [hl], e - ld a, d - or a - ret z - ; cap damage - ld a, $ff - ld [hl], a - ret - -; stores in wDamage, wAIMinDamage and wAIMaxDamage the calculated damage -; done to the Pokémon at hTempPlayAreaLocation_ff9d -; by the defending Pokémon, using the attack index at a -; input: -; a = attack index -; [hTempPlayAreaLocation_ff9d] = location of card to calculate -; damage as the receiver -EstimateDamage_FromDefendingPokemon: ; 1450b (5:450b) - call SwapTurn - ld [wSelectedAttack], a - ld e, a - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - ld d, a - call CopyAttackDataAndDamage_FromDeckIndex - call SwapTurn - ld a, [wLoadedAttackCategory] - cp POKEMON_POWER - jr nz, .is_attack - -; is a Pokémon Power -; set wDamage, wAIMinDamage and wAIMaxDamage to zero - ld hl, wDamage - xor a - ld [hli], a - ld [hl], a - ld [wAIMinDamage], a - ld [wAIMaxDamage], a - ld e, a - ld d, a - ret - -.is_attack -; set wAIMinDamage and wAIMaxDamage to damage of attack -; these values take into account the range of damage -; that the attack can span (e.g. min and max number of hits) - ld a, [wDamage] - ld [wAIMinDamage], a - ld [wAIMaxDamage], a - call SwapTurn - ldh a, [hTempPlayAreaLocation_ff9d] - push af - xor a - ldh [hTempPlayAreaLocation_ff9d], a - ld a, EFFECTCMDTYPE_AI - call TryExecuteEffectCommandFunction - pop af - ldh [hTempPlayAreaLocation_ff9d], a - call SwapTurn - ld a, [wAIMinDamage] - ld hl, wAIMaxDamage - or [hl] - jr nz, .calculation - ld a, [wDamage] - ld [wAIMinDamage], a - ld [wAIMaxDamage], a - -.calculation -; if temp. location is active, damage calculation can be done directly... - ldh a, [hTempPlayAreaLocation_ff9d] - or a - jr z, CalculateDamage_FromDefendingPokemon - -; ...otherwise substatuses need to be temporarily reset to account -; for the switching, to obtain the right damage calculation... - ld a, DUELVARS_ARENA_CARD_SUBSTATUS1 - call GetTurnDuelistVariable - push af - push hl - ld [hl], $00 - ; reset substatus2 - ld l, DUELVARS_ARENA_CARD_SUBSTATUS2 - ld a, [hl] - push af - push hl - ld [hl], $00 - ; reset changed resistance - ld l, DUELVARS_ARENA_CARD_CHANGED_RESISTANCE - ld a, [hl] - push af - push hl - ld [hl], $00 - call CalculateDamage_FromDefendingPokemon -; ...and subsequently recovered to continue the duel normally - pop hl - pop af - ld [hl], a - pop hl - pop af - ld [hl], a - pop hl - pop af - ld [hl], a - ret - -; similar to CalculateDamage_VersusDefendingPokemon but reversed, -; calculating damage of the defending Pokémon versus -; the card located in hTempPlayAreaLocation_ff9d -; taking into account weakness/resistance/pluspowers/defenders/etc -; and poison damage for two turns -; and outputs the result capped at a max of $ff -; input: -; [wAIMinDamage] = base damage -; [wAIMaxDamage] = base damage -; [wDamage] = base damage -; [hTempPlayAreaLocation_ff9d] = location of card to calculate -; damage as the receiver -CalculateDamage_FromDefendingPokemon: ; 1458c (5:458c) - ld hl, wAIMinDamage - call .CalculateDamage - ld hl, wAIMaxDamage - call .CalculateDamage - ld hl, wDamage - ; fallthrough - -.CalculateDamage ; 1459b (5:459b) - ld e, [hl] - ld d, $00 - push hl - - ; load player active card's data - call SwapTurn - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call LoadCardDataToBuffer2_FromDeckIndex - ld a, [wLoadedCard2ID] - ld [wTempTurnDuelistCardID], a - call SwapTurn - - ; load opponent's card data - ldh a, [hTempPlayAreaLocation_ff9d] - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call LoadCardDataToBuffer2_FromDeckIndex - ld a, [wLoadedCard2ID] - ld [wTempNonTurnDuelistCardID], a - - call SwapTurn - call HandleDoubleDamageSubstatus - bit UNAFFECTED_BY_WEAKNESS_RESISTANCE_F, d - res UNAFFECTED_BY_WEAKNESS_RESISTANCE_F, d - jr nz, .not_resistant - -; handle weakness - call GetArenaCardColor - call TranslateColorToWR - ld b, a - call SwapTurn - ldh a, [hTempPlayAreaLocation_ff9d] - or a - jr nz, .bench_weak - ld a, DUELVARS_ARENA_CARD_CHANGED_WEAKNESS - call GetTurnDuelistVariable - or a - jr nz, .unchanged_weak - -.bench_weak - ldh a, [hTempPlayAreaLocation_ff9d] - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call LoadCardDataToBuffer2_FromDeckIndex - ld a, [wLoadedCard2Weakness] -.unchanged_weak - and b - jr z, .not_weak - ; double de - sla e - rl d - -.not_weak -; handle resistance - ldh a, [hTempPlayAreaLocation_ff9d] - or a - jr nz, .bench_res - ld a, DUELVARS_ARENA_CARD_CHANGED_RESISTANCE - call GetTurnDuelistVariable - or a - jr nz, .unchanged_res - -.bench_res - ldh a, [hTempPlayAreaLocation_ff9d] - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call LoadCardDataToBuffer2_FromDeckIndex - ld a, [wLoadedCard2Resistance] -.unchanged_res - and b - jr z, .not_resistant - ld hl, -30 - add hl, de - ld e, l - ld d, h - -.not_resistant - ; apply pluspower and defender boosts - call SwapTurn - ld b, CARD_LOCATION_ARENA - call ApplyAttachedPluspower - call SwapTurn - ldh a, [hTempPlayAreaLocation_ff9d] - add CARD_LOCATION_ARENA - ld b, a - call ApplyAttachedDefender - ldh a, [hTempPlayAreaLocation_ff9d] - or a - call z, HandleDamageReduction - bit 7, d - jr z, .no_underflow - ld de, $0 - -.no_underflow - ldh a, [hTempPlayAreaLocation_ff9d] - or a - jr nz, .done - ld a, DUELVARS_ARENA_CARD_STATUS - call GetTurnDuelistVariable - and DOUBLE_POISONED - jr z, .done - ld c, 40 - and DOUBLE_POISONED & (POISONED ^ $ff) - jr nz, .add_poison - ld c, 20 -.add_poison - ld a, c - add e - ld e, a - ld a, $00 - adc d - ld d, a - -.done - pop hl - ld [hl], e - ld a, d - or a - ret z - ld a, $ff - ld [hl], a - ret diff --git a/src/engine/ai/deck_ai.asm b/src/engine/ai/deck_ai.asm deleted file mode 100644 index c330418..0000000 --- a/src/engine/ai/deck_ai.asm +++ /dev/null @@ -1,82 +0,0 @@ -; AI card retreat score bonus -; when the AI retreat routine runs through the Bench to choose -; a Pokemon to switch to, it looks up in this list and if -; a card ID matches, applies a retreat score bonus to this card. -; positive (negative) means more (less) likely to switch to this card. -ai_retreat: MACRO - db \1 ; card ID - db $80 + \2 ; retreat score (ranges between -128 and 127) -ENDM - -; AI card energy attach score bonus -; when the AI energy attachment routine runs through the Play Area to choose -; a Pokemon to attach an energy card, it looks up in this list and if -; a card ID matches, skips this card if the maximum number of energy -; cards attached has been reached. If it hasn't been reached, additionally -; applies a positive (or negative) AI score to attach energy to this card. -ai_energy: MACRO - db \1 ; card ID - db \2 ; maximum number of attached cards - db $80 + \3 ; energy score (ranges between -128 and 127) -ENDM - -; stores in WRAM pointer to data in argument -; e.g. store_list_pointer wSomeListPointer, SomeData -store_list_pointer: MACRO - ld hl, \1 - ld de, \2 - ld [hl], e - inc hl - ld [hl], d -ENDM - -; deck AIs are specialized to work on a given deck ID. -; they decide what happens during a turn, what Pokemon cards -; to pick during the start of the duel, etc. -; the different scenarios these are used are listed in AIACTION_* constants. -; each of these have a pointer table with the following structure: -; dw .do_turn : never called; -; -; dw .do_turn : called to handle the main turn logic, from the beginning -; of the turn up to the attack (or lack thereof); -; -; dw .start_duel : called at the start of the duel to initialize some -; variables and optionally set up CPU hand and deck; -; -; dw .forced_switch : logic to determine what Pokemon to pick when there's -; an effect that forces AI to switch to Bench card; -; -; dw .ko_switch : logic for picking which card to use after a KO; -; -; dw .take_prize : logic to decide which prize card to pick. - -; optionally, decks can also declare card lists that will add -; more specialized logic during various generic AI routines, -; and read during the .start_duel routines. -; the pointers to these lists are stored in memory: -; wAICardListAvoidPrize : list of cards to avoid being placed as prize; -; wAICardListArenaPriority : priority list of Arena card at duel start; -; wAICardListBenchPriority : priority list of Bench cards at duel start; -; wAICardListPlayFromHandPriority : priority list of cards to play from hand; -; wAICardListRetreatBonus : scores given to certain cards for retreat; -; wAICardListEnergyBonus : max number of energy cards and card scores. - -INCLUDE "engine/ai/decks/general.asm" -INCLUDE "engine/ai/decks/sams_practice.asm" -INCLUDE "engine/ai/decks/general_no_retreat.asm" -INCLUDE "engine/ai/decks/legendary_moltres.asm" -INCLUDE "engine/ai/decks/legendary_zapdos.asm" -INCLUDE "engine/ai/decks/legendary_articuno.asm" -INCLUDE "engine/ai/decks/legendary_dragonite.asm" -INCLUDE "engine/ai/decks/first_strike.asm" -INCLUDE "engine/ai/decks/rock_crusher.asm" -INCLUDE "engine/ai/decks/go_go_rain_dance.asm" -INCLUDE "engine/ai/decks/zapping_selfdestruct.asm" -INCLUDE "engine/ai/decks/flower_power.asm" -INCLUDE "engine/ai/decks/strange_psyshock.asm" -INCLUDE "engine/ai/decks/wonders_of_science.asm" -INCLUDE "engine/ai/decks/fire_charge.asm" -INCLUDE "engine/ai/decks/im_ronald.asm" -INCLUDE "engine/ai/decks/powerful_ronald.asm" -INCLUDE "engine/ai/decks/invincible_ronald.asm" -INCLUDE "engine/ai/decks/legendary_ronald.asm" diff --git a/src/engine/ai/decks/fire_charge.asm b/src/engine/ai/decks/fire_charge.asm deleted file mode 100644 index f5b347b..0000000 --- a/src/engine/ai/decks/fire_charge.asm +++ /dev/null @@ -1,80 +0,0 @@ -AIActionTable_FireCharge: ; 15232 (5:5232) - dw .do_turn ; unused - dw .do_turn - dw .start_duel - dw .forced_switch - dw .ko_switch - dw .take_prize - -.do_turn ; 1523e (5:523e) - call AIMainTurnLogic - ret - -.start_duel ; 15242 (5:5242) - call InitAIDuelVars - call .store_list_pointers - call SetUpBossStartingHandAndDeck - call TrySetUpBossStartingPlayArea - ret nc - call AIPlayInitialBasicCards - ret - -.forced_switch ; 15253 (5:5253) - call AIDecideBenchPokemonToSwitchTo - ret - -.ko_switch ; 15257 (5:5257) - call AIDecideBenchPokemonToSwitchTo - ret - -.take_prize ; 1525b (5:525b) - call AIPickPrizeCards - ret - -.list_arena ; 1525f (5:525f) - db JIGGLYPUFF3 - db CHANSEY - db TAUROS - db MAGMAR1 - db JIGGLYPUFF1 - db GROWLITHE - db $00 - -.list_bench ; 15266 (5:5266) - db JIGGLYPUFF3 - db CHANSEY - db GROWLITHE - db MAGMAR1 - db JIGGLYPUFF1 - db TAUROS - db $00 - -.list_retreat ; 1526e (5:526e) - ai_retreat JIGGLYPUFF1, -1 - ai_retreat CHANSEY, -1 - ai_retreat GROWLITHE, -1 - db $00 - -.list_energy ; 15274 (5:5274) - ai_energy GROWLITHE, 3, +0 - ai_energy ARCANINE2, 4, +0 - ai_energy MAGMAR1, 3, +0 - ai_energy JIGGLYPUFF1, 3, +0 - ai_energy JIGGLYPUFF3, 2, +0 - ai_energy WIGGLYTUFF, 3, +0 - ai_energy CHANSEY, 4, +0 - ai_energy TAUROS, 3, +0 - db $00 - -.list_prize ; 1528d (5:528d) - db GAMBLER - db $00 - -.store_list_pointers ; 1528f (5:528f) - store_list_pointer wAICardListAvoidPrize, .list_prize - store_list_pointer wAICardListArenaPriority, .list_arena - store_list_pointer wAICardListBenchPriority, .list_bench - store_list_pointer wAICardListPlayFromHandPriority, .list_bench - ; missing store_list_pointer wAICardListRetreatBonus, .list_retreat - store_list_pointer wAICardListEnergyBonus, .list_energy - ret diff --git a/src/engine/ai/decks/first_strike.asm b/src/engine/ai/decks/first_strike.asm deleted file mode 100644 index 2e636e1..0000000 --- a/src/engine/ai/decks/first_strike.asm +++ /dev/null @@ -1,76 +0,0 @@ -AIActionTable_FirstStrike: ; 14e89 (5:4e89) - dw .do_turn ; unused - dw .do_turn - dw .start_duel - dw .forced_switch - dw .ko_switch - dw .take_prize - -.do_turn ; 14e95 (5:4e95) - call AIMainTurnLogic - ret - -.start_duel ; 14e99 (5:4e99) - call InitAIDuelVars - call .store_list_pointers - call SetUpBossStartingHandAndDeck - call TrySetUpBossStartingPlayArea - ret nc - call AIPlayInitialBasicCards - ret - -.forced_switch ; 14eaa (5:4eaa) - call AIDecideBenchPokemonToSwitchTo - ret - -.ko_switch ; 14eae (5:4eae) - call AIDecideBenchPokemonToSwitchTo - ret - -.take_prize ; 14eb2 (5:4eb2) - call AIPickPrizeCards - ret - -.list_arena ; 14eb6 (5:1eb6) - db HITMONCHAN - db MACHOP - db HITMONLEE - db MANKEY - db $00 - -.list_bench ; 14ebb (5:1ebb) - db MACHOP - db HITMONLEE - db HITMONCHAN - db MANKEY - db $00 - -.list_retreat ; 14ec0 (5:1ec0) - ai_retreat MACHOP, -1 - ai_retreat MACHOKE, -1 - ai_retreat MANKEY, -2 - db $00 - -.list_energy ; 14ec7 (5:1ec7) - ai_energy MACHOP, 3, +0 - ai_energy MACHOKE, 4, +0 - ai_energy MACHAMP, 4, -1 - ai_energy HITMONCHAN, 3, +0 - ai_energy HITMONLEE, 3, +0 - ai_energy MANKEY, 2, -1 - ai_energy PRIMEAPE, 3, -1 - db $00 - -.list_prize ; 14edd (5:1edd) - db HITMONLEE - db HITMONCHAN - db $00 - -.store_list_pointers ; 14ee0 (5:4ee0) - store_list_pointer wAICardListAvoidPrize, .list_prize - store_list_pointer wAICardListArenaPriority, .list_arena - store_list_pointer wAICardListBenchPriority, .list_bench - store_list_pointer wAICardListPlayFromHandPriority, .list_bench - ; missing store_list_pointer wAICardListRetreatBonus, .list_retreat - store_list_pointer wAICardListEnergyBonus, .list_energy - ret diff --git a/src/engine/ai/decks/flower_power.asm b/src/engine/ai/decks/flower_power.asm deleted file mode 100644 index 4d423a3..0000000 --- a/src/engine/ai/decks/flower_power.asm +++ /dev/null @@ -1,75 +0,0 @@ -AIActionTable_FlowerPower: ; 1509b (5:509b) - dw .do_turn ; unused - dw .do_turn - dw .start_duel - dw .forced_switch - dw .ko_switch - dw .take_prize - -.do_turn ; 150a7 (5:50a7) - call AIMainTurnLogic - ret - -.start_duel ; 150ab (5:50ab) - call InitAIDuelVars - call .store_list_pointers - call SetUpBossStartingHandAndDeck - call TrySetUpBossStartingPlayArea - ret nc - call AIPlayInitialBasicCards - ret - -.forced_switch ; 150bc (5:50bc) - call AIDecideBenchPokemonToSwitchTo - ret - -.ko_switch ; 150c0 (5:50c0) - call AIDecideBenchPokemonToSwitchTo - ret - -.take_prize ; 150c4 (5:50c4) - call AIPickPrizeCards - ret - -.list_arena ; 150c8 (5:50c8) - db ODDISH - db EXEGGCUTE - db BULBASAUR - db $00 - -.list_bench ; 150cc (5:50cc) - db BULBASAUR - db EXEGGCUTE - db ODDISH - db $00 - -.list_retreat ; 150cf (5:50cf) - ai_retreat GLOOM, -2 - ai_retreat VILEPLUME, -2 - ai_retreat BULBASAUR, -2 - ai_retreat IVYSAUR, -2 - db $00 - -.list_energy ; 150d9 (5:50d9) - ai_energy BULBASAUR, 3, +0 - ai_energy IVYSAUR, 4, +0 - ai_energy VENUSAUR2, 4, +0 - ai_energy ODDISH, 2, +0 - ai_energy GLOOM, 3, -1 - ai_energy VILEPLUME, 3, -1 - ai_energy EXEGGCUTE, 3, +0 - ai_energy EXEGGUTOR, 22, +0 - db $00 - -.list_prize ; 150f2 (5:50f2) - db VENUSAUR2 - db $00 - -.store_list_pointers ; 150f4 (5:50f4) - store_list_pointer wAICardListAvoidPrize, .list_prize - store_list_pointer wAICardListArenaPriority, .list_arena - store_list_pointer wAICardListBenchPriority, .list_bench - store_list_pointer wAICardListPlayFromHandPriority, .list_bench - ; missing store_list_pointer wAICardListRetreatBonus, .list_retreat - store_list_pointer wAICardListEnergyBonus, .list_energy - ret diff --git a/src/engine/ai/decks/general.asm b/src/engine/ai/decks/general.asm deleted file mode 100644 index 039e101..0000000 --- a/src/engine/ai/decks/general.asm +++ /dev/null @@ -1,194 +0,0 @@ -; AI logic used by general decks -AIActionTable_GeneralDecks: ; 14668 (05:4668) - dw .do_turn ; unused - dw .do_turn - dw .start_duel - dw .forced_switch - dw .ko_switch - dw .take_prize - -.do_turn ; 14674 (5:4674) - call AIMainTurnLogic - ret - -.start_duel ; 14678 (5:4678) - call InitAIDuelVars - call AIPlayInitialBasicCards - ret - -.forced_switch ; 1467f (5:467f) - call AIDecideBenchPokemonToSwitchTo - ret - -.ko_switch ; 14683 (5:4683) - call AIDecideBenchPokemonToSwitchTo - ret - -.take_prize: ; 14687 (5:4687) - call AIPickPrizeCards - ret - -; handle AI routines for a whole turn -AIMainTurnLogic: ; 1468b (5:468b) -; initialize variables - call InitAITurnVars - ld a, AI_TRAINER_CARD_PHASE_01 - call AIProcessHandTrainerCards - farcall HandleAIAntiMewtwoDeckStrategy - jp nc, .try_attack -; handle Pkmn Powers - farcall HandleAIGoGoRainDanceEnergy - farcall HandleAIDamageSwap - farcall HandleAIPkmnPowers - ret c ; return if turn ended - farcall HandleAICowardice -; process Trainer cards -; phase 2 through 4. - ld a, AI_TRAINER_CARD_PHASE_02 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_03 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_04 - call AIProcessHandTrainerCards -; play Pokemon from hand - call AIDecidePlayPokemonCard - ret c ; return if turn ended -; process Trainer cards -; phase 5 through 12. - ld a, AI_TRAINER_CARD_PHASE_05 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_06 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_07 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_08 - call AIProcessHandTrainerCards - call AIProcessRetreat - ld a, AI_TRAINER_CARD_PHASE_10 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_11 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_12 - call AIProcessHandTrainerCards -; play Energy card if possible - ld a, [wAlreadyPlayedEnergy] - or a - jr nz, .skip_energy_attach_1 - call AIProcessAndTryToPlayEnergy -.skip_energy_attach_1 -; play Pokemon from hand again - call AIDecidePlayPokemonCard -; handle Pkmn Powers again - farcall HandleAIDamageSwap - farcall HandleAIPkmnPowers - ret c ; return if turn ended - farcall HandleAIGoGoRainDanceEnergy - ld a, AI_ENERGY_TRANS_ATTACK - farcall HandleAIEnergyTrans -; process Trainer cards phases 13 and 15 - ld a, AI_TRAINER_CARD_PHASE_13 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_15 - call AIProcessHandTrainerCards -; if used Professor Oak, process new hand -; if not, then proceed to attack. - ld a, [wPreviousAIFlags] - and AI_FLAG_USED_PROFESSOR_OAK - jr z, .try_attack - ld a, AI_TRAINER_CARD_PHASE_01 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_02 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_03 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_04 - call AIProcessHandTrainerCards - call AIDecidePlayPokemonCard - ret c ; return if turn ended - ld a, AI_TRAINER_CARD_PHASE_05 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_06 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_07 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_08 - call AIProcessHandTrainerCards - call AIProcessRetreat - ld a, AI_TRAINER_CARD_PHASE_10 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_11 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_12 - call AIProcessHandTrainerCards - ld a, [wAlreadyPlayedEnergy] - or a - jr nz, .skip_energy_attach_2 - call AIProcessAndTryToPlayEnergy -.skip_energy_attach_2 - call AIDecidePlayPokemonCard - farcall HandleAIDamageSwap - farcall HandleAIPkmnPowers - ret c ; return if turn ended - farcall HandleAIGoGoRainDanceEnergy - ld a, AI_ENERGY_TRANS_ATTACK - farcall HandleAIEnergyTrans - ld a, AI_TRAINER_CARD_PHASE_13 - call AIProcessHandTrainerCards - ; skip AI_TRAINER_CARD_PHASE_15 -.try_attack - ld a, AI_ENERGY_TRANS_TO_BENCH - farcall HandleAIEnergyTrans -; attack if possible, if not, -; finish turn without attacking. - call AIProcessAndTryToUseAttack - ret c ; return if AI attacked - ld a, OPPACTION_FINISH_NO_ATTACK - bank1call AIMakeDecision - ret - -; handles AI retreating logic -AIProcessRetreat: ; 14786 (5:4786) - ld a, [wAIRetreatedThisTurn] - or a - ret nz ; return, already retreated this turn - - call AIDecideWhetherToRetreat - ret nc ; return if not retreating - - call AIDecideBenchPokemonToSwitchTo - ret c ; return if no Bench Pokemon - -; store Play Area to retreat to and -; set wAIRetreatedThisTurn to true - ld [wAIPlayAreaCardToSwitch], a - ld a, $01 - ld [wAIRetreatedThisTurn], a - -; if AI can use Switch from hand, use it instead... - ld a, AI_TRAINER_CARD_PHASE_09 - call AIProcessHandTrainerCards - ld a, [wPreviousAIFlags] - and AI_FLAG_USED_SWITCH - jr nz, .used_switch -; ... else try retreating normally. - ld a, [wAIPlayAreaCardToSwitch] - call AITryToRetreat - ret - -.used_switch -; if AI used switch, unset its AI flag - ld a, [wPreviousAIFlags] - and ~AI_FLAG_USED_SWITCH ; clear Switch flag - ld [wPreviousAIFlags], a - -; bug, this doesn't make sense being here, since at this point -; Switch Trainer card was already used to retreat the Pokemon. -; what the routine will do is just transfer Energy cards to -; the Arena Pokemon for the purpose of retreating, and -; then not actually retreat, resulting in unusual behaviour. -; this would only work placed right after the AI checks whether -; they have Switch card in hand to use and doesn't have one. -; (and probably that was the original intention.) - ld a, AI_ENERGY_TRANS_RETREAT ; retreat - farcall HandleAIEnergyTrans - ret diff --git a/src/engine/ai/decks/general_no_retreat.asm b/src/engine/ai/decks/general_no_retreat.asm deleted file mode 100644 index 20d84e3..0000000 --- a/src/engine/ai/decks/general_no_retreat.asm +++ /dev/null @@ -1,140 +0,0 @@ -; acts just like a general deck AI except never retreats -AIActionTable_GeneralNoRetreat: ; 148dc (5:48dc) - dw .do_turn ; unused - dw .do_turn - dw .start_duel - dw .forced_switch - dw .ko_switch - dw .take_prize - -.do_turn ; 148e8 (5:48e8) - call AIDoTurn_GeneralNoRetreat - ret - -.start_duel ; 148ec (5:48ec) - call InitAIDuelVars - call AIPlayInitialBasicCards - ret - -.forced_switch ; 148f3 (5:48f3) - call AIDecideBenchPokemonToSwitchTo - ret - -.ko_switch ; 148f7 (5:48f7) - call AIDecideBenchPokemonToSwitchTo - ret - -.take_prize ; 148fb (5:48fb) - call AIPickPrizeCards - ret - -AIDoTurn_GeneralNoRetreat: ; 148ff (5:48ff) -; initialize variables - call InitAITurnVars - ld a, AI_TRAINER_CARD_PHASE_01 - call AIProcessHandTrainerCards - farcall HandleAIAntiMewtwoDeckStrategy - jp nc, .try_attack -; handle Pkmn Powers - farcall HandleAIGoGoRainDanceEnergy - farcall HandleAIDamageSwap - farcall HandleAIPkmnPowers - ret c ; return if turn ended - farcall HandleAICowardice -; process Trainer cards -; phase 2 through 4. - ld a, AI_TRAINER_CARD_PHASE_02 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_03 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_04 - call AIProcessHandTrainerCards -; play Pokemon from hand - call AIDecidePlayPokemonCard - ret c ; return if turn ended -; process Trainer cards -; phase 5 through 12. - ld a, AI_TRAINER_CARD_PHASE_05 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_06 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_07 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_08 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_10 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_11 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_12 - call AIProcessHandTrainerCards -; play Energy card if possible - ld a, [wAlreadyPlayedEnergy] - or a - jr nz, .skip_energy_attach_1 - call AIProcessAndTryToPlayEnergy -.skip_energy_attach_1 -; play Pokemon from hand again - call AIDecidePlayPokemonCard -; handle Pkmn Powers again - farcall HandleAIDamageSwap - farcall HandleAIPkmnPowers - ret c ; return if turn ended - farcall HandleAIGoGoRainDanceEnergy - ld a, AI_ENERGY_TRANS_ATTACK - farcall HandleAIEnergyTrans -; process Trainer cards phases 13 and 15 - ld a, AI_TRAINER_CARD_PHASE_13 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_15 - call AIProcessHandTrainerCards -; if used Professor Oak, process new hand -; if not, then proceed to attack. - ld a, [wPreviousAIFlags] - and AI_FLAG_USED_PROFESSOR_OAK - jr z, .try_attack - ld a, AI_TRAINER_CARD_PHASE_01 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_02 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_03 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_04 - call AIProcessHandTrainerCards - call AIDecidePlayPokemonCard - ret c ; return if turn ended - ld a, AI_TRAINER_CARD_PHASE_05 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_06 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_07 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_08 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_10 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_11 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_12 - call AIProcessHandTrainerCards - ld a, [wAlreadyPlayedEnergy] - or a - jr nz, .skip_energy_attach_2 - call AIProcessAndTryToPlayEnergy -.skip_energy_attach_2 - call AIDecidePlayPokemonCard - farcall HandleAIDamageSwap - farcall HandleAIPkmnPowers - ret c ; return if turn ended - farcall HandleAIGoGoRainDanceEnergy - ld a, AI_TRAINER_CARD_PHASE_13 - call AIProcessHandTrainerCards - ; skip AI_TRAINER_CARD_PHASE_15 -.try_attack -; attack if possible, if not, -; finish turn without attacking. - call AIProcessAndTryToUseAttack - ret c ; return if turn ended - ld a, OPPACTION_FINISH_NO_ATTACK - bank1call AIMakeDecision - ret diff --git a/src/engine/ai/decks/go_go_rain_dance.asm b/src/engine/ai/decks/go_go_rain_dance.asm deleted file mode 100644 index 23547e2..0000000 --- a/src/engine/ai/decks/go_go_rain_dance.asm +++ /dev/null @@ -1,79 +0,0 @@ -AIActionTable_GoGoRainDance: ; 14f8f (5:4f8f) - dw .do_turn ; unused - dw .do_turn - dw .start_duel - dw .forced_switch - dw .ko_switch - dw .take_prize - -.do_turn ; 14f9b (5:4f9b) - call AIMainTurnLogic - ret - -.start_duel ; 14f9f (5:4f9f) - call InitAIDuelVars - call .store_list_pointers - call SetUpBossStartingHandAndDeck - call TrySetUpBossStartingPlayArea - ret nc - call AIPlayInitialBasicCards - ret - -.forced_switch ; 14fb0 (5:4fb0) - call AIDecideBenchPokemonToSwitchTo - ret - -.ko_switch ; 14fb4 (5:4fb4) - call AIDecideBenchPokemonToSwitchTo - ret - -.take_prize ; 14fb8 (5:4fb8) - call AIPickPrizeCards - ret - -.list_arena ; 14fbc (5:4fbc) - db LAPRAS - db HORSEA - db GOLDEEN - db SQUIRTLE - db $00 - -.list_bench ; 14fc1 (5:4fc1) - db SQUIRTLE - db HORSEA - db GOLDEEN - db LAPRAS - db $00 - -.list_retreat ; 14fc6 (5:4fc6) - ai_retreat SQUIRTLE, -3 - ai_retreat WARTORTLE, -2 - ai_retreat HORSEA, -1 - db $00 - -.list_energy ; 14fcd (5:4fcd) - ai_energy SQUIRTLE, 2, +0 - ai_energy WARTORTLE, 3, +0 - ai_energy BLASTOISE, 5, +0 - ai_energy GOLDEEN, 1, +0 - ai_energy SEAKING, 2, +0 - ai_energy HORSEA, 2, +0 - ai_energy SEADRA, 3, +0 - ai_energy LAPRAS, 3, +0 - db $00 - -.list_prize ; 14fe6 (5:4fe6) - db GAMBLER - db ENERGY_RETRIEVAL - db SUPER_ENERGY_RETRIEVAL - db BLASTOISE - db $00 - -.store_list_pointers ; 14feb (5:4feb) - store_list_pointer wAICardListAvoidPrize, .list_prize - store_list_pointer wAICardListArenaPriority, .list_arena - store_list_pointer wAICardListBenchPriority, .list_bench - store_list_pointer wAICardListPlayFromHandPriority, .list_bench - ; missing store_list_pointer wAICardListRetreatBonus, .list_retreat - store_list_pointer wAICardListEnergyBonus, .list_energy - ret diff --git a/src/engine/ai/decks/im_ronald.asm b/src/engine/ai/decks/im_ronald.asm deleted file mode 100644 index b002d83..0000000 --- a/src/engine/ai/decks/im_ronald.asm +++ /dev/null @@ -1,80 +0,0 @@ -AIActionTable_ImRonald: ; 152bd (5:52bd) - dw .do_turn ; unused - dw .do_turn - dw .start_duel - dw .forced_switch - dw .ko_switch - dw .take_prize - -.do_turn ; 152c9 (5:52c9) - call AIMainTurnLogic - ret - -.start_duel ; 152cd (5:52cd) - call InitAIDuelVars - call .store_list_pointers - call SetUpBossStartingHandAndDeck - call TrySetUpBossStartingPlayArea - ret nc - call AIPlayInitialBasicCards - ret - -.forced_switch ; 152de (5:52de) - call AIDecideBenchPokemonToSwitchTo - ret - -.ko_switch ; 152e2 (5:52e2) - call AIDecideBenchPokemonToSwitchTo - ret - -.take_prize ; 152e6 (5:52e6) - call AIPickPrizeCards - ret - -.list_arena ; 152ea (5:52ea) - db LAPRAS - db SEEL - db CHARMANDER - db CUBONE - db SQUIRTLE - db GROWLITHE - db $00 - -.list_bench ; 152f1 (5:52f1) - db CHARMANDER - db SQUIRTLE - db SEEL - db CUBONE - db GROWLITHE - db LAPRAS - db $00 - -.list_retreat ; 152f8 (5:52f8) - db $00 - -.list_energy ; 152f9 (5:52f9) - ai_energy CHARMANDER, 3, +0 - ai_energy CHARMELEON, 5, +0 - ai_energy GROWLITHE, 2, +0 - ai_energy ARCANINE2, 4, +0 - ai_energy SQUIRTLE, 2, +0 - ai_energy WARTORTLE, 3, +0 - ai_energy SEEL, 3, +0 - ai_energy DEWGONG, 4, +0 - ai_energy LAPRAS, 3, +0 - ai_energy CUBONE, 3, +0 - ai_energy MAROWAK1, 3, +0 - db $00 - -.list_prize ; 1531b (5:531b) - db LAPRAS - db $00 - -.store_list_pointers ; 1531d (5:531d) - store_list_pointer wAICardListAvoidPrize, .list_prize - store_list_pointer wAICardListArenaPriority, .list_arena - store_list_pointer wAICardListBenchPriority, .list_bench - store_list_pointer wAICardListPlayFromHandPriority, .list_bench - ; missing store_list_pointer wAICardListRetreatBonus, .list_retreat - store_list_pointer wAICardListEnergyBonus, .list_energy - ret diff --git a/src/engine/ai/decks/invincible_ronald.asm b/src/engine/ai/decks/invincible_ronald.asm deleted file mode 100644 index 463560b..0000000 --- a/src/engine/ai/decks/invincible_ronald.asm +++ /dev/null @@ -1,78 +0,0 @@ -AIActionTable_InvincibleRonald: ; 153e8 (5:53e8) - dw .do_turn ; unused - dw .do_turn - dw .start_duel - dw .forced_switch - dw .ko_switch - dw .take_prize - -.do_turn ; 153f4 (5:53f4) - call AIMainTurnLogic - ret - -.start_duel ; 153f8 (5:53f8) - call InitAIDuelVars - call .store_list_pointers - call SetUpBossStartingHandAndDeck - call TrySetUpBossStartingPlayArea - ret nc - call AIPlayInitialBasicCards - ret - -.forced_switch ; 15409 (5:5409) - call AIDecideBenchPokemonToSwitchTo - ret - -.ko_switch ; 1540d (5:540d) - call AIDecideBenchPokemonToSwitchTo - ret - -.take_prize ; 15411 (5:5411) - call AIPickPrizeCards - ret - -.list_arena ; 15415 (5:5415) - db KANGASKHAN - db MAGMAR2 - db CHANSEY - db GEODUDE - db SCYTHER - db GRIMER - db $00 - -.list_bench ; 1541c (5:541c) - db GRIMER - db SCYTHER - db GEODUDE - db CHANSEY - db MAGMAR2 - db KANGASKHAN - db $00 - -.list_retreat ; 15423 (5:5423) - ai_retreat GRIMER, -1 - db $00 - -.list_energy ; 15426 (5:5426) - ai_energy GRIMER, 1, -1 - ai_energy MUK, 3, -1 - ai_energy SCYTHER, 4, +1 - ai_energy MAGMAR2, 2, +0 - ai_energy GEODUDE, 2, +0 - ai_energy GRAVELER, 3, +0 - ai_energy CHANSEY, 4, +0 - ai_energy KANGASKHAN, 4, -1 - db $00 - -.list_prize ; 1543f (5:543f) - db GAMBLER - db $00 - -.store_list_pointers ; 15441 (5:5441) - store_list_pointer wAICardListAvoidPrize, .list_prize - store_list_pointer wAICardListArenaPriority, .list_arena - store_list_pointer wAICardListBenchPriority, .list_bench - store_list_pointer wAICardListPlayFromHandPriority, .list_bench - ; missing store_list_pointer wAICardListRetreatBonus, .list_retreat - store_list_pointer wAICardListEnergyBonus, .list_energy - ret diff --git a/src/engine/ai/decks/legendary_articuno.asm b/src/engine/ai/decks/legendary_articuno.asm deleted file mode 100644 index 6409330..0000000 --- a/src/engine/ai/decks/legendary_articuno.asm +++ /dev/null @@ -1,209 +0,0 @@ -AIActionTable_LegendaryArticuno: ; 14c0b (5:4c0b) - dw .do_turn ; unused - dw .do_turn - dw .start_duel - dw .forced_switch - dw .ko_switch - dw .take_prize - -.do_turn ; 14c17 (5:4c17) - call AIDoTurn_LegendaryArticuno - ret - -.start_duel ; 14c1b (5:4c1b) - call InitAIDuelVars - call .store_list_pointers - call SetUpBossStartingHandAndDeck - call TrySetUpBossStartingPlayArea - ret nc - call AIPlayInitialBasicCards - ret - -.forced_switch ; 14c2c (5:4c2c) - call AIDecideBenchPokemonToSwitchTo - ret - -.ko_switch ; 14c30 (5:4c30) - call AIDecideBenchPokemonToSwitchTo - ret - -.take_prize ; 14c34 (5:4c34) - call AIPickPrizeCards - ret - -.list_arena ; 14c38 (5:4c38) - db CHANSEY - db LAPRAS - db DITTO - db SEEL - db ARTICUNO1 - db ARTICUNO2 - db $00 - -.list_bench ; 14c3f (5:4c3f) - db ARTICUNO1 - db SEEL - db LAPRAS - db CHANSEY - db DITTO - db $00 - -.list_retreat ; 14c45 (5:4c45) - ai_retreat SEEL, -3 - ai_retreat DITTO, -3 - db $00 - -.list_energy ; 14c4a (5:4c4a) - ai_energy SEEL, 3, +1 - ai_energy DEWGONG, 4, +0 - ai_energy LAPRAS, 3, +0 - ai_energy ARTICUNO1, 4, +1 - ai_energy ARTICUNO2, 3, +0 - ai_energy CHANSEY, 0, -8 - ai_energy DITTO, 3, +0 - db $00 - -.list_prize ; 14c60 (5:4c60) - db GAMBLER - db ARTICUNO2 - db $00 - -.store_list_pointers ; 14c63 (5:4c63) - store_list_pointer wAICardListAvoidPrize, .list_prize - store_list_pointer wAICardListArenaPriority, .list_arena - store_list_pointer wAICardListBenchPriority, .list_bench - store_list_pointer wAICardListPlayFromHandPriority, .list_bench - ; missing store_list_pointer wAICardListRetreatBonus, .list_retreat - store_list_pointer wAICardListEnergyBonus, .list_energy - ret - -; this routine handles how Legendary Articuno -; prioritizes playing energy cards to each Pokémon. -; first, it makes sure that all Lapras have at least -; 3 energy cards before moving on to Articuno, -; and then to Dewgong and Seel -ScoreLegendaryArticunoCards: ; 14c91 (5:4c91) - call SwapTurn - call CountPrizes - call SwapTurn - cp 3 - ret c - -; player prizes >= 3 -; if Lapras has more than half HP and -; can use second attack, check next for Articuno -; otherwise, check if Articuno or Dewgong -; have more than half HP and can use second attack -; and if so, the next Pokémon to check is Lapras - ld a, LAPRAS - call CheckForBenchIDAtHalfHPAndCanUseSecondAttack - jr c, .articuno - ld a, ARTICUNO1 - call CheckForBenchIDAtHalfHPAndCanUseSecondAttack - jr c, .lapras - ld a, DEWGONG - call CheckForBenchIDAtHalfHPAndCanUseSecondAttack - jr c, .lapras - jr .articuno - -; the following routines check for certain card IDs in bench -; and call RaiseAIScoreToAllMatchingIDsInBench if these are found. -; for Lapras, an additional check is made to its -; attached energy count, which skips calling the routine -; if this count is >= 3 -.lapras - ld a, LAPRAS - ld b, PLAY_AREA_BENCH_1 - call LookForCardIDInPlayArea_Bank5 - jr nc, .articuno - ld e, a - call CountNumberOfEnergyCardsAttached - cp 3 - jr nc, .articuno - ld a, LAPRAS - call RaiseAIScoreToAllMatchingIDsInBench - ret - -.articuno - ld a, ARTICUNO1 - ld b, PLAY_AREA_BENCH_1 - call LookForCardIDInPlayArea_Bank5 - jr nc, .dewgong - ld a, ARTICUNO1 - call RaiseAIScoreToAllMatchingIDsInBench - ret - -.dewgong - ld a, DEWGONG - ld b, PLAY_AREA_BENCH_1 - call LookForCardIDInPlayArea_Bank5 - jr nc, .seel - ld a, DEWGONG - call RaiseAIScoreToAllMatchingIDsInBench - ret - -.seel - ld a, SEEL - ld b, PLAY_AREA_BENCH_1 - call LookForCardIDInPlayArea_Bank5 - ret nc - ld a, SEEL - call RaiseAIScoreToAllMatchingIDsInBench - ret - -AIDoTurn_LegendaryArticuno: ; 14cf7 (5:4cf7) -; initialize variables - call InitAITurnVars - ld a, AI_TRAINER_CARD_PHASE_01 - call AIProcessHandTrainerCards - farcall HandleAIAntiMewtwoDeckStrategy - jp nc, .try_attack -; process Trainer cards - ld a, AI_TRAINER_CARD_PHASE_02 - call AIProcessHandTrainerCards -; play Pokemon from hand - call AIDecidePlayPokemonCard - ret c ; return if turn ended - call AIProcessRetreat - ld a, AI_TRAINER_CARD_PHASE_10 - call AIProcessHandTrainerCards -; play Energy card if possible - ld a, [wAlreadyPlayedEnergy] - or a - jr nz, .skip_energy_attach_1 - call AIProcessAndTryToPlayEnergy -.skip_energy_attach_1 -; play Pokemon from hand again - call AIDecidePlayPokemonCard -; process Trainer cards phases 13 and 15 - ld a, AI_TRAINER_CARD_PHASE_13 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_15 - call AIProcessHandTrainerCards -; if used Professor Oak, process new hand - ld a, [wPreviousAIFlags] - and AI_FLAG_USED_PROFESSOR_OAK - jr z, .try_attack - ld a, AI_TRAINER_CARD_PHASE_01 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_02 - call AIProcessHandTrainerCards - call AIDecidePlayPokemonCard - ret c ; return if turn ended - call AIProcessRetreat - ld a, AI_TRAINER_CARD_PHASE_10 - call AIProcessHandTrainerCards - ld a, [wAlreadyPlayedEnergy] - or a - jr nz, .skip_energy_attach_2 - call AIProcessAndTryToPlayEnergy -.skip_energy_attach_2 - call AIDecidePlayPokemonCard -.try_attack -; attack if possible, if not, -; finish turn without attacking. - call AIProcessAndTryToUseAttack - ret c ; return if turn ended - ld a, OPPACTION_FINISH_NO_ATTACK - bank1call AIMakeDecision - ret diff --git a/src/engine/ai/decks/legendary_dragonite.asm b/src/engine/ai/decks/legendary_dragonite.asm deleted file mode 100644 index 597f72c..0000000 --- a/src/engine/ai/decks/legendary_dragonite.asm +++ /dev/null @@ -1,166 +0,0 @@ -AIActionTable_LegendaryDragonite: ; 14d60 (05:4d60) - dw .do_turn ; unused - dw .do_turn - dw .start_duel - dw .forced_switch - dw .ko_switch - dw .take_prize - -.do_turn ; 14d6c (5:4d6c) - call AIDoTurn_LegendaryDragonite - ret - -.start_duel ; 14d70 (5:4d70) - call InitAIDuelVars - call .store_list_pointers - call SetUpBossStartingHandAndDeck - call TrySetUpBossStartingPlayArea - ret nc - call AIPlayInitialBasicCards - ret - -.forced_switch ; 14d81 (5:4d81) - call AIDecideBenchPokemonToSwitchTo - ret - -.ko_switch ; 14d85 (5:4d85) - call AIDecideBenchPokemonToSwitchTo - ret - -.take_prize ; 14d89 (5:4d89) - call AIPickPrizeCards - ret - -.list_arena ; 14d8d (5:4d8d) - db KANGASKHAN - db LAPRAS - db CHARMANDER - db DRATINI - db MAGIKARP - db $00 - -.list_bench ; 14d93 (5:4d93) - db CHARMANDER - db MAGIKARP - db DRATINI - db LAPRAS - db KANGASKHAN - db $00 - -.list_retreat ; 14d99 (5:4d99) - ai_retreat CHARMANDER, -1 - ai_retreat MAGIKARP, -5 - db $00 - -.list_energy ; 14d9e (5:4d9e) - ai_energy CHARMANDER, 3, +1 - ai_energy CHARMELEON, 4, +1 - ai_energy CHARIZARD, 5, +0 - ai_energy MAGIKARP, 3, +1 - ai_energy GYARADOS, 4, -1 - ai_energy DRATINI, 2, +0 - ai_energy DRAGONAIR, 4, +0 - ai_energy DRAGONITE1, 3, -1 - ai_energy KANGASKHAN, 2, -2 - ai_energy LAPRAS, 3, +0 - db $00 - -.list_prize ; 14dbd (5:4dbd) - db GAMBLER - db DRAGONITE1 - db KANGASKHAN - db $00 - -.store_list_pointers ; 14dc1 (5:4dc1) - store_list_pointer wAICardListAvoidPrize, .list_prize - store_list_pointer wAICardListArenaPriority, .list_arena - store_list_pointer wAICardListBenchPriority, .list_bench - store_list_pointer wAICardListPlayFromHandPriority, .list_bench - ; missing store_list_pointer wAICardListRetreatBonus, .list_retreat - store_list_pointer wAICardListEnergyBonus, .list_energy - ret - -AIDoTurn_LegendaryDragonite: ; 14def (5:4def) -; initialize variables - call InitAITurnVars - ld a, AI_TRAINER_CARD_PHASE_01 - call AIProcessHandTrainerCards - farcall HandleAIAntiMewtwoDeckStrategy - jp nc, .try_attack -; process Trainer cards - ld a, AI_TRAINER_CARD_PHASE_02 - call AIProcessHandTrainerCards -; play Pokemon from hand - call AIDecidePlayPokemonCard - ret c ; return if turn ended - ld a, AI_TRAINER_CARD_PHASE_07 - call AIProcessHandTrainerCards - call AIProcessRetreat - ld a, AI_TRAINER_CARD_PHASE_10 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_11 - call AIProcessHandTrainerCards -; play Energy card if possible - ld a, [wAlreadyPlayedEnergy] - or a - jr nz, .skip_energy_attach_1 - -; if Arena card is Kangaskhan and doesn't -; have Energy cards attached, try attaching from hand. -; otherwise run normal AI energy attach routine. - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call GetCardIDFromDeckIndex - ld a, KANGASKHAN - cp e - jr nz, .attach_normally - call CreateEnergyCardListFromHand - jr c, .skip_energy_attach_1 - ld e, PLAY_AREA_ARENA - call CountNumberOfEnergyCardsAttached - or a - jr nz, .attach_normally - xor a - ldh [hTempPlayAreaLocation_ff9d], a - call AITryToPlayEnergyCard - jr c, .skip_energy_attach_1 -.attach_normally - call AIProcessAndTryToPlayEnergy - -.skip_energy_attach_1 -; play Pokemon from hand again - call AIDecidePlayPokemonCard - ld a, AI_TRAINER_CARD_PHASE_15 - call AIProcessHandTrainerCards -; if used Professor Oak, process new hand -; if not, then proceed to attack. - ld a, [wPreviousAIFlags] - and AI_FLAG_USED_PROFESSOR_OAK - jr z, .try_attack - ld a, AI_TRAINER_CARD_PHASE_01 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_02 - call AIProcessHandTrainerCards - call AIDecidePlayPokemonCard - ret c ; return if turn ended - ld a, AI_TRAINER_CARD_PHASE_07 - call AIProcessHandTrainerCards - call AIProcessRetreat - ld a, AI_TRAINER_CARD_PHASE_10 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_11 - call AIProcessHandTrainerCards - ld a, [wAlreadyPlayedEnergy] - or a - jr nz, .skip_energy_attach_2 - call AIProcessAndTryToPlayEnergy -.skip_energy_attach_2 - call AIDecidePlayPokemonCard -.try_attack -; attack if possible, if not, -; finish turn without attacking. - call AIProcessAndTryToUseAttack - ret c ; return if turn ended - ld a, OPPACTION_FINISH_NO_ATTACK - bank1call AIMakeDecision - ret diff --git a/src/engine/ai/decks/legendary_moltres.asm b/src/engine/ai/decks/legendary_moltres.asm deleted file mode 100644 index c2a3882..0000000 --- a/src/engine/ai/decks/legendary_moltres.asm +++ /dev/null @@ -1,176 +0,0 @@ -AIActionTable_LegendaryMoltres: ; 149e8 (05:49e8) - dw .do_turn ; unused - dw .do_turn - dw .start_duel - dw .forced_switch - dw .ko_switch - dw .take_prize - -.do_turn ; 149f4 (5:49f4) - call AIDoTurn_LegendaryMoltres - ret - -.start_duel ; 149f8 (5:49f8) - call InitAIDuelVars - call .store_list_pointers - call SetUpBossStartingHandAndDeck - call TrySetUpBossStartingPlayArea - ret nc ; Play Area set up was successful - call AIPlayInitialBasicCards - ret - -.forced_switch ; 14a09 (5:4a09) - call AIDecideBenchPokemonToSwitchTo - ret - -.ko_switch ; 14a0d (5:4a0d) - call AIDecideBenchPokemonToSwitchTo - ret - -.take_prize ; 14a11 (5:4a11) - call AIPickPrizeCards - ret - -.list_arena ; 14a15 (5:4a15) - db MAGMAR2 - db GROWLITHE - db VULPIX - db MAGMAR1 - db MOLTRES1 - db MOLTRES2 - db $00 - -.list_bench ; 14a1c (5:4a1c) - db MOLTRES1 - db VULPIX - db GROWLITHE - db MAGMAR2 - db MAGMAR1 - db $00 - -.list_play_hand ; 14a22 (5:4a22) - db MOLTRES2 - db MOLTRES1 - db VULPIX - db GROWLITHE - db MAGMAR2 - db MAGMAR1 - db $00 - -.list_retreat ; 14a29 (5:4a29) - ai_retreat GROWLITHE, -5 - ai_retreat VULPIX, -5 - db $00 - -.list_energy ; 14a2e (5:4a2e) - ai_energy VULPIX, 3, +0 - ai_energy NINETALES2, 3, +1 - ai_energy GROWLITHE, 3, +1 - ai_energy ARCANINE2, 4, +1 - ai_energy MAGMAR1, 4, -1 - ai_energy MAGMAR2, 1, -1 - ai_energy MOLTRES2, 3, +2 - ai_energy MOLTRES1, 4, +2 - db $00 - -.list_prize ; 14a47 (5:4a47) - db ENERGY_REMOVAL - db MOLTRES2 - db $00 - -.store_list_pointers ; 14a4a (5:4a4a) - store_list_pointer wAICardListAvoidPrize, .list_prize - store_list_pointer wAICardListArenaPriority, .list_arena - store_list_pointer wAICardListBenchPriority, .list_bench - store_list_pointer wAICardListPlayFromHandPriority, .list_play_hand - store_list_pointer wAICardListRetreatBonus, .list_retreat - store_list_pointer wAICardListEnergyBonus, .list_energy - ret - -AIDoTurn_LegendaryMoltres: ; 14a81 (5:4a81) -; initialize variables - call InitAITurnVars - farcall HandleAIAntiMewtwoDeckStrategy - jp nc, .try_attack -; process Trainer cards -; phase 2 through 4. - ld a, AI_TRAINER_CARD_PHASE_02 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_04 - call AIProcessHandTrainerCards - -; check if AI can play Moltres2 -; from hand and if so, play it. - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - cp MAX_PLAY_AREA_POKEMON - jr nc, .skip_moltres ; skip if bench is full - ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK - call GetTurnDuelistVariable - cp DECK_SIZE - 9 - jr nc, .skip_moltres ; skip if cards in deck <= 9 - ld a, MUK - call CountPokemonIDInBothPlayAreas - jr c, .skip_moltres ; skip if Muk in play - ld a, MOLTRES2 - call LookForCardIDInHandList_Bank5 - jr nc, .skip_moltres ; skip if no Moltres2 in hand - ldh [hTemp_ffa0], a - ld a, OPPACTION_PLAY_BASIC_PKMN - bank1call AIMakeDecision - -.skip_moltres -; play Pokemon from hand - call AIDecidePlayPokemonCard - ret c ; return if turn ended -; process Trainer cards - ld a, AI_TRAINER_CARD_PHASE_05 - call AIProcessHandTrainerCards - call AIProcessRetreat - ld a, AI_TRAINER_CARD_PHASE_10 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_11 - call AIProcessHandTrainerCards -; play Energy card if possible - ld a, [wAlreadyPlayedEnergy] - or a - jr nz, .skip_attach_energy - -; if Magmar2 is the Arena card and has no energy attached, -; try attaching an energy card to it from the hand. -; otherwise, run normal AI energy attach routine. - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call GetCardIDFromDeckIndex - ld a, MAGMAR2 - cp e - jr nz, .attach_normally - ; Magmar2 is the Arena card - call CreateEnergyCardListFromHand - jr c, .skip_attach_energy - ld e, PLAY_AREA_ARENA - call CountNumberOfEnergyCardsAttached - or a - jr nz, .attach_normally - xor a ; PLAY_AREA_ARENA - ldh [hTempPlayAreaLocation_ff9d], a - call AITryToPlayEnergyCard - jr c, .skip_attach_energy - -.attach_normally -; play Energy card if possible - call AIProcessAndTryToPlayEnergy -.skip_attach_energy -; try playing Pokemon cards from hand again - call AIDecidePlayPokemonCard - ld a, AI_TRAINER_CARD_PHASE_13 - call AIProcessHandTrainerCards - -.try_attack -; attack if possible, if not, -; finish turn without attacking. - call AIProcessAndTryToUseAttack - ret c - ld a, OPPACTION_FINISH_NO_ATTACK - bank1call AIMakeDecision - ret diff --git a/src/engine/ai/decks/legendary_ronald.asm b/src/engine/ai/decks/legendary_ronald.asm deleted file mode 100644 index 3356838..0000000 --- a/src/engine/ai/decks/legendary_ronald.asm +++ /dev/null @@ -1,203 +0,0 @@ -AIActionTable_LegendaryRonald: ; 1546f (5:546f) - dw .do_turn ; unused - dw .do_turn - dw .start_duel - dw .forced_switch - dw .ko_switch - dw .take_prize - -.do_turn ; 1547b (5:547b) - call AIDoTurn_LegendaryRonald - ret - -.start_duel ; 1547f (5:547f) - call InitAIDuelVars - call .store_list_pointers - call SetUpBossStartingHandAndDeck - call TrySetUpBossStartingPlayArea - ret nc - call AIPlayInitialBasicCards - ret - -.forced_switch ; 15490 (5:5490) - call AIDecideBenchPokemonToSwitchTo - ret - -.ko_switch ; 15494 (5:5494) - call AIDecideBenchPokemonToSwitchTo - ret - -.take_prize ; 15498 (5:5498) - call AIPickPrizeCards - ret - -.list_arena ; 1549c (5:549c) - db KANGASKHAN - db DRATINI - db EEVEE - db ZAPDOS3 - db ARTICUNO2 - db MOLTRES2 - db $00 - -.list_bench ; 154a3 (5:54a3) - db KANGASKHAN - db DRATINI - db EEVEE - db $00 - -.list_play_hand ; 154a7 (5:54a7) - db MOLTRES2 - db ZAPDOS3 - db KANGASKHAN - db DRATINI - db EEVEE - db ARTICUNO2 - db $00 - -.list_retreat ; 154ae (5:54ae) - ai_retreat EEVEE, -2 - db $00 - -.list_energy ; 154b1 (5:54b1) - ai_energy FLAREON1, 3, +0 - ai_energy MOLTRES2, 3, +0 - ai_energy VAPOREON1, 3, +0 - ai_energy ARTICUNO2, 0, -8 - ai_energy JOLTEON1, 4, +0 - ai_energy ZAPDOS3, 0, -8 - ai_energy KANGASKHAN, 4, -1 - ai_energy EEVEE, 3, +0 - ai_energy DRATINI, 3, +0 - ai_energy DRAGONAIR, 4, +0 - ai_energy DRAGONITE1, 3, +0 - db $00 - -.list_prize ; 154d3 (5:54d3) - db MOLTRES2 - db ARTICUNO2 - db ZAPDOS3 - db DRAGONITE1 - db GAMBLER - db $00 - -.store_list_pointers ; 154d9 (5:54d9) - store_list_pointer wAICardListAvoidPrize, .list_prize - store_list_pointer wAICardListArenaPriority, .list_arena - store_list_pointer wAICardListBenchPriority, .list_bench - store_list_pointer wAICardListPlayFromHandPriority, .list_play_hand - ; missing store_list_pointer wAICardListRetreatBonus, .list_retreat - store_list_pointer wAICardListEnergyBonus, .list_energy - ret - -AIDoTurn_LegendaryRonald: ; 15507 (5:5507) -; initialize variables - call InitAITurnVars -; process Trainer cards - ld a, AI_TRAINER_CARD_PHASE_01 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_02 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_04 - call AIProcessHandTrainerCards - -; check if AI can play Moltres2 -; from hand and if so, play it. - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - cp MAX_PLAY_AREA_POKEMON - jr nc, .skip_moltres_1 ; skip if bench is full - ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK - call GetTurnDuelistVariable - cp DECK_SIZE - 9 - jr nc, .skip_moltres_1 ; skip if cards in deck <= 9 - ld a, MUK - call CountPokemonIDInBothPlayAreas - jr c, .skip_moltres_1 ; skip if Muk in play - ld a, MOLTRES2 - call LookForCardIDInHandList_Bank5 - jr nc, .skip_moltres_1 ; skip if no Moltres2 in hand - ldh [hTemp_ffa0], a - ld a, OPPACTION_PLAY_BASIC_PKMN - bank1call AIMakeDecision - -.skip_moltres_1 -; play Pokemon from hand - call AIDecidePlayPokemonCard - ret c ; return if turn ended -; process Trainer cards - ld a, AI_TRAINER_CARD_PHASE_05 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_07 - call AIProcessHandTrainerCards - call AIProcessRetreat - ld a, AI_TRAINER_CARD_PHASE_10 - call AIProcessHandTrainerCards -; play Energy card if possible - ld a, [wAlreadyPlayedEnergy] - or a - jr nz, .skip_attach_energy_1 - call AIProcessAndTryToPlayEnergy -.skip_attach_energy_1 -; try playing Pokemon cards from hand again - call AIDecidePlayPokemonCard - ret c ; return if turn ended - ld a, AI_TRAINER_CARD_PHASE_15 -; if used Professor Oak, process new hand -; if not, then proceed to attack. - call AIProcessHandTrainerCards - ld a, [wPreviousAIFlags] - and AI_FLAG_USED_PROFESSOR_OAK - jr z, .try_attack - ld a, AI_TRAINER_CARD_PHASE_01 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_02 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_04 - call AIProcessHandTrainerCards - -; check if AI can play Moltres2 -; from hand and if so, play it. - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - cp MAX_PLAY_AREA_POKEMON - jr nc, .skip_moltres_2 ; skip if bench is full - ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK - call GetTurnDuelistVariable - cp DECK_SIZE - 9 - jr nc, .skip_moltres_2 ; skip if cards in deck <= 9 - ld a, MUK - call CountPokemonIDInBothPlayAreas - jr c, .skip_moltres_2 ; skip if Muk in play - ld a, MOLTRES2 - call LookForCardIDInHandList_Bank5 - jr nc, .skip_moltres_2 ; skip if no Moltres2 in hand - ldh [hTemp_ffa0], a - ld a, OPPACTION_PLAY_BASIC_PKMN - bank1call AIMakeDecision - -.skip_moltres_2 - call AIDecidePlayPokemonCard - ret c ; return if turn ended - ld a, AI_TRAINER_CARD_PHASE_05 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_07 - call AIProcessHandTrainerCards - call AIProcessRetreat - ld a, AI_TRAINER_CARD_PHASE_10 - call AIProcessHandTrainerCards - ld a, [wAlreadyPlayedEnergy] - or a - jr nz, .skip_attach_energy_2 - call AIProcessAndTryToPlayEnergy -.skip_attach_energy_2 - call AIDecidePlayPokemonCard - ret c ; return if turn ended -.try_attack -; attack if possible, if not, -; finish turn without attacking. - call AIProcessAndTryToUseAttack - ret c ; return if turn ended - ld a, OPPACTION_FINISH_NO_ATTACK - bank1call AIMakeDecision - ret diff --git a/src/engine/ai/decks/legendary_zapdos.asm b/src/engine/ai/decks/legendary_zapdos.asm deleted file mode 100644 index cc99f0c..0000000 --- a/src/engine/ai/decks/legendary_zapdos.asm +++ /dev/null @@ -1,153 +0,0 @@ -AIActionTable_LegendaryZapdos: ; 14b0f (05:4b0f) - dw .do_turn ; unused - dw .do_turn - dw .start_duel - dw .forced_switch - dw .ko_switch - dw .take_prize - -.do_turn ; 14b1b (5:4b1b) - call AIDoTurn_LegendaryZapdos - ret - -.start_duel ; 14b1f (5:4b1f) - call InitAIDuelVars - call .store_list_pointers - call SetUpBossStartingHandAndDeck - call TrySetUpBossStartingPlayArea - ret nc - call AIPlayInitialBasicCards - ret - -.forced_switch ; 14b30 (5:4b30) - call AIDecideBenchPokemonToSwitchTo - ret - -.ko_switch ; 14b34 (5:4b34) - call AIDecideBenchPokemonToSwitchTo - ret - -.take_prize ; 14b38 (5:4b38) - call AIPickPrizeCards - ret - -.list_arena ; 14b3c (5:4b3c) - db ELECTABUZZ2 - db VOLTORB - db EEVEE - db ZAPDOS1 - db ZAPDOS2 - db ZAPDOS3 - db $00 - -.list_bench ; 14b43 (5:4b43) - db ZAPDOS2 - db ZAPDOS1 - db EEVEE - db VOLTORB - db ELECTABUZZ2 - db $00 - -.list_retreat ; 14b49 (5:4b49) - ai_retreat EEVEE, -5 - ai_retreat VOLTORB, -5 - ai_retreat ELECTABUZZ2, -5 - db $00 - -.list_energy ; 14b50 (5:4b50) - ai_energy VOLTORB, 1, -1 - ai_energy ELECTRODE1, 3, +0 - ai_energy ELECTABUZZ2, 2, -1 - ai_energy JOLTEON2, 3, +1 - ai_energy ZAPDOS1, 4, +2 - ai_energy ZAPDOS2, 4, +2 - ai_energy ZAPDOS3, 3, +1 - ai_energy EEVEE, 3, +0 - db $00 - -.list_prize ; 14b69 (5:4b69) - db GAMBLER - db ZAPDOS3 - db $00 - -.store_list_pointers ; 14b6c (5:4b6c) - store_list_pointer wAICardListAvoidPrize, .list_prize - store_list_pointer wAICardListArenaPriority, .list_arena - store_list_pointer wAICardListBenchPriority, .list_bench - store_list_pointer wAICardListPlayFromHandPriority, .list_bench - ; missing store_list_pointer wAICardListRetreatBonus, .list_retreat - store_list_pointer wAICardListEnergyBonus, .list_energy - ret - -AIDoTurn_LegendaryZapdos: ; 14b9a (5:4b9a) -; initialize variables - call InitAITurnVars - farcall HandleAIAntiMewtwoDeckStrategy - jp nc, .try_attack -; process Trainer cards - ld a, AI_TRAINER_CARD_PHASE_01 - call AIProcessHandTrainerCards - ld a, AI_TRAINER_CARD_PHASE_04 - call AIProcessHandTrainerCards -; play Pokemon from hand - call AIDecidePlayPokemonCard - ret c ; return if turn ended - ld a, AI_TRAINER_CARD_PHASE_07 - call AIProcessHandTrainerCards - call AIProcessRetreat - ld a, AI_TRAINER_CARD_PHASE_10 - call AIProcessHandTrainerCards -; play Energy card if possible. - ld a, [wAlreadyPlayedEnergy] - or a - jr nz, .skip_energy_attach - -; if Arena card is Voltorb and there's Electrode1 in hand, -; or if it's Electabuzz, try attaching Energy card -; to the Arena card if it doesn't have any energy attached. -; Otherwise if Energy card is not needed, -; go through normal AI energy attach routine. - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call GetCardIDFromDeckIndex - ld a, VOLTORB - cp e - jr nz, .check_electabuzz - ld a, ELECTRODE1 - call LookForCardIDInHandList_Bank5 - jr nc, .attach_normally - jr .voltorb_or_electabuzz -.check_electabuzz - ld a, ELECTABUZZ2 - cp e - jr nz, .attach_normally - -.voltorb_or_electabuzz - call CreateEnergyCardListFromHand - jr c, .skip_energy_attach - ld e, PLAY_AREA_ARENA - call CountNumberOfEnergyCardsAttached - or a - jr nz, .attach_normally - xor a ; PLAY_AREA_ARENA - ldh [hTempPlayAreaLocation_ff9d], a - call AITryToPlayEnergyCard - jr c, .skip_energy_attach - -.attach_normally - call AIProcessAndTryToPlayEnergy - -.skip_energy_attach -; play Pokemon from hand again - call AIDecidePlayPokemonCard - ret c ; return if turn ended - ld a, AI_TRAINER_CARD_PHASE_13 - call AIProcessHandTrainerCards -.try_attack -; attack if possible, if not, -; finish turn without attacking. - call AIProcessAndTryToUseAttack - ret c ; return if turn ended - ld a, OPPACTION_FINISH_NO_ATTACK - bank1call AIMakeDecision - ret diff --git a/src/engine/ai/decks/powerful_ronald.asm b/src/engine/ai/decks/powerful_ronald.asm deleted file mode 100644 index 096fbea..0000000 --- a/src/engine/ai/decks/powerful_ronald.asm +++ /dev/null @@ -1,92 +0,0 @@ -AIActionTable_PowerfulRonald: ; 1534b (5:534b) - dw .do_turn ; unused - dw .do_turn - dw .start_duel - dw .forced_switch - dw .ko_switch - dw .take_prize - -.do_turn ; 15357 (5:5357) - call AIMainTurnLogic - ret - -.start_duel ; 1535b (5:535b) - call InitAIDuelVars - call .store_list_pointers - call SetUpBossStartingHandAndDeck - call TrySetUpBossStartingPlayArea - ret nc - call AIPlayInitialBasicCards - ret - -.forced_switch ; 1536c (5:536c) - call AIDecideBenchPokemonToSwitchTo - ret - -.ko_switch ; 15370 (5:5370) - call AIDecideBenchPokemonToSwitchTo - ret - -.take_prize ; 15374 (5:5374) - call AIPickPrizeCards - ret - -.list_arena ; 15378 (5:5378) - db KANGASKHAN - db ELECTABUZZ2 - db HITMONCHAN - db MR_MIME - db LICKITUNG - db HITMONLEE - db TAUROS - db JYNX - db MEWTWO1 - db DODUO - db $00 - -.list_bench ; 15383 (5:5383) - db KANGASKHAN - db HITMONLEE - db HITMONCHAN - db TAUROS - db DODUO - db JYNX - db MEWTWO1 - db ELECTABUZZ2 - db MR_MIME - db LICKITUNG - db $00 - -.list_retreat ; 1538e (5:538e) - ai_retreat KANGASKHAN, -1 - ai_retreat DODUO, -1 - ai_retreat DODRIO, -1 - db $00 - -.list_energy ; 15395 (5:5395) - ai_energy ELECTABUZZ2, 2, +1 - ai_energy HITMONLEE, 3, +1 - ai_energy HITMONCHAN, 3, +1 - ai_energy MR_MIME, 2, +0 - ai_energy JYNX, 3, +0 - ai_energy MEWTWO1, 2, +0 - ai_energy DODUO, 3, -1 - ai_energy DODRIO, 3, -1 - ai_energy LICKITUNG, 2, +0 - ai_energy KANGASKHAN, 4, -1 - ai_energy TAUROS, 3, +0 - db $00 - -.list_prize ; 153b7 (5:53b7) - db GAMBLER - db ENERGY_REMOVAL - db $00 - -.store_list_pointers ; 153ba (5:53ba) - store_list_pointer wAICardListAvoidPrize, .list_prize - store_list_pointer wAICardListArenaPriority, .list_arena - store_list_pointer wAICardListBenchPriority, .list_bench - store_list_pointer wAICardListPlayFromHandPriority, .list_bench - ; missing store_list_pointer wAICardListRetreatBonus, .list_retreat - store_list_pointer wAICardListEnergyBonus, .list_energy - ret diff --git a/src/engine/ai/decks/rock_crusher.asm b/src/engine/ai/decks/rock_crusher.asm deleted file mode 100644 index 41a50fa..0000000 --- a/src/engine/ai/decks/rock_crusher.asm +++ /dev/null @@ -1,74 +0,0 @@ -AIActionTable_RockCrusher: ; 14f0e (5:4f0e) - dw .do_turn ; unused - dw .do_turn - dw .start_duel - dw .forced_switch - dw .ko_switch - dw .take_prize - -.do_turn ; 14f1a (5:4f1a) - call AIMainTurnLogic - ret - -.start_duel ; 14f1e (5:4f1e) - call InitAIDuelVars - call .store_list_pointers - call SetUpBossStartingHandAndDeck - call TrySetUpBossStartingPlayArea - ret nc - call AIPlayInitialBasicCards - ret - -.forced_switch ; 14f2f (5:4f2f) - call AIDecideBenchPokemonToSwitchTo - ret - -.ko_switch ; 14f33 (5:4f33) - call AIDecideBenchPokemonToSwitchTo - ret - -.take_prize ; 14f37 (5:4f37) - call AIPickPrizeCards - ret - -.list_arena ; 14f3b (5:4f3b) - db RHYHORN - db ONIX - db GEODUDE - db DIGLETT - db $00 - -.list_bench ; 14f40 (5:4f40) - db DIGLETT - db GEODUDE - db RHYHORN - db ONIX - db $00 - -.list_retreat ; 14f45 (5:4f45) - ai_retreat DIGLETT, -1 - db $00 - -.list_energy ; 14f48 (5:4f48) - ai_energy DIGLETT, 3, +1 - ai_energy DUGTRIO, 4, +0 - ai_energy GEODUDE, 2, +1 - ai_energy GRAVELER, 3, +0 - ai_energy GOLEM, 4, +0 - ai_energy ONIX, 2, -1 - ai_energy RHYHORN, 3, +0 - db $00 - -.list_prize ; 14f5e (5:4f5e) - db ENERGY_REMOVAL - db RHYHORN - db $00 - -.store_list_pointers ; 14f61 (5:4f61) - store_list_pointer wAICardListAvoidPrize, .list_prize - store_list_pointer wAICardListArenaPriority, .list_arena - store_list_pointer wAICardListBenchPriority, .list_bench - store_list_pointer wAICardListPlayFromHandPriority, .list_bench - ; missing store_list_pointer wAICardListRetreatBonus, .list_retreat - store_list_pointer wAICardListEnergyBonus, .list_energy - ret diff --git a/src/engine/ai/decks/sams_practice.asm b/src/engine/ai/decks/sams_practice.asm deleted file mode 100644 index dddce61..0000000 --- a/src/engine/ai/decks/sams_practice.asm +++ /dev/null @@ -1,205 +0,0 @@ -; AI for Sam's practice duel, which handles his scripted actions. -; will act as a normal duelist AI after turn 7. -AIActionTable_SamPractice: ; 147bd (05:47bd) - dw .do_turn ; unused - dw .do_turn - dw .start_duel - dw .forced_switch - dw .ko_switch - dw .take_prize - -.do_turn ; 147c9 (5:47c9) - call IsAIPracticeScriptedTurn - jr nc, .scripted_1 -; not scripted, use AI main turn logic - call AIMainTurnLogic - ret -.scripted_1 ; use scripted actions instead - call AIPerformScriptedTurn - ret - -.start_duel ; 147d6 (5:47d6) - call SetSamsStartingPlayArea - ret - -.forced_switch ; 147da (5:47da) - call IsAIPracticeScriptedTurn - jr nc, .scripted_2 - call AIDecideBenchPokemonToSwitchTo - ret -.scripted_2 - call PickRandomBenchPokemon - ret - -.ko_switch: ; 147e7 (5:47e7) - call IsAIPracticeScriptedTurn - jr nc, .scripted_3 - call AIDecideBenchPokemonToSwitchTo - ret -.scripted_3 - call GetPlayAreaLocationOfRaticateOrRattata - ret - -.take_prize: ; 147f4 (5:47f4) - call AIPickPrizeCards - ret - -; returns carry if number of turns -; the AI has taken >= 7. -; used to know whether AI Sam is still -; doing scripted turns. -IsAIPracticeScriptedTurn: ; 147f8 (5:47f8) - ld a, [wDuelTurns] - srl a - cp 7 - ccf - ret - -; places one Machop from the hand to the Play Area -; and sets the number of prizes to 2. -SetSamsStartingPlayArea: ; 14801 (5:4801) - call CreateHandCardList - ld hl, wDuelTempList -.loop_hand - ld a, [hli] - ldh [hTempCardIndex_ff98], a - cp $ff - ret z - call LoadCardDataToBuffer1_FromDeckIndex - cp MACHOP - jr nz, .loop_hand - ldh a, [hTempCardIndex_ff98] - call PutHandPokemonCardInPlayArea - ld a, 2 - ld [wDuelInitialPrizes], a - ret - -; outputs in a Play Area location of Raticate or Rattata -; in the Bench. If neither is found, just output PLAY_AREA_BENCH_1. -GetPlayAreaLocationOfRaticateOrRattata: ; 1481f (5:481f) - ld a, RATICATE - ld b, PLAY_AREA_BENCH_1 - call LookForCardIDInPlayArea_Bank5 - cp $ff - jr nz, .found - ld a, RATTATA - ld b, PLAY_AREA_BENCH_1 - call LookForCardIDInPlayArea_Bank5 - cp $ff - jr nz, .found - ld a, PLAY_AREA_BENCH_1 -.found - ldh [hTempPlayAreaLocation_ff9d], a - ret - -; has AI execute some scripted actions depending on Duel turn. -AIPerformScriptedTurn: ; 1483a (5:483a) - ld a, [wDuelTurns] - srl a - ld hl, .scripted_actions_list - call JumpToFunctionInTable - -; always attack with Arena card's first attack. -; if it's unusable end turn without attacking. - xor a - ldh [hTempPlayAreaLocation_ff9d], a - ld [wSelectedAttack], a - call CheckIfSelectedAttackIsUnusable - jr c, .unusable - call AITryUseAttack - ret - -.unusable - ld a, OPPACTION_FINISH_NO_ATTACK - bank1call AIMakeDecision - ret - -.scripted_actions_list ; 1485a (05:485a) - dw .turn_1 - dw .turn_2 - dw .turn_3 - dw .turn_4 - dw .turn_5 - dw .turn_6 - dw .turn_7 - -.turn_1 ; 14868 (5:4868) - ld d, MACHOP - ld e, FIGHTING_ENERGY - call AIAttachEnergyInHandToCardInPlayArea - ret - -.turn_2 ; 14870 (5:4870) - ld a, RATTATA - call LookForCardIDInHandList_Bank5 - ldh [hTemp_ffa0], a - ld a, OPPACTION_PLAY_BASIC_PKMN - bank1call AIMakeDecision - ld d, RATTATA - ld e, FIGHTING_ENERGY - call AIAttachEnergyInHandToCardInPlayArea - ret - -.turn_3 ; 14884 (5:4884) - ld a, RATTATA - ld b, PLAY_AREA_ARENA - call LookForCardIDInPlayArea_Bank5 - ldh [hTempPlayAreaLocation_ffa1], a - ld a, RATICATE - call LookForCardIDInHandList_Bank5 - ldh [hTemp_ffa0], a - ld a, OPPACTION_EVOLVE_PKMN - bank1call AIMakeDecision - ld d, RATICATE - ld e, LIGHTNING_ENERGY - call AIAttachEnergyInHandToCardInPlayArea - ret - -.turn_4 ; 148a1 (5:48a1) - ld d, RATICATE - ld e, LIGHTNING_ENERGY - call AIAttachEnergyInHandToCardInPlayArea - ret - -.turn_5 ; 148a9 (5:48a9) - ld a, MACHOP - call LookForCardIDInHandList_Bank5 - ldh [hTemp_ffa0], a - ld a, OPPACTION_PLAY_BASIC_PKMN - bank1call AIMakeDecision - ld d, MACHOP - ld e, FIGHTING_ENERGY - call AIAttachEnergyInHandToCardInBench - -; this is a bug, it's attempting to compare a card ID with a deck index. -; the intention was to change the card to switch to depending on whether -; the first Machop was KO'd at this point in the Duel or not. -; because of the buggy comparison, this will always jump the -; 'inc a' instruction and switch to PLAY_AREA_BENCH_1. -; in a normal Practice Duel following Dr. Mason's instructions, -; this will always lead to the AI correctly switching Raticate with Machop, -; but in case of a "Free" Duel where the first Machop is not KO'd, -; the intention was to switch to PLAY_AREA_BENCH_2 instead. -; but due to 'inc a' always being skipped, it will switch to Raticate. - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - cp MACHOP ; wrong - ld a, PLAY_AREA_BENCH_1 - jr nz, .retreat - inc a ; PLAY_AREA_BENCH_2 - -.retreat - call AITryToRetreat - ret - -.turn_6 ; 148cc (5:48cc) - ld d, MACHOP - ld e, FIGHTING_ENERGY - call AIAttachEnergyInHandToCardInPlayArea - ret - -.turn_7 ; 148d4 (5:48d4) - ld d, MACHOP - ld e, FIGHTING_ENERGY - call AIAttachEnergyInHandToCardInPlayArea - ret diff --git a/src/engine/ai/decks/strange_psyshock.asm b/src/engine/ai/decks/strange_psyshock.asm deleted file mode 100644 index ef378b0..0000000 --- a/src/engine/ai/decks/strange_psyshock.asm +++ /dev/null @@ -1,81 +0,0 @@ -AIActionTable_StrangePsyshock: ; 15122 (5:5122) - dw .do_turn ; unused - dw .do_turn - dw .start_duel - dw .forced_switch - dw .ko_switch - dw .take_prize - -.do_turn ; 1512e (5:512e) - call AIMainTurnLogic - ret - -.start_duel ; 15132 (5:5132) - call InitAIDuelVars - call .store_list_pointers - call SetUpBossStartingHandAndDeck - call TrySetUpBossStartingPlayArea - ret nc - call AIPlayInitialBasicCards - ret - -.forced_switch ; 15143 (5:5143) - call AIDecideBenchPokemonToSwitchTo - ret - -.ko_switch ; 15147 (5:5147) - call AIDecideBenchPokemonToSwitchTo - ret - -.take_prize ; 1514b (5:514b) - call AIPickPrizeCards - ret - -.list_arena ; 1514f (5:514f) - db KANGASKHAN - db CHANSEY - db SNORLAX - db MR_MIME - db ABRA - db $00 - -.list_bench ; 15155 (5:5155) - db ABRA - db MR_MIME - db KANGASKHAN - db SNORLAX - db CHANSEY - db $00 - -.list_retreat ; 1515b (5:515b) - ai_retreat ABRA, -3 - ai_retreat SNORLAX, -3 - ai_retreat KANGASKHAN, -1 - ai_retreat CHANSEY, -1 - db $00 - -.list_energy ; 15164 (5:5164) - ai_energy ABRA, 3, +1 - ai_energy KADABRA, 3, +0 - ai_energy ALAKAZAM, 3, +0 - ai_energy MR_MIME, 2, +0 - ai_energy CHANSEY, 2, -2 - ai_energy KANGASKHAN, 4, -2 - ai_energy SNORLAX, 0, -8 - db $00 - -.list_prize ; 1517a (5:517a) - db GAMBLER - db MR_MIME - db ALAKAZAM - db SWITCH - db $00 - -.store_list_pointers ; 1517f (5:517f) - store_list_pointer wAICardListAvoidPrize, .list_prize - store_list_pointer wAICardListArenaPriority, .list_arena - store_list_pointer wAICardListBenchPriority, .list_bench - store_list_pointer wAICardListPlayFromHandPriority, .list_bench - ; missing store_list_pointer wAICardListRetreatBonus, .list_retreat - store_list_pointer wAICardListEnergyBonus, .list_energy - ret diff --git a/src/engine/ai/decks/unreferenced.asm b/src/engine/ai/decks/unreferenced.asm deleted file mode 100644 index 8722a27..0000000 --- a/src/engine/ai/decks/unreferenced.asm +++ /dev/null @@ -1,42 +0,0 @@ -AIActionTable_Unreferenced: ; 1406a (5:406a) - dw $406c - dw .do_turn - dw .do_turn - dw .star_duel - dw .forced_switch - dw .ko_switch - dw .take_prize - -.do_turn - call AIDecidePlayPokemonCard - call AIDecideWhetherToRetreat - jr nc, .try_attack - call AIDecideBenchPokemonToSwitchTo - call AITryToRetreat - call AIDecideWhetherToRetreat - jr nc, .try_attack - call AIDecideBenchPokemonToSwitchTo - call AITryToRetreat -.try_attack - call AIProcessAndTryToPlayEnergy - call AIProcessAndTryToUseAttack - ret c - ld a, OPPACTION_FINISH_NO_ATTACK - bank1call AIMakeDecision - ret - -.star_duel - call AIPlayInitialBasicCards - ret - -.forced_switch - call AIDecideBenchPokemonToSwitchTo - ret - -.ko_switch - call AIDecideBenchPokemonToSwitchTo - ret - -.take_prize - call AIPickPrizeCards - ret diff --git a/src/engine/ai/decks/wonders_of_science.asm b/src/engine/ai/decks/wonders_of_science.asm deleted file mode 100644 index 706a7e6..0000000 --- a/src/engine/ai/decks/wonders_of_science.asm +++ /dev/null @@ -1,77 +0,0 @@ -AIActionTable_WondersOfScience: ; 151ad (5:51ad) - dw .do_turn ; unused - dw .do_turn - dw .start_duel - dw .forced_switch - dw .ko_switch - dw .take_prize - -.do_turn ; 151b9 (5:51b9) - call AIMainTurnLogic - ret - -.start_duel ; 151bd (5:51bd) - call InitAIDuelVars - call .store_list_pointers - call SetUpBossStartingHandAndDeck - call TrySetUpBossStartingPlayArea - ret nc - call AIPlayInitialBasicCards - ret - -.forced_switch ; 151ce (5:51ce) - call AIDecideBenchPokemonToSwitchTo - ret - -.ko_switch ; 151d2 (5:51d2) - call AIDecideBenchPokemonToSwitchTo - ret - -.take_prize ; 151d6 (5:51d6) - call AIPickPrizeCards - ret - -.list_arena ; 151da (5:51da) - db MEWTWO1 - db MEWTWO3 - db MEWTWO2 - db GRIMER - db KOFFING - db PORYGON - db $00 - -.list_bench ; 151e1 (5:51e1) - db GRIMER - db KOFFING - db MEWTWO3 - db MEWTWO2 - db MEWTWO1 - db PORYGON - db $00 - -.list_retreat ; 151e8 (5:51e8) - db $00 - -.list_energy ; 151e9 (5:51e9) - ai_energy GRIMER, 3, +0 - ai_energy MUK, 4, +0 - ai_energy KOFFING, 2, +0 - ai_energy WEEZING, 3, +0 - ai_energy MEWTWO1, 2, -1 - ai_energy MEWTWO3, 2, -1 - ai_energy MEWTWO2, 2, -1 - ai_energy PORYGON, 2, -1 - db $00 - -.list_prize ; 15202 (5:5202) - db MUK - db $00 - -.store_list_pointers ; 15204 (5:5204) - store_list_pointer wAICardListAvoidPrize, .list_prize - store_list_pointer wAICardListArenaPriority, .list_arena - store_list_pointer wAICardListBenchPriority, .list_bench - store_list_pointer wAICardListPlayFromHandPriority, .list_bench - ; missing store_list_pointer wAICardListRetreatBonus, .list_retreat - store_list_pointer wAICardListEnergyBonus, .list_energy - ret diff --git a/src/engine/ai/decks/zapping_selfdestruct.asm b/src/engine/ai/decks/zapping_selfdestruct.asm deleted file mode 100644 index da5e7c6..0000000 --- a/src/engine/ai/decks/zapping_selfdestruct.asm +++ /dev/null @@ -1,75 +0,0 @@ -AIActionTable_ZappingSelfdestruct: ; 15019 (5:5019) - dw .do_turn ; unused - dw .do_turn - dw .start_duel - dw .forced_switch - dw .ko_switch - dw .take_prize - -.do_turn ; 15025 (5:5025) - call AIMainTurnLogic - ret - -.start_duel ; 15029 (5:5029) - call InitAIDuelVars - call .store_list_pointers - call SetUpBossStartingHandAndDeck - call TrySetUpBossStartingPlayArea - ret nc - call AIPlayInitialBasicCards - ret - -.forced_switch ; 1503a (5:503a) - call AIDecideBenchPokemonToSwitchTo - ret - -.ko_switch ; 1503e (5:503e) - call AIDecideBenchPokemonToSwitchTo - ret - -.take_prize ; 15042 (5:5042) - call AIPickPrizeCards - ret - -.list_arena ; 15046 (5:5046) - db KANGASKHAN - db ELECTABUZZ2 - db TAUROS - db MAGNEMITE1 - db VOLTORB - db $00 - -.list_bench ; 1504c (5:504c) - db MAGNEMITE1 - db VOLTORB - db ELECTABUZZ2 - db TAUROS - db KANGASKHAN - db $00 - -.list_retreat ; 15052 (5:5052) - ai_retreat VOLTORB, -1 - db $00 - -.list_energy ; 15055 (5:5055) - ai_energy MAGNEMITE1, 3, +1 - ai_energy MAGNETON1, 4, +0 - ai_energy VOLTORB, 3, +1 - ai_energy ELECTRODE1, 3, +0 - ai_energy ELECTABUZZ2, 1, +0 - ai_energy KANGASKHAN, 2, -2 - ai_energy TAUROS, 3, +0 - db $00 - -.list_prize ; 1506b (5:506b) - db KANGASKHAN - db $00 - -.store_list_pointers ; 1506d (5:506d) - store_list_pointer wAICardListAvoidPrize, .list_prize - store_list_pointer wAICardListArenaPriority, .list_arena - store_list_pointer wAICardListBenchPriority, .list_bench - store_list_pointer wAICardListPlayFromHandPriority, .list_bench - ; missing store_list_pointer wAICardListRetreatBonus, .list_retreat - store_list_pointer wAICardListEnergyBonus, .list_energy - ret diff --git a/src/engine/ai/energy.asm b/src/engine/ai/energy.asm deleted file mode 100644 index ce8c037..0000000 --- a/src/engine/ai/energy.asm +++ /dev/null @@ -1,1048 +0,0 @@ -; processes AI energy card playing logic -; with AI_ENERGY_FLAG_DONT_PLAY flag on -; unreferenced -Func_16488: ; 16488 (5:6488) - ld a, AI_ENERGY_FLAG_DONT_PLAY - ld [wAIEnergyAttachLogicFlags], a - ld de, wTempPlayAreaAIScore - ld hl, wPlayAreaAIScore - ld b, MAX_PLAY_AREA_POKEMON -.loop - ld a, [hli] - ld [de], a - inc de - dec b - jr nz, .loop - ld a, [wAIScore] - ld [de], a - jr AIProcessAndTryToPlayEnergy.has_logic_flags - -; have AI choose an energy card to play, but do not play it. -; does not consider whether the cards have evolutions to be played. -; return carry if an energy card is chosen to use in any Play Area card, -; and if so, return its Play Area location in hTempPlayAreaLocation_ff9d. -AIProcessButDontPlayEnergy_SkipEvolution: ; 164a1 (5:64a1) - ld a, AI_ENERGY_FLAG_DONT_PLAY | AI_ENERGY_FLAG_SKIP_EVOLUTION - ld [wAIEnergyAttachLogicFlags], a - -; backup wPlayAreaAIScore in wTempPlayAreaAIScore. - ld de, wTempPlayAreaAIScore - ld hl, wPlayAreaAIScore - ld b, MAX_PLAY_AREA_POKEMON -.loop - ld a, [hli] - ld [de], a - inc de - dec b - jr nz, .loop - - ld a, [wAIScore] - ld [de], a - - jr AIProcessEnergyCards - -; have AI choose an energy card to play, but do not play it. -; does not consider whether the cards have evolutions to be played. -; return carry if an energy card is chosen to use in any Bench card, -; and if so, return its Play Area location in hTempPlayAreaLocation_ff9d. -AIProcessButDontPlayEnergy_SkipEvolutionAndArena: ; 164ba (5:64ba) - ld a, AI_ENERGY_FLAG_DONT_PLAY | AI_ENERGY_FLAG_SKIP_EVOLUTION | AI_ENERGY_FLAG_SKIP_ARENA_CARD - ld [wAIEnergyAttachLogicFlags], a - -; backup wPlayAreaAIScore in wTempPlayAreaAIScore. - ld de, wTempPlayAreaAIScore - ld hl, wPlayAreaAIScore - ld b, MAX_PLAY_AREA_POKEMON -.loop - ld a, [hli] - ld [de], a - inc de - dec b - jr nz, .loop - - ld a, [wAIScore] - ld [de], a - - jr AIProcessEnergyCards - -; copies wTempPlayAreaAIScore to wPlayAreaAIScore -; and loads wAIScore with value in wTempAIScore. -; identical to RetrievePlayAreaAIScoreFromBackup2. -RetrievePlayAreaAIScoreFromBackup1: ; 164d3 (5:64d3) - push af - ld de, wPlayAreaAIScore - ld hl, wTempPlayAreaAIScore - ld b, MAX_PLAY_AREA_POKEMON -.loop - ld a, [hli] - ld [de], a - inc de - dec b - jr nz, .loop - ld a, [hl] - ld [wAIScore], a - pop af - ret - -; have AI decide whether to play energy card from hand -; and determine which card is best to attach it. -AIProcessAndTryToPlayEnergy: ; 164e8 (5:64e8) - xor a - ld [wAIEnergyAttachLogicFlags], a - -.has_logic_flags - call CreateEnergyCardListFromHand - jr nc, AIProcessEnergyCards - -; no energy - ld a, [wAIEnergyAttachLogicFlags] - or a - jr z, .exit - jp RetrievePlayAreaAIScoreFromBackup1 -.exit - or a - ret - -; have AI decide whether to play energy card -; and determine which card is best to attach it. -AIProcessEnergyCards: ; 164fc (5:64fc) -; initialize Play Area AI score - ld a, $80 - ld b, MAX_PLAY_AREA_POKEMON - ld hl, wPlayAreaEnergyAIScore -.loop - ld [hli], a - dec b - jr nz, .loop - -; Legendary Articuno Deck has its own energy card logic - call HandleLegendaryArticunoEnergyScoring - -; start the main Play Area loop - ld b, PLAY_AREA_ARENA - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - ld c, a - -.loop_play_area - push bc - ld a, b - ldh [hTempPlayAreaLocation_ff9d], a - ld a, $80 - ld [wAIScore], a - ld a, $ff - ld [wTempAI], a - ld a, [wAIEnergyAttachLogicFlags] - and AI_ENERGY_FLAG_SKIP_EVOLUTION - jr nz, .check_venusaur - -; check if energy needed is found in hand -; and if there's an evolution in hand or deck -; and if so, add to AI score - call CreateHandCardList - ldh a, [hTempPlayAreaLocation_ff9d] - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - ld [wCurCardCanAttack], a - call GetAttacksEnergyCostBits - ld hl, wDuelTempList - call CheckEnergyFlagsNeededInList - jp nc, .store_score - ld a, [wCurCardCanAttack] - call CheckForEvolutionInList - jr nc, .no_evolution_in_hand - ld [wTempAI], a ; store evolution card found - ld a, 2 - call AddToAIScore - jr .check_venusaur - -.no_evolution_in_hand - ld a, [wCurCardCanAttack] - call CheckForEvolutionInDeck - jr nc, .check_venusaur - ld a, 1 - call AddToAIScore - -; if there's no Muk in any Play Area -; and there's Venusaur2 in own Play Area, -; add to AI score -.check_venusaur - ld a, MUK - call CountPokemonIDInBothPlayAreas - jr c, .check_if_active - ld a, VENUSAUR2 - call CountPokemonIDInPlayArea - jr nc, .check_if_active - ld a, 1 - call AddToAIScore - -.check_if_active - ldh a, [hTempPlayAreaLocation_ff9d] - or a - jr nz, .bench - -; arena - ld a, [wAIBarrierFlagCounter] - bit AI_MEWTWO_MILL_F, a - jr z, .add_to_score - -; subtract from score instead -; if Player is running Mewtwo1 mill deck. - ld a, 5 - call SubFromAIScore - jr .check_defending_can_ko - -.add_to_score - ld a, 4 - call AddToAIScore - -; lower AI score if poison/double poison -; will KO Pokémon between turns -; or if the defending Pokémon can KO - ld a, DUELVARS_ARENA_CARD_HP - call GetTurnDuelistVariable - call CalculateByteTensDigit - cp 3 - jr nc, .check_defending_can_ko - ; hp < 30 - cp 2 - jr z, .has_20_hp - ; hp = 10 - ld a, DUELVARS_ARENA_CARD_STATUS - call GetTurnDuelistVariable - and POISONED - jr z, .check_defending_can_ko - jr .poison_will_ko -.has_20_hp - ld a, DUELVARS_ARENA_CARD_STATUS - call GetTurnDuelistVariable - and DOUBLE_POISONED - jr z, .check_defending_can_ko -.poison_will_ko - ld a, 10 - call SubFromAIScore - jr .check_bench -.check_defending_can_ko - call CheckIfDefendingPokemonCanKnockOut - jr nc, .ai_score_bonus - ld a, 10 - call SubFromAIScore - -; if either poison will KO or defending Pokémon can KO, -; check if there are bench Pokémon, -; if there are not, add AI score -.check_bench - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - dec a - jr nz, .ai_score_bonus - ld a, 6 - call AddToAIScore - jr .ai_score_bonus - -; lower AI score by 3 - (bench HP)/10 -; if bench HP < 30 -.bench - add DUELVARS_ARENA_CARD_HP - call GetTurnDuelistVariable - call CalculateByteTensDigit - cp 3 - jr nc, .ai_score_bonus -; hp < 30 - ld b, a - ld a, 3 - sub b - call SubFromAIScore - -; check list in wAICardListEnergyBonus -.ai_score_bonus - ld a, [wAICardListEnergyBonus + 1] - or a - jr z, .check_boss_deck ; is null - ld h, a - ld a, [wAICardListEnergyBonus] - ld l, a - - push hl - ldh a, [hTempPlayAreaLocation_ff9d] - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call GetCardIDFromDeckIndex - pop hl - -.loop_id_list - ld a, [hli] - or a - jr z, .check_boss_deck - cp e - jr nz, .next_id - - ; number of attached energy cards - ld a, [hli] - ld d, a - push de - ldh a, [hTempPlayAreaLocation_ff9d] - ld e, a - call GetPlayAreaCardAttachedEnergies - ld a, [wTotalAttachedEnergies] - pop de - cp d - jr c, .check_id_score - ; already reached target number of energy cards - ld a, 10 - call SubFromAIScore - jr .store_score - -.check_id_score - ld a, [hli] - cp $80 - jr c, .decrease_score_1 - sub $80 - call AddToAIScore - jr .check_boss_deck - -.decrease_score_1 - ld d, a - ld a, $80 - sub d - call SubFromAIScore - jr .check_boss_deck - -.next_id - inc hl - inc hl - jr .loop_id_list - -; if it's a boss deck, call Func_174f2 -; and apply to the AI score the values -; determined for this card -.check_boss_deck - call CheckIfNotABossDeckID - jr c, .skip_boss_deck - - call Func_174f2 - ldh a, [hTempPlayAreaLocation_ff9d] - ld c, a - ld b, $00 - ld hl, wPlayAreaEnergyAIScore - add hl, bc - ld a, [hl] - cp $80 - jr c, .decrease_score_2 - sub $80 - call AddToAIScore - jr .skip_boss_deck - -.decrease_score_2 - ld b, a - ld a, $80 - sub b - call SubFromAIScore - -.skip_boss_deck - ld a, 1 - call AddToAIScore - -; add AI score for both attacks, -; according to their energy requirements. - xor a ; first attack - call DetermineAIScoreOfAttackEnergyRequirement - ld a, SECOND_ATTACK - call DetermineAIScoreOfAttackEnergyRequirement - -; store bench score for this card. -.store_score - ldh a, [hTempPlayAreaLocation_ff9d] - ld c, a - ld b, $00 - ld hl, wPlayAreaAIScore - add hl, bc - ld a, [wAIScore] - ld [hl], a - pop bc - inc b - dec c - jp nz, .loop_play_area - -; the Play Area loop is over and the score -; for each card has been calculated. -; now to determine the highest score. - call FindPlayAreaCardWithHighestAIScore - jp nc, .not_found - - ld a, [wAIEnergyAttachLogicFlags] - or a - jr z, .play_card - scf - jp RetrievePlayAreaAIScoreFromBackup1 - -.play_card - call CreateEnergyCardListFromHand - jp AITryToPlayEnergyCard - -.not_found: ; 1668a (5:668a) - ld a, [wAIEnergyAttachLogicFlags] - or a - jr z, .no_carry - jp RetrievePlayAreaAIScoreFromBackup1 -.no_carry - or a - ret - -; checks score related to selected attack, -; in order to determine whether to play energy card. -; the AI score is increased/decreased accordingly. -; input: -; [wSelectedAttack] = attack to check. -DetermineAIScoreOfAttackEnergyRequirement: ; 16695 (5:6695) - ld [wSelectedAttack], a - call CheckEnergyNeededForAttack - jp c, .not_enough_energy - ld a, ATTACK_FLAG2_ADDRESS | ATTACHED_ENERGY_BOOST_F - call CheckLoadedAttackFlag - jr c, .attached_energy_boost - ld a, ATTACK_FLAG2_ADDRESS | DISCARD_ENERGY_F - call CheckLoadedAttackFlag - jr c, .discard_energy - jp .check_evolution - -.attached_energy_boost - ld a, [wLoadedAttackEffectParam] - cp MAX_ENERGY_BOOST_IS_LIMITED - jr z, .check_surplus_energy - - ; is MAX_ENERGY_BOOST_IS_NOT_LIMITED, - ; which is equal to 3, add to score. - call AddToAIScore - jp .check_evolution - -.check_surplus_energy - call CheckIfNoSurplusEnergyForAttack - jr c, .asm_166cd - cp 3 ; check how much surplus energy - jr c, .asm_166cd - -.asm_166c5 - ld a, 5 - call SubFromAIScore - jp .check_evolution - -.asm_166cd - ld a, 2 - call AddToAIScore - -; check whether attack has ATTACHED_ENERGY_BOOST flag -; and add to AI score if attaching another energy -; will KO defending Pokémon. -; add more to score if this is currently active Pokémon. - ld a, ATTACK_FLAG2_ADDRESS | ATTACHED_ENERGY_BOOST_F - call CheckLoadedAttackFlag - jp nc, .check_evolution - ld a, [wSelectedAttack] - call EstimateDamage_VersusDefendingCard - ld a, DUELVARS_ARENA_CARD_HP - call GetNonTurnDuelistVariable - ld hl, wDamage - sub [hl] - jp c, .check_evolution - jp z, .check_evolution - ld a, [wDamage] - add 10 ; boost gained by attaching another energy card - ld b, a - ld a, DUELVARS_ARENA_CARD_HP - call GetNonTurnDuelistVariable - sub b - jr c, .attaching_kos_player - jr nz, .check_evolution - -.attaching_kos_player - ld a, 20 - call AddToAIScore - ldh a, [hTempPlayAreaLocation_ff9d] - or a - jr nz, .check_evolution - ld a, 10 - call AddToAIScore - jr .check_evolution - -; checks if there is surplus energy for attack -; that discards attached energy card. -; if current card is Zapdos2, don't add to score. -; if there is no surplus energy, encourage playing energy. -.discard_energy - ld a, [wLoadedCard1ID] - cp ZAPDOS2 - jr z, .check_evolution - call CheckIfNoSurplusEnergyForAttack - jr c, .asm_166cd - jr .asm_166c5 - -.not_enough_energy - ld a, ATTACK_FLAG2_ADDRESS | FLAG_2_BIT_5_F - call CheckLoadedAttackFlag - jr nc, .check_color_needed - ld a, 5 - call SubFromAIScore - -; if the energy card color needed is in hand, increase AI score. -; if a colorless card is needed, increase AI score. -.check_color_needed - ld a, b - or a - jr z, .check_colorless_needed - ld a, e - call LookForCardIDInHand - jr c, .check_colorless_needed - ld a, 4 - call AddToAIScore - jr .check_total_needed -.check_colorless_needed - ld a, c - or a - jr z, .check_evolution - ld a, 3 - call AddToAIScore - -; if only one energy card is needed for attack, -; encourage playing energy card. -.check_total_needed - ld a, b - add c - dec a - jr nz, .check_evolution - ld a, 3 - call AddToAIScore - -; if the attack KOs player and this is the active card, add to AI score. - ldh a, [hTempPlayAreaLocation_ff9d] - or a - jr nz, .check_evolution - ld a, [wSelectedAttack] - call EstimateDamage_VersusDefendingCard - ld a, DUELVARS_ARENA_CARD_HP - call GetNonTurnDuelistVariable - ld hl, wDamage - sub [hl] - jr z, .atk_kos_defending - jr nc, .check_evolution -.atk_kos_defending - ld a, 20 - call AddToAIScore - -; this is possibly a bug. -; this is an identical check as above to test whether this card is active. -; in case it is active, the score gets added 10 more points, -; in addition to the 20 points already added above. -; what was probably intended was to add 20 points -; plus 10 in case it is the Arena card. - ldh a, [hTempPlayAreaLocation_ff9d] - or a - jr nz, .check_evolution - ld a, 10 - call AddToAIScore - -.check_evolution - ld a, [wTempAI] ; evolution in hand - cp $ff - ret z - -; temporarily replace this card with evolution in hand. - ld b, a - ldh a, [hTempPlayAreaLocation_ff9d] - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - push af - ld [hl], b - -; check for energy still needed for evolution to attack. -; if FLAG_2_BIT_5 is not set, check what color is needed. -; if the energy card color needed is in hand, increase AI score. -; if a colorless card is needed, increase AI score. - call CheckEnergyNeededForAttack - jr nc, .done - ld a, ATTACK_FLAG2_ADDRESS | FLAG_2_BIT_5_F - call CheckLoadedAttackFlag - jr c, .done - ld a, b - or a - jr z, .check_colorless_needed_evo - ld a, e - call LookForCardIDInHand - jr c, .check_colorless_needed_evo - ld a, 2 - call AddToAIScore - jr .done -.check_colorless_needed_evo - ld a, c - or a - jr z, .done - ld a, 1 - call AddToAIScore - -; recover the original card in the Play Area location. -.done - ldh a, [hTempPlayAreaLocation_ff9d] - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - pop af - ld [hl], a - ret - -; returns in hTempPlayAreaLocation_ff9d the Play Area location -; of the card with the highest Play Area AI score, unless -; the highest score is below $85. -; if it succeeds in return a card location, set carry. -; if AI_ENERGY_FLAG_SKIP_ARENA_CARD is set in wAIEnergyAttachLogicFlags -; doesn't include the Arena card and there's no minimum score. -FindPlayAreaCardWithHighestAIScore: ; 167b5 (5:67b5) - ld a, [wAIEnergyAttachLogicFlags] - and AI_ENERGY_FLAG_SKIP_ARENA_CARD - jr nz, .only_bench - - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - ld b, a - ld c, PLAY_AREA_ARENA - ld e, c - ld d, c - ld hl, wPlayAreaAIScore -; find highest Play Area AI score. -.loop_1 - ld a, [hli] - cp e - jr c, .next_1 - jr z, .next_1 - ld e, a ; overwrite highest score found - ld d, c ; overwrite Play Area of highest score -.next_1 - inc c - dec b - jr nz, .loop_1 - -; if highest AI score is below $85, return no carry. -; else, store Play Area location and return carry. - ld a, e - cp $85 - jr c, .not_enough_score - ld a, d - ldh [hTempPlayAreaLocation_ff9d], a - scf - ret -.not_enough_score - or a - ret - -; same as above but only check bench Pokémon scores. -.only_bench - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - dec a - jr z, .no_carry - - ld b, a - ld e, 0 - ld c, PLAY_AREA_BENCH_1 - ld d, c - ld hl, wPlayAreaAIScore + 1 -.loop_2 - ld a, [hli] - cp e - jr c, .next_2 - jr z, .next_2 - ld e, a ; overwrite highest score found - ld d, c ; overwrite Play Area of highest score -.next_2 - inc c - dec b - jr nz, .loop_2 - -; in this case, there is no minimum threshold AI score. - ld a, d - ldh [hTempPlayAreaLocation_ff9d], a - scf - ret -.no_carry - or a - ret - -; returns carry if there's an evolution card -; that can evolve card in hTempPlayAreaLocation_ff9d, -; and that card needs energy to use wSelectedAttack. -CheckIfEvolutionNeedsEnergyForAttack: ; 16805 (5:6805) - call CreateHandCardList - ldh a, [hTempPlayAreaLocation_ff9d] - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call CheckCardEvolutionInHandOrDeck - jr c, .has_evolution - or a - ret - -.has_evolution - ld b, a - ldh a, [hTempPlayAreaLocation_ff9d] - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - push af - ld [hl], b - call CheckEnergyNeededForAttack - jr c, .not_enough_energy - ldh a, [hTempPlayAreaLocation_ff9d] - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - pop af - ld [hl], a - or a - ret - -.not_enough_energy - ldh a, [hTempPlayAreaLocation_ff9d] - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - pop af - ld [hl], a - scf - ret - -; returns in e the card ID of the energy required for -; the Discard/Energy Boost attack loaded in wSelectedAttack. -; if it's Zapdos2's Thunderbolt attack, return no carry. -; if it's Charizard's Fire Spin or Exeggutor's Big Eggsplosion -; attack, don't return energy card ID, but set carry. -; output: -; b = 1 if needs color energy, 0 otherwise; -; c = 1 if only needs colorless energy, 0 otherwise; -; carry set if not Zapdos2's Thunderbolt attack. -GetEnergyCardForDiscardOrEnergyBoostAttack: ; 1683b (5:683b) -; load card ID and check selected attack index. - ldh a, [hTempPlayAreaLocation_ff9d] - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call LoadCardDataToBuffer2_FromDeckIndex - ld b, a - ld a, [wSelectedAttack] - or a - jr z, .first_attack - -; check if second attack is Zapdos2's Thunderbolt, -; Charizard's Fire Spin or Exeggutor's Big Eggsplosion, -; for these to be treated differently. -; for both attacks, load its energy cost. - ld a, b - cp ZAPDOS2 - jr z, .zapdos2 - cp CHARIZARD - jr z, .charizard_or_exeggutor - cp EXEGGUTOR - jr z, .charizard_or_exeggutor - ld hl, wLoadedCard2Atk2EnergyCost - jr .fire -.first_attack - ld hl, wLoadedCard2Atk1EnergyCost - -; check which energy color the attack requires, -; and load in e the card ID of corresponding energy card, -; then return carry flag set. -.fire - ld a, [hli] - ld b, a - and $f0 - jr z, .grass - ld e, FIRE_ENERGY - jr .set_carry -.grass - ld a, b - and $0f - jr z, .lightning - ld e, GRASS_ENERGY - jr .set_carry -.lightning - ld a, [hli] - ld b, a - and $f0 - jr z, .water - ld e, LIGHTNING_ENERGY - jr .set_carry -.water - ld a, b - and $0f - jr z, .fighting - ld e, WATER_ENERGY - jr .set_carry -.fighting - ld a, [hli] - ld b, a - and $f0 - jr z, .psychic - ld e, FIGHTING_ENERGY - jr .set_carry -.psychic - ld e, PSYCHIC_ENERGY - -.set_carry - lb bc, $01, $00 - scf - ret - -; for Zapdos2's Thunderbolt attack, return with no carry. -.zapdos2 - or a - ret - -; Charizard's Fire Spin and Exeggutor's Big Eggsplosion, -; return carry. -.charizard_or_exeggutor - lb bc, $00, $01 - scf - ret - -; called after the AI has decided which card to attach -; energy from hand. AI does checks to determine whether -; this card needs more energy or not, and chooses the -; right energy card to play. If the card is played, -; return with carry flag set. -AITryToPlayEnergyCard: ; 1689f (5:689f) -; check if energy cards are still needed for attacks. -; if first attack doesn't need, test for the second attack. - xor a - ld [wTempAI], a - ld [wSelectedAttack], a - call CheckEnergyNeededForAttack - jr nc, .second_attack - ld a, b - or a - jr nz, .check_deck - ld a, c - or a - jr nz, .check_deck - -.second_attack - ld a, SECOND_ATTACK - ld [wSelectedAttack], a - call CheckEnergyNeededForAttack - jr nc, .check_discard_or_energy_boost - ld a, b - or a - jr nz, .check_deck - ld a, c - or a - jr nz, .check_deck - -; neither attack needs energy cards to be used. -; check whether these attacks can be given -; extra energy cards for their effects. -.check_discard_or_energy_boost - ld a, $01 - ld [wTempAI], a - -; for both attacks, check if it has the effect of -; discarding energy cards or attached energy boost. - xor a ; FIRST_ATTACK_OR_PKMN_POWER - ld [wSelectedAttack], a - call CheckEnergyNeededForAttack - ld a, ATTACK_FLAG2_ADDRESS | ATTACHED_ENERGY_BOOST_F - call CheckLoadedAttackFlag - jr c, .energy_boost_or_discard_energy - ld a, ATTACK_FLAG2_ADDRESS | DISCARD_ENERGY_F - call CheckLoadedAttackFlag - jr c, .energy_boost_or_discard_energy - - ld a, SECOND_ATTACK - ld [wSelectedAttack], a - call CheckEnergyNeededForAttack - ld a, ATTACK_FLAG2_ADDRESS | ATTACHED_ENERGY_BOOST_F - call CheckLoadedAttackFlag - jr c, .energy_boost_or_discard_energy - ld a, ATTACK_FLAG2_ADDRESS | DISCARD_ENERGY_F - call CheckLoadedAttackFlag - jr c, .energy_boost_or_discard_energy - -; if none of the attacks have those flags, do an additional -; check to ascertain whether evolution card needs energy -; to use second attack. Return if all these checks fail. - call CheckIfEvolutionNeedsEnergyForAttack - ret nc - call CreateEnergyCardListFromHand - jr .check_deck - -; for attacks that discard energy or get boost for -; additional energy cards, get the energy card ID required by attack. -; if it's Zapdos2's Thunderbolt attack, return. -.energy_boost_or_discard_energy - call GetEnergyCardForDiscardOrEnergyBoostAttack - ret nc - -; some decks allow basic Pokémon to be given double colorless -; in anticipation for evolution, so play card if that is the case. -.check_deck - call CheckSpecificDecksToAttachDoubleColorless - jr c, .play_energy_card - - ld a, b - or a - jr z, .colorless_energy - -; in this case, Pokémon needs a specific basic energy card. -; look for basic energy card needed in hand and play it. - ld a, e - call LookForCardIDInHand - ldh [hTemp_ffa0], a - jr nc, .play_energy_card - -; in this case Pokémon just needs colorless (any basic energy card). -; if active card, check if it needs 2 colorless. -; if it does (and also doesn't additionally need a color energy), -; look for double colorless card in hand and play it if found. -.colorless_energy - ldh a, [hTempPlayAreaLocation_ff9d] - or a - jr nz, .look_for_any_energy - ld a, c - or a - jr z, .check_if_done - cp 2 - jr nz, .look_for_any_energy - - ; needs two colorless - ld hl, wDuelTempList -.loop_1 - ld a, [hli] - cp $ff - jr z, .look_for_any_energy - ldh [hTemp_ffa0], a - call GetCardIDFromDeckIndex - ld a, e - cp DOUBLE_COLORLESS_ENERGY - jr nz, .loop_1 - jr .play_energy_card - -; otherwise, look for any card and play it. -; if it's a boss deck, only play double colorless in this situation. -.look_for_any_energy - ld hl, wDuelTempList - call CountCardsInDuelTempList - call ShuffleCards -.loop_2 - ld a, [hli] - cp $ff - jr z, .check_if_done - call CheckIfOpponentHasBossDeckID - jr nc, .load_card - push af - call GetCardIDFromDeckIndex - ld a, e - cp DOUBLE_COLORLESS_ENERGY - pop bc - jr z, .loop_2 - ld a, b -.load_card - ldh [hTemp_ffa0], a - -; plays energy card loaded in hTemp_ffa0 and sets carry flag. -.play_energy_card - ldh a, [hTempPlayAreaLocation_ff9d] - ldh [hTempPlayAreaLocation_ffa1], a - ld a, OPPACTION_PLAY_ENERGY - bank1call AIMakeDecision - scf - ret - -; wTempAI is 1 if the attack had a Discard/Energy Boost effect, -; and 0 otherwise. If 1, then return. If not one, check if -; there is still a second attack to check. -.check_if_done - ld a, [wTempAI] - or a - jr z, .check_first_attack - ret -.check_first_attack - ld a, [wSelectedAttack] - or a - jp z, .second_attack - ret - -; check if playing certain decks so that AI can decide whether to play -; double colorless to some specific cards. -; these are cards that do not need double colorless to any of their attacks -; but are required by their evolutions. -; return carry if there's a double colorless in hand to attach -; and it's one of the card IDs from these decks. -; output: -; [hTemp_ffa0] = card index of double colorless in hand; -; carry set if can play energy card. -CheckSpecificDecksToAttachDoubleColorless: ; 1696e (5:696e) - push bc - push de - push hl - -; check if AI is playing any of the applicable decks. - ld a, [wOpponentDeckID] - cp LEGENDARY_DRAGONITE_DECK_ID - jr z, .legendary_dragonite_deck - cp FIRE_CHARGE_DECK_ID - jr z, .fire_charge_deck - cp LEGENDARY_RONALD_DECK_ID - jr z, .legendary_ronald_deck - -.no_carry - pop hl - pop de - pop bc - or a - ret - -; if playing Legendary Dragonite deck, -; check for Charmander and Dratini. -.legendary_dragonite_deck - call .get_id - cp CHARMANDER - jr z, .check_colorless_attached - cp DRATINI - jr z, .check_colorless_attached - jr .no_carry - -; if playing Fire Charge deck, -; check for Growlithe. -.fire_charge_deck - call .get_id - cp GROWLITHE - jr z, .check_colorless_attached - jr .no_carry - -; if playing Legendary Ronald deck, -; check for Dratini. -.legendary_ronald_deck - call .get_id - cp DRATINI - jr z, .check_colorless_attached - jr .no_carry - -; check if card has any colorless energy cards attached, -; and if there are any, return no carry. -.check_colorless_attached - ldh a, [hTempPlayAreaLocation_ff9d] - ld e, a - call GetPlayAreaCardAttachedEnergies - ld a, [wAttachedEnergies + COLORLESS] - or a - jr nz, .no_carry - -; card has no colorless energy, so look for double colorless -; in hand and if found, return carry and its card index. - ld a, DOUBLE_COLORLESS_ENERGY - call LookForCardIDInHand - jr c, .no_carry - ldh [hTemp_ffa0], a - pop hl - pop de - pop bc - scf - ret - -.get_id: - ldh a, [hTempPlayAreaLocation_ff9d] - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call GetCardIDFromDeckIndex - ld a, e - ret diff --git a/src/engine/ai/hand_pokemon.asm b/src/engine/ai/hand_pokemon.asm deleted file mode 100644 index 27a4176..0000000 --- a/src/engine/ai/hand_pokemon.asm +++ /dev/null @@ -1,627 +0,0 @@ -; determine whether AI plays -; basic cards from hand -AIDecidePlayPokemonCard: ; 15eae (5:5eae) - call CreateHandCardList - call SortTempHandByIDList - ld hl, wDuelTempList - ld de, wHandTempList - call CopyHandCardList - ld hl, wHandTempList - -.next_hand_card - ld a, [hli] - cp $ff - jp z, AIDecideEvolution - - ld [wTempAIPokemonCard], a - push hl - call LoadCardDataToBuffer1_FromDeckIndex - ld a, [wLoadedCard1Type] - cp TYPE_ENERGY - jr nc, .skip - ; skip non-pokemon cards - - ld a, [wLoadedCard1Stage] - or a - jr nz, .skip - ; skip non-basic pokemon - - ld a, 130 - ld [wAIScore], a - call AIDecidePlayLegendaryBirds - -; if Play Area has more than 4 Pokémon, decrease AI score -; else, increase AI score - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - cp 4 - jr c, .has_4_or_fewer - ld a, 20 - call SubFromAIScore - jr .check_defending_can_ko -.has_4_or_fewer - ld a, 50 - call AddToAIScore - -; if defending Pokémon can KO active card, increase AI score -.check_defending_can_ko - xor a - ldh [hTempPlayAreaLocation_ff9d], a - call CheckIfDefendingPokemonCanKnockOut - jr nc, .check_energy_cards - ld a, 20 - call AddToAIScore - -; if energy cards are found in hand -; for this card's attacks, raise AI score -.check_energy_cards - ld a, [wTempAIPokemonCard] - call GetAttacksEnergyCostBits - call CheckEnergyFlagsNeededInList - jr nc, .check_evolution_hand - ld a, 20 - call AddToAIScore - -; if evolution card is found in hand -; for this card, raise AI score -.check_evolution_hand - ld a, [wTempAIPokemonCard] - call CheckForEvolutionInList - jr nc, .check_evolution_deck - ld a, 20 - call AddToAIScore - -; if evolution card is found in deck -; for this card, raise AI score -.check_evolution_deck - ld a, [wTempAIPokemonCard] - call CheckForEvolutionInDeck - jr nc, .check_score - ld a, 10 - call AddToAIScore - -; if AI score is >= 180, play card from hand -.check_score - ld a, [wAIScore] - cp 180 - jr c, .skip - ld a, [wTempAIPokemonCard] - ldh [hTemp_ffa0], a - call CheckIfCardCanBePlayed - jr c, .skip - ld a, OPPACTION_PLAY_BASIC_PKMN - bank1call AIMakeDecision - jr c, .done -.skip - pop hl - jp .next_hand_card -.done - pop hl - ret - -; determine whether AI evolves -; Pokémon in the Play Area -AIDecideEvolution: ; 15f4c (5:5f4c) - call CreateHandCardList - ld hl, wDuelTempList - ld de, wHandTempList - call CopyHandCardList - ld hl, wHandTempList - -.next_hand_card - ld a, [hli] - cp $ff - jp z, .done - ld [wTempAIPokemonCard], a - -; check if Prehistoric Power is active -; and if so, skip to next card in hand - push hl - call IsPrehistoricPowerActive - jp c, .done_hand_card - -; load evolution data to buffer1 -; skip if it's not a Pokémon card -; and if it's a basic stage card - ld a, [wTempAIPokemonCard] - call LoadCardDataToBuffer1_FromDeckIndex - ld a, [wLoadedCard1Type] - cp TYPE_ENERGY - jp nc, .done_hand_card - ld a, [wLoadedCard1Stage] - or a - jp z, .done_hand_card - -; start looping Pokémon in Play Area -; to find a card to evolve - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - ld c, a - ld b, 0 -.next_bench_pokemon - push bc - ld e, b - ld a, [wTempAIPokemonCard] - ld d, a - call CheckIfCanEvolveInto - pop bc - push bc - jp c, .done_bench_pokemon - -; store this Play Area location in wTempAI -; and initialize the AI score - ld a, b - ld [wTempAI], a - ldh [hTempPlayAreaLocation_ff9d], a - ld a, $80 - ld [wAIScore], a - call AIDecideSpecialEvolutions - -; check if the card can use any attacks -; and if any of those attacks can KO - xor a - ld [wSelectedAttack], a - call CheckIfSelectedAttackIsUnusable - jr nc, .can_attack - ld a, $01 - ld [wSelectedAttack], a - call CheckIfSelectedAttackIsUnusable - jr c, .cant_attack_or_ko -.can_attack - ld a, $01 - ld [wCurCardCanAttack], a - call CheckIfAnyAttackKnocksOutDefendingCard - jr nc, .check_evolution_attacks - call CheckIfSelectedAttackIsUnusable - jr c, .check_evolution_attacks - ld a, $01 - ld [wCurCardCanKO], a - jr .check_evolution_attacks -.cant_attack_or_ko - xor a - ld [wCurCardCanAttack], a - ld [wCurCardCanKO], a - -; check evolution to see if it can use any of its attacks: -; if it can, raise AI score; -; if it can't, decrease AI score and if an energy card that is needed -; can be played from the hand, raise AI score. -.check_evolution_attacks - ldh a, [hTempPlayAreaLocation_ff9d] - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - push af - ld a, [wTempAIPokemonCard] - ld [hl], a - xor a - ld [wSelectedAttack], a - call CheckIfSelectedAttackIsUnusable - jr nc, .evolution_can_attack - ld a, $01 - ld [wSelectedAttack], a - call CheckIfSelectedAttackIsUnusable - jr c, .evolution_cant_attack -.evolution_can_attack - ld a, 5 - call AddToAIScore - jr .check_evolution_ko -.evolution_cant_attack - ld a, [wCurCardCanAttack] - or a - jr z, .check_evolution_ko - ld a, 2 - call SubFromAIScore - ld a, [wAlreadyPlayedEnergy] - or a - jr nz, .check_evolution_ko - call LookForEnergyNeededInHand - jr nc, .check_evolution_ko - ld a, 7 - call AddToAIScore - -; if it's an active card: -; if evolution can't KO but the current card can, lower AI score; -; if evolution can KO as well, raise AI score. -.check_evolution_ko - ld a, [wCurCardCanAttack] - or a - jr z, .check_defending_can_ko_evolution - ld a, [wTempAI] - or a - jr nz, .check_defending_can_ko_evolution - call CheckIfAnyAttackKnocksOutDefendingCard - jr nc, .evolution_cant_ko - call CheckIfSelectedAttackIsUnusable - jr c, .evolution_cant_ko - ld a, 5 - call AddToAIScore - jr .check_defending_can_ko_evolution -.evolution_cant_ko - ld a, [wCurCardCanKO] - or a - jr z, .check_defending_can_ko_evolution - ld a, 20 - call SubFromAIScore - -; if defending Pokémon can KO evolution, lower AI score -.check_defending_can_ko_evolution - ld a, [wTempAI] - or a - jr nz, .check_mr_mime - xor a - ldh [hTempPlayAreaLocation_ff9d], a - call CheckIfDefendingPokemonCanKnockOut - jr nc, .check_mr_mime - ld a, 5 - call SubFromAIScore - -; if evolution can't damage player's Mr Mime, lower AI score -.check_mr_mime - ld a, [wTempAI] - call CheckDamageToMrMime - jr c, .check_defending_can_ko - ld a, 20 - call SubFromAIScore - -; if defending Pokémon can KO current card, raise AI score -.check_defending_can_ko - ld a, [wTempAI] - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - pop af - ld [hl], a - ld a, [wTempAI] - or a - jr nz, .check_2nd_stage_hand - xor a - ldh [hTempPlayAreaLocation_ff9d], a - call CheckIfDefendingPokemonCanKnockOut - jr nc, .check_status - ld a, 5 - call AddToAIScore - -; if current card has a status condition, raise AI score -.check_status - ld a, DUELVARS_ARENA_CARD_STATUS - call GetTurnDuelistVariable - or a - jr z, .check_2nd_stage_hand - ld a, 4 - call AddToAIScore - -; if hand has 2nd stage card to evolve evolution card, raise AI score -.check_2nd_stage_hand - ld a, [wTempAIPokemonCard] - call CheckForEvolutionInList - jr nc, .check_2nd_stage_deck - ld a, 2 - call AddToAIScore - jr .check_damage - -; if deck has 2nd stage card to evolve evolution card, raise AI score -.check_2nd_stage_deck - ld a, [wTempAIPokemonCard] - call CheckForEvolutionInDeck - jr nc, .check_damage - ld a, 1 - call AddToAIScore - -; decrease AI score proportional to damage -; AI score -= floor(Damage / 40) -.check_damage - ld a, [wTempAI] - ld e, a - call GetCardDamageAndMaxHP - or a - jr z, .check_mysterious_fossil - srl a - srl a - call CalculateByteTensDigit - call SubFromAIScore - -; if is Mysterious Fossil or -; wLoadedCard1Unknown2 is set to $02, -; raise AI score -.check_mysterious_fossil - ld a, [wTempAI] - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call LoadCardDataToBuffer1_FromDeckIndex - ld a, [wLoadedCard1ID] - cp MYSTERIOUS_FOSSIL - jr z, .mysterious_fossil - ld a, [wLoadedCard1Unknown2] - cp $02 - jr nz, .pikachu_deck - ld a, 2 - call AddToAIScore - jr .pikachu_deck - -.mysterious_fossil - ld a, 5 - call AddToAIScore - -; in Pikachu Deck, decrease AI score for evolving Pikachu -.pikachu_deck - ld a, [wOpponentDeckID] - cp PIKACHU_DECK_ID - jr nz, .check_score - ld a, [wLoadedCard1ID] - cp PIKACHU1 - jr z, .pikachu - cp PIKACHU2 - jr z, .pikachu - cp PIKACHU3 - jr z, .pikachu - cp PIKACHU4 - jr nz, .check_score -.pikachu - ld a, 3 - call SubFromAIScore - -; if AI score >= 133, go through with the evolution -.check_score - ld a, [wAIScore] - cp 133 - jr c, .done_bench_pokemon - ld a, [wTempAI] - ldh [hTempPlayAreaLocation_ffa1], a - ld a, [wTempAIPokemonCard] - ldh [hTemp_ffa0], a - ld a, OPPACTION_EVOLVE_PKMN - bank1call AIMakeDecision - pop bc - jr .done_hand_card - -.done_bench_pokemon - pop bc - inc b - dec c - jp nz, .next_bench_pokemon -.done_hand_card - pop hl - jp .next_hand_card -.done - or a - ret - -; determine AI score for evolving -; Charmeleon, Magikarp, Dragonair and Grimer -; in certain decks -AIDecideSpecialEvolutions: ; 16120 (5:6120) -; check if deck applies - ld a, [wOpponentDeckID] - cp LEGENDARY_DRAGONITE_DECK_ID - jr z, .legendary_dragonite - cp INVINCIBLE_RONALD_DECK_ID - jr z, .invincible_ronald - cp LEGENDARY_RONALD_DECK_ID - jr z, .legendary_ronald - ret - -.legendary_dragonite - ld a, [wLoadedCard2ID] - cp CHARMELEON - jr z, .charmeleon - cp MAGIKARP - jr z, .magikarp - cp DRAGONAIR - jr z, .dragonair - ret - -; check if number of energy cards attached to Charmeleon are at least 3 -; and if adding the energy cards in hand makes at least 6 energy cards -.charmeleon - ldh a, [hTempPlayAreaLocation_ff9d] - ld e, a - call CountNumberOfEnergyCardsAttached - cp 3 - jr c, .not_enough_energy - push af - farcall CountOppEnergyCardsInHand - pop bc - add b - cp 6 - jr c, .not_enough_energy - ld a, 3 - call AddToAIScore - ret -.not_enough_energy - ld a, 10 - call SubFromAIScore - ret - -; check if Magikarp is not the active card -; and has at least 2 energy cards attached -.magikarp - ldh a, [hTempPlayAreaLocation_ff9d] - or a ; active card - ret z - ld e, a - call CountNumberOfEnergyCardsAttached - cp 2 - ret c - ld a, 3 - call AddToAIScore - ret - -.invincible_ronald - ld a, [wLoadedCard2ID] - cp GRIMER - jr z, .grimer - ret - -; check if Grimer is not active card -.grimer - ldh a, [hTempPlayAreaLocation_ff9d] - or a ; active card - ret z - ld a, 10 - call AddToAIScore - ret - -.legendary_ronald - ld a, [wLoadedCard2ID] - cp DRAGONAIR - jr z, .dragonair - ret - -.dragonair - ldh a, [hTempPlayAreaLocation_ff9d] - or a ; active card - jr z, .is_active - -; if Dragonair is benched, check all Pokémon in Play Area -; and sum all the damage in HP of all cards -; if this result is >= 70, check if there's -; a Muk in any duelist's Play Area - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - ld b, a - ld c, 0 -.loop - dec b - ld e, b - push bc - call GetCardDamageAndMaxHP - pop bc - add c - ld c, a - ld a, b - or a - jr nz, .loop - ld a, 70 - cp c - jr c, .check_muk -.lower_score - ld a, 10 - call SubFromAIScore - ret - -; if there's no Muk, raise score -.check_muk - ld a, MUK - call CountPokemonIDInBothPlayAreas - jr c, .lower_score - ld a, 10 - call AddToAIScore - ret - -; if Dragonair is active, check its damage in HP -; if this result is >= 50, -; and if at least 3 energy cards attached, -; check if there's a Muk in any duelist's Play Area -.is_active - ld e, 0 - call GetCardDamageAndMaxHP - cp 50 - jr c, .lower_score - ld e, PLAY_AREA_ARENA - call GetPlayAreaCardAttachedEnergies - ld a, [wTotalAttachedEnergies] - cp 3 - jr c, .lower_score - jr .check_muk - -; determine AI score for the legendary cards -; Moltres, Zapdos and Articuno -AIDecidePlayLegendaryBirds: ; 161d5 (5:61d5) -; check if deck applies - ld a, [wOpponentDeckID] - cp LEGENDARY_ZAPDOS_DECK_ID - jr z, .begin - cp LEGENDARY_ARTICUNO_DECK_ID - jr z, .begin - cp LEGENDARY_RONALD_DECK_ID - jr z, .begin - ret - -; check if card applies -.begin - ld a, [wLoadedCard1ID] - cp ARTICUNO2 - jr z, .articuno - cp MOLTRES2 - jr z, .moltres - cp ZAPDOS3 - jr z, .zapdos - ret - -.articuno - ; exit if not enough Pokemon in Play Area - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - cp 2 - ret c - - call CheckIfActiveCardCanKnockOut - jr c, .subtract - call CheckIfActivePokemonCanUseAnyNonResidualAttack - jr nc, .subtract - call AIDecideWhetherToRetreat - jr c, .subtract - - ; checks for player's active card status - ld a, DUELVARS_ARENA_CARD_STATUS - call GetNonTurnDuelistVariable - and CNF_SLP_PRZ - or a - jr nz, .subtract - - ; checks for player's Pokemon Power - call SwapTurn - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - ld d, a - ld e, $00 - call CopyAttackDataAndDamage_FromDeckIndex - call SwapTurn - ld a, [wLoadedAttackCategory] - cp POKEMON_POWER - jr z, .check_muk_and_snorlax - - ; return if no space on the bench - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - cp MAX_BENCH_POKEMON - jr c, .check_muk_and_snorlax - ret - -.check_muk_and_snorlax - ; checks for Muk in both Play Areas - ld a, MUK - call CountPokemonIDInBothPlayAreas - jr c, .subtract - ; checks if player's active card is Snorlax - ld a, DUELVARS_ARENA_CARD - call GetNonTurnDuelistVariable - call SwapTurn - call GetCardIDFromDeckIndex - call SwapTurn - ld a, e - cp SNORLAX - jr z, .subtract - -; add - ld a, 70 - call AddToAIScore - ret -.subtract - ld a, 100 - call SubFromAIScore - ret - -.moltres - ; checks if there's enough cards in deck - ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK - call GetTurnDuelistVariable - cp 56 ; max number of cards not in deck to activate - jr nc, .subtract - ret - -.zapdos - ; checks for Muk in both Play Areas - ld a, MUK - call CountPokemonIDInBothPlayAreas - jr c, .subtract - ret diff --git a/src/engine/ai/init.asm b/src/engine/ai/init.asm deleted file mode 100644 index 33132cf..0000000 --- a/src/engine/ai/init.asm +++ /dev/null @@ -1,98 +0,0 @@ -InitAIDuelVars: ; 15636 (5:5636) - ld a, wAIDuelVarsEnd - wAIDuelVars - ld hl, wAIDuelVars - call ClearMemory_Bank5 - ld a, 5 - ld [wAIPokedexCounter], a - ld a, $ff - ld [wAIPeekedPrizes], a - ret - -; initializes some variables and sets value of wAIBarrierFlagCounter. -; if Player uses Barrier 3 times in a row, AI checks if Player's deck -; has only Mewtwo1 Pokemon cards (running a Mewtwo1 mill deck). -InitAITurnVars: ; 15649 (5:5649) -; increase Pokedex counter by 1 - ld a, [wAIPokedexCounter] - inc a - ld [wAIPokedexCounter], a - - xor a - ld [wPreviousAIFlags], a - ld [wAITriedAttack], a - ld [wcddc], a - ld [wAIRetreatedThisTurn], a - -; checks if the Player used an attack last turn -; and if it was the second attack of their card. - ld a, [wPlayerAttackingAttackIndex] - cp $ff - jr z, .check_flag - or a - jr z, .check_flag - ld a, [wPlayerAttackingCardIndex] - cp $ff - jr z, .check_flag - -; if the card is Mewtwo1, it means the Player -; used its second attack, Barrier. - call SwapTurn - call GetCardIDFromDeckIndex - call SwapTurn - ld a, e - cp MEWTWO1 - jr nz, .check_flag - ; Player used Barrier last turn - -; check if flag was already set, if so, -; reset wAIBarrierFlagCounter to $80. - ld a, [wAIBarrierFlagCounter] - bit AI_MEWTWO_MILL_F, a - jr nz, .set_flag - -; if not, increase it by 1 and check if it exceeds 2. - inc a - ld [wAIBarrierFlagCounter], a - cp 3 - jr c, .done - -; this means that the Player used Barrier -; at least 3 turns in a row. -; check if Player is running Mewtwo1-only deck, -; if so, set wAIBarrierFlagCounter flag. - ld a, DUELVARS_ARENA_CARD - call GetNonTurnDuelistVariable - call SwapTurn - call GetCardIDFromDeckIndex - call SwapTurn - ld a, e - cp MEWTWO1 - jr nz, .reset_1 - farcall CheckIfPlayerHasPokemonOtherThanMewtwo1 - jr nc, .set_flag -.reset_1 -; reset wAIBarrierFlagCounter - xor a - ld [wAIBarrierFlagCounter], a - jr .done - -.set_flag - ld a, AI_MEWTWO_MILL - ld [wAIBarrierFlagCounter], a - jr .done - -.check_flag -; increase counter by 1 if flag is set - ld a, [wAIBarrierFlagCounter] - bit AI_MEWTWO_MILL_F, a - jr z, .reset_2 - inc a - ld [wAIBarrierFlagCounter], a - jr .done - -.reset_2 -; reset wAIBarrierFlagCounter - xor a - ld [wAIBarrierFlagCounter], a -.done - ret diff --git a/src/engine/ai/pkmn_powers.asm b/src/engine/ai/pkmn_powers.asm deleted file mode 100644 index 8ae629a..0000000 --- a/src/engine/ai/pkmn_powers.asm +++ /dev/null @@ -1,1228 +0,0 @@ -; handle AI routines for Energy Trans. -; uses AI_ENERGY_TRANS_* constants as input: -; - AI_ENERGY_TRANS_RETREAT: transfers enough Grass Energy cards to -; Arena Pokemon for it to be able to pay the Retreat Cost; -; - AI_ENERGY_TRANS_ATTACK: transfers enough Grass Energy cards to -; Arena Pokemon for it to be able to use its second attack; -; - AI_ENERGY_TRANS_TO_BENCH: transfers all Grass Energy cards from -; Arena Pokemon to Bench in case Arena card will be KO'd. -HandleAIEnergyTrans: ; 2219b (8:619b) - ld [wce06], a - -; choose to randomly return - farcall AIChooseRandomlyNotToDoAction - ret c - - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - dec a - ret z ; return if no Bench cards - - ld a, VENUSAUR2 - call CountPokemonIDInPlayArea - ret nc ; return if no Venusaur2 found in own Play Area - - ld a, MUK - call CountPokemonIDInBothPlayAreas - ret c ; return if Muk found in any Play Area - - ld a, [wce06] - cp AI_ENERGY_TRANS_RETREAT - jr z, .check_retreat - - cp AI_ENERGY_TRANS_TO_BENCH - jp z, AIEnergyTransTransferEnergyToBench - - ; AI_ENERGY_TRANS_ATTACK - call .CheckEnoughGrassEnergyCardsForAttack - ret nc - jr .TransferEnergyToArena - -.check_retreat - call .CheckEnoughGrassEnergyCardsForRetreatCost - ret nc - -; use Energy Trans to transfer number of Grass energy cards -; equal to input a from the Bench to the Arena card. -.TransferEnergyToArena - ld [wAINumberOfEnergyTransCards], a - -; look for Venusaur2 in Play Area -; so that its PKMN Power can be used. - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - dec a - ld b, a -.loop_play_area - ld a, DUELVARS_ARENA_CARD - add b - call GetTurnDuelistVariable - ldh [hTempCardIndex_ff9f], a - call GetCardIDFromDeckIndex - ld a, e - cp VENUSAUR2 - jr z, .use_pkmn_power - - ld a, b - or a - ret z ; return when finished Play Area loop - - dec b - jr .loop_play_area - -; use Energy Trans Pkmn Power -.use_pkmn_power - ld a, b - ldh [hTemp_ffa0], a - ld a, OPPACTION_USE_PKMN_POWER - bank1call AIMakeDecision - ld a, OPPACTION_EXECUTE_PKMN_POWER_EFFECT - bank1call AIMakeDecision - - xor a ; PLAY_AREA_ARENA - ldh [hAIEnergyTransPlayAreaLocation], a - ld a, [wAINumberOfEnergyTransCards] - ld d, a - -; look for Grass energy cards that -; are currently attached to a Bench card. - ld e, 0 -.loop_deck_locations - ld a, DUELVARS_CARD_LOCATIONS - add e - call GetTurnDuelistVariable - and %00011111 - cp CARD_LOCATION_BENCH_1 - jr c, .next_card - - and %00001111 - ldh [hTempPlayAreaLocation_ffa1], a - - ld a, e - push de - call GetCardIDFromDeckIndex - ld a, e - pop de - cp GRASS_ENERGY - jr nz, .next_card - - ; store the deck index of energy card - ld a, e - ldh [hAIEnergyTransEnergyCard], a - - push de - ld d, 30 -.small_delay_loop - call DoFrame - dec d - jr nz, .small_delay_loop - - ld a, OPPACTION_6B15 - bank1call AIMakeDecision - pop de - dec d - jr z, .done_transfer - -.next_card - inc e - ld a, DECK_SIZE - cp e - jr nz, .loop_deck_locations - -; transfer is done, perform delay -; and return to main scene. -.done_transfer - ld d, 60 -.big_delay_loop - call DoFrame - dec d - jr nz, .big_delay_loop - ld a, OPPACTION_DUEL_MAIN_SCENE - bank1call AIMakeDecision - ret - -; checks if the Arena card needs energy for its second attack, -; and if it does, return carry if transferring Grass energy from Bench -; would be enough to use it. Outputs number of energy cards needed in a. -.CheckEnoughGrassEnergyCardsForAttack ; 22246 (8:6246) - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call GetCardIDFromDeckIndex - ld a, e - cp EXEGGUTOR - jr z, .is_exeggutor - - xor a ; PLAY_AREA_ARENA - ldh [hTempPlayAreaLocation_ff9d], a - ld a, SECOND_ATTACK - ld [wSelectedAttack], a - farcall CheckEnergyNeededForAttack - jr nc, .attack_false ; return if no energy needed - -; check if colorless energy is needed... - ld a, c - or a - jr nz, .count_if_enough - -; ...otherwise check if basic energy card is needed -; and it's grass energy. - ld a, b - or a - jr z, .attack_false - ld a, e - cp GRASS_ENERGY - jr nz, .attack_false - ld c, b - jr .count_if_enough - -.attack_false - or a - ret - -.count_if_enough -; if there's enough Grass energy cards in Bench -; to satisfy the attack energy cost, return carry. - push bc - call .CountGrassEnergyInBench - pop bc - cp c - jr c, .attack_false - ld a, c - scf - ret - -.is_exeggutor -; in case it's Exeggutor in Arena, return carry -; if there are any Grass energy cards in Bench. - call .CountGrassEnergyInBench - or a - jr z, .attack_false - - scf - ret - -; outputs in a the number of Grass energy cards -; currently attached to Bench cards. -.CountGrassEnergyInBench ; 22286 (8:6286) - lb de, 0, 0 -.count_loop - ld a, DUELVARS_CARD_LOCATIONS - add e - call GetTurnDuelistVariable - and %00011111 - cp CARD_LOCATION_BENCH_1 - jr c, .count_next - -; is in bench - ld a, e - push de - call GetCardIDFromDeckIndex - ld a, e - pop de - cp GRASS_ENERGY - jr nz, .count_next - inc d -.count_next - inc e - ld a, DECK_SIZE - cp e - jr nz, .count_loop - ld a, d - ret - -; returns carry if there are enough Grass energy cards in Bench -; to satisfy the retreat cost of the Arena card. -; if so, output the number of energy cards still needed in a. -.CheckEnoughGrassEnergyCardsForRetreatCost ; 222a9 (8:62a9) - xor a ; PLAY_AREA_ARENA - ldh [hTempPlayAreaLocation_ff9d], a - call GetPlayAreaCardRetreatCost - ld b, a - ld e, PLAY_AREA_ARENA - farcall CountNumberOfEnergyCardsAttached - cp b - jr nc, .retreat_false ; return if enough to retreat - -; see if there's enough Grass energy cards -; in the Bench to satisfy retreat cost - ld c, a - ld a, b - sub c - ld c, a - push bc - call .CountGrassEnergyInBench - pop bc - cp c - jr c, .retreat_false ; return if less cards than needed - -; output number of cards needed to retreat - ld a, c - scf - ret -.retreat_false - or a - ret - -; AI logic to determine whether to use Energy Trans Pkmn Power -; to transfer energy cards attached from the Arena Pokemon to -; some card in the Bench. -AIEnergyTransTransferEnergyToBench: ; 222ca (8:62ca) - xor a ; PLAY_AREA_ARENA - ldh [hTempPlayAreaLocation_ff9d], a - farcall CheckIfDefendingPokemonCanKnockOut - ret nc ; return if Defending can't KO - -; processes attacks and see if any attack would be used by AI. -; if so, return. - farcall AIProcessButDontUseAttack - ret c - -; return if Arena card has no Grass energy cards attached. - ld e, PLAY_AREA_ARENA - call GetPlayAreaCardAttachedEnergies - ld a, [wAttachedEnergies + GRASS] - or a - ret z - -; if no energy card attachment is needed, return. - farcall AIProcessButDontPlayEnergy_SkipEvolutionAndArena - ret nc - -; AI decided that an energy card is needed -; so look for Venusaur2 in Play Area -; so that its PKMN Power can be used. - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - dec a - ld b, a -.loop_play_area - ld a, DUELVARS_ARENA_CARD - add b - call GetTurnDuelistVariable - ldh [hTempCardIndex_ff9f], a - ld [wAIVenusaur2DeckIndex], a - call GetCardIDFromDeckIndex - ld a, e - cp VENUSAUR2 - jr z, .use_pkmn_power - - ld a, b - or a - ret z ; return when Play Area loop is ended - - dec b - jr .loop_play_area - -; use Energy Trans Pkmn Power -.use_pkmn_power - ld a, b - ldh [hTemp_ffa0], a - ld [wAIVenusaur2PlayAreaLocation], a - ld a, OPPACTION_USE_PKMN_POWER - bank1call AIMakeDecision - ld a, OPPACTION_EXECUTE_PKMN_POWER_EFFECT - bank1call AIMakeDecision - -; loop for each energy cards that are going to be transferred. -.loop_energy - xor a - ldh [hTempPlayAreaLocation_ffa1], a - ld a, [wAIVenusaur2PlayAreaLocation] - ldh [hTemp_ffa0], a - - ; returns when Arena card has no Grass energy cards attached. - ld e, PLAY_AREA_ARENA - call GetPlayAreaCardAttachedEnergies - ld a, [wAttachedEnergies + GRASS] - or a - jr z, .done_transfer - -; look for Grass energy cards that -; are currently attached to Arena card. - ld e, 0 -.loop_deck_locations - ld a, DUELVARS_CARD_LOCATIONS - add e - call GetTurnDuelistVariable - cp CARD_LOCATION_ARENA - jr nz, .next_card - - ld a, e - push de - call GetCardIDFromDeckIndex - ld a, e - pop de - cp GRASS_ENERGY - jr nz, .next_card - - ; store the deck index of energy card - ld a, e - ldh [hAIEnergyTransEnergyCard], a - jr .transfer - -.next_card - inc e - ld a, DECK_SIZE - cp e - jr nz, .loop_deck_locations - jr .done_transfer - -.transfer -; get the Bench card location to transfer Grass energy card to. - farcall AIProcessButDontPlayEnergy_SkipEvolutionAndArena - jr nc, .done_transfer - ldh a, [hTempPlayAreaLocation_ff9d] - ldh [hAIEnergyTransPlayAreaLocation], a - - ld d, 30 -.small_delay_loop - call DoFrame - dec d - jr nz, .small_delay_loop - - ld a, [wAIVenusaur2DeckIndex] - ldh [hTempCardIndex_ff9f], a - ld d, a - ld e, FIRST_ATTACK_OR_PKMN_POWER - call CopyAttackDataAndDamage_FromDeckIndex - ld a, OPPACTION_6B15 - bank1call AIMakeDecision - jr .loop_energy - -; transfer is done, perform delay -; and return to main scene. -.done_transfer - ld d, 60 -.big_delay_loop - call DoFrame - dec d - jr nz, .big_delay_loop - ld a, OPPACTION_DUEL_MAIN_SCENE - bank1call AIMakeDecision - ret - -; handles AI logic for using some Pkmn Powers. -; Pkmn Powers handled here are: -; - Heal; -; - Shift; -; - Peek; -; - Strange Behavior; -; - Curse. -; returns carry if turn ended. -HandleAIPkmnPowers: ; 2237f (8:637f) - ld a, MUK - call CountPokemonIDInBothPlayAreas - ccf - ret nc ; return no carry if Muk is in play - - farcall AIChooseRandomlyNotToDoAction - ccf - ret nc ; return no carry if AI randomly decides to - - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - ld b, a - ld c, PLAY_AREA_ARENA - ld a, DUELVARS_ARENA_CARD_STATUS - call GetTurnDuelistVariable - and CNF_SLP_PRZ - jr nz, .next_2 - -.loop_play_area - ld a, DUELVARS_ARENA_CARD - add c - call GetTurnDuelistVariable - ld [wce08], a - - push af - push bc - ld d, a - ld a, c - ldh [hTempPlayAreaLocation_ff9d], a - ld e, FIRST_ATTACK_OR_PKMN_POWER - call CopyAttackDataAndDamage_FromDeckIndex - ld a, [wLoadedAttackCategory] - cp POKEMON_POWER - jr z, .execute_effect - pop bc - jr .next_3 - -.execute_effect - ld a, EFFECTCMDTYPE_INITIAL_EFFECT_2 - bank1call TryExecuteEffectCommandFunction - pop bc - jr c, .next_3 - -; TryExecuteEffectCommandFunction was successful, -; so check what Pkmn Power this is through card's ID. - pop af - call GetCardIDFromDeckIndex - ld a, e - push bc - -; check heal - cp VILEPLUME - jr nz, .check_shift - call HandleAIHeal - jr .next_1 -.check_shift - cp VENOMOTH - jr nz, .check_peek - call HandleAIShift - jr .next_1 -.check_peek - cp MANKEY - jr nz, .check_strange_behavior - call HandleAIPeek - jr .next_1 -.check_strange_behavior - cp SLOWBRO - jr nz, .check_curse - call HandleAIStrangeBehavior - jr .next_1 -.check_curse - cp GENGAR - jr nz, .next_1 - call z, HandleAICurse - jr c, .done - -.next_1 - pop bc -.next_2 - inc c - ld a, c - cp b - jr nz, .loop_play_area - ret - -.next_3 - pop af - jr .next_2 - -.done - pop bc - ret - -; checks whether AI uses Heal on Pokemon in Play Area. -; input: -; c = Play Area location (PLAY_AREA_*) of Vileplume. -HandleAIHeal: ; 22402 (8:6402) - ld a, c - ldh [hTemp_ffa0], a - call .CheckHealTarget - ret nc ; return if no target to heal - push af - ld a, [wce08] - ldh [hTempCardIndex_ff9f], a - ld a, OPPACTION_USE_PKMN_POWER - bank1call AIMakeDecision - pop af - ldh [hPlayAreaEffectTarget], a - ld a, OPPACTION_EXECUTE_PKMN_POWER_EFFECT - bank1call AIMakeDecision - ld a, OPPACTION_DUEL_MAIN_SCENE - bank1call AIMakeDecision - ret - -; finds a target suitable for AI to use Heal on. -; only heals Arena card if the Defending Pokemon -; cannot KO it after Heal is used. -; returns carry if target was found and outputs -; in a the Play Area location of that card. -.CheckHealTarget ; 22422 (8:6422) -; check if Arena card has any damage counters, -; if not, check Bench instead. - ld e, PLAY_AREA_ARENA - call GetCardDamageAndMaxHP - or a - jr z, .check_bench - - xor a ; PLAY_AREA_ARENA - ldh [hTempPlayAreaLocation_ff9d], a - farcall CheckIfDefendingPokemonCanKnockOut - jr nc, .set_carry ; return carry if can't KO - ld d, a - ld a, DUELVARS_ARENA_CARD_HP - call GetTurnDuelistVariable - ld h, a - ld e, PLAY_AREA_ARENA - call GetCardDamageAndMaxHP - ; this seems useless since it was already - ; checked that Arena card has damage, - ; so card damage is at least 10. - cp 10 + 1 - jr c, .check_remaining - ld a, 10 - ; a = min(10, CardDamage) - -; checks if Defending Pokemon can still KO -; if Heal is used on this card. -; if Heal prevents KO, return carry. -.check_remaining - ld l, a - ld a, h ; load remaining HP - add l ; add 1 counter to account for heal - sub d ; subtract damage of strongest opponent attack - jr c, .check_bench - jr z, .check_bench - -.set_carry - xor a ; PLAY_AREA_ARENA - scf - ret - -; check Bench for Pokemon with damage counters -; and find the one with the most damage. -.check_bench - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - ld d, a - lb bc, 0, 0 - ld e, PLAY_AREA_BENCH_1 -.loop_bench - ld a, e - cp d - jr z, .done - push bc - call GetCardDamageAndMaxHP - pop bc - cp b - jr c, .next_bench - jr z, .next_bench - ld b, a ; store this damage - ld c, e ; store this Play Area location -.next_bench - inc e - jr .loop_bench - -; check if a Pokemon with damage counters was found -; in the Bench and, if so, return carry. -.done - ld a, c - or a - jr z, .not_found -; found - scf - ret -.not_found - or a - ret - -; checks whether AI uses Shift. -; input: -; c = Play Area location (PLAY_AREA_*) of Venomoth -HandleAIShift: ; 22476 (8:6476) - ld a, c - or a - ret nz ; return if Venomoth is not Arena card - - ldh [hTemp_ffa0], a - call GetArenaCardColor - call TranslateColorToWR - ld b, a - call SwapTurn - call GetArenaCardWeakness - ld [wAIDefendingPokemonWeakness], a - call SwapTurn - or a - ret z ; return if Defending Pokemon has no weakness - and b - ret nz ; return if Venomoth is already Defending card's weakness type - -; check whether there's a card in play with -; the same color as the Player's card weakness - call .CheckWhetherTurnDuelistHasColor - jr c, .found - call SwapTurn - call .CheckWhetherTurnDuelistHasColor - call SwapTurn - ret nc ; return if no color found - -.found - ld a, [wce08] - ldh [hTempCardIndex_ff9f], a - ld a, OPPACTION_USE_PKMN_POWER - bank1call AIMakeDecision - -; converts WR_* to appropriate color - ld a, [wAIDefendingPokemonWeakness] - ld b, 0 -.loop_color - bit 7, a - jr nz, .done - inc b - rlca - jr .loop_color - -; use Pkmn Power effect -.done - ld a, b - ldh [hAIPkmnPowerEffectParam], a - ld a, OPPACTION_EXECUTE_PKMN_POWER_EFFECT - bank1call AIMakeDecision - ld a, OPPACTION_DUEL_MAIN_SCENE - bank1call AIMakeDecision - ret - -; returns carry if turn Duelist has a Pokemon -; with same color as wAIDefendingPokemonWeakness. -.CheckWhetherTurnDuelistHasColor ; 224c6 (8:64c6) - ld a, [wAIDefendingPokemonWeakness] - ld b, a - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable -.loop_play_area - ld a, [hli] - cp $ff - jr z, .false - push bc - call GetCardIDFromDeckIndex - call GetCardType - ; in case this is a Mysterious Fossil or Clefairy Doll card, - ; AI might read the type of the card incorrectly here. - ; uncomment the following lines to account for this - ; cp TYPE_TRAINER - ; jr nz, .not_trainer - ; pop bc - ; jr .loop_play_area -; .not_trainer - call TranslateColorToWR - pop bc - and b - jr z, .loop_play_area -; true - scf - ret -.false - or a - ret - -; checks whether AI uses Peek. -; input: -; c = Play Area location (PLAY_AREA_*) of Mankey. -HandleAIPeek: ; 224e6 (8:64e6) - ld a, c - ldh [hTemp_ffa0], a - ld a, 50 - call Random - cp 3 - ret nc ; return 47 out of 50 times - -; choose what to use Peek on at random - ld a, 3 - call Random - or a - jr z, .check_ai_prizes - cp 2 - jr c, .check_player_hand - -; check Player's Deck - ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK - call GetNonTurnDuelistVariable - cp DECK_SIZE - 1 - ret nc ; return if Player has one or no cards in Deck - ld a, AI_PEEK_TARGET_DECK - jr .use_peek - -.check_ai_prizes - ld a, DUELVARS_PRIZES - call GetTurnDuelistVariable - ld hl, wAIPeekedPrizes - and [hl] - ld [hl], a - or a - ret z ; return if no prizes - - ld c, a - ld b, $1 - ld d, 0 -.loop_prizes - ld a, c - and b - jr nz, .found_prize - sla b - inc d - jr .loop_prizes -.found_prize -; remove this prize's flag from the prize list -; and use Peek on first one in list (lowest bit set) - ld a, c - sub b - ld [hl], a - ld a, AI_PEEK_TARGET_PRIZE - add d - jr .use_peek - -.check_player_hand - call SwapTurn - call CreateHandCardList - call SwapTurn - or a - ret z ; return if no cards in Hand -; shuffle list and pick the first entry to Peek - ld hl, wDuelTempList - call CountCardsInDuelTempList - call ShuffleCards - ld a, [wDuelTempList] - or AI_PEEK_TARGET_HAND - -.use_peek - push af - ld a, [wce08] - ldh [hTempCardIndex_ff9f], a - ld a, OPPACTION_USE_PKMN_POWER - bank1call AIMakeDecision - pop af - ldh [hAIPkmnPowerEffectParam], a - ld a, OPPACTION_EXECUTE_PKMN_POWER_EFFECT - bank1call AIMakeDecision - ld a, OPPACTION_DUEL_MAIN_SCENE - bank1call AIMakeDecision - ret - -; checks whether AI uses Strange Behavior. -; input: -; c = Play Area location (PLAY_AREA_*) of Slowbro. -HandleAIStrangeBehavior: ; 2255d (8:655d) - ld a, c - or a - ret z ; return if Slowbro is Arena card - - ldh [hTemp_ffa0], a - ld e, PLAY_AREA_ARENA - call GetCardDamageAndMaxHP - or a - ret z ; return if Arena card has no damage counters - - ld [wce06], a - ldh a, [hTemp_ffa0] - add DUELVARS_ARENA_CARD_HP - call GetTurnDuelistVariable - sub 10 - ret z ; return if Slowbro has only 10 HP remaining - -; if Slowbro can't receive all damage counters, -; only transfer remaining HP - 10 damage - ld hl, wce06 - cp [hl] - jr c, .use_strange_behavior - ld a, [hl] ; can receive all damage counters - -.use_strange_behavior - push af - ld a, [wce08] - ldh [hTempCardIndex_ff9f], a - ld a, OPPACTION_USE_PKMN_POWER - bank1call AIMakeDecision - xor a - ldh [hAIPkmnPowerEffectParam], a - ld a, OPPACTION_EXECUTE_PKMN_POWER_EFFECT - bank1call AIMakeDecision - pop af - -; loop counters chosen to transfer and use Pkmn Power - call ConvertHPToCounters - ld e, a -.loop_counters - ld d, 30 -.small_delay_loop - call DoFrame - dec d - jr nz, .small_delay_loop - push de - ld a, OPPACTION_6B15 - bank1call AIMakeDecision - pop de - dec e - jr nz, .loop_counters - -; return to main scene - ld d, 60 -.big_delay_loop - call DoFrame - dec d - jr nz, .big_delay_loop - ld a, OPPACTION_DUEL_MAIN_SCENE - bank1call AIMakeDecision - ret - -; checks whether AI uses Curse. -; input: -; c = Play Area location (PLAY_AREA_*) of Gengar. -HandleAICurse: ; 225b5 (8:65b5) - ld a, c - ldh [hTemp_ffa0], a - -; loop Player's Play Area and checks their damage. -; finds the card with lowest remaining HP and -; stores its HP and its Play Area location - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetNonTurnDuelistVariable - ld d, a - ld e, PLAY_AREA_ARENA - lb bc, 0, $ff - ld h, PLAY_AREA_ARENA - call SwapTurn -.loop_play_area_1 - push bc - call GetCardDamageAndMaxHP - pop bc - or a - jr z, .next_1 - - inc b - ld a, e - add DUELVARS_ARENA_CARD_HP - push hl - call GetTurnDuelistVariable - pop hl - cp c - jr nc, .next_1 - ; lower HP than one stored - ld c, a ; store this HP - ld h, e ; store this Play Area location - -.next_1 - inc e - ld a, e - cp d - jr nz, .loop_play_area_1 ; reached end of Play Area - - ld a, 1 - cp b - jr nc, .failed ; return if less than 2 cards with damage - -; card in Play Area with lowest HP remaining was found. -; look for another card to take damage counter from. - ld a, h - ldh [hTempRetreatCostCards], a - ld b, a - ld a, 10 - cp c - jr z, .hp_10_remaining - ; if has more than 10 HP remaining, - ; skip Arena card in choosing which - ; card to take damage counter from. - ld e, PLAY_AREA_BENCH_1 - jr .second_card - -.hp_10_remaining - ; if Curse can KO, then include - ; Player's Arena card to take - ; damage counter from. - ld e, PLAY_AREA_ARENA - -.second_card - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - ld d, a -.loop_play_area_2 - ld a, e - cp b - jr z, .next_2 ; skip same Pokemon card - push bc - call GetCardDamageAndMaxHP - pop bc - jr nz, .use_curse ; has damage counters, choose this card -.next_2 - inc e - ld a, e - cp d - jr nz, .loop_play_area_2 - -.failed - call SwapTurn - or a - ret - -.use_curse - ld a, e - ldh [hAIPkmnPowerEffectParam], a - call SwapTurn - ld a, [wce08] - ldh [hTempCardIndex_ff9f], a - ld a, OPPACTION_USE_PKMN_POWER - bank1call AIMakeDecision - ld a, OPPACTION_EXECUTE_PKMN_POWER_EFFECT - bank1call AIMakeDecision - ld a, OPPACTION_DUEL_MAIN_SCENE - bank1call AIMakeDecision - ret - -; handles AI logic for Cowardice -HandleAICowardice: ; 2262d (8:662d) - ld a, MUK - call CountPokemonIDInBothPlayAreas - ret c ; return if there's Muk in play - - farcall AIChooseRandomlyNotToDoAction - ret c ; randomly return - - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - cp 1 - ret z ; return if only one Pokemon in Play Area - - ld b, a - ld c, PLAY_AREA_ARENA - ld a, DUELVARS_ARENA_CARD_STATUS - call GetTurnDuelistVariable - and CNF_SLP_PRZ - jr nz, .next -.loop - ld a, DUELVARS_ARENA_CARD - add c - call GetTurnDuelistVariable - ld [wce08], a - call GetCardIDFromDeckIndex - ld a, e - push bc - cp TENTACOOL - call z, .CheckWhetherToUseCowardice - pop bc - jr nc, .next - - dec b ; subtract 1 from number of Pokemon in Play Area - ld a, 1 - cp b - ret z ; return if no longer has Bench Pokemon - ld c, PLAY_AREA_ARENA ; reset back to Arena - jr .loop - -.next - inc c - ld a, c - cp b - jr nz, .loop - ret - -; checks whether AI uses Cowardice. -; return carry if Pkmn Power was used. -; input: -; c = Play Area location (PLAY_AREA_*) of Tentacool. -.CheckWhetherToUseCowardice ; 22671 (8:6671) - ld a, c - ldh [hTemp_ffa0], a - ld e, a - call GetCardDamageAndMaxHP -.asm_22678 - or a - ret z ; return if has no damage counters - - ldh a, [hTemp_ffa0] - or a - jr nz, .is_benched - - ; this part is buggy if AIDecideBenchPokemonToSwitchTo returns carry - ; but since this was already checked beforehand, this never happens. - ; so jr c, .asm_22678 can be safely removed. - farcall AIDecideBenchPokemonToSwitchTo - jr c, .asm_22678 ; bug, this jumps in the middle of damage checking - jr .use_cowardice -.is_benched - ld a, $ff -.use_cowardice - push af - ld a, [wce08] - ldh [hTempCardIndex_ff9f], a - ld a, OPPACTION_USE_PKMN_POWER - bank1call AIMakeDecision - pop af - ldh [hAIPkmnPowerEffectParam], a - ld a, OPPACTION_EXECUTE_PKMN_POWER_EFFECT - bank1call AIMakeDecision - ld a, OPPACTION_DUEL_MAIN_SCENE - bank1call AIMakeDecision - scf - ret - -; AI logic for Damage Swap to transfer damage from Arena card -; to a card in Bench with more than 10 HP remaining -; and with no energy cards attached. -HandleAIDamageSwap: ; 226a3 (8:66a3) - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - dec a - ret z ; return if no Bench Pokemon - - farcall AIChooseRandomlyNotToDoAction - ret c - - ld a, ALAKAZAM - call CountPokemonIDInPlayArea - ret nc ; return if no Alakazam - ld a, MUK - call CountPokemonIDInBothPlayAreas - ret c ; return if there's Muk in play - -; only take damage off certain cards in Arena - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call GetCardIDFromDeckIndex - ld a, e - cp ALAKAZAM - jr z, .ok - cp KADABRA - jr z, .ok - cp ABRA - jr z, .ok - cp MR_MIME - ret nz - -.ok - ld e, PLAY_AREA_ARENA - call GetCardDamageAndMaxHP - or a - ret z ; return if no damage - - call ConvertHPToCounters - ld [wce06], a - ld a, ALAKAZAM - ld b, PLAY_AREA_BENCH_1 - farcall LookForCardIDInPlayArea_Bank5 - jr c, .is_in_bench - -; Alakazam is Arena card - xor a -.is_in_bench - ld [wce08], a - call .CheckForDamageSwapTargetInBench - ret c ; return if not found - -; use Damage Swap - ld a, [wce08] - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - ldh [hTempCardIndex_ff9f], a - ld a, [wce08] - ldh [hTemp_ffa0], a - ld a, OPPACTION_USE_PKMN_POWER - bank1call AIMakeDecision - ld a, OPPACTION_EXECUTE_PKMN_POWER_EFFECT - bank1call AIMakeDecision - - ld a, [wce06] - ld e, a -.loop_damage - ld d, 30 -.small_delay_loop - call DoFrame - dec d - jr nz, .small_delay_loop - - push de - call .CheckForDamageSwapTargetInBench - jr c, .no_more_target - - ldh [hTempRetreatCostCards], a - xor a ; PLAY_AREA_ARENA - ldh [hAIPkmnPowerEffectParam], a - ld a, OPPACTION_6B15 - bank1call AIMakeDecision - pop de - dec e - jr nz, .loop_damage - -.done -; return to main scene - ld d, 60 -.big_delay_loop - call DoFrame - dec d - jr nz, .big_delay_loop - ld a, OPPACTION_DUEL_MAIN_SCENE - bank1call AIMakeDecision - ret - -.no_more_target - pop de - jr .done - -; looks for a target in the bench to receive damage counters. -; returns carry if one is found, and outputs remaining HP in a. -.CheckForDamageSwapTargetInBench ; 2273c (8:673c) - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - ld b, a - ld c, PLAY_AREA_BENCH_1 - lb de, $ff, $ff - -; look for candidates in bench to get the damage counters -; only target specific card IDs. -.loop_bench - ld a, c - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - push de - call GetCardIDFromDeckIndex - ld a, e - pop de - cp CHANSEY - jr z, .found_candidate - cp KANGASKHAN - jr z, .found_candidate - cp SNORLAX - jr z, .found_candidate - cp MR_MIME - jr z, .found_candidate - -.next_play_area - inc c - ld a, c - cp b - jr nz, .loop_bench - -; done - ld a, e - cp $ff - jr nz, .no_carry - ld a, d - cp $ff - jr z, .set_carry -.no_carry - or a - ret - -.found_candidate -; found a potential candidate to receive damage counters - ld a, DUELVARS_ARENA_CARD_HP - add c - call GetTurnDuelistVariable - cp 20 - jr c, .next_play_area ; ignore cards with only 10 HP left - - ld d, c ; store damage - push de - push bc - ld e, c - farcall CountNumberOfEnergyCardsAttached - pop bc - pop de - or a - jr nz, .next_play_area ; ignore cards with attached energy - ld e, c ; store deck index - jr .next_play_area - -.set_carry - scf - ret - -; handles AI logic for attaching energy cards -; in Go Go Rain Dance deck. -HandleAIGoGoRainDanceEnergy: ; 22790 (8:6790) - ld a, [wOpponentDeckID] - cp GO_GO_RAIN_DANCE_DECK_ID - ret nz ; return if not Go Go Rain Dance deck - - ld a, BLASTOISE - call CountPokemonIDInPlayArea - ret nc ; return if no Blastoise - ld a, MUK - call CountPokemonIDInBothPlayAreas - ret c ; return if there's Muk in play - -; play all the energy cards that is needed. -.loop - farcall AIProcessAndTryToPlayEnergy - jr c, .loop - ret diff --git a/src/engine/ai/retreat.asm b/src/engine/ai/retreat.asm deleted file mode 100644 index 768a48b..0000000 --- a/src/engine/ai/retreat.asm +++ /dev/null @@ -1,1009 +0,0 @@ -; determine AI score for retreating -; return carry if AI decides to retreat -AIDecideWhetherToRetreat: ; 158b2 (5:58b2) - ld a, [wGotHeadsFromConfusionCheckDuringRetreat] - or a - jp nz, .no_carry - xor a - ld [wAIPlayEnergyCardForRetreat], a - call LoadDefendingPokemonColorWRAndPrizeCards - ld a, $80 ; initial retreat score - ld [wAIScore], a - ld a, [wcdb4] - or a - jr z, .check_status - srl a - srl a - sla a - call AddToAIScore - -.check_status - ld a, DUELVARS_ARENA_CARD_STATUS - call GetTurnDuelistVariable - or a - jr z, .check_ko_1 ; no status - and DOUBLE_POISONED - jr z, .check_cnf ; no poison - ld a, 2 - call AddToAIScore -.check_cnf - ld a, [hl] - and CNF_SLP_PRZ - cp CONFUSED - jr nz, .check_ko_1 - ld a, 1 - call AddToAIScore - -.check_ko_1 - xor a - ldh [hTempPlayAreaLocation_ff9d], a - call CheckIfAnyAttackKnocksOutDefendingCard - jr nc, .active_cant_ko_1 - call CheckIfSelectedAttackIsUnusable - jp nc, .active_cant_use_atk - call LookForEnergyNeededForAttackInHand - jr nc, .active_cant_ko_1 - -.active_cant_use_atk - ld a, 5 - call SubFromAIScore - ld a, [wAIOpponentPrizeCount] - cp 2 - jr nc, .active_cant_ko_1 - ld a, 35 - call SubFromAIScore - -.active_cant_ko_1 - call CheckIfDefendingPokemonCanKnockOut - jr nc, .defending_cant_ko - ld a, 2 - call AddToAIScore - - call CheckIfNotABossDeckID - jr c, .check_resistance_1 - ld a, [wAIPlayerPrizeCount] - cp 2 - jr nc, .check_prize_count - ld a, $01 - ld [wAIPlayEnergyCardForRetreat], a - -.defending_cant_ko - call CheckIfNotABossDeckID - jr c, .check_resistance_1 - ld a, [wAIPlayerPrizeCount] - cp 2 - jr nc, .check_prize_count - ld a, 2 - call AddToAIScore - -.check_prize_count - ld a, [wAIOpponentPrizeCount] - cp 2 - jr nc, .check_resistance_1 - ld a, 2 - call SubFromAIScore - -.check_resistance_1 - call GetArenaCardColor - call TranslateColorToWR - ld b, a - ld a, [wAIPlayerResistance] - and b - jr z, .check_weakness_1 - ld a, 1 - call AddToAIScore - -; check bench for Pokémon that -; the defending card is not resistant to -; if one is found, skip SubFromAIScore - ld a, [wAIPlayerResistance] - ld b, a - ld a, DUELVARS_BENCH - call GetTurnDuelistVariable -.loop_resistance_1 - ld a, [hli] - cp $ff - jr z, .exit_loop_resistance_1 - call LoadCardDataToBuffer1_FromDeckIndex - ld a, [wLoadedCard1Type] - call TranslateColorToWR - and b - jr nz, .loop_resistance_1 - jr .check_weakness_1 -.exit_loop_resistance_1 - ld a, 2 - call SubFromAIScore - -.check_weakness_1 - ld a, [wAIPlayerColor] - ld b, a - call GetArenaCardWeakness - and b - jr z, .check_resistance_2 - ld a, 2 - call AddToAIScore - -; check bench for Pokémon that -; is not weak to defending Pokémon -; if one is found, skip SubFromAIScore - ld a, [wAIPlayerColor] - ld b, a - ld a, DUELVARS_BENCH - call GetTurnDuelistVariable -.loop_weakness_1 - ld a, [hli] - cp $ff - jr z, .exit_loop_weakness_1 - call LoadCardDataToBuffer1_FromDeckIndex - ld a, [wLoadedCard1Weakness] - and b - jr nz, .loop_weakness_1 - jr .check_resistance_2 -.exit_loop_weakness_1 - ld a, 3 - call SubFromAIScore - -.check_resistance_2 - ld a, [wAIPlayerColor] - ld b, a - call GetArenaCardResistance - and b - jr z, .check_weakness_2 - ld a, 3 - call SubFromAIScore - -; check bench for Pokémon that -; is the defending Pokémon's weakness -; if none is found, skip AddToAIScore -.check_weakness_2 - ld a, [wAIPlayerWeakness] - ld b, a - ld a, DUELVARS_BENCH - call GetTurnDuelistVariable - ld e, $00 -.loop_weakness_2 - inc e - ld a, [hli] - cp $ff - jr z, .check_resistance_3 - push de - call LoadCardDataToBuffer1_FromDeckIndex - ld a, [wLoadedCard1Type] - call TranslateColorToWR - pop de - and b - jr z, .loop_weakness_2 - ld a, 2 - call AddToAIScore - - push de - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call GetCardIDFromDeckIndex - ld a, e - pop de - cp PORYGON - jr nz, .check_weakness_3 - -; handle Porygon - ld a, e - call CheckIfCanDamageDefendingPokemon - jr nc, .check_weakness_3 - ld a, 10 - call AddToAIScore - jr .check_resistance_3 - -.check_weakness_3 - call GetArenaCardColor - call TranslateColorToWR - ld b, a - ld a, [wAIPlayerWeakness] - and b - jr z, .check_resistance_3 - ld a, 3 - call SubFromAIScore - -; check bench for Pokémon that -; is resistant to defending Pokémon -; if none is found, skip AddToAIScore -.check_resistance_3 - ld a, [wAIPlayerColor] - ld b, a - ld a, DUELVARS_BENCH - call GetTurnDuelistVariable -.loop_resistance_2 - ld a, [hli] - cp $ff - jr z, .check_ko_2 - call LoadCardDataToBuffer1_FromDeckIndex - ld a, [wLoadedCard1Resistance] - and b - jr z, .loop_resistance_2 - ld a, 1 - call AddToAIScore - -; check bench for Pokémon that -; can KO defending Pokémon -; if none is found, skip AddToAIScore -.check_ko_2 - ld a, DUELVARS_BENCH - call GetTurnDuelistVariable - ld c, 0 -.loop_ko_1 - inc c - ld a, [hli] - cp $ff - jr z, .check_defending_id - ld a, c - ldh [hTempPlayAreaLocation_ff9d], a - push hl - push bc - call CheckIfAnyAttackKnocksOutDefendingCard - jr nc, .no_ko - call CheckIfSelectedAttackIsUnusable - jr nc, .success - call LookForEnergyNeededForAttackInHand - jr c, .success -.no_ko - pop bc - pop hl - jr .loop_ko_1 -.success - pop bc - pop hl - ld a, 2 - call AddToAIScore - -; a bench Pokémon was found that can KO -; if this is a boss deck and it's at last prize card -; if arena Pokémon cannot KO, add to AI score -; and set wAIPlayEnergyCardForRetreat to $01 - - ld a, [wAIOpponentPrizeCount] - cp 2 - jr nc, .check_defending_id - call CheckIfNotABossDeckID - jr c, .check_defending_id - - xor a - ldh [hTempPlayAreaLocation_ff9d], a - call CheckIfAnyAttackKnocksOutDefendingCard - jr nc, .active_cant_ko_2 - call CheckIfSelectedAttackIsUnusable - jp nc, .check_defending_id -.active_cant_ko_2 - ld a, 40 - call AddToAIScore - ld a, $01 - ld [wAIPlayEnergyCardForRetreat], a - -.check_defending_id - ld a, DUELVARS_ARENA_CARD - call GetNonTurnDuelistVariable - call SwapTurn - call GetCardIDFromDeckIndex - call SwapTurn - ld a, e - cp MR_MIME - jr z, .mr_mime_or_hitmonlee - cp HITMONLEE ; ?? - jr nz, .check_retreat_cost - -; check bench if there's any Pokémon -; that can damage defending Pokémon -; this is done because of Mr. Mime's PKMN PWR -; but why Hitmonlee ($87) as well? -.mr_mime_or_hitmonlee - xor a - call CheckIfCanDamageDefendingPokemon - jr c, .check_retreat_cost - ld a, DUELVARS_BENCH - call GetTurnDuelistVariable - ld c, 0 -.loop_damage - inc c - ld a, [hli] - cp $ff - jr z, .check_retreat_cost - ld a, c - push hl - push bc - call CheckIfCanDamageDefendingPokemon - jr c, .can_damage - pop bc - pop hl - jr .loop_damage -.can_damage - pop bc - pop hl - ld a, 5 - call AddToAIScore - ld a, $01 - ld [wAIPlayEnergyCardForRetreat], a - -; subtract from wAIScore if retreat cost is larger than 1 -; then check if any cards have at least half HP, -; are final evolutions and can use second attack in the bench -; and adds to wAIScore if the active Pokémon doesn't meet -; these conditions -.check_retreat_cost - xor a - ldh [hTempPlayAreaLocation_ff9d], a - call GetPlayAreaCardRetreatCost - cp 2 - jr c, .one_or_none - cp 3 - jr nc, .three_or_more - ; exactly two - ld a, 1 - call SubFromAIScore - jr .one_or_none - -.three_or_more - ld a, 2 - call SubFromAIScore - -.one_or_none - call CheckIfArenaCardIsAtHalfHPCanEvolveAndUseSecondAttack - jr c, .check_defending_can_ko - call CountNumberOfSetUpBenchPokemon - cp 2 - jr c, .check_defending_can_ko - call AddToAIScore - -; check bench for Pokémon that -; the defending Pokémon can't knock out -; if none is found, skip SubFromAIScore -.check_defending_can_ko - ld a, DUELVARS_BENCH - call GetTurnDuelistVariable - ld e, 0 -.loop_ko_2 - inc e - ld a, [hli] - cp $ff - jr z, .exit_loop_ko - push de - push hl - call LoadCardDataToBuffer2_FromDeckIndex - ld a, [wLoadedCard2ID] - pop hl - pop de - cp MYSTERIOUS_FOSSIL - jr z, .loop_ko_2 - cp CLEFAIRY_DOLL - jr z, .loop_ko_2 - ld a, e - ldh [hTempPlayAreaLocation_ff9d], a - push de - push hl - call CheckIfDefendingPokemonCanKnockOut - pop hl - pop de - jr c, .loop_ko_2 - jr .check_active_id -.exit_loop_ko - ld a, 20 - call SubFromAIScore - -.check_active_id - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call GetCardIDFromDeckIndex - ld a, e - cp MYSTERIOUS_FOSSIL - jr z, .mysterious_fossil_or_clefairy_doll - cp CLEFAIRY_DOLL - jr z, .mysterious_fossil_or_clefairy_doll - -; if wAIScore is at least 131, set carry - ld a, [wAIScore] - cp 131 - jr nc, .set_carry -.no_carry - or a - ret -.set_carry - scf - ret - -; set carry regardless if active card is -; either Mysterious Fossil or Clefairy Doll -; and there's a bench Pokémon who is not KO'd -; by defending Pokémon and can damage it -.mysterious_fossil_or_clefairy_doll - ld e, 0 -.loop_ko_3 - inc e - ld a, e - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - cp $ff - jr z, .no_carry - ld a, e - ldh [hTempPlayAreaLocation_ff9d], a - push de - call CheckIfDefendingPokemonCanKnockOut - pop de - jr c, .loop_ko_3 - ld a, e - push de - call CheckIfCanDamageDefendingPokemon - pop de - jr nc, .loop_ko_3 - jr .set_carry - -; if player's turn and loaded attack is not a Pokémon Power OR -; if opponent's turn and wAITriedAttack == 0 -; set wcdda's bit 7 flag -Func_15b54: ; 15b54 (5:5b54) - xor a - ld [wcdda], a - ld a, [wWhoseTurn] - cp OPPONENT_TURN - jr z, .opponent - -; player - ld a, [wLoadedAttackCategory] - cp POKEMON_POWER - ret z - jr .set_flag - -.opponent - ld a, [wAITriedAttack] - or a - ret nz - -.set_flag - ld a, %10000000 - ld [wcdda], a - ret - -; calculates AI score for bench Pokémon -; returns in a and [hTempPlayAreaLocation_ff9d] the -; Play Area location of best card to switch to. -; returns carry if no Bench Pokemon. -AIDecideBenchPokemonToSwitchTo: ; 15b72 (5:5b72) - xor a - ldh [hTempPlayAreaLocation_ff9d], a - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - cp 2 - ret c - -; has at least 2 Pokémon in Play Area - call Func_15b54 - call LoadDefendingPokemonColorWRAndPrizeCards - ld a, 50 - ld [wAIScore], a - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - ld b, a - ld c, PLAY_AREA_ARENA - push bc - jp .store_score - -.next_bench - push bc - ld a, c - ldh [hTempPlayAreaLocation_ff9d], a - ld a, 50 - ld [wAIScore], a - -; check if card can KO defending Pokémon -; if it can, raise AI score -; if on last prize card, raise AI score again - call CheckIfAnyAttackKnocksOutDefendingCard - jr nc, .check_can_use_atks - call CheckIfSelectedAttackIsUnusable - jr c, .check_can_use_atks - ld a, 10 - call AddToAIScore - ld a, [wcdda] - or %00000001 - ld [wcdda], a - call CountPrizes - cp 2 - jp nc, .check_defending_weak - ld a, 10 - call AddToAIScore - -; calculates damage of both attacks -; to raise AI score accordingly -.check_can_use_atks - xor a - ld [wSelectedAttack], a - call CheckIfSelectedAttackIsUnusable - call nc, .HandleAttackDamageScore - ld a, $01 - ld [wSelectedAttack], a - call CheckIfSelectedAttackIsUnusable - call nc, .HandleAttackDamageScore - jr .check_energy_card - -; adds to AI score depending on amount of damage -; it can inflict to the defending Pokémon -; AI score += floor(Damage / 10) + 1 -.HandleAttackDamageScore - ld a, [wSelectedAttack] - call EstimateDamage_VersusDefendingCard - ld a, [wDamage] - call CalculateByteTensDigit - inc a - call AddToAIScore - ret - -; if an energy card that is needed is found in hand -; calculate damage of the move and raise AI score -; AI score += floor(Damage / 20) -.check_energy_card - call LookForEnergyNeededInHand - jr nc, .check_attached_energy - ld a, [wSelectedAttack] - call EstimateDamage_VersusDefendingCard - ld a, [wDamage] - call CalculateByteTensDigit - srl a - call AddToAIScore - -; if no energies attached to card, lower AI score -.check_attached_energy - ldh a, [hTempPlayAreaLocation_ff9d] - ld e, a - call GetPlayAreaCardAttachedEnergies - ld a, [wTotalAttachedEnergies] - or a - jr nz, .check_mr_mime - ld a, 1 - call SubFromAIScore - -; if can damage Mr Mime, raise AI score -.check_mr_mime - ld a, DUELVARS_ARENA_CARD - call GetNonTurnDuelistVariable - call SwapTurn - call LoadCardDataToBuffer2_FromDeckIndex - call SwapTurn - cp MR_MIME - jr nz, .check_defending_weak - xor a - call EstimateDamage_VersusDefendingCard - ld a, [wDamage] - or a - jr nz, .can_damage - ld a, $01 - call EstimateDamage_VersusDefendingCard - ld a, [wDamage] - or a - jr z, .check_defending_weak -.can_damage - ld a, 5 - call AddToAIScore - -; if defending card is weak to this card, raise AI score -.check_defending_weak - ldh a, [hTempPlayAreaLocation_ff9d] - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call LoadCardDataToBuffer1_FromDeckIndex - ld a, [wLoadedCard1Type] - call TranslateColorToWR - ld c, a - ld hl, wAIPlayerWeakness - and [hl] - jr z, .check_defending_resist - ld a, 3 - call AddToAIScore - -; if defending card is resistant to this card, lower AI score -.check_defending_resist - ld a, c - ld hl, wAIPlayerResistance - and [hl] - jr z, .check_resistance - ld a, 2 - call SubFromAIScore - -; if this card is resistant to defending Pokémon, raise AI score -.check_resistance - ld a, [wAIPlayerColor] - ld hl, wLoadedCard1Resistance - and [hl] - jr z, .check_weakness - ld a, 2 - call AddToAIScore - -; if this card is weak to defending Pokémon, lower AI score -.check_weakness - ld a, [wAIPlayerColor] - ld hl, wLoadedCard1Weakness - and [hl] - jr z, .check_retreat_cost - ld a, 3 - call SubFromAIScore - -; if this card's retreat cost < 2, raise AI score -; if this card's retreat cost > 2, lower AI score -.check_retreat_cost - call GetPlayAreaCardRetreatCost - cp 2 - jr c, .one_or_none - jr z, .check_player_prize_count - ld a, 1 - call SubFromAIScore - jr .check_player_prize_count -.one_or_none - ld a, 1 - call AddToAIScore - -; if wcdda != $81 -; if defending Pokémon can KO this card -; if player is not at last prize card, lower 3 from AI score -; if player is at last prize card, lower 10 from AI score -.check_player_prize_count - ld a, [wcdda] - cp %10000000 | %00000001 - jr z, .check_hp - call CheckIfDefendingPokemonCanKnockOut - jr nc, .check_hp - ld e, 3 - ld a, [wAIPlayerPrizeCount] - cp 1 - jr nz, .lower_score_1 - ld e, 10 -.lower_score_1 - ld a, e - call SubFromAIScore - -; if this card's HP is 0, make AI score 0 -.check_hp - ldh a, [hTempPlayAreaLocation_ff9d] - add DUELVARS_ARENA_CARD_HP - call GetTurnDuelistVariable - or a - jr nz, .add_hp_score - ld [wAIScore], a - jr .store_score - -; AI score += floor(HP/40) -.add_hp_score - ld b, a - ld a, 4 - call CalculateBDividedByA_Bank5 - call CalculateByteTensDigit - call AddToAIScore - -; raise AI score if -; - is a Mr Mime OR -; - is a Mew1 and defending card is not basic stage - ldh a, [hTempPlayAreaLocation_ff9d] - add DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call LoadCardDataToBuffer1_FromDeckIndex - cp MR_MIME - jr z, .raise_score - cp MEW1 - jr nz, .asm_15cf0 - ld a, DUELVARS_ARENA_CARD - call GetNonTurnDuelistVariable - call LoadCardDataToBuffer2_FromDeckIndex - ld a, [wLoadedCard2Stage] - or a - jr z, .asm_15cf0 -.raise_score - ld a, 5 - call AddToAIScore - -; if wLoadedCard1Unknown2 == $01, lower AI score -.asm_15cf0 - ld a, [wLoadedCard1Unknown2] - cp $01 - jr nz, .mysterious_fossil_or_clefairy_doll - ld a, 2 - call SubFromAIScore - -; if card is Mysterious Fossil or Clefairy Doll, -; lower AI score -.mysterious_fossil_or_clefairy_doll - ld a, [wLoadedCard1ID] - cp MYSTERIOUS_FOSSIL - jr z, .lower_score_2 - cp CLEFAIRY_DOLL - jr nz, .ai_score_bonus -.lower_score_2 - ld a, 10 - call SubFromAIScore - -.ai_score_bonus - ld b, a - ld a, [wAICardListRetreatBonus + 1] - or a - jr z, .store_score - ld h, a - ld a, [wAICardListRetreatBonus] - ld l, a - -.loop_ids - ld a, [hli] - or a - jr z, .store_score ; list is over - cp b - jr nz, .next_id - ld a, [hl] - cp $80 - jr c, .subtract_score - sub $80 - call AddToAIScore - jr .next_id -.subtract_score - ld c, a - ld a, $80 - sub c - call SubFromAIScore -.next_id - inc hl - jr .loop_ids - -.store_score - ldh a, [hTempPlayAreaLocation_ff9d] - ld c, a - ld b, $00 - ld hl, wPlayAreaAIScore - add hl, bc - ld a, [wAIScore] - ld [hl], a - pop bc - inc c - dec b - jp nz, .next_bench - -; done - xor a - ld [wcdb4], a - jp FindHighestBenchScore - -; handles AI action of retreating Arena Pokémon -; and chooses which energy cards to discard. -; if card can't discard, return carry. -; in case it's Clefairy Doll or Mysterious Fossil, -; handle its effect to discard itself instead of retreating. -; input: -; - a = Play Area location (PLAY_AREA_*) of card to retreat to. -AITryToRetreat: ; 15d4f (5:5d4f) - push af - ld a, [wAIPlayEnergyCardForRetreat] - or a - jr z, .check_id - -; AI is allowed to play an energy card -; from the hand in order to provide -; the necessary energy for retreat cost - -; check status - ld a, DUELVARS_ARENA_CARD_STATUS - call GetTurnDuelistVariable - and CNF_SLP_PRZ - cp ASLEEP - jp z, .check_id - cp PARALYZED - jp z, .check_id - -; if an energy card hasn't been played yet, -; checks if the Pokémon needs just one more energy to retreat -; if it does, check if there are any energy cards in hand -; and if there are, play that energy card - ld a, [wAlreadyPlayedEnergy] - or a - jr nz, .check_id - ld e, PLAY_AREA_ARENA - call CountNumberOfEnergyCardsAttached - push af - xor a - ldh [hTempPlayAreaLocation_ff9d], a - call GetPlayAreaCardRetreatCost - pop bc - cp b - jr c, .check_id - jr z, .check_id - ; energy attached < retreat cost - sub b - cp 1 - jr nz, .check_id - call CreateEnergyCardListFromHand - jr c, .check_id - ld a, [wDuelTempList] - ldh [hTemp_ffa0], a - xor a - ldh [hTempPlayAreaLocation_ffa1], a - ld a, OPPACTION_PLAY_ENERGY - bank1call AIMakeDecision - -.check_id - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call GetCardIDFromDeckIndex - ld a, e - cp MYSTERIOUS_FOSSIL - jp z, .mysterious_fossil_or_clefairy_doll - cp CLEFAIRY_DOLL - jp z, .mysterious_fossil_or_clefairy_doll - -; if card is Asleep or Paralyzed, set carry and exit -; else, load the status in hTemp_ffa0 - pop af - ldh [hTempPlayAreaLocation_ffa1], a - ld a, DUELVARS_ARENA_CARD_STATUS - call GetTurnDuelistVariable - ld b, a - and CNF_SLP_PRZ - cp ASLEEP - jp z, .set_carry - cp PARALYZED - jp z, .set_carry - ld a, b - ldh [hTemp_ffa0], a - ld a, $ff - ldh [hTempRetreatCostCards], a - -; check energy required to retreat -; if the cost is 0, retreat right away - xor a - ldh [hTempPlayAreaLocation_ff9d], a - call GetPlayAreaCardRetreatCost - ld [wTempCardRetreatCost], a - or a - jp z, .retreat - -; if cost > 0 and number of energy cards attached == cost -; discard them all - xor a - call CreateArenaOrBenchEnergyCardList - ld e, PLAY_AREA_ARENA - call GetPlayAreaCardAttachedEnergies - ld a, [wTotalAttachedEnergies] - ld c, a - ld a, [wTempCardRetreatCost] - cp c - jr nz, .choose_energy_discard - - ld hl, hTempRetreatCostCards - ld de, wDuelTempList -.loop_1 - ld a, [de] - inc de - ld [hli], a - cp $ff - jr nz, .loop_1 - jp .retreat - -; if cost > 0 and number of energy cards attached > cost -; choose energy cards to discard according to color -.choose_energy_discard - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - call GetCardIDFromDeckIndex - ld a, e - ld [wTempCardID], a - call LoadCardDataToBuffer1_FromCardID - ld a, [wLoadedCard1Type] - or TYPE_ENERGY - ld [wTempCardType], a - ld a, [wTempCardRetreatCost] - ld c, a - -; first, look for and discard double colorless energy -; if retreat cost is >= 2 - ld hl, wDuelTempList - ld de, hTempRetreatCostCards -.loop_2 - ld a, c - cp 2 - jr c, .energy_not_same_color - ld a, [hli] - cp $ff - jr z, .energy_not_same_color - ld [de], a - push de - call GetCardIDFromDeckIndex - ld a, e - pop de - cp DOUBLE_COLORLESS_ENERGY - jr nz, .loop_2 - ld a, [de] - call RemoveCardFromDuelTempList - dec hl - inc de - dec c - dec c - jr nz, .loop_2 - jr .end_retreat_list - -; second, shuffle attached cards and discard energy cards -; that are not of the same type as the Pokémon -; the exception for this are cards that are needed for -; some attacks but are not of the same color as the Pokémon -; (i.e. Psyduck's Headache attack) -; and energy cards attached to Eevee corresponding to a -; color of any of its evolutions (water, fire, lightning) -.energy_not_same_color - ld hl, wDuelTempList - call CountCardsInDuelTempList - call ShuffleCards -.loop_3 - ld a, [hli] - cp $ff - jr z, .any_energy - ld [de], a - call CheckIfEnergyIsUseful - jr c, .loop_3 - ld a, [de] - call RemoveCardFromDuelTempList - dec hl - inc de - dec c - jr nz, .loop_3 - jr .end_retreat_list - -; third, discard any card until -; cost requirement is met -.any_energy - ld hl, wDuelTempList -.loop_4 - ld a, [hli] - cp $ff - jr z, .set_carry - ld [de], a - inc de - push de - call GetCardIDFromDeckIndex - ld a, e - pop de - cp DOUBLE_COLORLESS_ENERGY - jr nz, .not_double_colorless - dec c - jr z, .end_retreat_list -.not_double_colorless - dec c - jr nz, .loop_4 - -.end_retreat_list - ld a, $ff - ld [de], a - -.retreat - ld a, OPPACTION_ATTEMPT_RETREAT - bank1call AIMakeDecision - or a - ret -.set_carry - scf - ret - -; handle Mysterious Fossil and Clefairy Doll -; if there are bench Pokémon, use effect to discard card -; this is equivalent to using its Pokémon Power -.mysterious_fossil_or_clefairy_doll - ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA - call GetTurnDuelistVariable - cp 2 - jr nc, .has_bench - ; doesn't have any bench - pop af - jr .set_carry - -.has_bench - ld a, DUELVARS_ARENA_CARD - call GetTurnDuelistVariable - ldh [hTempCardIndex_ff9f], a - xor a - ldh [hTemp_ffa0], a - ld a, OPPACTION_USE_PKMN_POWER - bank1call AIMakeDecision - pop af - ldh [hAIPkmnPowerEffectParam], a - ld a, OPPACTION_EXECUTE_PKMN_POWER_EFFECT - bank1call AIMakeDecision - ld a, OPPACTION_DUEL_MAIN_SCENE - bank1call AIMakeDecision - or a - ret diff --git a/src/engine/ai/special_attacks.asm b/src/engine/ai/special_attacks.asm deleted file mode 100644 index 770324e..0000000 --- a/src/engine/ai/special_attacks.asm +++ /dev/null @@ -1,481 +0,0 @@ -; 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: ; 16dcd (5:6dcd) - 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: ; 16e3e (5:6e3e) - 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: ; 16e55 (5:6e55) - 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: ; 16e77 (5:6e77) - 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: ; 16ead (5:6ead) - 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: ; 16ec2 (5:6ec2) - 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: ; 16ecb (5:6ecb) - 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: ; 16eea (5:6eea) - 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: ; 16f0f (5:6f0f) - 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: ; 16f18 (5:6f18) - 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: ; 16f41 (5:6f41) - 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: ; 16f4e (5:6f4e) - 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: ; 16fb8 (5:6fb8) - ld a, $83 - ret - -; dismiss attack if cards in deck <= 20. -; otherwise return a score of $80 + 0. -.Fetch: ; 16fbb (5:6fbb) - 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: ; 16fc8 (5:6fc8) - 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: ; 16ff2 (5:6ff2) - 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: ; 17005 (5:7005) - 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: ; 17019 (5:7019) -; 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: ; 17057 (5:7057) - 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 diff --git a/src/engine/ai/trainer_cards.asm b/src/engine/ai/trainer_cards.asm deleted file mode 100644 index 4bee001..0000000 --- a/src/engine/ai/trainer_cards.asm +++ /dev/null @@ -1,6073 +0,0 @@ -INCLUDE "data/duel/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 |