AI knows how to handle Illusion (#2726)

* AI knows how to handle Illusion
This commit is contained in:
DizzyEggg 2023-02-27 09:12:52 +01:00 committed by GitHub
parent 44d2cc7232
commit 919fb184fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 80 additions and 15 deletions

View File

@ -252,6 +252,7 @@ struct AI_SavedBattleMon
u16 moves[MAX_MON_MOVES]; u16 moves[MAX_MON_MOVES];
u16 heldItem; u16 heldItem;
u16 species; u16 species;
u8 types[3];
}; };
struct AiPartyMon struct AiPartyMon

View File

@ -538,23 +538,73 @@ void SaveBattlerData(u8 battlerId)
AI_THINKING_STRUCT->saved[battlerId].species = gBattleMons[battlerId].species; AI_THINKING_STRUCT->saved[battlerId].species = gBattleMons[battlerId].species;
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
AI_THINKING_STRUCT->saved[battlerId].moves[i] = gBattleMons[battlerId].moves[i]; AI_THINKING_STRUCT->saved[battlerId].moves[i] = gBattleMons[battlerId].moves[i];
AI_THINKING_STRUCT->saved[battlerId].types[0] = gBattleMons[battlerId].type1;
AI_THINKING_STRUCT->saved[battlerId].types[1] = gBattleMons[battlerId].type2;
} }
} }
static bool32 ShouldFailForIllusion(u16 illusionSpecies, u32 battlerId)
{
u32 i, j;
if (BATTLE_HISTORY->abilities[battlerId] == ABILITY_ILLUSION)
return FALSE;
// Don't fall for Illusion if the mon used a move it cannot know.
for (i = 0; i < MAX_MON_MOVES; i++)
{
u16 move = BATTLE_HISTORY->usedMoves[battlerId][i];
if (move == MOVE_NONE)
continue;
for (j = 0; gLevelUpLearnsets[illusionSpecies][j].move != MOVE_UNAVAILABLE; j++)
{
if (gLevelUpLearnsets[illusionSpecies][j].move == move)
break;
}
// The used move is in the learnsets of the fake species.
if (gLevelUpLearnsets[illusionSpecies][j].move != MOVE_UNAVAILABLE)
continue;
// The used move can be learned from Tm/Hm or Move Tutors.
if (CanLearnTeachableMove(illusionSpecies, move))
continue;
// 'Illegal move', AI won't fail for the illusion.
return FALSE;
}
return TRUE;
}
void SetBattlerData(u8 battlerId) void SetBattlerData(u8 battlerId)
{ {
if (!IsBattlerAIControlled(battlerId)) if (!IsBattlerAIControlled(battlerId))
{ {
struct Pokemon *illusionMon; u32 i, species, illusionSpecies;
u32 i;
// Simulate Illusion
species = gBattleMons[battlerId].species;
illusionSpecies = GetIllusionMonSpecies(battlerId);
if (illusionSpecies != SPECIES_NONE && ShouldFailForIllusion(illusionSpecies, battlerId))
{
// If the battler's type has not been changed, AI assumes the types of the illusion mon.
if (gBattleMons[battlerId].type1 == gSpeciesInfo[species].types[0]
&& gBattleMons[battlerId].type2 == gSpeciesInfo[species].types[1])
{
gBattleMons[battlerId].type1 = gSpeciesInfo[illusionSpecies].types[0];
gBattleMons[battlerId].type2 = gSpeciesInfo[illusionSpecies].types[1];
}
species = illusionSpecies;
}
// Use the known battler's ability. // Use the known battler's ability.
if (BATTLE_HISTORY->abilities[battlerId] != ABILITY_NONE) if (BATTLE_HISTORY->abilities[battlerId] != ABILITY_NONE)
gBattleMons[battlerId].ability = BATTLE_HISTORY->abilities[battlerId]; gBattleMons[battlerId].ability = BATTLE_HISTORY->abilities[battlerId];
// Check if mon can only have one ability. // Check if mon can only have one ability.
else if (gSpeciesInfo[gBattleMons[battlerId].species].abilities[1] == ABILITY_NONE else if (gSpeciesInfo[species].abilities[1] == ABILITY_NONE
|| gSpeciesInfo[gBattleMons[battlerId].species].abilities[1] == gSpeciesInfo[gBattleMons[battlerId].species].abilities[0]) || gSpeciesInfo[species].abilities[1] == gSpeciesInfo[species].abilities[0])
gBattleMons[battlerId].ability = gSpeciesInfo[gBattleMons[battlerId].species].abilities[0]; gBattleMons[battlerId].ability = gSpeciesInfo[species].abilities[0];
// The ability is unknown. // The ability is unknown.
else else
gBattleMons[battlerId].ability = ABILITY_NONE; gBattleMons[battlerId].ability = ABILITY_NONE;
@ -567,10 +617,6 @@ void SetBattlerData(u8 battlerId)
if (BATTLE_HISTORY->usedMoves[battlerId][i] == 0) if (BATTLE_HISTORY->usedMoves[battlerId][i] == 0)
gBattleMons[battlerId].moves[i] = 0; gBattleMons[battlerId].moves[i] = 0;
} }
// Simulate Illusion
if ((illusionMon = GetIllusionMonPtr(battlerId)) != NULL)
gBattleMons[battlerId].species = GetMonData(illusionMon, MON_DATA_SPECIES2);
} }
} }
@ -585,6 +631,8 @@ void RestoreBattlerData(u8 battlerId)
gBattleMons[battlerId].species = AI_THINKING_STRUCT->saved[battlerId].species; gBattleMons[battlerId].species = AI_THINKING_STRUCT->saved[battlerId].species;
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
gBattleMons[battlerId].moves[i] = AI_THINKING_STRUCT->saved[battlerId].moves[i]; gBattleMons[battlerId].moves[i] = AI_THINKING_STRUCT->saved[battlerId].moves[i];
gBattleMons[battlerId].type1 = AI_THINKING_STRUCT->saved[battlerId].types[0];
gBattleMons[battlerId].type2 = AI_THINKING_STRUCT->saved[battlerId].types[1];
} }
} }

