From 9c7db9f45e43732342ad72a8110bb8439c96f790 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Sun, 15 Jul 2018 12:39:07 +0200 Subject: [PATCH] New AI damage and type functions --- asm/battle_frontier_1.s | 6 +- include/battle_ai_script_commands.h | 3 + include/battle_script_commands.h | 3 - include/battle_util.h | 2 + src/battle_ai_script_commands.c | 140 +++++++++------- src/battle_ai_switch_items.c | 112 +++++-------- src/battle_script_commands.c | 238 +--------------------------- src/battle_util.c | 70 +++++--- 8 files changed, 185 insertions(+), 389 deletions(-) diff --git a/asm/battle_frontier_1.s b/asm/battle_frontier_1.s index 522c5d5f5..561bd2651 100644 --- a/asm/battle_frontier_1.s +++ b/asm/battle_frontier_1.s @@ -10109,9 +10109,9 @@ _08194074: lsls r0, r4, 1 add r0, r10 ldrh r0, [r0] - bl AI_TypeCalc - lsls r0, 24 - lsrs r5, r0, 24 + bl CalcPartyMonTypeEffectivenessMultiplier + ldr r5, =gMoveResultFlags + ldrb r5, [r5] movs r0, 0x6 ands r0, r5 cmp r0, 0x6 diff --git a/include/battle_ai_script_commands.h b/include/battle_ai_script_commands.h index d23ad048a..dbf72a8c2 100644 --- a/include/battle_ai_script_commands.h +++ b/include/battle_ai_script_commands.h @@ -6,6 +6,9 @@ #define AI_CHOICE_FLEE 4 #define AI_CHOICE_WATCH 5 +s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef); +s32 AI_CalcPartyMonDamage(u16 move, u8 battlerAtk, u8 battlerDef, struct Pokemon *mon); +u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef); void BattleAI_HandleItemUseBeforeAISetup(u8 defaultScoreMoves); void BattleAI_SetupAIData(u8 defaultScoreMoves); u8 BattleAI_ChooseMoveOrAction(void); diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index 142ac1f7b..83a0a3057 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -4,9 +4,6 @@ #define WINDOW_CLEAR 0x1 #define WINDOW_x80 0x80 -void AI_CalcDmg(u8 battlerIdAtk, u8 battlerIdDef); -u8 TypeCalc(u16 move, u8 battlerIdAtk, u8 battlerIdDef); -u8 AI_TypeCalc(u16 move, u16 targetSpecies, u8 targetAbility); u8 GetBattlerTurnOrderNum(u8 battlerId); void SetMoveEffect(bool8 primary, u8 certain); void BattleDestroyYesNoCursorAt(u8 cursorPosition); diff --git a/include/battle_util.h b/include/battle_util.h index fedfcba77..35f454652 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -81,5 +81,7 @@ u8 GetBattleMonMoveSlot(struct BattlePokemon *battleMon, u16 move); u32 GetBattlerWeight(u8 battlerId); s32 CalculateMoveDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, s32 fixedBasePower, bool32 isCrit, bool32 randomFactor); u16 CalcTypeEffectivenessMultiplier(u16 move, u8 moveType, u8 battlerAtk, u8 battlerDef, bool32 recordAbilities); +u16 CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u8 abilityDef); +u16 GetTypeModifier(u8 atkType, u8 defType); #endif // GUARD_BATTLE_UTIL_H diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index f4eca8c8e..f8169e6cf 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -652,6 +652,21 @@ void ClearBattlerItemEffectHistory(u8 battlerId) BATTLE_HISTORY->itemEffects[battlerId] = 0; } +s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef) +{ + return CalculateMoveDamage(move, battlerAtk, battlerDef, gBattleMoves[move].type, 0, FALSE, FALSE); +} + +s32 AI_CalcPartyMonDamage(u16 move, u8 battlerAtk, u8 battlerDef, struct Pokemon *mon) +{ + return 0; +} + +u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef) +{ + return CalcTypeEffectivenessMultiplier(move, gBattleMoves[move].type, battlerAtk, battlerDef, FALSE); +} + static void BattleAICmd_if_random_less_than(void) { u16 random = Random(); @@ -1194,9 +1209,8 @@ static void BattleAICmd_get_how_powerful_move_is(void) && gBattleMoves[gBattleMons[sBattler_AI].moves[checkedMove]].power > 1) { gCurrentMove = gBattleMons[sBattler_AI].moves[checkedMove]; - AI_CalcDmg(sBattler_AI, gBattlerTarget); - TypeCalc(gCurrentMove, sBattler_AI, gBattlerTarget); - moveDmgs[checkedMove] = gBattleMoveDamage * AI_THINKING_STRUCT->simulatedRNG[checkedMove] / 100; + moveDmgs[checkedMove] = AI_CalcDamage(gCurrentMove, sBattler_AI, gBattlerTarget); + moveDmgs[checkedMove] = moveDmgs[checkedMove] * AI_THINKING_STRUCT->simulatedRNG[checkedMove] / 100; if (moveDmgs[checkedMove] == 0) moveDmgs[checkedMove] = 1; } @@ -1456,32 +1470,39 @@ static void BattleAICmd_get_highest_type_effectiveness(void) u8 *dynamicMoveType; gDynamicBasePower = 0; - dynamicMoveType = &gBattleStruct->dynamicMoveType; - *dynamicMoveType = 0; + gBattleStruct->dynamicMoveType = 0; gMoveResultFlags = 0; - gIsCriticalHit = 1; AI_THINKING_STRUCT->funcResult = 0; for (i = 0; i < 4; i++) { - gBattleMoveDamage = 40; gCurrentMove = gBattleMons[sBattler_AI].moves[i]; - if (gCurrentMove != MOVE_NONE) { - TypeCalc(gCurrentMove, sBattler_AI, gBattlerTarget); + u32 effectivenessMultiplier = AI_GetTypeEffectiveness(gCurrentMove, sBattler_AI, gBattlerTarget); - if (gBattleMoveDamage == 120) // Super effective STAB. - gBattleMoveDamage = AI_EFFECTIVENESS_x2; - if (gBattleMoveDamage == 240) - gBattleMoveDamage = AI_EFFECTIVENESS_x4; - if (gBattleMoveDamage == 30) // Not very effective STAB. - gBattleMoveDamage = AI_EFFECTIVENESS_x0_5; - if (gBattleMoveDamage == 15) - gBattleMoveDamage = AI_EFFECTIVENESS_x0_25; - - if (gMoveResultFlags & MOVE_RESULT_DOESNT_AFFECT_FOE) + switch (effectivenessMultiplier) + { + case UQ_4_12(0.0): + default: gBattleMoveDamage = AI_EFFECTIVENESS_x0; + break; + case UQ_4_12(0.25): + gBattleMoveDamage = AI_EFFECTIVENESS_x0_25; + break; + case UQ_4_12(0.5): + gBattleMoveDamage = AI_EFFECTIVENESS_x0_5; + break; + case UQ_4_12(1.0): + gBattleMoveDamage = AI_EFFECTIVENESS_x1; + break; + case UQ_4_12(2.0): + gBattleMoveDamage = AI_EFFECTIVENESS_x2; + break; + case UQ_4_12(4.0): + gBattleMoveDamage = AI_EFFECTIVENESS_x4; + break; + } if (AI_THINKING_STRUCT->funcResult < gBattleMoveDamage) AI_THINKING_STRUCT->funcResult = gBattleMoveDamage; @@ -1494,31 +1515,36 @@ static void BattleAICmd_get_highest_type_effectiveness(void) static void BattleAICmd_if_type_effectiveness(void) { u8 damageVar; + u32 effectivenessMultiplier; gDynamicBasePower = 0; gBattleStruct->dynamicMoveType = 0; gMoveResultFlags = 0; - gIsCriticalHit = 1; - - gBattleMoveDamage = AI_EFFECTIVENESS_x1; gCurrentMove = AI_THINKING_STRUCT->moveConsidered; - TypeCalc(gCurrentMove, sBattler_AI, gBattlerTarget); - - if (gBattleMoveDamage == 120) // Super effective STAB. - gBattleMoveDamage = AI_EFFECTIVENESS_x2; - if (gBattleMoveDamage == 240) - gBattleMoveDamage = AI_EFFECTIVENESS_x4; - if (gBattleMoveDamage == 30) // Not very effective STAB. - gBattleMoveDamage = AI_EFFECTIVENESS_x0_5; - if (gBattleMoveDamage == 15) - gBattleMoveDamage = AI_EFFECTIVENESS_x0_25; - - if (gMoveResultFlags & MOVE_RESULT_DOESNT_AFFECT_FOE) - gBattleMoveDamage = AI_EFFECTIVENESS_x0; - - // Store gBattleMoveDamage in a u8 variable because gAIScriptPtr[1] is a u8. - damageVar = gBattleMoveDamage; + effectivenessMultiplier = AI_GetTypeEffectiveness(gCurrentMove, sBattler_AI, gBattlerTarget); + switch (effectivenessMultiplier) + { + case UQ_4_12(0.0): + default: + damageVar = AI_EFFECTIVENESS_x0; + break; + case UQ_4_12(0.25): + damageVar = AI_EFFECTIVENESS_x0_25; + break; + case UQ_4_12(0.5): + damageVar = AI_EFFECTIVENESS_x0_5; + break; + case UQ_4_12(1.0): + damageVar = AI_EFFECTIVENESS_x1; + break; + case UQ_4_12(2.0): + damageVar = AI_EFFECTIVENESS_x2; + break; + case UQ_4_12(4.0): + damageVar = AI_EFFECTIVENESS_x4; + break; + } if (damageVar == gAIScriptPtr[1]) gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); @@ -1578,7 +1604,7 @@ static void BattleAICmd_if_status_not_in_party(void) u32 statusToCompareTo; u8 battlerId; - switch(gAIScriptPtr[1]) + switch (gAIScriptPtr[1]) { case 1: battlerId = sBattler_AI; @@ -1600,8 +1626,8 @@ static void BattleAICmd_if_status_not_in_party(void) if (species != SPECIES_NONE && species != SPECIES_EGG && hp != 0 && status == statusToCompareTo) { - gAIScriptPtr += 10; // UB: Still bugged in Emerald. Uncomment the return statement to fix. - // return; + gAIScriptPtr += 10; + return; } } @@ -1700,6 +1726,8 @@ static void BattleAICmd_if_stat_level_not_equal(void) static void BattleAICmd_if_can_faint(void) { + s32 dmg; + if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power < 2) { gAIScriptPtr += 5; @@ -1709,18 +1737,14 @@ static void BattleAICmd_if_can_faint(void) gDynamicBasePower = 0; gBattleStruct->dynamicMoveType = 0; gMoveResultFlags = 0; - gIsCriticalHit = 1; - gCurrentMove = AI_THINKING_STRUCT->moveConsidered; - AI_CalcDmg(sBattler_AI, gBattlerTarget); - TypeCalc(gCurrentMove, sBattler_AI, gBattlerTarget); - - gBattleMoveDamage = gBattleMoveDamage * AI_THINKING_STRUCT->simulatedRNG[AI_THINKING_STRUCT->movesetIndex] / 100; + dmg = AI_CalcDamage(AI_THINKING_STRUCT->moveConsidered, sBattler_AI, gBattlerTarget); + dmg = dmg * AI_THINKING_STRUCT->simulatedRNG[AI_THINKING_STRUCT->movesetIndex] / 100; // Moves always do at least 1 damage. - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; + if (dmg == 0) + dmg = 1; - if (gBattleMons[gBattlerTarget].hp <= gBattleMoveDamage) + if (gBattleMons[gBattlerTarget].hp <= dmg) gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1); else gAIScriptPtr += 5; @@ -1728,6 +1752,8 @@ static void BattleAICmd_if_can_faint(void) static void BattleAICmd_if_cant_faint(void) { + s32 dmg; + if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power < 2) { gAIScriptPtr += 5; @@ -1737,16 +1763,14 @@ static void BattleAICmd_if_cant_faint(void) gDynamicBasePower = 0; gBattleStruct->dynamicMoveType = 0; gMoveResultFlags = 0; - gIsCriticalHit = 1; - gCurrentMove = AI_THINKING_STRUCT->moveConsidered; - AI_CalcDmg(sBattler_AI, gBattlerTarget); - TypeCalc(gCurrentMove, sBattler_AI, gBattlerTarget); + dmg = AI_CalcDamage(AI_THINKING_STRUCT->moveConsidered, sBattler_AI, gBattlerTarget); + dmg = dmg * AI_THINKING_STRUCT->simulatedRNG[AI_THINKING_STRUCT->movesetIndex] / 100; - gBattleMoveDamage = gBattleMoveDamage * AI_THINKING_STRUCT->simulatedRNG[AI_THINKING_STRUCT->movesetIndex] / 100; + // Moves always do at least 1 damage. + if (dmg == 0) + dmg = 1; - // This macro is missing the damage 0 = 1 assumption. - - if (gBattleMons[gBattlerTarget].hp > gBattleMoveDamage) + if (gBattleMons[gBattlerTarget].hp > dmg) gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1); else gAIScriptPtr += 5; diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index f4d167275..babf3004e 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -1,5 +1,6 @@ #include "global.h" #include "battle.h" +#include "battle_ai_script_commands.h" #include "battle_controllers.h" #include "constants/abilities.h" #include "constants/moves.h" @@ -11,7 +12,7 @@ // this file's functions static bool8 HasSuperEffectiveMoveAgainstOpponents(bool8 noRng); -static bool8 FindMonWithFlagsAndSuperEffective(u8 flags, u8 moduloPercent); +static bool8 FindMonWithFlagsAndSuperEffective(u16 flags, u8 moduloPercent); static bool8 ShouldUseItem(void); static bool8 ShouldSwitchIfPerishSong(void) @@ -33,7 +34,6 @@ static bool8 ShouldSwitchIfWonderGuard(void) { u8 opposingPosition; u8 opposingBattler; - u8 moveFlags; s32 i, j; s32 firstId; s32 lastId; // + 1 @@ -52,12 +52,11 @@ static bool8 ShouldSwitchIfWonderGuard(void) for (opposingBattler = GetBattlerAtPosition(opposingPosition), 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) - return FALSE; + if (move != MOVE_NONE) + { + if (AI_GetTypeEffectiveness(move, gActiveBattler, opposingBattler) >= UQ_4_12(2.0)) + return FALSE; + } } // Get party information. @@ -90,22 +89,18 @@ static bool8 ShouldSwitchIfWonderGuard(void) if (i == gBattlerPartyIndexes[gActiveBattler]) continue; - GetMonData(&party[i], MON_DATA_SPECIES); // Unused return value. - GetMonData(&party[i], MON_DATA_ALT_ABILITY); // Unused return value. - for (opposingBattler = GetBattlerAtPosition(opposingPosition), j = 0; j < 4; j++) { move = GetMonData(&party[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) + if (move != MOVE_NONE) { - // We found a mon. - *(gBattleStruct->AI_monToSwitchIntoId + gActiveBattler) = i; - BtlController_EmitTwoReturnValues(1, B_ACTION_SWITCH, 0); - return TRUE; + if (AI_GetTypeEffectiveness(move, gActiveBattler, opposingBattler) >= UQ_4_12(2.0) && Random() % 3 < 2) + { + // We found a mon. + *(gBattleStruct->AI_monToSwitchIntoId + gActiveBattler) = i; + BtlController_EmitTwoReturnValues(1, B_ACTION_SWITCH, 0); + return TRUE; + } } } } @@ -254,7 +249,6 @@ static bool8 HasSuperEffectiveMoveAgainstOpponents(bool8 noRng) u8 opposingPosition; u8 opposingBattler; s32 i; - u8 moveFlags; u16 move; opposingPosition = BATTLE_OPPOSITE(GetBattlerPosition(gActiveBattler)); @@ -268,8 +262,7 @@ static bool8 HasSuperEffectiveMoveAgainstOpponents(bool8 noRng) if (move == MOVE_NONE) continue; - moveFlags = AI_TypeCalc(move, gBattleMons[opposingBattler].species, gBattleMons[opposingBattler].ability); - if (moveFlags & MOVE_RESULT_SUPER_EFFECTIVE) + if (AI_GetTypeEffectiveness(move, gActiveBattler, opposingBattler) >= UQ_4_12(2.0)) { if (noRng) return TRUE; @@ -291,8 +284,7 @@ static bool8 HasSuperEffectiveMoveAgainstOpponents(bool8 noRng) if (move == MOVE_NONE) continue; - moveFlags = AI_TypeCalc(move, gBattleMons[opposingBattler].species, gBattleMons[opposingBattler].ability); - if (moveFlags & MOVE_RESULT_SUPER_EFFECTIVE) + if (AI_GetTypeEffectiveness(move, gActiveBattler, opposingBattler) >= UQ_4_12(2.0)) { if (noRng) return TRUE; @@ -319,7 +311,7 @@ static bool8 AreStatsRaised(void) return (buffedStatsValue > 3); } -static bool8 FindMonWithFlagsAndSuperEffective(u8 flags, u8 moduloPercent) +static bool8 FindMonWithFlagsAndSuperEffective(u16 flags, u8 moduloPercent) { u8 battlerIn1, battlerIn2; s32 firstId; @@ -327,7 +319,6 @@ static bool8 FindMonWithFlagsAndSuperEffective(u8 flags, u8 moduloPercent) struct Pokemon *party; s32 i, j; u16 move; - u8 moveFlags; if (gLastLandedMoves[gActiveBattler] == 0) return FALSE; @@ -395,8 +386,8 @@ static bool8 FindMonWithFlagsAndSuperEffective(u8 flags, u8 moduloPercent) else monAbility = gBaseStats[species].ability1; - moveFlags = AI_TypeCalc(gLastLandedMoves[gActiveBattler], species, monAbility); - if (moveFlags & flags) + CalcPartyMonTypeEffectivenessMultiplier(gLastLandedMoves[gActiveBattler], species, monAbility); + if (gMoveResultFlags & flags) { battlerIn1 = gLastHitBy[gActiveBattler]; @@ -406,8 +397,7 @@ static bool8 FindMonWithFlagsAndSuperEffective(u8 flags, u8 moduloPercent) if (move == 0) continue; - moveFlags = AI_TypeCalc(move, gBattleMons[battlerIn1].species, gBattleMons[battlerIn1].ability); - if (moveFlags & MOVE_RESULT_SUPER_EFFECTIVE && Random() % moduloPercent == 0) + if (AI_GetTypeEffectiveness(move, gActiveBattler, battlerIn1) >= UQ_4_12(2.0) && Random() % moduloPercent == 0) { *(gBattleStruct->AI_monToSwitchIntoId + gActiveBattler) = i; BtlController_EmitTwoReturnValues(1, B_ACTION_SWITCH, 0); @@ -598,34 +588,10 @@ void AI_TrySwitchOrUseItem(void) BtlController_EmitTwoReturnValues(1, B_ACTION_USE_MOVE, (gActiveBattler ^ BIT_SIDE) << 8); } -static void ModulateByTypeEffectiveness(u8 atkType, u8 defType1, u8 defType2, 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) == atkType) - { - // Check type1. - if (TYPE_EFFECT_DEF_TYPE(i) == defType1) - *var = (*var * TYPE_EFFECT_MULTIPLIER(i)) / 10; - // Check type2. - if (TYPE_EFFECT_DEF_TYPE(i) == defType2 && defType1 != defType2) - *var = (*var * TYPE_EFFECT_MULTIPLIER(i)) / 10; - } - i += 3; - } -} - u8 GetMostSuitableMonToSwitchInto(void) { u8 opposingBattler; - u8 bestDmg; // Note : should be changed to u32 for obvious reasons. + u32 bestDmg; u8 bestMonId; u8 battlerIn1, battlerIn2; s32 firstId; @@ -695,11 +661,22 @@ u8 GetMostSuitableMonToSwitchInto(void) && i != *(gBattleStruct->monToSwitchIntoId + battlerIn1) && i != *(gBattleStruct->monToSwitchIntoId + 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); + u32 typeDmg = UQ_4_12(1.0); + + u8 atkType1 = gBaseStats[species].type1; + u8 atkType2 = gBaseStats[species].type2; + u8 defType1 = gBattleMons[opposingBattler].type1; + u8 defType2 = gBattleMons[opposingBattler].type2; + + typeDmg *= GetTypeModifier(atkType1, defType1); + if (atkType2 != atkType1) + typeDmg *= GetTypeModifier(atkType2, defType1); + if (defType2 != defType1) + { + typeDmg *= GetTypeModifier(atkType1, defType2); + if (atkType2 != atkType1) + typeDmg *= GetTypeModifier(atkType2, defType2); + } if (bestDmg < typeDmg) { bestDmg = typeDmg; @@ -718,7 +695,7 @@ u8 GetMostSuitableMonToSwitchInto(void) for (i = 0; i < 4; i++) { move = GetMonData(&party[bestMonId], MON_DATA_MOVE1 + i); - if (move != MOVE_NONE && TypeCalc(move, gActiveBattler, opposingBattler) & MOVE_RESULT_SUPER_EFFECTIVE) + if (move != MOVE_NONE && AI_GetTypeEffectiveness(move, gActiveBattler, opposingBattler) >= UQ_4_12(2.0)) break; } @@ -757,16 +734,15 @@ u8 GetMostSuitableMonToSwitchInto(void) for (j = 0; j < 4; j++) { + s32 dmg = 0; move = GetMonData(&party[i], MON_DATA_MOVE1 + j); - gBattleMoveDamage = 0; if (move != MOVE_NONE && gBattleMoves[move].power != 1) { - AI_CalcDmg(gActiveBattler, opposingBattler); - TypeCalc(move, gActiveBattler, opposingBattler); + dmg = AI_CalcPartyMonDamage(move, gActiveBattler, opposingBattler, &party[i]); } - if (bestDmg < gBattleMoveDamage) + if (bestDmg < dmg) { - bestDmg = gBattleMoveDamage; + bestDmg = dmg; bestMonId = i; } } @@ -776,7 +752,7 @@ u8 GetMostSuitableMonToSwitchInto(void) } // 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 +static u8 GetAI_ItemType(u16 itemId, const u8 *itemEffect) { if (itemId == ITEM_FULL_RESTORE) return AI_ITEM_FULL_RESTORE; diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index b8acec8a5..36aa9ba8a 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1289,112 +1289,12 @@ static void atk05_damagecalc(void) gBattlescriptCurrInstr++; } -void AI_CalcDmg(u8 attacker, u8 defender) -{ - // To modify. -} - -static void ModulateDmgByType(u8 multiplier) -{ - gBattleMoveDamage = gBattleMoveDamage * multiplier / 10; - if (gBattleMoveDamage == 0 && multiplier != 0) - gBattleMoveDamage = 1; - - switch (multiplier) - { - case TYPE_MUL_NO_EFFECT: - gMoveResultFlags |= MOVE_RESULT_DOESNT_AFFECT_FOE; - gMoveResultFlags &= ~MOVE_RESULT_NOT_VERY_EFFECTIVE; - gMoveResultFlags &= ~MOVE_RESULT_SUPER_EFFECTIVE; - break; - case TYPE_MUL_NOT_EFFECTIVE: - if (gBattleMoves[gCurrentMove].power && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)) - { - if (gMoveResultFlags & MOVE_RESULT_SUPER_EFFECTIVE) - gMoveResultFlags &= ~MOVE_RESULT_SUPER_EFFECTIVE; - else - gMoveResultFlags |= MOVE_RESULT_NOT_VERY_EFFECTIVE; - } - break; - case TYPE_MUL_SUPER_EFFECTIVE: - if (gBattleMoves[gCurrentMove].power && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)) - { - if (gMoveResultFlags & MOVE_RESULT_NOT_VERY_EFFECTIVE) - gMoveResultFlags &= ~MOVE_RESULT_NOT_VERY_EFFECTIVE; - else - gMoveResultFlags |= MOVE_RESULT_SUPER_EFFECTIVE; - } - break; - } -} - static void atk06_typecalc(void) { - s32 i = 0; u8 moveType; - if (gCurrentMove == MOVE_STRUGGLE) - { - gBattlescriptCurrInstr++; - return; - } - GET_MOVE_TYPE(gCurrentMove, moveType); - - // check stab - if (IS_BATTLER_OF_TYPE(gBattlerAttacker, moveType)) - { - gBattleMoveDamage = gBattleMoveDamage * 15; - gBattleMoveDamage = gBattleMoveDamage / 10; - } - - if (gBattleMons[gBattlerTarget].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) - { - gLastUsedAbility = gBattleMons[gBattlerTarget].ability; - gMoveResultFlags |= (MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE); - gLastLandedMoves[gBattlerTarget] = 0; - gLastHitByType[gBattlerTarget] = 0; - gBattleCommunication[6] = moveType; - RecordAbilityBattle(gBattlerTarget, gLastUsedAbility); - } - else - { - while (TYPE_EFFECT_ATK_TYPE(i) != TYPE_ENDTABLE) - { - if (TYPE_EFFECT_ATK_TYPE(i) == TYPE_FORESIGHT) - { - if (gBattleMons[gBattlerTarget].status2 & STATUS2_FORESIGHT) - break; - i += 3; - continue; - } - else if (TYPE_EFFECT_ATK_TYPE(i) == moveType) - { - // check type1 - if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[gBattlerTarget].type1) - ModulateDmgByType(TYPE_EFFECT_MULTIPLIER(i)); - // check type2 - if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[gBattlerTarget].type2 && - gBattleMons[gBattlerTarget].type1 != gBattleMons[gBattlerTarget].type2) - ModulateDmgByType(TYPE_EFFECT_MULTIPLIER(i)); - } - i += 3; - } - } - - if (gBattleMons[gBattlerTarget].ability == ABILITY_WONDER_GUARD && AttacksThisTurn(gBattlerAttacker, gCurrentMove) == 2 - && (!(gMoveResultFlags & MOVE_RESULT_SUPER_EFFECTIVE) || ((gMoveResultFlags & (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE)) == (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE))) - && gBattleMoves[gCurrentMove].power) - { - gLastUsedAbility = ABILITY_WONDER_GUARD; - gMoveResultFlags |= MOVE_RESULT_MISSED; - gLastLandedMoves[gBattlerTarget] = 0; - gLastHitByType[gBattlerTarget] = 0; - gBattleCommunication[6] = 3; - RecordAbilityBattle(gBattlerTarget, gLastUsedAbility); - } - if (gMoveResultFlags & MOVE_RESULT_DOESNT_AFFECT_FOE) - gProtectStructs[gBattlerAttacker].targetNotAffected = 1; + CalcTypeEffectivenessMultiplier(gCurrentMove, moveType, gBattlerAttacker, gBattlerTarget, TRUE); gBattlescriptCurrInstr++; } @@ -1474,142 +1374,6 @@ static void CheckWonderGuardAndLevitate(void) } } -static void ModulateDmgByType2(u8 multiplier, u16 move, u8* flags) // same as ModulateDmgByType except different arguments -{ - gBattleMoveDamage = gBattleMoveDamage * multiplier / 10; - if (gBattleMoveDamage == 0 && multiplier != 0) - gBattleMoveDamage = 1; - - switch (multiplier) - { - case TYPE_MUL_NO_EFFECT: - *flags |= MOVE_RESULT_DOESNT_AFFECT_FOE; - *flags &= ~MOVE_RESULT_NOT_VERY_EFFECTIVE; - *flags &= ~MOVE_RESULT_SUPER_EFFECTIVE; - break; - case TYPE_MUL_NOT_EFFECTIVE: - if (gBattleMoves[move].power && !(*flags & MOVE_RESULT_NO_EFFECT)) - { - if (*flags & MOVE_RESULT_SUPER_EFFECTIVE) - *flags &= ~MOVE_RESULT_SUPER_EFFECTIVE; - else - *flags |= MOVE_RESULT_NOT_VERY_EFFECTIVE; - } - break; - case TYPE_MUL_SUPER_EFFECTIVE: - if (gBattleMoves[move].power && !(*flags & MOVE_RESULT_NO_EFFECT)) - { - if (*flags & MOVE_RESULT_NOT_VERY_EFFECTIVE) - *flags &= ~MOVE_RESULT_NOT_VERY_EFFECTIVE; - else - *flags |= MOVE_RESULT_SUPER_EFFECTIVE; - } - break; - } -} - -u8 TypeCalc(u16 move, u8 attacker, u8 defender) -{ - s32 i = 0; - u8 flags = 0; - u8 moveType; - - if (move == MOVE_STRUGGLE) - return 0; - - moveType = gBattleMoves[move].type; - - // check stab - if (IS_BATTLER_OF_TYPE(attacker, moveType)) - { - gBattleMoveDamage = gBattleMoveDamage * 15; - gBattleMoveDamage = gBattleMoveDamage / 10; - } - - if (gBattleMons[defender].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) - { - flags |= (MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE); - } - else - { - while (TYPE_EFFECT_ATK_TYPE(i) != TYPE_ENDTABLE) - { - if (TYPE_EFFECT_ATK_TYPE(i) == TYPE_FORESIGHT) - { - if (gBattleMons[defender].status2 & STATUS2_FORESIGHT) - break; - i += 3; - continue; - } - - else if (TYPE_EFFECT_ATK_TYPE(i) == moveType) - { - // check type1 - if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[defender].type1) - ModulateDmgByType2(TYPE_EFFECT_MULTIPLIER(i), move, &flags); - // check type2 - if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[defender].type2 && - gBattleMons[defender].type1 != gBattleMons[defender].type2) - ModulateDmgByType2(TYPE_EFFECT_MULTIPLIER(i), move, &flags); - } - i += 3; - } - } - - if (gBattleMons[defender].ability == ABILITY_WONDER_GUARD && !(flags & MOVE_RESULT_MISSED) - && AttacksThisTurn(attacker, move) == 2 - && (!(flags & MOVE_RESULT_SUPER_EFFECTIVE) || ((flags & (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE)) == (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE))) - && gBattleMoves[move].power) - { - flags |= MOVE_RESULT_MISSED; - } - return flags; -} - -u8 AI_TypeCalc(u16 move, u16 targetSpecies, u8 targetAbility) -{ - s32 i = 0; - u8 flags = 0; - u8 type1 = gBaseStats[targetSpecies].type1, type2 = gBaseStats[targetSpecies].type2; - u8 moveType; - - if (move == MOVE_STRUGGLE) - return 0; - - moveType = gBattleMoves[move].type; - - if (targetAbility == ABILITY_LEVITATE && moveType == TYPE_GROUND) - { - flags = MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE; - } - else - { - while (TYPE_EFFECT_ATK_TYPE(i) != TYPE_ENDTABLE) - { - if (TYPE_EFFECT_ATK_TYPE(i) == TYPE_FORESIGHT) - { - i += 3; - continue; - } - if (TYPE_EFFECT_ATK_TYPE(i) == moveType) - { - // check type1 - if (TYPE_EFFECT_DEF_TYPE(i) == type1) - ModulateDmgByType2(TYPE_EFFECT_MULTIPLIER(i), move, &flags); - // check type2 - if (TYPE_EFFECT_DEF_TYPE(i) == type2 && type1 != type2) - ModulateDmgByType2(TYPE_EFFECT_MULTIPLIER(i), move, &flags); - } - i += 3; - } - } - if (targetAbility == ABILITY_WONDER_GUARD - && (!(flags & MOVE_RESULT_SUPER_EFFECTIVE) || ((flags & (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE)) == (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE))) - && gBattleMoves[move].power) - flags |= MOVE_RESULT_DOESNT_AFFECT_FOE; - return flags; -} - static void atk07_adjustdamage(void) { u8 holdEffect, param; diff --git a/src/battle_util.c b/src/battle_util.c index cf88d168d..784812488 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -4661,6 +4661,29 @@ static inline void MulByTypeEffectiveness(u16 *modifier, u16 move, u8 moveType, MulModifier(modifier, mod); } +static void UpdateMoveResultFlags(u16 modifier) +{ + if (modifier == UQ_4_12(0.0)) + { + gMoveResultFlags |= MOVE_RESULT_DOESNT_AFFECT_FOE; + gMoveResultFlags &= ~(MOVE_RESULT_NOT_VERY_EFFECTIVE | MOVE_RESULT_SUPER_EFFECTIVE); + } + else if (modifier == UQ_4_12(1.0)) + { + gMoveResultFlags &= ~(MOVE_RESULT_NOT_VERY_EFFECTIVE | MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_DOESNT_AFFECT_FOE); + } + else if (modifier > UQ_4_12(1.0)) + { + gMoveResultFlags |= MOVE_RESULT_SUPER_EFFECTIVE; + gMoveResultFlags &= ~(MOVE_RESULT_NOT_VERY_EFFECTIVE | MOVE_RESULT_DOESNT_AFFECT_FOE); + } + else //if (modifier < UQ_4_12(1.0)) + { + gMoveResultFlags |= MOVE_RESULT_NOT_VERY_EFFECTIVE; + gMoveResultFlags &= ~(MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_DOESNT_AFFECT_FOE); + } +} + u16 CalcTypeEffectivenessMultiplier(u16 move, u8 moveType, u8 battlerAtk, u8 battlerDef, bool32 recordAbilities) { u16 modifier = UQ_4_12(1.0); @@ -4697,25 +4720,32 @@ u16 CalcTypeEffectivenessMultiplier(u16 move, u8 moveType, u8 battlerAtk, u8 bat } } - if (modifier == UQ_4_12(0.0)) - { - gMoveResultFlags |= MOVE_RESULT_DOESNT_AFFECT_FOE; - gMoveResultFlags &= ~(MOVE_RESULT_NOT_VERY_EFFECTIVE | MOVE_RESULT_SUPER_EFFECTIVE); - } - else if (modifier == UQ_4_12(1.0)) - { - gMoveResultFlags &= ~(MOVE_RESULT_NOT_VERY_EFFECTIVE | MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_DOESNT_AFFECT_FOE); - } - else if (modifier > UQ_4_12(1.0)) - { - gMoveResultFlags |= MOVE_RESULT_SUPER_EFFECTIVE; - gMoveResultFlags &= ~(MOVE_RESULT_NOT_VERY_EFFECTIVE | MOVE_RESULT_DOESNT_AFFECT_FOE); - } - else //if (modifier < UQ_4_12(1.0)) - { - gMoveResultFlags |= MOVE_RESULT_NOT_VERY_EFFECTIVE; - gMoveResultFlags &= ~(MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_DOESNT_AFFECT_FOE); - } - + UpdateMoveResultFlags(modifier); return modifier; } + +u16 CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u8 abilityDef) +{ + u16 modifier = UQ_4_12(1.0); + u8 moveType = gBattleMoves[move].type; + + if (move != MOVE_STRUGGLE && moveType != TYPE_MYSTERY) + { + MulByTypeEffectiveness(&modifier, move, moveType, 0, gBaseStats[speciesDef].type1); + if (gBaseStats[speciesDef].type2 != gBaseStats[speciesDef].type1) + MulByTypeEffectiveness(&modifier, move, moveType, 0, gBaseStats[speciesDef].type2); + + if (moveType == TYPE_GROUND && abilityDef == ABILITY_LEVITATE && !(gFieldStatuses & STATUS_FIELD_GRAVITY)) + modifier = UQ_4_12(0.0); + if (abilityDef == ABILITY_WONDER_GUARD && modifier <= UQ_4_12(1.0) && gBattleMoves[move].power) + modifier = UQ_4_12(0.0); + } + + UpdateMoveResultFlags(modifier); + return modifier; +} + +u16 GetTypeModifier(u8 atkType, u8 defType) +{ + return sTypeEffectivenessTable[atkType][defType]; +}