diff options
author | ElectroDeoxys <ElectroDeoxys@gmail.com> | 2020-04-28 20:20:20 +0100 |
---|---|---|
committer | ElectroDeoxys <ElectroDeoxys@gmail.com> | 2020-04-28 20:20:20 +0100 |
commit | 7d9ea8a30d19fae6a39bb36981e27db6edbea5e7 (patch) | |
tree | 632526b60f8642fa2362e6a5582799e906b28718 /src | |
parent | e38d9f1de3abe1cdb54e7292ead677151348bd4e (diff) |
AI routines and Energy Trans logic
Diffstat (limited to 'src')
-rw-r--r-- | src/constants/duel_constants.asm | 41 | ||||
-rw-r--r-- | src/engine/bank01.asm | 1 | ||||
-rw-r--r-- | src/engine/bank05.asm | 589 | ||||
-rw-r--r-- | src/engine/bank08.asm | 447 | ||||
-rw-r--r-- | src/engine/effect_functions.asm | 92 | ||||
-rw-r--r-- | src/engine/home.asm | 2 | ||||
-rw-r--r-- | src/hram.asm | 14 | ||||
-rw-r--r-- | src/wram.asm | 39 |
8 files changed, 1013 insertions, 212 deletions
diff --git a/src/constants/duel_constants.asm b/src/constants/duel_constants.asm index 65f58e3..b667c50 100644 --- a/src/constants/duel_constants.asm +++ b/src/constants/duel_constants.asm @@ -232,21 +232,32 @@ AI_FLAG_USED_PROFESSOR_OAK EQU 1 << 2 AI_FLAG_MODIFIED_HAND EQU 1 << 3 AI_FLAG_USED_GUST_OF_WIND EQU 1 << 4 +; used as input for AIProcessEnergyCards to determine what to check +; and whether to play card after the routine is over. +; I suspect AI_ENERGY_FLAG_DONT_PLAY to be a flag to signal the routine +; not to actually play the energy card after it's finished, +; but AIProcessEnergyCards checks whether ANY flag is set in order +; to decide not to play it, so it's redundant in the presence of another flag. +AI_ENERGY_FLAG_DONT_PLAY EQU 1 << 0 ; whether to play energy card (?) +AI_ENERGY_FLAG_SKIP_EVOLUTION EQU 1 << 1 ; whether to check if card has evolutions +AI_ENERGY_FLAG_SKIP_ARENA_CARD EQU 1 << 7 ; whether to include Arena card in determining which card to attach energy + ; used to determine which Trainer cards for AI ; to process in AIProcessHandTrainerCards. ; aside from a few exceptions, these go in chronological order. -AI_TRAINER_CARD_PHASE_01 EQU $1 -AI_TRAINER_CARD_PHASE_02 EQU $2 -AI_TRAINER_CARD_PHASE_03 EQU $3 -AI_TRAINER_CARD_PHASE_04 EQU $4 -AI_TRAINER_CARD_PHASE_05 EQU $5 -AI_TRAINER_CARD_PHASE_06 EQU $6 -AI_TRAINER_CARD_PHASE_07 EQU $7 -AI_TRAINER_CARD_PHASE_08 EQU $8 -AI_TRAINER_CARD_PHASE_09 EQU $9 -AI_TRAINER_CARD_PHASE_10 EQU $a -AI_TRAINER_CARD_PHASE_11 EQU $b -AI_TRAINER_CARD_PHASE_12 EQU $c -AI_TRAINER_CARD_PHASE_13 EQU $d -AI_TRAINER_CARD_PHASE_14 EQU $e -AI_TRAINER_CARD_PHASE_15 EQU $f + const_def 1 + const AI_TRAINER_CARD_PHASE_01 ; $1 + const AI_TRAINER_CARD_PHASE_02 ; $2 + const AI_TRAINER_CARD_PHASE_03 ; $3 + const AI_TRAINER_CARD_PHASE_04 ; $4 + const AI_TRAINER_CARD_PHASE_05 ; $5 + const AI_TRAINER_CARD_PHASE_06 ; $6 + const AI_TRAINER_CARD_PHASE_07 ; $7 + const AI_TRAINER_CARD_PHASE_08 ; $8 + const AI_TRAINER_CARD_PHASE_09 ; $9 + const AI_TRAINER_CARD_PHASE_10 ; $a + const AI_TRAINER_CARD_PHASE_11 ; $b + const AI_TRAINER_CARD_PHASE_12 ; $c + const AI_TRAINER_CARD_PHASE_13 ; $d + const AI_TRAINER_CARD_PHASE_14 ; $e + const AI_TRAINER_CARD_PHASE_15 ; $f diff --git a/src/engine/bank01.asm b/src/engine/bank01.asm index b73b47c..7668903 100644 --- a/src/engine/bank01.asm +++ b/src/engine/bank01.asm @@ -6835,6 +6835,7 @@ OppAction_ExecutePokemonPowerEffect: ; 6b07 (1:6b07) ret ; 0x6b15 +; execute the EFFECTCMDTYPE_AFTER_DAMAGE command of the used Pokemon Power OppAction_6b15: ; 6b15 (1:6b15) ld a, EFFECTCMDTYPE_AFTER_DAMAGE call TryExecuteEffectCommandFunction diff --git a/src/engine/bank05.asm b/src/engine/bank05.asm index ee45de4..ba0a565 100644 --- a/src/engine/bank05.asm +++ b/src/engine/bank05.asm @@ -74,8 +74,8 @@ Func_14078: ; 14078 (5:4078) call AIDecideBenchPokemonToSwitchTo call AIChooseEnergyToDiscardForRetreatCost .asm_14091 - call AIDecidePlayEnergyCardFromHand - call Func_169f8 + call AIProcessAndTryToPlayEnergy + call AIProcessAndTryToUseAttack ret c ld a, OPPACTION_FINISH_NO_ATTACK bank1call AIMakeDecision @@ -220,8 +220,44 @@ LoadDefendingPokemonColorWRAndPrizeCards: ; 1411d (5:411d) ret ; 0x14145 -Func_14145: ; 14145 (5:4145) - INCROM $14145, $14184 +; 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 CopyMoveDataAndDamage_FromDeckIndex + ld a, OPPACTION_BEGIN_ATTACK + bank1call AIMakeDecision + ret c + + call AISelectSpecialAttackParameters + jr c, .use_attack + ld a, OPPACTION_BEGIN_ATTACK + call TryExecuteEffectCommandFunction + +.use_attack + ld a, [wSelectedAttack] + ld e, a + ld a, DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + ld d, a + call CopyMoveDataAndDamage_FromDeckIndex + ld a, OPPACTION_USE_ATTACK + bank1call AIMakeDecision + ret c + + ld a, OPPACTION_ATTACK_ANIM_AND_DAMAGE + call TryExecuteEffectCommandFunction + ld a, OPPACTION_ATTACK_ANIM_AND_DAMAGE + bank1call AIMakeDecision + ret +; 0x14184 ; return carry if any of the following is satisfied: ; - deck index in a corresponds to a double colorless energy card; @@ -1145,7 +1181,7 @@ PointerTable_14668: ; 14668 (05:4668) dw Func_14674 ; not used dw Func_14674 ; general AI for battles dw Func_14678 ; basic pokemon placement / cheater shuffling on better AI - dw Func_1467f + dw Func_1467f ; deciding which Bench Pokemon to switch to dw Func_14683 dw Func_14687 @@ -1160,11 +1196,11 @@ Func_14678: ; 14678 (5:4678) ret Func_1467f: ; 1467f (5:467f) - call $5b72 + call AIDecideBenchPokemonToSwitchTo ret Func_14683: ; 14683 (5:4683) - call $5b72 + call AIDecideBenchPokemonToSwitchTo ret Func_14687: ; 14687 (5:4687) @@ -1174,105 +1210,108 @@ Func_14687: ; 14687 (5:4687) ; AI for general decks i think Func_1468b: ; 1468b (5:468b) call Func_15649 - ld a, $1 + + ld a, AI_TRAINER_CARD_PHASE_01 call AIProcessHandTrainerCards - farcall $8, $67d3 - jp nc, $4776 - farcall $8, $6790 - farcall $8, $66a3 - farcall $8, $637f + farcall Func_227d3 + jp nc, .asm_14776 + + farcall Func_22790 + farcall Func_226a3 + farcall Func_2237f ret c - farcall $8, $662d - ld a, $2 + + farcall Func_2262d + + ld a, AI_TRAINER_CARD_PHASE_02 call AIProcessHandTrainerCards - ld a, $3 + ld a, AI_TRAINER_CARD_PHASE_03 call AIProcessHandTrainerCards - ld a, $4 + ld a, AI_TRAINER_CARD_PHASE_04 call AIProcessHandTrainerCards - call $5eae + call AIDecidePlayPokemonCard ret c - ld a, $5 + + ld a, AI_TRAINER_CARD_PHASE_05 call AIProcessHandTrainerCards - ld a, $6 + ld a, AI_TRAINER_CARD_PHASE_06 call AIProcessHandTrainerCards - ld a, $7 + ld a, AI_TRAINER_CARD_PHASE_07 call AIProcessHandTrainerCards - ld a, $8 + ld a, AI_TRAINER_CARD_PHASE_08 call AIProcessHandTrainerCards - call $4786 - ld a, $a + call Func_14786 + ld a, AI_TRAINER_CARD_PHASE_10 call AIProcessHandTrainerCards - ld a, $b + ld a, AI_TRAINER_CARD_PHASE_11 call AIProcessHandTrainerCards - ld a, $c + ld a, AI_TRAINER_CARD_PHASE_12 call AIProcessHandTrainerCards ld a, [wAlreadyPlayedEnergy] or a jr nz, .asm_146ed - call $64e8 - + call AIProcessAndTryToPlayEnergy .asm_146ed - call $5eae - farcall $8, $66a3 - farcall $8, $637f + call AIDecidePlayPokemonCard + farcall Func_226a3 + farcall Func_2237f ret c - farcall $8, $6790 - ld a, $d - farcall $8, $619b - ld a, $d + farcall Func_22790 + ld a, $0d + farcall HandleAIEnergyTrans + ld a, AI_TRAINER_CARD_PHASE_13 call AIProcessHandTrainerCards - ld a, $f + ld a, AI_TRAINER_CARD_PHASE_15 call AIProcessHandTrainerCards ld a, [wPreviousAIFlags] - and AI_FLAG_USED_PROFESSOR_OAK + and $04 jr z, .asm_14776 - ld a, $1 + ld a, AI_TRAINER_CARD_PHASE_01 call AIProcessHandTrainerCards - ld a, $2 + ld a, AI_TRAINER_CARD_PHASE_02 call AIProcessHandTrainerCards - ld a, $3 + ld a, AI_TRAINER_CARD_PHASE_03 call AIProcessHandTrainerCards - ld a, $4 + ld a, AI_TRAINER_CARD_PHASE_04 call AIProcessHandTrainerCards - call $5eae + call AIDecidePlayPokemonCard ret c - ld a, $5 + ld a, AI_TRAINER_CARD_PHASE_05 call AIProcessHandTrainerCards - ld a, $6 + ld a, AI_TRAINER_CARD_PHASE_06 call AIProcessHandTrainerCards - ld a, $7 + ld a, AI_TRAINER_CARD_PHASE_07 call AIProcessHandTrainerCards - ld a, $8 + ld a, AI_TRAINER_CARD_PHASE_08 call AIProcessHandTrainerCards - call $4786 - ld a, $a + call Func_14786 + ld a, AI_TRAINER_CARD_PHASE_10 call AIProcessHandTrainerCards - ld a, $b + ld a, AI_TRAINER_CARD_PHASE_11 call AIProcessHandTrainerCards - ld a, $c + ld a, AI_TRAINER_CARD_PHASE_12 call AIProcessHandTrainerCards ld a, [wAlreadyPlayedEnergy] or a jr nz, .asm_1475b - call $64e8 - + call AIProcessAndTryToPlayEnergy .asm_1475b - call $5eae - farcall $8, $66a3 - farcall $8, $637f + call AIDecidePlayPokemonCard + farcall Func_226a3 + farcall Func_2237f ret c - farcall $8, $6790 - ld a, $d - farcall $8, $619b - ld a, $d + farcall Func_22790 + ld a, $0d + farcall HandleAIEnergyTrans + ld a, AI_TRAINER_CARD_PHASE_13 call AIProcessHandTrainerCards .asm_14776 - ld a, $e - farcall $8, $619b - call $69f8 + ld a, $0e + farcall HandleAIEnergyTrans + call AIProcessAndTryToUseAttack ret c - ld a, $5 + ld a, OPPACTION_FINISH_NO_ATTACK bank1call AIMakeDecision ret ; 0x14786 @@ -1735,6 +1774,8 @@ CountNumberOfEnergyCardsAttached: ; 15787 (5:5787) ; 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 @@ -2207,7 +2248,7 @@ AIDecideWhetherToRetreat: ; 158b2 (5:58b2) .one_or_none call CheckIfArenaCardIsAtHalfHPCanEvolveAndUseSecondMove jr c, .check_defending_can_ko - call CheckIfBenchCardsAreAtHalfHPCanEvolveAndUseSecondMove + call CountNumberOfSetUpBenchPokemon cp 2 jr c, .check_defending_can_ko call AddToAIScore @@ -2324,7 +2365,8 @@ Func_15b54: ; 15b54 (5:5b54) ; calculates AI score for bench Pokémon ; returns in hTempPlayAreaLocation_ff9d the -; Play Area location of best card to switch to +; 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 @@ -2376,17 +2418,17 @@ AIDecideBenchPokemonToSwitchTo: ; 15b72 (5:5b72) xor a ld [wSelectedAttack], a call CheckIfSelectedMoveIsUnusable - call nc, .calculate_damage + call nc, .HandleAttackDamageScore ld a, $01 ld [wSelectedAttack], a call CheckIfSelectedMoveIsUnusable - call nc, .calculate_damage + 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 -.calculate_damage +.HandleAttackDamageScore ld a, [wSelectedAttack] call EstimateDamage_VersusDefendingCard ld a, [wDamage] @@ -4006,47 +4048,58 @@ CheckForEvolutionInDeck: ; 16451 (5:6451) Func_16488 ; 16488 (5:6488) INCROM $16488, $164a1 -; copies wPlayAreaAIScore to wTempPlayAreaAIScore. -; copies AIScore to wcde3. -; decides which card to get energy card. -Func_164a1: ; 164a1 (5:64a1) - ld a, $03 - ld [wcdd8], a +; 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_play_area +.loop ld a, [hli] ld [de], a inc de dec b - jr nz, .loop_play_area + jr nz, .loop ld a, [wAIScore] ld [de], a - jr AIDecideWhichCardToAttachEnergy -Func_164ba: ; 164ba (5:64ba) - ld a, $83 - ld [wcdd8], 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 -.asm_164c7 +.loop ld a, [hli] ld [de], a inc de dec b - jr nz, .asm_164c7 + jr nz, .loop ld a, [wAIScore] ld [de], a - jr AIDecideWhichCardToAttachEnergy + + jr AIProcessEnergyCards ; copies wTempPlayAreaAIScore to wPlayAreaAIScore -; and loads wAIscore with value in wcde3. -; identical to Func_169e3. -Func_164d3: ; 164d3 (5:64d3) +; and loads wAIscore with value in wTempAIScore. +; identical to RetrievePlayAreaAIScoreFromBackup2. +RetrievePlayAreaAIScoreFromBackup1: ; 164d3 (5:64d3) push af ld de, wPlayAreaAIScore ld hl, wTempPlayAreaAIScore @@ -4065,34 +4118,37 @@ Func_164d3: ; 164d3 (5:64d3) ; have AI decide whether to play energy card from hand ; and determine which card is best to attach it. -AIDecidePlayEnergyCardFromHand: ; 164e8 (5:64e8) +AIProcessAndTryToPlayEnergy: ; 164e8 (5:64e8) xor a - ld [wcdd8], a + ld [wAIEnergyAttachLogicFlags], a call CreateEnergyCardListFromHand - jr nc, AIDecideWhichCardToAttachEnergy + jr nc, AIProcessEnergyCards ; no energy - ld a, [wcdd8] + ld a, [wAIEnergyAttachLogicFlags] or a jr z, .exit - jp Func_164d3 + jp RetrievePlayAreaAIScoreFromBackup1 .exit or a ret ; have AI decide whether to play energy card ; and determine which card is best to attach it. -AIDecideWhichCardToAttachEnergy: ; 164fc (5:64fc) +AIProcessEnergyCards: ; 164fc (5:64fc) +; initialize Play Area AI score ld a, $80 ld b, MAX_PLAY_AREA_POKEMON - ld hl, wcde4 + 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 @@ -4106,8 +4162,8 @@ AIDecideWhichCardToAttachEnergy: ; 164fc (5:64fc) ld [wAIScore], a ld a, $ff ld [wTempAI], a - ld a, [wcdd8] - and $02 + ld a, [wAIEnergyAttachLogicFlags] + and AI_ENERGY_FLAG_SKIP_EVOLUTION jr nz, .check_venusaur ; check if energy needed is found in hand @@ -4125,7 +4181,7 @@ AIDecideWhichCardToAttachEnergy: ; 164fc (5:64fc) ld a, [wCurCardCanAttack] call CheckForEvolutionInList jr nc, .no_evolution_in_hand - ld [wTempAI], a + ld [wTempAI], a ; store evolution card found ld a, 2 call AddToAIScore jr .check_venusaur @@ -4137,8 +4193,9 @@ AIDecideWhichCardToAttachEnergy: ; 164fc (5:64fc) ld a, 1 call AddToAIScore -; if there's no Muk in Play Area -; and there's Venusaur2, add to AI score +; 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 @@ -4157,27 +4214,27 @@ AIDecideWhichCardToAttachEnergy: ; 164fc (5:64fc) ; arena ld a, [wcda7] bit 7, a - jr z, .check_arena_hp + jr z, .skip_subtracting_score ld a, 5 call SubFromAIScore jr .check_defending_can_ko -; lower AI score if poison/double poison -; will KO Pokémon between turns -; or if the defending Pokémon can KO -.check_arena_hp +.skip_subtracting_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 + ; hp < 30 cp 2 jr z, .has_20_hp -; hp = 10 + ; hp = 10 ld a, DUELVARS_ARENA_CARD_STATUS call GetTurnDuelistVariable and POISONED @@ -4288,11 +4345,12 @@ AIDecideWhichCardToAttachEnergy: ; 164fc (5:64fc) .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, wcde4 + ld hl, wPlayAreaEnergyAIScore add hl, bc ld a, [hl] cp $80 @@ -4336,24 +4394,24 @@ AIDecideWhichCardToAttachEnergy: ; 164fc (5:64fc) ; for each card has been calculated. ; now to determine the highest score. call FindPlayAreaCardWithHighestAIScore - jp nc, .asm_1668a + jp nc, .not_found - ld a, [wcdd8] + ld a, [wAIEnergyAttachLogicFlags] or a jr z, .play_card scf - jp Func_164d3 + jp RetrievePlayAreaAIScoreFromBackup1 .play_card call CreateEnergyCardListFromHand jp AITryToPlayEnergyCard -.asm_1668a: ; 1668a (5:668a) - ld a, [wcdd8] +.not_found: ; 1668a (5:668a) + ld a, [wAIEnergyAttachLogicFlags] or a - jr z, .asm_16693 - jp Func_164d3 -.asm_16693 + jr z, .no_carry + jp RetrievePlayAreaAIScoreFromBackup1 +.no_carry or a ret ; 0x16695 @@ -4562,15 +4620,17 @@ DetermineAIScoreOfMoveEnergyRequirement: ; 16695 (5:6695) ; 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, [wcdd8] - and $80 - jr nz, .asm_167e1 + 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, 0 ; PLAY_AREA_ARENA + ld c, PLAY_AREA_ARENA ld e, c ld d, c ld hl, wPlayAreaAIScore @@ -4601,7 +4661,7 @@ FindPlayAreaCardWithHighestAIScore: ; 167b5 (5:67b5) ret ; same as above but only check bench Pokémon scores. -.asm_167e1 +.only_bench ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA call GetTurnDuelistVariable dec a @@ -4624,6 +4684,7 @@ FindPlayAreaCardWithHighestAIScore: ; 167b5 (5:67b5) dec b jr nz, .loop_2 +; in this case, there is no minimum threshold AI score. ld a, d ldh [hTempPlayAreaLocation_ff9d], a scf @@ -4694,16 +4755,16 @@ GetEnergyCardForDiscardOrEnergyBoostAttack: ; 1683b (5:683b) jr z, .first_attack ; check if second attack is Zapdos2's Thunderbolt, -; Charizard's Fire Spin or Exeggcutor's Big Eggsplosion, +; 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_exeggcutor + jr z, .charizard_or_exeggutor cp EXEGGUTOR - jr z, .charizard_or_exeggcutor + jr z, .charizard_or_exeggutor ld hl, wLoadedCard2Move2EnergyCost jr .fire .first_attack @@ -4758,9 +4819,9 @@ GetEnergyCardForDiscardOrEnergyBoostAttack: ; 1683b (5:683b) or a ret -; Charizard's Fire Spin and Exeggcutor's Big Eggsplosion, +; Charizard's Fire Spin and Exeggutor's Big Eggsplosion, ; return carry. -.charizard_or_exeggcutor +.charizard_or_exeggutor lb bc, $00, $01 scf ret @@ -5019,11 +5080,13 @@ CheckSpecificDecksToAttachDoubleColorless: ; 1696e (5:696e) ret ; 0x169ca -Func_169ca: ; 169ca (5:69ca) +; 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 [wcdd9], a + ld [wAIExecuteProcessedAttack], a -; copy wPlayAreaAIScore to wTempPlayAreaAIScore. +; backup wPlayAreaAIScore in wTempPlayAreaAIScore. ld de, wTempPlayAreaAIScore ld hl, wPlayAreaAIScore ld b, MAX_PLAY_AREA_POKEMON @@ -5034,15 +5097,15 @@ Func_169ca: ; 169ca (5:69ca) dec b jr nz, .loop -; copies wAIScore to wcde3 +; copies wAIScore to wTempAIScore ld a, [wAIScore] ld [de], a - jr Func_169fc + jr AIProcessAttacks ; copies wTempPlayAreaAIScore to wPlayAreaAIScore -; and loads wAIscore with value in wcde3. -; identical to Func_164d3. -Func_169e3: ; 169e3 (5:69e3) +; and loads wAIscore with value in wTempAIScore. +; identical to RetrievePlayAreaAIScoreFromBackup1. +RetrievePlayAreaAIScoreFromBackup2: ; 169e3 (5:69e3) push af ld de, wPlayAreaAIScore ld hl, wTempPlayAreaAIScore @@ -5060,12 +5123,18 @@ Func_169e3: ; 169e3 (5:69e3) ret ; 0x169f8 -Func_169f8: ; 169f8 (5:69f8) +; have AI choose and execute an attack. +; return carry if an attack was chosen and attempted. +AIProcessAndTryToUseAttack: ; 169f8 (5:69f8) xor a - ld [wcdd9], a + ld [wAIExecuteProcessedAttack], a ; fallthrough -Func_169fc: ; 169fc (5:69fc) +; 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 @@ -5077,23 +5146,23 @@ Func_169fc: ; 169fc (5:69fc) .no_pluspower ld a, [wcda7] cp $80 - jp z, .asm_16a77 + jp z, .dont_attack ; determine AI score of both attacks. xor a ; FIRST_ATTACK_OR_PKMN_POWER call GetAIScoreOfAttack ld a, [wAIScore] - ld [wPlayAreaAIScore], a + ld [wFirstAttackAIScore], a ld a, SECOND_ATTACK call GetAIScoreOfAttack ; compare both attack scores ld c, SECOND_ATTACK - ld a, [wPlayAreaAIScore] + ld a, [wFirstAttackAIScore] ld b, a ld a, [wAIScore] cp b - jr nc, .asm_16a30 + jr nc, .check_score ; first attack has higher score dec c ld a, b @@ -5103,9 +5172,9 @@ Func_169fc: ; 169fc (5:69fc) ; 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. -.asm_16a30 +.check_score cp $50 ; minimum score to use attack - jr c, .asm_16a77 + jr c, .dont_attack ; enough score, proceed ld a, c @@ -5115,14 +5184,18 @@ Func_169fc: ; 169fc (5:69fc) call CheckWhetherToSwitchToFirstAttack .attack_chosen - ld a, [wcdd9] +; check whether to execute the attack chosen + ld a, [wAIExecuteProcessedAttack] or a - jr z, .asm_16a48 + jr z, .execute + +; set carry and reset Play Area AI score +; to the previous values. scf - jp Func_169e3 + jp RetrievePlayAreaAIScoreFromBackup2 -.asm_16a48 - ld a, $0e +.execute + ld a, AI_TRAINER_CARD_PHASE_14 call AIProcessHandTrainerCards ; load this attack's damage output against @@ -5134,39 +5207,52 @@ Func_169fc: ; 169fc (5:69fc) ld a, [wDamage] or a - jr z, .asm_16a62 - ; if damage is 0, fallthrough + jr z, .check_damage_bench + ; if damage is not 0, fallthrough -.cannot_damage +.can_damage xor a ld [wcdb4], a - jr .asm_16a6d + jr .use_attack -.asm_16a62 +.check_damage_bench +; check if it can otherwise damage player's bench ld a, MOVE_FLAG1_ADDRESS | DAMAGE_TO_OPPONENT_BENCH_F call CheckLoadedMoveFlag - jr c, .cannot_damage + jr c, .can_damage + +; cannot damage either Defending Pokemon or Bench ld hl, wcdb4 inc [hl] -.asm_16a6d + +; return carry if attack is chosen +; and AI tries to use it. +.use_attack ld a, $01 ld [wcddb], a - call Func_14145 + call AITryUseAttack scf ret -.asm_16a77 - ld a, [wcdd9] + +.dont_attack + ld a, [wAIExecuteProcessedAttack] or a - jr z, .asm_16a80 - jp Func_169e3 -.asm_16a80 + 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 ; 0x16a86 -; determines the AI score of attack index in a. +; 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 @@ -5737,7 +5823,7 @@ HandleSpecialAIMoves: ; 16dcd (5:6dcd) cp BELLSPROUT jr z, HandleCallForFamily cp EXEGGUTOR - jp z, HandleExeggcutorTeleport + jp z, HandleExeggutorTeleport cp SCYTHER jp z, HandleSwordsDanceAndFocusEnergy cp KRABBY @@ -5864,7 +5950,7 @@ HandleJigglypuff2FriendshipSong: ; 16ead (5:6ead) ret ; if AI decides to retreat, return a score of $80 + 10. -HandleExeggcutorTeleport: ; 16ec2 (5:6ec2) +HandleExeggutorTeleport: ; 16ec2 (5:6ec2) call AIDecideWhetherToRetreat jp nc, HandleSpecialAIMoves.zero ld a, $8a @@ -5942,14 +6028,14 @@ HandlePorygonConversion: ; 16f18 (5:6f18) jr nz, .conversion_2 ; conversion 1 - call CheckIfBenchCardsAreAtHalfHPCanEvolveAndUseSecondMove + call CountNumberOfSetUpBenchPokemon cp 2 jr c, .low_score ld a, $82 ret .conversion_2 - call CheckIfBenchCardsAreAtHalfHPCanEvolveAndUseSecondMove + call CountNumberOfSetUpBenchPokemon cp 2 jr nc, .low_score ld a, $82 @@ -6097,7 +6183,7 @@ HandleElectrode1EnergySpike: ; 16ff2 (5:6ff2) ld e, LIGHTNING_ENERGY call CheckIfAnyCardIDinLocation jp nc, HandleSpecialAIMoves.zero - call Func_164a1 + call AIProcessButDontPlayEnergy_SkipEvolution jp nc, HandleSpecialAIMoves.zero ld a, $83 ret @@ -6125,7 +6211,7 @@ HandleHyperBeam: ; 17005 (5:7005) CheckWhetherToSwitchToFirstAttack: ; 17019 (5:7019) ; this checks whether the first attack is also viable ; (has more than minimum score to be used) - ld a, [wPlayAreaAIScore] + ld a, [wFirstAttackAIScore] cp $50 jr c, .keep_second_attack @@ -6209,7 +6295,7 @@ CheckIfAnyBasicPokemonInDeck: ; 17057 (5:7057) ; return carry and that card's Play Area location in a. ; output: ; a = card location of Pokémon card, if found; -; cerry set if such a card is found. +; carry set if such a card is found. LookForCardThatIsKnockedOutOnDevolution: ; 17080 (5:7080) ldh a, [hTempPlayAreaLocation_ff9d] push af @@ -6307,15 +6393,16 @@ CheckIfArenaCardIsAtHalfHPCanEvolveAndUseSecondMove: ; 170c9 (5:70c9) ret ; 0x17101 -; returns carry if at least one Pokémon in bench -; meets the following conditions: -; - card HP >= half max HP +; 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 move -; Also outputs the number of Pokémon in bench +; Outputs the number of Pokémon in bench ; that meet these requirements in a -CheckIfBenchCardsAreAtHalfHPCanEvolveAndUseSecondMove: ; 17101 (5:7101) +; and returns carry if at least one is found +CountNumberOfSetUpBenchPokemon: ; 17101 (5:7101) ldh a, [hTempPlayAreaLocation_ff9d] ld d, a ld a, [wSelectedAttack] @@ -6333,17 +6420,24 @@ CheckIfBenchCardsAreAtHalfHPCanEvolveAndUseSecondMove: ; 17101 (5:7101) 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 @@ -6386,8 +6480,138 @@ CheckIfBenchCardsAreAtHalfHPCanEvolveAndUseSecondMove: ; 17101 (5:7101) ret ; 0x17161 -Func_17161 ; 17161 (5:7161) - INCROM $17161, $171fb +; 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 +; 0x1716e + +.SelectAttackParameters: ; 1716e (5:716e) + ld a, DUELVARS_ARENA_CARD + call GetTurnDuelistVariable + call GetCardIDFromDeckIndex + ld a, e + cp MEW3 + jr z, .devolution_beam + cp MEWTWO3 + jr z, .energy_absorption + cp MEWTWO2 + jr z, .energy_absorption + cp EXEGGUTOR + jr z, .teleport + cp ELECTRODE1 + jr z, .energy_spike + ; fallthrough + +.no_carry + or a + ret + +.devolution_beam +; 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 + +.energy_absorption +; 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 CreateEnergyCardListFromOpponentDiscardPile + +; find any energy card different from +; the one found by CheckIfAnyCardIDinLocation. +; since using this move 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 + +.energy_spike +; 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 +; 0x171fb ; return carry if Pokémon at play area location ; in hTempPlayAreaLocation_ff9d does not have @@ -6591,7 +6815,7 @@ CheckIfCanDamageDefendingPokemon: ; 17383 (5:7383) ; sets carry if any on the moves knocks out ; also outputs the largest damage dealt in a ; input: -; [hTempPlayAreaLocation_ff9d] = locaion of card to check +; [hTempPlayAreaLocation_ff9d] = location of card to check ; output: ; a = largest damage of both moves ; carry set if can knock out @@ -6825,7 +7049,7 @@ CheckForBenchIDAtHalfHPAndCanUseSecondMove: ; 17474 (5:7474) ret ; 0x174cd -; add 5 to wcde4 AI score corresponding to all cards +; 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 @@ -6848,7 +7072,7 @@ RaiseAIScoreToAllMatchingIDsInBench: ; 174cd (5:74cd) ld c, e ld b, $00 push hl - ld hl, wcde4 + ld hl, wPlayAreaEnergyAIScore add hl, bc ld a, 5 add [hl] @@ -6860,8 +7084,8 @@ RaiseAIScoreToAllMatchingIDsInBench: ; 174cd (5:74cd) ; 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 wcde4 -; while all others get decreased wcde4 +; 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 @@ -6880,6 +7104,7 @@ Func_174f2: ; 174f2 (5:74f2) ld a, [hli] cp $ff ret z + ld [wcdf9], a push de push hl @@ -6945,11 +7170,11 @@ Func_174f2: ; 174f2 (5:74f2) jr .loop_2 ; c = play area location of highest score -; decrease wcde4 score for all cards with same ID +; decrease wPlayAreaEnergyAIScore score for all cards with same ID ; except for the one with highest score -; increase wcde4 score for card with highest ID +; increase wPlayAreaEnergyAIScore score for card with highest ID .asm_17560 - ld hl, wcde4 + ld hl, wPlayAreaEnergyAIScore ld de, wcdea ld b, PLAY_AREA_ARENA .loop_3 diff --git a/src/engine/bank08.asm b/src/engine/bank08.asm index 5a0f535..6850b82 100644 --- a/src/engine/bank08.asm +++ b/src/engine/bank08.asm @@ -6219,8 +6219,449 @@ AIDecide_PokemonTrader_Flamethrower: ; 22133 (8:6133) ret ; 0x2219b -Func_2219b: ; 2219b (8:219b) - INCROM $2219b, $227f6 +; handle AI routines for Energy Trans. +; depending on input, AI can use Energy Trans to +; give Arena or Bench cards some Grass energy cards, +; depending whether it's for attack, retreat, etc. +HandleAIEnergyTrans: ; 2219b (8:619b) + ld [wce06], a + +; choose to randomly return + farcall ChooseRandomlyNotToPlayTrainerCard + 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 $09 + jr z, .check_retreat + + cp $0e + jp z, .TransferEnergyToBench + + 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_1 + 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_1 + + ld a, b + or a + ret z ; return when finished Play Area loop + + dec b + jr .loop_play_area_1 + +; use Energy Trans Pkmn Power +.use_pkmn_power_1 + 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_1 + ld a, DUELVARS_CARD_LOCATIONS + add e + call GetTurnDuelistVariable + and %00011111 + cp CARD_LOCATION_BENCH_1 + jr c, .next_card_1 + + 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_1 + + ; store the deck index of energy card + ld a, e + ldh [hAIEnergyTransEnergyCard], a + + push de + ld d, 30 +.small_delay_1 + call DoFrame + dec d + jr nz, .small_delay_1 + + ld a, OPPACTION_6B15 + bank1call AIMakeDecision + pop de + dec d + jr z, .done_transfer_1 + +.next_card_1 + inc e + ld a, DECK_SIZE + cp e + jr nz, .loop_deck_locations_1 + +; transfer is done, perform delay +; and return to main scene. +.done_transfer_1 + ld d, 60 +.big_delay_1 + call DoFrame + dec d + jr nz, .big_delay_1 + ld a, OPPACTION_DUEL_MAIN_SCENE + bank1call AIMakeDecision + ret +; 0x22246 + +; checks if the Arena card has not enough energy for second attack, +; and if not, return carry if transferring Grass energy from Bench +; would be enough to use it and 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 +; 0x22286 + +; 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 +; 0x222a9 + +; 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 +; 0x222ca + +; 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. +.TransferEnergyToBench ; 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_2 + 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_2 + + ld a, b + or a + ret z ; return when Play Area loop is ended + + dec b + jr .loop_play_area_2 + +; use Energy Trans Pkmn Power +.use_pkmn_power_2 + 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_2 + +; look for Grass energy cards that +; are currently attached to Arena card. + ld e, 0 +.loop_deck_locations_2 + ld a, DUELVARS_CARD_LOCATIONS + add e + call GetTurnDuelistVariable + cp CARD_LOCATION_ARENA + jr nz, .next_card_2 + + ld a, e + push de + call GetCardIDFromDeckIndex + ld a, e + pop de + cp GRASS_ENERGY + jr nz, .next_card_2 + + ; store the deck index of energy card + ld a, e + ldh [hAIEnergyTransEnergyCard], a + jr .transfer + +.next_card_2 + inc e + ld a, DECK_SIZE + cp e + jr nz, .loop_deck_locations_2 + jr .done_transfer_2 + +.transfer +; get the Bench card location to transfer Grass energy card to. + farcall AIProcessButDontPlayEnergy_SkipEvolutionAndArena + jr nc, .done_transfer_2 + ldh a, [hTempPlayAreaLocation_ff9d] + ldh [hAIEnergyTransPlayAreaLocation], a + + ld d, 30 +.small_delay_2 + call DoFrame + dec d + jr nz, .small_delay_2 + + ld a, [wAIVenusaur2DeckIndex] + ldh [hTempCardIndex_ff9f], a + ld d, a + ld e, FIRST_ATTACK_OR_PKMN_POWER + call CopyMoveDataAndDamage_FromDeckIndex + ld a, OPPACTION_6B15 + bank1call AIMakeDecision + jr .loop_energy + +; transfer is done, perform delay +; and return to main scene. +.done_transfer_2 + ld d, 60 +.big_delay_2 + call DoFrame + dec d + jr nz, .big_delay_2 + ld a, OPPACTION_DUEL_MAIN_SCENE + bank1call AIMakeDecision + ret +; 0x2237f + +Func_2237f: ; 2237f (8:237f) + INCROM $2237f, $2262d + +Func_2262d: ; 2262d (8:262d) + INCROM $2262d, $226a3 + +Func_226a3: ; 226a3 (8:26a3) + INCROM $226a3, $22790 + +Func_22790: ; 22790 (8:2790) + INCROM $22790, $227d3 + +; checks wcda7 and Pokemon in Play Area that are set up. +; if there's at least 4, goes to AI_TRAINER_CARD_PHASE_05. +; else, returns carry. +Func_227d3: ; 227d3 (8:67d3) + ld a, [wcda7] + bit 7, a + jr z, .set_carry + cp %10000010 + jr c, .asm_227e4 + + xor a + ld [wcda7], a + jr .set_carry + +.asm_227e4 + farcall CountNumberOfSetUpBenchPokemon + cp 4 + jr c, .set_carry + + ld a, AI_TRAINER_CARD_PHASE_05 + farcall AIProcessHandTrainerCards + or a + ret + +.set_carry + scf + ret +; 0x227f6 ; lists in wDuelTempList all the basic energy cards ; in card location of a. @@ -7128,7 +7569,7 @@ FindDuplicatePokemonCards: ; 22b6f (8:6b6f) ; return carry flag if move is not high recoil. Func_22bad: ; 22bad (8:6bad) - farcall Func_169ca + farcall AIProcessButDontUseAttack ret nc ld a, [wSelectedAttack] ld e, a diff --git a/src/engine/effect_functions.asm b/src/engine/effect_functions.asm index 8832134..dbda9ad 100644 --- a/src/engine/effect_functions.asm +++ b/src/engine/effect_functions.asm @@ -292,7 +292,9 @@ ApplySubstatus2ToDefendingCard: ; 2c149 (b:4149) ret ; 0x2c166 -Func_2c166: ; 2c166 (b:4166) +; overwrites in wDamage, wAIMinDamage and wAIMaxDamage +; with the value in a. +StoreDamageInfo: ; 2c166 (b:4166) ld [wDamage], a ld [wAIMinDamage], a ld [wAIMaxDamage], a @@ -348,7 +350,77 @@ HandleSwitchDefendingPokemonEffect: ; 2c1ec (b:41ec) ret ; 0x2c221 - INCROM $2c221, $2c487 + INCROM $2c221, $2c2a4 + +; makes a list in wDuelTempList with the deck indices +; of all the energy cards found in opponent's Discard Pile. +; if (c == 0), all energy cards are allowed; +; if (c != 0), double colorless energy cards are not counted. +; returns carry if no energy cards were found. +CreateEnergyCardListFromOpponentDiscardPile: ; 2c2a4 (b:42a4) + ld c, $00 + +; get number of cards in Discard Pile +; and have hl point to the end of the +; Discard Pile list in wOpponentDeckCards. + ld a, DUELVARS_NUMBER_OF_CARDS_IN_DISCARD_PILE + call GetTurnDuelistVariable + ld b, a + add DUELVARS_DECK_CARDS + ld l, a + + ld de, wDuelTempList + inc b + jr .next_card + +.check_energy + ld a, [hl] + call LoadCardDataToBuffer2_FromDeckIndex + ld a, [wLoadedCard2Type] + and TYPE_ENERGY + jr z, .next_card + +; if (c != $00), then we dismiss Double Colorless +; energy cards found. + ld a, c + or a + jr z, .copy + ld a, [wLoadedCard2Type] + cp TYPE_ENERGY_DOUBLE_COLORLESS + jr nc, .next_card + +.copy + ld a, [hl] + ld [de], a + inc de + +; goes through Discard Pile list +; in wOpponentDeckCards in descending order. +.next_card + dec l + dec b + jr nz, .check_energy + +; terminating byte on wDuelTempList + ld a, $ff + ld [de], a + +; check if any energy card was found +; by checking whether the first byte +; in wDuelTempList is $ff. +; if none were found, return carry. + ld a, [wDuelTempList] + cp $ff + jr z, .set_carry + or a + ret + +.set_carry + scf + ret +; 0x2c2e0 + + INCROM $2c2e0, $2c487 ; handles the selection of a forced switch ; by link/AI opponent or by the player. @@ -558,7 +630,7 @@ Twineedle_MultiplierEffect: ; 2c7f5 (b:47f5) add a add e call ATimes10 - call Func_2c166 + call StoreDamageInfo ret ; 0x2c80d @@ -679,4 +751,16 @@ Toxic_DoublePoisonEffect: ; 2c994 (b:4994) ret ; 0x2c998 - INCROM $2c998, $30000
\ No newline at end of file + INCROM $2c998, $2cbfb + +Func_2cbfb: ; 2cbfb (b:4bfb) + ldh a, [hAIEnergyTransPlayAreaLocation] + ld e, a + ldh a, [hAIEnergyTransEnergyCard] + call AddCardToHand + call PutHandCardInPlayArea + bank1call PrintPlayAreaCardList_EnableLCD + ret +; 0x2cc0a + + INCROM $2cc0a, $30000
\ No newline at end of file diff --git a/src/engine/home.asm b/src/engine/home.asm index 4f9fc31..338dbb0 100644 --- a/src/engine/home.asm +++ b/src/engine/home.asm @@ -5218,7 +5218,7 @@ Func_1bca: ; 1bca (0:1bca) ret ; 0x1c05 -; return in a the retreat cost of the turn holder's arena or benchx Pokemon +; return in a the retreat cost of the turn holder's arena or bench Pokemon ; given the PLAY_AREA_* value in hTempPlayAreaLocation_ff9d GetPlayAreaCardRetreatCost: ; 1c05 (0:1c05) ldh a, [hTempPlayAreaLocation_ff9d] diff --git a/src/hram.asm b/src/hram.asm index 9cdba06..2b4fbc9 100644 --- a/src/hram.asm +++ b/src/hram.asm @@ -85,10 +85,24 @@ hTemp_ffa0:: ; ffa0 hTempPlayAreaLocation_ffa1:: ; ffa1 ds $1 +UNION + ; $ff-terminated list of cards to be discarded upon retreat hTempRetreatCostCards:: ; ffa2 ds $6 +NEXTU + +; parameters chosen by AI in Energy Trans routine. +; the deck index (0-59) of the energy card to transfer +; and the Play Area location (PLAY_AREA_*) of card to receive that energy card. +hAIEnergyTransEnergyCard:: ; ffa2 + ds $1 +hAIEnergyTransPlayAreaLocation:: ; ffa3 + ds $1 + +ENDU + ; hffa8 through hffb0 belong to the text engine hffa8:: ; ffa8 ds $1 diff --git a/src/wram.asm b/src/wram.asm index e5fc9c6..2a10fe2 100644 --- a/src/wram.asm +++ b/src/wram.asm @@ -1230,11 +1230,21 @@ wTempCardType:: ; cdba wAIScore:: ; cdbe ds $1 +UNION + ; used for AI decisions that involve ; each card in the Play Area. wPlayAreaAIScore:: ; cdbf ds MAX_PLAY_AREA_POKEMON +NEXTU + +; stores the score determined by AI for first attack +wFirstAttackAIScore:: ; cdbf + ds $1 + +ENDU + ds $0a ; information about the defending Pokémon and @@ -1274,10 +1284,16 @@ wAIPluspowerAttack:: ; cdd6 wAIPlayEnergyCardForRetreat:: ; cdd7 ds $1 -wcdd8:: ; cdd8 +; flags defined by AI_ENERGY_FLAG_* constants +; used as input for AIProcessEnergyCards +; to determine what to check in the routine. +wAIEnergyAttachLogicFlags:: ; cdd8 ds $1 -wcdd9:: ; cdd9 +; used as input to AIProcessAttacks. +; if 0, execute the attack chosen by the AI. +; if not 0, return without executing attack. +wAIExecuteProcessedAttack:: ; cdd9 ds $1 wcdda:: ; cdda @@ -1289,15 +1305,17 @@ wcddb:: ; cddb wcddc:: ; cddc ds $1 -; used to compliment wPlayAreaAIScore, -; to temporarily do calculations and store results. +; used to temporarily backup wPlayAreaAIScore values. wTempPlayAreaAIScore:: ; cddd ds MAX_PLAY_AREA_POKEMON -wcde3:: ; cde3 +wTempAIScore:: ; cde3 ds $1 -wcde4:: ; cde4 +; used for AI decisions that involve +; each card in the Play Area involving +; attaching Energy cards. +wPlayAreaEnergyAIScore:: ; cde4 ds MAX_PLAY_AREA_POKEMON wcdea:: ; cdea @@ -1355,8 +1373,15 @@ wAIMoveIsNonDamaging:: ; ce02 wce03:: ; ce03 ds $1 - ds $2 +; used by AI to store information of Venusaur2 +; while handling Energy Trans logic. +wAIVenusaur2DeckIndex:: ; ce04 + ds $1 +wAIVenusaur2PlayAreaLocation:: ; ce05 + ds $1 +; number of cards to be transferred by AI using Energy Trans. +wAINumberOfEnergyTransCards:: wce06:: ; ce06 ds $1 |