Fix switching 1v1 calcs not handling 0 (#7131)
This commit is contained in:
parent
b55ee2288b
commit
06c54a2d60
@ -261,13 +261,10 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler)
|
||||
if (playerMove != MOVE_NONE && !IsBattleMoveStatus(playerMove) && GetMoveEffect(playerMove) != EFFECT_FOCUS_PUNCH)
|
||||
{
|
||||
damageTaken = AI_GetDamage(opposingBattler, battler, i, AI_DEFENDING, gAiLogicData);
|
||||
if (playerMove == gBattleStruct->choicedMove[opposingBattler]) // If player is choiced, only care about the choice locked move
|
||||
if (damageTaken > maxDamageTaken && !AI_DoesChoiceItemBlockMove(opposingBattler, playerMove))
|
||||
{
|
||||
return maxDamageTaken = damageTaken;
|
||||
break;
|
||||
}
|
||||
if (damageTaken > maxDamageTaken)
|
||||
maxDamageTaken = damageTaken;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -281,7 +278,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler)
|
||||
}
|
||||
|
||||
// Check if current mon can 1v1 in spite of bad matchup, and don't switch out if it can
|
||||
if (hitsToKoPlayer < hitsToKoAI || (hitsToKoPlayer == hitsToKoAI && AI_IsFaster(battler, opposingBattler, aiBestMove)))
|
||||
if ((hitsToKoPlayer != 0 && (hitsToKoPlayer < hitsToKoAI || hitsToKoAI == 0)) || (hitsToKoPlayer == hitsToKoAI && AI_IsFaster(battler, opposingBattler, aiBestMove)))
|
||||
return FALSE;
|
||||
|
||||
// If we don't have any other viable options, don't switch out
|
||||
@ -1805,7 +1802,7 @@ static u32 GetSwitchinHitsToKO(s32 damageTaken, u32 battler)
|
||||
|
||||
// No damage being dealt
|
||||
if ((damageTaken + statusDamage + recurringDamage <= recurringHealing) || damageTaken + statusDamage + recurringDamage == 0)
|
||||
return startingHP;
|
||||
return hitsToKO;
|
||||
|
||||
// Mon fainted to hazards
|
||||
if (startingHP == 0)
|
||||
@ -2012,6 +2009,18 @@ static inline bool32 IsFreeSwitch(enum SwitchType switchType, u32 battlerSwitchi
|
||||
|
||||
static inline bool32 CanSwitchinWin1v1(u32 hitsToKOAI, u32 hitsToKOPlayer, bool32 isSwitchinFirst, bool32 isFreeSwitch)
|
||||
{
|
||||
// Player's best move deals 0 damage
|
||||
if (hitsToKOAI == 0 && hitsToKOPlayer > 0)
|
||||
return TRUE;
|
||||
|
||||
// AI's best move deals 0 damage
|
||||
if (hitsToKOPlayer == 0 && hitsToKOAI > 0)
|
||||
return FALSE;
|
||||
|
||||
// Neither mon can damage the other
|
||||
if (hitsToKOPlayer == 0 && hitsToKOAI == 0)
|
||||
return FALSE;
|
||||
|
||||
// Free switch, need to outspeed or take 1 extra hit
|
||||
if (isFreeSwitch)
|
||||
{
|
||||
@ -2028,7 +2037,7 @@ static inline bool32 CanSwitchinWin1v1(u32 hitsToKOAI, u32 hitsToKOPlayer, bool3
|
||||
// Everything runs in the same loop to minimize computation time. This makes it harder to read, but hopefully the comments can guide you!
|
||||
static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId, u32 battler, u32 opposingBattler, u32 battlerIn1, u32 battlerIn2, enum SwitchType switchType)
|
||||
{
|
||||
int revengeKillerId = PARTY_SIZE, slowRevengeKillerId = PARTY_SIZE, fastThreatenId = PARTY_SIZE, slowThreatenId = PARTY_SIZE, damageMonId = PARTY_SIZE;
|
||||
int revengeKillerId = PARTY_SIZE, slowRevengeKillerId = PARTY_SIZE, fastThreatenId = PARTY_SIZE, slowThreatenId = PARTY_SIZE, damageMonId = PARTY_SIZE, generic1v1MonId = 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, aceMonCount = 0;
|
||||
s32 defensiveMonHitKOThreshold = 3; // 3HKO threshold that candidate defensive mons must exceed
|
||||
@ -2073,9 +2082,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
for (j = 0; j < MAX_MON_MOVES; j++)
|
||||
{
|
||||
aiMove = gAiLogicData->switchinCandidate.battleMon.moves[j];
|
||||
|
||||
if (aiMove != MOVE_NONE && !IsBattleMoveStatus(aiMove))
|
||||
damageDealt = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, gAiLogicData->switchinCandidate.battleMon, AI_ATTACKING);
|
||||
damageDealt = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, gAiLogicData->switchinCandidate.battleMon, AI_ATTACKING);
|
||||
|
||||
// Offensive switchin decisions are based on which whether switchin moves first and whether it can win a 1v1
|
||||
isSwitchinFirst = AI_WhoStrikesFirstPartyMon(battler, opposingBattler, gAiLogicData->switchinCandidate.battleMon, aiMove);
|
||||
@ -2106,6 +2113,9 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
defensiveMonId = i;
|
||||
}
|
||||
|
||||
if (canSwitchinWin1v1)
|
||||
generic1v1MonId = i;
|
||||
|
||||
// Check for mon with resistance and super effective move for best type matchup mon with effective move
|
||||
if (aiMove != MOVE_NONE && !IsBattleMoveStatus(aiMove))
|
||||
{
|
||||
@ -2184,6 +2194,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
else if (typeMatchupEffectiveId != PARTY_SIZE) return typeMatchupEffectiveId;
|
||||
else if (typeMatchupId != PARTY_SIZE) return typeMatchupId;
|
||||
else if (batonPassId != PARTY_SIZE) return batonPassId;
|
||||
else if (generic1v1MonId != PARTY_SIZE) return generic1v1MonId;
|
||||
else if (damageMonId != PARTY_SIZE) return damageMonId;
|
||||
}
|
||||
else
|
||||
@ -2194,6 +2205,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
else if (typeMatchupId != PARTY_SIZE) return typeMatchupId;
|
||||
else if (defensiveMonId != PARTY_SIZE) return defensiveMonId;
|
||||
else if (batonPassId != PARTY_SIZE) return batonPassId;
|
||||
else if (generic1v1MonId != PARTY_SIZE) return generic1v1MonId;
|
||||
}
|
||||
// If ace mon is the last available Pokemon and U-Turn/Volt Switch or Eject Pack/Button was used - switch to the mon.
|
||||
if (aceMonId != PARTY_SIZE && CountUsablePartyMons(battler) <= aceMonCount
|
||||
|
||||
@ -1255,3 +1255,16 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI won't send out defensive mon
|
||||
TURN { MOVE(player, MOVE_WATER_PULSE); EXPECT_MOVE(opponent, MOVE_BULLDOZE); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI considers 0 hits to KO as losing a 1v1")
|
||||
{
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_OMNISCIENT);
|
||||
PLAYER(SPECIES_JOLTEON) { Level(100); Ability(ABILITY_VOLT_ABSORB); Moves(MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_ZIGZAGOON) { Level(1); HP(1); Moves(MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_TANGELA) { Level(100); Moves(MOVE_THUNDERBOLT); }
|
||||
OPPONENT(SPECIES_TANGELA) { Level(100); Moves(MOVE_GIGA_DRAIN); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TACKLE); EXPECT_SEND_OUT(opponent, 2); }
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user