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
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

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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];
}