ref: 0aadbec02a3a26fbad302cc56b841f3bd987370c
dir: /engine/battle/ai/switch.asm/
CheckPlayerMoveTypeMatchups: ; Check how well the moves you've already used ; fare against the enemy's Pokemon. Used to ; score a potential switch. push hl push de push bc ld a, BASE_AI_SWITCH_SCORE ld [wEnemyAISwitchScore], a ld hl, wPlayerUsedMoves ld a, [hl] and a jr z, .unknown_moves ld d, NUM_MOVES ld e, 0 .loop ld a, [hli] and a jr z, .exit push hl dec a ld hl, Moves + MOVE_POWER call GetMoveAttr and a jr z, .next inc hl call GetMoveByte ld hl, wEnemyMonType call CheckTypeMatchup ld a, [wTypeMatchup] cp EFFECTIVE + 1 ; 1.0 + 0.1 jr nc, .super_effective and a jr z, .next cp EFFECTIVE ; 1.0 jr nc, .neutral ; not very effective ld a, e cp 1 ; 0.1 jr nc, .next ld e, 1 jr .next .neutral ld e, 2 jr .next .super_effective call .DecreaseScore pop hl jr .done .next pop hl dec d jr nz, .loop .exit ld a, e cp 2 jr z, .done call .IncreaseScore ld a, e and a jr nz, .done call .IncreaseScore jr .done .unknown_moves ld a, [wBattleMonType1] ld b, a ld hl, wEnemyMonType1 call CheckTypeMatchup ld a, [wTypeMatchup] cp EFFECTIVE + 1 ; 1.0 + 0.1 jr c, .ok call .DecreaseScore .ok ld a, [wBattleMonType2] cp b jr z, .ok2 call CheckTypeMatchup ld a, [wTypeMatchup] cp EFFECTIVE + 1 ; 1.0 + 0.1 jr c, .ok2 call .DecreaseScore .ok2 .done call .CheckEnemyMoveMatchups pop bc pop de pop hl ret .CheckEnemyMoveMatchups: ld de, wEnemyMonMoves ld b, NUM_MOVES + 1 ld c, 0 ld a, [wTypeMatchup] push af .loop2 dec b jr z, .exit2 ld a, [de] and a jr z, .exit2 inc de dec a ld hl, Moves + MOVE_POWER call GetMoveAttr and a jr z, .loop2 inc hl call GetMoveByte ld hl, wBattleMonType1 call CheckTypeMatchup ld a, [wTypeMatchup] ; immune and a jr z, .loop2 ; not very effective inc c cp EFFECTIVE jr c, .loop2 ; neutral inc c inc c inc c inc c inc c cp EFFECTIVE jr z, .loop2 ; super effective ld c, 100 jr .loop2 .exit2 pop af ld [wTypeMatchup], a ld a, c and a jr z, .doubledown ; double down cp 5 jr c, .DecreaseScore ; down cp 100 ret c jr .IncreaseScore ; up .doubledown call .DecreaseScore .DecreaseScore: ld a, [wEnemyAISwitchScore] dec a ld [wEnemyAISwitchScore], a ret .IncreaseScore: ld a, [wEnemyAISwitchScore] inc a ld [wEnemyAISwitchScore], a ret CheckAbleToSwitch: xor a ld [wEnemySwitchMonParam], a call FindAliveEnemyMons ret c ld a, [wEnemySubStatus1] bit SUBSTATUS_PERISH, a jr z, .no_perish ld a, [wEnemyPerishCount] cp 1 jr nz, .no_perish ; Perish count is 1 call FindAliveEnemyMons call FindEnemyMonsWithAtLeastQuarterMaxHP call FindEnemyMonsThatResistPlayer call FindAliveEnemyMonsWithASuperEffectiveMove ld a, e cp 2 jr nz, .not_2 ld a, [wEnemyAISwitchScore] add $30 ; maximum chance ld [wEnemySwitchMonParam], a ret .not_2 call FindAliveEnemyMons sla c sla c ld b, $ff .loop1 inc b sla c jr nc, .loop1 ld a, b add $30 ; maximum chance ld [wEnemySwitchMonParam], a ret .no_perish call CheckPlayerMoveTypeMatchups ld a, [wEnemyAISwitchScore] cp 11 ret nc ld a, [wLastPlayerCounterMove] and a jr z, .no_last_counter_move call FindEnemyMonsImmuneToLastCounterMove ld a, [wEnemyAISwitchScore] and a jr z, .no_last_counter_move ld c, a call FindEnemyMonsWithASuperEffectiveMove ld a, [wEnemyAISwitchScore] cp $ff ret z ld b, a ld a, e cp 2 jr z, .not_2_again call CheckPlayerMoveTypeMatchups ld a, [wEnemyAISwitchScore] cp 10 ret nc ld a, b add $10 ld [wEnemySwitchMonParam], a ret .not_2_again ld c, $10 call CheckPlayerMoveTypeMatchups ld a, [wEnemyAISwitchScore] cp 10 jr nc, .okay ld c, $20 .okay ld a, b add c ld [wEnemySwitchMonParam], a ret .no_last_counter_move call CheckPlayerMoveTypeMatchups ld a, [wEnemyAISwitchScore] cp 10 ret nc call FindAliveEnemyMons call FindEnemyMonsWithAtLeastQuarterMaxHP call FindEnemyMonsThatResistPlayer call FindAliveEnemyMonsWithASuperEffectiveMove ld a, e cp $2 ret nz ld a, [wEnemyAISwitchScore] add $10 ld [wEnemySwitchMonParam], a ret FindAliveEnemyMons: ld a, [wOTPartyCount] cp 2 jr c, .only_one ld d, a ld e, 0 ld b, 1 << (PARTY_LENGTH - 1) ld c, 0 ld hl, wOTPartyMon1HP .loop ld a, [wCurOTMon] cp e jr z, .next push bc ld b, [hl] inc hl ld a, [hld] or b pop bc jr z, .next ld a, c or b ld c, a .next srl b push bc ld bc, PARTYMON_STRUCT_LENGTH add hl, bc pop bc inc e dec d jr nz, .loop ld a, c and a jr nz, .more_than_one .only_one scf ret .more_than_one and a ret FindEnemyMonsImmuneToLastCounterMove: ld hl, wOTPartyMon1 ld a, [wOTPartyCount] ld b, a ld c, 1 << (PARTY_LENGTH - 1) ld d, 0 xor a ld [wEnemyAISwitchScore], a .loop ld a, [wCurOTMon] cp d push hl jr z, .next push hl push bc ; If the Pokemon has at least 1 HP... ld bc, MON_HP add hl, bc pop bc ld a, [hli] or [hl] pop hl jr z, .next ld a, [hl] ld [wCurSpecies], a call GetBaseData ; the player's last move is damaging... ld a, [wLastPlayerCounterMove] dec a ld hl, Moves + MOVE_POWER call GetMoveAttr and a jr z, .next ; and the Pokemon is immune to it... inc hl call GetMoveByte ld hl, wBaseType call CheckTypeMatchup ld a, [wTypeMatchup] and a jr nz, .next ; ... encourage that Pokemon. ld a, [wEnemyAISwitchScore] or c ld [wEnemyAISwitchScore], a .next pop hl dec b ret z push bc ld bc, PARTYMON_STRUCT_LENGTH add hl, bc pop bc inc d srl c jr .loop FindAliveEnemyMonsWithASuperEffectiveMove: push bc ld a, [wOTPartyCount] ld e, a ld hl, wOTPartyMon1HP ld b, 1 << (PARTY_LENGTH - 1) ld c, 0 .loop ld a, [hli] or [hl] jr z, .next ld a, b or c ld c, a .next srl b push bc ld bc, wPartyMon2HP - (wPartyMon1HP + 1) add hl, bc pop bc dec e jr nz, .loop ld a, c pop bc and c ld c, a ; fallthrough FindEnemyMonsWithASuperEffectiveMove: ld a, -1 ld [wEnemyAISwitchScore], a ld hl, wOTPartyMon1Moves ld b, 1 << (PARTY_LENGTH - 1) ld d, 0 ld e, 0 .loop ld a, b and c jr z, .next push hl push bc ; for move on mon: ld b, NUM_MOVES ld c, 0 .loop3 ; if move is None: break ld a, [hli] and a push hl jr z, .break3 ; if move has no power: continue dec a ld hl, Moves + MOVE_POWER call GetMoveAttr and a jr z, .nope ; check type matchups inc hl call GetMoveByte ld hl, wBattleMonType1 call CheckTypeMatchup ; if immune or not very effective: continue ld a, [wTypeMatchup] cp 10 jr c, .nope ; if neutral: load 1 and continue ld e, 1 cp EFFECTIVE + 1 jr c, .nope ; if super-effective: load 2 and break ld e, 2 jr .break3 .nope pop hl dec b jr nz, .loop3 jr .done .break3 pop hl .done ld a, e pop bc pop hl cp 2 jr z, .done2 ; at least one move is super-effective cp 1 jr nz, .next ; no move does more than half damage ; encourage this pokemon ld a, d or b ld d, a jr .next ; such a long jump .next ; next pokemon? push bc ld bc, PARTYMON_STRUCT_LENGTH add hl, bc pop bc srl b jr nc, .loop ; if no pokemon has a super-effective move: return ld a, d ld b, a and a ret z .done2 ; convert the bit flag to an int and return push bc sla b sla b ld c, $ff .loop2 inc c sla b jr nc, .loop2 ld a, c ld [wEnemyAISwitchScore], a pop bc ret FindEnemyMonsThatResistPlayer: push bc ld hl, wOTPartySpecies ld b, 1 << (PARTY_LENGTH - 1) ld c, 0 .loop ld a, [hli] cp $ff jr z, .done push hl ld [wCurSpecies], a call GetBaseData ld a, [wLastPlayerCounterMove] and a jr z, .skip_move dec a ld hl, Moves + MOVE_POWER call GetMoveAttr and a jr z, .skip_move inc hl call GetMoveByte jr .check_type .skip_move ld a, [wBattleMonType1] ld hl, wBaseType call CheckTypeMatchup ld a, [wTypeMatchup] cp 10 + 1 jr nc, .dont_choose_mon ld a, [wBattleMonType2] .check_type ld hl, wBaseType call CheckTypeMatchup ld a, [wTypeMatchup] cp EFFECTIVE + 1 jr nc, .dont_choose_mon ld a, b or c ld c, a .dont_choose_mon srl b pop hl jr .loop .done ld a, c pop bc and c ld c, a ret FindEnemyMonsWithAtLeastQuarterMaxHP: push bc ld de, wOTPartySpecies ld b, 1 << (PARTY_LENGTH - 1) ld c, 0 ld hl, wOTPartyMon1HP .loop ld a, [de] inc de cp $ff jr z, .done push hl push bc ld b, [hl] inc hl ld c, [hl] inc hl inc hl ; hl = MaxHP + 1 ; bc = [CurHP] * 4 srl c rl b srl c rl b ; if bc >= [hl], encourage ld a, [hld] cp c ld a, [hl] sbc b pop bc jr nc, .next ld a, b or c ld c, a .next srl b pop hl push bc ld bc, PARTYMON_STRUCT_LENGTH add hl, bc pop bc jr .loop .done ld a, c pop bc and c ld c, a ret