mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2025-02-04 10:20:01 +01:00
New AI damage and type functions
This commit is contained in:
parent
5a38bb61db
commit
9c7db9f45e
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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];
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user