diff options
Diffstat (limited to 'src/battle/battle_9.c')
-rwxr-xr-x | src/battle/battle_9.c | 838 |
1 files changed, 837 insertions, 1 deletions
diff --git a/src/battle/battle_9.c b/src/battle/battle_9.c index d9a1ee97e..c8bb89a0a 100755 --- a/src/battle/battle_9.c +++ b/src/battle/battle_9.c @@ -1,27 +1,863 @@ #include "global.h" #include "battle.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 gLastHitBy[]; 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[BATTLE_BANKS_COUNT]; +/*static*/ bool8 HasSuperEffectiveMoveAgainstOpponents(bool8 noRng); +/*static*/ bool8 FindMonWithFlagsAndSuperEffective(u8 flags, u8 moduloPercent); +/*static*/ bool8 ShouldUseItem(void); +/*static*/ u8 GetMostSuitableMonToSwitchInto(void); + + /*static*/ bool8 ShouldSwitchIfPerishSong(void) { if (gStatuses3[gActiveBattler] & STATUS3_PERISH_SONG && gDisableStructs[gActiveBattler].perishSongTimer1 == 0) { - ewram160C8arr(GetBankIdentity(gActiveBattler)) = 6; // gBattleStruct->AI_monToSwitchIntoId[GetBankIdentity(gActiveBattler)] = 6; + 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 opposingBank; + 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 + opposingBank = 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[opposingBank].species, gBattleMons[opposingBank].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 + + opposingBank = 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[opposingBank].species, gBattleMons[opposingBank].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 +__attribute__((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 bankIn1, bankIn2; + 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) + { + bankIn1 = gActiveBattler; + if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gActiveBattler)))]) + bankIn2 = gActiveBattler; + else + bankIn2 = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gActiveBattler))); + } + else + { + bankIn1 = gActiveBattler; + bankIn2 = 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[bankIn1]) + continue; + if (i == gBattlerPartyIndexes[bankIn2]) + continue; + if (i == ewram16068arr(bankIn1)) + continue; + if (i == ewram16068arr(bankIn2)) + 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 opposingBank; + s32 i; + u8 moveFlags; + u16 move; + + opposingBank = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + if (!(gAbsentBattlerFlags & gBitTable[opposingBank])) + { + for (i = 0; i < 4; i++) + { + move = gBattleMons[gActiveBattler].moves[i]; + if (move == MOVE_NONE) + continue; + + moveFlags = AI_TypeCalc(move, gBattleMons[opposingBank].species, gBattleMons[opposingBank].ability); + if (moveFlags & MOVE_RESULT_SUPER_EFFECTIVE) + { + if (noRng) + return TRUE; + if (Random() % 10 != 0) + return TRUE; + } + } + } + if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + return FALSE; + + opposingBank = GetBattlerAtPosition(BATTLE_PARTNER(B_POSITION_PLAYER_LEFT)); + if (!(gAbsentBattlerFlags & gBitTable[opposingBank])) + { + for (i = 0; i < 4; i++) + { + move = gBattleMons[gActiveBattler].moves[i]; + if (move == MOVE_NONE) + continue; + + moveFlags = AI_TypeCalc(move, gBattleMons[opposingBank].species, gBattleMons[opposingBank].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 bankIn1, bankIn2; + 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) + { + bankIn1 = gActiveBattler; + if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gActiveBattler)))]) + bankIn2 = gActiveBattler; + else + bankIn2 = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gActiveBattler))); + } + else + { + bankIn1 = gActiveBattler; + bankIn2 = 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[bankIn1]) + continue; + if (i == gBattlerPartyIndexes[bankIn2]) + continue; + if (i == ewram16068arr(bankIn1)) + continue; + if (i == ewram16068arr(bankIn2)) + 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) + { + bankIn1 = 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[bankIn1].species, gBattleMons[bankIn1].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 bankIn1, bankIn2; + 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) + { + bankIn1 = gActiveBattler; + if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(GetBattlerPosition(gActiveBattler) ^ BIT_FLANK)]) + bankIn2 = gActiveBattler; + else + bankIn2 = GetBattlerAtPosition(GetBattlerPosition(gActiveBattler) ^ BIT_FLANK); + } + else + { + bankIn1 = gActiveBattler; + bankIn2 = 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[bankIn1]) + continue; + if (i == gBattlerPartyIndexes[bankIn2]) + continue; + if (i == ewram16068arr(bankIn1)) + continue; + if (i == ewram16068arr(bankIn2)) + 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 bankIn1, bankIn2; + + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + { + if (ShouldSwitch()) + { + if (ewram160C8arr(GetBattlerPosition(gActiveBattler)) == 6) + { + s32 monToSwitchId = GetMostSuitableMonToSwitchInto(); + if (monToSwitchId == 6) + { + if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + { + bankIn1 = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + bankIn2 = bankIn1; + } + else + { + bankIn1 = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + bankIn2 = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); + } + + for (monToSwitchId = 0; monToSwitchId < 6; monToSwitchId++) + { + if (GetMonData(&gEnemyParty[monToSwitchId], MON_DATA_HP) == 0) + continue; + if (monToSwitchId == gBattlerPartyIndexes[bankIn1]) + continue; + if (monToSwitchId == gBattlerPartyIndexes[bankIn2]) + continue; + if (monToSwitchId == ewram16068arr(bankIn1)) + continue; + if (monToSwitchId == ewram16068arr(bankIn2)) + 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 opposingBank; + u8 bestDmg; // note : should be changed to s32 + u8 bestMonId; + u8 bankIn1, bankIn2; + s32 i, j; + u8 invalidMons; + u16 move; + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + bankIn1 = gActiveBattler; + if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(GetBattlerPosition(gActiveBattler) ^ BIT_FLANK)]) + bankIn2 = gActiveBattler; + else + bankIn2 = GetBattlerAtPosition(GetBattlerPosition(gActiveBattler) ^ BIT_FLANK); + + // UB: It considers the opponent only player's side even though it can battle alongside player; + opposingBank = Random() & BIT_FLANK; + if (gAbsentBattlerFlags & gBitTable[opposingBank]) + opposingBank ^= BIT_FLANK; + } + else + { + opposingBank = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + bankIn1 = gActiveBattler; + bankIn2 = 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[bankIn1] != i + && gBattlerPartyIndexes[bankIn2] != i + && i != ewram16068arr(bankIn1) + && i != ewram16068arr(bankIn2)) + { + u8 type1 = gBaseStats[species].type1; + u8 type2 = gBaseStats[species].type2; + u8 typeDmg = 10; + ModulateByTypeEffectiveness(gBattleMons[opposingBank].type1, type1, type2, &typeDmg); + ModulateByTypeEffectiveness(gBattleMons[opposingBank].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, opposingBank) & 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[bankIn1] == i) + continue; + if (gBattlerPartyIndexes[bankIn2] == i) + continue; + if (i == ewram16068arr(bankIn1)) + continue; + if (i == ewram16068arr(bankIn2)) + 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, opposingBank); + TypeCalc(move, gActiveBattler, opposingBank); + } + if (bestDmg < gBattleMoveDamage) + { + bestDmg = gBattleMoveDamage; + bestMonId = i; + } + } + } + + return bestMonId; +} |