diff options
Diffstat (limited to 'src/battle/battle_ai_switch_items.c')
-rw-r--r-- | src/battle/battle_ai_switch_items.c | 1007 |
1 files changed, 0 insertions, 1007 deletions
diff --git a/src/battle/battle_ai_switch_items.c b/src/battle/battle_ai_switch_items.c deleted file mode 100644 index 2cf11b50e..000000000 --- a/src/battle/battle_ai_switch_items.c +++ /dev/null @@ -1,1007 +0,0 @@ -#include "global.h" -#include "battle.h" -#include "battle_ai_switch_items.h" -#include "battle_script_commands.h" -#include "data2.h" -#include "ewram.h" -#include "pokemon.h" -#include "random.h" -#include "rom_8077ABC.h" -#include "rom3.h" -#include "util.h" -#include "constants/abilities.h" -#include "constants/items.h" -#include "constants/moves.h" -#include "constants/species.h" - -extern u8 gUnknown_02023A14_50; - -extern u8 gActiveBattler; -extern u16 gBattleTypeFlags; -extern u8 gAbsentBattlerFlags; -extern s32 gBattleMoveDamage; -extern u8 gMoveResultFlags; -extern u16 gDynamicBasePower; -extern u8 gCritMultiplier; -extern u16 gBattlerPartyIndexes[]; -extern u16 gLastLandedMoves[]; -extern const u8 gTypeEffectiveness[]; -extern struct BattlePokemon gBattleMons[]; -extern u32 gStatuses3[MAX_BATTLERS_COUNT]; - -static bool8 HasSuperEffectiveMoveAgainstOpponents(bool8 noRng); -static bool8 FindMonWithFlagsAndSuperEffective(u8 flags, u8 moduloPercent); -static bool8 ShouldUseItem(void); - - -static bool8 ShouldSwitchIfPerishSong(void) -{ - if (gStatuses3[gActiveBattler] & STATUS3_PERISH_SONG - && gDisableStructs[gActiveBattler].perishSongTimer1 == 0) - { - ewram160C8arr(GetBattlerPosition(gActiveBattler)) = 6; // gBattleStruct->AI_monToSwitchIntoId[GetBattlerPosition(gActiveBattler)] = 6; - Emitcmd33(1, 2, 0); - return TRUE; - } - - return FALSE; -} - -#ifdef NONMATCHING -static bool8 ShouldSwitchIfWonderGuard(void) -{ - u8 opposingBattler; - u8 moveFlags; - s32 i, j; - - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - return FALSE; - - if (gBattleMons[GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)].ability != ABILITY_WONDER_GUARD) - return FALSE; - - // check if pokemon has a super effective move - opposingBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); - for (i = 0; i < 4; i++) - { - u16 move = gBattleMons[gActiveBattler].moves[i]; - if (move == MOVE_NONE) - continue; - - moveFlags = AI_TypeCalc(move, gBattleMons[opposingBattler].species, gBattleMons[opposingBattler].ability); - if (moveFlags & MOVE_RESULT_SUPER_EFFECTIVE) - return FALSE; - } - - // find a pokemon in the party that has a super effective move - for (i = 0; i < 6; i++) - { - if (GetMonData(&gEnemyParty[i], MON_DATA_HP) == 0 - || GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2) == SPECIES_NONE - || GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2) == SPECIES_EGG - || i == gBattlerPartyIndexes[gActiveBattler]) - continue; - - GetMonData(&gEnemyParty[i], MON_DATA_SPECIES); // unused return value - GetMonData(&gEnemyParty[i], MON_DATA_ALT_ABILITY); // unused return value - - opposingBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); - for (j = 0; j < 4; j++) - { - u16 move = GetMonData(&gEnemyParty[i], MON_DATA_MOVE1 + j); - if (move == MOVE_NONE) - continue; - - moveFlags = AI_TypeCalc(move, gBattleMons[opposingBattler].species, gBattleMons[opposingBattler].ability); - if (moveFlags & MOVE_RESULT_SUPER_EFFECTIVE && (Random() % 3) < 2) - { - // we found a mon - ewram160C8arr(GetBattlerPosition(gActiveBattler)) = i; // gBattleStruct->AI_monToSwitchIntoId[GetBattlerPosition(gActiveBattler)] = i; - Emitcmd33(1, B_ACTION_SWITCH, 0); - return TRUE; - } - } - } - - return FALSE; // at this point there is not a single pokemon in the party that has a super effective move against a pokemon with wonder guard -} -#else -NAKED -static bool8 ShouldSwitchIfWonderGuard(void) -{ - asm(".syntax unified\n\ - push {r4-r7,lr}\n\ - mov r7, r9\n\ - mov r6, r8\n\ - push {r6,r7}\n\ - ldr r0, _0803606C @ =gBattleTypeFlags\n\ - ldrh r1, [r0]\n\ - movs r0, 0x1\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _080360A0\n\ - b _080361C8\n\ - .align 2, 0\n\ -_0803606C: .4byte gBattleTypeFlags\n\ -_08036070:\n\ - ldr r0, _08036094 @ =gActiveBattler\n\ - ldrb r0, [r0]\n\ - bl GetBattlerPosition\n\ - ldr r1, _08036098 @ =gSharedMem\n\ - lsls r0, 24\n\ - lsrs r0, 25\n\ - ldr r2, _0803609C @ =0x000160c8\n\ - adds r0, r2\n\ - adds r0, r1\n\ - strb r6, [r0]\n\ - movs r0, 0x1\n\ - movs r1, 0x2\n\ - movs r2, 0\n\ - bl Emitcmd33\n\ - movs r0, 0x1\n\ - b _080361CA\n\ - .align 2, 0\n\ -_08036094: .4byte gActiveBattler\n\ -_08036098: .4byte gSharedMem\n\ -_0803609C: .4byte 0x000160c8\n\ -_080360A0:\n\ - ldr r4, _080361D8 @ =gBattleMons\n\ - movs r0, 0\n\ - bl GetBattlerAtPosition\n\ - lsls r0, 24\n\ - lsrs r0, 24\n\ - movs r1, 0x58\n\ - muls r0, r1\n\ - adds r0, r4\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - cmp r0, 0x19\n\ - beq _080360BC\n\ - b _080361C8\n\ -_080360BC:\n\ - movs r0, 0\n\ - bl GetBattlerAtPosition\n\ - lsls r0, 24\n\ - lsrs r2, r0, 24\n\ - movs r6, 0\n\ - adds r7, r4, 0\n\ - movs r5, 0x58\n\ - adds r0, r2, 0\n\ - muls r0, r5\n\ - adds r4, r0, r7\n\ - movs r3, 0x20\n\ - adds r3, r4\n\ - mov r8, r3\n\ -_080360D8:\n\ - lsls r1, r6, 1\n\ - ldr r0, _080361DC @ =gActiveBattler\n\ - ldrb r0, [r0]\n\ - muls r0, r5\n\ - adds r1, r0\n\ - adds r0, r7, 0\n\ - adds r0, 0xC\n\ - adds r1, r0\n\ - ldrh r0, [r1]\n\ - cmp r0, 0\n\ - beq _08036104\n\ - ldrh r1, [r4]\n\ - mov r3, r8\n\ - ldrb r2, [r3]\n\ - bl AI_TypeCalc\n\ - lsls r0, 24\n\ - lsrs r1, r0, 24\n\ - movs r0, 0x2\n\ - ands r1, r0\n\ - cmp r1, 0\n\ - bne _080361C8\n\ -_08036104:\n\ - adds r6, 0x1\n\ - cmp r6, 0x3\n\ - ble _080360D8\n\ - movs r6, 0\n\ - ldr r0, _080361E0 @ =gEnemyParty\n\ - mov r9, r0\n\ -_08036110:\n\ - movs r0, 0x64\n\ - adds r5, r6, 0\n\ - muls r5, r0\n\ - mov r2, r9\n\ - adds r4, r5, r2\n\ - adds r0, r4, 0\n\ - movs r1, 0x39\n\ - bl GetMonData\n\ - cmp r0, 0\n\ - beq _080361C2\n\ - adds r0, r4, 0\n\ - movs r1, 0x41\n\ - bl GetMonData\n\ - cmp r0, 0\n\ - beq _080361C2\n\ - adds r0, r4, 0\n\ - movs r1, 0x41\n\ - bl GetMonData\n\ - movs r1, 0xCE\n\ - lsls r1, 1\n\ - cmp r0, r1\n\ - beq _080361C2\n\ - ldr r1, _080361E4 @ =gBattlerPartyIndexes\n\ - ldr r0, _080361DC @ =gActiveBattler\n\ - ldrb r0, [r0]\n\ - lsls r0, 1\n\ - adds r0, r1\n\ - ldrh r0, [r0]\n\ - cmp r6, r0\n\ - beq _080361C2\n\ - adds r0, r4, 0\n\ - movs r1, 0xB\n\ - bl GetMonData\n\ - adds r0, r4, 0\n\ - movs r1, 0x2E\n\ - bl GetMonData\n\ - movs r0, 0\n\ - bl GetBattlerAtPosition\n\ - lsls r0, 24\n\ - lsrs r2, r0, 24\n\ - movs r4, 0\n\ - mov r8, r5\n\ - ldr r1, _080361D8 @ =gBattleMons\n\ - movs r0, 0x58\n\ - muls r0, r2\n\ - adds r5, r0, r1\n\ - adds r7, r5, 0\n\ - adds r7, 0x20\n\ -_0803617C:\n\ - adds r1, r4, 0\n\ - adds r1, 0xD\n\ - mov r0, r8\n\ - add r0, r9\n\ - bl GetMonData\n\ - lsls r0, 16\n\ - lsrs r0, 16\n\ - cmp r0, 0\n\ - beq _080361BC\n\ - ldrh r1, [r5]\n\ - ldrb r2, [r7]\n\ - bl AI_TypeCalc\n\ - lsls r0, 24\n\ - lsrs r1, r0, 24\n\ - movs r0, 0x2\n\ - ands r1, r0\n\ - cmp r1, 0\n\ - beq _080361BC\n\ - bl Random\n\ - lsls r0, 16\n\ - lsrs r0, 16\n\ - movs r1, 0x3\n\ - bl __umodsi3\n\ - lsls r0, 16\n\ - lsrs r0, 16\n\ - cmp r0, 0x1\n\ - bhi _080361BC\n\ - b _08036070\n\ -_080361BC:\n\ - adds r4, 0x1\n\ - cmp r4, 0x3\n\ - ble _0803617C\n\ -_080361C2:\n\ - adds r6, 0x1\n\ - cmp r6, 0x5\n\ - ble _08036110\n\ -_080361C8:\n\ - movs r0, 0\n\ -_080361CA:\n\ - pop {r3,r4}\n\ - mov r8, r3\n\ - mov r9, r4\n\ - pop {r4-r7}\n\ - pop {r1}\n\ - bx r1\n\ - .align 2, 0\n\ -_080361D8: .4byte gBattleMons\n\ -_080361DC: .4byte gActiveBattler\n\ -_080361E0: .4byte gEnemyParty\n\ -_080361E4: .4byte gBattlerPartyIndexes\n\ - .syntax divided\n"); -} -#endif // NONMATCHING - -static bool8 FindMonThatAbsorbsOpponentsMove(void) -{ - u8 battlerIn1, battlerIn2; - u8 absorbingTypeAbility; - s32 i; - - if (HasSuperEffectiveMoveAgainstOpponents(TRUE) && Random() % 3 != 0) - return FALSE; - if (gLastLandedMoves[gActiveBattler] == 0) - return FALSE; - if (gLastLandedMoves[gActiveBattler] == 0xFFFF) - return FALSE; - if (gBattleMoves[gLastLandedMoves[gActiveBattler]].power == 0) - return FALSE; - - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - { - battlerIn1 = gActiveBattler; - if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gActiveBattler)))]) - battlerIn2 = gActiveBattler; - else - battlerIn2 = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gActiveBattler))); - } - else - { - battlerIn1 = gActiveBattler; - battlerIn2 = gActiveBattler; - } - - if (gBattleMoves[gLastLandedMoves[gActiveBattler]].type == TYPE_FIRE) - absorbingTypeAbility = ABILITY_FLASH_FIRE; - else if (gBattleMoves[gLastLandedMoves[gActiveBattler]].type == TYPE_WATER) - absorbingTypeAbility = ABILITY_WATER_ABSORB; - else if (gBattleMoves[gLastLandedMoves[gActiveBattler]].type == TYPE_ELECTRIC) - absorbingTypeAbility = ABILITY_VOLT_ABSORB; - else - return FALSE; - - if (gBattleMons[gActiveBattler].ability == absorbingTypeAbility) - return FALSE; - - for (i = 0; i < 6; i++) - { - u16 species; - u8 monAbility; - - if (GetMonData(&gEnemyParty[i], MON_DATA_HP) == 0) - continue; - if (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2) == SPECIES_NONE) - continue; - if (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2) == SPECIES_EGG) - continue; - if (i == gBattlerPartyIndexes[battlerIn1]) - continue; - if (i == gBattlerPartyIndexes[battlerIn2]) - continue; - if (i == ewram16068arr(battlerIn1)) - continue; - if (i == ewram16068arr(battlerIn2)) - continue; - - species = GetMonData(&gEnemyParty[i], MON_DATA_SPECIES); - if (GetMonData(&gEnemyParty[i], MON_DATA_ALT_ABILITY) != 0) - monAbility = gBaseStats[species].ability2; - else - monAbility = gBaseStats[species].ability1; - - if (absorbingTypeAbility == monAbility && Random() & 1) - { - // we found a mon - ewram160C8arr(GetBattlerPosition(gActiveBattler)) = i; - Emitcmd33(1, B_ACTION_SWITCH, 0); - return TRUE; - } - } - - return FALSE; -} - -static bool8 ShouldSwitchIfNaturalCure(void) -{ - if (!(gBattleMons[gActiveBattler].status1 & STATUS_SLEEP)) - return FALSE; - if (gBattleMons[gActiveBattler].ability != ABILITY_NATURAL_CURE) - return FALSE; - if (gBattleMons[gActiveBattler].hp < gBattleMons[gActiveBattler].maxHP / 2) - return FALSE; - - if ((gLastLandedMoves[gActiveBattler] == 0 || gLastLandedMoves[gActiveBattler] == 0xFFFF) && Random() & 1) - { - ewram160C8arr(GetBattlerPosition(gActiveBattler)) = 6; - Emitcmd33(1, B_ACTION_SWITCH, 0); - return TRUE; - } - else if (gBattleMoves[gLastLandedMoves[gActiveBattler]].power == 0 && Random() & 1) - { - ewram160C8arr(GetBattlerPosition(gActiveBattler)) = 6; - Emitcmd33(1, B_ACTION_SWITCH, 0); - return TRUE; - } - - if (FindMonWithFlagsAndSuperEffective(MOVE_RESULT_DOESNT_AFFECT_FOE, 1)) - return TRUE; - if (FindMonWithFlagsAndSuperEffective(MOVE_RESULT_NOT_VERY_EFFECTIVE, 1)) - return TRUE; - if (Random() & 1) - { - ewram160C8arr(GetBattlerPosition(gActiveBattler)) = 6; - Emitcmd33(1, B_ACTION_SWITCH, 0); - return TRUE; - } - - return FALSE; -} - -static bool8 HasSuperEffectiveMoveAgainstOpponents(bool8 noRng) -{ - u8 opposingBattler; - s32 i; - u8 moveFlags; - u16 move; - - opposingBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); - if (!(gAbsentBattlerFlags & gBitTable[opposingBattler])) - { - for (i = 0; i < 4; i++) - { - move = gBattleMons[gActiveBattler].moves[i]; - if (move == MOVE_NONE) - continue; - - moveFlags = AI_TypeCalc(move, gBattleMons[opposingBattler].species, gBattleMons[opposingBattler].ability); - if (moveFlags & MOVE_RESULT_SUPER_EFFECTIVE) - { - if (noRng) - return TRUE; - if (Random() % 10 != 0) - return TRUE; - } - } - } - if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) - return FALSE; - - opposingBattler = GetBattlerAtPosition(BATTLE_PARTNER(B_POSITION_PLAYER_LEFT)); - if (!(gAbsentBattlerFlags & gBitTable[opposingBattler])) - { - for (i = 0; i < 4; i++) - { - move = gBattleMons[gActiveBattler].moves[i]; - if (move == MOVE_NONE) - continue; - - moveFlags = AI_TypeCalc(move, gBattleMons[opposingBattler].species, gBattleMons[opposingBattler].ability); - if (moveFlags & MOVE_RESULT_SUPER_EFFECTIVE) - { - if (noRng) - return TRUE; - if (Random() % 10 != 0) - return TRUE; - } - } - } - - return FALSE; -} - -static bool8 AreStatsRaised(void) -{ - u8 buffedStatsValue = 0; - s32 i; - - for (i = 0; i < BATTLE_STATS_NO; i++) - { - if (gBattleMons[gActiveBattler].statStages[i] > 6) - buffedStatsValue += gBattleMons[gActiveBattler].statStages[i] - 6; - } - - return (buffedStatsValue > 3); -} - -static bool8 FindMonWithFlagsAndSuperEffective(u8 flags, u8 moduloPercent) -{ - u8 battlerIn1, battlerIn2; - s32 i, j; - u16 move; - u8 moveFlags; - - if (gLastLandedMoves[gActiveBattler] == 0) - return FALSE; - if (gLastLandedMoves[gActiveBattler] == 0xFFFF) - return FALSE; - if (gLastHitBy[gActiveBattler] == 0xFF) - return FALSE; - if (gBattleMoves[gLastLandedMoves[gActiveBattler]].power == 0) - return FALSE; - - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - { - battlerIn1 = gActiveBattler; - if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gActiveBattler)))]) - battlerIn2 = gActiveBattler; - else - battlerIn2 = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gActiveBattler))); - } - else - { - battlerIn1 = gActiveBattler; - battlerIn2 = gActiveBattler; - } - - for (i = 0; i < 6; i++) - { - u16 species; - u8 monAbility; - - if (GetMonData(&gEnemyParty[i], MON_DATA_HP) == 0) - continue; - if (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2) == SPECIES_NONE) - continue; - if (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2) == SPECIES_EGG) - continue; - if (i == gBattlerPartyIndexes[battlerIn1]) - continue; - if (i == gBattlerPartyIndexes[battlerIn2]) - continue; - if (i == ewram16068arr(battlerIn1)) - continue; - if (i == ewram16068arr(battlerIn2)) - continue; - - species = GetMonData(&gEnemyParty[i], MON_DATA_SPECIES); - if (GetMonData(&gEnemyParty[i], MON_DATA_ALT_ABILITY) != 0) - monAbility = gBaseStats[species].ability2; - else - monAbility = gBaseStats[species].ability1; - - moveFlags = AI_TypeCalc(gLastLandedMoves[gActiveBattler], species, monAbility); - if (moveFlags & flags) - { - battlerIn1 = gLastHitBy[gActiveBattler]; - - for (j = 0; j < 4; j++) - { - move = GetMonData(&gEnemyParty[i], MON_DATA_MOVE1 + j); - if (move == 0) - continue; - - moveFlags = AI_TypeCalc(move, gBattleMons[battlerIn1].species, gBattleMons[battlerIn1].ability); - if (moveFlags & MOVE_RESULT_SUPER_EFFECTIVE && Random() % moduloPercent == 0) - { - ewram160C8arr(GetBattlerPosition(gActiveBattler)) = i; - Emitcmd33(1, B_ACTION_SWITCH, 0); - return TRUE; - } - } - } - } - - return FALSE; -} - -static bool8 ShouldSwitch(void) -{ - u8 battlerIn1, battlerIn2; - s32 i; - s32 availableToSwitch; - - if (gBattleMons[gActiveBattler].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION)) - return FALSE; - if (gStatuses3[gActiveBattler] & STATUS3_ROOTED) - return FALSE; - if (AbilityBattleEffects(ABILITYEFFECT_CHECK_OTHER_SIDE, gActiveBattler, ABILITY_SHADOW_TAG, 0, 0)) - return FALSE; - if (AbilityBattleEffects(ABILITYEFFECT_CHECK_OTHER_SIDE, gActiveBattler, ABILITY_ARENA_TRAP, 0, 0)) - return FALSE; // misses the flying or levitate check - if (AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, ABILITY_MAGNET_PULL, 0, 0)) - { - if (gBattleMons[gActiveBattler].type1 == TYPE_STEEL) - return FALSE; - if (gBattleMons[gActiveBattler].type2 == TYPE_STEEL) - return FALSE; - } - - availableToSwitch = 0; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - { - battlerIn1 = gActiveBattler; - if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(GetBattlerPosition(gActiveBattler) ^ BIT_FLANK)]) - battlerIn2 = gActiveBattler; - else - battlerIn2 = GetBattlerAtPosition(GetBattlerPosition(gActiveBattler) ^ BIT_FLANK); - } - else - { - battlerIn1 = gActiveBattler; - battlerIn2 = gActiveBattler; - } - - for (i = 0; i < 6; i++) - { - if (GetMonData(&gEnemyParty[i], MON_DATA_HP) == 0) - continue; - if (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2) == SPECIES_NONE) - continue; - if (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2) == SPECIES_EGG) - continue; - if (i == gBattlerPartyIndexes[battlerIn1]) - continue; - if (i == gBattlerPartyIndexes[battlerIn2]) - continue; - if (i == ewram16068arr(battlerIn1)) - continue; - if (i == ewram16068arr(battlerIn2)) - continue; - - availableToSwitch++; - } - - if (availableToSwitch == 0) - return FALSE; - if (ShouldSwitchIfPerishSong()) - return TRUE; - if (ShouldSwitchIfWonderGuard()) - return TRUE; - if (FindMonThatAbsorbsOpponentsMove()) - return TRUE; - if (ShouldSwitchIfNaturalCure()) - return TRUE; - if (HasSuperEffectiveMoveAgainstOpponents(FALSE)) - return FALSE; - if (AreStatsRaised()) - return FALSE; - if (FindMonWithFlagsAndSuperEffective(MOVE_RESULT_DOESNT_AFFECT_FOE, 2) - || FindMonWithFlagsAndSuperEffective(MOVE_RESULT_NOT_VERY_EFFECTIVE, 3)) - return TRUE; - - return FALSE; -} - -void AI_TrySwitchOrUseItem(void) -{ - u8 battlerIn1, battlerIn2; - - if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) - { - if (ShouldSwitch()) - { - if (ewram160C8arr(GetBattlerPosition(gActiveBattler)) == 6) - { - s32 monToSwitchId = GetMostSuitableMonToSwitchInto(); - if (monToSwitchId == 6) - { - if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) - { - battlerIn1 = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); - battlerIn2 = battlerIn1; - } - else - { - battlerIn1 = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); - battlerIn2 = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); - } - - for (monToSwitchId = 0; monToSwitchId < 6; monToSwitchId++) - { - if (GetMonData(&gEnemyParty[monToSwitchId], MON_DATA_HP) == 0) - continue; - if (monToSwitchId == gBattlerPartyIndexes[battlerIn1]) - continue; - if (monToSwitchId == gBattlerPartyIndexes[battlerIn2]) - continue; - if (monToSwitchId == ewram16068arr(battlerIn1)) - continue; - if (monToSwitchId == ewram16068arr(battlerIn2)) - continue; - - break; - } - } - - ewram160C8arr(GetBattlerPosition(gActiveBattler)) = monToSwitchId; - } - - ewram16068arr(gActiveBattler) = ewram160C8arr(GetBattlerPosition(gActiveBattler)); - return; - } - else - { - #if DEBUG - if (!(gUnknown_02023A14_50 & 0x20) && ShouldUseItem()) - return; - #else - if (ShouldUseItem()) - return; - #endif - } - } - - Emitcmd33(1, B_ACTION_USE_MOVE, (gActiveBattler ^ BIT_SIDE) << 8); -} - -static void ModulateByTypeEffectiveness(u8 attackType, u8 defenseType1, u8 defenseType2, u8 *var) -{ - s32 i = 0; - - while (TYPE_EFFECT_ATK_TYPE(i) != TYPE_ENDTABLE) - { - if (TYPE_EFFECT_ATK_TYPE(i) == TYPE_FORESIGHT) - { - i += 3; - continue; - } - else if (TYPE_EFFECT_ATK_TYPE(i) == attackType) - { - // check type1 - if (TYPE_EFFECT_DEF_TYPE(i) == defenseType1) - *var = (*var * TYPE_EFFECT_MULTIPLIER(i)) / 10; - // check type2 - if (TYPE_EFFECT_DEF_TYPE(i) == defenseType2 && defenseType1 != defenseType2) - *var = (*var * TYPE_EFFECT_MULTIPLIER(i)) / 10; - } - i += 3; - } -} - -u8 GetMostSuitableMonToSwitchInto(void) -{ - u8 opposingBattler; - u8 bestDmg; // note : should be changed to s32 - u8 bestMonId; - u8 battlerIn1, battlerIn2; - s32 i, j; - u8 invalidMons; - u16 move; - - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - { - battlerIn1 = gActiveBattler; - if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(GetBattlerPosition(gActiveBattler) ^ BIT_FLANK)]) - battlerIn2 = gActiveBattler; - else - battlerIn2 = GetBattlerAtPosition(GetBattlerPosition(gActiveBattler) ^ BIT_FLANK); - - // UB: It considers the opponent only player's side even though it can battle alongside player; - opposingBattler = Random() & BIT_FLANK; - if (gAbsentBattlerFlags & gBitTable[opposingBattler]) - opposingBattler ^= BIT_FLANK; - } - else - { - opposingBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); - battlerIn1 = gActiveBattler; - battlerIn2 = gActiveBattler; - } - - invalidMons = 0; - - while (invalidMons != 0x3F) // all mons are invalid - { - bestDmg = 0; - bestMonId = 6; - // find the mon which type is the most suitable offensively - for (i = 0; i < 6; i++) - { - u16 species = GetMonData(&gEnemyParty[i], MON_DATA_SPECIES); - if (species != SPECIES_NONE - && GetMonData(&gEnemyParty[i], MON_DATA_HP) != 0 - && !(gBitTable[i] & invalidMons) - && gBattlerPartyIndexes[battlerIn1] != i - && gBattlerPartyIndexes[battlerIn2] != i - && i != ewram16068arr(battlerIn1) - && i != ewram16068arr(battlerIn2)) - { - u8 type1 = gBaseStats[species].type1; - u8 type2 = gBaseStats[species].type2; - u8 typeDmg = 10; - ModulateByTypeEffectiveness(gBattleMons[opposingBattler].type1, type1, type2, &typeDmg); - ModulateByTypeEffectiveness(gBattleMons[opposingBattler].type2, type1, type2, &typeDmg); - if (bestDmg < typeDmg) - { - bestDmg = typeDmg; - bestMonId = i; - } - } - else - { - invalidMons |= gBitTable[i]; - } - } - - // ok, we know the mon has the right typing but does it have at least one super effective move? - if (bestMonId != 6) - { - for (i = 0; i < 4; i++) - { - move = GetMonData(&gEnemyParty[bestMonId], MON_DATA_MOVE1 + i); - if (move != MOVE_NONE && TypeCalc(move, gActiveBattler, opposingBattler) & MOVE_RESULT_SUPER_EFFECTIVE) - break; - } - - if (i != 4) - return bestMonId; // has both the typing and at least one super effective move - - invalidMons |= gBitTable[bestMonId]; // sorry buddy, we want something better - } - else - { - invalidMons = 0x3F; // no viable mon to switch - } - } - - gDynamicBasePower = 0; - gBattleStruct->dynamicMoveType = 0; - gBattleStruct->dmgMultiplier = 1; - gMoveResultFlags = 0; - gCritMultiplier = 1; - bestDmg = 0; - bestMonId = 6; - - // if we couldn't find the best mon in terms of typing, find the one that deals most damage - for (i = 0; i < 6; i++) - { - if ((u16)(GetMonData(&gEnemyParty[i], MON_DATA_SPECIES)) == SPECIES_NONE) - continue; - if (GetMonData(&gEnemyParty[i], MON_DATA_HP) == 0) - continue; - if (gBattlerPartyIndexes[battlerIn1] == i) - continue; - if (gBattlerPartyIndexes[battlerIn2] == i) - continue; - if (i == ewram16068arr(battlerIn1)) - continue; - if (i == ewram16068arr(battlerIn2)) - continue; - - for (j = 0; j < 4; j++) - { - move = GetMonData(&gEnemyParty[i], MON_DATA_MOVE1 + j); - gBattleMoveDamage = 0; - if (move != MOVE_NONE && gBattleMoves[move].power != 1) - { - AI_CalcDmg(gActiveBattler, opposingBattler); - TypeCalc(move, gActiveBattler, opposingBattler); - } - if (bestDmg < gBattleMoveDamage) - { - bestDmg = gBattleMoveDamage; - bestMonId = i; - } - } - } - - return bestMonId; -} - -// TODO: use PokemonItemEffect struct instead of u8 once it's documented -static u8 GetAI_ItemType(u8 itemId, const u8 *itemEffect) // NOTE: should take u16 as item Id argument -{ - if (itemId == ITEM_FULL_RESTORE) - return AI_ITEM_FULL_RESTORE; - if (itemEffect[4] & 4) - return AI_ITEM_HEAL_HP; - if (itemEffect[3] & 0x3F) - return AI_ITEM_CURE_CONDITION; - if (itemEffect[0] & 0x3F || itemEffect[1] != 0 || itemEffect[2] != 0) - return AI_ITEM_X_STAT; - if (itemEffect[3] & 0x80) - return AI_ITEM_GUARD_SPECS; - - return AI_ITEM_NOT_RECOGNIZABLE; -} - -static bool8 ShouldUseItem(void) -{ - s32 i; - u8 validMons = 0; - bool8 shouldUse = FALSE; - - for (i = 0; i < 6; i++) - { - if (GetMonData(&gEnemyParty[i], MON_DATA_HP) != 0 - && GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2) != SPECIES_NONE - && GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2) != SPECIES_EGG) - { - validMons++; - } - } - - for (i = 0; i < 4; i++) - { - u16 item; - const u8 *itemEffects; - u8 paramOffset; - u8 battlerSide; - - if (i != 0 && validMons > (AI_BATTLE_HISTORY->numItems - i) + 1) - continue; - item = AI_BATTLE_HISTORY->trainerItems[i]; - if (item == ITEM_NONE) - continue; - if (gItemEffectTable[item - 13] == NULL) - continue; - - if (item == ITEM_ENIGMA_BERRY) - itemEffects = gSaveBlock1.enigmaBerry.itemEffect; - else - itemEffects = gItemEffectTable[item - 13]; - - ewram160D8(gActiveBattler) = GetAI_ItemType(item, itemEffects); - - switch (ewram160D8(gActiveBattler)) - { - case AI_ITEM_FULL_RESTORE: - if (gBattleMons[gActiveBattler].hp >= gBattleMons[gActiveBattler].maxHP / 4) - break; - if (gBattleMons[gActiveBattler].hp == 0) - break; - shouldUse = TRUE; - break; - case AI_ITEM_HEAL_HP: - paramOffset = GetItemEffectParamOffset(item, 4, 4); - if (paramOffset == 0) - break; - if (gBattleMons[gActiveBattler].hp == 0) - break; - if (gBattleMons[gActiveBattler].hp < gBattleMons[gActiveBattler].maxHP / 4 || gBattleMons[gActiveBattler].maxHP - gBattleMons[gActiveBattler].hp > itemEffects[paramOffset]) - shouldUse = TRUE; - break; - case AI_ITEM_CURE_CONDITION: - ewram160DA(gActiveBattler) = 0; - if (itemEffects[3] & 0x20 && gBattleMons[gActiveBattler].status1 & STATUS_SLEEP) - { - ewram160DA(gActiveBattler) |= 0x20; - shouldUse = TRUE; - } - if (itemEffects[3] & 0x10 && (gBattleMons[gActiveBattler].status1 & STATUS_POISON || gBattleMons[gActiveBattler].status1 & STATUS_TOXIC_POISON)) - { - ewram160DA(gActiveBattler) |= 0x10; - shouldUse = TRUE; - } - if (itemEffects[3] & 0x8 && gBattleMons[gActiveBattler].status1 & STATUS_BURN) - { - ewram160DA(gActiveBattler) |= 0x8; - shouldUse = TRUE; - } - if (itemEffects[3] & 0x4 && gBattleMons[gActiveBattler].status1 & STATUS_FREEZE) - { - ewram160DA(gActiveBattler) |= 0x4; - shouldUse = TRUE; - } - if (itemEffects[3] & 0x2 && gBattleMons[gActiveBattler].status1 & STATUS_PARALYSIS) - { - ewram160DA(gActiveBattler) |= 0x2; - shouldUse = TRUE; - } - if (itemEffects[3] & 0x1 && gBattleMons[gActiveBattler].status2 & STATUS2_CONFUSION) - { - ewram160DA(gActiveBattler) |= 0x1; - shouldUse = TRUE; - } - break; - case AI_ITEM_X_STAT: - ewram160DA(gActiveBattler) = 0; - if (gDisableStructs[gActiveBattler].isFirstTurn == 0) - break; - if (itemEffects[0] & 0xF) - ewram160DA(gActiveBattler) |= 0x1; - if (itemEffects[1] & 0xF0) - ewram160DA(gActiveBattler) |= 0x2; - if (itemEffects[1] & 0xF) - ewram160DA(gActiveBattler) |= 0x4; - if (itemEffects[2] & 0xF) - ewram160DA(gActiveBattler) |= 0x8; - if (itemEffects[2] & 0xF0) - ewram160DA(gActiveBattler) |= 0x20; - if (itemEffects[0] & 0x30) - ewram160DA(gActiveBattler) |= 0x80; - shouldUse = TRUE; - break; - case AI_ITEM_GUARD_SPECS: - battlerSide = GetBattlerSide(gActiveBattler); - if (gDisableStructs[gActiveBattler].isFirstTurn != 0 && gSideTimers[battlerSide].mistTimer == 0) - shouldUse = TRUE; - break; - case AI_ITEM_NOT_RECOGNIZABLE: - return FALSE; - } - - if (shouldUse) - { - Emitcmd33(1, B_ACTION_USE_ITEM, 0); - ewram160D4(gActiveBattler) = item; - AI_BATTLE_HISTORY->trainerItems[i] = 0; - return shouldUse; - } - } - - return FALSE; -} |