summaryrefslogtreecommitdiff
path: root/src/engine/ai
diff options
context:
space:
mode:
authorElectroDeoxys <ElectroDeoxys@gmail.com>2021-09-29 09:02:02 +0100
committerElectroDeoxys <ElectroDeoxys@gmail.com>2021-09-29 09:02:02 +0100
commitbae47106f18266d2c3b97b6d954b91d9b16c0ccf (patch)
tree4d1a24de37ddb1b22ff22991a275fca351a3651d /src/engine/ai
parentb0487fa979d0b5f3241e9e0659dd4b29a7e38f18 (diff)
Reorganise some folders in engine/
Diffstat (limited to 'src/engine/ai')
-rw-r--r--src/engine/ai/attacks.asm721
-rw-r--r--src/engine/ai/boss_deck_set_up.asm167
-rw-r--r--src/engine/ai/common.asm970
-rw-r--r--src/engine/ai/core.asm2770
-rw-r--r--src/engine/ai/damage_calculation.asm450
-rw-r--r--src/engine/ai/deck_ai.asm82
-rw-r--r--src/engine/ai/decks/fire_charge.asm80
-rw-r--r--src/engine/ai/decks/first_strike.asm76
-rw-r--r--src/engine/ai/decks/flower_power.asm75
-rw-r--r--src/engine/ai/decks/general.asm194
-rw-r--r--src/engine/ai/decks/general_no_retreat.asm140
-rw-r--r--src/engine/ai/decks/go_go_rain_dance.asm79
-rw-r--r--src/engine/ai/decks/im_ronald.asm80
-rw-r--r--src/engine/ai/decks/invincible_ronald.asm78
-rw-r--r--src/engine/ai/decks/legendary_articuno.asm209
-rw-r--r--src/engine/ai/decks/legendary_dragonite.asm166
-rw-r--r--src/engine/ai/decks/legendary_moltres.asm176
-rw-r--r--src/engine/ai/decks/legendary_ronald.asm203
-rw-r--r--src/engine/ai/decks/legendary_zapdos.asm153
-rw-r--r--src/engine/ai/decks/powerful_ronald.asm92
-rw-r--r--src/engine/ai/decks/rock_crusher.asm74
-rw-r--r--src/engine/ai/decks/sams_practice.asm205
-rw-r--r--src/engine/ai/decks/strange_psyshock.asm81
-rw-r--r--src/engine/ai/decks/unreferenced.asm42
-rw-r--r--src/engine/ai/decks/wonders_of_science.asm77
-rw-r--r--src/engine/ai/decks/zapping_selfdestruct.asm75
-rw-r--r--src/engine/ai/energy.asm1048
-rw-r--r--src/engine/ai/hand_pokemon.asm627
-rw-r--r--src/engine/ai/init.asm98
-rw-r--r--src/engine/ai/pkmn_powers.asm1228
-rw-r--r--src/engine/ai/retreat.asm1009
-rw-r--r--src/engine/ai/special_attacks.asm481
-rw-r--r--src/engine/ai/trainer_cards.asm6073
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