New AI damage and type functions

This commit is contained in:
DizzyEggg 2018-07-15 12:39:07 +02:00
parent 5a38bb61db
commit 9c7db9f45e
8 changed files with 185 additions and 389 deletions

View File

@ -10109,9 +10109,9 @@ _08194074:
lsls r0, r4, 1 lsls r0, r4, 1
add r0, r10 add r0, r10
ldrh r0, [r0] ldrh r0, [r0]
bl AI_TypeCalc bl CalcPartyMonTypeEffectivenessMultiplier
lsls r0, 24 ldr r5, =gMoveResultFlags
lsrs r5, r0, 24 ldrb r5, [r5]
movs r0, 0x6 movs r0, 0x6
ands r0, r5 ands r0, r5
cmp r0, 0x6 cmp r0, 0x6

View File

@ -6,6 +6,9 @@
#define AI_CHOICE_FLEE 4 #define AI_CHOICE_FLEE 4
#define AI_CHOICE_WATCH 5 #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_HandleItemUseBeforeAISetup(u8 defaultScoreMoves);
void BattleAI_SetupAIData(u8 defaultScoreMoves); void BattleAI_SetupAIData(u8 defaultScoreMoves);
u8 BattleAI_ChooseMoveOrAction(void); u8 BattleAI_ChooseMoveOrAction(void);

View File

@ -4,9 +4,6 @@
#define WINDOW_CLEAR 0x1 #define WINDOW_CLEAR 0x1
#define WINDOW_x80 0x80 #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); u8 GetBattlerTurnOrderNum(u8 battlerId);
void SetMoveEffect(bool8 primary, u8 certain); void SetMoveEffect(bool8 primary, u8 certain);
void BattleDestroyYesNoCursorAt(u8 cursorPosition); void BattleDestroyYesNoCursorAt(u8 cursorPosition);

View File

@ -81,5 +81,7 @@ u8 GetBattleMonMoveSlot(struct BattlePokemon *battleMon, u16 move);
u32 GetBattlerWeight(u8 battlerId); u32 GetBattlerWeight(u8 battlerId);
s32 CalculateMoveDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, s32 fixedBasePower, bool32 isCrit, bool32 randomFactor); 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 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 #endif // GUARD_BATTLE_UTIL_H

View File

