diff options
| author | xCrystal <rgr.crystal@gmail.com> | 2020-04-24 20:15:48 +0200 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-04-24 20:15:48 +0200 | 
| commit | 9aa5cba752d247f94179b0c9fc6a558f26f77a47 (patch) | |
| tree | d388927011c7a24add473cb2ab77e2a207b9e2e7 /src/engine | |
| parent | e330142a3d14f5d737bc74c162cc04059075b5bb (diff) | |
| parent | a5e06695a1bfd86a0f24483fdfe186fb565e3faf (diff) | |
Merge pull request #65 from ElectroDeoxys/master
Disassemble & document AI routines in bank 5 and 8
Diffstat (limited to 'src/engine')
| -rw-r--r-- | src/engine/bank01.asm | 10 | ||||
| -rw-r--r-- | src/engine/bank05.asm | 441 | ||||
| -rw-r--r-- | src/engine/bank08.asm | 6406 | ||||
| -rw-r--r-- | src/engine/home.asm | 16 | 
4 files changed, 6540 insertions, 333 deletions
| diff --git a/src/engine/bank01.asm b/src/engine/bank01.asm index 5131025..b73b47c 100644 --- a/src/engine/bank01.asm +++ b/src/engine/bank01.asm @@ -3055,7 +3055,7 @@ PracticeDuelVerify_Turn2: ; 5438 (1:5438)  	ld a, [wTempCardID_ccc2]  	cp SEAKING  	jp nz, ReturnWrongAction -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	cp 1  	jp nz, ReturnWrongAction  	ld e, PLAY_AREA_ARENA @@ -3090,7 +3090,7 @@ PracticeDuelVerify_Turn4: ; 5467 (1:5467)  	ld a, [wTempCardID_ccc2]  	cp SEAKING  	jr nz, ReturnWrongAction -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	cp 1  	jr nz, ReturnWrongAction  	ret @@ -3127,7 +3127,7 @@ PracticeDuelVerify_Turn7Or8: ; 54b7 (1:54b7)  	ld a, [wTempCardID_ccc2]  	cp STARMIE  	jr nz, ReturnWrongAction -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	cp 1  	jr nz, ReturnWrongAction  	ret @@ -6041,7 +6041,7 @@ DisplayOpponentUsedMoveScreen: ; 6635 (1:6635)  	ld a, CARDPAGE_POKEMON_OVERVIEW  	ld [wCardPageNumber], a  	ld hl, wLoadedCard1Move1Name -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	or a  	jr z, .first_move  	ld hl, wLoadedCard1Move2Name @@ -6886,7 +6886,7 @@ OppAction_6b3e: ; 6b3e (1:6b3e)  	call SwapTurn  	ldh a, [hTempCardIndex_ff9f]  	ld [wPlayerAttackingCardIndex], a -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	ld [wPlayerAttackingMoveIndex], a  	ld a, [wTempCardID_ccc2]  	ld [wPlayerAttackingCardID], a diff --git a/src/engine/bank05.asm b/src/engine/bank05.asm index 251f5c5..ee45de4 100644 --- a/src/engine/bank05.asm +++ b/src/engine/bank05.asm @@ -91,7 +91,7 @@ Func_1409e: ; 1409e (5:409e)  ; input:  ; 	[hTempPlayAreaLocation_ff9d] = location of attacking card to consider  ; output: -; 	[wSelectedMoveIndex] = move index that KOs +; 	[wSelectedAttack] = move index that KOs  CheckIfAnyMoveKnocksOutDefendingCard: ; 140ae (5:40ae)  	xor a ; first move  	call CheckIfMoveKnocksOutDefendingCard @@ -116,10 +116,10 @@ CheckIfMoveKnocksOutDefendingCard: ; 140b5 (5:40b5)  ; to exactly 0 HP.  ; outputs that attack index in wSelectedMove.  CheckIfAnyDefendingPokemonAttackDealsSameDamageAsHP: ; 140c5 (5:40c5) -	xor a ; first attack +	xor a ; FIRST_ATTACK_OR_PKMN_POWER  	call .check_damage  	ret c -	ld a, $01 ; second attack +	ld a, SECOND_ATTACK  .check_damage  	call EstimateDamage_FromDefendingPokemon @@ -326,7 +326,7 @@ Func_14226: ; 14226 (5:4226)  ; can't use a move or if that selected move doesn't have enough energy  ; input:  ;	[hTempPlayAreaLocation_ff9d] = location of Pokémon card -;	[wSelectedMoveIndex]         = selected move to examine +;	[wSelectedAttack]         = selected move to examine  CheckIfSelectedMoveIsUnusable: ; 1424b (5:424b)  	ldh a, [hTempPlayAreaLocation_ff9d]  	or a @@ -340,7 +340,7 @@ CheckIfSelectedMoveIsUnusable: ; 1424b (5:424b)  	ld a, DUELVARS_ARENA_CARD  	call GetTurnDuelistVariable  	ld d, a -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	ld e, a  	call CopyMoveDataAndDamage_FromDeckIndex  	call HandleAmnesiaSubstatus @@ -361,7 +361,7 @@ CheckIfSelectedMoveIsUnusable: ; 1424b (5:424b)  ; and checks if there is enough energy to execute the selected move  ; input:  ;	[hTempPlayAreaLocation_ff9d] = location of Pokémon card -;	[wSelectedMoveIndex]         = selected move to examine +;	[wSelectedAttack]         = selected move to examine  ; output:  ;	b = basic energy still needed  ;	c = colorless energy still needed @@ -374,7 +374,7 @@ CheckEnergyNeededForAttack: ; 14279 (5:4279)  	add DUELVARS_ARENA_CARD  	call GetTurnDuelistVariable  	ld d, a -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	ld e, a  	call CopyMoveDataAndDamage_FromDeckIndex  	ld hl, wLoadedMoveName @@ -634,7 +634,7 @@ CreateEnergyCardListFromHand: ; 1438c (5:438c)  ; looks for card ID in hand and  ; sets carry if a card wasn't found -; as opposed to LookForCardIDInHandList +; as opposed to LookForCardIDInHandList_Bank5  ; this function doesn't create a list  ; and preserves hl, de and bc  ; input: @@ -686,7 +686,7 @@ LookForCardIDInHand: ; 143bf (5:43bf)  ;	a = move index to take into account  ;	[hTempPlayAreaLocation_ff9d] = location of attacking card to consider  EstimateDamage_VersusDefendingCard: ; 143e5 (5:43e5) -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	ld e, a  	ldh a, [hTempPlayAreaLocation_ff9d]  	add DUELVARS_ARENA_CARD @@ -903,7 +903,7 @@ _CalculateDamage_VersusDefendingPokemon: ; 14462 (5:4462)  ;	                               damage as the receiver  EstimateDamage_FromDefendingPokemon: ; 1450b (5:450b)  	call SwapTurn -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	ld e, a  	ld a, DUELVARS_ARENA_CARD  	call GetTurnDuelistVariable @@ -1135,8 +1135,8 @@ _CalculateDamage_FromDefendingPokemon: ; 1459b (5:459b)  	ret  ; 0x14663 -Func_14663: ; 14663 (5:4663) -	farcall Func_200e5 +AIProcessHandTrainerCards: ; 14663 (5:4663) +	farcall _AIProcessHandTrainerCards  	ret  ; GENERAL DECK POINTER LIST - Not sure on all of these. @@ -1175,7 +1175,7 @@ Func_14687: ; 14687 (5:4687)  Func_1468b: ; 1468b (5:468b)  	call Func_15649  	ld a, $1 -	call Func_14663 +	call AIProcessHandTrainerCards  	farcall $8, $67d3  	jp nc, $4776  	farcall $8, $6790 @@ -1184,28 +1184,28 @@ Func_1468b: ; 1468b (5:468b)  	ret c  	farcall $8, $662d  	ld a, $2 -	call Func_14663 +	call AIProcessHandTrainerCards  	ld a, $3 -	call Func_14663 +	call AIProcessHandTrainerCards  	ld a, $4 -	call Func_14663 +	call AIProcessHandTrainerCards  	call $5eae  	ret c  	ld a, $5 -	call Func_14663 +	call AIProcessHandTrainerCards  	ld a, $6 -	call Func_14663 +	call AIProcessHandTrainerCards  	ld a, $7 -	call Func_14663 +	call AIProcessHandTrainerCards  	ld a, $8 -	call Func_14663 +	call AIProcessHandTrainerCards  	call $4786  	ld a, $a -	call Func_14663 +	call AIProcessHandTrainerCards  	ld a, $b -	call Func_14663 +	call AIProcessHandTrainerCards  	ld a, $c -	call Func_14663 +	call AIProcessHandTrainerCards  	ld a, [wAlreadyPlayedEnergy]  	or a  	jr nz, .asm_146ed @@ -1220,37 +1220,37 @@ Func_1468b: ; 1468b (5:468b)  	ld a, $d  	farcall $8, $619b  	ld a, $d -	call Func_14663 +	call AIProcessHandTrainerCards  	ld a, $f -	call Func_14663 -	ld a, [wce20] -	and $4 +	call AIProcessHandTrainerCards +	ld a, [wPreviousAIFlags] +	and AI_FLAG_USED_PROFESSOR_OAK  	jr z, .asm_14776  	ld a, $1 -	call Func_14663 +	call AIProcessHandTrainerCards  	ld a, $2 -	call Func_14663 +	call AIProcessHandTrainerCards  	ld a, $3 -	call Func_14663 +	call AIProcessHandTrainerCards  	ld a, $4 -	call Func_14663 +	call AIProcessHandTrainerCards  	call $5eae  	ret c  	ld a, $5 -	call Func_14663 +	call AIProcessHandTrainerCards  	ld a, $6 -	call Func_14663 +	call AIProcessHandTrainerCards  	ld a, $7 -	call Func_14663 +	call AIProcessHandTrainerCards  	ld a, $8 -	call Func_14663 +	call AIProcessHandTrainerCards  	call $4786  	ld a, $a -	call Func_14663 +	call AIProcessHandTrainerCards  	ld a, $b -	call Func_14663 +	call AIProcessHandTrainerCards  	ld a, $c -	call Func_14663 +	call AIProcessHandTrainerCards  	ld a, [wAlreadyPlayedEnergy]  	or a  	jr nz, .asm_1475b @@ -1265,7 +1265,7 @@ Func_1468b: ; 1468b (5:468b)  	ld a, $d  	farcall $8, $619b  	ld a, $d -	call Func_14663 +	call AIProcessHandTrainerCards  .asm_14776  	ld a, $e @@ -1317,7 +1317,7 @@ ScoreLegendaryArticunoCards: ; 14c91 (5:4c91)  .lapras  	ld a, LAPRAS  	ld b, PLAY_AREA_BENCH_1 -	call LookForCardIDInBench +	call LookForCardIDInPlayArea_Bank5  	jr nc, .articuno  	ld e, a  	call CountNumberOfEnergyCardsAttached @@ -1330,7 +1330,7 @@ ScoreLegendaryArticunoCards: ; 14c91 (5:4c91)  .articuno  	ld a, ARTICUNO1  	ld b, PLAY_AREA_BENCH_1 -	call LookForCardIDInBench +	call LookForCardIDInPlayArea_Bank5  	jr nc, .dewgong  	ld a, ARTICUNO1  	call RaiseAIScoreToAllMatchingIDsInBench @@ -1339,7 +1339,7 @@ ScoreLegendaryArticunoCards: ; 14c91 (5:4c91)  .dewgong  	ld a, DEWGONG  	ld b, PLAY_AREA_BENCH_1 -	call LookForCardIDInBench +	call LookForCardIDInPlayArea_Bank5  	jr nc, .seel  	ld a, DEWGONG  	call RaiseAIScoreToAllMatchingIDsInBench @@ -1348,7 +1348,7 @@ ScoreLegendaryArticunoCards: ; 14c91 (5:4c91)  .seel  	ld a, SEEL  	ld b, PLAY_AREA_BENCH_1 -	call LookForCardIDInBench +	call LookForCardIDInPlayArea_Bank5  	ret nc  	ld a, SEEL  	call RaiseAIScoreToAllMatchingIDsInBench @@ -1386,7 +1386,7 @@ Data_1514f: ; 1514f (5:514f)  ; output:  ; 	a = card deck index, if found  ;	carry set if found -LookForCardIDInHandList: ; 155d2 (5:55d2) +LookForCardIDInHandList_Bank5: ; 155d2 (5:55d2)  	ld [wTempCardIDToLook], a  	call CreateHandCardList  	ld hl, wDuelTempList @@ -1408,7 +1408,7 @@ LookForCardIDInHandList: ; 155d2 (5:55d2)  ; 0x155ef  ; returns carry if card ID in a -; is found in bench, starting with +; is found in Play Area, starting with  ; location in b  ; input:  ;	a = card ID @@ -1416,7 +1416,7 @@ LookForCardIDInHandList: ; 155d2 (5:55d2)  ; ouput:  ;	a = PLAY_AREA_* of found card  ;	carry set if found -LookForCardIDInBench: ; 155ef (5:55ef) +LookForCardIDInPlayArea_Bank5: ; 155ef (5:55ef)  	ld [wTempCardIDToLook], a  .loop @@ -1450,7 +1450,7 @@ Func_15612: ; 15612 (5:5612)  Func_15636: ; 15636 (5:5636)  	ld a, $10  	ld hl, wcda5 -	call ZeroData +	call ClearMemory_Bank5  	ld a, $5  	ld [wcda6], a  	ld a, $ff @@ -1462,7 +1462,7 @@ Func_15649: ; 15649 (5:5649)  	inc a  	ld [wcda6], a  	xor a -	ld [wce20], a +	ld [wPreviousAIFlags], a  	ld [wcddb], a  	ld [wcddc], a  	ld [wce03], a @@ -1530,7 +1530,7 @@ Func_15649: ; 15649 (5:5649)  ; after removing that attached energy card.  ; input:  ;	[hTempPlayAreaLocation_ff9d] = location of Pokémon card -;	[wSelectedMoveIndex]         = selected move to examine +;	[wSelectedAttack]         = selected move to examine  ; output:  ;	b = basic energy still needed  ;	c = colorless energy still needed @@ -1543,7 +1543,7 @@ CheckEnergyNeededForAttackAfterDiscard: ; 156c3 (5:56c3)  	add DUELVARS_ARENA_CARD  	call GetTurnDuelistVariable  	ld d, a -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	ld e, a  	call CopyMoveDataAndDamage_FromDeckIndex  	ld hl, wLoadedMoveName @@ -1561,7 +1561,7 @@ CheckEnergyNeededForAttackAfterDiscard: ; 156c3 (5:56c3)  .is_attack  	ldh a, [hTempPlayAreaLocation_ff9d] -	farcall GetEnergyCardToDiscard +	farcall AIPickEnergyCardToDiscard  	call LoadCardDataToBuffer1_FromDeckIndex  	cp DOUBLE_COLORLESS_ENERGY  	jr z, .colorless @@ -1642,7 +1642,7 @@ CheckEnergyNeededForAttackAfterDiscard: ; 156c3 (5:56c3)  ; 0x1575e  ; zeroes a bytes starting at hl -ZeroData: ; 1575e (5:575e) +ClearMemory_Bank5: ; 1575e (5:575e)  	push af  	push bc  	push hl @@ -1659,7 +1659,7 @@ ZeroData: ; 1575e (5:575e)  ; 0x1576b  ; returns in a the tens digit of value in a -CalculateTensDigit: ; 1576b (5:576b) +CalculateByteTensDigit: ; 1576b (5:576b)  	push bc  	ld c, 0  .loop @@ -1678,7 +1678,7 @@ CalculateTensDigit: ; 1576b (5:576b)  ; input:  ; 	a = divisor  ; 	b = dividend -CalculateBDividedByA: ; 15778 (5:5778) +CalculateBDividedByA_Bank5: ; 15778 (5:5778)  	push bc  	ld c, a  	ld a, b @@ -1765,8 +1765,99 @@ CheckIfAnyCardIDinLocation: ; 157a3 (5:57a3)  	ret  ; 0x157c6 -Func_157c6: ; 157c6 (5:57c6) -	INCROM $157c6, $158b2 +; 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 +; 0x157f3 + +; 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 +; 0x1581b + +Func_1581b: ; 1581b (5:581b) +	INCROM $1581b, $158b2  ; determine AI score for retreating  ; return carry if AI decides to retreat @@ -1779,7 +1870,7 @@ AIDecideWhetherToRetreat: ; 158b2 (5:58b2)  	call LoadDefendingPokemonColorWRAndPrizeCards  	ld a, 128 ; initial retreat score  	ld [wAIScore], a -	ld a, [$cdb4] +	ld a, [wcdb4]  	or a  	jr z, .check_status  	srl a @@ -2283,11 +2374,11 @@ AIDecideBenchPokemonToSwitchTo: ; 15b72 (5:5b72)  ; to raise AI score accordingly  .check_can_use_moves  	xor a -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	call CheckIfSelectedMoveIsUnusable  	call nc, .calculate_damage  	ld a, $01 -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	call CheckIfSelectedMoveIsUnusable  	call nc, .calculate_damage  	jr .check_energy_card @@ -2296,10 +2387,10 @@ AIDecideBenchPokemonToSwitchTo: ; 15b72 (5:5b72)  ; it can inflict to the defending Pokémon  ; AI score += floor(Damage / 10) + 1  .calculate_damage -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	call EstimateDamage_VersusDefendingCard  	ld a, [wDamage] -	call CalculateTensDigit +	call CalculateByteTensDigit  	inc a  	call AddToAIScore  	ret @@ -2310,10 +2401,10 @@ AIDecideBenchPokemonToSwitchTo: ; 15b72 (5:5b72)  .check_energy_card  	call LookForEnergyNeededInHand  	jr nc, .check_attached_energy -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	call EstimateDamage_VersusDefendingCard  	ld a, [wDamage] -	call CalculateTensDigit +	call CalculateByteTensDigit  	srl a  	call AddToAIScore @@ -2440,8 +2531,8 @@ AIDecideBenchPokemonToSwitchTo: ; 15b72 (5:5b72)  .add_hp_score  	ld b, a  	ld a, 4 -	call CalculateBDividedByA -	call CalculateTensDigit +	call CalculateBDividedByA_Bank5 +	call CalculateByteTensDigit  	call AddToAIScore  ; raise AI score if @@ -2530,7 +2621,7 @@ AIDecideBenchPokemonToSwitchTo: ; 15b72 (5:5b72)  ; done  	xor a -	ld [$cdb4], a +	ld [wcdb4], a  	jp FindHighestBenchScore  ; 0x15d4f @@ -2948,11 +3039,11 @@ AIDecideEvolution: ; 15f4c (5:5f4c)  ; check if the card can use any moves  ; and if any of those moves can KO  	xor a -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	call CheckIfSelectedMoveIsUnusable  	jr nc, .can_attack  	ld a, $01 -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	call CheckIfSelectedMoveIsUnusable  	jr c, .cant_attack_or_ko  .can_attack @@ -2982,11 +3073,11 @@ AIDecideEvolution: ; 15f4c (5:5f4c)  	ld a, [wTempAIPokemonCard]  	ld [hl], a  	xor a -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	call CheckIfSelectedMoveIsUnusable  	jr nc, .evolution_can_attack  	ld a, $01 -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	call CheckIfSelectedMoveIsUnusable  	jr c, .evolution_cant_attack  .evolution_can_attack @@ -3104,7 +3195,7 @@ AIDecideEvolution: ; 15f4c (5:5f4c)  	jr z, .check_mysterious_fossil  	srl a  	srl a -	call CalculateTensDigit +	call CalculateByteTensDigit  	call SubFromAIScore  ; if is Mysterious Fossil or  @@ -3206,7 +3297,7 @@ Func_16120: ; 16120 (5:6120)  	cp 3  	jr c, .not_enough_energy  	push af -	farcall CountEnergyCardsInHand +	farcall CountOppEnergyCardsInHand  	pop bc  	add b  	cp 6 @@ -3466,7 +3557,7 @@ CheckIfActivePokemonCanUseAnyNonResidualMove: ; 162a1 (5:62a1)  	xor a ; active card  	ldh [hTempPlayAreaLocation_ff9d], a  ; first move -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	call CheckIfSelectedMoveIsUnusable  	jr c, .next_move  	ld a, [wLoadedMoveCategory] @@ -3476,7 +3567,7 @@ CheckIfActivePokemonCanUseAnyNonResidualMove: ; 162a1 (5:62a1)  .next_move  ; second move  	ld a, $01 -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	call CheckIfSelectedMoveIsUnusable  	jr c, .fail  	ld a, [wLoadedMoveCategory] @@ -3502,7 +3593,7 @@ CheckIfActivePokemonCanUseAnyNonResidualMove: ; 162a1 (5:62a1)  ;	[hTempPlayAreaLocation_ff9d] = location of Pokémon card  LookForEnergyNeededInHand: ; 162c8 (5:62c8)  	xor a ; first move -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	call CheckEnergyNeededForAttack  	ld a, b  	add c @@ -3516,7 +3607,7 @@ LookForEnergyNeededInHand: ; 162c8 (5:62c8)  .second_attack  	ld a, $01 ; second move -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	call CheckEnergyNeededForAttack  	ld a, b  	add c @@ -3536,7 +3627,7 @@ LookForEnergyNeededInHand: ; 162c8 (5:62c8)  	or a  	jr z, .one_colorless  	ld a, e -	call LookForCardIDInHandList +	call LookForCardIDInHandList_Bank5  	ret c  	jr .no_carry @@ -3548,7 +3639,7 @@ LookForEnergyNeededInHand: ; 162c8 (5:62c8)  .two_colorless  	ld a, DOUBLE_COLORLESS_ENERGY -	call LookForCardIDInHandList +	call LookForCardIDInHandList_Bank5  	ret c  	jr .no_carry  ; 0x16311 @@ -3562,7 +3653,7 @@ LookForEnergyNeededInHand: ; 162c8 (5:62c8)  ; return carry if successful in finding card  ; input:  ;	[hTempPlayAreaLocation_ff9d] = location of Pokémon card -;	[wSelectedMoveIndex]         = selected move to examine +;	[wSelectedAttack]         = selected move to examine  LookForEnergyNeededForMoveInHand: ; 16311 (5:6311)  	call CheckEnergyNeededForAttack  	ld a, b @@ -3583,7 +3674,7 @@ LookForEnergyNeededForMoveInHand: ; 16311 (5:6311)  	or a  	jr z, .one_colorless  	ld a, e -	call LookForCardIDInHandList +	call LookForCardIDInHandList_Bank5  	ret c  	jr .done @@ -3595,7 +3686,7 @@ LookForEnergyNeededForMoveInHand: ; 16311 (5:6311)  .two_colorless  	ld a, DOUBLE_COLORLESS_ENERGY -	call LookForCardIDInHandList +	call LookForCardIDInHandList_Bank5  	ret c  	jr .done  ; 0x1633f @@ -4080,7 +4171,7 @@ AIDecideWhichCardToAttachEnergy: ; 164fc (5:64fc)  	ld a, DUELVARS_ARENA_CARD_HP  	call GetTurnDuelistVariable -	call CalculateTensDigit +	call CalculateByteTensDigit  	cp 3  	jr nc, .check_defending_can_ko  ; hp < 30 @@ -4124,7 +4215,7 @@ AIDecideWhichCardToAttachEnergy: ; 164fc (5:64fc)  .bench  	add DUELVARS_ARENA_CARD_HP  	call GetTurnDuelistVariable -	call CalculateTensDigit +	call CalculateByteTensDigit  	cp 3  	jr nc, .asm_165e1  ; hp < 30 @@ -4271,9 +4362,9 @@ AIDecideWhichCardToAttachEnergy: ; 164fc (5:64fc)  ; in order to determine whether to play energy card.  ; the AI score is increased/decreased accordingly.  ; input: -;	[wSelectedMoveIndex] = move to check. +;	[wSelectedAttack] = move to check.  DetermineAIScoreOfMoveEnergyRequirement: ; 16695 (5:6695) -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	call CheckEnergyNeededForAttack  	jp c, .not_enough_energy  	ld a, MOVE_FLAG2_ADDRESS | ATTACHED_ENERGY_BOOST_F @@ -4285,9 +4376,12 @@ DetermineAIScoreOfMoveEnergyRequirement: ; 16695 (5:6695)  	jp .check_evolution  .attached_energy_boost -	ld a, [wLoadedMoveUnknown1] -	cp $02 +	ld a, [wLoadedMoveEffectParam] +	cp MAX_ENERGY_BOOST_IS_LIMITED  	jr z, .check_surplus_energy + +	; is MAX_ENERGY_BOOST_IS_NOT_LIMITED, +	; which is equal to 3, add to score.  	call AddToAIScore  	jp .check_evolution @@ -4313,7 +4407,7 @@ DetermineAIScoreOfMoveEnergyRequirement: ; 16695 (5:6695)  	ld a, MOVE_FLAG2_ADDRESS | ATTACHED_ENERGY_BOOST_F  	call CheckLoadedMoveFlag  	jp nc, .check_evolution -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	call EstimateDamage_VersusDefendingCard  	ld a, DUELVARS_ARENA_CARD_HP  	call GetNonTurnDuelistVariable @@ -4392,7 +4486,7 @@ DetermineAIScoreOfMoveEnergyRequirement: ; 16695 (5:6695)  	ldh a, [hTempPlayAreaLocation_ff9d]  	or a  	jr nz, .check_evolution -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	call EstimateDamage_VersusDefendingCard  	ld a, DUELVARS_ARENA_CARD_HP  	call GetNonTurnDuelistVariable @@ -4580,7 +4674,7 @@ CheckIfEvolutionNeedsEnergyForMove: ; 16805 (5:6805)  ; 0x1683b  ; returns in e the card ID of the energy required for -; the Discard/Energy Boost attack loaded in wSelectedMoveIndex. +; the Discard/Energy Boost attack loaded in wSelectedAttack.  ; if it's Zapdos2's Thunderbolt attack, return no carry.  ; if it's Charizard's Fire Spin or Exeggutor's Big Eggplosion  ; attack, don't return energy card ID, but set carry. @@ -4595,7 +4689,7 @@ GetEnergyCardForDiscardOrEnergyBoostAttack: ; 1683b (5:683b)  	call GetTurnDuelistVariable  	call LoadCardDataToBuffer2_FromDeckIndex  	ld b, a -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	or a  	jr z, .first_attack @@ -4682,7 +4776,7 @@ AITryToPlayEnergyCard: ; 1689f (5:689f)  ; if first attack doesn't need, test for the second attack.  	xor a  	ld [wTempAI], a -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	call CheckEnergyNeededForAttack  	jr nc, .second_attack  	ld a, b @@ -4693,8 +4787,8 @@ AITryToPlayEnergyCard: ; 1689f (5:689f)  	jr nz, .check_deck  .second_attack -	ld a, $01 ; second attack -	ld [wSelectedMoveIndex], a +	ld a, SECOND_ATTACK +	ld [wSelectedAttack], a  	call CheckEnergyNeededForAttack  	jr nc, .check_discard_or_energy_boost  	ld a, b @@ -4713,8 +4807,8 @@ AITryToPlayEnergyCard: ; 1689f (5:689f)  ; for both attacks, check if it has the effect of  ; discarding energy cards or attached energy boost. -	xor a ; first attack -	ld [wSelectedMoveIndex], a +	xor a ; FIRST_ATTACK_OR_PKMN_POWER +	ld [wSelectedAttack], a  	call CheckEnergyNeededForAttack  	ld a, MOVE_FLAG2_ADDRESS | ATTACHED_ENERGY_BOOST_F  	call CheckLoadedMoveFlag @@ -4723,8 +4817,8 @@ AITryToPlayEnergyCard: ; 1689f (5:689f)  	call CheckLoadedMoveFlag  	jr c, .energy_boost_or_discard_energy -	ld a, $01 ; second attack -	ld [wSelectedMoveIndex], a +	ld a, SECOND_ATTACK +	ld [wSelectedAttack], a  	call CheckEnergyNeededForAttack  	ld a, MOVE_FLAG2_ADDRESS | ATTACHED_ENERGY_BOOST_F  	call CheckLoadedMoveFlag @@ -4832,7 +4926,7 @@ AITryToPlayEnergyCard: ; 1689f (5:689f)  	jr z, .check_first_attack  	ret  .check_first_attack -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	or a  	jp z, .second_attack  	ret @@ -4940,14 +5034,14 @@ Func_169ca: ; 169ca (5:69ca)  	dec b  	jr nz, .loop +; copies wAIScore to wcde3  	ld a, [wAIScore]  	ld [de], a -	jr Func_169f8.asm_169fc +	jr Func_169fc  ; copies wTempPlayAreaAIScore to wPlayAreaAIScore  ; and loads wAIscore with value in wcde3.  ; identical to Func_164d3. -; TODO: reconsider function structure here.  Func_169e3: ; 169e3 (5:69e3)  	push af  	ld de, wPlayAreaAIScore @@ -4959,6 +5053,7 @@ Func_169e3: ; 169e3 (5:69e3)  	inc de  	dec b  	jr nz, .loop +  	ld a, [hl]  	ld [wAIScore], a  	pop af @@ -4968,27 +5063,32 @@ Func_169e3: ; 169e3 (5:69e3)  Func_169f8: ; 169f8 (5:69f8)  	xor a  	ld [wcdd9], a -.asm_169fc -	ld a, [wce20] -	and $01 -	jr z, .asm_16a0b -	ld a, [wcdd6] -	ld [wSelectedMoveIndex], a -	jr .first_attack -	 -.asm_16a0b +	; fallthrough + +Func_169fc: ; 169fc (5:69fc) +; if AI used Pluspower, load its attack index +	ld a, [wPreviousAIFlags] +	and AI_FLAG_USED_PLUSPOWER +	jr z, .no_pluspower +	ld a, [wAIPluspowerAttack] +	ld [wSelectedAttack], a +	jr .attack_chosen + +.no_pluspower  	ld a, [wcda7]  	cp $80  	jp z, .asm_16a77  ; determine AI score of both attacks. -	xor a ; first attack +	xor a ; FIRST_ATTACK_OR_PKMN_POWER  	call GetAIScoreOfAttack  	ld a, [wAIScore]  	ld [wPlayAreaAIScore], a -	ld a, $01 ; second attack +	ld a, SECOND_ATTACK  	call GetAIScoreOfAttack -	ld c, $01 + +; compare both attack scores +	ld c, SECOND_ATTACK  	ld a, [wPlayAreaAIScore]  	ld b, a  	ld a, [wAIScore] @@ -5006,13 +5106,15 @@ Func_169f8: ; 169f8 (5:69f8)  .asm_16a30  	cp $50 ; minimum score to use attack  	jr c, .asm_16a77 +	; enough score, proceed +  	ld a, c -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	or a -	jr z, .first_attack +	jr z, .attack_chosen  	call CheckWhetherToSwitchToFirstAttack -.first_attack +.attack_chosen  	ld a, [wcdd9]  	or a  	jr z, .asm_16a48 @@ -5021,23 +5123,30 @@ Func_169f8: ; 169f8 (5:69f8)  .asm_16a48  	ld a, $0e -	call Func_14663 -	xor a +	call AIProcessHandTrainerCards + +; load this attack's damage output against +; the current Defending Pokemon. +	xor a ; PLAY_AREA_ARENA  	ldh [hTempPlayAreaLocation_ff9d], a -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	call EstimateDamage_VersusDefendingCard  	ld a, [wDamage] +  	or a  	jr z, .asm_16a62 -.asm_16a5c +	; if damage is 0, fallthrough + +.cannot_damage  	xor a -	ld [$cdb4], a +	ld [wcdb4], a  	jr .asm_16a6d +  .asm_16a62  	ld a, MOVE_FLAG1_ADDRESS | DAMAGE_TO_OPPONENT_BENCH_F  	call CheckLoadedMoveFlag -	jr c, .asm_16a5c -	ld hl, $cdb4 +	jr c, .cannot_damage +	ld hl, wcdb4  	inc [hl]  .asm_16a6d  	ld a, $01 @@ -5051,7 +5160,7 @@ Func_169f8: ; 169f8 (5:69f8)  	jr z, .asm_16a80  	jp Func_169e3  .asm_16a80 -	ld hl, $cdb4 +	ld hl, wcdb4  	inc [hl]  	or a  	ret @@ -5060,7 +5169,7 @@ Func_169f8: ; 169f8 (5:69f8)  ; determines the AI score of attack index in a.  GetAIScoreOfAttack: ; 16a86 (5:6a86)  ; initialize AI score. -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	ld a, $50  	ld [wAIScore], a @@ -5103,7 +5212,7 @@ GetAIScoreOfAttack: ; 16a86 (5:6a86)  	; player is under No Damage substatus  	ld a, $01  	ld [wAICannotDamage], a -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	call EstimateDamage_VersusDefendingCard  	ld a, [wLoadedMoveCategory]  	cp POKEMON_POWER @@ -5117,7 +5226,7 @@ GetAIScoreOfAttack: ; 16a86 (5:6a86)  ; calculate damage to player to check if move can KO.  ; encourage move if it's able to KO.  .check_if_can_ko -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	call EstimateDamage_VersusDefendingCard  	ld a, DUELVARS_ARENA_CARD_HP  	call GetNonTurnDuelistVariable @@ -5142,7 +5251,7 @@ GetAIScoreOfAttack: ; 16a86 (5:6a86)  	ld [wTempAI], a  	or a  	jr z, .no_damage -	call CalculateTensDigit +	call CalculateByteTensDigit  	call AddToAIScore  	jr .check_recoil  .no_damage @@ -5174,13 +5283,13 @@ GetAIScoreOfAttack: ; 16a86 (5:6a86)  .is_recoil  	; sub from AI score number of damage counters  	; that move deals to itself. -	ld a, [wLoadedMoveUnknown1] +	ld a, [wLoadedMoveEffectParam]  	or a  	jp z, .check_defending_can_ko  	ld [wDamage], a  	call ApplyDamageModifiers_DamageToSelf  	ld a, e -	call CalculateTensDigit +	call CalculateByteTensDigit  	call SubFromAIScore  	push de @@ -5395,12 +5504,12 @@ GetAIScoreOfAttack: ; 16a86 (5:6a86)  ; if defending card can KO, encourage move  ; unless move is non-damaging.  .check_defending_can_ko -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	push af  	call CheckIfDefendingPokemonCanKnockOut  	pop bc  	ld a, b -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	jr nc, .check_discard  	ld a, 5  	call AddToAIScore @@ -5413,7 +5522,7 @@ GetAIScoreOfAttack: ; 16a86 (5:6a86)  ; subtract from AI score if this move requires  ; discarding any energy cards.  .check_discard -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	ld e, a  	ld a, DUELVARS_ARENA_CARD  	call GetTurnDuelistVariable @@ -5424,14 +5533,14 @@ GetAIScoreOfAttack: ; 16a86 (5:6a86)  	jr nc, .asm_16ca6  	ld a, 1  	call SubFromAIScore -	ld a, [wLoadedMoveUnknown1] +	ld a, [wLoadedMoveEffectParam]  	call SubFromAIScore  .asm_16ca6  	ld a, MOVE_FLAG2_ADDRESS | FLAG_2_BIT_6_F  	call CheckLoadedMoveFlag  	jr nc, .check_nullify_flag -	ld a, [wLoadedMoveUnknown1] +	ld a, [wLoadedMoveEffectParam]  	call AddToAIScore  ; encourage move if it has a nullify or weaken attack effect. @@ -5454,13 +5563,13 @@ GetAIScoreOfAttack: ; 16a86 (5:6a86)  	ld a, MOVE_FLAG2_ADDRESS | HEAL_USER_F  	call CheckLoadedMoveFlag  	jr nc, .check_status_effect -	ld a, [wLoadedMoveUnknown1] +	ld a, [wLoadedMoveEffectParam]  	cp 1  	jr z, .tally_heal_score  	ld a, [wTempAI] -	call CalculateTensDigit +	call CalculateByteTensDigit  	ld b, a -	ld a, [wLoadedMoveUnknown1] +	ld a, [wLoadedMoveEffectParam]  	cp 3  	jr z, .asm_16cec  	srl b @@ -5469,7 +5578,7 @@ GetAIScoreOfAttack: ; 16a86 (5:6a86)  .asm_16cec  	ld a, DUELVARS_ARENA_CARD_HP  	call GetTurnDuelistVariable -	call CalculateTensDigit +	call CalculateByteTensDigit  	cp b  	jr c, .tally_heal_score  	ld a, b @@ -5477,9 +5586,9 @@ GetAIScoreOfAttack: ; 16a86 (5:6a86)  	push af  	ld e, PLAY_AREA_ARENA  	call GetCardDamage -	call CalculateTensDigit +	call CalculateByteTensDigit  	pop bc -	cp b ; wLoadedMoveUnknown1 +	cp b ; wLoadedMoveEffectParam  	jr c, .add_heal_score  	ld a, b  .add_heal_score @@ -5771,7 +5880,7 @@ HandleSwordsDanceAndFocusEnergy: ; 16ecb (5:6ecb)  	or a  	jr nz, .success  	ld a, $01 ; second move -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	call CheckIfSelectedMoveIsUnusable  	jr c, .success  	ld a, $01 ; second move @@ -5828,7 +5937,7 @@ HandlePorygonConversion: ; 16f18 (5:6f18)  	cp CONFUSED  	jp z, HandleSpecialAIMoves.zero -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	or a  	jr nz, .conversion_2 @@ -6053,11 +6162,11 @@ CheckWhetherToSwitchToFirstAttack: ; 17019 (5:7019)  	jr c, .keep_second_attack  ; switch to first attack  	xor a -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	ret  .keep_second_attack  	ld a, $01 -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	ret  ; 0x17057 @@ -6186,7 +6295,7 @@ CheckIfArenaCardIsAtHalfHPCanEvolveAndUseSecondMove: ; 170c9 (5:70c9)  	xor a ; active card  	ldh [hTempPlayAreaLocation_ff9d], a  	ld a, $01 ; second move -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	push hl  	call CheckIfSelectedMoveIsUnusable  	pop hl @@ -6209,7 +6318,7 @@ CheckIfArenaCardIsAtHalfHPCanEvolveAndUseSecondMove: ; 170c9 (5:70c9)  CheckIfBenchCardsAreAtHalfHPCanEvolveAndUseSecondMove: ; 17101 (5:7101)  	ldh a, [hTempPlayAreaLocation_ff9d]  	ld d, a -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	ld e, a  	push de  	ld a, DUELVARS_BENCH @@ -6253,7 +6362,7 @@ CheckIfBenchCardsAreAtHalfHPCanEvolveAndUseSecondMove: ; 17101 (5:7101)  	ld a, c  	ldh [hTempPlayAreaLocation_ff9d], a  	ld a, $01 ; second move -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	push bc  	push hl  	call CheckIfSelectedMoveIsUnusable @@ -6267,7 +6376,7 @@ CheckIfBenchCardsAreAtHalfHPCanEvolveAndUseSecondMove: ; 17101 (5:7101)  	pop hl  	pop de  	ld a, e -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	ld a, d  	ldh [hTempPlayAreaLocation_ff9d], a  	ld a, b @@ -6282,11 +6391,11 @@ Func_17161 ; 17161 (5:7161)  ; return carry if Pokémon at play area location  ; in hTempPlayAreaLocation_ff9d does not have -; energy required for the move index in wSelectedMoveIndex +; energy required for the move index in wSelectedAttack  ; or has exactly the same amount of energy needed  ; input:  ;	[hTempPlayAreaLocation_ff9d] = play area location -;	[wSelectedMoveIndex]         = move index to check +;	[wSelectedAttack]         = move index to check  ; output:  ;	a = number of extra energy cards attached  CheckIfNoSurplusEnergyForMove: ; 171fb (5:71fb) @@ -6294,7 +6403,7 @@ CheckIfNoSurplusEnergyForMove: ; 171fb (5:71fb)  	add DUELVARS_ARENA_CARD  	call GetTurnDuelistVariable  	ld d, a -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	ld e, a  	call CopyMoveDataAndDamage_FromDeckIndex  	ld hl, wLoadedMoveName @@ -6448,7 +6557,7 @@ Func_172af ; 172af (5:72af)  CheckIfCanDamageDefendingPokemon: ; 17383 (5:7383)  	ldh [hTempPlayAreaLocation_ff9d], a  	xor a ; first move -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	call CheckIfSelectedMoveIsUnusable  	jr c, .second_attack  	xor a @@ -6459,7 +6568,7 @@ CheckIfCanDamageDefendingPokemon: ; 17383 (5:7383)  .second_attack  	ld a, $01 ; second move -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	call CheckIfSelectedMoveIsUnusable  	jr c, .no_carry  	ld a, $01 @@ -6526,7 +6635,7 @@ CheckIfDefendingPokemonCanKnockOut: ; 173b1 (5:73b1)  ;	a = move index  ;	[hTempPlayAreaLocation_ff9d] = location of card to check  CheckIfDefendingPokemonCanKnockOutWithMove: ; 173e4 (5:73e4) -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	ldh a, [hTempPlayAreaLocation_ff9d]  	push af  	xor a @@ -6540,7 +6649,7 @@ CheckIfDefendingPokemonCanKnockOutWithMove: ; 173e4 (5:73e4)  	jr c, .done  ; player's active Pokémon can use move -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	call EstimateDamage_FromDefendingPokemon  	ldh a, [hTempPlayAreaLocation_ff9d]  	add DUELVARS_ARENA_CARD_HP @@ -6601,8 +6710,12 @@ CheckIfNotABossDeckID: ; 17426 (5:7426)  ; probability to return carry:  ; - 50% if deck AI is playing is on the list; -; - 25% for all other decks. -Func_1743b: ; 1743b (5:743b) +; - 25% for all other decks; +; - 0% for boss decks. +; used for certain decks to randomly choose +; not to play Trainer card in hand. +ChooseRandomlyNotToPlayTrainerCard: ; 1743b (5:743b) +; boss decks always use Trainer cards.  	push hl  	push de  	call CheckIfNotABossDeckID @@ -6654,7 +6767,7 @@ CheckForBenchIDAtHalfHPAndCanUseSecondMove: ; 17474 (5:7474)  	ld [wcdf9], a  	ldh a, [hTempPlayAreaLocation_ff9d]  	ld d, a -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	ld e, a  	push de  	ld a, DUELVARS_ARENA_CARD @@ -6692,7 +6805,7 @@ CheckForBenchIDAtHalfHPAndCanUseSecondMove: ; 17474 (5:7474)  	ld a, c  	ldh [hTempPlayAreaLocation_ff9d], a  	ld a, $01 ; second move -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	push bc  	call CheckIfSelectedMoveIsUnusable  	pop bc @@ -6702,7 +6815,7 @@ CheckForBenchIDAtHalfHPAndCanUseSecondMove: ; 17474 (5:7474)  	pop hl  	pop de  	ld a, e -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	ld a, d  	ldh [hTempPlayAreaLocation_ff9d], a  	ld a, b @@ -6752,7 +6865,7 @@ RaiseAIScoreToAllMatchingIDsInBench: ; 174cd (5:74cd)  Func_174f2: ; 174f2 (5:74f2)  	ld a, MAX_PLAY_AREA_POKEMON  	ld hl, wcdfa -	call ZeroData +	call ClearMemory_Bank5  	ld a, DUELVARS_BENCH  	call GetTurnDuelistVariable  	ld e, 0 @@ -6761,7 +6874,7 @@ Func_174f2: ; 174f2 (5:74f2)  	push hl  	ld a, MAX_PLAY_AREA_POKEMON  	ld hl, wcdea -	call ZeroData +	call ClearMemory_Bank5  	pop hl  	inc e  	ld a, [hli] @@ -6875,7 +6988,7 @@ Func_17583: ; 17583 (5:7583)  	push hl  	push de  	call GetCardDamage -	call CalculateTensDigit +	call CalculateByteTensDigit  	ld b, a  	push bc  	call CountNumberOfEnergyCardsAttached diff --git a/src/engine/bank08.asm b/src/engine/bank08.asm index 48ed23f..5a0f535 100644 --- a/src/engine/bank08.asm +++ b/src/engine/bank08.asm @@ -6,47 +6,47 @@ unknown_data_20000: MACRO  ENDM  Data_20000: ; 20000 (8:4000) -	unknown_data_20000 $07, POTION,                 CheckIfPotionPreventsKnockOut, AIPlayPotion -	unknown_data_20000 $0a, POTION,                 FindTargetCardForPotion, AIPlayPotion -	unknown_data_20000 $08, SUPER_POTION,           CheckIfSuperPotionPreventsKnockOut, AIPlaySuperPotion -	unknown_data_20000 $0b, SUPER_POTION,           FindTargetCardForSuperPotion, AIPlaySuperPotion -	unknown_data_20000 $0d, DEFENDER,               CheckIfDefenderPreventsKnockOut, AIPlayDefender -	unknown_data_20000 $0e, DEFENDER,               CheckIfDefenderPreventsRecoilKnockOut, AIPlayDefender -	unknown_data_20000 $0d, PLUSPOWER,              $4501, AIPlayPluspower -	unknown_data_20000 $0e, PLUSPOWER,              $45a5, AIPlayPluspower -	unknown_data_20000 $09, SWITCH,                 $462e, $4612 -	unknown_data_20000 $07, GUST_OF_WIND,           $467e, $4666 -	unknown_data_20000 $0a, GUST_OF_WIND,           $467e, $4666 -	unknown_data_20000 $04, BILL,                   $4878, $486d -	unknown_data_20000 $05, ENERGY_REMOVAL,         $4895, $4880 -	unknown_data_20000 $05, SUPER_ENERGY_REMOVAL,   $49bc, $4994 -	unknown_data_20000 $07, POKEMON_BREEDER,        $4b1b, $4b06 -	unknown_data_20000 $0f, PROFESSOR_OAK,          $4cc1, $4cae -	unknown_data_20000 $0a, ENERGY_RETRIEVAL,       $4e6e, $4e44 -	unknown_data_20000 $0b, SUPER_ENERGY_RETRIEVAL, $4fc1, $4f80 -	unknown_data_20000 $06, POKEMON_CENTER,         $50eb, $50e0 -	unknown_data_20000 $07, IMPOSTER_PROFESSOR_OAK, $517b, $5170 -	unknown_data_20000 $0c, ENERGY_SEARCH,          $51aa, $519a -	unknown_data_20000 $03, POKEDEX,                $52dc, $52b4 -	unknown_data_20000 $07, FULL_HEAL,              $5428, $541d -	unknown_data_20000 $0a, MR_FUJI,                $54a7, $5497 -	unknown_data_20000 $0a, SCOOP_UP,               $5506, $54f1 -	unknown_data_20000 $02, MAINTENANCE,            $562c, $560f -	unknown_data_20000 $03, RECYCLE,                $56b8, $569a -	unknown_data_20000 $0d, LASS,                   $5768, $5755 -	unknown_data_20000 $04, ITEM_FINDER,            $57b1, $578f -	unknown_data_20000 $01, IMAKUNI_CARD,           $581e, $5813 -	unknown_data_20000 $01, GAMBLER,                $5875, $582d -	unknown_data_20000 $05, REVIVE,                 $58a9, $5899 -	unknown_data_20000 $0d, POKEMON_FLUTE,          $58e8, $58d8 -	unknown_data_20000 $05, CLEFAIRY_DOLL,          $5982, $5977 -	unknown_data_20000 $05, MYSTERIOUS_FOSSIL,      $5982, $5977 -	unknown_data_20000 $02, POKE_BALL,              $59c6, $59a6 -	unknown_data_20000 $02, COMPUTER_SEARCH,        $5b34, $5b12 -	unknown_data_20000 $02, POKEMON_TRADER,         $5d8f, $5d7a +	unknown_data_20000 AI_TRAINER_CARD_PHASE_07, POTION,                 AIDecide_Potion1,                        AIPlay_Potion +	unknown_data_20000 AI_TRAINER_CARD_PHASE_10, POTION,                 AIDecide_Potion2,                        AIPlay_Potion +	unknown_data_20000 AI_TRAINER_CARD_PHASE_08, SUPER_POTION,           AIDecide_SuperPotion1,                   AIPlay_SuperPotion +	unknown_data_20000 AI_TRAINER_CARD_PHASE_11, SUPER_POTION,           AIDecide_SuperPotion2,                   AIPlay_SuperPotion +	unknown_data_20000 AI_TRAINER_CARD_PHASE_13, DEFENDER,               AIDecide_Defender1,                      AIPlay_Defender +	unknown_data_20000 AI_TRAINER_CARD_PHASE_14, DEFENDER,               AIDecide_Defender2,                      AIPlay_Defender +	unknown_data_20000 AI_TRAINER_CARD_PHASE_13, PLUSPOWER,              AIDecide_Pluspower1,                     AIPlay_Pluspower +	unknown_data_20000 AI_TRAINER_CARD_PHASE_14, PLUSPOWER,              AIDecide_Pluspower2,                     AIPlay_Pluspower +	unknown_data_20000 AI_TRAINER_CARD_PHASE_09, SWITCH,                 AIDecide_Switch,                         AIPlay_Switch +	unknown_data_20000 AI_TRAINER_CARD_PHASE_07, GUST_OF_WIND,           AIDecide_GustOfWind,                     AIPlay_GustOfWind +	unknown_data_20000 AI_TRAINER_CARD_PHASE_10, GUST_OF_WIND,           AIDecide_GustOfWind,                     AIPlay_GustOfWind +	unknown_data_20000 AI_TRAINER_CARD_PHASE_04, BILL,                   AIDecide_Bill,                           AIPlay_Bill +	unknown_data_20000 AI_TRAINER_CARD_PHASE_05, ENERGY_REMOVAL,         AIDecide_EnergyRemoval,                  AIPlay_EnergyRemoval +	unknown_data_20000 AI_TRAINER_CARD_PHASE_05, SUPER_ENERGY_REMOVAL,   AIDecide_SuperEnergyRemoval,             AIPlay_SuperEnergyRemoval +	unknown_data_20000 AI_TRAINER_CARD_PHASE_07, POKEMON_BREEDER,        AIDecide_PokemonBreeder,                 AIPlay_PokemonBreeder +	unknown_data_20000 AI_TRAINER_CARD_PHASE_15, PROFESSOR_OAK,          AIDecide_ProfessorOak,                   AIPlay_ProfessorOak +	unknown_data_20000 AI_TRAINER_CARD_PHASE_10, ENERGY_RETRIEVAL,       AIDecide_EnergyRetrieval,                AIPlay_EnergyRetrieval +	unknown_data_20000 AI_TRAINER_CARD_PHASE_11, SUPER_ENERGY_RETRIEVAL, AIDecide_SuperEnergyRetrieval,           AIPlay_SuperEnergyRetrieval +	unknown_data_20000 AI_TRAINER_CARD_PHASE_06, POKEMON_CENTER,         AIDecide_PokemonCenter,                  AIPlay_PokemonCenter +	unknown_data_20000 AI_TRAINER_CARD_PHASE_07, IMPOSTER_PROFESSOR_OAK, AIDecide_ImposterProfessorOak,           AIPlay_ImposterProfessorOak +	unknown_data_20000 AI_TRAINER_CARD_PHASE_12, ENERGY_SEARCH,          AIDecide_EnergySearch,                   AIPlay_EnergySearch +	unknown_data_20000 AI_TRAINER_CARD_PHASE_03, POKEDEX,                AIDecide_Pokedex,                        AIPlay_Pokedex +	unknown_data_20000 AI_TRAINER_CARD_PHASE_07, FULL_HEAL,              AIDecide_FullHeal,                       AIPlay_FullHeal +	unknown_data_20000 AI_TRAINER_CARD_PHASE_10, MR_FUJI,                AIDecide_MrFuji,                         AIPlay_MrFuji +	unknown_data_20000 AI_TRAINER_CARD_PHASE_10, SCOOP_UP,               AIDecide_ScoopUp,                        AIPlay_ScoopUp +	unknown_data_20000 AI_TRAINER_CARD_PHASE_02, MAINTENANCE,            AIDecide_Maintenance,                    AIPlay_Maintenance +	unknown_data_20000 AI_TRAINER_CARD_PHASE_03, RECYCLE,                AIDecide_Recycle,                        AIPlay_Recycle +	unknown_data_20000 AI_TRAINER_CARD_PHASE_13, LASS,                   AIDecide_Lass,                           AIPlay_Lass +	unknown_data_20000 AI_TRAINER_CARD_PHASE_04, ITEM_FINDER,            AIDecide_ItemFinder,                     AIPlay_ItemFinder +	unknown_data_20000 AI_TRAINER_CARD_PHASE_01, IMAKUNI_CARD,           AIDecide_Imakuni,                        AIPlay_Imakuni +	unknown_data_20000 AI_TRAINER_CARD_PHASE_01, GAMBLER,                AIDecide_Gambler,                        AIPlay_Gambler +	unknown_data_20000 AI_TRAINER_CARD_PHASE_05, REVIVE,                 AIDecide_Revive,                         AIPlay_Revive +	unknown_data_20000 AI_TRAINER_CARD_PHASE_13, POKEMON_FLUTE,          AIDecide_PokemonFlute,                   AIPlay_PokemonFlute +	unknown_data_20000 AI_TRAINER_CARD_PHASE_05, CLEFAIRY_DOLL,          AIDecide_ClefairyDollOrMysteriousFossil, AIPlay_ClefairyDollOrMysteriousFossil +	unknown_data_20000 AI_TRAINER_CARD_PHASE_05, MYSTERIOUS_FOSSIL,      AIDecide_ClefairyDollOrMysteriousFossil, AIPlay_ClefairyDollOrMysteriousFossil +	unknown_data_20000 AI_TRAINER_CARD_PHASE_02, POKE_BALL,              AIDecide_Pokeball,                       AIPlay_Pokeball +	unknown_data_20000 AI_TRAINER_CARD_PHASE_02, COMPUTER_SEARCH,        AIDecide_ComputerSearch,                 AIPlay_ComputerSearch +	unknown_data_20000 AI_TRAINER_CARD_PHASE_02, POKEMON_TRADER,         AIDecide_PokemonTrader,                  AIPlay_PokemonTrader  	db $ff -Func_200e5: ; 200e5 (8:40e5) +_AIProcessHandTrainerCards: ; 200e5 (8:40e5)  	ld [wce18], a  ; create hand list in wDuelTempList and wTempHandCardList.  	call CreateHandCardList @@ -57,7 +57,7 @@ Func_200e5: ; 200e5 (8:40e5)  .loop_hand  	ld a, [hli] -	ld [wce16], a +	ld [wAITrainerCardToPlay], a  	cp $ff  	ret z @@ -67,7 +67,7 @@ Func_200e5: ; 200e5 (8:40e5)  	ld hl, Data_20000  .loop_data  	xor a -	ld [wce21], a +	ld [wCurrentAIFlags], a  	ld a, [hli]  	cp $ff  	jp z, .pop_hl @@ -75,16 +75,18 @@ Func_200e5: ; 200e5 (8:40e5)  ; compare input to first byte in data and continue if equal.  	cp d  	jp nz, .inc_hl_by_5 +  	ld a, [hli]  	ld [wce17], a -	ld a, [wce16] +	ld a, [wAITrainerCardToPlay]  	call LoadCardDataToBuffer1_FromDeckIndex +  	cp SWITCH  	jr nz, .skip_switch_check  	ld b, a -	ld a, [wce20] -	and $02 +	ld a, [wPreviousAIFlags] +	and AI_FLAG_USED_SWITCH  	jr nz, .inc_hl_by_4  	ld a, b @@ -95,61 +97,79 @@ Func_200e5: ; 200e5 (8:40e5)  	cp b  	jr nz, .inc_hl_by_4 +; found Trainer card  	push hl  	push de -	ld a, [wce16] +	ld a, [wAITrainerCardToPlay]  	ldh [hTempCardIndex_ff9f], a + +; if Headache effects prevent playing card +; move on to the next item in list.  	bank1call CheckCantUseTrainerDueToHeadache  	jp c, .next_in_data +  	call LoadNonPokemonCardEffectCommands  	ld a, EFFECTCMDTYPE_INITIAL_EFFECT_1  	call TryExecuteEffectCommandFunction  	jp c, .next_in_data -	farcall Func_1743b + +; AI can randomly choose not to play card. +	farcall ChooseRandomlyNotToPlayTrainerCard  	jr c, .next_in_data + +; call routine to decide whether to play Trainer card  	pop de  	pop hl  	push hl  	call CallIndirect  	pop hl  	jr nc, .inc_hl_by_4 + +; routine returned carry, which means +; this card should be played.  	inc hl  	inc hl -	ld [wce19], a +	ld [wAITrainerCardParameter], a +; show Play Trainer Card screen  	push de  	push hl -	ld a, [wce16] +	ld a, [wAITrainerCardToPlay]  	ldh [hTempCardIndex_ff9f], a  	ld a, OPPACTION_PLAY_TRAINER  	bank1call AIMakeDecision  	pop hl  	pop de  	jr c, .inc_hl_by_2 + +; execute the effects of the Trainer card  	push hl  	call CallIndirect  	pop hl  	inc hl  	inc hl -	ld a, [wce20] +	ld a, [wPreviousAIFlags]  	ld b, a -	ld a, [wce21] +	ld a, [wCurrentAIFlags]  	or b -	ld [wce20], a +	ld [wPreviousAIFlags], a  	pop hl -	and $08 +	and AI_FLAG_MODIFIED_HAND  	jp z, .loop_hand -.asm_20186 ; 20186 (8:4186) +; the hand was modified during the Trainer effect +; so it needs to be re-listed again and +; looped from the top.  	call CreateHandCardList  	ld hl, wDuelTempList  	ld de, wTempHandCardList  	call CopyBuffer  	ld hl, wTempHandCardList -	ld a, [wce20] -	and $f7 -	ld [wce20], a +; clear the AI_FLAG_MODIFIED_HAND flag +	ld a, [wPreviousAIFlags] +	and ~AI_FLAG_MODIFIED_HAND +	ld [wPreviousAIFlags], a  	jp .loop_hand  .inc_hl_by_5 @@ -177,10 +197,10 @@ Func_200e5: ; 200e5 (8:40e5)  ; 0x201b5  ; makes AI use Potion card. -AIPlayPotion: ; 201b5 (8:41b5) -	ld a, [wce16] +AIPlay_Potion: ; 201b5 (8:41b5) +	ld a, [wAITrainerCardToPlay]  	ldh [hTempCardIndex_ff9f], a -	ld a, [wce19] +	ld a, [wAITrainerCardParameter]  	ldh [hTemp_ffa0], a  	ld e, a  	call GetCardDamage @@ -199,7 +219,7 @@ AIPlayPotion: ; 201b5 (8:41b5)  ; next turn after using Potion.  ; if it cannot, return carry.  ; also take into account whether move is high recoil. -CheckIfPotionPreventsKnockOut: ; 201d1 (8:41d1) +AIDecide_Potion1: ; 201d1 (8:41d1)  	farcall AIDecideWhetherToRetreat  	jr c, .no_carry  	call Func_22bad @@ -242,7 +262,7 @@ CheckIfPotionPreventsKnockOut: ; 201d1 (8:41d1)  ; output:  ;	a = card to use Potion on;  ;	carry set if Potion should be used. -FindTargetCardForPotion: ; 20204 (8:4204) +AIDecide_Potion2: ; 20204 (8:4204)  	xor a  	ldh [hTempPlayAreaLocation_ff9d], a  	farcall CheckIfDefendingPokemonCanKnockOut @@ -342,16 +362,16 @@ FindTargetCardForPotion: ; 20204 (8:4204)  ; and have the BOOST_IF_TAKEN_DAMAGE effect.  .check_boost_if_taken_damage ; 2027e (8:427e)  	push de -	xor a ; first attack -	ld [wSelectedMoveIndex], a +	xor a ; FIRST_ATTACK_OR_PKMN_POWER +	ld [wSelectedAttack], a  	farcall CheckIfSelectedMoveIsUnusable  	jr c, .second_attack  	ld a, MOVE_FLAG3_ADDRESS | BOOST_IF_TAKEN_DAMAGE_F  	call CheckLoadedMoveFlag  	jr c, .set_carry  .second_attack -	ld a, $01 ; second attack -	ld [wSelectedMoveIndex], a +	ld a, SECOND_ATTACK +	ld [wSelectedAttack], a  	farcall CheckIfSelectedMoveIsUnusable  	jr c, .false  	ld a, MOVE_FLAG3_ADDRESS | BOOST_IF_TAKEN_DAMAGE_F @@ -368,14 +388,14 @@ FindTargetCardForPotion: ; 20204 (8:4204)  ; 0x202a8  ; makes AI use Super Potion card. -AIPlaySuperPotion: ; 202a8 (8:42a8) -	ld a, [wce16] +AIPlay_SuperPotion: ; 202a8 (8:42a8) +	ld a, [wAITrainerCardToPlay]  	ldh [hTempCardIndex_ff9f], a -	ld a, [wce19] +	ld a, [wAITrainerCardParameter]  	ldh [hTempPlayAreaLocation_ffa1], a -	call GetEnergyCardToDiscard +	call AIPickEnergyCardToDiscard  	ldh [hTemp_ffa0], a -	ld a, [wce19] +	ld a, [wAITrainerCardParameter]  	ld e, a  	call GetCardDamage  	cp 40 @@ -393,7 +413,7 @@ AIPlaySuperPotion: ; 202a8 (8:42a8)  ; active card next turn after using Super Potion.  ; if it cannot, return carry.  ; also take into account whether move is high recoil. -CheckIfSuperPotionPreventsKnockOut: ; 202cc (8:42cc) +AIDecide_SuperPotion1: ; 202cc (8:42cc)  	farcall AIDecideWhetherToRetreat  	jr c, .no_carry  	call Func_22bad @@ -411,7 +431,7 @@ CheckIfSuperPotionPreventsKnockOut: ; 202cc (8:42cc)  	ld a, DUELVARS_ARENA_CARD_HP  	call GetTurnDuelistVariable  	ld h, a -	ld e, $00 +	ld e, PLAY_AREA_ARENA  	call GetCardDamage  	cp 40 + 1 ; if damage < 40  	jr c, .calculate_hp @@ -447,7 +467,7 @@ CheckIfSuperPotionPreventsKnockOut: ; 202cc (8:42cc)  ; output:  ;	a = card to use Super Potion on;  ;	carry set if Super Potion should be used. -FindTargetCardForSuperPotion: ; 2030f (8:430f) +AIDecide_SuperPotion2: ; 2030f (8:430f)  	xor a  	ldh [hTempPlayAreaLocation_ff9d], a  	farcall CheckIfDefendingPokemonCanKnockOut @@ -457,7 +477,7 @@ FindTargetCardForSuperPotion: ; 2030f (8:430f)  	ld a, DUELVARS_ARENA_CARD_HP  	call GetTurnDuelistVariable  	ld h, a -	ld e, $00 +	ld e, PLAY_AREA_ARENA  	call GetCardDamage  	cp 40 + 1 ; if damage < 40  	jr c, .calculate_hp @@ -564,16 +584,16 @@ FindTargetCardForSuperPotion: ; 2030f (8:430f)  ; and have the BOOST_IF_TAKEN_DAMAGE effect.  .check_boost_if_taken_damage ; 2039e (8:439e)  	push de -	xor a ; first attack -	ld [wSelectedMoveIndex], a +	xor a ; FIRST_ATTACK_OR_PKMN_POWER +	ld [wSelectedAttack], a  	farcall CheckIfSelectedMoveIsUnusable  	jr c, .second_attack_1  	ld a, MOVE_FLAG3_ADDRESS | BOOST_IF_TAKEN_DAMAGE_F  	call CheckLoadedMoveFlag  	jr c, .true_1  .second_attack_1 -	ld a, $01 ; second attack -	ld [wSelectedMoveIndex], a +	ld a, SECOND_ATTACK +	ld [wSelectedAttack], a  	farcall CheckIfSelectedMoveIsUnusable  	jr c, .false_1  	ld a, MOVE_FLAG3_ADDRESS | BOOST_IF_TAKEN_DAMAGE_F @@ -593,8 +613,8 @@ FindTargetCardForSuperPotion: ; 2030f (8:430f)  ; given that they have enough energy to be used before discarding.  .check_energy_cost ; 203c8 (8:43c8)  	push de -	xor a ; first attack -	ld [wSelectedMoveIndex], a +	xor a ; FIRST_ATTACK_OR_PKMN_POWER +	ld [wSelectedAttack], a  	ld a, e  	ldh [hTempPlayAreaLocation_ff9d], a  	farcall CheckEnergyNeededForAttack @@ -605,8 +625,8 @@ FindTargetCardForSuperPotion: ; 2030f (8:430f)  .second_attack_2  	pop de  	push de -	ld a, $01 ; second attack -	ld [wSelectedMoveIndex], a +	ld a, SECOND_ATTACK +	ld [wSelectedAttack], a  	ld a, e  	ldh [hTempPlayAreaLocation_ff9d], a  	farcall CheckEnergyNeededForAttack @@ -624,8 +644,8 @@ FindTargetCardForSuperPotion: ; 2030f (8:430f)  	ret  ; 0x203f8 -AIPlayDefender: ; 203f8 (8:43f8) -	ld a, [wce16] +AIPlay_Defender: ; 203f8 (8:43f8) +	ld a, [wAITrainerCardToPlay]  	ldh [hTempCardIndex_ff9f], a  	xor a  	ldh [hTemp_ffa0], a @@ -637,17 +657,17 @@ AIPlayDefender: ; 203f8 (8:43f8)  ; returns carry if using Defender can prevent a KO  ; by the defending Pokémon.  ; this takes into account both attacks and whether they're useable. -CheckIfDefenderPreventsKnockOut: ; 20406 (8:4406) -	xor a +AIDecide_Defender1: ; 20406 (8:4406) +	xor a ; PLAY_AREA_ARENA  	ldh [hTempPlayAreaLocation_ff9d], a  	farcall CheckIfAnyMoveKnocksOutDefendingCard -	jr nc, .asm_2041b +	jr nc, .cannot_ko  	farcall CheckIfSelectedMoveIsUnusable  	jr nc, .no_carry  	farcall LookForEnergyNeededForMoveInHand  	jr c, .no_carry -.asm_2041b +.cannot_ko  ; check if any of the defending Pokémon's attacks deal  ; damage exactly equal to current HP, and if so,  ; only continue if that move is useable. @@ -658,7 +678,7 @@ CheckIfDefenderPreventsKnockOut: ; 20406 (8:4406)  	call SwapTurn  	jr c, .no_carry -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	farcall EstimateDamage_FromDefendingPokemon  	ld a, [wDamage]  	ld [wce06], a @@ -666,11 +686,11 @@ CheckIfDefenderPreventsKnockOut: ; 20406 (8:4406)  ; load in a the attack that was not selected,  ; and check if it is useable. -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	ld b, a  	ld a, $01  	sub b -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	push de  	call SwapTurn  	farcall CheckIfSelectedMoveIsUnusable @@ -680,7 +700,7 @@ CheckIfDefenderPreventsKnockOut: ; 20406 (8:4406)  ; the other attack is useable.  ; compare its damage to the selected move. -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	push de  	farcall EstimateDamage_FromDefendingPokemon  	pop de @@ -692,11 +712,11 @@ CheckIfDefenderPreventsKnockOut: ; 20406 (8:4406)  ; and deals less damage than the selected move,  ; switch back to the other attack.  .switch_back -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	ld b, a  	ld a, $01  	sub b -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	ld a, [wce06]  	ld [wDamage], a @@ -722,7 +742,7 @@ CheckIfDefenderPreventsKnockOut: ; 20406 (8:4406)  ; return carry if using Defender prevents Pokémon  ; from being knocked out by an attack with recoil. -CheckIfDefenderPreventsRecoilKnockOut: ; 20486 (8:4486) +AIDecide_Defender2: ; 20486 (8:4486)  	ld a, MOVE_FLAG1_ADDRESS | HIGH_RECOIL_F  	call CheckLoadedMoveFlag  	jr c, .recoil @@ -736,14 +756,14 @@ CheckIfDefenderPreventsRecoilKnockOut: ; 20486 (8:4486)  	ld a, DUELVARS_ARENA_CARD  	call GetTurnDuelistVariable  	call LoadCardDataToBuffer2_FromDeckIndex -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	or a  	jr nz, .second_attack  ; first attack -	ld a, [wLoadedCard2Move1Unknown1] +	ld a, [wLoadedCard2Move1EffectParam]  	jr .check_weak  .second_attack -	ld a, [wLoadedCard2Move2Unknown1] +	ld a, [wLoadedCard2Move2EffectParam]  ; double recoil damage if card is weak to its own color.  .check_weak @@ -795,20 +815,23 @@ CheckIfDefenderPreventsRecoilKnockOut: ; 20486 (8:4486)  	ret  ; 0x204e8 -AIPlayPluspower: ; 204e8 (8:44e8) -	ld a, [wce21] -	or $01 -	ld [wce21], a -	ld a, [wce19] -	ld [wcdd6], a -	ld a, [wce16] +AIPlay_Pluspower: ; 204e8 (8:44e8) +	ld a, [wCurrentAIFlags] +	or AI_FLAG_USED_PLUSPOWER +	ld [wCurrentAIFlags], a +	ld a, [wAITrainerCardParameter] +	ld [wAIPluspowerAttack], a +	ld a, [wAITrainerCardToPlay]  	ldh [hTempCardIndex_ff9f], a  	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS  	bank1call AIMakeDecision  	ret  ; 0x20501 -Func_20501: ; 20501 (8:4501) +; returns carry if using a Pluspower can KO defending Pokémon +; if active card cannot KO without the boost. +; outputs in a the attack to use. +AIDecide_Pluspower1: ; 20501 (8:4501)  ; this is mistakenly duplicated  	xor a  	ldh [hTempPlayAreaLocation_ff9d], a @@ -848,36 +871,44 @@ Func_20501: ; 20501 (8:4501)  	call SwapTurn  	jr c, .no_carry -	xor a ; first attack -	ld [wSelectedMoveIndex], a -	call .asm_20562 -	jr c, .asm_20551 -	ld a, $01 ; second attack -	ld [wSelectedMoveIndex], a -	call .asm_20562 -	jr c, .asm_20559 +; check both attacks and decide which one +; can KO with Pluspower boost. +; if neither can KO, return no carry. +	xor a ; FIRST_ATTACK_OR_PKMN_POWER +	ld [wSelectedAttack], a +	call .check_ko_with_pluspower +	jr c, .kos_with_pluspower_1 +	ld a, SECOND_ATTACK +	ld [wSelectedAttack], a +	call .check_ko_with_pluspower +	jr c, .kos_with_pluspower_2  .no_carry  	or a  	ret -.asm_20551 -	call .asm_20589 + +; first attack can KO with Pluspower. +.kos_with_pluspower_1 +	call .check_mr_mime  	jr nc, .no_carry -	xor a ; first attack +	xor a ; FIRST_ATTACK_OR_PKMN_POWER  	scf  	ret -.asm_20559 -	call .asm_20589 +; second attack can KO with Pluspower. +.kos_with_pluspower_2 +	call .check_mr_mime  	jr nc, .no_carry -	ld a, $01 ; first attack +	ld a, SECOND_ATTACK  	scf  	ret  ; 0x20562 -.asm_20562 ; 20562 (8:4562) +; return carry if move is useable and KOs +; defending Pokémon with Pluspower boost. +.check_ko_with_pluspower ; 20562 (8:4562)  	farcall CheckIfSelectedMoveIsUnusable  	jr c, .unusable -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	farcall EstimateDamage_VersusDefendingCard  	ld a, DUELVARS_ARENA_CARD_HP  	call GetNonTurnDuelistVariable @@ -887,23 +918,25 @@ Func_20501: ; 20501 (8:4501)  	jr c, .no_carry  	jr z, .no_carry  	ld a, [hl] -	add 10 +	add 10 ; add Pluspower boost  	ld c, a  	ld a, b  	sub c -	ret c -	ret nz +	ret c ; return carry if damage > HP left +	ret nz ; does not KO  	scf -	ret +	ret ; KOs with Pluspower boost  .unusable  	or a  	ret  ; 0x20589 -.asm_20589 ; 20589 (8:4589) +; returns carry if Pluspower boost does +; not exceed 30 damage when facing Mr. Mime. +.check_mr_mime ; 20589 (8:4589)  	ld a, [wDamage] -	add 10 -	cp 30 +	add 10 ; add Pluspower boost +	cp 30 ; no danger in preventing damage  	ret c  	call SwapTurn  	ld a, DUELVARS_ARENA_CARD @@ -911,41 +944,5359 @@ Func_20501: ; 20501 (8:4501)  	call GetCardIDFromDeckIndex  	call SwapTurn  	ld a, e -	cp $9b +	cp MR_MIME  	ret z +; damage is >= 30 but not Mr. Mime  	scf  	ret  ; 0x205a5 -Func_205a5: ; 205a5 (8:45a5) +; returns carry 7/10 of the time +; if selected move is useable, can't KO without Pluspower boost +; can damage Mr. Mime even with Pluspower boost +; and has a minimum damage > 0. +; outputs in a the attack to use. +AIDecide_Pluspower2: ; 205a5 (8:45a5)  	xor a  	ldh [hTempPlayAreaLocation_ff9d], a -	call Func_205d7 -	jr nc, .asm_205b9 -	call Func_205f6 -	jr nc, .asm_205b9 -	call Func_205bb -	jr nc, .asm_205b9 +	call .check_can_ko +	jr nc, .no_carry +	call .check_random +	jr nc, .no_carry +	call .check_mr_mime +	jr nc, .no_carry  	scf  	ret -.asm_205b9 +.no_carry  	or a  	ret  ; 0x205bb -Func_205bb: ; 205bb (8:45bb) -	INCROM $205bb, $205d7 +; returns carry if Pluspower boost does +; not exceed 30 damage when facing Mr. Mime. +.check_mr_mime ; 205bb (8:45bb) +	ld a, [wDamage] +	add 10 ; add Pluspower boost +	cp 30 ; no danger in preventing damage +	ret c +	call SwapTurn +	ld a, DUELVARS_ARENA_CARD +	call GetTurnDuelistVariable +	call GetCardIDFromDeckIndex +	call SwapTurn +	ld a, e +	cp MR_MIME +	ret z +; damage is >= 30 but not Mr. Mime +	scf +	ret +; 0x205d7 + +; return carry if move is useable but cannot KO. +.check_can_ko ; 205d7 (8:45d7) +	farcall CheckIfSelectedMoveIsUnusable +	jr c, .unuseable +	ld a, [wSelectedAttack] +	farcall EstimateDamage_VersusDefendingCard +	ld a, DUELVARS_ARENA_CARD_HP +	call GetNonTurnDuelistVariable +	ld b, a +	ld hl, wDamage +	sub [hl] +	jr c, .no_carry +	jr z, .no_carry +; can't KO. +	scf +	ret +.unuseable +	or a +	ret +; 0x205f6 + +; return carry 7/10 of the time if +; move is useable and minimum damage > 0. +.check_random ; 205f6 (8:45f6) +	farcall CheckIfSelectedMoveIsUnusable +	jr c, .unuseable +	ld a, [wSelectedAttack] +	farcall EstimateDamage_VersusDefendingCard +	ld a, [wAIMinDamage] +	cp 10 +	jr c, .unuseable +	ld a, 10 +	call Random +	cp 3 +	ret +; 0x20612 + +AIPlay_Switch: ; 20612 (8:4612) +	ld a, [wCurrentAIFlags] +	or AI_FLAG_USED_SWITCH +	ld [wCurrentAIFlags], a +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, [wAITrainerCardParameter] +	ldh [hTemp_ffa0], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	xor a +	ld [wcdb4], a +	ret +; 0x2062e + +; returns carry if the active card has less energy cards +; than the retreat cost and if AI can't play an energy +; card from the hand to fulfill the cost +AIDecide_Switch: ; 2062e (8:462e) +; check if AI can already play an energy card from hand to retreat +	ld a, [wAIPlayEnergyCardForRetreat] +	or a +	jr z, .check_cost_amount + +; can't play energy card from hand to retreat +; compare number of energy cards attached to retreat cost +	xor a ; PLAY_AREA_ARENA +	ldh [hTempPlayAreaLocation_ff9d], a +	call GetPlayAreaCardRetreatCost +	push af +	ld e, PLAY_AREA_ARENA +	farcall CountNumberOfEnergyCardsAttached +	ld b, a +	pop af +	sub b +	; jump if cards attached > retreat cost +	jr c, .check_cost_amount +	cp 2 +	; jump if retreat cost is 2 more energy cards +	; than the number of cards attached +	jr nc, .switch + +.check_cost_amount +	xor a ; PLAY_AREA_ARENA +	ldh [hTempPlayAreaLocation_ff9d], a +	call GetPlayAreaCardRetreatCost +	cp 3 +	; jump if retreat cost >= 3 +	jr nc, .switch + +	push af +	ld e, PLAY_AREA_ARENA +	farcall CountNumberOfEnergyCardsAttached +	pop bc +	cp b +	; jump if energy cards attached < retreat cost +	jr c, .switch +	ret + +.switch +	farcall AIDecideBenchPokemonToSwitchTo +	ccf +	ret +; 0x20666 + +AIPlay_GustOfWind: ; 20666 (8:4666) +	ld a, [wCurrentAIFlags] +	or AI_FLAG_USED_GUST_OF_WIND +	ld [wCurrentAIFlags], a +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, [wAITrainerCardParameter] +	ldh [hTemp_ffa0], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x2067e + +AIDecide_GustOfWind: ; 2067e (8:467e) +	ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA +	call GetNonTurnDuelistVariable +	dec a +	or a +	ret z ; no bench cards + +; if used Gust Of Wind already, +; do not use it again. +	ld a, [wPreviousAIFlags] +	and AI_FLAG_USED_GUST_OF_WIND +	ret nz + +	farcall CheckIfActivePokemonCanUseAnyNonResidualMove +	ret nc ; no non-residual move can be used + +	xor a ; PLAY_AREA_ARENA +	ldh [hTempPlayAreaLocation_ff9d], a +	farcall CheckIfAnyMoveKnocksOutDefendingCard +	jr nc, .check_id ; if can't KO +	farcall CheckIfSelectedMoveIsUnusable +	jr nc, .no_carry ; if KO move is useable +	farcall LookForEnergyNeededForMoveInHand +	jr c, .no_carry ; if energy card is in hand + +.check_id +	; skip if current active card is MEW3 or MEWTWO1 +	ld a, DUELVARS_ARENA_CARD +	call GetTurnDuelistVariable +	call GetCardIDFromDeckIndex +	ld a, e +	cp MEW3 +	jr z, .no_carry +	cp MEWTWO1 +	jr z, .no_carry + +	call .FindBenchCardToKnockOut +	ret c + +	xor a ; PLAY_AREA_ARENA +	ldh [hTempPlayAreaLocation_ff9d], a +	call .CheckIfNoAttackDealsDamage +	jr c, .check_bench_energy + +	; skip if current arena card's color is +	; the defending card's weakness +	call GetArenaCardColor +	call TranslateColorToWR +	ld b, a +	call SwapTurn +	call GetArenaCardWeakness +	call SwapTurn +	and b +	jr nz, .no_carry + +; check weakness +	call .FindBenchCardWithWeakness +	ret nc ; no bench card weak to arena card +	scf +	ret ; found bench card weak to arena card + +.no_carry +	or a +	ret + +; being here means AI's arena card cannot damage player's arena card + +; first check if there is a card in player's bench that +; has no attached energy cards and that the AI can damage +.check_bench_energy +	; return carry if there's a bench card with weakness +	call .FindBenchCardWithWeakness +	ret c + +	ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA +	call GetNonTurnDuelistVariable +	ld d, a +	ld e, PLAY_AREA_ARENA +; loop through bench and check attached energy cards +.loop_1 +	inc e +	dec d +	jr z, .check_bench_hp +	call SwapTurn +	call GetPlayAreaCardAttachedEnergies +	call SwapTurn +	ld a, [wTotalAttachedEnergies] +	or a +	jr nz, .loop_1 ; skip if has energy attached +	call .CheckIfCanDamageBenchedCard +	jr nc, .loop_1 +	ld a, e +	scf +	ret + +.check_bench_hp +	ld a, $ff +	ld [wce06], a +	xor a +	ld [wce08], a +	ld e, a +	ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA +	call GetNonTurnDuelistVariable +	ld d, a + +; find bench card with least amount of available HP +.loop_2 +	inc e +	dec d +	jr z, .check_found +	ld a, e +	add DUELVARS_ARENA_CARD_HP +	call GetNonTurnDuelistVariable +	ld b, a +	ld a, [wce06] +	inc b +	cp b +	jr c, .loop_2 +	call .CheckIfCanDamageBenchedCard +	jr nc, .loop_2 +	dec b +	ld a, b +	ld [wce06], a +	ld a, e +	ld [wce08], a +	jr .loop_2 + +.check_found +	ld a, [wce08] +	or a +	jr z, .no_carry +; a card was found + +.set_carry +	scf +	ret + +.check_can_damage +	push bc +	push hl +	xor a ; PLAY_AREA_ARENA +	farcall CheckIfCanDamageDefendingPokemon +	pop hl +	pop bc +	jr nc, .loop_3 +	ld a, c +	scf +	ret + +; returns carry if any of the player's +; benched cards is weak to color in b +; and has a way to damage it +.FindBenchCardWithWeakness ; 2074d (8:474d) +	ld a, DUELVARS_BENCH +	call GetNonTurnDuelistVariable +	ld c, PLAY_AREA_ARENA +.loop_3 +	inc c +	ld a, [hli] +	cp $ff +	jr z, .no_carry +	call SwapTurn +	call LoadCardDataToBuffer1_FromDeckIndex +	call SwapTurn +	ld a, [wLoadedCard1Weakness] +	and b +	jr nz, .check_can_damage +	jr .loop_3 + +; returns carry if neither attack can deal damage +.CheckIfNoAttackDealsDamage ; 2076b (8:476b) +	xor a ; FIRST_ATTACK_OR_PKMN_POWER +	ld [wSelectedAttack], a +	call .CheckIfAttackDealsNoDamage +	jr c, .second_attack +	ret +.second_attack +	ld a, SECOND_ATTACK +	ld [wSelectedAttack], a +	call .CheckIfAttackDealsNoDamage +	jr c, .true +	ret +.true +	scf +	ret + +; returns carry if attack is Pokemon Power +; or otherwise doesn't deal any damage +.CheckIfAttackDealsNoDamage ; 20782 (8:4782) +	ld a, [wSelectedAttack] +	ld e, a +	ld a, DUELVARS_ARENA_CARD +	call GetTurnDuelistVariable +	ld d, a +	call CopyMoveDataAndDamage_FromDeckIndex +	ld a, [wLoadedMoveCategory] + +	; skip if move is a Power or has 0 damage +	cp POKEMON_POWER +	jr z, .no_damage +	ld a, [wDamage] +	or a +	ret z + +	; check damage against defending card +	ld a, [wSelectedAttack] +	farcall EstimateDamage_VersusDefendingCard +	ld a, [wAIMaxDamage] +	or a +	ret nz + +.no_damage +	scf +	ret + +; returns carry if there is a player's bench card that +; the opponent's current active card can KO +.FindBenchCardToKnockOut ; 207a9 (8:47a9) +	ld a, DUELVARS_BENCH +	call GetNonTurnDuelistVariable +	ld e, PLAY_AREA_BENCH_1 + +.loop_4 +	ld a, [hli] +	cp $ff +	ret z + +; overwrite the player's active card and its HP +; with the current bench card that is being checked +	push hl +	push de +	ld b, a +	ld a, DUELVARS_ARENA_CARD +	call GetNonTurnDuelistVariable +	push af +	ld [hl], b +	ld a, e +	add DUELVARS_ARENA_CARD_HP +	call GetNonTurnDuelistVariable +	ld b, a +	ld a, DUELVARS_ARENA_CARD_HP +	call GetNonTurnDuelistVariable +	push af +	ld [hl], b + +	xor a ; PLAY_AREA_ARENA +	ldh [hTempPlayAreaLocation_ff9d], a +	call .CheckIfAnyAttackKnocksOut +	jr nc, .next +	farcall CheckIfSelectedMoveIsUnusable +	jr nc, .found +	farcall LookForEnergyNeededForMoveInHand +	jr c, .found + +; the following two local routines can be condensed into one +; since they both revert the player's arena card +.next +	ld a, DUELVARS_ARENA_CARD_HP +	call GetNonTurnDuelistVariable +	pop af +	ld [hl], a +	ld a, DUELVARS_ARENA_CARD +	call GetNonTurnDuelistVariable +	pop af +	ld [hl], a +	pop de +	inc e +	pop hl +	jr .loop_4 + +; revert player's arena card and set carry +.found +	ld a, DUELVARS_ARENA_CARD_HP +	call GetNonTurnDuelistVariable +	pop af +	ld [hl], a +	ld a, DUELVARS_ARENA_CARD +	call GetNonTurnDuelistVariable +	pop af +	ld [hl], a +	pop de +	ld a, e +	pop hl +	scf +	ret + +; returns carry if any of arena card's attacks +; KOs player card in location stored in e +.CheckIfAnyAttackKnocksOut ; 20806 (8:4806) +	xor a ; FIRST_ATTACK_OR_PKMN_POWER +	call .CheckIfAttackKnocksOut +	ret c +	ld a, SECOND_ATTACK + +; returns carry if attack KOs player card +; in location stored in e +.CheckIfAttackKnocksOut +	push de +	farcall EstimateDamage_VersusDefendingCard +	pop de +	ld a, DUELVARS_ARENA_CARD_HP +	add e +	call GetNonTurnDuelistVariable +	ld hl, wDamage +	sub [hl] +	ret c +	ret nz +	scf +	ret + +; returns carry if opponent's arena card can damage +; this benched card if it were switched with +; the player's arena card +.CheckIfCanDamageBenchedCard ; 20821 (8:4821) +	push bc +	push de +	push hl + +	; overwrite arena card data +	ld a, e +	add DUELVARS_ARENA_CARD +	call GetNonTurnDuelistVariable +	ld b, a +	ld a, DUELVARS_ARENA_CARD +	call GetNonTurnDuelistVariable +	push af +	ld [hl], b + +	; overwrite arena card HP +	ld a, e +	add DUELVARS_ARENA_CARD_HP +	call GetNonTurnDuelistVariable +	ld b, a +	ld a, DUELVARS_ARENA_CARD_HP +	call GetNonTurnDuelistVariable +	push af +	ld [hl], b + +	xor a ; PLAY_AREA_ARENA +	farcall CheckIfCanDamageDefendingPokemon +	jr c, .can_damage + +; the following two local routines can be condensed into one +; since they both revert the player's arena card + +; can't damage +	ld a, DUELVARS_ARENA_CARD_HP +	call GetNonTurnDuelistVariable +	pop af +	ld [hl], a +	ld a, DUELVARS_ARENA_CARD +	call GetNonTurnDuelistVariable +	pop af +	ld [hl], a +	pop hl +	pop de +	pop bc +	or a +	ret + +.can_damage +	ld a, DUELVARS_ARENA_CARD_HP +	call GetNonTurnDuelistVariable +	pop af +	ld [hl], a +	ld a, DUELVARS_ARENA_CARD +	call GetNonTurnDuelistVariable +	pop af +	ld [hl], a +	pop hl +	pop de +	pop bc +	scf +	ret +; 0x2086d + +AIPlay_Bill: ; 2086d (8:486d) +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x20878 + +; return carry if cards in deck > 9 +AIDecide_Bill: ; 20878 (8:4878) +	ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK +	call GetTurnDuelistVariable +	cp DECK_SIZE - 9 +	ret +; 0x20880 + +AIPlay_EnergyRemoval: ; 20880 (8:4880) +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, [wAITrainerCardParameter] +	ldh [hTemp_ffa0], a +	ld a, [wce1a] +	ldh [hTempPlayAreaLocation_ffa1], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x20895 + +; picks an energy card in the player's Play Area to remove +AIDecide_EnergyRemoval: ; 20895 (8:4895) +; check if the current active card can KO player's card +; if it's possible to KO, then do not consider the player's +; active card to remove its attached energy +	xor a ; PLAY_AREA_ARENA +	ldh [hTempPlayAreaLocation_ff9d], a +	farcall CheckIfAnyMoveKnocksOutDefendingCard +	jr nc, .cannot_ko +	farcall CheckIfSelectedMoveIsUnusable +	jr nc, .can_ko +	farcall LookForEnergyNeededForMoveInHand +	jr nc, .cannot_ko + +.can_ko +	; start checking from the bench +	ld a, PLAY_AREA_BENCH_1 +	ld [wce0f], a +	jr .check_bench_energy +.cannot_ko +	; start checking from the arena card +	xor a ; PLAY_AREA_ARENA +	ld [wce0f], a + +; loop each card and check if it has enough energy to use any attack +; if it does, then proceed to pick an energy card to remove +.check_bench_energy +	call SwapTurn +	ld a, [wce0f] +	ld e, a +.loop_1 +	ld a, DUELVARS_ARENA_CARD +	add e +	call GetTurnDuelistVariable +	cp $ff +	jr z, .default + +	ld d, a +	call .CheckIfCardHasEnergyAttached +	jr nc, .next_1 +	call .CheckIfNotEnoughEnergyToAttack +	jr nc, .pick_energy ; jump if enough energy to attack +.next_1 +	inc e +	jr .loop_1 + +.pick_energy +; a play area card was picked to remove energy +; store the picked energy card to remove in wce1a +; and set carry +	ld a, e +	push af +	call PickAttachedEnergyCardToRemove +	ld [wce1a], a +	pop af +	call SwapTurn +	scf +	ret + +; if no card in player's Play Area was found with enough energy +; to attack, just pick an energy card from player's active card +; (in case the AI cannot KO it this turn) +.default +	ld a, [wce0f] +	or a +	jr nz, .check_bench_damage ; not active card +	call .CheckIfCardHasEnergyAttached +	jr c, .pick_energy + +; lastly, check what attack on player's Play Area is highest damaging +; and pick an energy card attached to that Pokemon to remove +.check_bench_damage +	xor a +	ld [wce06], a +	ld [wce08], a + +	ld e, PLAY_AREA_BENCH_1 +.loop_2 +	ld a, DUELVARS_ARENA_CARD +	add e +	call GetTurnDuelistVariable +	cp $ff +	jr z, .found_damage + +	ld d, a +	call .CheckIfCardHasEnergyAttached +	jr nc, .next_2 +	call .FindHighestDamagingAttack +.next_2 +	inc e +	jr .loop_2 + +.found_damage +	ld a, [wce08] +	or a +	jr z, .no_carry ; skip if none found +	ld e, a +	jr .pick_energy +.no_carry +	call SwapTurn +	or a +	ret + +; returns carry if this card has any energy cards attached +.CheckIfCardHasEnergyAttached ; 2091a (8:491a) +	call GetPlayAreaCardAttachedEnergies +	ld a, [wTotalAttachedEnergies] +	or a +	ret z +	scf +	ret + +; returns carry if this card does not +; have enough energy for either of its attacks +.CheckIfNotEnoughEnergyToAttack ; 20924 (8:4924) +	push de +	xor a ; FIRST_ATTACK_OR_PKMN_POWER +	ld [wSelectedAttack], a +	ld a, e +	ldh [hTempPlayAreaLocation_ff9d], a +	farcall CheckEnergyNeededForAttack +	jr nc, .enough_energy +	pop de + +	push de +	ld a, SECOND_ATTACK +	ld [wSelectedAttack], a +	ld a, e +	ldh [hTempPlayAreaLocation_ff9d], a +	farcall CheckEnergyNeededForAttack +	jr nc, .check_surplus +	pop de + +; neither attack has enough energy +	scf +	ret + +.enough_energy +	pop de +	or a +	ret + +; first attack doesn't have enough energy (or is just a Pokemon Power) +; but second attack has enough energy to be used +; check if there's surplus energy for attack and, if so, return carry +.check_surplus +	farcall CheckIfNoSurplusEnergyForMove +	pop de +	ccf +	ret + +; stores in wce06 the highest damaging attack +; for the card in play area location in e +; and stores this card's location in wce08 +.FindHighestDamagingAttack ; 2094f (8:494f) +	push de +	ld a, e +	ldh [hTempPlayAreaLocation_ff9d], a + +	xor a ; FIRST_ATTACK_OR_PKMN_POWER +	farcall EstimateDamage_VersusDefendingCard +	ld a, [wDamage] +	or a +	jr z, .skip_1 +	ld e, a +	ld a, [wce06] +	cp e +	jr nc, .skip_1 +	ld a, e +	ld [wce06], a ; store this damage value +	pop de +	ld a, e +	ld [wce08], a ; store this location +	jr .second_attack + +.skip_1 +	pop de + +.second_attack +	push de +	ld a, e +	ldh [hTempPlayAreaLocation_ff9d], a + +	ld a, SECOND_ATTACK +	farcall EstimateDamage_VersusDefendingCard +	ld a, [wDamage] +	or a +	jr z, .skip_2 +	ld e, a +	ld a, [wce06] +	cp e +	jr nc, .skip_2 +	ld a, e +	ld [wce06], a ; store this damage value +	pop de +	ld a, e +	ld [wce08], a ; store this location +	ret +.skip_2 +	pop de +	ret +; 0x20994 + +AIPlay_SuperEnergyRemoval: ; 20994 (8:4994) +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, [wAITrainerCardParameter] +	ldh [hTemp_ffa0], a +	ld a, [wce1a] +	ldh [hTempPlayAreaLocation_ffa1], a +	ld a, [wce1b] +	ldh [hTempRetreatCostCards], a +	ld a, [wce1c] +	ldh [hTempRetreatCostCards + 1], a +	ld a, [wce1d] +	ldh [hTempRetreatCostCards + 2], a +	ld a, $ff +	ldh [hTempRetreatCostCards + 3], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x209bc + +; picks two energy cards in the player's Play Area to remove +AIDecide_SuperEnergyRemoval: ; 209bc (8:49bc) +	ld e, PLAY_AREA_BENCH_1 +.loop_1 +; first find an Arena card with a color energy card +; to discard for card effect +; return immediately if no Arena cards +	ld a, DUELVARS_ARENA_CARD +	add e +	call GetTurnDuelistVariable +	cp $ff +	jr z, .exit +	 +	ld d, a +	push de +	call .LookForNonDoubleColorless +	pop de +	jr c, .not_double_colorless +	inc e +	jr .loop_1 + +; returns carry if an energy card other than double colorless +; is found attached to the card in play area location e +.LookForNonDoubleColorless +	ld a, e +	call CreateArenaOrBenchEnergyCardList +	ld hl, wDuelTempList +.loop_2 +	ld a, [hli] +	cp $ff +	ret z +	call LoadCardDataToBuffer1_FromDeckIndex +	cp DOUBLE_COLORLESS_ENERGY +	; any basic energy card +	; will set carry flag here +	jr nc, .loop_2 +	ret + +.exit +	or a +	ret + +; card in Play Area location e was found with +; a basic energy card +.not_double_colorless +	ld a, e +	ld [wce0f], a + +; check if the current active card can KO player's card +; if it's possible to KO, then do not consider the player's +; active card to remove its attached energy +	xor a ; PLAY_AREA_ARENA +	ldh [hTempPlayAreaLocation_ff9d], a +	farcall CheckIfAnyMoveKnocksOutDefendingCard +	jr nc, .cannot_ko +	farcall CheckIfSelectedMoveIsUnusable +	jr nc, .can_ko +	farcall LookForEnergyNeededForMoveInHand +	jr nc, .cannot_ko + +.can_ko +	; start checking from the bench +	call SwapTurn +	ld e, PLAY_AREA_BENCH_1 +	jr .loop_3 +.cannot_ko +	; start checking from the arena card +	call SwapTurn +	ld e, PLAY_AREA_ARENA + +; loop each card and check if it has enough energy to use any attack +; if it does, then proceed to pick energy cards to remove +.loop_3 +	ld a, DUELVARS_ARENA_CARD +	add e +	call GetTurnDuelistVariable +	cp $ff +	jr z, .no_carry + +	ld d, a +	call .CheckIfFewerThanTwoEnergyCards +	jr c, .next_1 +	call .CheckIfNotEnoughEnergyToAttack +	jr nc, .found_card ; jump if enough energy to attack +.next_1 +	inc e +	jr .loop_3 + +.found_card +; a play area card was picked to remove energy +; if this is not the Arena Card, then check +; entire bench to pick the highest damage +	ld a, e +	or a +	jr nz, .check_bench_damage + +; store the picked energy card to remove in wce1a +; and set carry +.pick_energy +	ld [wce1b], a +	call PickTwoAttachedEnergyCards +	ld [wce1c], a +	ld a, b +	ld [wce1d], a +	call SwapTurn +	ld a, [wce0f] +	push af +	call AIPickEnergyCardToDiscard +	ld [wce1a], a +	pop af +	scf +	ret + +; check what attack on player's Play Area is highest damaging +; and pick an energy card attached to that Pokemon to remove +.check_bench_damage +	xor a +	ld [wce06], a +	ld [wce08], a + +	ld e, PLAY_AREA_BENCH_1 +.loop_4 +	ld a, DUELVARS_ARENA_CARD +	add e +	call GetTurnDuelistVariable +	cp $ff +	jr z, .found_damage + +	ld d, a +	call .CheckIfFewerThanTwoEnergyCards +	jr c, .next_2 +	call .CheckIfNotEnoughEnergyToAttack +	jr c, .next_2 +	call .FindHighestDamagingAttack +.next_2 +	inc e +	jr .loop_4 + +.found_damage +	ld a, [wce08] +	or a +	jr z, .no_carry +	jr .pick_energy +.no_carry +	call SwapTurn +	or a +	ret + +; returns carry if the number of energy cards attached +; is fewer than 2, or if all energy combined yields +; fewer than 2 energy +.CheckIfFewerThanTwoEnergyCards ; 20a77 (8:4a77) +	call GetPlayAreaCardAttachedEnergies +	ld a, [wTotalAttachedEnergies] +	cp 2 +	ret c ; return if fewer than 2 attached cards + +; count all energy attached +; i.e. colored energy card = 1 +; and double colorless energy card = 2 +	xor a +	ld b, NUM_COLORED_TYPES +	ld hl, wAttachedEnergies +.loop_5 +	add [hl] +	inc hl +	dec b +	jr nz, .loop_5 +	ld b, [hl] +	srl b +	add b +	cp 2 +	ret + +; returns carry if this card does not +; have enough energy for either of its attacks +.CheckIfNotEnoughEnergyToAttack ; 20a92 (8:4a92) +	push de +	xor a ; FIRST_ATTACK_OR_PKMN_POWER +	ld [wSelectedAttack], a +	ld a, e +	ldh [hTempPlayAreaLocation_ff9d], a +	farcall CheckEnergyNeededForAttack +	jr nc, .enough_energy +	pop de + +	push de +	ld a, SECOND_ATTACK +	ld [wSelectedAttack], a +	ld a, e +	ldh [hTempPlayAreaLocation_ff9d], a +	farcall CheckEnergyNeededForAttack +	jr nc, .check_surplus +	pop de + +; neither attack has enough energy +	scf +	ret + +.enough_energy +	pop de +	or a +	ret + +; first attack doesn't have enough energy (or is just a Pokemon Power) +; but second attack has enough energy to be used +; check if there's surplus energy for attack and, if so, +; return carry if this surplus energy is at least 2 +.check_surplus +	farcall CheckIfNoSurplusEnergyForMove +	cp 2 +	jr c, .enough_energy +	pop de +	scf +	ret +; 0x20ac1 + +; stores in wce06 the highest damaging attack +; for the card in play area location in e +; and stores this card's location in wce08 +.FindHighestDamagingAttack ; 20ac1 (8:4ac1) +	push de +	ld a, e +	ldh [hTempPlayAreaLocation_ff9d], a + +	xor a ; FIRST_ATTACK_OR_PKMN_POWER +	farcall EstimateDamage_VersusDefendingCard +	ld a, [wDamage] +	or a +	jr z, .skip_1 +	ld e, a +	ld a, [wce06] +	cp e +	jr nc, .skip_1 +	ld a, e +	ld [wce06], a ; store this damage value +	pop de +	ld a, e +	ld [wce08], a ; store this location +	jr .second_attack + +.skip_1 +	pop de + +.second_attack +	push de +	ld a, e +	ldh [hTempPlayAreaLocation_ff9d], a + +	ld a, SECOND_ATTACK +	farcall EstimateDamage_VersusDefendingCard +	ld a, [wDamage] +	or a +	jr z, .skip_2 +	ld e, a +	ld a, [wce06] +	cp e +	jr nc, .skip_2 +	ld a, e +	ld [wce06], a ; store this damage value +	pop de +	ld a, e +	ld [wce08], a ; store this location +	ret +.skip_2 +	pop de +	ret +; 0x20b06 + +AIPlay_PokemonBreeder: ; 20b06 (8:4b06) +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, [wAITrainerCardParameter] +	ldh [hTempPlayAreaLocation_ffa1], a +	ld a, [wce1a] +	ldh [hTemp_ffa0], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x20b1b + +AIDecide_PokemonBreeder: ; 20b1b (8:4b1b) +	call IsPrehistoricPowerActive +	jp c, .done + +	ld a, 7 +	ld hl, wce08 +	call ClearMemory_Bank8 + +	xor a +	ld [wce06], a +	call CreateHandCardList +	ld hl, wDuelTempList + +.loop_hand_1 +	ld a, [hli] +	cp $ff +	jr z, .not_found_in_hand + +; check if card in hand is any of the following +; stage 2 Pokemon cards +	ld d, a +	call LoadCardDataToBuffer1_FromDeckIndex +	cp VENUSAUR1 +	jr z, .found +	cp VENUSAUR2 +	jr z, .found +	cp BLASTOISE +	jr z, .found +	cp VILEPLUME +	jr z, .found +	cp ALAKAZAM +	jr z, .found +	cp GENGAR +	jr nz, .loop_hand_1 + +.found +	ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA +	push hl +	call GetTurnDuelistVariable +	pop hl +	ld c, a +	ld e, PLAY_AREA_ARENA + +; check Play Area for card that can evolve into +; the picked stage 2 Pokemon +.loop_play_area_1 +	push hl +	push bc +	push de +	call CheckIfCanEvolveInto_BasicToStage2 +	pop de +	call nc, .can_evolve +	pop bc +	pop hl +	inc e +	dec c +	jr nz, .loop_play_area_1 +	jr .loop_hand_1 + +.can_evolve +	ld a, DUELVARS_ARENA_CARD_HP +	add e +	call GetTurnDuelistVariable +	call ConvertHPToCounters +	swap a +	ld b, a + +; count number of energy cards attached and keep +; the lowest 4 bits (capped at $0f) +	call GetPlayAreaCardAttachedEnergies +	ld a, [wTotalAttachedEnergies] +	cp $10 +	jr c, .not_maxed_out +	ld a, %00001111 +.not_maxed_out +	or b + +; 4 high bits of a = HP counters Pokemon still has +; 4 low  bits of a = number of energy cards attached + +; store this score in wce08 + PLAY_AREA* +	ld hl, wce08 +	ld c, e +	ld b, $00 +	add hl, bc +	ld [hl], a + +; store the deck index of stage 2 Pokemon in wce0f + PLAY_AREA* +	ld hl, wce0f +	add hl, bc +	ld [hl], d + +; increase wce06 by one +	ld hl, wce06 +	inc [hl] +	ret + +.not_found_in_hand +	ld a, [wce06] +	or a +	jr z, .check_evolution_and_dragonite + +; an evolution has been found before +	xor a +	ld [wce06], a +	ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA +	call GetTurnDuelistVariable +	ld c, a +	ld e, $00 +	ld d, $00 + +; find highest score in wce08 +.loop_score_1 +	ld hl, wce08 +	add hl, de +	ld a, [wce06] +	cp [hl] +	jr nc, .not_higher + +; store this score to wce06 +	ld a, [hl] +	ld [wce06], a +; store this PLay Area location to wce07 +	ld a, e +	ld [wce07], a + +.not_higher +	inc e +	dec c +	jr nz, .loop_score_1 + +; store the deck index of the stage 2 card +; that has been decided in wce1a, +; return the Play Area location of card +; to evolve in a and return carry +	ld a, [wce07] +	ld e, a +	ld hl, wce0f +	add hl, de +	ld a, [hl] +	ld [wce1a], a +	ld a, [wce07] +	scf +	ret + +.check_evolution_and_dragonite +	ld a, 7 +	ld hl, wce08 +	call ClearMemory_Bank8 + +	xor a +	ld [wce06], a +	call CreateHandCardList +	ld hl, wDuelTempList +	push hl + +.loop_hand_2 +	pop hl +	ld a, [hli] +	cp $ff +	jr z, .check_evolution_found + +	push hl +	ld d, a +	ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA +	call GetTurnDuelistVariable +	ld c, a +	ld e, PLAY_AREA_ARENA + +.loop_play_area_2 +; check if evolution is possible +	push bc +	push de +	call CheckIfCanEvolveInto_BasicToStage2 +	pop de +	call nc, .HandleDragonite1Evolution +	call nc, .can_evolve + +; not possible to evolve or returned carry +; when handling Dragonite1 evolution +	pop bc +	inc e +	dec c +	jr nz, .loop_play_area_2 +	jr .loop_hand_2 + +.check_evolution_found +	ld a, [wce06] +	or a +	jr nz, .evolution_was_found +; no evolution was found before +	or a +	ret + +.evolution_was_found +	xor a +	ld [wce06], a +	ld a, $ff +	ld [wce07], a + +	ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA +	call GetTurnDuelistVariable +	ld c, a +	ld e, $00 +	ld d, $00 + +; find highest score in wce08 with at least +; 2 energy cards attached +.loop_score_2 +	ld hl, wce08 +	add hl, de +	ld a, [wce06] +	cp [hl] +	jr nc, .next_score + +; take the lower 4 bits (total energy cards) +; and skip if less than 2 +	ld a, [hl] +	ld b, a +	and %00001111 +	cp 2 +	jr c, .next_score + +; has at least 2 energy cards +; store the score in wce06 +	ld a, b +	ld [wce06], a +; store this PLay Area location to wce07 +	ld a, e +	ld [wce07], a + +.next_score +	inc e +	dec c +	jr nz, .loop_score_2 + +	ld a, [wce07] +	cp $ff +	jr z, .done + +; a card to evolve was found +; store the deck index of the stage 2 card +; that has been decided in wce1a, +; return the Play Area location of card +; to evolve in a and return carry +	ld e, a +	ld hl, wce0f +	add hl, de +	ld a, [hl] +	ld [wce1a], a +	ld a, [wce07] +	scf +	ret + +.done +	or a +	ret + +; return carry if card is evolving to Dragonite1 and if +; - the card that is evolving is not Arena card and +;   number of damage counters in Play Area is under 8; +; - the card that is evolving is Arena card and has under 5 +;   damage counters or has less than 3 energy cards attached. +.HandleDragonite1Evolution ; 20c5c (8:4c5c) +	push af +	push bc +	push de +	push hl +	push de + +; check card ID +	ld a, d +	call GetCardIDFromDeckIndex +	ld a, e +	pop de +	cp DRAGONITE1 +	jr nz, .no_carry + +; check card Play Area location +	ld a, e +	or a +	jr z, .active_card_dragonite + +; the card that is evolving is not active card +	ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA +	call GetTurnDuelistVariable +	ld b, a +	ld c, 0 + +; count damage counters in Play Area +.loop_play_area_damage +	dec b +	ld e, b +	push bc +	call GetCardDamage +	pop bc +	call ConvertHPToCounters +	add c +	ld c, a + +	ld a, b +	or a +	jr nz, .loop_play_area_damage + +; compare number of total damage counters +; with 7, if less or equal to that, set carry +	ld a, 7 +	cp c +	jr c, .no_carry +	jr .set_carry + +.active_card_dragonite +; the card that is evolving is active card +; compare number of this card's damage counters +; with 5, if less than that, set carry +	ld e, PLAY_AREA_ARENA +	call GetCardDamage +	cp 5 +	jr c, .set_carry + +; compare number of this card's attached energy cards +; with 3, if less than that, set carry +	ld e, PLAY_AREA_ARENA +	farcall CountNumberOfEnergyCardsAttached +	cp 3 +	jr c, .set_carry +	jr .no_carry + +.no_carry +	pop hl +	pop de +	pop bc +	pop af +	ret + +.set_carry +	pop hl +	pop de +	pop bc +	pop af +	scf +	ret +; 0x20cae + +AIPlay_ProfessorOak: ; 20cae (8:4cae) +	ld a, [wCurrentAIFlags] +	or AI_FLAG_USED_PROFESSOR_OAK | AI_FLAG_MODIFIED_HAND +	ld [wCurrentAIFlags], a +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x20cc1 + +; sets carry if AI determines a score of playing +; Professor Oak is over a certain threshold. +AIDecide_ProfessorOak: ; 20cc1 (8:4cc1) +; return if cards in deck <= 6 +	ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK +	call GetTurnDuelistVariable +	cp DECK_SIZE - 6 +	ret nc + +	ld a, [wOpponentDeckID] +	cp LEGENDARY_ARTICUNO_DECK_ID +	jp z, .HandleLegendaryArticunoDeck +	cp EXCAVATION_DECK_ID +	jp z, .HandleExcavationDeck +	cp WONDERS_OF_SCIENCE_DECK_ID +	jp z, .HandleWondersOfScienceDeck + +; return if cards in deck <= 14 +.check_cards_deck +	ld a, [hl] +	cp DECK_SIZE - 14 +	ret nc + +; initialize score +	ld a, $1e +	ld [wce06], a + +; check number of cards in hand +.check_cards_hand +	ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND +	call GetTurnDuelistVariable +	cp 4 +	jr nc, .more_than_3_cards + +; less than 4 cards in hand +	ld a, [wce06] +	add $32 +	ld [wce06], a +	jr .check_energy_cards + +.more_than_3_cards +	cp 9 +	jr c, .check_energy_cards + +; more than 8 cards +	ld a, [wce06] +	sub $1e +	ld [wce06], a + +.check_energy_cards +	farcall CreateEnergyCardListFromHand +	jr nc, .handle_blastoise + +; no energy cards in hand +	ld a, [wce06] +	add $28 +	ld [wce06], a + +.handle_blastoise +	ld a, MUK +	call CountPokemonIDInBothPlayAreas +	jr c, .check_hand + +; no Muk in Play Area +	ld a, BLASTOISE +	call CountPokemonIDInPlayArea +	jr nc, .check_hand + +; at least one Blastoise in AI Play Area +	ld a, WATER_ENERGY +	farcall LookForCardIDInHand +	jr nc, .check_hand + +; no Water energy in hand +	ld a, [wce06] +	add $0a +	ld [wce06], a + +; this part seems buggy +; the AI loops through all the cards in hand and checks +; if any of them is not a Pokemon card and has Basic stage. +; it seems like the intention was that if there was +; any Basic Pokemon still in hand, the AI would add to the score. +.check_hand +	call CreateHandCardList +	ld hl, wDuelTempList +.loop_hand +	ld a, [hli] +	cp $ff +	jr z, .check_evolution + +	call LoadCardDataToBuffer1_FromDeckIndex +	ld a, [wLoadedCard1Type] +	cp TYPE_ENERGY +	jr c, .loop_hand ; bug, should be jr nc + +	ld a, [wLoadedCard1Stage] +	or a +	jr nz, .loop_hand + +	ld a, [wce06] +	add $0a +	ld [wce06], a + +.check_evolution +	xor a +	ld [wce0f], a +	ld [wce0f + 1], a + +	ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA +	call GetTurnDuelistVariable +	ld d, a +	ld e, PLAY_AREA_ARENA + +.loop_play_area +	push de +	call .LookForEvolution +	pop de +	jr nc, .not_in_hand + +; there's a card in hand that can evolve +	ld a, $01 +	ld [wce0f], a + +.not_in_hand +; check if a card that can evolve was found at all +; if not, go to the next card in the Play Area +	ld a, [wce08] +	cp $01 +	jr nz, .next_play_area + +; if it was found, set wce0f + 1 to $01 +	ld a, $01 +	ld [wce0f + 1], a + +.next_play_area +	inc e +	dec d +	jr nz, .loop_play_area + +; if a card was found that evolves... +	ld a, [wce0f + 1] +	or a +	jr z, .check_score + +; ...but that card is not in the hand... +	ld a, [wce0f] +	or a +	jr nz, .check_score + +; ...add to the score +	ld a, [wce06] +	add $0a +	ld [wce06], a + +; only return carry if score >  $3c +.check_score +	ld a, [wce06] +	ld b, $3c +	cp b +	jr nc, .set_carry +	or a +	ret + +.set_carry +	scf +	ret +; 0x20d9d + +; return carry if there's a card in the hand that +; can evolve the card in Play Area location in e. +; sets wce08 to $01 if any card is found that can +; evolve regardless of card location. +.LookForEvolution ; 20d9d (8:4d9d) +	xor a +	ld [wce08], a +	ld d, 0 + +; loop through the whole deck to check if there's +; a card that can evolve this Pokemon. +.loop_deck_evolution +	push de +	call CheckIfCanEvolveInto +	pop de +	jr nc, .can_evolve +.evolution_not_in_hand +	inc d +	ld a, DECK_SIZE +	cp d +	jr nz, .loop_deck_evolution + +	or a +	ret + +; a card was found that can evolve, set wce08 to $01 +; and if the card is in the hand, return carry. +; otherwise resume looping through deck. +.can_evolve +	ld a, $01 +	ld [wce08], a +	ld a, DUELVARS_CARD_LOCATIONS +	add d +	call GetTurnDuelistVariable +	cp CARD_LOCATION_HAND +	jr nz, .evolution_not_in_hand + +	scf +	ret +; 0x20dc3 + +; handles Legendary Articuno Deck AI logic. +.HandleLegendaryArticunoDeck ; 20dc3 (8:4dc3) +	ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA +	call GetTurnDuelistVariable +	cp 3 +	jr nc, .check_playable_cards + +; has less than 3 Pokemon in Play Area. +	push af +	call CreateHandCardList +	pop af +	ld d, a +	ld e, PLAY_AREA_ARENA + +; if no cards in hand evolve cards in Play Area, +; returns carry. +.loop_play_area_articuno +	ld a, DUELVARS_ARENA_CARD +	add e + +	push de +	call GetTurnDuelistVariable +	farcall CheckForEvolutionInList +	pop de +	jr c, .check_playable_cards + +	inc e +	ld a, d +	cp e +	jr nz, .loop_play_area_articuno + +.set_carry_articuno +	scf +	ret + +; if there are more than 3 energy cards in hand, +; return no carry, otherwise check for playable cards. +.check_playable_cards +	call CountOppEnergyCardsInHand +	cp 4 +	jr nc, .no_carry_articuno + +; remove both Professor Oak cards from list +; before checking for playable cards +	call CreateHandCardList +	ld hl, wDuelTempList +	ld e, PROFESSOR_OAK +	farcall RemoveCardIDInList +	ld e, PROFESSOR_OAK +	farcall RemoveCardIDInList + +; look in hand for cards that can be played. +; if a card that cannot be played is found, return no carry. +; otherwise return carry. +.loop_hand_articuno +	ld a, [hli] +	cp $ff +	jr z, .set_carry_articuno +	push hl +	farcall CheckIfCardCanBePlayed +	pop hl +	jr c, .loop_hand_articuno + +.no_carry_articuno +	or a +	ret +; 0x20e11 + +; handles Excavation deck AI logic. +; sets score depending on whether there's no +; Mysterious Fossil in play and in hand. +.HandleExcavationDeck ; 20e11 (8:4e11) +; return no carry if cards in deck < 15 +	ld a, [hl] +	cp 46 +	ret nc + +; look for Mysterious Fossil +	ld a, MYSTERIOUS_FOSSIL +	call LookForCardIDInHandAndPlayArea +	jr c, .found_mysterious_fossil +	ld a, $50 +	ld [wce06], a +	jp .check_cards_hand +.found_mysterious_fossil +	ld a, $1e +	ld [wce06], a +	jp .check_cards_hand +; 0x20e2c + +; handles Wonders of Science AI logic. +; if there's either Grimer or Muk in hand, +; do not play Professor Oak. +.HandleWondersOfScienceDeck ; 20e2c (8:4e2c) +	ld a, GRIMER +	call LookForCardIDInHandList_Bank8 +	jr c, .found_grimer_or_muk +	ld a, MUK +	call LookForCardIDInHandList_Bank8 +	jr c, .found_grimer_or_muk + +	ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK +	call GetTurnDuelistVariable +	jp .check_cards_deck + +.found_grimer_or_muk +	or a +	ret +; 0x20e44 + +AIPlay_EnergyRetrieval: ; 20e44 (8:4e44) +	ld a, [wCurrentAIFlags] +	or AI_FLAG_MODIFIED_HAND +	ld [wCurrentAIFlags], a +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, [wAITrainerCardParameter] +	ldh [hTemp_ffa0], a +	ld a, [wce1a] +	ldh [hTempPlayAreaLocation_ffa1], a +	ld a, [wce1b] +	ldh [hTempRetreatCostCards], a +	cp $ff +	jr z, .asm_20e68 +	ld a, $ff +	ldh [$ffa3], a +.asm_20e68 +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x20e6e + +; checks whether AI can play Energy Retrieval and +; picks the energy cards from the discard pile, +; and duplicate cards in hand to discard. +AIDecide_EnergyRetrieval: ; 20e6e (8:4e6e) +; return no carry if no cards in hand +	farcall CreateEnergyCardListFromHand +	jp nc, .no_carry + +; handle Go Go Rain Dance deck +; return no carry if there's no Muk card in play and +; if there's no Blastoise card in Play Area +; if there's a Muk in play, continue as normal +	ld a, [wOpponentDeckID] +	cp GO_GO_RAIN_DANCE_DECK_ID +	jr nz, .start +	ld a, MUK +	call CountPokemonIDInBothPlayAreas +	jr c, .start +	ld a, BLASTOISE +	call CountPokemonIDInPlayArea +	jp nc, .no_carry + +.start +; find duplicate cards in hand +	call CreateHandCardList +	ld hl, wDuelTempList +	call FindDuplicateCards +	jp c, .no_carry + +	ld [wce06], a +	ld a, CARD_LOCATION_DISCARD_PILE +	call FindBasicEnergyCardsInLocation +	jp c, .no_carry + +; some basic energy cards were found in Discard Pile +	ld a, $ff +	ld [wce1a], a +	ld [wce1b], a +	ld [wce1c], a + +	ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA +	call GetTurnDuelistVariable +	ld d, a +	ld e, PLAY_AREA_ARENA + +; first check if there are useful energy cards in the list +; and choose them for retrieval first +.loop_play_area +	ld a, DUELVARS_ARENA_CARD +	add e +	push de + +; load this card's ID in wTempCardID +; and this card's Type in wTempCardType +	call GetTurnDuelistVariable +	call GetCardIDFromDeckIndex +	ld a, e +	ld [wTempCardID], a +	call LoadCardDataToBuffer1_FromCardID +	pop de +	ld a, [wLoadedCard1Type] +	or TYPE_ENERGY +	ld [wTempCardType], a + +; loop the energy cards in the Discard Pile +; and check if they are useful for this Pokemon +	ld hl, wDuelTempList +.loop_energy_cards_1 +	ld a, [hli] +	cp $ff +	jr z, .next_play_area + +	ld b, a +	push hl +	farcall CheckIfEnergyIsUseful +	pop hl +	jr nc, .loop_energy_cards_1 + +	ld a, [wce1a] +	cp $ff +	jr nz, .second_energy_1 + +; check if there were already chosen cards, +; if this is the second chosen card, return carry + +; first energy card found +	ld a, b +	ld [wce1a], a +	call RemoveCardFromList +	jr .next_play_area +.second_energy_1 +	ld a, b +	ld [wce1b], a +	jr .set_carry + +.next_play_area +	inc e +	dec d +	jr nz, .loop_play_area + +; next, if there are still energy cards left to choose, +; loop through the energy cards again and select +; them in order. +	ld hl, wDuelTempList +.loop_energy_cards_2 +	ld a, [hli] +	cp $ff +	jr z, .check_chosen +	ld b, a +	ld a, [wce1a] +	cp $ff +	jr nz, .second_energy_2 +	ld a, b +	ld [wce1a], a +	call RemoveCardFromList +	jr .loop_energy_cards_2 + +.second_energy_2 +	ld a, b +	ld [wce1b], a +	jr .set_carry + +; will set carry if at least one has been chosen +.check_chosen +	ld a, [wce1a] +	cp $ff +	jr nz, .set_carry +.no_carry +	or a +	ret + +.set_carry +	ld a, [wce06] +	scf +	ret +; 0x20f27 + +; remove an element from the list +; and shortens it accordingly +; input: +;   hl = pointer to element after the one to remove +RemoveCardFromList: ; 20f27 (8:4f27) +	push de +	ld d, h +	ld e, l +	dec hl +	push hl +.loop_remove +	ld a, [de] +	ld [hli], a +	cp $ff +	jr z, .done_remove +	inc de +	jr .loop_remove +.done_remove +	pop hl +	pop de +	ret +; 0x20f38 + +; finds duplicates in card list in hl. +; if a duplicate of Pokemon cards are found, return in +; a the deck index of the second one. +; otherwise, if a duplicate of non-Pokemon cards are found +; return in a the deck index of the second one. +; if no duplicates found, return carry. +; input: +;   hl = list to look in +; output: +;   a = deck index of duplicate card +FindDuplicateCards: ; 20f38 (8:4f38) +	ld a, $ff +	ld [wce0f], a +	ld [wce0f + 1], a +	push hl + +.loop_outer +; get ID of current card +	pop hl +	ld a, [hli] +	cp $ff +	jr z, .check_found +	call GetCardIDFromDeckIndex +	ld b, e +	push hl + +; loop the rest of the list to find +; another card with the same ID +.loop_inner +	ld a, [hli] +	cp $ff +	jr z, .loop_outer +	ld c, a +	call GetCardIDFromDeckIndex +	ld a, e +	cp b +	jr nz, .loop_inner + +; found two cards with same ID +	push bc +	call GetCardType +	pop bc +	cp TYPE_ENERGY +	jr c, .not_energy + +; they are energy or trainer cards +; loads wce0f+1 with this card deck index +	ld a, c +	ld [wce0f + 1], a +	jr .loop_outer + +.not_energy +; they are Pokemon cards +; loads wce0f with this card deck index +	ld a, c +	ld [wce0f], a +	jr .loop_outer + +.check_found +	ld a, [wce0f] +	cp $ff +	jr nz, .no_carry +	ld a, [wce0f + 1] +	cp $ff +	jr nz, .no_carry + +; only set carry if duplicate cards were not found +	scf +	ret + +.no_carry +; two cards with the same ID were found +; of either Pokemon or Non-Pokemon cards +	or a +	ret +; 0x20f80 + +AIPlay_SuperEnergyRetrieval: ; 20f80 (8:4f80) +	ld a, [wCurrentAIFlags] +	or AI_FLAG_MODIFIED_HAND +	ld [wCurrentAIFlags], a +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, [wAITrainerCardParameter] +	ldh [hTemp_ffa0], a +	ld a, [wce1a] +	ldh [hTempPlayAreaLocation_ffa1], a +	ld a, [wce1b] +	ldh [hTempRetreatCostCards], a +	ld a, [wce1c] +	ldh [$ffa3], a +	cp $ff +	jr z, .asm_20fbb +	ld a, [wce1d] +	ldh [$ffa4], a +	cp $ff +	jr z, .asm_20fbb +	ld a, [wce1e] +	ldh [$ffa5], a +	cp $ff +	jr z, .asm_20fbb +	ld a, $ff +	ldh [$ffa6], a +.asm_20fbb +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x20fc1 + +AIDecide_SuperEnergyRetrieval: ; 20fc1 (8:4fc1) +; return no carry if no cards in hand +	farcall CreateEnergyCardListFromHand +	jp nc, .no_carry + +; handle Go Go Rain Dance deck +; return no carry if there's no Muk card in play and +; if there's no Blastoise card in Play Area +; if there's a Muk in play, continue as normal +	ld a, [wOpponentDeckID] +	cp GO_GO_RAIN_DANCE_DECK_ID +	jr nz, .start +	ld a, MUK +	call CountPokemonIDInBothPlayAreas +	jr c, .start +	ld a, BLASTOISE +	call CountPokemonIDInPlayArea +	jp nc, .no_carry + +.start +; find duplicate cards in hand +	call CreateHandCardList +	ld hl, wDuelTempList +	call FindDuplicateCards +	jp c, .no_carry + +; remove the duplicate card in hand +; and run the hand check again +	ld [wce06], a +	ld hl, wDuelTempList +	call FindAndRemoveCardFromList +	call FindDuplicateCards +	jp c, .no_carry + +	ld [wce08], a +	ld a, CARD_LOCATION_DISCARD_PILE +	call FindBasicEnergyCardsInLocation +	jp c, .no_carry + +; some basic energy cards were found in Discard Pile +	ld a, $ff +	ld [wce1b], a +	ld [wce1c], a +	ld [wce1d], a +	ld [wce1e], a +	ld [wce1f], a + +	ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA +	call GetTurnDuelistVariable +	ld d, a +	ld e, PLAY_AREA_ARENA + +; first check if there are useful energy cards in the list +; and choose them for retrieval first +.loop_play_area +	ld a, DUELVARS_ARENA_CARD +	add e +	push de + +; load this card's ID in wTempCardID +; and this card's Type in wTempCardType +	call GetTurnDuelistVariable +	call GetCardIDFromDeckIndex +	ld a, e +	ld [wTempCardID], a +	call LoadCardDataToBuffer1_FromCardID +	pop de +	ld a, [wLoadedCard1Type] +	or TYPE_ENERGY +	ld [wTempCardType], a + +; loop the energy cards in the Discard Pile +; and check if they are useful for this Pokemon +	ld hl, wDuelTempList +.loop_energy_cards_1 +	ld a, [hli] +	cp $ff +	jr z, .next_play_area + +	ld b, a +	push hl +	farcall CheckIfEnergyIsUseful +	pop hl +	jr nc, .loop_energy_cards_1 + +; first energy +	ld a, [wce1b] +	cp $ff +	jr nz, .second_energy_1 +	ld a, b +	ld [wce1b], a +	call RemoveCardFromList +	jr .next_play_area + +.second_energy_1 +	ld a, [wce1c] +	cp $ff +	jr nz, .third_energy_1 +	ld a, b +	ld [wce1c], a +	call RemoveCardFromList +	jr .next_play_area + +.third_energy_1 +	ld a, [wce1d] +	cp $ff +	jr nz, .fourth_energy_1 +	ld a, b +	ld [wce1d], a +	call RemoveCardFromList +	jr .next_play_area + +.fourth_energy_1 +	ld a, b +	ld [wce1e], a +	jr .set_carry + +.next_play_area +	inc e +	dec d +	jr nz, .loop_play_area + +; next, if there are still energy cards left to choose, +; loop through the energy cards again and select +; them in order. +	ld hl, wDuelTempList +.loop_energy_cards_2 +	ld a, [hli] +	cp $ff +	jr z, .check_chosen +	ld b, a +	ld a, [wce1b] +	cp $ff +	jr nz, .second_energy_2 +	ld a, b + +; first energy +	ld [wce1b], a +	call RemoveCardFromList +	jr .loop_energy_cards_2 + +.second_energy_2 +	ld a, [wce1c] +	cp $ff +	jr nz, .third_energy_2 +	ld a, b +	ld [wce1c], a +	call RemoveCardFromList +	jr .loop_energy_cards_2 + +.third_energy_2 +	ld a, [wce1d] +	cp $ff +	jr nz, .fourth_energy +	ld a, b +	ld [wce1d], a +	call RemoveCardFromList +	jr .loop_energy_cards_2 + +.fourth_energy +	ld a, b +	ld [wce1e], a +	jr .set_carry + +; will set carry if at least one has been chosen +.check_chosen +	ld a, [wce1b] +	cp $ff +	jr nz, .set_carry + +.no_carry +	or a +	ret +.set_carry +	ld a, [wce08] +	ld [wce1a], a +	ld a, [wce06] +	scf +	ret +; 0x210d5 + +; finds the card with deck index a in list hl, +; and removes it from the list. +; the card HAS to exist in the list, since this +; routine does not check for the terminating byte $ff! +; input: +;   a  = card deck index to look +;   hl = pointer to list of cards +FindAndRemoveCardFromList: ; 210d5 (8:50d5) +	push hl +	ld b, a +.loop_duplicate +	ld a, [hli] +	cp b +	jr nz, .loop_duplicate +	call RemoveCardFromList +	pop hl +	ret +; 0x210e0 + +AIPlay_PokemonCenter: ; 210e0 (8:50e0) +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x210eb + +AIDecide_PokemonCenter: ; 210eb (8:50eb) +	xor a +	ldh [hTempPlayAreaLocation_ff9d], a + +; return if active Pokemon can KO player's card. +	farcall CheckIfAnyMoveKnocksOutDefendingCard +	jr nc, .start +	farcall CheckIfSelectedMoveIsUnusable +	jr nc, .no_carry +	farcall LookForEnergyNeededForMoveInHand +	jr c, .no_carry + +.start +	xor a +	ld [wce06], a +	ld [wce08], a +	ld [wce0f], a + +	ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA +	call GetTurnDuelistVariable +	ld d, a +	ld e, PLAY_AREA_ARENA + +.loop_play_area +	ld a, DUELVARS_ARENA_CARD +	add e +	push de +	call GetTurnDuelistVariable +	call LoadCardDataToBuffer1_FromDeckIndex +	ld a, e ; useless instruction +	pop de + +; get this Pokemon's current HP in number of counters +; and add it to the total. +	ld a, [wLoadedCard1HP] +	call ConvertHPToCounters +	ld b, a +	ld a, [wce06] +	add b +	ld [wce06], a + +; get this Pokemon's current damage counters +; and add it to the total. +	call GetCardDamage +	call ConvertHPToCounters +	ld b, a +	ld a, [wce08] +	add b +	ld [wce08], a + +; get this Pokemon's number of attached energy cards +; and add it to the total. +; if there's overflow, return no carry. +	call GetPlayAreaCardAttachedEnergies +	ld a, [wTotalAttachedEnergies] +	ld b, a +	ld a, [wce0f] +	add b +	jr c, .no_carry +	ld [wce0f], a + +	inc e +	dec d +	jr nz, .loop_play_area + +; if (number of damage counters / 2) < (total energy cards attached) +; return no carry. +	ld a, [wce08] +	srl a +	ld hl, wce0f +	cp [hl] +	jr c, .no_carry + +; if (number of HP counters * 6 / 10) >= (number of damage counters) +; return no carry. +	ld a, [wce06] +	ld l, a +	ld h, 6 +	call HtimesL +	call CalculateWordTensDigit +	ld a, l +	ld hl, wce08 +	cp [hl] +	jr nc, .no_carry + +	scf +	ret + +.no_carry +	or a +	ret +; 0x21170 + +AIPlay_ImposterProfessorOak: ; 21170 (8:5170) +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x2117b + +; sets carry depending on player's number of cards +; in deck in in hand. +AIDecide_ImposterProfessorOak: ; 2117b (8:517b) +	ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK +	call GetNonTurnDuelistVariable +	cp DECK_SIZE - 14 +	jr c, .more_than_14_cards + +; if player has less than 14 cards in deck, only +; set carry if number of cards in their hands < 6 +	ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND +	call GetNonTurnDuelistVariable +	cp 6 +	jr c, .set_carry +.no_carry +	or a +	ret + +; if player has more than 14 cards in deck, only +; set carry if number of cards in their hands >= 9 +.more_than_14_cards +	ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND +	call GetNonTurnDuelistVariable +	cp 9 +	jr c, .no_carry +.set_carry +	scf +	ret +; 0x2119a + +AIPlay_EnergySearch: ; 2119a (8:519a) +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, [wAITrainerCardParameter] +	ldh [hTemp_ffa0], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x211aa + +; AI checks for playing Energy Search +AIDecide_EnergySearch: ; 211aa (8:51aa) +	farcall CreateEnergyCardListFromHand +	jr c, .start +	call .CheckForUsefulEnergyCards +	jr c, .start + +; there are energy cards in hand and at least +; one of them is useful to a card in Play Area +.no_carry +	or a +	ret + +.start +	ld a, [wOpponentDeckID] +	cp HEATED_BATTLE_DECK_ID +	jr z, .heated_battle +	cp WONDERS_OF_SCIENCE_DECK_ID +	jr z, .wonders_of_science + +; if no energy cards in deck, return no carry +	ld a, CARD_LOCATION_DECK +	call FindBasicEnergyCardsInLocation +	jr c, .no_carry + +; if any of the energy cards in deck is useful +; return carry right away... +	call .CheckForUsefulEnergyCards +	jr c, .no_useful +	scf +	ret + +; ...otherwise save the list in a before return carry. +.no_useful +	ld a, [wDuelTempList] +	scf +	ret + +; Heated Battle deck only searches for Fire and Lightning +; if they are found to be useful to some card in Play Area +.heated_battle +	ld a, CARD_LOCATION_DECK +	call FindBasicEnergyCardsInLocation +	jr c, .no_carry +	call .CheckUsefulFireOrLightningEnergy +	jr c, .no_carry +	scf +	ret + +; this subroutine has a bug. +; it was supposed to use the .CheckUsefulGrassEnergy subroutine +; but uses .CheckUsefulFireOrLightningEnergy instead. +.wonders_of_science +	ld a, CARD_LOCATION_DECK +	call FindBasicEnergyCardsInLocation +	jr c, .no_carry +	call .CheckUsefulFireOrLightningEnergy +	jr c, .no_carry +	scf +	ret +; 0x211f1 + +; return carry if cards in wDuelTempList are not +; useful to any of the Play Area Pokemon +.CheckForUsefulEnergyCards ; 211f1 (8:51f1) +	ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA +	call GetTurnDuelistVariable +	ld d, a +	ld e, PLAY_AREA_ARENA + +.loop_play_area_1 +	ld a, DUELVARS_ARENA_CARD +	add e +	push de +	call GetTurnDuelistVariable + +; store ID and type of card +	call GetCardIDFromDeckIndex +	ld a, e +	ld [wTempCardID], a +	call LoadCardDataToBuffer1_FromCardID +	pop de +	ld a, [wLoadedCard1Type] +	or TYPE_ENERGY +	ld [wTempCardType], a + +; look in list for a useful energy, +; is any is found return no carry. +	ld hl, wDuelTempList +.loop_energy_1 +	ld a, [hli] +	cp $ff +	jr z, .none_found +	ld b, a +	push hl +	farcall CheckIfEnergyIsUseful +	pop hl +	jr nc, .loop_energy_1 + +	ld a, b +	or a +	ret + +.none_found +	inc e +	ld a, e +	cp d +	jr nz, .loop_play_area_1 + +	scf +	ret +; 0x2122e + +; checks whether there are useful energies +; only for Fire and Lightning type Pokemon cards +; in Play Area. If none found, return carry. +.CheckUsefulFireOrLightningEnergy ; 2122e (8:522e) +	ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA +	call GetTurnDuelistVariable +	ld d, a +	ld e, PLAY_AREA_ARENA + +.loop_play_area_2 +	ld a, DUELVARS_ARENA_CARD +	add e +	push de +	call GetTurnDuelistVariable + +; get card's ID and Type +	call GetCardIDFromDeckIndex +	ld a, e +	ld [wTempCardID], a +	call LoadCardDataToBuffer1_FromCardID +	pop de +	ld a, [wLoadedCard1Type] +	or TYPE_ENERGY + +; only do check if the Pokemon's type +; is either Fire or Lightning +	cp TYPE_ENERGY_FIRE +	jr z, .fire_or_lightning +	cp TYPE_ENERGY_LIGHTNING +	jr nz, .next_play_area + +; loop each energy card in list +.fire_or_lightning +	ld [wTempCardType], a +	ld hl, wDuelTempList +.loop_energy_2 +	ld a, [hli] +	cp $ff +	jr z, .next_play_area + +; if this energy card is useful, +; return no carry. +	ld b, a +	push hl +	farcall CheckIfEnergyIsUseful +	pop hl +	jr nc, .loop_energy_2 + +	ld a, b +	or a +	ret + +.next_play_area +	inc e +	ld a, e +	cp d +	jr nz, .loop_play_area_2 + +; no card was found to be useful +; for Fire/Lightning type Pokemon card. +	scf +	ret +; 0x21273 + +; checks whether there are useful energies +; only for Grass type Pokemon cards +; in Play Area. If none found, return carry. +.CheckUsefulGrassEnergy ; 21273 (8:5273) +; unreferenced +	ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA +	call GetTurnDuelistVariable +	ld d, a +	ld e, PLAY_AREA_ARENA + +.loop_play_area_3 +	ld a, DUELVARS_ARENA_CARD +	add e +	push de +	call GetTurnDuelistVariable + +; get card's ID and Type +	call GetCardIDFromDeckIndex +	ld a, e +	ld [wTempCardID], a +	call LoadCardDataToBuffer1_FromCardID +	pop de +	ld a, [wLoadedCard1Type] +	or TYPE_ENERGY + +; only do check if the Pokemon's type is Grass +	cp TYPE_ENERGY_GRASS +	jr nz, .next_play_area_3 + +; loop each energy card in list +	ld [wTempCardType], a +	ld hl, wDuelTempList +.loop_energy_3 +	ld a, [hli] +	cp $ff +	jr z, .next_play_area_3 + +; if this energy card is useful, +; return no carry. +	ld b, a +	push hl +	farcall CheckIfEnergyIsUseful +	pop hl +	jr nc, .loop_energy_3 + +	ld a, b +	or a +	ret + +.next_play_area_3 +	inc e +	ld a, e +	cp d +	jr nz, .loop_play_area_3 + +; no card was found to be useful +; for Grass type Pokemon card. +	scf +	ret +; 0x212b4 + +AIPlay_Pokedex: ; 212b4 (8:52b4) +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, [wce1a] +	ldh [hTemp_ffa0], a +	ld a, [wce1b] +	ldh [hTempPlayAreaLocation_ffa1], a +	ld a, [wce1c] +	ldh [hTempRetreatCostCards], a +	ld a, [wce1d] +	ldh [$ffa3], a +	ld a, [wce1e] +	ldh [$ffa4], a +	ld a, $ff +	ldh [$ffa5], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x212dc + +AIDecide_Pokedex: ; 212dc (8:52dc) +	ld a, [wcda6] +	cp $06 +	jr c, .no_carry + +; return no carry if number of cards in deck <= 4 +	ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK +	call GetTurnDuelistVariable +	cp DECK_SIZE - 4 +	jr nc, .no_carry + +; has a 3 in 10 chance of actually playing card +	ld a, 10 +	call Random +	cp 3 +	jr c, .pick_cards + +.no_carry +	or a +	ret + +.pick_cards +; the following comparison is disregarded +; the Wonders of Science deck was probably intended +; to use PickPokedexCards_Unreferenced instead +	ld a, [wOpponentDeckID] +	cp WONDERS_OF_SCIENCE_DECK_ID +	jp PickPokedexCards ; bug, should be jp nz +; 0x212ff + +; picks order of the cards in deck from the effects of Pokedex. +; prioritises Pokemon cards, then Trainer cards, then energy cards. +; stores the resulting order in wce1a. +PickPokedexCards_Unreferenced: ; 212ff (8:52ff) +; unreferenced +	xor a +	ld [wcda6], a + +	ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK +	call GetTurnDuelistVariable +	add DUELVARS_DECK_CARDS +	ld l, a +	lb de, $00, $00 +	ld b, 5 + +; run through 5 of the remaining cards in deck +.next_card +	ld a, [hli] +	ld c, a +	call .GetCardType + +; load this card's deck index and type in memory +; wce08 = card types +; wce0f = card deck indices +	push hl +	ld hl, wce08 +	add hl, de +	ld [hl], a +	ld hl, wce0f +	add hl, de +	ld [hl], c +	pop hl + +	inc e +	dec b +	jr nz, .next_card + +; terminate the wce08 list +	ld a, $ff +	ld [wce08 + 5], a + +	ld de, wce1a + +; find Pokemon +	ld hl, wce08 +	ld c, -1 +	ld b, $00 + +; run through the stored cards +; and look for any Pokemon cards. +.loop_pokemon +	inc c +	ld a, [hli] +	cp $ff +	jr z, .find_trainers +	cp TYPE_ENERGY +	jr nc, .loop_pokemon +; found a Pokemon card +; store it in wce1a list +	push hl +	ld hl, wce0f +	add hl, bc +	ld a, [hl] +	pop hl +	ld [de], a +	inc de +	jr .loop_pokemon + +; run through the stored cards +; and look for any Trainer cards. +.find_trainers +	ld hl, wce08 +	ld c, -1 +	ld b, $00 + +.loop_trainers +	inc c +	ld a, [hli] +	cp $ff +	jr z, .find_energy +	cp TYPE_TRAINER +	jr nz, .loop_trainers +; found a Trainer card +; store it in wce1a list +	push hl +	ld hl, wce0f +	add hl, bc +	ld a, [hl] +	pop hl +	ld [de], a +	inc de +	jr .loop_trainers + +.find_energy +	ld hl, wce08 +	ld c, -1 +	ld b, $00 + +; run through the stored cards +; and look for any energy cards. +.loop_energy +	inc c +	ld a, [hli] +	cp $ff +	jr z, .done +	and TYPE_ENERGY +	jr z, .loop_energy +; found an energy card +; store it in wce1a list +	push hl +	ld hl, wce0f +	add hl, bc +	ld a, [hl] +	pop hl +	ld [de], a +	inc de +	jr .loop_energy + +.done +	scf +	ret +; 0x21383 + +.GetCardType ; 21383 (8:5383) +	push bc +	push de +	call GetCardIDFromDeckIndex +	call GetCardType +	pop de +	pop bc +	ret +; 0x2138e + +; picks order of the cards in deck from the effects of Pokedex. +; prioritises energy cards, then Pokemon cards, then Trainer cards. +; stores the resulting order in wce1a. +PickPokedexCards: ; 2138e (8:538e) +	xor a +	ld [wcda6], a + +	ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK +	call GetTurnDuelistVariable +	add DUELVARS_DECK_CARDS +	ld l, a +	lb de, $00, $00 +	ld b, 5 + +; run through 5 of the remaining cards in deck +.next_card +	ld a, [hli] +	ld c, a +	call .GetCardType + +; load this card's deck index and type in memory +; wce08 = card types +; wce0f = card deck indices +	push hl +	ld hl, wce08 +	add hl, de +	ld [hl], a +	ld hl, wce0f +	add hl, de +	ld [hl], c +	pop hl + +	inc e +	dec b +	jr nz, .next_card + +; terminate the wce08 list +	ld a, $ff +	ld [wce08 + 5], a + +	ld de, wce1a + +; find energy +	ld hl, wce08 +	ld c, -1 +	ld b, $00 + +; run through the stored cards +; and look for any energy cards. +.loop_energy +	inc c +	ld a, [hli] +	cp $ff +	jr z, .find_pokemon +	and TYPE_ENERGY +	jr z, .loop_energy +; found an energy card +; store it in wce1a list +	push hl +	ld hl, wce0f +	add hl, bc +	ld a, [hl] +	pop hl +	ld [de], a +	inc de +	jr .loop_energy + +.find_pokemon +	ld hl, wce08 +	ld c, -1 +	ld b, $00 + +; run through the stored cards +; and look for any Pokemon cards. +.loop_pokemon +	inc c +	ld a, [hli] +	cp $ff +	jr z, .find_trainers +	cp TYPE_ENERGY +	jr nc, .loop_pokemon +; found a Pokemon card +; store it in wce1a list +	push hl +	ld hl, wce0f +	add hl, bc +	ld a, [hl] +	pop hl +	ld [de], a +	inc de +	jr .loop_pokemon + +; run through the stored cards +; and look for any Trainer cards. +.find_trainers +	ld hl, wce08 +	ld c, -1 +	ld b, $00 + +.loop_trainers +	inc c +	ld a, [hli] +	cp $ff +	jr z, .done +	cp TYPE_TRAINER +	jr nz, .loop_trainers +; found a Trainer card +; store it in wce1a list +	push hl +	ld hl, wce0f +	add hl, bc +	ld a, [hl] +	pop hl +	ld [de], a +	inc de +	jr .loop_trainers + +.done +	scf +	ret +; 0x21412 + +.GetCardType ; 21412 (8:5412) +	push bc +	push de +	call GetCardIDFromDeckIndex +	call GetCardType +	pop de +	pop bc +	ret +; 0x2141d + +AIPlay_FullHeal: ; 2141d (8:541d) +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x21428 + +AIDecide_FullHeal: ; 21428 (8:5428) +	ld a, DUELVARS_ARENA_CARD_STATUS +	call GetTurnDuelistVariable + +; skip if no status on arena card +	or a ; NO_STATUS +	jr z, .no_carry + +	and CNF_SLP_PRZ +	cp PARALYZED +	jr z, .paralyzed +	cp ASLEEP +	jr z, .asleep +	cp CONFUSED +	jr z, .confused +	; if either PSN or DBLPSN, fallthrough + +.set_carry +	scf +	ret + +.asleep +; set carry if any of the following +; cards are in the Play Area. +	ld a, GASTLY1 +	ld b, PLAY_AREA_ARENA +	call LookForCardIDInPlayArea_Bank8 +	jr c, .set_carry +	ld a, GASTLY2 +	ld b, PLAY_AREA_ARENA +	call LookForCardIDInPlayArea_Bank8 +	jr c, .set_carry +	ld a, HAUNTER2 +	ld b, PLAY_AREA_ARENA +	call LookForCardIDInPlayArea_Bank8 +	jr c, .set_carry + +; otherwise fallthrough + +.paralyzed +; if Scoop Up is in hand and decided to be played, skip. +	ld a, SCOOP_UP +	call LookForCardIDInHandList_Bank8 +	jr nc, .no_scoop_up_prz +	call AIDecide_ScoopUp +	jr c, .no_carry + +.no_scoop_up_prz +; if card can damage defending Pokemon... +	xor a ; PLAY_AREA_ARENA +	farcall CheckIfCanDamageDefendingPokemon +	jr nc, .no_carry +; ...and can play an energy card to retreat, set carry. +	ld a, [wAIPlayEnergyCardForRetreat] +	or a +	jr nz, .set_carry + +; if not, check whether it's a card it would rather retreat, +; and if it isn't, set carry. +	farcall AIDecideWhetherToRetreat +	jr nc, .set_carry + +.no_carry +	or a +	ret + +.confused +; if Scoop Up is in hand and decided to be played, skip. +	ld a, SCOOP_UP +	call LookForCardIDInHandList_Bank8 +	jr nc, .no_scoop_up_cnf +	call AIDecide_ScoopUp +	jr c, .no_carry + +.no_scoop_up_cnf +; if card can damage defending Pokemon... +	xor a ; PLAY_AREA_ARENA +	farcall CheckIfCanDamageDefendingPokemon +	jr nc, .no_carry +; ...and can play an energy card to retreat, set carry. +	ld a, [wAIPlayEnergyCardForRetreat] +	or a +	jr nz, .set_carry +; if not, return no carry. +	jr .no_carry +; 0x21497 + +AIPlay_MrFuji: ; 21497 (8:5497) +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, [wAITrainerCardParameter] +	ldh [hTemp_ffa0], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x214a7 + +; AI logic for playing Mr Fuji +AIDecide_MrFuji: ; 214a7 (8:54a7) +	ld a, $ff +	ld [wce06], a +	ld [wce08], a + +; if just one Pokemon in Play Area, skip. +	ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA +	call GetTurnDuelistVariable +	cp 1 +	ret z + +	dec a +	ld d, a +	ld e, PLAY_AREA_BENCH_1 + +; find a Pokemon in the bench that has damage counters. +.loop_bench +	ld a, DUELVARS_ARENA_CARD +	add e +	push de +	call GetTurnDuelistVariable +	call LoadCardDataToBuffer1_FromDeckIndex +	pop de + +	ld a, [wLoadedCard1HP] +	ld b, a + +	; skip if zero damage counters +	call GetCardDamage +	call ConvertHPToCounters +	or a +	jr z, .next + +; a = damage counters +; b = hp left +	call CalculateBDividedByA_Bank8 +	cp 20 +	jr nc, .next + +; here, HP left in counters is less than twice +; the number of damage counters, that is: +; HP < 1/3 max HP + +; if value is less than the one found before, store this one. +	ld hl, wce08 +	cp [hl] +	jr nc, .next +	ld [hl], a +	ld a, e +	ld [wce06], a +.next +	inc e +	dec d +	jr nz, .loop_bench + +	ld a, [wce06] +	cp $ff +	ret z + +	scf +	ret +; 0x214f1 + +AIPlay_ScoopUp: ; 214f1 (8:54f1) +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, [wAITrainerCardParameter] +	ldh [hTemp_ffa0], a +	ld a, [wce1a] +	ldh [hTempPlayAreaLocation_ffa1], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x21506 + +AIDecide_ScoopUp: ; 21506 (8:5506) +	xor a +	ldh [hTempPlayAreaLocation_ff9d], a + +; if only one Pokemon in Play Area, skip. +	ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA +	call GetTurnDuelistVariable +	cp 2 +	jr c, .no_carry + +; handle some decks differently +	ld a, [wOpponentDeckID] +	cp LEGENDARY_ARTICUNO_DECK_ID +	jr z, .HandleLegendaryArticuno +	cp LEGENDARY_RONALD_DECK_ID +	jp z, .HandleLegendaryRonald + +; if can't KO defending Pokemon, check if defending Pokemon +; can KO this card. If so, then continue. +; If not, return no carry. + +; if it can KO the defending Pokemon this turn, +; return no carry. +	farcall CheckIfAnyMoveKnocksOutDefendingCard +	jr nc, .cannot_ko +	farcall CheckIfSelectedMoveIsUnusable +	jr nc, .no_carry +	farcall LookForEnergyNeededForMoveInHand +	jr c, .no_carry + +.cannot_ko +	ld a, DUELVARS_ARENA_CARD_STATUS +	call GetTurnDuelistVariable +	and CNF_SLP_PRZ +	cp PARALYZED +	jr z, .cannot_retreat +	cp ASLEEP +	jr z, .cannot_retreat + +; doesn't have a status that prevents retreat. +; so check if it has enough energy to retreat. +; if not, return no carry. +	xor a +	ldh [hTempPlayAreaLocation_ff9d], a +	call GetPlayAreaCardRetreatCost +	ld b, a +	ld e, PLAY_AREA_ARENA +	farcall CountNumberOfEnergyCardsAttached +	cp b +	jr c, .cannot_retreat + +.no_carry +	or a +	ret + +.cannot_retreat +; store damage and total HP left +	ld a, DUELVARS_ARENA_CARD +	call GetTurnDuelistVariable +	call LoadCardDataToBuffer1_FromDeckIndex +	ld a, [wLoadedCard1HP] +	call ConvertHPToCounters +	ld d, a + +; skip if card has no damage counters. +	ld e, PLAY_AREA_ARENA +	call GetCardDamage +	or a +	jr z, .no_carry + +; if (total damage / total HP counters) < 7 +; return carry. +; (this corresponds to damage counters +; being under 70% of the max HP) +	ld b, a +	ld a, d +	call CalculateBDividedByA_Bank8 +	cp 7 +	jr c, .no_carry + +; store Pokemon to switch to in wce1a and set carry. +.decide_switch +	farcall AIDecideBenchPokemonToSwitchTo +	jr c, .no_carry +	ld [wce1a], a +	xor a +	scf +	ret + +; this deck will use Scoop Up on a benched Articuno2. +; it checks if the defending Pokemon is a Snorlax, +; but interestingly does not check for Muk in both Play Areas. +; will also use Scoop Up on  +.HandleLegendaryArticuno +; if less than 3 Play Area Pokemon cards, skip. +	ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA +	call GetTurnDuelistVariable +	cp 3 +	jr c, .no_carry + +; look for Articuno2 in bench +	ld a, ARTICUNO2 +	ld b, PLAY_AREA_BENCH_1 +	call LookForCardIDInPlayArea_Bank8 +	jr c, .articuno_bench + +; check Arena card +	ld a, DUELVARS_ARENA_CARD +	call GetTurnDuelistVariable +	call GetCardIDFromDeckIndex +	ld a, e +	cp ARTICUNO2 +	jr z, .articuno_or_chansey +	cp CHANSEY +	jr nz, .no_carry + +; here either Articuno2 or Chansey +; is the Arena Card. +.articuno_or_chansey +; if can't KO defending Pokemon, check if defending Pokemon +; can KO this card. If so, then continue. +; If not, return no carry. + +; if it can KO the defending Pokemon this turn, +; return no carry. +	farcall CheckIfAnyMoveKnocksOutDefendingCard +	jr nc, .check_ko +	farcall CheckIfSelectedMoveIsUnusable +	jr nc, .no_carry +	farcall LookForEnergyNeededForMoveInHand +	jr c, .no_carry +.check_ko +	farcall CheckIfDefendingPokemonCanKnockOut +	jr nc, .no_carry +	jr .decide_switch + +.articuno_bench +; skip if the defending card is Snorlax +	push af +	ld a, DUELVARS_ARENA_CARD +	call GetNonTurnDuelistVariable +	call SwapTurn +	call GetCardIDFromDeckIndex +	call SwapTurn +	ld a, e +	cp SNORLAX +	pop bc +	jr z, .no_carry + +; check attached energy cards. +; if it has any, return no carry. +	ld a, b +.check_attached_energy +	ld e, a +	push af +	farcall CountNumberOfEnergyCardsAttached +	or a +	pop bc +	ld a, b +	jr z, .no_energy +	jp .no_carry + +.no_energy +; has decided to Scoop Up benched card, +; store $ff as the Pokemon card to switch to +; because there's no need to switch. +	push af +	ld a, $ff +	ld [wce1a], a +	pop af +	scf +	ret +; 0x215e7 + +; this deck will use Scoop Up on a benched Articuno2, Zapdos3 or Molres2. +; interestingly, does not check for Muk in both Play Areas. +.HandleLegendaryRonald ; 215e7 (8:55e7) +; if less than 3 Play Area Pokemon cards, skip. +	ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA +	call GetTurnDuelistVariable +	cp 3 +	jp c, .no_carry + +	ld a, ARTICUNO2 +	ld b, PLAY_AREA_BENCH_1 +	call LookForCardIDInPlayArea_Bank8 +	jr c, .articuno_bench +	ld a, ZAPDOS3 +	ld b, PLAY_AREA_BENCH_1 +	call LookForCardIDInPlayArea_Bank8 +	jr c, .check_attached_energy +	ld a, MOLTRES2 +	ld b, PLAY_AREA_BENCH_1 +	call LookForCardIDInPlayArea_Bank8 +	jr c, .check_attached_energy +	jp .no_carry +; 0x2160f + +AIPlay_Maintenance: ; 2160f (8:560f) +	ld a, [wCurrentAIFlags] +	or AI_FLAG_MODIFIED_HAND +	ld [wCurrentAIFlags], a +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, [wce1a] +	ldh [hTemp_ffa0], a +	ld a, [wce1b] +	ldh [hTempPlayAreaLocation_ffa1], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x2162c + +; AI logic for playing Maintenance +AIDecide_Maintenance: ; 2162c (8:562c) +; Imakuni? has his own thing +	ld a, [wOpponentDeckID] +	cp IMAKUNI_DECK_ID +	jr z, .imakuni + +; skip if number of cars in hand < 4. +	ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND +	call GetTurnDuelistVariable +	cp 4 +	jr c, .no_carry + +; list out all the hand cards and remove +; wAITrainerCardToPlay from list.Then find any duplicate cards. +	call CreateHandCardList +	ld hl, wDuelTempList +	ld a, [wAITrainerCardToPlay] +	call FindAndRemoveCardFromList +; if duplicates are not found, return no carry. +	call FindDuplicateCards +	jp c, .no_carry + +; store the first duplicate card and remove it from the list. +; run duplicate check again. +	ld [wce1a], a +	ld hl, wDuelTempList +	call FindAndRemoveCardFromList +; if duplicates are not found, return no carry. +	call FindDuplicateCards +	jp c, .no_carry + +; store the second duplicate card and return carry. +	ld [wce1b], a +	scf +	ret + +.no_carry +	or a +	ret + +.imakuni +; has a 2 in 10 chance of not skipping. +	ld a, 10 +	call Random +	cp 2 +	jr nc, .no_carry + +; skip if number of cards in hand < 3. +	ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND +	call GetTurnDuelistVariable +	cp 3 +	jr c, .no_carry + +; shuffle hand cards +	call CreateHandCardList +	ld hl, wDuelTempList +	call CountCardsInDuelTempList +	call ShuffleCards + +; go through each card and find +; cards that are different from wAITrainerCardToPlay. +; if found, add those cards to wce1a and wce1a+1. +	ld a, [wAITrainerCardToPlay] +	ld b, a +	ld c, 2 +	ld de, wce1a + +.loop +	ld a, [hli] +	cp $ff +	jr z, .no_carry +	cp b +	jr z, .loop +	ld [de], a +	inc de +	dec c +	jr nz, .loop + +; two cards were found, return carry. +	scf +	ret +; 0x2169a + +AIPlay_Recycle: ; 2169a (8:569a) +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ldtx de, TrainerCardSuccessCheckText +	bank1call TossCoin +	jr nc, .asm_216ae +	ld a, [wAITrainerCardParameter] +	ldh [hTemp_ffa0], a +	jr .asm_216b2 +.asm_216ae +	ld a, $ff +	ldh [hTemp_ffa0], a +.asm_216b2 +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x216b8 + +; lists cards to look for in the Discard Pile. +; has priorities for Ghost Deck, and a "default" priority list +; (which is the Fire Charge deck, since it's the only other +; deck that runs a Recycle card in it.) +AIDecide_Recycle: ; 216b8 (8:56b8) +; no use checking if no cards in Discard Pile +	call CreateDiscardPileCardList +	jr c, .no_carry + +	ld a, $ff +	ld [wce08], a +	ld [wce08 + 1], a +	ld [wce08 + 2], a +	ld [wce08 + 3], a +	ld [wce08 + 4], a + +; handle Ghost deck differently +	ld hl, wDuelTempList +	ld a, [wOpponentDeckID] +	cp GHOST_DECK_ID +	jr z, .loop_2 + +; priority list for Fire Charge deck +.loop_1 +	ld a, [hli] +	cp $ff +	jr z, .done + +	ld b, a +	call LoadCardDataToBuffer1_FromDeckIndex + +; double colorless +	cp DOUBLE_COLORLESS_ENERGY +	jr nz, .chansey +	ld a, b +	ld [wce08], a +	jr .loop_1 + +.chansey +	cp CHANSEY +	jr nz, .tauros +	ld a, b +	ld [wce08 + 1], a +	jr .loop_1 + +.tauros +	cp TAUROS +	jr nz, .jigglypuff +	ld a, b +	ld [wce08 + 2], a +	jr .loop_1 + +.jigglypuff +	cp JIGGLYPUFF1 +	jr nz, .loop_1 +	ld a, b +	ld [wce08 + 3], a +	jr .loop_1 + +; loop through wce08 and set carry +; on the first that was found in Discard Pile. +; if none were found, return no carry. +.done +	ld hl, wce08 +	ld b, 5 +.loop_found +	ld a, [hli] +	cp $ff +	jr nz, .set_carry +	dec b +	jr nz, .loop_found +.no_carry +	or a +	ret +.set_carry +	scf +	ret + +; priority list for Ghost deck +.loop_2 +	ld a, [hli] +	cp $ff +	jr z, .done + +	ld b, a +	call LoadCardDataToBuffer1_FromDeckIndex + +; gastly2 +	cp GASTLY2 +	jr nz, .gastly1 +	ld a, b +	ld [wce08], a +	jr .loop_2 + +.gastly1 +	cp GASTLY1 +	jr nz, .zubat +	ld a, b +	ld [wce08 + 1], a +	jr .loop_2 + +.zubat +	cp ZUBAT +	jr nz, .ditto +	ld a, b +	ld [wce08 + 2], a +	jr .loop_2 + +.ditto +	cp DITTO +	jr nz, .meowth +	ld a, b +	ld [wce08 + 3], a +	jr .loop_2 + +.meowth +	cp MEOWTH2 +	jr nz, .loop_2 +	ld a, b +	ld [wce08 + 4], a +	jr .loop_2 +; 0x21755 + +AIPlay_Lass: ; 21755 (8:5755) +	ld a, [wCurrentAIFlags] +	or AI_FLAG_MODIFIED_HAND +	ld [wCurrentAIFlags], a +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x21768 + +AIDecide_Lass: ; 21768 (8:5768) +; skip if player has less than 7 cards in hand +	ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND +	call GetNonTurnDuelistVariable +	cp 7 +	jr c, .no_carry + +; look for Trainer cards in hand (except for Lass) +; if any is found, return no carry. +; otherwise, return carry. +	call CreateHandCardList +	ld hl, wDuelTempList +.loop +	ld a, [hli] +	cp $ff +	jr z, .set_carry +	ld b, a +	call LoadCardDataToBuffer1_FromDeckIndex +	cp LASS +	jr z, .loop +	ld a, [wLoadedCard1Type] +	cp TYPE_TRAINER +	jr nz, .loop +.no_carry +	or a +	ret +.set_carry +	scf +	ret +; 0x2178f + +AIPlay_ItemFinder: ; 2178f (8:578f) +	ld a, [wCurrentAIFlags] +	or AI_FLAG_MODIFIED_HAND +	ld [wCurrentAIFlags], a +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, [wce1a] +	ldh [hTemp_ffa0], a +	ld a, [wce1b] +	ldh [hTempPlayAreaLocation_ffa1], a +	ld a, [wAITrainerCardParameter] +	ldh [hTempRetreatCostCards], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x217b1 + +; checks whether there's Energy Removal in Discard Pile. +; if so, find duplicate cards in hand to discard +; that are not Mr Mime and Pokemon Trader cards. +; this logic is suitable only for Strange Psyshock deck. +AIDecide_ItemFinder: ; 217b1 (8:57b1) +; skip if no Discard Pile. +	call CreateDiscardPileCardList +	jr c, .no_carry + +; look for Energy Removal in Discard Pile +	ld hl, wDuelTempList +.loop_discard_pile +	ld a, [hli] +	cp $ff +	jr z, .no_carry +	ld b, a +	call LoadCardDataToBuffer1_FromDeckIndex +	cp ENERGY_REMOVAL +	jr nz, .loop_discard_pile +; found, store this deck index +	ld a, b +	ld [wce06], a + +; before looking for cards to discard in hand, +; remove any Mr Mime and Pokemon Trader cards. +; this way these are guaranteed to not be discarded. +	call CreateHandCardList +	ld hl, wDuelTempList +.loop_hand +	ld a, [hli] +	cp $ff +	jr z, .choose_discard +	ld b, a +	call LoadCardDataToBuffer1_FromDeckIndex +	cp MR_MIME +	jr nz, .pkmn_trader +	call RemoveCardFromList +	jr .loop_hand +.pkmn_trader +	cp POKEMON_TRADER +	jr nz, .loop_hand +	call RemoveCardFromList +	jr .loop_hand + +; choose cards to discard from hand. +.choose_discard +	ld hl, wDuelTempList + +; do not discard wAITrainerCardToPlay +	ld a, [wAITrainerCardToPlay] +	call FindAndRemoveCardFromList +; find any duplicates, if not found, return no carry. +	call FindDuplicateCards +	jp c, .no_carry + +; store the duplicate found in wce1a and +; remove it from the hand list. +	ld [wce1a], a +	ld hl, wDuelTempList +	call FindAndRemoveCardFromList +; find duplicates again, if not found, return no carry. +	call FindDuplicateCards +	jp c, .no_carry + +; store the duplicate found in wce1b. +; output the card to be recovered from the Discard Pile. +	ld [wce1b], a +	ld a, [wce06] +	scf +	ret + +.no_carry +	or a +	ret +; 0x21813 + +AIPlay_Imakuni: ; 21813 (8:5813) +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x2181e + +; only sets carry if Active card is not confused. +AIDecide_Imakuni: ; 2181e (8:581e) +	ld a, DUELVARS_ARENA_CARD_STATUS +	call GetTurnDuelistVariable +	and CNF_SLP_PRZ +	cp CONFUSED +	jr z, .confused +	scf +	ret +.confused +	or a +	ret +; 0x2182d + +AIPlay_Gambler: ; 2182d (8:582d) +	ld a, [wCurrentAIFlags] +	or AI_FLAG_MODIFIED_HAND +	ld [wCurrentAIFlags], a +	ld a, [wOpponentDeckID] +	cp IMAKUNI_DECK_ID +	jr z, .asm_2186a +	ld hl, wRNG1 +	ld a, [hli] +	ld [wce06], a +	ld a, [hli] +	ld [wce08], a +	ld a, [hl] +	ld [wce0f], a +	ld a, $50 +	ld [hld], a +	ld [hld], a +	ld [hl], a +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ld hl, wRNG1 +	ld a, [wce06] +	ld [hli], a +	ld a, [wce08] +	ld [hli], a +	ld a, [wce0f] +	ld [hl], a +	ret +.asm_2186a +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x21875 + +; checks whether to play Gambler. +; aside from Imakuni, all other opponents only +; play if there's less than 4 cards in the deck. +AIDecide_Gambler: ; 21875 (8:5875) +; Imakuni? has his own routine +	ld a, [wOpponentDeckID] +	cp IMAKUNI_DECK_ID +	jr z, .imakuni + +	ld a, [wcda7] +	and $80 +	jr z, .no_carry + +; set carry if number of cards in deck <= 4 +	ld a, DUELVARS_NUMBER_OF_CARDS_NOT_IN_DECK +	call GetTurnDuelistVariable +	cp DECK_SIZE - 4 +	jr nc, .set_carry +.no_carry +	or a +	ret + +.imakuni +; has a 2 in 10 chance of returning carry +	ld a, 10 +	call Random +	cp 2 +	jr nc, .no_carry +.set_carry +	scf +	ret +; 0x21899 + +AIPlay_Revive: ; 21899 (8:5899) +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, [wAITrainerCardParameter] +	ldh [hTemp_ffa0], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x218a9 + +; checks certain cards in Discard Pile to use Revive on. +; suitable for Muscle For Brains deck only. +AIDecide_Revive: ; 218a9 (8:58a9) +; skip if no cards in Discard Pile +	call CreateDiscardPileCardList +	jr c, .no_carry + +; skip if number of Pokemon cards in Play Area >= 4 +	ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA +	call GetTurnDuelistVariable +	cp 4 +	jr nc, .no_carry + +; look in Discard Pile for specific cards. +	ld hl, wDuelTempList +.loop_discard_pile +	ld a, [hli] +	cp $ff +	jr z, .no_carry +	ld b, a +	call LoadCardDataToBuffer1_FromDeckIndex + +; these checks have a bug. +; it works fine for Hitmonchan and Hitmonlee, +; but in case it's a Tauros card, the routine will fallthrough +; into the Kangaskhan check. since it will never be equal to Kangaskhan, +; it will fallthrough into the set carry branch. +; in case it's a Kangaskhan card, the check will fail in the Tauros check +; and jump back into the loop. so just by accident the Tauros check works, +; but Kangaskhan will never be correctly checked because of this. +	cp HITMONCHAN +	jr z, .set_carry +	cp HITMONLEE +	jr z, .set_carry +	cp TAUROS +	jr nz, .loop_discard_pile ; bug, these two lines should be swapped +	cp KANGASKHAN +	jr z, .set_carry ; bug, these two lines should be swapped + +.set_carry +	ld a, b +	scf +	ret +.no_carry +	or a +	ret +; 0x218d8 + +AIPlay_PokemonFlute: ; 218d8 (8:58d8) +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, [wAITrainerCardParameter] +	ldh [hTemp_ffa0], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x218e8 + +AIDecide_PokemonFlute: ; 218e8 (8:58e8) +; if player has no Discard Pile, skip. +	call SwapTurn +	call CreateDiscardPileCardList +	call SwapTurn +	jr c, .no_carry + +; if player's Play Area is already full, skip. +	ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA +	call GetNonTurnDuelistVariable +	cp MAX_PLAY_AREA_POKEMON +	jr nc, .no_carry + +	ld a, [wOpponentDeckID] +	cp IMAKUNI_DECK_ID +	jr z, .imakuni + +	ld a, $ff +	ld [wce06], a +	ld [wce08], a + +; find Basic stage Pokemon with lowest HP in Discard Pile +	ld hl, wDuelTempList +.loop_1 +	ld a, [hli] +	cp $ff +	jr z, .done + +	ld b, a +	call SwapTurn +	call LoadCardDataToBuffer1_FromDeckIndex +	call SwapTurn +; skip this card if it's not Pokemon card +	ld a, [wLoadedCard1Type] +	cp TYPE_ENERGY +	jr nc, .loop_1 +; skip this card if it's not Basic Stage +	ld a, [wLoadedCard1Stage] +	or a ; BASIC +	jr nz, .loop_1 + +; compare this HP with one stored +	ld a, [wLoadedCard1HP] +	push hl +	ld hl, wce06 +	cp [hl] +	pop hl +	jr nc, .loop_1 +; if lower, store this one +	ld [wce06], a +	ld a, b +	ld [wce08], a +	jr .loop_1 + +.done +; if lowest HP found >= 50, return no carry +	ld a, [wce06] +	cp 50 +	jr nc, .no_carry +; otherwise output its deck index in a and set carry. +	ld a, [wce08] +	scf +	ret +.no_carry +	or a +	ret + +.imakuni +; has 2 in 10 chance of not skipping +	ld a, 10 +	call Random +	cp 2 +	jr nc, .no_carry + +; look for any Basic Pokemon card +	ld hl, wDuelTempList +.loop_2 +	ld a, [hli] +	cp $ff +	jr z, .no_carry +	ld b, a +	call SwapTurn +	call LoadCardDataToBuffer1_FromDeckIndex +	call SwapTurn +	ld a, [wLoadedCard1Type] +	cp TYPE_ENERGY +	jr nc, .loop_2 +	ld a, [wLoadedCard1Stage] +	or a ; BASIC +	jr nz, .loop_2 + +; a Basic stage Pokemon was found, return carry +	ld a, b +	scf +	ret +; 0x21977 + +AIPlay_ClefairyDollOrMysteriousFossil: ; 21977 (8:5977) +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x21982 + +; AI logic for playing Clefairy Doll +AIDecide_ClefairyDollOrMysteriousFossil: ; 21982 (8:5982) +; if has max number of Play Area Pokemon, skip +	ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA +	call GetTurnDuelistVariable +	cp MAX_PLAY_AREA_POKEMON +	jr nc, .no_carry + +; store number of Play Area Pokemon cards +	ld [wce06], a + +; if the Arena card is Wigglytuff, return carry +	ld a, DUELVARS_ARENA_CARD +	call GetTurnDuelistVariable +	call GetCardIDFromDeckIndex +	ld a, e +	cp WIGGLYTUFF +	jr z, .set_carry + +; if number of Play Area Pokemon >= 4, return no carry +	ld a, [wce06] +	cp 4 +	jr nc, .no_carry + +.set_carry +	scf +	ret +.no_carry +	or a +	ret +; 0x219a6 + +AIPlay_Pokeball: ; 219a6 (8:59a6) +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ldtx de, TrainerCardSuccessCheckText +	bank1call TossCoin +	ldh [hTemp_ffa0], a +	jr nc, .asm_219bc +	ld a, [wAITrainerCardParameter] +	ldh [hTempPlayAreaLocation_ffa1], a +	jr .asm_219c0 +.asm_219bc +	ld a, $ff +	ldh [hTempPlayAreaLocation_ffa1], a +.asm_219c0 +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x219c6 + +AIDecide_Pokeball: ; 219c6 (8:59c6) +; go to the routines associated with deck ID +	ld a, [wOpponentDeckID] +	cp FIRE_CHARGE_DECK_ID +	jr z, .fire_charge +	cp HARD_POKEMON_DECK_ID +	jr z, .hard_pokemon +	cp PIKACHU_DECK_ID +	jr z, .pikachu +	cp ETCETERA_DECK_ID +	jr z, .etcetera +	cp LOVELY_NIDORAN_DECK_ID +	jp z, .lovely_nidoran +	or a +	ret + +; this deck runs a deck check for specific +; card IDs in order of decreasing priority +.fire_charge +	ld e, CHANSEY +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	ret c +	ld e, TAUROS +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	ret c +	ld e, JIGGLYPUFF1 +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	ret c +	ret + +; this deck runs a deck check for specific +; card IDs in order of decreasing priority +.hard_pokemon +	ld e, RHYHORN +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	ret c +	ld e, RHYDON +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	ret c +	ld e, ONIX +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	ret c +	ret + +; this deck runs a deck check for specific +; card IDs in order of decreasing priority +.pikachu +	ld e, PIKACHU2 +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	ret c +	ld e, PIKACHU3 +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	ret c +	ld e, PIKACHU4 +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	ret c +	ld e, PIKACHU1 +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	ret c +	ld e, FLYING_PIKACHU +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	ret c +	ret + +; this deck runs a deck check for specific +; card IDs in order of decreasing priority +; given a specific energy card in hand. +; also it avoids redundancy, so if it already +; has that card ID in the hand, it is skipped. +.etcetera +; fire +	ld a, FIRE_ENERGY +	call LookForCardIDInHandList_Bank8 +	jr nc, .lightning +	ld a, CHARMANDER +	call LookForCardIDInHandList_Bank8 +	jr c, .lightning +	ld a, MAGMAR2 +	call LookForCardIDInHandList_Bank8 +	jr c, .lightning +	ld e, CHARMANDER +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	ret c +	ld e, MAGMAR2 +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	ret c + +.lightning +	ld a, LIGHTNING_ENERGY +	call LookForCardIDInHandList_Bank8 +	jr nc, .fighting +	ld a, PIKACHU1 +	call LookForCardIDInHandList_Bank8 +	jr c, .fighting +	ld a, MAGNEMITE1 +	call LookForCardIDInHandList_Bank8 +	jr c, .fighting +	ld e, PIKACHU1 +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	ret c +	ld e, MAGNEMITE1 +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	ret c + +.fighting +	ld a, FIGHTING_ENERGY +	call LookForCardIDInHandList_Bank8 +	jr nc, .psychic +	ld a, DIGLETT +	call LookForCardIDInHandList_Bank8 +	jr c, .psychic +	ld a, MACHOP +	call LookForCardIDInHandList_Bank8 +	jr c, .psychic +	ld e, DIGLETT +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	ret c +	ld e, MACHOP +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	ret c + +.psychic +	ld a, PSYCHIC_ENERGY +	call LookForCardIDInHandList_Bank8 +	jr nc, .done_etcetera +	ld a, GASTLY1 +	call LookForCardIDInHandList_Bank8 +	jr c, .done_etcetera +	ld a, JYNX +	call LookForCardIDInHandList_Bank8 +	jr c, .done_etcetera +	ld e, GASTLY1 +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	ret c +	ld e, JYNX +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	ret c +.done_etcetera +	or a +	ret + +; this deck looks for card evolutions if +; its pre-evolution is in hand or in Play Area. +; if none of these are found, it looks for pre-evolutions +; of cards it has in hand. +; it does this for both the NidoranM (first) +; and NidoranF (second) families. +.lovely_nidoran +	ld b, NIDORANM +	ld a, NIDORINO +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	ret c +	ld b, NIDORINO +	ld a, NIDOKING +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	ret c +	ld a, NIDORANM +	ld b, NIDORINO +	call LookForCardIDInDeck_GivenCardIDInHand +	ret c +	ld a, NIDORINO +	ld b, NIDOKING +	call LookForCardIDInDeck_GivenCardIDInHand +	ret c +	ld b, NIDORANF +	ld a, NIDORINA +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	ret c +	ld b, NIDORINA +	ld a, NIDOQUEEN +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	ret c +	ld a, NIDORANF +	ld b, NIDORINA +	call LookForCardIDInDeck_GivenCardIDInHand +	ret c +	ld a, NIDORINA +	ld b, NIDOQUEEN +	call LookForCardIDInDeck_GivenCardIDInHand +	ret c +	ret +; 0x21b12 + +AIPlay_ComputerSearch: ; 21b12 (8:5b12) +	ld a, [wCurrentAIFlags] +	or AI_FLAG_MODIFIED_HAND +	ld [wCurrentAIFlags], a +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, [wAITrainerCardParameter] +	ldh [hTempRetreatCostCards], a +	ld a, [wce1a] +	ldh [hTemp_ffa0], a +	ld a, [wce1b] +	ldh [hTempPlayAreaLocation_ffa1], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x21b34 + +; checks what Deck ID AI is playing and handle +; them in their own routine. +AIDecide_ComputerSearch: ; 21b34 (8:5b34) +; skip if number of cards in hand < 3 +	ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND +	call GetTurnDuelistVariable +	cp 3 +	jr c, .no_carry + +	ld a, [wOpponentDeckID] +	cp ROCK_CRUSHER_DECK_ID +	jr z, AIDecide_ComputerSearch_RockCrusher +	cp WONDERS_OF_SCIENCE_DECK_ID +	jp z, AIDecide_ComputerSearch_WondersOfScience +	cp FIRE_CHARGE_DECK_ID +	jp z, AIDecide_ComputerSearch_FireCharge +	cp ANGER_DECK_ID +	jp z, AIDecide_ComputerSearch_Anger + +.no_carry +	or a +	ret + +AIDecide_ComputerSearch_RockCrusher: ; 21b55 (8:5b55) +; if number of cards in hand is equal to 3, +; target Professor Oak in deck +	ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND +	call GetTurnDuelistVariable +	cp 3 +	jr nz, .graveler + +	ld e, PROFESSOR_OAK +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	jr c, .find_discard_cards_1 +	; no Professor Oak in deck, fallthrough + +.no_carry +	or a +	ret + +.find_discard_cards_1 +	ld [wce06], a +	ld a, $ff +	ld [wce1a], a +	ld [wce1b], a + +	call CreateHandCardList +	ld hl, wDuelTempList +	ld de, wce1a +.loop_hand_1 +	ld a, [hli] +	cp $ff +	jr z, .check_discard_cards + +	ld c, a +	call LoadCardDataToBuffer1_FromDeckIndex + +; if any of the following cards are in the hand, +; return no carry. +	cp PROFESSOR_OAK +	jr z, .no_carry +	cp FIGHTING_ENERGY +	jr z, .no_carry +	cp DOUBLE_COLORLESS_ENERGY +	jr z, .no_carry +	cp DIGLETT +	jr z, .no_carry +	cp GEODUDE +	jr z, .no_carry +	cp ONIX +	jr z, .no_carry +	cp RHYHORN +	jr z, .no_carry + +; if it's same as wAITrainerCardToPlay, skip this card. +	ld a, [wAITrainerCardToPlay] +	ld b, a +	ld a, c +	cp b +	jr z, .loop_hand_1 + +; store this card index in memory +	ld [de], a +	inc de +	jr .loop_hand_1 + +.check_discard_cards +; check if two cards were found +; if so, output in a the deck index +; of Professor Oak card found in deck and set carry. +	ld a, [wce1b] +	cp $ff +	jr z, .no_carry +	ld a, [wce06] +	scf +	ret + +; more than 3 cards in hand, so look for +; specific evolution cards. + +; checks if there is a Graveler card in the deck to target. +; if so, check if there's Geodude in hand or Play Area, +; and if there's no Graveler card in hand, proceed. +; also removes Geodude from hand list so that it is not discarded. +.graveler +	ld e, GRAVELER +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	jr nc, .golem +	ld [wce06], a +	ld a, GEODUDE +	call LookForCardIDInHandAndPlayArea +	jr nc, .golem +	ld a, GRAVELER +	call LookForCardIDInHandList_Bank8 +	jr c, .golem +	call CreateHandCardList +	ld hl, wDuelTempList +	ld e, GEODUDE +	farcall RemoveCardIDInList +	jr .find_discard_cards_2 + +; checks if there is a Golem card in the deck to target. +; if so, check if there's Graveler in Play Area, +; and if there's no Golem card in hand, proceed. +.golem +	ld e, GOLEM +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	jr nc, .dugtrio +	ld [wce06], a +	ld a, GRAVELER +	call LookForCardIDInPlayArea_Bank8 +	jr nc, .dugtrio +	ld a, GOLEM +	call LookForCardIDInHandList_Bank8 +	jr c, .dugtrio +	call CreateHandCardList +	ld hl, wDuelTempList +	jr .find_discard_cards_2 + +; checks if there is a Dugtrio card in the deck to target. +; if so, check if there's Diglett in Play Area, +; and if there's no Dugtrio card in hand, proceed. +.dugtrio +	ld e, DUGTRIO +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	jp nc, .no_carry +	ld [wce06], a +	ld a, DIGLETT +	call LookForCardIDInPlayArea_Bank8 +	jp nc, .no_carry +	ld a, DUGTRIO +	call LookForCardIDInHandList_Bank8 +	jp c, .no_carry +	call CreateHandCardList +	ld hl, wDuelTempList +	jr .find_discard_cards_2 + +.find_discard_cards_2 +	ld a, $ff +	ld [wce1a], a +	ld [wce1b], a + +	ld bc, wce1a +	ld d, $00 ; start considering Trainer cards only + +; stores wAITrainerCardToPlay in e so that +; all routines ignore it for the discard effects. +	ld a, [wAITrainerCardToPlay] +	ld e, a + +; this loop will store in wce1a cards to discard from hand. +; at the start it will only consider Trainer cards, +; then if there are still needed to discard, +; move on to Pokemon cards, and finally to Energy cards. +.loop_hand_2 +	call RemoveFromListDifferentCardOfGivenType +	jr c, .found +	inc d ; move on to next type (Pokemon, then Energy) +	ld a, $03 +	cp d +	jp z, .no_carry ; no more types to look +	jr .loop_hand_2 +.found +; store this card in memory, +; and if there's still one more card to search for, +; jump back into the loop. +	ld [bc], a +	inc bc +	ld a, [wce1b] +	cp $ff +	jr z, .loop_hand_2 + +; output in a Computer Search target and set carry. +	ld a, [wce06] +	scf +	ret + +AIDecide_ComputerSearch_WondersOfScience: ; 21c56 (8:5c56) +; if number of cards in hand < 5, target Professor Oak in deck +	ld a, DUELVARS_NUMBER_OF_CARDS_IN_HAND +	call GetTurnDuelistVariable +	cp 5 +	jr nc, .look_in_hand + +; target Professor Oak for Computer Search +	ld e, PROFESSOR_OAK +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	jp nc, .look_in_hand ; can be a jr +	ld [wce06], a +	jr .find_discard_cards + +; Professor Oak not in deck, move on to +; look for other cards instead. +; if Grimer or Muk are not in hand, +; check whether to use Computer Search on them. +.look_in_hand +	ld a, GRIMER +	call LookForCardIDInHandList_Bank8 +	jr nc, .target_grimer +	ld a, MUK +	call LookForCardIDInHandList_Bank8 +	jr nc, .target_muk + +.no_carry +	or a +	ret + +; first check Grimer +; if in deck, check cards to discard. +.target_grimer +	ld e, GRIMER +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	jp nc, .no_carry ; can be a jr +	ld [wce06], a +	jr .find_discard_cards + +; first check Muk +; if in deck, check cards to discard. +.target_muk +	ld e, MUK +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	jp nc, .no_carry ; can be a jr +	ld [wce06], a + +; only discard Trainer cards from hand. +; if there are less than 2 Trainer cards to discard, +; then return with no carry. +; else, store the cards to discard and the +; target card deck index, and return carry. +.find_discard_cards +	call CreateHandCardList +	ld hl, wDuelTempList +	ld d, $00 ; first consider Trainer cards + +; ignore wAITrainerCardToPlay for the discard effects. +	ld a, [wAITrainerCardToPlay] +	ld e, a +	call RemoveFromListDifferentCardOfGivenType +	jr nc, .no_carry +	ld [wce1a], a +	call RemoveFromListDifferentCardOfGivenType +	jr nc, .no_carry +	ld [wce1b], a +	ld a, [wce06] +	scf +	ret + +AIDecide_ComputerSearch_FireCharge: ; 21cbb (8:5cbb) +; pick target card in deck from highest to lowest priority. +; if not found in hand, go to corresponding branch. +	ld a, CHANSEY +	call LookForCardIDInHandList_Bank8 +	jr nc, .chansey +	ld a, TAUROS +	call LookForCardIDInHandList_Bank8 +	jr nc, .tauros +	ld a, JIGGLYPUFF1 +	call LookForCardIDInHandList_Bank8 +	jr nc, .jigglypuff +	; fallthrough + +.no_carry +	or a +	ret + +; for each card targeted, check if it's in deck and, +; if not, then return no carry. +; else, look for cards to discard. +.chansey +	ld e, CHANSEY +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	jp nc, .no_carry +	ld [wce06], a +	jr .find_discard_cards +.tauros +	ld e, TAUROS +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	jp nc, .no_carry +	ld [wce06], a +	jr .find_discard_cards +.jigglypuff +	ld e, JIGGLYPUFF1 +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	jp nc, .no_carry +	ld [wce06], a + +; only discard Trainer cards from hand. +; if there are less than 2 Trainer cards to discard, +; then return with no carry. +; else, store the cards to discard and the +; target card deck index, and return carry. +.find_discard_cards +	call CreateHandCardList +	ld hl, wDuelTempList +	ld d, $00 ; first consider Trainer cards -Func_205d7: ; 205d7 (8:45d7) -	INCROM $205d7, $205f6 +; ignore wAITrainerCardToPlay for the discard effects. +	ld a, [wAITrainerCardToPlay] +	ld e, a +	call RemoveFromListDifferentCardOfGivenType +	jr nc, .no_carry +	ld [wce1a], a +	call RemoveFromListDifferentCardOfGivenType +	jr nc, .no_carry +	ld [wce1b], a +	ld a, [wce06] +	scf +	ret +; 0x21d1e -Func_205f6: ; 205f6 (8:45f6) -	INCROM $205f6, $2282e +AIDecide_ComputerSearch_Anger: ; 21d1e (8:5d1e) +; for each of the following cards, +; first run a check if there's a pre-evolution in +; Play Area or in the hand. If there is, choose it as target. +; otherwise, check if the evolution card is in +; hand and if so, choose it as target instead. +	ld b, RATTATA +	ld a, RATICATE +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .find_discard_cards +	ld a, RATTATA +	ld b, RATICATE +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_discard_cards +	ld b, GROWLITHE +	ld a, ARCANINE1 +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .find_discard_cards +	ld a, GROWLITHE +	ld b, ARCANINE1 +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_discard_cards +	ld b, DODUO +	ld a, DODRIO +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .find_discard_cards +	ld a, DODUO +	ld b, DODRIO +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_discard_cards +	; fallthrough + +.no_carry +	or a +	ret + +; only discard Trainer cards from hand. +; if there are less than 2 Trainer cards to discard, +; then return with no carry. +; else, store the cards to discard and the +; target card deck index, and return carry. +.find_discard_cards +	ld [wce06], a +	call CreateHandCardList +	ld hl, wDuelTempList +	ld d, $00 ; first consider Trainer cards + +; ignore wAITrainerCardToPlay for the discard effects. +	ld a, [wAITrainerCardToPlay] +	ld e, a +	call RemoveFromListDifferentCardOfGivenType +	jr nc, .no_carry +	ld [wce1a], a +	call RemoveFromListDifferentCardOfGivenType +	jr nc, .no_carry +	ld [wce1b], a +	ld a, [wce06] +	scf +	ret +; 0x21d7a + +AIPlay_PokemonTrader: ; 21d7a (8:5d7a) +	ld a, [wAITrainerCardToPlay] +	ldh [hTempCardIndex_ff9f], a +	ld a, [wAITrainerCardParameter] +	ldh [hTemp_ffa0], a +	ld a, [wce1a] +	ldh [hTempPlayAreaLocation_ffa1], a +	ld a, OPPACTION_EXECUTE_TRAINER_EFFECTS +	bank1call AIMakeDecision +	ret +; 0x21d8f + +AIDecide_PokemonTrader: ; 21d8f (8:5d8f) +; each deck has their own routine for picking +; what Pokemon to look for. +	ld a, [wOpponentDeckID] +	cp LEGENDARY_MOLTRES_DECK_ID +	jr z, AIDecide_PokemonTrader_LegendaryMoltres +	cp LEGENDARY_ARTICUNO_DECK_ID +	jr z, AIDecide_PokemonTrader_LegendaryArticuno +	cp LEGENDARY_DRAGONITE_DECK_ID +	jp z, AIDecide_PokemonTrader_LegendaryDragonite +	cp LEGENDARY_RONALD_DECK_ID +	jp z, AIDecide_PokemonTrader_LegendaryRonald +	cp BLISTERING_POKEMON_DECK_ID +	jp z, AIDecide_PokemonTrader_BlisteringPokemon +	cp SOUND_OF_THE_WAVES_DECK_ID +	jp z, AIDecide_PokemonTrader_SoundOfTheWaves +	cp POWER_GENERATOR_DECK_ID +	jp z, AIDecide_PokemonTrader_PowerGenerator +	cp FLOWER_GARDEN_DECK_ID +	jp z, AIDecide_PokemonTrader_FlowerGarden +	cp STRANGE_POWER_DECK_ID +	jp z, AIDecide_PokemonTrader_StrangePower +	cp FLAMETHROWER_DECK_ID +	jp z, AIDecide_PokemonTrader_Flamethrower +	or a +	ret + +AIDecide_PokemonTrader_LegendaryMoltres: ; 21dc4 (8:5dc4) +; look for Moltres2 card in deck to trade with a +; card in hand different from Moltres1. +	ld a, MOLTRES2 +	ld e, MOLTRES1 +	call LookForCardIDToTradeWithDifferentHandCard +	jr nc, .no_carry +; success +	ld [wce1a], a +	ld a, e +	scf +	ret +.no_carry +	or a +	ret + +AIDecide_PokemonTrader_LegendaryArticuno: ; 21dd5 (8:5dd5) +; if has none of these cards in Hand or Play Area, proceed +	ld a, ARTICUNO1 +	call LookForCardIDInHandAndPlayArea +	jr c, .no_carry +	ld a, LAPRAS +	call LookForCardIDInHandAndPlayArea +	jr c, .no_carry + +; if doesn't have Seel in Hand or Play Area, +; look for it in the deck. +; otherwise, look for Dewgong instead. +	ld a, SEEL +	call LookForCardIDInHandAndPlayArea +	jr c, .dewgong + +	ld e, SEEL +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	jr nc, .dewgong +	ld [wce1a], a +	jr .check_hand + +.dewgong +	ld a, DEWGONG +	call LookForCardIDInHandAndPlayArea +	jr c, .no_carry +	ld e, DEWGONG +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	jr nc, .no_carry +	ld [wce1a], a + +; a Seel or Dewgong was found in deck, +; check hand for card to trade for +.check_hand +	ld a, CHANSEY +	call CheckIfHasCardIDInHand +	jr c, .set_carry +	ld a, DITTO +	call CheckIfHasCardIDInHand +	jr c, .set_carry +	ld a, ARTICUNO2 +	call CheckIfHasCardIDInHand +	jr c, .set_carry +	; doesn't have any of the cards in hand + +.no_carry +	or a +	ret + +.set_carry +	scf +	ret +; 0x21e24 + +AIDecide_PokemonTrader_LegendaryDragonite: ; 21e24 (8:5e24) +; if has less than 5 cards of energy +; and of Pokemon in hand/Play Area, +; target a Kangaskhan in deck. +	farcall CountOppEnergyCardsInHandAndAttached +	cp 5 +	jr c, .kangaskhan +	call CountPokemonCardsInHandAndInPlayArea +	cp 5 +	jr c, .kangaskhan +	; total number of energy cards >= 5 +	; total number of Pokemon cards >= 5 + +; for each of the following cards, +; first run a check if there's a pre-evolution in +; Play Area or in the hand. If there is, choose it as target. +; otherwise, check if the evolution card is in +; hand and if so, choose it as target instead. +	ld b, MAGIKARP +	ld a, GYARADOS +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .choose_hand +	ld a, MAGIKARP +	ld b, GYARADOS +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .choose_hand +	ld b, DRATINI +	ld a, DRAGONAIR +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .choose_hand +	ld b, DRAGONAIR +	ld a, DRAGONITE1 +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .choose_hand +	ld a, DRATINI +	ld b, DRAGONAIR +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .choose_hand +	ld a, DRAGONAIR +	ld b, DRAGONITE1 +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .choose_hand +	ld b, CHARMANDER +	ld a, CHARMELEON +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .choose_hand +	ld b, CHARMELEON +	ld a, CHARIZARD +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .choose_hand +	ld a, CHARMANDER +	ld b, CHARMELEON +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .choose_hand +	ld a, CHARMELEON +	ld b, CHARIZARD +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .choose_hand +	jr .no_carry + +.kangaskhan +	ld e, KANGASKHAN +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	jr nc, .no_carry + +; card was found as target in deck, +; look for card in hand to trade with +.choose_hand +	ld [wce1a], a +	ld a, DRAGONAIR +	call CheckIfHasCardIDInHand +	jr c, .set_carry +	ld a, CHARMELEON +	call CheckIfHasCardIDInHand +	jr c, .set_carry +	ld a, GYARADOS +	call CheckIfHasCardIDInHand +	jr c, .set_carry +	ld a, MAGIKARP +	call CheckIfHasCardIDInHand +	jr c, .set_carry +	ld a, CHARMANDER +	call CheckIfHasCardIDInHand +	jr c, .set_carry +	ld a, DRATINI +	call CheckIfHasCardIDInHand +	jr c, .set_carry +	; non found + +.no_carry +	or a +	ret +.set_carry +	scf +	ret +; 0x21ec9 + +AIDecide_PokemonTrader_LegendaryRonald: ; 21ec9 (8:5ec9) +; for each of the following cards, +; first run a check if there's a pre-evolution in +; Play Area or in the hand. If there is, choose it as target. +; otherwise, check if the evolution card is in +; hand and if so, choose it as target instead. +	ld b, EEVEE +	ld a, FLAREON1 +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .choose_hand +	ld b, EEVEE +	ld a, VAPOREON1 +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .choose_hand +	ld b, EEVEE +	ld a, JOLTEON1 +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .choose_hand +	ld a, EEVEE +	ld b, FLAREON1 +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .choose_hand +	ld a, EEVEE +	ld b, VAPOREON1 +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .choose_hand +	ld a, EEVEE +	ld b, JOLTEON1 +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .choose_hand +	ld b, DRATINI +	ld a, DRAGONAIR +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .choose_hand +	ld b, DRAGONAIR +	ld a, DRAGONITE1 +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .choose_hand +	ld a, DRATINI +	ld b, DRAGONAIR +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .choose_hand +	ld a, DRAGONAIR +	ld b, DRAGONITE1 +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .choose_hand +	jr .no_carry + +; card was found as target in deck, +; look for card in hand to trade with +.choose_hand +	ld [wce1a], a +	ld a, ZAPDOS3 +	call LookForCardIDInHandList_Bank8 +	jr c, .set_carry +	ld a, ARTICUNO2 +	call LookForCardIDInHandList_Bank8 +	jr c, .set_carry +	ld a, MOLTRES2 +	call LookForCardIDInHandList_Bank8 +	jr c, .set_carry +	; none found + +.no_carry +	or a +	ret +.set_carry +	scf +	ret +; 0x21f41 + +AIDecide_PokemonTrader_BlisteringPokemon: ; 21f41 (8:5f41) +; for each of the following cards, +; first run a check if there's a pre-evolution in +; Play Area or in the hand. If there is, choose it as target. +; otherwise, check if the evolution card is in +; hand and if so, choose it as target instead. +	ld b, RHYHORN +	ld a, RHYDON +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .find_duplicates +	ld a, RHYHORN +	ld b, RHYDON +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_duplicates +	ld b, CUBONE +	ld a, MAROWAK1 +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .find_duplicates +	ld a, CUBONE +	ld b, MAROWAK1 +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_duplicates +	ld b, PONYTA +	ld a, RAPIDASH +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .find_duplicates +	ld a, PONYTA +	ld b, RAPIDASH +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_duplicates +	jr .no_carry + +; a card in deck was found to look for, +; check if there are duplicates in hand to trade with. +.find_duplicates +	ld [wce1a], a +	call FindDuplicatePokemonCards +	jr c, .set_carry +.no_carry +	or a +	ret +.set_carry +	scf +	ret +; 0x21f85 + +AIDecide_PokemonTrader_SoundOfTheWaves: ; 21f85 (8:5f85) +; for each of the following cards, +; first run a check if there's a pre-evolution in +; Play Area or in the hand. If there is, choose it as target. +; otherwise, check if the evolution card is in +; hand and if so, choose it as target instead. +	ld b, SEEL +	ld a, DEWGONG +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .choose_hand +	ld a, SEEL +	ld b, DEWGONG +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .choose_hand +	ld b, KRABBY +	ld a, KINGLER +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .choose_hand +	ld a, KRABBY +	ld b, KINGLER +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .choose_hand +	ld b, SHELLDER +	ld a, CLOYSTER +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .choose_hand +	ld a, SHELLDER +	ld b, CLOYSTER +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .choose_hand +	ld b, HORSEA +	ld a, SEADRA +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .choose_hand +	ld a, HORSEA +	ld b, SEADRA +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .choose_hand +	ld b, TENTACOOL +	ld a, TENTACRUEL +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .choose_hand +	ld a, TENTACOOL +	ld b, TENTACRUEL +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .choose_hand +	jr .no_carry + +; card was found as target in deck, +; look for card in hand to trade with +.choose_hand +	ld [wce1a], a +	ld a, SEEL +	call CheckIfHasCardIDInHand +	jr c, .set_carry +	ld a, KRABBY +	call CheckIfHasCardIDInHand +	jr c, .set_carry +	ld a, HORSEA +	call CheckIfHasCardIDInHand +	jr c, .set_carry +	ld a, SHELLDER +	call CheckIfHasCardIDInHand +	jr c, .set_carry +	ld a, TENTACOOL +	call CheckIfHasCardIDInHand +	jr c, .set_carry +	; none found + +.no_carry +	or a +	ret +.set_carry +	scf +	ret +; 0x2200b + +AIDecide_PokemonTrader_PowerGenerator: ; 2200b (8:600b) +; for each of the following cards, +; first run a check if there's a pre-evolution in +; Play Area or in the hand. If there is, choose it as target. +; otherwise, check if the evolution card is in +; hand and if so, choose it as target instead. +	ld b, PIKACHU2 +	ld a, RAICHU1 +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jp c, .find_duplicates +	ld b, PIKACHU1 +	ld a, RAICHU1 +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .find_duplicates +	ld a, PIKACHU2 +	ld b, RAICHU1 +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_duplicates +	ld a, PIKACHU1 +	ld b, RAICHU1 +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_duplicates +	ld b, VOLTORB +	ld a, ELECTRODE2 +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .find_duplicates +	ld b, VOLTORB +	ld a, ELECTRODE1 +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .find_duplicates +	ld a, VOLTORB +	ld b, ELECTRODE2 +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_duplicates +	ld a, VOLTORB +	ld b, ELECTRODE1 +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_duplicates +	ld b, MAGNEMITE1 +	ld a, MAGNETON2 +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .find_duplicates +	ld b, MAGNEMITE2 +	ld a, MAGNETON2 +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .find_duplicates +	ld b, MAGNEMITE1 +	ld a, MAGNETON1 +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .find_duplicates +	ld b, MAGNEMITE2 +	ld a, MAGNETON1 +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .find_duplicates +	ld a, MAGNEMITE2 +	ld b, MAGNETON2 +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_duplicates +	ld a, MAGNEMITE1 +	ld b, MAGNETON2 +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_duplicates +	ld a, MAGNEMITE2 +	ld b, MAGNETON1 +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_duplicates +	ld a, MAGNEMITE1 +	ld b, MAGNETON1 +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_duplicates +	; bug, missing jr .no_carry + +; since this last check falls through regardless of result, +; register a might hold an invalid deck index, +; which might lead to hilarious results like Brandon +; trading a Pikachu with a Grass Energy from the deck. +; however, since it's deep in a tower of conditionals, +; reaching here is extremely unlikely. + +; a card in deck was found to look for, +; check if there are duplicates in hand to trade with. +.find_duplicates +	ld [wce1a], a +	call FindDuplicatePokemonCards +	jr c, .set_carry +	or a +	ret +.set_carry +	scf +	ret +; 0x220a8 + +AIDecide_PokemonTrader_FlowerGarden: ; 220a8 (8:60a8) +; for each of the following cards, +; first run a check if there's a pre-evolution in +; Play Area or in the hand. If there is, choose it as target. +; otherwise, check if the evolution card is in +; hand and if so, choose it as target instead. +	ld b, BULBASAUR +	ld a, IVYSAUR +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .find_duplicates +	ld b, IVYSAUR +	ld a, VENUSAUR2 +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .find_duplicates +	ld a, BULBASAUR +	ld b, IVYSAUR +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_duplicates +	ld a, IVYSAUR +	ld b, VENUSAUR2 +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_duplicates +	ld b, BELLSPROUT +	ld a, WEEPINBELL +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .find_duplicates +	ld b, WEEPINBELL +	ld a, VICTREEBEL +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .find_duplicates +	ld a, BELLSPROUT +	ld b, WEEPINBELL +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_duplicates +	ld a, WEEPINBELL +	ld b, VICTREEBEL +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_duplicates +	ld b, ODDISH +	ld a, GLOOM +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .find_duplicates +	ld b, GLOOM +	ld a, VILEPLUME +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .find_duplicates +	ld a, ODDISH +	ld b, GLOOM +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_duplicates +	ld a, GLOOM +	ld b, VILEPLUME +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_duplicates +	jr .no_carry + +; a card in deck was found to look for, +; check if there are duplicates in hand to trade with. +.find_duplicates +	ld [wce1a], a +	call FindDuplicatePokemonCards +	jr c, .found +.no_carry +	or a +	ret +.found +	scf +	ret +; 0x22122 + +AIDecide_PokemonTrader_StrangePower: ; 22122 (8:6122) +; looks for a Pokemon in hand to trade with Mr Mime in deck. +; inputing Mr Mime in register e for the function is redundant +; since it already checks whether a Mr Mime exists in the hand. +	ld a, MR_MIME +	ld e, MR_MIME +	call LookForCardIDToTradeWithDifferentHandCard +	jr nc, .no_carry +; found +	ld [wce1a], a +	ld a, e +	scf +	ret +.no_carry +	or a +	ret +; 0x22133 + +AIDecide_PokemonTrader_Flamethrower: ; 22133 (8:6133) +; for each of the following cards, +; first run a check if there's a pre-evolution in +; Play Area or in the hand. If there is, choose it as target. +; otherwise, check if the evolution card is in +; hand and if so, choose it as target instead. +	ld b, CHARMANDER +	ld a, CHARMELEON +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .find_duplicates +	ld b, CHARMELEON +	ld a, CHARIZARD +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .find_duplicates +	ld a, CHARMANDER +	ld b, CHARMELEON +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_duplicates +	ld a, CHARMELEON +	ld b, CHARIZARD +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_duplicates +	ld b, VULPIX +	ld a, NINETAILS1 +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .find_duplicates +	ld a, VULPIX +	ld b, NINETAILS1 +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_duplicates +	ld b, GROWLITHE +	ld a, ARCANINE2 +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .find_duplicates +	ld a, GROWLITHE +	ld b, ARCANINE2 +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_duplicates +	ld b, EEVEE +	ld a, FLAREON2 +	call LookForCardIDInDeck_GivenCardIDInHandAndPlayArea +	jr c, .find_duplicates +	ld a, EEVEE +	ld b, FLAREON2 +	call LookForCardIDInDeck_GivenCardIDInHand +	jr c, .find_duplicates +	jr .no_carry + +; a card in deck was found to look for, +; check if there are duplicates in hand to trade with. +.find_duplicates +	ld [wce1a], a +	call FindDuplicatePokemonCards +	jr c, .set_carry +.no_carry +	or a +	ret +.set_carry +	scf +	ret +; 0x2219b + +Func_2219b: ; 2219b (8:219b) +	INCROM $2219b, $227f6 + +; lists in wDuelTempList all the basic energy cards +; in card location of a. +; outputs in a number of cards found. +; returns carry if none were found. +; input: +;   a = CARD_LOCATION_* to look +; output: +;   a = number of cards found +FindBasicEnergyCardsInLocation: ; 227f6 (8:67f6) +	ld [wTempAI], a +	lb de, 0, 0 +	ld hl, wDuelTempList + +; d = number of basic energy cards found +; e = current card in deck +; loop entire deck +.loop +	ld a, DUELVARS_CARD_LOCATIONS +	add e +	push hl +	call GetTurnDuelistVariable +	ld hl, wTempAI +	cp [hl] +	pop hl +	jr nz, .next_card + +; is in the card location we're looking for +	ld a, e +	push de +	push hl +	call GetCardIDFromDeckIndex +	pop hl +	ld a, e +	pop de +	cp DOUBLE_COLORLESS_ENERGY +	; only basic energy cards +	; will set carry here +	jr nc, .next_card + +; is a basic energy card +; add this card to the TempList +	ld a, e +	ld [hli], a +	inc d +.next_card +	inc e +	ld a, DECK_SIZE +	cp e +	jr nz, .loop + +; check if any were found +	ld a, d +	or a +	jr z, .set_carry + +; some were found, add the termination byte on TempList +	ld a, $ff +	ld [hl], a +	ld a, d +	ret + +.set_carry +	scf +	ret +; 0x2282e  ; returns in a the card index of energy card  ; attached to Pokémon in Play Area location a, -; that is to be discarded. -GetEnergyCardToDiscard: ; 2282e (8:682e) +; that is to be discarded by the AI for an effect. +; outputs $ff is none was found. +; input: +;	a = PLAY_AREA_* constant of card +; output: +;	a = deck index of attached energy card chosen +AIPickEnergyCardToDiscard: ; 2282e (8:682e)  ; load Pokémon's attached energy cards.  	ldh [hTempPlayAreaLocation_ff9d], a  	call CreateArenaOrBenchEnergyCardList @@ -994,8 +6345,206 @@ GetEnergyCardToDiscard: ; 2282e (8:682e)  	ret  ; 0x22875 -Func_22875: ; 22875 (8:6875) -	INCROM $22875, $2297b +; returns in a the deck index of an energy card attached to card +; in player's Play Area location a to remove. +; prioritises double colorless energy, then any useful energy, +; then defaults to the first energy card attached if neither +; of those are found. +; returns $ff in a if there are no energy cards attached. +; input: +;   a = Play Area location to check +; output: +;   a = deck index of attached energy card +PickAttachedEnergyCardToRemove: ; 22875 (8:6875) +; construct energy list and check if there are any energy cards attached +	ldh [hTempPlayAreaLocation_ff9d], a +	call CreateArenaOrBenchEnergyCardList +	ldh a, [hTempPlayAreaLocation_ff9d] +	ld e, a +	call GetPlayAreaCardAttachedEnergies +	ld a, [wTotalAttachedEnergies] +	or a +	jr z, .no_energy + +; load card data and store its type +	ldh a, [hTempPlayAreaLocation_ff9d] +	ld b, a +	ld a, DUELVARS_ARENA_CARD +	add b +	call GetTurnDuelistVariable +	call GetCardIDFromDeckIndex +	ld a, e +	ld [wTempCardID], a +	call LoadCardDataToBuffer1_FromCardID +	ld a, [wLoadedCard1Type] +	or TYPE_ENERGY +	ld [wTempCardType], a + +; first look for any double colorless energy +	ld hl, wDuelTempList +.loop_1 +	ld a, [hl] +	cp $ff +	jr z, .check_useful +	push hl +	call GetCardIDFromDeckIndex +	ld a, e +	cp DOUBLE_COLORLESS_ENERGY +	pop hl +	jr z, .found +	inc hl +	jr .loop_1 + +; then look for any energy cards that are useful +.check_useful +	ld hl, wDuelTempList +.loop_2 +	ld a, [hl] +	cp $ff +	jr z, .default +	farcall CheckIfEnergyIsUseful +	jr c, .found +	inc hl +	jr .loop_2 + +; return the energy card that was found +.found +	ld a, [hl] +	ret + +; if none were found with the above criteria, +; just return the first option +.default +	ld hl, wDuelTempList +	ld a, [hl] +	ret + +; return $ff if no energy cards attached +.no_energy +	ld a, $ff +	ret +; 0x228d1 + +; stores in wTempAI and wCurCardCanAttack the deck indices +; of energy cards attached to card in Play Area location a. +; prioritises double colorless energy, then any useful energy, +; then defaults to the first two energy cards attached if neither +; of those are found. +; returns $ff in a if there are no energy cards attached. +; input: +;   a = Play Area location to check +; output: +;   [wTempAI] = deck index of attached energy card +;   [wCurCardCanAttack] = deck index of attached energy card +PickTwoAttachedEnergyCards: ; 228d1 (8:68d1) +	ldh [hTempPlayAreaLocation_ff9d], a +	call CreateArenaOrBenchEnergyCardList +	ldh a, [hTempPlayAreaLocation_ff9d] +	ld e, a +	farcall CountNumberOfEnergyCardsAttached +	cp 2 +	jp c, .not_enough + +; load card data and store its type +	ldh a, [hTempPlayAreaLocation_ff9d] +	ld b, a +	ld a, DUELVARS_ARENA_CARD +	add b +	call GetTurnDuelistVariable +	call GetCardIDFromDeckIndex +	ld a, e +	ld [wTempCardID], a +	call LoadCardDataToBuffer1_FromCardID +	ld a, [wLoadedCard1Type] +	or TYPE_ENERGY +	ld [wTempCardType], a +	ld a, $ff +	ld [wTempAI], a +	ld [wCurCardCanAttack], a + +; first look for any double colorless energy +	ld hl, wDuelTempList +.loop_1 +	ld a, [hl] +	cp $ff +	jr z, .check_useful +	push hl +	call GetCardIDFromDeckIndex +	ld a, e +	cp DOUBLE_COLORLESS_ENERGY +	pop hl +	jr z, .found_double_colorless +	inc hl +	jr .loop_1 +.found_double_colorless +	ld a, [wTempAI] +	cp $ff +	jr nz, .already_chosen_1 +	ld a, [hli] +	ld [wTempAI], a +	jr .loop_1 +.already_chosen_1 +	ld a, [hl] +	ld [wCurCardCanAttack], a +	jr .done + +; then look for any energy cards that are useful +.check_useful +	ld hl, wDuelTempList +.loop_2 +	ld a, [hl] +	cp $ff +	jr z, .default +	farcall CheckIfEnergyIsUseful +	jr c, .found_useful +	inc hl +	jr .loop_2 +.found_useful +	ld a, [wTempAI] +	cp $ff +	jr nz, .already_chosen_2 +	ld a, [hli] +	ld [wTempAI], a +	jr .loop_2 +.already_chosen_2 +	ld a, [hl] +	ld [wCurCardCanAttack], a +	jr .done + +; if none were found with the above criteria, +; just return the first 2 options +.default +	ld hl, wDuelTempList +	ld a, [wTempAI] +	cp $ff +	jr nz, .pick_one_card + +; pick 2 cards +	ld a, [hli] +	ld [wTempAI], a +	ld a, [hl] +	ld [wCurCardCanAttack], a +	jr .done +.pick_one_card +	ld a, [wTempAI] +	ld b, a +.loop_3 +	ld a, [hli] +	cp b +	jr z, .loop_3 ; already picked +	ld [wCurCardCanAttack], a + +.done +	ld a, [wCurCardCanAttack] +	ld b, a +	ld a, [wTempAI] +	ret + +; return $ff if no energy cards attached +.not_enough +	ld a, $ff +	ret +; 0x2297b  ; copies $ff terminated buffer from hl to de  CopyBuffer: ; 2297b (8:697b) @@ -1007,15 +6556,29 @@ CopyBuffer: ; 2297b (8:697b)  	jr CopyBuffer  ; 0x22983 -Func_22983: ; 22983 (8:6983) -	INCROM $22983, $22990 +; zeroes a bytes starting at hl +ClearMemory_Bank8: ; 22983 (8:6983) +	push af +	push bc +	push hl +	ld b, a +	xor a +.loop +	ld [hli], a +	dec b +	jr nz, .loop +	pop hl +	pop bc +	pop af +	ret +; 0x22990  ; counts number of energy cards found in hand  ; and outputs result in a  ; sets carry if none are found  ; output:  ; 	a = number of energy cards found -CountEnergyCardsInHand: ; 22990 (8:6990) +CountOppEnergyCardsInHand: ; 22990 (8:6990)  	farcall CreateEnergyCardListFromHand  	ret c  	ld b, -1 @@ -1030,14 +6593,544 @@ CountEnergyCardsInHand: ; 22990 (8:6990)  	ret  ; 0x229a3 -Func_229a3 ; 229a3 (8:69a3) -	INCROM $229a3, $22bad +; converts HP in a to number of equivalent damage counters +; input: +; 	a = HP +; output: +; 	a = number of damage counters +ConvertHPToCounters: ; 229a3 (8:69a3) +	push bc +	ld c, 0 +.loop +	sub 10 +	jr c, .carry +	inc c +	jr .loop +.carry +	ld a, c +	pop bc +	ret +; 0x229b0 + +; calculates floor(hl / 10) +CalculateWordTensDigit: ; 229b0 (8:69b0) +	push bc +	push de +	lb bc, $ff, -10 +	lb de, $ff, -1 +.asm_229b8 +	inc de +	add hl, bc +	jr c, .asm_229b8 +	ld h, d +	ld l, e +	pop de +	pop bc +	ret +; 0x229c1 + +; returns in a division of b by a +CalculateBDividedByA_Bank8: ; 229c1 (8:69c1) +	push bc +	ld c, a +	ld a, b +	ld b, c +	ld c, 0 +.loop +	sub b +	jr c, .done +	inc c +	jr .loop +.done +	ld a, c +	pop bc +	ret +; 0x229d0 + +; returns in a the deck index of the first +; instance of card with ID equal to the ID in e +; in card location a. +; returns carry if found. +; input: +;   a = CARD_LOCATION_* +;   e = card ID to look for +LookForCardIDInLocation: ; 229d0 (8:69d0) +	ld b, a +	ld c, e +	lb de, $00, 0 ; d is never used +.loop +	ld a, DUELVARS_CARD_LOCATIONS +	add e +	call GetTurnDuelistVariable +	cp b +	jr nz, .next +	ld a, e +	push de +	call GetCardIDFromDeckIndex +	ld a, e +	pop de +	cp c +	jr z, .found +.next +	inc e +	ld a, DECK_SIZE +	cp e +	jr nz, .loop + +; not found +	or a +	ret +.found +	ld a, e +	scf +	ret +; 0x229f3 + +; return carry if card ID loaded in a is found in hand +; and outputs in a the deck index of that card +; input: +;	a = card ID +; output: +; 	a = card deck index, if found +;	carry set if found +LookForCardIDInHandList_Bank8: ; 229f3 (8:69f3) +	ld [wTempCardIDToLook], a +	call CreateHandCardList +	ld hl, wDuelTempList + +.loop +	ld a, [hli] +	cp $ff +	ret z + +	ldh [hTempCardIndex_ff98], a +	call LoadCardDataToBuffer1_FromDeckIndex +	ld b, a +	ld a, [wTempCardIDToLook] +	cp b +	jr nz, .loop + +	ldh a, [hTempCardIndex_ff98] +	scf +	ret +; 0x22a10 + +; searches in deck for card ID 1 in a, and +; if found, searches in Hand/Play Area for card ID 2 in b, and +; if found, searches for card ID 1 in Hand/Play Area, and +; if none found, return carry and output deck index +; of the card ID 1 in deck. +; input: +;   a = card ID 1 +;   b = card ID 2 +; output: +;   a = index of card ID 1 in deck +LookForCardIDInDeck_GivenCardIDInHandAndPlayArea: ; 22a10 (8:6a10) +; store a in wCurCardCanAttack +; and b in wTempAI +	ld c, a +	ld a, b +	ld [wTempAI], a +	ld a, c +	ld [wCurCardCanAttack], a + +; look for the card ID 1 in deck +	ld e, a +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	ret nc + +; was found, store its deck index in memory +	ld [wTempAIPokemonCard], a + +; look for the card ID 2 +; in Hand and Play Area, return if not found. +	ld a, [wTempAI] +	call LookForCardIDInHandAndPlayArea +	ret nc + +; look for the card ID 1 in the Hand and Play Area +; if any card is found, return no carry. +	ld a, [wCurCardCanAttack] +	call LookForCardIDInHandAndPlayArea +	jr c, .no_carry +; none found + +	ld a, [wTempAIPokemonCard] +	scf +	ret + +.no_carry +	or a +	ret +; 0x22a39 + +; returns carry if card ID in a +; is found in Play Area or in hand +; input: +;	a = card ID +LookForCardIDInHandAndPlayArea: ; 22a39 (8:6a39) +	ld b, a +	push bc +	call LookForCardIDInHandList_Bank8 +	pop bc +	ret c + +	ld a, b +	ld b, PLAY_AREA_ARENA +	call LookForCardIDInPlayArea_Bank8 +	ret c +	or a +	ret +; 0x22a49 + +; searches in deck for card ID 1 in a, and +; if found, searches in Hand Area for card ID 2 in b, and +; if found, searches for card ID 1 in Hand/Play Area, and +; if none found, return carry and output deck index +; of the card ID 1 in deck. +; input: +;   a = card ID 1 +;   b = card ID 2 +; output: +;   a = index of card ID 1 in deck +LookForCardIDInDeck_GivenCardIDInHand: ; 22a49 (8:6a49) +; store a in wCurCardCanAttack +; and b in wTempAI +	ld c, a +	ld a, b +	ld [wTempAI], a +	ld a, c +	ld [wCurCardCanAttack], a + +; look for the card ID 1 in deck +	ld e, a +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	ret nc + +; was found, store its deck index in memory +	ld [wTempAIPokemonCard], a + +; look for the card ID 2 in hand, return if not found. +	ld a, [wTempAI] +	call LookForCardIDInHandList_Bank8 +	ret nc + +; look for the card ID 1 in the Hand and Play Area +; if any card is found, return no carry. +	ld a, [wCurCardCanAttack] +	call LookForCardIDInHandAndPlayArea +	jr c, .no_carry +; none found + +	ld a, [wTempAIPokemonCard] +	scf +	ret + +.no_carry +	or a +	ret +; 0x22a72 + +; 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 +; ouput: +;	a = PLAY_AREA_* of found card +;	carry set if found +LookForCardIDInPlayArea_Bank8: ; 22a72 (8:6a72) +	ld [wTempCardIDToLook], a +.loop +	ld a, DUELVARS_ARENA_CARD +	add b +	call GetTurnDuelistVariable +	cp $ff +	ret z + +	call LoadCardDataToBuffer1_FromDeckIndex +	ld c, a +	ld a, [wTempCardIDToLook] +	cp c +	jr z, .is_same + +	inc b +	ld a, MAX_PLAY_AREA_POKEMON +	cp b +	jr nz, .loop +	ld b, $ff +	or a +	ret + +.is_same +	ld a, b +	scf +	ret +; 0x22a95 + +; runs through list avoiding card in e. +; removes first card in list not equal to e +; and that has a type allowed to be removed, in d. +; returns carry if successful in finding a card. +; input: +;   d = type of card allowed to be removed +;       ($00 = Trainer, $01 = Pokemon, $02 = Energy) +;   e = card deck index to avoid removing +; output: +;   a = card index of removed card +RemoveFromListDifferentCardOfGivenType: ; 22a95 (8:6a95) +	push hl +	push de +	push bc +	call CountCardsInDuelTempList +	call ShuffleCards + +; loop list until a card with +; deck index different from e is found. +.loop_list +	ld a, [hli] +	cp $ff +	jr z, .no_carry +	cp e +	jr z, .loop_list + +; get this card's type +	ldh [hTempCardIndex_ff98], a +	push de +	call GetCardIDFromDeckIndex +	call GetCardType +	pop de +	cp TYPE_ENERGY +	jr c, .pkmn_card +	cp TYPE_TRAINER +	jr nz, .energy + +; only remove from list specific type. + +; trainer +	ld a, d +	or a +	jr nz, .loop_list +	jr .remove_card +.energy +	ld a, d +	cp $02 +	jr nz, .loop_list +	jr .remove_card +.pkmn_card +	ld a, d +	cp $01 +	jr nz, .loop_list +	; fallthrough + +.remove_card +	ld d, h +	ld e, l +	dec hl +.loop_remove +	ld a, [de] +	inc de +	ld [hli], a +	cp $ff +	jr nz, .loop_remove + +; success +	ldh a, [hTempCardIndex_ff98] +	pop bc +	pop de +	pop hl +	scf +	ret +.no_carry +	pop bc +	pop de +	pop hl +	or a +	ret +; 0x22ae0 + +; used in Pokemon Trader checks to look for a specific +; card in the deck to trade with a card in hand that +; has a card ID different from e. +; returns carry if successful. +; input: +;   a = card ID 1 +;   e = card ID 2 +; output: +;   a = deck index of card ID 1 found in deck +;   e = deck index of Pokemon card in hand dfferent than card ID 2 +LookForCardIDToTradeWithDifferentHandCard: ; 22ae0 (8:6ae0) +	ld hl, wCurCardCanAttack +	ld [hl], e +	ld [wTempAI], a + +; if card ID 1 is in hand, return no carry. +	call LookForCardIDInHandList_Bank8 +	jr c, .no_carry + +; if card ID 1 is not in deck, return no carry. +	ld a, [wTempAI] +	ld e, a +	ld a, CARD_LOCATION_DECK +	call LookForCardIDInLocation +	jr nc, .no_carry + +; store its deck index +	ld [wTempAI], a + +; look in hand for Pokemon card ID that +; is different from card ID 2. +	ld a, [wCurCardCanAttack] +	ld c, a +	call CreateHandCardList +	ld hl, wDuelTempList + +.loop_hand +	ld a, [hli] +	cp $ff +	jr z, .no_carry +	ld b, a +	call LoadCardDataToBuffer1_FromDeckIndex +	cp c +	jr z, .loop_hand +	ld a, [wLoadedCard1Type] +	cp TYPE_ENERGY +	jr nc, .loop_hand + +; found, output deck index of card ID 1 in deck +; and deck index of card found in hand, and set carry +	ld e, b +	ld a, [wTempAI] +	scf +	ret + +.no_carry +	or a +	ret +; 0x22b1f + +; returns carry if at least one card in the hand +; has the card ID of input. Outputs its index. +; input: +;   a = card ID to look for +; output: +;   a = deck index of card in hand found +CheckIfHasCardIDInHand: ; 22b1f (8:6b1f) +	ld [wTempCardIDToLook], a +	call CreateHandCardList +	ld hl, wDuelTempList +	ld c, 0 + +.loop_hand +	ld a, [hli] +	cp $ff +	ret z +	ldh [hTempCardIndex_ff98], a +	call LoadCardDataToBuffer1_FromDeckIndex +	ld b, a +	ld a, [wTempCardIDToLook] +	cp b +	jr nz, .loop_hand +	ld a, c +	or a +	jr nz, .set_carry +	inc c +	jr nz, .loop_hand + +.set_carry +	ldh a, [hTempCardIndex_ff98] +	scf +	ret +; 0x22b45 + +; outputs in a total number of Pokemon cards in hand +; plus Pokemon in Turn Duelist's Play Area. +CountPokemonCardsInHandAndInPlayArea: ; 22b45 (8:6b45) +	ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA +	call GetTurnDuelistVariable +	ld [wTempAI], a +	call CreateHandCardList +	ld hl, wDuelTempList +.loop_hand +	ld a, [hli] +	cp $ff +	jr z, .done +	call GetCardIDFromDeckIndex +	call GetCardType +	cp TYPE_ENERGY +	jr nc, .loop_hand +	ld a, [wTempAI] +	inc a +	ld [wTempAI], a +	jr .loop_hand +.done +	ld a, [wTempAI] +	ret +; 0x22b6f + +; returns carry if a duplicate Pokemon card is found in hand. +; outputs in a the deck index of one of them. +FindDuplicatePokemonCards: ; 22b6f (8:6b6f) +	ld a, $ff +	ld [wTempAI], a +	call CreateHandCardList +	ld hl, wDuelTempList +	push hl + +.loop_hand_outer +	pop hl +	ld a, [hli] +	cp $ff +	jr z, .done +	call GetCardIDFromDeckIndex +	ld b, e +	push hl + +.loop_hand_inner +	ld a, [hli] +	cp $ff +	jr z, .loop_hand_outer +	ld c, a +	call GetCardIDFromDeckIndex +	ld a, e +	cp b +	jr nz, .loop_hand_inner + +; found two cards with same ID, +; if they are Pokemon cards, store its deck index. +	push bc +	call GetCardType +	pop bc +	cp TYPE_ENERGY +	jr nc, .loop_hand_outer +	ld a, c +	ld [wTempAI], a +	; for some reason loop still continues +	; even though if some other duplicate +	; cards are found, it overwrites the result. +	jr .loop_hand_outer + +.done +	ld a, [wTempAI] +	cp $ff +	jr z, .no_carry + +; found +	scf +	ret +.no_carry +	or a +	ret +; 0x22bad  ; return carry flag if move is not high recoil.  Func_22bad: ; 22bad (8:6bad)  	farcall Func_169ca  	ret nc -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	ld e, a  	ld a, DUELVARS_ARENA_CARD  	call GetTurnDuelistVariable @@ -1049,5 +7142,6 @@ Func_22bad: ; 22bad (8:6bad)  	ret  ; 0x22bc6 -Func_22bc6 ; 22bc6 (8:6bc6) -	INCROM $22bc6, $24000 +rept $143a +	db $ff +endr diff --git a/src/engine/home.asm b/src/engine/home.asm index b7374aa..545995a 100644 --- a/src/engine/home.asm +++ b/src/engine/home.asm @@ -4376,7 +4376,7 @@ Func_161e: ; 161e (0:161e)  ; 0x16ad  ; copies, given a card identified by register a (card ID): -; - e into wSelectedMoveIndex and d into hTempCardIndex_ff9f +; - e into wSelectedAttack and d into hTempCardIndex_ff9f  ; - Move1 (if e == 0) or Move2 (if e == 1) data into wLoadedMove  ; - Also from that move, its Damage field into wDamage  ; finally, clears wNoDamageOrEffect and wDealtDamage @@ -4384,7 +4384,7 @@ CopyMoveDataAndDamage_FromCardID: ; 16ad (0:16ad)  	push de  	push af  	ld a, e -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	ld a, d  	ldh [hTempCardIndex_ff9f], a  	pop af @@ -4395,13 +4395,13 @@ CopyMoveDataAndDamage_FromCardID: ; 16ad (0:16ad)  	jr CopyMoveDataAndDamage  ; copies, given a card identified by register d (0-59 deck index): -; - e into wSelectedMoveIndex and d into hTempCardIndex_ff9f +; - e into wSelectedAttack and d into hTempCardIndex_ff9f  ; - Move1 (if e == 0) or Move2 (if e == 1) data into wLoadedMove  ; - Also from that move, its Damage field into wDamage  ; finally, clears wNoDamageOrEffect and wDealtDamage  CopyMoveDataAndDamage_FromDeckIndex: ; 16c0 (0:16c0)  	ld a, e -	ld [wSelectedMoveIndex], a +	ld [wSelectedAttack], a  	ld a, d  	ldh [hTempCardIndex_ff9f], a  	call LoadCardDataToBuffer1_FromDeckIndex @@ -4465,7 +4465,7 @@ Func_16f6: ; 16f6 (0:16f6)  ; Use an attack (from DuelMenu_Attack) or a Pokemon Power (from DuelMenu_PkmnPower)  UseAttackOrPokemonPower: ; 1730 (0:1730) -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	ld [wPlayerAttackingMoveIndex], a  	ldh a, [hTempCardIndex_ff9f]  	ld [wPlayerAttackingCardIndex], a @@ -5259,7 +5259,7 @@ MoveCardToDiscardPileIfInArena: ; 1c13 (0:1c13)  	ret  ; 0x1c35 -; calculate damage of card at CARD_LOCATION_PLAY_AREA + e +; calculate damage of card at CARD_LOCATION_* in e  ; return the result in a  GetCardDamage: ; 1c35 (0:1c35)  	push hl @@ -9858,7 +9858,7 @@ HandleCantAttackSubstatus: ; 33c1 (0:33c1)  	ret  ; return carry if the turn holder's arena Pokemon cannot use -; selected move at wSelectedMoveIndex due to amnesia +; selected move at wSelectedAttack due to amnesia  HandleAmnesiaSubstatus: ; 33e1 (0:33e1)  	ld a, DUELVARS_ARENA_CARD_SUBSTATUS2  	call GetTurnDuelistVariable @@ -9874,7 +9874,7 @@ HandleAmnesiaSubstatus: ; 33e1 (0:33e1)  .affected_by_amnesia  	ld a, DUELVARS_ARENA_CARD_DISABLED_MOVE_INDEX  	call GetTurnDuelistVariable -	ld a, [wSelectedMoveIndex] +	ld a, [wSelectedAttack]  	cp [hl]  	jr nz, .not_the_disabled_move  	ldtx hl, UnableToUseAttackDueToAmnesiaText | 
