diff --git a/include/battle_controllers.h b/include/battle_controllers.h index 50860a7285..5e92cac763 100644 --- a/include/battle_controllers.h +++ b/include/battle_controllers.h @@ -313,6 +313,8 @@ void MoveSelectionDestroyCursorAt(u8 cursorPosition); void PlayerHandleChooseMove(u32 battler); void HandleInputChooseMove(u32 battler); void HandleInputChooseTarget(u32 battler); +void HandleInputShowEntireFieldTargets(u32 battler); +void HandleInputShowTargets(u32 battler); void HandleMoveSwitching(u32 battler); void HandleChooseMoveAfterDma3(u32 battler); diff --git a/include/config/item.h b/include/config/item.h index 2f60739335..272848e82e 100644 --- a/include/config/item.h +++ b/include/config/item.h @@ -20,6 +20,7 @@ #define I_POWER_ITEM_BOOST GEN_LATEST // In Gen7+, Power Items grant 8 EVs instead of 4 EVs. #define I_PREMIER_BALL_BONUS GEN_LATEST // In LGPE onwards (Gen8+ here), you are given a Premier Ball for every 10 Poké Balls of any type and in the same purchase. Previously, it only applied to regular Poké Balls and only 1 could be obtained per purchase. #define I_ROTOM_CATALOG_THUNDER_SHOCK GEN_LATEST // In Gen9+, reverting Rotom to its base form will teach it Thunder Shock even if it knows another move. +#define I_REPEL_INCLUDE_FAINTED GEN_LATEST // In Gen1 and Gen6+, Repels always use the level of the first member of the party to check which wild Pokémon to prevent encounters with, even if that member is fainted. In Gen2-5, it only uses the level of the first non-fainted Pokémon. // TM config #define I_REUSABLE_TMS FALSE // In Gen5-8, TMs are reusable. Setting this to TRUE will make all vanilla TMs reusable, though they can also be cherry-picked by setting their importance to 1. diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index df055d62ba..55b38f7ad7 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -1739,6 +1739,14 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) break; case EFFECT_HIT_ESCAPE: break; + case EFFECT_CHILLY_RECEPTION: + if (CountUsablePartyMons(battlerAtk) == 0) + ADJUST_SCORE(-10); + else if (weather & (B_WEATHER_SNOW | B_WEATHER_PRIMAL_ANY) || IsMoveEffectWeather(aiData->partnerMove)) + ADJUST_SCORE(-8); + else if (weather & B_WEATHER_HAIL) + ADJUST_SCORE(-2); // mainly to prevent looping between hail and snow + break; case EFFECT_BELLY_DRUM: case EFFECT_FILLET_AWAY: if (aiData->abilities[battlerAtk] == ABILITY_CONTRARY) @@ -2773,6 +2781,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case EFFECT_SNOWSCAPE: case EFFECT_RAIN_DANCE: case EFFECT_SANDSTORM: + case EFFECT_CHILLY_RECEPTION: if (IsMoveEffectWeather(move)) ADJUST_SCORE(-10); break; @@ -2852,6 +2861,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) } break; case EFFECT_SNOWSCAPE: + case EFFECT_CHILLY_RECEPTION: if (IsBattlerAlive(battlerAtkPartner) && ShouldSetSnow(battlerAtkPartner, atkPartnerAbility, atkPartnerHoldEffect)) { @@ -3621,6 +3631,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) //fallthrough case EFFECT_HIT_ESCAPE: case EFFECT_PARTING_SHOT: + case EFFECT_CHILLY_RECEPTION: if (!IsDoubleBattle()) { switch (ShouldPivot(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, movesetIndex)) @@ -4879,6 +4890,7 @@ static s32 AI_SetupFirstTurn(u32 battlerAtk, u32 battlerDef, u32 move, s32 score case EFFECT_SANDSTORM: case EFFECT_HAIL: case EFFECT_SNOWSCAPE: + case EFFECT_CHILLY_RECEPTION: case EFFECT_GEOMANCY: case EFFECT_VICTORY_DANCE: ADJUST_SCORE(DECENT_EFFECT); diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index c31dab8936..e2d0d85a3c 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -2002,7 +2002,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId, } // If ace mon is the last available Pokemon and U-Turn/Volt Switch was used - switch to the mon. if (aceMonId != PARTY_SIZE - && (gMovesInfo[gLastUsedMove].effect == EFFECT_HIT_ESCAPE || gMovesInfo[gLastUsedMove].effect == EFFECT_PARTING_SHOT || gMovesInfo[gLastUsedMove].effect == EFFECT_BATON_PASS)) + && (gMovesInfo[gLastUsedMove].effect == EFFECT_HIT_ESCAPE || gMovesInfo[gLastUsedMove].effect == EFFECT_PARTING_SHOT || gMovesInfo[gLastUsedMove].effect == EFFECT_BATON_PASS || gMovesInfo[gLastUsedMove].effect == EFFECT_CHILLY_RECEPTION)) return aceMonId; return PARTY_SIZE; diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index f1509fdd80..8c1cb578ed 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -3262,7 +3262,8 @@ bool32 IsMoveEffectWeather(u32 move) || gMovesInfo[move].effect == EFFECT_RAIN_DANCE || gMovesInfo[move].effect == EFFECT_SANDSTORM || gMovesInfo[move].effect == EFFECT_HAIL - || gMovesInfo[move].effect == EFFECT_SNOWSCAPE)) + || gMovesInfo[move].effect == EFFECT_SNOWSCAPE + || gMovesInfo[move].effect == EFFECT_CHILLY_RECEPTION)) return TRUE; return FALSE; } diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index 61f2b8162d..52507157e7 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -593,7 +593,7 @@ static void HideShownTargets(u32 battler) } } -static void HandleInputShowEntireFieldTargets(u32 battler) +void HandleInputShowEntireFieldTargets(u32 battler) { if (JOY_HELD(DPAD_ANY) && gSaveBlock2Ptr->optionsButtonMode == OPTIONS_BUTTON_MODE_L_EQUALS_A) gPlayerDpadHoldFrames++; @@ -621,7 +621,7 @@ static void HandleInputShowEntireFieldTargets(u32 battler) } } -static void HandleInputShowTargets(u32 battler) +void HandleInputShowTargets(u32 battler) { if (JOY_HELD(DPAD_ANY) && gSaveBlock2Ptr->optionsButtonMode == OPTIONS_BUTTON_MODE_L_EQUALS_A) gPlayerDpadHoldFrames++; diff --git a/src/type_icons.c b/src/type_icons.c index 2877d22071..361312ab91 100644 --- a/src/type_icons.c +++ b/src/type_icons.c @@ -471,15 +471,27 @@ static void FreeAllTypeIconResources(void) } } +static void (* const sShowTypesControllerFuncs[])(u32 battler) = +{ + PlayerHandleChooseMove, + HandleChooseMoveAfterDma3, + HandleInputChooseTarget, + HandleInputShowTargets, + HandleInputShowEntireFieldTargets, + HandleMoveSwitching, + HandleInputChooseMove, +}; + + static bool32 ShouldHideTypeIcon(u32 battlerId) { - return gBattlerControllerFuncs[battlerId] != PlayerHandleChooseMove - && gBattlerControllerFuncs[battlerId] != HandleInputChooseMove - && gBattlerControllerFuncs[battlerId] != HandleChooseMoveAfterDma3 - && gBattlerControllerFuncs[battlerId] != HandleInputChooseMove - && gBattlerControllerFuncs[battlerId] != HandleInputChooseTarget - && gBattlerControllerFuncs[battlerId] != HandleMoveSwitching - && gBattlerControllerFuncs[battlerId] != HandleInputChooseMove; + u32 funcIndex; + + for (funcIndex = 0; funcIndex < ARRAY_COUNT(sShowTypesControllerFuncs); funcIndex++) + if (gBattlerControllerFuncs[battlerId] == sShowTypesControllerFuncs[funcIndex]) + return FALSE; + + return TRUE; } static s32 GetTypeIconHideMovement(bool32 useDoubleBattleCoords, u32 position) diff --git a/src/wild_encounter.c b/src/wild_encounter.c index ae7770aa3a..033eec56da 100644 --- a/src/wild_encounter.c +++ b/src/wild_encounter.c @@ -1002,14 +1002,10 @@ static bool8 IsWildLevelAllowedByRepel(u8 wildLevel) for (i = 0; i < PARTY_SIZE; i++) { - if (GetMonData(&gPlayerParty[i], MON_DATA_HP) && !GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG)) + if (I_REPEL_INCLUDE_FAINTED == GEN_1 || I_REPEL_INCLUDE_FAINTED >= GEN_6 || GetMonData(&gPlayerParty[i], MON_DATA_HP)) { - u8 ourLevel = GetMonData(&gPlayerParty[i], MON_DATA_LEVEL); - - if (wildLevel < ourLevel) - return FALSE; - else - return TRUE; + if (!GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG)) + return wildLevel >= GetMonData(&gPlayerParty[i], MON_DATA_LEVEL); } } diff --git a/test/battle/ai/ai_flag_sequence_switching.c b/test/battle/ai/ai_flag_sequence_switching.c index 1b4a264a24..7a0f3528bd 100644 --- a/test/battle/ai/ai_flag_sequence_switching.c +++ b/test/battle/ai/ai_flag_sequence_switching.c @@ -64,7 +64,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SEQUENCE_SWITCHING: Roar and Dragon Tail still fo } } -AI_SINGLE_BATTLE_TEST("AI_FLAG_SEQUENCE_SWITCHING: AI will always switch into lowest party index after U-Turn, Parting Shot, and Baton Pass") +AI_SINGLE_BATTLE_TEST("AI_FLAG_SEQUENCE_SWITCHING: AI will always switch into lowest party index after U-Turn, Parting Shot, Baton Pass, and Chilly Reception") { u32 j, aiSequenceSwitchingFlag = 0, move = MOVE_NONE; @@ -72,6 +72,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SEQUENCE_SWITCHING: AI will always switch into lo MOVE_U_TURN, MOVE_PARTING_SHOT, MOVE_BATON_PASS, + MOVE_CHILLY_RECEPTION, }; for (j = 0; j < ARRAY_COUNT(switchMoves); j++) @@ -84,6 +85,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SEQUENCE_SWITCHING: AI will always switch into lo ASSUME(gMovesInfo[MOVE_U_TURN].effect == EFFECT_HIT_ESCAPE); ASSUME(gMovesInfo[MOVE_PARTING_SHOT].effect == EFFECT_PARTING_SHOT); ASSUME(gMovesInfo[MOVE_BATON_PASS].effect == EFFECT_BATON_PASS); + ASSUME(gMovesInfo[MOVE_CHILLY_RECEPTION].effect == EFFECT_CHILLY_RECEPTION); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiSequenceSwitchingFlag); PLAYER(SPECIES_SWELLOW) { Level (50); } OPPONENT(SPECIES_MACHOP) { Level(1); Moves(move); }