@ -652,6 +652,21 @@ void ClearBattlerItemEffectHistory(u8 battlerId)
BATTLE_HISTORY->itemEffects[battlerId] = 0; 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) static void BattleAICmd_if_random_less_than(void)
{ {
u16 random = Random(); u16 random = Random();
@ -1194,9 +1209,8 @@ static void BattleAICmd_get_how_powerful_move_is(void)
&& gBattleMoves[gBattleMons[sBattler_AI].moves[checkedMove]].power > 1) && gBattleMoves[gBattleMons[sBattler_AI].moves[checkedMove]].power > 1)
{ {
gCurrentMove = gBattleMons[sBattler_AI].moves[checkedMove]; gCurrentMove = gBattleMons[sBattler_AI].moves[checkedMove];
AI_CalcDmg(sBattler_AI, gBattlerTarget); moveDmgs[checkedMove] = AI_CalcDamage(gCurrentMove, sBattler_AI, gBattlerTarget);
TypeCalc(gCurrentMove, sBattler_AI, gBattlerTarget); moveDmgs[checkedMove] = moveDmgs[checkedMove] * AI_THINKING_STRUCT->simulatedRNG[checkedMove] / 100;
moveDmgs[checkedMove] = gBattleMoveDamage * AI_THINKING_STRUCT->simulatedRNG[checkedMove] / 100;
if (moveDmgs[checkedMove] == 0) if (moveDmgs[checkedMove] == 0)
moveDmgs[checkedMove] = 1; moveDmgs[checkedMove] = 1;
} }
@ -1456,32 +1470,39 @@ static void BattleAICmd_get_highest_type_effectiveness(void)
u8 *dynamicMoveType; u8 *dynamicMoveType;
gDynamicBasePower = 0; gDynamicBasePower = 0;
dynamicMoveType = &gBattleStruct->dynamicMoveType; gBattleStruct->dynamicMoveType = 0;
*dynamicMoveType = 0;
gMoveResultFlags = 0; gMoveResultFlags = 0;
gIsCriticalHit = 1;
AI_THINKING_STRUCT->funcResult = 0; AI_THINKING_STRUCT->funcResult = 0;
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
{ {
gBattleMoveDamage = 40;
gCurrentMove = gBattleMons[sBattler_AI].moves[i]; gCurrentMove = gBattleMons[sBattler_AI].moves[i];
if (gCurrentMove != MOVE_NONE) if (gCurrentMove != MOVE_NONE)
{ {
TypeCalc(gCurrentMove, sBattler_AI, gBattlerTarget); u32 effectivenessMultiplier = AI_GetTypeEffectiveness(gCurrentMove, sBattler_AI, gBattlerTarget);
if (gBattleMoveDamage == 120) // Super effective STAB. switch (effectivenessMultiplier)
gBattleMoveDamage = AI_EFFECTIVENESS_x2; {
if (gBattleMoveDamage == 240) case UQ_4_12(0.0):
gBattleMoveDamage = AI_EFFECTIVENESS_x4; default:
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; 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) if (AI_THINKING_STRUCT->funcResult < gBattleMoveDamage)
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) static void BattleAICmd_if_type_effectiveness(void)
{ {
u8 damageVar; u8 damageVar;
u32 effectivenessMultiplier;
gDynamicBasePower = 0; gDynamicBasePower = 0;
gBattleStruct->dynamicMoveType = 0; gBattleStruct->dynamicMoveType = 0;
gMoveResultFlags = 0; gMoveResultFlags = 0;
gIsCriticalHit = 1;
gBattleMoveDamage = AI_EFFECTIVENESS_x1;
gCurrentMove = AI_THINKING_STRUCT->moveConsidered; gCurrentMove = AI_THINKING_STRUCT->moveConsidered;
TypeCalc(gCurrentMove, sBattler_AI, gBattlerTarget); effectivenessMultiplier = AI_GetTypeEffectiveness(gCurrentMove, sBattler_AI, gBattlerTarget);
switch (effectivenessMultiplier)
if (gBattleMoveDamage == 120) // Super effective STAB. {
gBattleMoveDamage = AI_EFFECTIVENESS_x2; case UQ_4_12(0.0):
if (gBattleMoveDamage == 240) default:
gBattleMoveDamage = AI_EFFECTIVENESS_x4; damageVar = AI_EFFECTIVENESS_x0;
if (gBattleMoveDamage == 30) // Not very effective STAB. break;
gBattleMoveDamage = AI_EFFECTIVENESS_x0_5; case UQ_4_12(0.25):
if (gBattleMoveDamage == 15) damageVar = AI_EFFECTIVENESS_x0_25;
gBattleMoveDamage = AI_EFFECTIVENESS_x0_25; break;
case UQ_4_12(0.5):
if (gMoveResultFlags & MOVE_RESULT_DOESNT_AFFECT_FOE) damageVar = AI_EFFECTIVENESS_x0_5;
gBattleMoveDamage = AI_EFFECTIVENESS_x0; break;
case UQ_4_12(1.0):
// Store gBattleMoveDamage in a u8 variable because gAIScriptPtr[1] is a u8. damageVar = AI_EFFECTIVENESS_x1;
damageVar = gBattleMoveDamage; 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]) if (damageVar == gAIScriptPtr[1])
gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2); gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 2);
@ -1600,8 +1626,8 @@ static void BattleAICmd_if_status_not_in_party(void)
if (species != SPECIES_NONE && species != SPECIES_EGG && hp != 0 && status == statusToCompareTo) if (species != SPECIES_NONE && species != SPECIES_EGG && hp != 0 && status == statusToCompareTo)
{ {
gAIScriptPtr += 10; // UB: Still bugged in Emerald. Uncomment the return statement to fix. gAIScriptPtr += 10;
// return; return;
} }
} }
@ -1700,6 +1726,8 @@ static void BattleAICmd_if_stat_level_not_equal(void)
static void BattleAICmd_if_can_faint(void) static void BattleAICmd_if_can_faint(void)
{ {
s32 dmg;
if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power < 2) if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power < 2)
{ {
gAIScriptPtr += 5; gAIScriptPtr += 5;
@ -1709,18 +1737,14 @@ static void BattleAICmd_if_can_faint(void)
gDynamicBasePower = 0; gDynamicBasePower = 0;
gBattleStruct->dynamicMoveType = 0; gBattleStruct->dynamicMoveType = 0;
gMoveResultFlags = 0; gMoveResultFlags = 0;
gIsCriticalHit = 1; dmg = AI_CalcDamage(AI_THINKING_STRUCT->moveConsidered, sBattler_AI, gBattlerTarget);
gCurrentMove = AI_THINKING_STRUCT->moveConsidered; dmg = dmg * AI_THINKING_STRUCT->simulatedRNG[AI_THINKING_STRUCT->movesetIndex] / 100;
AI_CalcDmg(sBattler_AI, gBattlerTarget);
TypeCalc(gCurrentMove, sBattler_AI, gBattlerTarget);
gBattleMoveDamage = gBattleMoveDamage * AI_THINKING_STRUCT->simulatedRNG[AI_THINKING_STRUCT->movesetIndex] / 100;
// Moves always do at least 1 damage. // Moves always do at least 1 damage.
if (gBattleMoveDamage == 0) if (dmg == 0)
gBattleMoveDamage = 1; dmg = 1;
if (gBattleMons[gBattlerTarget].hp <= gBattleMoveDamage) if (gBattleMons[gBattlerTarget].hp <= dmg)
gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1); gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
else else
gAIScriptPtr += 5; gAIScriptPtr += 5;
@ -1728,6 +1752,8 @@ static void BattleAICmd_if_can_faint(void)
static void BattleAICmd_if_cant_faint(void) static void BattleAICmd_if_cant_faint(void)
{ {
s32 dmg;
if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power < 2) if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power < 2)
{ {
gAIScriptPtr += 5; gAIScriptPtr += 5;
@ -1737,16 +1763,14 @@ static void BattleAICmd_if_cant_faint(void)
gDynamicBasePower = 0; gDynamicBasePower = 0;
gBattleStruct->dynamicMoveType = 0; gBattleStruct->dynamicMoveType = 0;
gMoveResultFlags = 0; gMoveResultFlags = 0;
gIsCriticalHit = 1; dmg = AI_CalcDamage(AI_THINKING_STRUCT->moveConsidered, sBattler_AI, gBattlerTarget);
gCurrentMove = AI_THINKING_STRUCT->moveConsidered; dmg = dmg * AI_THINKING_STRUCT->simulatedRNG[AI_THINKING_STRUCT->movesetIndex] / 100;
AI_CalcDmg(sBattler_AI, gBattlerTarget);
TypeCalc(gCurrentMove, sBattler_AI, gBattlerTarget);
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 > dmg)
if (gBattleMons[gBattlerTarget].hp > gBattleMoveDamage)
gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1); gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
else else
gAIScriptPtr += 5; gAIScriptPtr += 5;

View File

@ -1,5 +1,6 @@
#include "global.h" #include "global.h"
#include "battle.h" #include "battle.h"
#include "battle_ai_script_commands.h"
#include "battle_controllers.h" #include "battle_controllers.h"
#include "constants/abilities.h" #include "constants/abilities.h"
#include "constants/moves.h" #include "constants/moves.h"
@ -11,7 +12,7 @@
// this file's functions // this file's functions
static bool8 HasSuperEffectiveMoveAgainstOpponents(bool8 noRng); 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 ShouldUseItem(void);
static bool8 ShouldSwitchIfPerishSong(void) static bool8 ShouldSwitchIfPerishSong(void)
@ -33,7 +34,6 @@ static bool8 ShouldSwitchIfWonderGuard(void)
{ {
u8 opposingPosition; u8 opposingPosition;
u8 opposingBattler; u8 opposingBattler;
u8 moveFlags;
s32 i, j; s32 i, j;
s32 firstId; s32 firstId;
s32 lastId; // + 1 s32 lastId; // + 1
@ -52,13 +52,12 @@ static bool8 ShouldSwitchIfWonderGuard(void)
for (opposingBattler = GetBattlerAtPosition(opposingPosition), i = 0; i < 4; i++) for (opposingBattler = GetBattlerAtPosition(opposingPosition), i = 0; i < 4; i++)
{ {
move = gBattleMons[gActiveBattler].moves[i]; move = gBattleMons[gActiveBattler].moves[i];
if (move == MOVE_NONE) if (move != MOVE_NONE)
continue; {
if (AI_GetTypeEffectiveness(move, gActiveBattler, opposingBattler) >= UQ_4_12(2.0))
moveFlags = AI_TypeCalc(move, gBattleMons[opposingBattler].species, gBattleMons[opposingBattler].ability);
if (moveFlags & MOVE_RESULT_SUPER_EFFECTIVE)
return FALSE; return FALSE;
} }
}
// Get party information. // Get party information.
if (gBattleTypeFlags & (BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_x800000)) if (gBattleTypeFlags & (BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_x800000))
@ -90,17 +89,12 @@ static bool8 ShouldSwitchIfWonderGuard(void)
if (i == gBattlerPartyIndexes[gActiveBattler]) if (i == gBattlerPartyIndexes[gActiveBattler])
continue; 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++) for (opposingBattler = GetBattlerAtPosition(opposingPosition), j = 0; j < 4; j++)
{ {
move = GetMonData(&party[i], MON_DATA_MOVE1 + j); move = GetMonData(&party[i], MON_DATA_MOVE1 + j);
if (move == MOVE_NONE) if (move != MOVE_NONE)
continue; {
if (AI_GetTypeEffectiveness(move, gActiveBattler, opposingBattler) >= UQ_4_12(2.0) && Random() % 3 < 2)
moveFlags = AI_TypeCalc(move, gBattleMons[opposingBattler].species, gBattleMons[opposingBattler].ability);
if (moveFlags & MOVE_RESULT_SUPER_EFFECTIVE && Random() % 3 < 2)
{ {
// We found a mon. // We found a mon.
*(gBattleStruct->AI_monToSwitchIntoId + gActiveBattler) = i; *(gBattleStruct->AI_monToSwitchIntoId + gActiveBattler) = i;
@ -109,6 +103,7 @@ static bool8 ShouldSwitchIfWonderGuard(void)
} }
} }
} }
}
return FALSE; // There is not a single Pokemon in the party that has a super effective move against a mon with Wonder Guard. return FALSE; // There is not a single Pokemon in the party that has a super effective move against a mon with Wonder Guard.
} }
@ -254,7 +249,6 @@ static bool8 HasSuperEffectiveMoveAgainstOpponents(bool8 noRng)
u8 opposingPosition; u8 opposingPosition;
u8 opposingBattler; u8 opposingBattler;
s32 i; s32 i;
u8 moveFlags;
u16 move; u16 move;
opposingPosition = BATTLE_OPPOSITE(GetBattlerPosition(gActiveBattler)); opposingPosition = BATTLE_OPPOSITE(GetBattlerPosition(gActiveBattler));
@ -268,8 +262,7 @@ static bool8 HasSuperEffectiveMoveAgainstOpponents(bool8 noRng)
if (move == MOVE_NONE) if (move == MOVE_NONE)
continue; continue;
moveFlags = AI_TypeCalc(move, gBattleMons[opposingBattler].species, gBattleMons[opposingBattler].ability); if (AI_GetTypeEffectiveness(move, gActiveBattler, opposingBattler) >= UQ_4_12(2.0))
if (moveFlags & MOVE_RESULT_SUPER_EFFECTIVE)
{ {
if (noRng) if (noRng)
return TRUE; return TRUE;
@ -291,8 +284,7 @@ static bool8 HasSuperEffectiveMoveAgainstOpponents(bool8 noRng)
if (move == MOVE_NONE) if (move == MOVE_NONE)
continue; continue;
moveFlags = AI_TypeCalc(move, gBattleMons[opposingBattler].species, gBattleMons[opposingBattler].ability); if (AI_GetTypeEffectiveness(move, gActiveBattler, opposingBattler) >= UQ_4_12(2.0))
if (moveFlags & MOVE_RESULT_SUPER_EFFECTIVE)
{ {
if (noRng) if (noRng)
return TRUE; return TRUE;
@ -319,7 +311,7 @@ static bool8 AreStatsRaised(void)
return (buffedStatsValue > 3); return (buffedStatsValue > 3);
} }
static bool8 FindMonWithFlagsAndSuperEffective(u8 flags, u8 moduloPercent) static bool8 FindMonWithFlagsAndSuperEffective(u16 flags, u8 moduloPercent)
{ {
u8 battlerIn1, battlerIn2; u8 battlerIn1, battlerIn2;
s32 firstId; s32 firstId;
@ -327,7 +319,6 @@ static bool8 FindMonWithFlagsAndSuperEffective(u8 flags, u8 moduloPercent)
struct Pokemon *party; struct Pokemon *party;
s32 i, j; s32 i, j;
u16 move; u16 move;
u8 moveFlags;
if (gLastLandedMoves[gActiveBattler] == 0) if (gLastLandedMoves[gActiveBattler] == 0)
return FALSE; return FALSE;
@ -395,8 +386,8 @@ static bool8 FindMonWithFlagsAndSuperEffective(u8 flags, u8 moduloPercent)
else else
monAbility = gBaseStats[species].ability1; monAbility = gBaseStats[species].ability1;
moveFlags = AI_TypeCalc(gLastLandedMoves[gActiveBattler], species, monAbility); CalcPartyMonTypeEffectivenessMultiplier(gLastLandedMoves[gActiveBattler], species, monAbility);
if (moveFlags & flags) if (gMoveResultFlags & flags)
{ {
battlerIn1 = gLastHitBy[gActiveBattler]; battlerIn1 = gLastHitBy[gActiveBattler];
@ -406,8 +397,7 @@ static bool8 FindMonWithFlagsAndSuperEffective(u8 flags, u8 moduloPercent)
if (move == 0) if (move == 0)
continue; continue;
moveFlags = AI_TypeCalc(move, gBattleMons[battlerIn1].species, gBattleMons[battlerIn1].ability); if (AI_GetTypeEffectiveness(move, gActiveBattler, battlerIn1) >= UQ_4_12(2.0) && Random() % moduloPercent == 0)
if (moveFlags & MOVE_RESULT_SUPER_EFFECTIVE && Random() % moduloPercent == 0)
{ {
*(gBattleStruct->AI_monToSwitchIntoId + gActiveBattler) = i; *(gBattleStruct->AI_monToSwitchIntoId + gActiveBattler) = i;
BtlController_EmitTwoReturnValues(1, B_ACTION_SWITCH, 0); 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); 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 GetMostSuitableMonToSwitchInto(void)
{ {
u8 opposingBattler; u8 opposingBattler;
u8 bestDmg; // Note : should be changed to u32 for obvious reasons. u32 bestDmg;
u8 bestMonId; u8 bestMonId;
u8 battlerIn1, battlerIn2; u8 battlerIn1, battlerIn2;
s32 firstId; s32 firstId;
@ -695,11 +661,22 @@ u8 GetMostSuitableMonToSwitchInto(void)
&& i != *(gBattleStruct->monToSwitchIntoId + battlerIn1) && i != *(gBattleStruct->monToSwitchIntoId + battlerIn1)
&& i != *(gBattleStruct->monToSwitchIntoId + battlerIn2)) && i != *(gBattleStruct->monToSwitchIntoId + battlerIn2))
{ {
u8 type1 = gBaseStats[species].type1; u32 typeDmg = UQ_4_12(1.0);
u8 type2 = gBaseStats[species].type2;
u8 typeDmg = 10; u8 atkType1 = gBaseStats[species].type1;
ModulateByTypeEffectiveness(gBattleMons[opposingBattler].type1, type1, type2, &typeDmg); u8 atkType2 = gBaseStats[species].type2;
ModulateByTypeEffectiveness(gBattleMons[opposingBattler].type2, type1, type2, &typeDmg); 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) if (bestDmg < typeDmg)
{ {
bestDmg = typeDmg; bestDmg = typeDmg;
@ -718,7 +695,7 @@ u8 GetMostSuitableMonToSwitchInto(void)
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
{ {
move = GetMonData(&party[bestMonId], MON_DATA_MOVE1 + 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; break;
} }
@ -757,16 +734,15 @@ u8 GetMostSuitableMonToSwitchInto(void)
for (j = 0; j < 4; j++) for (j = 0; j < 4; j++)
{ {
s32 dmg = 0;
move = GetMonData(&party[i], MON_DATA_MOVE1 + j); move = GetMonData(&party[i], MON_DATA_MOVE1 + j);
gBattleMoveDamage = 0;
if (move != MOVE_NONE && gBattleMoves[move].power != 1) if (move != MOVE_NONE && gBattleMoves[move].power != 1)
{ {
AI_CalcDmg(gActiveBattler, opposingBattler); dmg = AI_CalcPartyMonDamage(move, gActiveBattler, opposingBattler, &party[i]);
TypeCalc(move, gActiveBattler, opposingBattler);
} }
if (bestDmg < gBattleMoveDamage) if (bestDmg < dmg)
{ {
bestDmg = gBattleMoveDamage; bestDmg = dmg;
bestMonId = i; bestMonId = i;
} }
} }
@ -776,7 +752,7 @@ u8 GetMostSuitableMonToSwitchInto(void)
} }
// TODO: use PokemonItemEffect struct instead of u8 once it's documented. // 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) if (itemId == ITEM_FULL_RESTORE)
return AI_ITEM_FULL_RESTORE; return AI_ITEM_FULL_RESTORE;

View File

@ -1289,112 +1289,12 @@ static void atk05_damagecalc(void)
gBattlescriptCurrInstr++; 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) static void atk06_typecalc(void)
{ {
s32 i = 0;
u8 moveType; u8 moveType;
if (gCurrentMove == MOVE_STRUGGLE)
{
gBattlescriptCurrInstr++;
return;
}
GET_MOVE_TYPE(gCurrentMove, moveType); GET_MOVE_TYPE(gCurrentMove, moveType);
CalcTypeEffectivenessMultiplier(gCurrentMove, moveType, gBattlerAttacker, gBattlerTarget, TRUE);
// 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;
gBattlescriptCurrInstr++; 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) static void atk07_adjustdamage(void)
{ {
u8 holdEffect, param; u8 holdEffect, param;

View File

@ -4661,6 +4661,29 @@ static inline void MulByTypeEffectiveness(u16 *modifier, u16 move, u8 moveType,
MulModifier(modifier, mod); 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 CalcTypeEffectivenessMultiplier(u16 move, u8 moveType, u8 battlerAtk, u8 battlerDef, bool32 recordAbilities)
{ {
u16 modifier = UQ_4_12(1.0); 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)) UpdateMoveResultFlags(modifier);
{
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);
}
return 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];
}