From 08dd7da30cfbd22919de70d2a4a39fee088e6a0c Mon Sep 17 00:00:00 2001 From: GGbond Date: Fri, 30 Jan 2026 01:33:36 +0800 Subject: [PATCH] Fix AI wakeup-turn detection to consider Early Bird (#9053) --- src/battle_ai_util.c | 27 ++++++++--------- test/battle/ability/early_bird.c | 47 ++++++++++++++++++++++++++++- test/battle/ai/ai_check_viability.c | 19 ++++++++++++ 3 files changed, 77 insertions(+), 16 deletions(-) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 70683fc420..6bb814b66f 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -3829,24 +3829,21 @@ bool32 HasChoiceEffect(u32 battler) } } -static u32 FindMoveUsedXTurnsAgo(u32 battlerId, u32 x) -{ - s32 i, index = gBattleHistory->moveHistoryIndex[battlerId]; - for (i = 0; i < x; i++) - { - if (--index < 0) - index = AI_MOVE_HISTORY_COUNT - 1; - } - return gBattleHistory->moveHistory[battlerId][index]; -} - bool32 IsWakeupTurn(u32 battler) { - // Check if rest was used 2 turns ago - if ((gBattleMons[battler].status1 & STATUS1_SLEEP) == 1 && GetMoveEffect(FindMoveUsedXTurnsAgo(battler, 2)) == EFFECT_REST) - return TRUE; - else // no way to know + u32 sleepTurns = gBattleMons[battler].status1 & STATUS1_SLEEP; + u32 toSub; + + if (sleepTurns == 0) return FALSE; + + // Early Bird reduces the sleep timer twice as fast. + if (gAiLogicData->abilities[battler] == ABILITY_EARLY_BIRD) + toSub = 2; + else + toSub = 1; + + return sleepTurns <= toSub; } bool32 AnyPartyMemberStatused(u32 battlerId, bool32 checkSoundproof) diff --git a/test/battle/ability/early_bird.c b/test/battle/ability/early_bird.c index 9b368970f6..0f41fffc03 100644 --- a/test/battle/ability/early_bird.c +++ b/test/battle/ability/early_bird.c @@ -1,4 +1,49 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("TODO: Write Early Bird (Ability) test titles") +SINGLE_BATTLE_TEST("Early Bird wakes up if 1 sleep turn is preset") +{ + GIVEN { + PLAYER(SPECIES_DODUO) { Ability(ABILITY_EARLY_BIRD); Status1(STATUS1_SLEEP_TURN(1)); Moves(MOVE_CELEBRATE); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); } + } SCENE { + MESSAGE("Doduo woke up!"); + STATUS_ICON(player, none: TRUE); + MESSAGE("Doduo used Celebrate!"); + } +} + +SINGLE_BATTLE_TEST("Early Bird turns a 3-turn sleep into one missed turn") +{ + GIVEN { + PLAYER(SPECIES_DODUO) { Ability(ABILITY_EARLY_BIRD); Status1(STATUS1_SLEEP_TURN(3)); Moves(MOVE_CELEBRATE); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); } + } SCENE { + MESSAGE("Doduo is fast asleep."); + MESSAGE("Doduo woke up!"); + STATUS_ICON(player, none: TRUE); + MESSAGE("Doduo used Celebrate!"); + } +} + +SINGLE_BATTLE_TEST("Early Bird reduces Rest sleep to one turn") +{ + GIVEN { + PLAYER(SPECIES_DODUO) { Ability(ABILITY_EARLY_BIRD); MaxHP(99); HP(66); Moves(MOVE_REST, MOVE_CELEBRATE); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_REST); } + TURN { MOVE(player, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); } + } SCENE { + MESSAGE("Doduo is fast asleep."); + MESSAGE("Doduo woke up!"); + STATUS_ICON(player, none: TRUE); + MESSAGE("Doduo used Celebrate!"); + } +} diff --git a/test/battle/ai/ai_check_viability.c b/test/battle/ai/ai_check_viability.c index 0e6170b5fa..f5bd39b27b 100644 --- a/test/battle/ai/ai_check_viability.c +++ b/test/battle/ai/ai_check_viability.c @@ -135,6 +135,25 @@ AI_SINGLE_BATTLE_TEST("AI will only use Dream Eater if target is asleep") } } +AI_SINGLE_BATTLE_TEST("AI chooses Sleep Talk only when it will not wake up with Early Bird") +{ + enum Ability ability; + + PARAMETRIZE { ability = ABILITY_RUN_AWAY; } + PARAMETRIZE { ability = ABILITY_EARLY_BIRD; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_DODRIO) { Ability(ability); Status1(STATUS1_SLEEP_TURN(2)); Moves(MOVE_SLEEP_TALK, MOVE_TACKLE); } + } WHEN { + if (ability == ABILITY_EARLY_BIRD) + TURN { EXPECT_MOVE(opponent, MOVE_TACKLE); } + else + TURN { EXPECT_MOVE(opponent, MOVE_SLEEP_TALK); } + } +} + AI_SINGLE_BATTLE_TEST("AI sees increased base power of Spit Up") { GIVEN {