View File

@ -9817,6 +9817,18 @@ static void MulByTypeEffectiveness(u16 *modifier, u16 move, u8 moveType, u8 batt
MulModifier(modifier, mod); MulModifier(modifier, mod);
} }
static void TryNoticeIllusionInTypeEffectiveness(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, u16 resultingModifier, u32 illusionSpecies)
{
// Check if the type effectiveness would've been different if the pokemon really had the types as the disguise.
u16 presumedModifier = UQ_4_12(1.0);
MulByTypeEffectiveness(&presumedModifier, move, moveType, battlerDef, gSpeciesInfo[illusionSpecies].types[0], battlerAtk, FALSE);
if (gSpeciesInfo[illusionSpecies].types[1] != gSpeciesInfo[illusionSpecies].types[0])
MulByTypeEffectiveness(&presumedModifier, move, moveType, battlerDef, gSpeciesInfo[illusionSpecies].types[1], battlerAtk, FALSE);
if (presumedModifier != resultingModifier)
RecordAbilityBattle(battlerDef, ABILITY_ILLUSION);
}
static void UpdateMoveResultFlags(u16 modifier) static void UpdateMoveResultFlags(u16 modifier)
{ {
if (modifier == UQ_4_12(0.0)) if (modifier == UQ_4_12(0.0))
@ -9842,6 +9854,7 @@ static void UpdateMoveResultFlags(u16 modifier)
static u16 CalcTypeEffectivenessMultiplierInternal(u16 move, u8 moveType, u8 battlerAtk, u8 battlerDef, bool32 recordAbilities, u16 modifier) static u16 CalcTypeEffectivenessMultiplierInternal(u16 move, u8 moveType, u8 battlerAtk, u8 battlerDef, bool32 recordAbilities, u16 modifier)
{ {
u32 illusionSpecies;
u16 defAbility = GetBattlerAbility(battlerDef); u16 defAbility = GetBattlerAbility(battlerDef);
MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, gBattleMons[battlerDef].type1, battlerAtk, recordAbilities); MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, gBattleMons[battlerDef].type1, battlerAtk, recordAbilities);
@ -9851,15 +9864,18 @@ static u16 CalcTypeEffectivenessMultiplierInternal(u16 move, u8 moveType, u8 bat
&& gBattleMons[battlerDef].type3 != gBattleMons[battlerDef].type1) && gBattleMons[battlerDef].type3 != gBattleMons[battlerDef].type1)
MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, gBattleMons[battlerDef].type3, battlerAtk, recordAbilities); MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, gBattleMons[battlerDef].type3, battlerAtk, recordAbilities);
if (recordAbilities && (illusionSpecies = GetIllusionMonSpecies(battlerDef)))
TryNoticeIllusionInTypeEffectiveness(move, moveType, battlerAtk, battlerDef, modifier, illusionSpecies);
if (gBattleMoves[move].split == SPLIT_STATUS && move != MOVE_THUNDER_WAVE) if (gBattleMoves[move].split == SPLIT_STATUS && move != MOVE_THUNDER_WAVE)
{ {
modifier = UQ_4_12(1.0); modifier = UQ_4_12(1.0);
#if B_GLARE_GHOST <= GEN_3 #if B_GLARE_GHOST <= GEN_3
if (move == MOVE_GLARE && IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST)) if (move == MOVE_GLARE && IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST))
{ {
modifier = UQ_4_12(0.0); modifier = UQ_4_12(0.0);
} }
#endif #endif
} }
else if (moveType == TYPE_GROUND && !IsBattlerGrounded2(battlerDef, TRUE) && !(gBattleMoves[move].flags & FLAG_DMG_UNGROUNDED_IGNORE_TYPE_IF_FLYING)) else if (moveType == TYPE_GROUND && !IsBattlerGrounded2(battlerDef, TRUE) && !(gBattleMoves[move].flags & FLAG_DMG_UNGROUNDED_IGNORE_TYPE_IF_FLYING))
{ {