Fixed ace switching bugs (#5922)
This commit is contained in:
parent
55f0d3aad5
commit
8d818445d2
2 changed files with 65 additions and 12 deletions
|
@ -917,7 +917,6 @@ bool32 ShouldSwitch(u32 battler)
|
|||
struct Pokemon *party;
|
||||
s32 i;
|
||||
s32 availableToSwitch;
|
||||
bool32 hasAceMon = FALSE;
|
||||
|
||||
if (gBattleMons[battler].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION))
|
||||
return FALSE;
|
||||
|
@ -966,7 +965,6 @@ bool32 ShouldSwitch(u32 battler)
|
|||
continue;
|
||||
if (IsAceMon(battler, i))
|
||||
{
|
||||
hasAceMon = TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -974,12 +972,7 @@ bool32 ShouldSwitch(u32 battler)
|
|||
}
|
||||
|
||||
if (availableToSwitch == 0)
|
||||
{
|
||||
if (hasAceMon) // If the ace mon is the only available mon, use it
|
||||
availableToSwitch++;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// NOTE: The sequence of the below functions matter! Do not change unless you have carefully considered the outcome.
|
||||
// Since the order is sequencial, and some of these functions prompt switch to specific party members.
|
||||
|
@ -1771,7 +1764,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
|||
{
|
||||
int revengeKillerId = PARTY_SIZE, slowRevengeKillerId = PARTY_SIZE, fastThreatenId = PARTY_SIZE, slowThreatenId = PARTY_SIZE, damageMonId = PARTY_SIZE;
|
||||
int batonPassId = PARTY_SIZE, typeMatchupId = PARTY_SIZE, typeMatchupEffectiveId = PARTY_SIZE, defensiveMonId = PARTY_SIZE, aceMonId = PARTY_SIZE, trapperId = PARTY_SIZE;
|
||||
int i, j, aliveCount = 0, bits = 0;
|
||||
int i, j, aliveCount = 0, bits = 0, aceMonCount = 0;
|
||||
s32 defensiveMonHitKOThreshold = 3; // 3HKO threshold that candidate defensive mons must exceed
|
||||
s32 playerMonHP = gBattleMons[opposingBattler].hp, maxDamageDealt = 0, damageDealt = 0;
|
||||
u32 aiMove, hitsToKOAI, maxHitsToKO = 0;
|
||||
|
@ -1794,6 +1787,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
|||
else if (IsAceMon(battler, i))
|
||||
{
|
||||
aceMonId = i;
|
||||
aceMonCount++;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
@ -1940,7 +1934,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
|||
else if (batonPassId != PARTY_SIZE) return batonPassId;
|
||||
}
|
||||
// If ace mon is the last available Pokemon and U-Turn/Volt Switch was used - switch to the mon.
|
||||
if (aceMonId != PARTY_SIZE && IsSwitchOutEffect(gMovesInfo[gLastUsedMove].effect))
|
||||
if (aceMonId != PARTY_SIZE && CountUsablePartyMons(battler) <= aceMonCount && IsSwitchOutEffect(gMovesInfo[gLastUsedMove].effect))
|
||||
return aceMonId;
|
||||
|
||||
return PARTY_SIZE;
|
||||
|
@ -2018,7 +2012,7 @@ u32 GetMostSuitableMonToSwitchInto(u32 battler, bool32 switchAfterMonKOd)
|
|||
// This all handled by the GetBestMonIntegrated function if the AI_FLAG_SMART_MON_CHOICES flag is set
|
||||
else
|
||||
{
|
||||
s32 i, aliveCount = 0;
|
||||
s32 i, aliveCount = 0, aceMonCount = 0;
|
||||
u32 invalidMons = 0, aceMonId = PARTY_SIZE;
|
||||
// Get invalid slots ids.
|
||||
for (i = firstId; i < lastId; i++)
|
||||
|
@ -2035,6 +2029,7 @@ u32 GetMostSuitableMonToSwitchInto(u32 battler, bool32 switchAfterMonKOd)
|
|||
else if (IsAceMon(battler, i)) // Save Ace Pokemon for last.
|
||||
{
|
||||
aceMonId = i;
|
||||
aceMonCount++;
|
||||
invalidMons |= 1u << i;
|
||||
}
|
||||
else
|
||||
|
@ -2054,8 +2049,8 @@ u32 GetMostSuitableMonToSwitchInto(u32 battler, bool32 switchAfterMonKOd)
|
|||
if (bestMonId != PARTY_SIZE)
|
||||
return bestMonId;
|
||||
|
||||
// If ace mon is the last available Pokemon and switch move was used - switch to the mon.
|
||||
if (aceMonId != PARTY_SIZE)
|
||||
// If ace mon is the last available Pokemon and U-Turn/Volt Switch was used - switch to the mon.
|
||||
if (aceMonId != PARTY_SIZE && CountUsablePartyMons(battler) <= aceMonCount && IsSwitchOutEffect(gMovesInfo[gLastUsedMove].effect))
|
||||
return aceMonId;
|
||||
|
||||
return PARTY_SIZE;
|
||||
|
|
|
@ -909,3 +909,61 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: AI correctly handles abilities
|
|||
TURN { MOVE(player, MOVE_WATER_GUN); EXPECT_MOVE(opponent, MOVE_ABSORB); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI won't switch out if Yawn'd with only Ace mon remaining")
|
||||
{
|
||||
u32 aceFlag;
|
||||
PARAMETRIZE{ aceFlag = 0; }
|
||||
PARAMETRIZE{ aceFlag = AI_FLAG_ACE_POKEMON; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_YAWN].effect == EFFECT_YAWN);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | aceFlag | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_SMART_SWITCHING);
|
||||
PLAYER(SPECIES_SLOWKING) { Moves(MOVE_YAWN, MOVE_CONFUSION, MOVE_POWER_GEM, MOVE_WATER_PULSE); Item(ITEM_LEFTOVERS); }
|
||||
OPPONENT(SPECIES_SCOLIPEDE) { Moves(MOVE_POISON_TAIL); }
|
||||
OPPONENT(SPECIES_ABSOL) { Moves(MOVE_KNOCK_OFF, MOVE_CRUNCH); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_YAWN); EXPECT_MOVE(opponent, MOVE_POISON_TAIL); }
|
||||
if (aceFlag)
|
||||
TURN { MOVE(player, MOVE_POWER_GEM); EXPECT_MOVE(opponent, MOVE_POISON_TAIL); }
|
||||
else
|
||||
TURN { MOVE(player, MOVE_POWER_GEM); EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI won't switch in ace mon after U-Turn if other options available")
|
||||
{
|
||||
u32 aceFlag;
|
||||
PARAMETRIZE{ aceFlag = 0; }
|
||||
PARAMETRIZE{ aceFlag = AI_FLAG_ACE_POKEMON; }
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | aceFlag | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_SMART_SWITCHING);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_SURF); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_U_TURN); }
|
||||
OPPONENT(SPECIES_NUMEL) { Level(5); Moves(MOVE_SPLASH); }
|
||||
OPPONENT(SPECIES_SCIZOR) { Moves(MOVE_BUG_BITE); }
|
||||
} WHEN {
|
||||
if (aceFlag)
|
||||
TURN { EXPECT_MOVE(opponent, MOVE_U_TURN); EXPECT_SEND_OUT(opponent, 1); MOVE(player, MOVE_SURF); }
|
||||
else
|
||||
TURN { EXPECT_MOVE(opponent, MOVE_U_TURN); EXPECT_SEND_OUT(opponent, 2); MOVE(player, MOVE_SURF); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("Switch AI: AI won't switch in ace mon after U-Turn if other options available")
|
||||
{
|
||||
u32 aceFlag;
|
||||
PARAMETRIZE{ aceFlag = 0; }
|
||||
PARAMETRIZE{ aceFlag = AI_FLAG_ACE_POKEMON; }
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | aceFlag | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_SURF); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_U_TURN); }
|
||||
OPPONENT(SPECIES_NUMEL) { Level(5); Moves(MOVE_SPLASH); }
|
||||
OPPONENT(SPECIES_SCIZOR) { Moves(MOVE_BUG_BITE); }
|
||||
} WHEN {
|
||||
if (aceFlag)
|
||||
TURN { EXPECT_MOVE(opponent, MOVE_U_TURN); EXPECT_SEND_OUT(opponent, 1); MOVE(player, MOVE_SURF); }
|
||||
else
|
||||
TURN { EXPECT_MOVE(opponent, MOVE_U_TURN); EXPECT_SEND_OUT(opponent, 2); MOVE(player, MOVE_SURF); }
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue