Split bank 8

This commit is contained in:
ElectroDeoxys 2021-06-07 16:33:15 +01:00
parent 36ef80903a
commit 09239933ed
29 changed files with 2281 additions and 2280 deletions

View File

@ -134,7 +134,7 @@ Each deck AI lists some Pokémon card IDs that have an associated score for retr
However, the game never actually stores the pointer to these lists (a notable expection being the Legendary Moltres deck), so the AI cannot access these score modifiers.
**Fix:** Edit all applicable decks in `src/engine/deck_ai/decks/`, uncommenting the following line:
**Fix:** Edit all applicable decks in `src/engine/ai/decks/`, uncommenting the following line:
```diff
.store_list_pointers
store_list_pointer wAICardListAvoidPrize, .list_prize
@ -283,7 +283,7 @@ AIDecide_PokemonTrader_PowerGenerator: ; 2200b (8:600b)
## AI never uses Energy Trans in order to retreat Arena card
There is a mistake in the AI retreat logic, in [src/engine/deck_ai/decks/general.asm](https://github.com/pret/poketcg/blob/master/src/engine/deck_ai/decks/general.asm):
There is a mistake in the AI retreat logic, in [src/engine/ai/decks/general.asm](https://github.com/pret/poketcg/blob/master/src/engine/ai/decks/general.asm):
```
.used_switch
; if AI used switch, unset its AI flag
@ -308,7 +308,7 @@ There is a mistake in the AI retreat logic, in [src/engine/deck_ai/decks/general
## Sam's practice deck does wrong card ID check
There is a mistake in the AI logic for deciding which Pokémon for Sam to switch to, in [src/engine/deck_ai/decks/sams_practice.asm](https://github.com/pret/poketcg/blob/master/src/engine/deck_ai/decks/sams_practice.asm):
There is a mistake in the AI logic for deciding which Pokémon for Sam to switch to, in [src/engine/ai/decks/sams_practice.asm](https://github.com/pret/poketcg/blob/master/src/engine/ai/decks/sams_practice.asm):
```
; this is a bug, it's attempting to compare a card ID with a deck index.
; the intention was to change the card to switch to depending on whether

View File

@ -0,0 +1,47 @@
ai_trainer_card_logic: MACRO
db \1 ; AI_TRAINER_CARD_PHASE_* constant
db \2 ; ID of trainer card
dw \3 ; function for AI decision to play card
dw \4 ; function for AI playing the card
ENDM
AITrainerCardLogic: ; 20000 (8:4000)
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_07, POTION, AIDecide_Potion1, AIPlay_Potion
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_10, POTION, AIDecide_Potion2, AIPlay_Potion
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_08, SUPER_POTION, AIDecide_SuperPotion1, AIPlay_SuperPotion
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_11, SUPER_POTION, AIDecide_SuperPotion2, AIPlay_SuperPotion
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_13, DEFENDER, AIDecide_Defender1, AIPlay_Defender
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_14, DEFENDER, AIDecide_Defender2, AIPlay_Defender
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_13, PLUSPOWER, AIDecide_Pluspower1, AIPlay_Pluspower
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_14, PLUSPOWER, AIDecide_Pluspower2, AIPlay_Pluspower
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_09, SWITCH, AIDecide_Switch, AIPlay_Switch
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_07, GUST_OF_WIND, AIDecide_GustOfWind, AIPlay_GustOfWind
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_10, GUST_OF_WIND, AIDecide_GustOfWind, AIPlay_GustOfWind
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_04, BILL, AIDecide_Bill, AIPlay_Bill
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_05, ENERGY_REMOVAL, AIDecide_EnergyRemoval, AIPlay_EnergyRemoval
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_05, SUPER_ENERGY_REMOVAL, AIDecide_SuperEnergyRemoval, AIPlay_SuperEnergyRemoval
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_07, POKEMON_BREEDER, AIDecide_PokemonBreeder, AIPlay_PokemonBreeder
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_15, PROFESSOR_OAK, AIDecide_ProfessorOak, AIPlay_ProfessorOak
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_10, ENERGY_RETRIEVAL, AIDecide_EnergyRetrieval, AIPlay_EnergyRetrieval
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_11, SUPER_ENERGY_RETRIEVAL, AIDecide_SuperEnergyRetrieval, AIPlay_SuperEnergyRetrieval
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_06, POKEMON_CENTER, AIDecide_PokemonCenter, AIPlay_PokemonCenter
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_07, IMPOSTER_PROFESSOR_OAK, AIDecide_ImposterProfessorOak, AIPlay_ImposterProfessorOak
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_12, ENERGY_SEARCH, AIDecide_EnergySearch, AIPlay_EnergySearch
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_03, POKEDEX, AIDecide_Pokedex, AIPlay_Pokedex
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_07, FULL_HEAL, AIDecide_FullHeal, AIPlay_FullHeal
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_10, MR_FUJI, AIDecide_MrFuji, AIPlay_MrFuji
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_10, SCOOP_UP, AIDecide_ScoopUp, AIPlay_ScoopUp
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_02, MAINTENANCE, AIDecide_Maintenance, AIPlay_Maintenance
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_03, RECYCLE, AIDecide_Recycle, AIPlay_Recycle
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_13, LASS, AIDecide_Lass, AIPlay_Lass
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_04, ITEM_FINDER, AIDecide_ItemFinder, AIPlay_ItemFinder
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_01, IMAKUNI_CARD, AIDecide_Imakuni, AIPlay_Imakuni
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_01, GAMBLER, AIDecide_Gambler, AIPlay_Gambler
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_05, REVIVE, AIDecide_Revive, AIPlay_Revive
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_13, POKEMON_FLUTE, AIDecide_PokemonFlute, AIPlay_PokemonFlute
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_05, CLEFAIRY_DOLL, AIDecide_ClefairyDollOrMysteriousFossil, AIPlay_ClefairyDollOrMysteriousFossil
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_05, MYSTERIOUS_FOSSIL, AIDecide_ClefairyDollOrMysteriousFossil, AIPlay_ClefairyDollOrMysteriousFossil
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_02, POKE_BALL, AIDecide_Pokeball, AIPlay_Pokeball
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_02, COMPUTER_SEARCH, AIDecide_ComputerSearch, AIPlay_ComputerSearch
ai_trainer_card_logic AI_TRAINER_CARD_PHASE_02, POKEMON_TRADER, AIDecide_PokemonTrader, AIPlay_PokemonTrader
db $ff

970
src/engine/ai/common.asm Normal file
View File

@ -0,0 +1,970 @@
; runs through Player's whole deck and
; sets carry if there's any Pokemon other
; than Mewtwo1.
CheckIfPlayerHasPokemonOtherThanMewtwo1: ; 227a9 (8:67a9)
call SwapTurn
ld e, 0
.loop_deck
ld a, e
push de
call LoadCardDataToBuffer2_FromDeckIndex
pop de
ld a, [wLoadedCard2Type]
cp TYPE_ENERGY
jp nc, .next ; can be a jr
ld a, [wLoadedCard2ID]
cp MEWTWO1
jr nz, .not_mewtwo1
.next
inc e
ld a, DECK_SIZE
cp e
jr nz, .loop_deck
; no carry
call SwapTurn
or a
ret
.not_mewtwo1
call SwapTurn
scf
ret
; returns no carry if, given the Player is using a Mewtwo1 mill deck,
; the AI already has a Bench fully set up, in which case it
; will process some Trainer cards in hand (namely Energy Removals).
; this is used to check whether to skip some normal AI routines
; this turn and jump right to the attacking phase.
HandleAIAntiMewtwoDeckStrategy: ; 227d3 (8:67d3)
; return carry if Player is not playing Mewtwo1 mill deck
ld a, [wAIBarrierFlagCounter]
bit AI_MEWTWO_MILL_F, a
jr z, .set_carry
; else, check if there's been less than 2 turns
; without the Player using Barrier.
cp AI_MEWTWO_MILL + 2
jr c, .count_bench
; if there has been, reset wAIBarrierFlagCounter
; and return carry.
xor a
ld [wAIBarrierFlagCounter], a
jr .set_carry
; else, check number of Pokemon that are set up in Bench
; if less than 4, return carry.
.count_bench
farcall CountNumberOfSetUpBenchPokemon
cp 4
jr c, .set_carry
; if there's at least 4 Pokemon in the Bench set up,
; process Trainer hand cards of AI_TRAINER_CARD_PHASE_05
ld a, AI_TRAINER_CARD_PHASE_05
farcall AIProcessHandTrainerCards
or a
ret
.set_carry
scf
ret
; lists in wDuelTempList all the basic energy cards
; in card location of a.
; outputs in a number of cards found.
; returns carry if none were found.
; input:
; a = CARD_LOCATION_* to look
; output:
; a = number of cards found
FindBasicEnergyCardsInLocation: ; 227f6 (8:67f6)
ld [wTempAI], a
lb de, 0, 0
ld hl, wDuelTempList
; d = number of basic energy cards found
; e = current card in deck
; loop entire deck
.loop
ld a, DUELVARS_CARD_LOCATIONS
add e
push hl
call GetTurnDuelistVariable
ld hl, wTempAI
cp [hl]
pop hl
jr nz, .next_card
; is in the card location we're looking for
ld a, e
push de
push hl
call GetCardIDFromDeckIndex
pop hl
ld a, e
pop de
cp DOUBLE_COLORLESS_ENERGY
; only basic energy cards
; will set carry here
jr nc, .next_card
; is a basic energy card
; add this card to the TempList
ld a, e
ld [hli], a
inc d
.next_card
inc e
ld a, DECK_SIZE
cp e
jr nz, .loop
; check if any were found
ld a, d
or a
jr z, .set_carry
; some were found, add the termination byte on TempList
ld a, $ff
ld [hl], a
ld a, d
ret
.set_carry
scf
ret
; returns in a the card index of energy card
; attached to Pokémon in Play Area location a,
; that is to be discarded by the AI for an effect.
; outputs $ff is none was found.
; input:
; a = PLAY_AREA_* constant of card
; output:
; a = deck index of attached energy card chosen
AIPickEnergyCardToDiscard: ; 2282e (8:682e)
; load Pokémon's attached energy cards.
ldh [hTempPlayAreaLocation_ff9d], a
call CreateArenaOrBenchEnergyCardList
ldh a, [hTempPlayAreaLocation_ff9d]
ld e, a
call GetPlayAreaCardAttachedEnergies
ld a, [wTotalAttachedEnergies]
or a
jr z, .no_energy
; load card's ID and type.
ldh a, [hTempPlayAreaLocation_ff9d]
ld b, a
ld a, DUELVARS_ARENA_CARD
add b
call GetTurnDuelistVariable
call GetCardIDFromDeckIndex
ld a, e
ld [wTempCardID], a
call LoadCardDataToBuffer1_FromCardID
ld a, [wLoadedCard1Type]
or TYPE_ENERGY
ld [wTempCardType], a
; find a card that is not useful.
; if none is found, just return the first energy card attached.
ld hl, wDuelTempList
.loop
ld a, [hl]
cp $ff
jr z, .not_found
farcall CheckIfEnergyIsUseful
jr nc, .found
inc hl
jr .loop
.found
ld a, [hl]
ret
.not_found
ld hl, wDuelTempList
ld a, [hl]
ret
.no_energy
ld a, $ff
ret
; returns in a the deck index of an energy card attached to card
; in player's Play Area location a to remove.
; prioritizes double colorless energy, then any useful energy,
; then defaults to the first energy card attached if neither
; of those are found.
; returns $ff in a if there are no energy cards attached.
; input:
; a = Play Area location to check
; output:
; a = deck index of attached energy card
PickAttachedEnergyCardToRemove: ; 22875 (8:6875)
; construct energy list and check if there are any energy cards attached
ldh [hTempPlayAreaLocation_ff9d], a
call CreateArenaOrBenchEnergyCardList
ldh a, [hTempPlayAreaLocation_ff9d]
ld e, a
call GetPlayAreaCardAttachedEnergies
ld a, [wTotalAttachedEnergies]
or a
jr z, .no_energy
; load card data and store its type
ldh a, [hTempPlayAreaLocation_ff9d]
ld b, a
ld a, DUELVARS_ARENA_CARD
add b
call GetTurnDuelistVariable
call GetCardIDFromDeckIndex
ld a, e
ld [wTempCardID], a
call LoadCardDataToBuffer1_FromCardID
ld a, [wLoadedCard1Type]
or TYPE_ENERGY
ld [wTempCardType], a
; first look for any double colorless energy
ld hl, wDuelTempList
.loop_1
ld a, [hl]
cp $ff
jr z, .check_useful
push hl
call GetCardIDFromDeckIndex
ld a, e
cp DOUBLE_COLORLESS_ENERGY
pop hl
jr z, .found
inc hl
jr .loop_1
; then look for any energy cards that are useful
.check_useful
ld hl, wDuelTempList
.loop_2
ld a, [hl]
cp $ff
jr z, .default
farcall CheckIfEnergyIsUseful
jr c, .found
inc hl
jr .loop_2
; return the energy card that was found
.found
ld a, [hl]
ret
; if none were found with the above criteria,
; just return the first option
.default
ld hl, wDuelTempList
ld a, [hl]
ret
; return $ff if no energy cards attached
.no_energy
ld a, $ff
ret
; stores in wTempAI and wCurCardCanAttack the deck indices
; of energy cards attached to card in Play Area location a.
; prioritizes double colorless energy, then any useful energy,
; then defaults to the first two energy cards attached if neither
; of those are found.
; returns $ff in a if there are no energy cards attached.
; input:
; a = Play Area location to check
; output:
; [wTempAI] = deck index of attached energy card
; [wCurCardCanAttack] = deck index of attached energy card
PickTwoAttachedEnergyCards: ; 228d1 (8:68d1)
ldh [hTempPlayAreaLocation_ff9d], a
call CreateArenaOrBenchEnergyCardList
ldh a, [hTempPlayAreaLocation_ff9d]
ld e, a
farcall CountNumberOfEnergyCardsAttached
cp 2
jp c, .not_enough
; load card data and store its type
ldh a, [hTempPlayAreaLocation_ff9d]
ld b, a
ld a, DUELVARS_ARENA_CARD
add b
call GetTurnDuelistVariable
call GetCardIDFromDeckIndex
ld a, e
ld [wTempCardID], a
call LoadCardDataToBuffer1_FromCardID
ld a, [wLoadedCard1Type]
or TYPE_ENERGY
ld [wTempCardType], a
ld a, $ff
ld [wTempAI], a
ld [wCurCardCanAttack], a
; first look for any double colorless energy
ld hl, wDuelTempList
.loop_1
ld a, [hl]
cp $ff
jr z, .check_useful
push hl
call GetCardIDFromDeckIndex
ld a, e
cp DOUBLE_COLORLESS_ENERGY
pop hl
jr z, .found_double_colorless
inc hl
jr .loop_1
.found_double_colorless
ld a, [wTempAI]
cp $ff
jr nz, .already_chosen_1
ld a, [hli]
ld [wTempAI], a
jr .loop_1
.already_chosen_1
ld a, [hl]
ld [wCurCardCanAttack], a
jr .done
; then look for any energy cards that are useful
.check_useful
ld hl, wDuelTempList
.loop_2
ld a, [hl]
cp $ff
jr z, .default
farcall CheckIfEnergyIsUseful
jr c, .found_useful
inc hl
jr .loop_2
.found_useful
ld a, [wTempAI]
cp $ff
jr nz, .already_chosen_2
ld a, [hli]
ld [wTempAI], a
jr .loop_2
.already_chosen_2
ld a, [hl]
ld [wCurCardCanAttack], a
jr .done
; if none were found with the above criteria,
; just return the first 2 options
.default
ld hl, wDuelTempList
ld a, [wTempAI]
cp $ff
jr nz, .pick_one_card
; pick 2 cards
ld a, [hli]
ld [wTempAI], a
ld a, [hl]
ld [wCurCardCanAttack], a
jr .done
.pick_one_card
ld a, [wTempAI]
ld b, a
.loop_3
ld a, [hli]
cp b
jr z, .loop_3 ; already picked
ld [wCurCardCanAttack], a
.done
ld a, [wCurCardCanAttack]
ld b, a
ld a, [wTempAI]
ret
; return $ff if no energy cards attached
.not_enough
ld a, $ff
ret
; copies $ff terminated buffer from hl to de
CopyBuffer: ; 2297b (8:697b)
ld a, [hli]
ld [de], a
cp $ff
ret z
inc de
jr CopyBuffer
; zeroes a bytes starting at hl
ClearMemory_Bank8: ; 22983 (8:6983)
push af
push bc
push hl
ld b, a
xor a
.loop
ld [hli], a
dec b
jr nz, .loop
pop hl
pop bc
pop af
ret
; counts number of energy cards found in hand
; and outputs result in a
; sets carry if none are found
; output:
; a = number of energy cards found
CountOppEnergyCardsInHand: ; 22990 (8:6990)
farcall CreateEnergyCardListFromHand
ret c
ld b, -1
ld hl, wDuelTempList
.loop
inc b
ld a, [hli]
cp $ff
jr nz, .loop
ld a, b
or a
ret
; converts HP in a to number of equivalent damage counters
; input:
; a = HP
; output:
; a = number of damage counters
ConvertHPToCounters: ; 229a3 (8:69a3)
push bc
ld c, 0
.loop
sub 10
jr c, .carry
inc c
jr .loop
.carry
ld a, c
pop bc
ret
; calculates floor(hl / 10)
CalculateWordTensDigit: ; 229b0 (8:69b0)
push bc
push de
lb bc, $ff, -10
lb de, $ff, -1
.asm_229b8
inc de
add hl, bc
jr c, .asm_229b8
ld h, d
ld l, e
pop de
pop bc
ret
; returns in a division of b by a
CalculateBDividedByA_Bank8: ; 229c1 (8:69c1)
push bc
ld c, a
ld a, b
ld b, c
ld c, 0
.loop
sub b
jr c, .done
inc c
jr .loop
.done
ld a, c
pop bc
ret
; returns in a the deck index of the first
; instance of card with ID equal to the ID in e
; in card location a.
; returns carry if found.
; input:
; a = CARD_LOCATION_*
; e = card ID to look for
LookForCardIDInLocation: ; 229d0 (8:69d0)
ld b, a
ld c, e
lb de, $00, 0 ; d is never used
.loop
ld a, DUELVARS_CARD_LOCATIONS
add e
call GetTurnDuelistVariable
cp b
jr nz, .next
ld a, e
push de
call GetCardIDFromDeckIndex
ld a, e
pop de
cp c
jr z, .found
.next
inc e
ld a, DECK_SIZE
cp e
jr nz, .loop
; not found
or a
ret
.found
ld a, e
scf
ret
; return carry if card ID loaded in a is found in hand
; and outputs in a the deck index of that card
; input:
; a = card ID
; output:
; a = card deck index, if found
; carry set if found
LookForCardIDInHandList_Bank8: ; 229f3 (8:69f3)
ld [wTempCardIDToLook], a
call CreateHandCardList
ld hl, wDuelTempList
.loop
ld a, [hli]
cp $ff
ret z
ldh [hTempCardIndex_ff98], a
call LoadCardDataToBuffer1_FromDeckIndex
ld b, a
ld a, [wTempCardIDToLook]
cp b
jr nz, .loop
ldh a, [hTempCardIndex_ff98]
scf
ret
; searches in deck for card ID 1 in a, and
; if found, searches in Hand/Play Area for card ID 2 in b, and
; if found, searches for card ID 1 in Hand/Play Area, and
; if none found, return carry and output deck index
; of the card ID 1 in deck.
; input:
; a = card ID 1
; b = card ID 2
; output:
; a = index of card ID 1 in deck
LookForCardIDInDeck_GivenCardIDInHandAndPlayArea: ; 22a10 (8:6a10)
; store a in wCurCardCanAttack
; and b in wTempAI
ld c, a
ld a, b
ld [wTempAI], a
ld a, c
ld [wCurCardCanAttack], a
; look for the card ID 1 in deck
ld e, a
ld a, CARD_LOCATION_DECK
call LookForCardIDInLocation
ret nc
; was found, store its deck index in memory
ld [wTempAIPokemonCard], a
; look for the card ID 2
; in Hand and Play Area, return if not found.
ld a, [wTempAI]
call LookForCardIDInHandAndPlayArea
ret nc
; look for the card ID 1 in the Hand and Play Area
; if any card is found, return no carry.
ld a, [wCurCardCanAttack]
call LookForCardIDInHandAndPlayArea
jr c, .no_carry
; none found
ld a, [wTempAIPokemonCard]
scf
ret
.no_carry
or a
ret
; returns carry if card ID in a
; is found in Play Area or in hand
; input:
; a = card ID
LookForCardIDInHandAndPlayArea: ; 22a39 (8:6a39)
ld b, a
push bc
call LookForCardIDInHandList_Bank8
pop bc
ret c
ld a, b
ld b, PLAY_AREA_ARENA
call LookForCardIDInPlayArea_Bank8
ret c
or a
ret
; searches in deck for card ID 1 in a, and
; if found, searches in Hand Area for card ID 2 in b, and
; if found, searches for card ID 1 in Hand/Play Area, and
; if none found, return carry and output deck index
; of the card ID 1 in deck.
; input:
; a = card ID 1
; b = card ID 2
; output:
; a = index of card ID 1 in deck
LookForCardIDInDeck_GivenCardIDInHand: ; 22a49 (8:6a49)
; store a in wCurCardCanAttack
; and b in wTempAI
ld c, a
ld a, b
ld [wTempAI], a
ld a, c
ld [wCurCardCanAttack], a
; look for the card ID 1 in deck
ld e, a
ld a, CARD_LOCATION_DECK
call LookForCardIDInLocation
ret nc
; was found, store its deck index in memory
ld [wTempAIPokemonCard], a
; look for the card ID 2 in hand, return if not found.
ld a, [wTempAI]
call LookForCardIDInHandList_Bank8
ret nc
; look for the card ID 1 in the Hand and Play Area
; if any card is found, return no carry.
ld a, [wCurCardCanAttack]
call LookForCardIDInHandAndPlayArea
jr c, .no_carry
; none found
ld a, [wTempAIPokemonCard]
scf
ret
.no_carry
or a
ret
; returns carry if card ID in a
; is found in Play Area, starting with
; location in b
; input:
; a = card ID
; b = PLAY_AREA_* to start with
; output:
; a = PLAY_AREA_* of found card
; carry set if found
LookForCardIDInPlayArea_Bank8: ; 22a72 (8:6a72)
ld [wTempCardIDToLook], a
.loop
ld a, DUELVARS_ARENA_CARD
add b
call GetTurnDuelistVariable
cp $ff
ret z
call LoadCardDataToBuffer1_FromDeckIndex
ld c, a
ld a, [wTempCardIDToLook]
cp c
jr z, .is_same
inc b
ld a, MAX_PLAY_AREA_POKEMON
cp b
jr nz, .loop
ld b, $ff
or a
ret
.is_same
ld a, b
scf
ret
; runs through list avoiding card in e.
; removes first card in list not equal to e
; and that has a type allowed to be removed, in d.
; returns carry if successful in finding a card.
; input:
; d = type of card allowed to be removed
; ($00 = Trainer, $01 = Pokemon, $02 = Energy)
; e = card deck index to avoid removing
; output:
; a = card index of removed card
RemoveFromListDifferentCardOfGivenType: ; 22a95 (8:6a95)
push hl
push de
push bc
call CountCardsInDuelTempList
call ShuffleCards
; loop list until a card with
; deck index different from e is found.
.loop_list
ld a, [hli]
cp $ff
jr z, .no_carry
cp e
jr z, .loop_list
; get this card's type
ldh [hTempCardIndex_ff98], a
push de
call GetCardIDFromDeckIndex
call GetCardType
pop de
cp TYPE_ENERGY
jr c, .pkmn_card
cp TYPE_TRAINER
jr nz, .energy
; only remove from list specific type.
; trainer
ld a, d
or a
jr nz, .loop_list
jr .remove_card
.energy
ld a, d
cp $02
jr nz, .loop_list
jr .remove_card
.pkmn_card
ld a, d
cp $01
jr nz, .loop_list
; fallthrough
.remove_card
ld d, h
ld e, l
dec hl
.loop_remove
ld a, [de]
inc de
ld [hli], a
cp $ff
jr nz, .loop_remove
; success
ldh a, [hTempCardIndex_ff98]
pop bc
pop de
pop hl
scf
ret
.no_carry
pop bc
pop de
pop hl
or a
ret
; used in Pokemon Trader checks to look for a specific
; card in the deck to trade with a card in hand that
; has a card ID different from e.
; returns carry if successful.
; input:
; a = card ID 1
; e = card ID 2
; output:
; a = deck index of card ID 1 found in deck
; e = deck index of Pokemon card in hand different than card ID 2
LookForCardIDToTradeWithDifferentHandCard: ; 22ae0 (8:6ae0)
ld hl, wCurCardCanAttack
ld [hl], e
ld [wTempAI], a
; if card ID 1 is in hand, return no carry.
call LookForCardIDInHandList_Bank8
jr c, .no_carry
; if card ID 1 is not in deck, return no carry.
ld a, [wTempAI]
ld e, a
ld a, CARD_LOCATION_DECK
call LookForCardIDInLocation
jr nc, .no_carry
; store its deck index
ld [wTempAI], a
; look in hand for Pokemon card ID that
; is different from card ID 2.
ld a, [wCurCardCanAttack]
ld c, a
call CreateHandCardList
ld hl, wDuelTempList
.loop_hand
ld a, [hli]
cp $ff
jr z, .no_carry
ld b, a
call LoadCardDataToBuffer1_FromDeckIndex
cp c
jr z, .loop_hand
ld a, [wLoadedCard1Type]
cp TYPE_ENERGY
jr nc, .loop_hand
; found, output deck index of card ID 1 in deck
; and deck index of card found in hand, and set carry
ld e, b
ld a, [wTempAI]
scf
ret
.no_carry
or a
ret
; returns carry if at least one card in the hand
; has the card ID of input. Outputs its index.
; input:
; a = card ID to look for
; output:
; a = deck index of card in hand found
CheckIfHasCardIDInHand: ; 22b1f (8:6b1f)
ld [wTempCardIDToLook], a
call CreateHandCardList
ld hl, wDuelTempList
ld c, 0
.loop_hand
ld a, [hli]
cp $ff
ret z
ldh [hTempCardIndex_ff98], a
call LoadCardDataToBuffer1_FromDeckIndex
ld b, a
ld a, [wTempCardIDToLook]
cp b
jr nz, .loop_hand
ld a, c
or a
jr nz, .set_carry
inc c
jr nz, .loop_hand
.set_carry
ldh a, [hTempCardIndex_ff98]
scf
ret
; outputs in a total number of Pokemon cards in hand
; plus Pokemon in Turn Duelist's Play Area.
CountPokemonCardsInHandAndInPlayArea: ; 22b45 (8:6b45)
ld a, DUELVARS_NUMBER_OF_POKEMON_IN_PLAY_AREA
call GetTurnDuelistVariable
ld [wTempAI], a
call CreateHandCardList
ld hl, wDuelTempList
.loop_hand
ld a, [hli]
cp $ff
jr z, .done
call GetCardIDFromDeckIndex
call GetCardType
cp TYPE_ENERGY
jr nc, .loop_hand
ld a, [wTempAI]
inc a
ld [wTempAI], a
jr .loop_hand
.done
ld a, [wTempAI]
ret
; returns carry if a duplicate Pokemon card is found in hand.
; outputs in a the deck index of one of them.
FindDuplicatePokemonCards: ; 22b6f (8:6b6f)
ld a, $ff
ld [wTempAI], a
call CreateHandCardList
ld hl, wDuelTempList
push hl
.loop_hand_outer
pop hl
ld a, [hli]
cp $ff
jr z, .done
call GetCardIDFromDeckIndex
ld b, e
push hl
.loop_hand_inner
ld a, [hli]
cp $ff
jr z, .loop_hand_outer
ld c, a
call GetCardIDFromDeckIndex
ld a, e
cp b
jr nz, .loop_hand_inner
; found two cards with same ID,
; if they are Pokemon cards, store its deck index.
push bc
call GetCardType
pop bc
cp TYPE_ENERGY
jr nc, .loop_hand_outer
ld a, c
ld [wTempAI], a
; for some reason loop still continues
; even though if some other duplicate
; cards are found, it overwrites the result.
jr .loop_hand_outer
.done
ld a, [wTempAI]
cp $ff
jr z, .no_carry
; found
scf
ret
.no_carry
or a
ret
; return carry flag if attack is not high recoil.
AICheckIfAttackIsHighRecoil: ; 22bad (8:6bad)
farcall AIProcessButDontUseAttack
ret nc
ld a, [wSelectedAttack]
ld e, a
ld a, DUELVARS_ARENA_CARD
call GetTurnDuelistVariable
ld d, a
call CopyAttackDataAndDamage_FromDeckIndex
ld a, ATTACK_FLAG1_ADDRESS | HIGH_RECOIL_F
call CheckLoadedAttackFlag
ccf
ret

View File

@ -61,22 +61,22 @@ ENDM
; wAICardListRetreatBonus : scores given to certain cards for retreat;
; wAICardListEnergyBonus : max number of energy cards and card scores.
INCLUDE "engine/deck_ai/decks/general.asm"
INCLUDE "engine/deck_ai/decks/sams_practice.asm"
INCLUDE "engine/deck_ai/decks/general_no_retreat.asm"
INCLUDE "engine/deck_ai/decks/legendary_moltres.asm"
INCLUDE "engine/deck_ai/decks/legendary_zapdos.asm"
INCLUDE "engine/deck_ai/decks/legendary_articuno.asm"
INCLUDE "engine/deck_ai/decks/legendary_dragonite.asm"
INCLUDE "engine/deck_ai/decks/first_strike.asm"
INCLUDE "engine/deck_ai/decks/rock_crusher.asm"
INCLUDE "engine/deck_ai/decks/go_go_rain_dance.asm"
INCLUDE "engine/deck_ai/decks/zapping_selfdestruct.asm"
INCLUDE "engine/deck_ai/decks/flower_power.asm"
INCLUDE "engine/deck_ai/decks/strange_psyshock.asm"
INCLUDE "engine/deck_ai/decks/wonders_of_science.asm"
INCLUDE "engine/deck_ai/decks/fire_charge.asm"
INCLUDE "engine/deck_ai/decks/im_ronald.asm"
INCLUDE "engine/deck_ai/decks/powerful_ronald.asm"
INCLUDE "engine/deck_ai/decks/invincible_ronald.asm"
INCLUDE "engine/deck_ai/decks/legendary_ronald.asm"
INCLUDE "engine/ai/decks/general.asm"
INCLUDE "engine/ai/decks/sams_practice.asm"
INCLUDE "engine/ai/decks/general_no_retreat.asm"
INCLUDE "engine/ai/decks/legendary_moltres.asm"
INCLUDE "engine/ai/decks/legendary_zapdos.asm"
INCLUDE "engine/ai/decks/legendary_articuno.asm"
INCLUDE "engine/ai/decks/legendary_dragonite.asm"
INCLUDE "engine/ai/decks/first_strike.asm"
INCLUDE "engine/ai/decks/rock_crusher.asm"
INCLUDE "engine/ai/decks/go_go_rain_dance.asm"
INCLUDE "engine/ai/decks/zapping_selfdestruct.asm"
INCLUDE "engine/ai/decks/flower_power.asm"
INCLUDE "engine/ai/decks/strange_psyshock.asm"
INCLUDE "engine/ai/decks/wonders_of_science.asm"
INCLUDE "engine/ai/decks/fire_charge.asm"
INCLUDE "engine/ai/decks/im_ronald.asm"
INCLUDE "engine/ai/decks/powerful_ronald.asm"
INCLUDE "engine/ai/decks/invincible_ronald.asm"
INCLUDE "engine/ai/decks/legendary_ronald.asm"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1205,7 +1205,7 @@ AIProcessHandTrainerCards: ; 14663 (5:4663)
farcall _AIProcessHandTrainerCards
ret
INCLUDE "engine/deck_ai/deck_ai.asm"
INCLUDE "engine/ai/deck_ai.asm"
; return carry if card ID loaded in a is found in hand
; and outputs in a the deck index of that card

View File

@ -8258,7 +8258,7 @@ AIDoAction_TakePrize: ; 2bd7 (0:2bd7)
jr AIDoAction ; this line is not needed
; calls the appropriate AI routine to handle action,
; depending on the deck ID (see engine/deck_ai/deck_ai.asm)
; depending on the deck ID (see engine/ai/deck_ai.asm)
; input:
; - a = AIACTION_* constant
AIDoAction: ; 2bdb (0:2bdb)

View File

@ -46,7 +46,7 @@ ROMX $07
"Credits Sequence"
"Booster Packs"
ROMX $08
"Bank 8"
"AI Logic"
ROMX $0b
"Effect Functions"
ROMX $0c

View File

@ -31,8 +31,10 @@ INCLUDE "data/sequences/credits_sequence.asm"
SECTION "Booster Packs", ROMX
INCLUDE "engine/booster_packs.asm"
SECTION "Bank 8", ROMX
INCLUDE "engine/bank08.asm"
SECTION "AI Logic", ROMX
INCLUDE "engine/ai/trainer_cards.asm"
INCLUDE "engine/ai/pkmn_powers.asm"
INCLUDE "engine/ai/common.asm"
SECTION "Effect Functions", ROMX
INCLUDE "engine/effect_functions.asm"