diff --git a/include/battle.h b/include/battle.h index edefe6d21c..40ba305f73 100644 --- a/include/battle.h +++ b/include/battle.h @@ -235,7 +235,8 @@ struct AiLogicData u32 shouldConsiderExplosion:1; // Determines whether AI should consider explosion moves this turn u32 shouldSwitch:4; // Stores result of ShouldSwitch, which decides whether a mon should be switched out u32 shouldConsiderFinalGambit:1; // Determines whether AI should consider Final Gambit this turn - u32 padding2:19; + u32 switchInCalc:1; // Indicates if we're doing switch in calcs, this is purely for Retaliate damage calcs + u32 padding2:18; }; struct AiThinkingStruct diff --git a/src/battle_ai_switch.c b/src/battle_ai_switch.c index e3d0c0acbc..8b1db4d64e 100644 --- a/src/battle_ai_switch.c +++ b/src/battle_ai_switch.c @@ -50,6 +50,8 @@ static void InitializeSwitchinCandidate(enum BattlerId switchinBattler, u32 monI SetBattlerAiData(switchinBattler, gAiLogicData); SetBattlerFieldStatusForSwitchin(switchinBattler); gBattlerPartyIndexes[switchinBattler] = monIndex; + gAiLogicData->switchInCalc = TRUE; + for (enum BattlerId battlerIndex = 0; battlerIndex < gBattlersCount; battlerIndex++) { if (switchinBattler == battlerIndex || !IsBattlerAlive(battlerIndex)) @@ -59,6 +61,7 @@ static void InitializeSwitchinCandidate(enum BattlerId switchinBattler, u32 monI CalcBattlerAiMovesData(gAiLogicData, battlerIndex, switchinBattler, AI_GetSwitchinWeather(switchinBattler), AI_GetSwitchinFieldStatus(switchinBattler)); } + gAiLogicData->switchInCalc = FALSE; gBattlerPartyIndexes[switchinBattler] = storeCurrBattlerPartyIndex; gAiThinkingStruct->saved[switchinBattler].saved = FALSE; } diff --git a/src/battle_main.c b/src/battle_main.c index 3c9eeece26..72c2b651e5 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -4018,7 +4018,7 @@ void BattleTurnPassed(void) { if (gSideTimers[i].retaliateTimer > 0) gSideTimers[i].retaliateTimer--; - } + } gFieldStatuses &= ~STATUS_FIELD_ION_DELUGE; diff --git a/src/battle_util.c b/src/battle_util.c index a608a56335..8db2e1e858 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -6551,9 +6551,12 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct BattleContext *ctx) modifier = uq4_12_multiply(modifier, UQ_4_12(2.0)); break; case EFFECT_RETALIATE: - if (gSideTimers[atkSide].retaliateTimer == 1) + { + u32 retaliateTimer = gSideTimers[atkSide].retaliateTimer; + if (retaliateTimer == 1 || (gAiLogicData->switchInCalc && retaliateTimer == 2)) modifier = uq4_12_multiply(modifier, UQ_4_12(2.0)); break; + } case EFFECT_SOLAR_BEAM: if ((GetConfig(B_SANDSTORM_SOLAR_BEAM) >= GEN_3 && IsBattlerWeatherAffected(battlerAtk, B_WEATHER_LOW_LIGHT)) || IsBattlerWeatherAffected(battlerAtk, (B_WEATHER_RAIN | B_WEATHER_ICY_ANY | B_WEATHER_FOG))) // Excludes Sandstorm diff --git a/test/battle/ai/ai_calc_best_move_score.c b/test/battle/ai/ai_calc_best_move_score.c index 7fd3ff546b..a3efc06ad0 100644 --- a/test/battle/ai/ai_calc_best_move_score.c +++ b/test/battle/ai/ai_calc_best_move_score.c @@ -285,3 +285,24 @@ AI_SINGLE_BATTLE_TEST("Fillet Away AI handling") TURN { MOVE(player, move); EXPECT_MOVE(opponent, move == MOVE_SCALD ? MOVE_FILLET_AWAY : MOVE_AQUA_CUTTER); } } } + +AI_SINGLE_BATTLE_TEST("Retaliate sees damage correctly on the field") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_WOBBUFFET) { Level(50); HP(100); Nature(NATURE_QUIRKY); Ability(ABILITY_TELEPATHY); Speed(58); Moves(MOVE_TACKLE); } + OPPONENT(SPECIES_RATTATA){ Level(1); HP(1); Nature(NATURE_QUIRKY); Speed(1); Moves(MOVE_TACKLE);} + OPPONENT(SPECIES_KANGASKHAN) { Level(50); Nature(NATURE_QUIRKY); Ability(ABILITY_INNER_FOCUS); Speed(251); Moves(MOVE_RETALIATE, MOVE_SLASH); } + } WHEN { + TURN { + MOVE(player, MOVE_TACKLE); + EXPECT_MOVE(opponent, MOVE_TACKLE); + EXPECT_SEND_OUT(opponent, 1); + } + TURN { + MOVE(player, MOVE_TACKLE); + SCORE_EQ_VAL(opponent, MOVE_RETALIATE, (AI_SCORE_DEFAULT + BEST_DAMAGE_MOVE + FAST_KILL)); + SCORE_EQ_VAL(opponent, MOVE_SLASH, (AI_SCORE_DEFAULT)); + } + } +} diff --git a/test/battle/ai/ai_switching.c b/test/battle/ai/ai_switching.c index 477bf5a784..27ecef7e8e 100644 --- a/test/battle/ai/ai_switching.c +++ b/test/battle/ai/ai_switching.c @@ -2225,3 +2225,16 @@ AI_SINGLE_BATTLE_TEST("Rage Fist stacks are seen properly for switch logic") TURN { MOVE(player, MOVE_PSYCHIC); EXPECT_SEND_OUT(opponent, 1); } } } + +AI_SINGLE_BATTLE_TEST("Retaliate sees damage correctly for post ko switch in") +{ + 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_GABITE) { Level(50); Speed(2);} + OPPONENT(SPECIES_ZIGZAGOON) { Level(1); Speed(3); HP(1); Moves(MOVE_TACKLE); } + OPPONENT(SPECIES_GROUDON) { Level(85); Speed(3); Moves(MOVE_PRECIPICE_BLADES); } + OPPONENT(SPECIES_STOUTLAND) { Level(50); Speed(3); Moves(MOVE_RETALIATE); } + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); EXPECT_SEND_OUT(opponent, 2); } + } +}