diff options
Diffstat (limited to 'src/engine/ai/core.asm')
-rw-r--r-- | src/engine/ai/core.asm | 2770 |
1 files changed, 0 insertions, 2770 deletions
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 |