Fixes various Choice lock issues (#7383)

This commit is contained in:
Alex 2025-07-25 16:18:30 +02:00 committed by GitHub
parent e222b725d2
commit e7cf162180
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 44 additions and 43 deletions

View File

@ -123,6 +123,7 @@ enum MoveSuccessOrder
CANCELLER_BIDE,
CANCELLER_THAW,
CANCELLER_STANCE_CHANGE_2,
CANCELLER_CHOICE_LOCK,
CANCELLER_WEATHER_PRIMAL,
CANCELLER_DYNAMAX_BLOCKED,
CANCELLER_POWDER_STATUS,

View File

@ -137,7 +137,6 @@ enum MoveEndEffects
MOVEEND_ABILITIES_ATTACKER,
MOVEEND_STATUS_IMMUNITY_ABILITIES,
MOVEEND_SYNCHRONIZE_ATTACKER,
MOVEEND_CHOICE_MOVE,
MOVEEND_ATTACKER_INVISIBLE,
MOVEEND_ATTACKER_VISIBLE,
MOVEEND_TARGET_VISIBLE,

View File

@ -145,8 +145,6 @@ enum ItemHoldEffect
HOLD_EFFECT_COUNT
};
#define HOLD_EFFECT_CHOICE(holdEffect) ((holdEffect == HOLD_EFFECT_CHOICE_BAND || holdEffect == HOLD_EFFECT_CHOICE_SCARF || holdEffect == HOLD_EFFECT_CHOICE_SPECS))
// Terrain seed params
#define HOLD_EFFECT_PARAM_ELECTRIC_TERRAIN 0
#define HOLD_EFFECT_PARAM_GRASSY_TERRAIN 1

View File

@ -6,6 +6,8 @@
#include "constants/items.h"
#include "constants/moves.h"
#include "constants/tms_hms.h"
#include "constants/item_effects.h"
#include "constants/hold_effects.h"
/* Expands to:
* enum
@ -190,5 +192,6 @@ u32 GetItemFlingPower(u32 itemId);
u32 GetItemStatus1Mask(u16 itemId);
bool32 ItemHasVolatileFlag(u16 itemId, enum Volatile volatile);
u32 GetItemSellPrice(u32 itemId);
bool32 IsHoldEffectChoice(enum ItemHoldEffect holdEffect);
#endif // GUARD_ITEM_H

View File

@ -2889,7 +2889,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
}
// Choice items
if (HOLD_EFFECT_CHOICE(aiData->holdEffects[battlerAtk]) && IsBattlerItemEnabled(battlerAtk))
if (IsHoldEffectChoice(aiData->holdEffects[battlerAtk]) && IsBattlerItemEnabled(battlerAtk))
{
// Don't use user-target moves ie. Swords Dance, with exceptions
if ((moveTarget & MOVE_TARGET_USER)
@ -3060,7 +3060,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
// Both Pokemon use Trick Room on the final turn of Trick Room to anticipate both opponents Protecting to stall out.
// This unsets Trick Room and resets it with a full timer.
case EFFECT_TRICK_ROOM:
if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == gBattleTurnCounter
if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == gBattleTurnCounter
&& ShouldSetFieldStatus(battlerAtk, STATUS_FIELD_TRICK_ROOM)
&& HasMoveWithEffect(battlerAtkPartner, MOVE_TRICK_ROOM)
&& RandomPercentage(RNG_AI_REFRESH_TRICK_ROOM_ON_LAST_TURN, DOUBLE_TRICK_ROOM_ON_LAST_TURN_CHANCE))
@ -3068,7 +3068,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
break;
case EFFECT_TAILWIND:
// Anticipate both opponents protecting to stall out Trick Room, and apply Tailwind.
if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == gBattleTurnCounter
if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == gBattleTurnCounter
&& RandomPercentage(RNG_AI_APPLY_TAILWIND_ON_LAST_TURN_OF_TRICK_ROOM, TAILWIND_IN_TRICK_ROOM_CHANCE))
ADJUST_SCORE(BEST_EFFECT);
break;

View File

@ -165,7 +165,7 @@ static bool32 AI_DoesChoiceEffectBlockMove(u32 battler, u32 move)
{
// Choice locked into something else
if (gAiLogicData->lastUsedMove[battler] != MOVE_NONE && gAiLogicData->lastUsedMove[battler] != move
&& ((HOLD_EFFECT_CHOICE(GetBattlerHoldEffect(battler, FALSE)) && IsBattlerItemEnabled(battler))
&& ((IsHoldEffectChoice(GetBattlerHoldEffect(battler, FALSE)) && IsBattlerItemEnabled(battler))
|| gBattleMons[battler].ability == ABILITY_GORILLA_TACTICS))
return TRUE;
return FALSE;
@ -1003,7 +1003,7 @@ static bool32 ShouldSwitchIfBadChoiceLock(u32 battler)
|| CanAbilityBlockMove(battler, opposingBattler, gAiLogicData->abilities[battler], gAiLogicData->abilities[opposingBattler], lastUsedMove, AI_CHECK)))
moveAffectsTarget = FALSE;
if (HOLD_EFFECT_CHOICE(holdEffect) && IsBattlerItemEnabled(battler))
if (IsHoldEffectChoice(holdEffect) && IsBattlerItemEnabled(battler))
{
if ((GetMoveCategory(lastUsedMove) == DAMAGE_CATEGORY_STATUS || !moveAffectsTarget) && RandomPercentage(RNG_AI_SWITCH_CHOICE_LOCKED, GetSwitchChance(SHOULD_SWITCH_CHOICE_LOCKED)))
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
@ -1902,7 +1902,7 @@ static u32 GetBattleMonTypeMatchup(struct BattlePokemon opposingBattleMon, struc
typeEffectiveness1 = uq4_12_multiply(typeEffectiveness1, (GetTypeModifier(atkType1, defType2)));
if (typeEffectiveness1 == 0) // Immunity
typeEffectiveness1 = UQ_4_12(0.1);
if (atkType2 != atkType1)
{
typeEffectiveness2 = uq4_12_multiply(typeEffectiveness2, (GetTypeModifier(atkType2, defType1)));

View File

@ -5939,7 +5939,6 @@ static void Cmd_moveend(void)
s32 i;
bool32 effect = FALSE;
u32 moveType = 0;
enum ItemHoldEffect holdEffectAtk = HOLD_EFFECT_NONE;
u32 endMode, endState;
u32 originallyUsedMove;
@ -5951,7 +5950,6 @@ static void Cmd_moveend(void)
endMode = cmd->endMode;
endState = cmd->endState;
holdEffectAtk = GetBattlerHoldEffect(gBattlerAttacker, TRUE);
moveType = GetBattleMoveType(gCurrentMove);
enum BattleMoveEffects moveEffect = GetMoveEffect(gCurrentMove);
@ -6149,35 +6147,6 @@ static void Cmd_moveend(void)
effect = TRUE;
gBattleScripting.moveendState++;
break;
case MOVEEND_CHOICE_MOVE: // update choice band move
{
u16 *choicedMoveAtk = &gBattleStruct->choicedMove[gBattlerAttacker];
if (gHitMarker & HITMARKER_OBEYS
&& !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
&& gChosenMove != MOVE_STRUGGLE
&& (*choicedMoveAtk == MOVE_NONE || *choicedMoveAtk == MOVE_UNAVAILABLE)
&& (HOLD_EFFECT_CHOICE(holdEffectAtk) || GetBattlerAbility(gBattlerAttacker) == ABILITY_GORILLA_TACTICS))
{
if ((moveEffect == EFFECT_BATON_PASS || moveEffect == EFFECT_HEALING_WISH)
&& !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_FAILED))
{
gBattleScripting.moveendState++;
break;
}
*choicedMoveAtk = gChosenMove;
}
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (gBattleMons[gBattlerAttacker].moves[i] == *choicedMoveAtk)
break;
}
if (i == MAX_MON_MOVES)
{
*choicedMoveAtk = MOVE_NONE;
}
gBattleScripting.moveendState++;
break;
}
case MOVEEND_ITEM_EFFECTS_TARGET:
if (ItemBattleEffects(ITEMEFFECT_TARGET, gBattlerTarget))
effect = TRUE;

View File

@ -1481,7 +1481,7 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler)
}
gPotentialItemEffectBattler = battler;
if (DYNAMAX_BYPASS_CHECK && HOLD_EFFECT_CHOICE(holdEffect) && *choicedMove != MOVE_NONE && *choicedMove != MOVE_UNAVAILABLE && *choicedMove != move)
if (DYNAMAX_BYPASS_CHECK && IsHoldEffectChoice(holdEffect) && *choicedMove != MOVE_NONE && *choicedMove != MOVE_UNAVAILABLE && *choicedMove != move)
{
gCurrentMove = *choicedMove;
gLastUsedItem = gBattleMons[battler].item;
@ -1600,7 +1600,7 @@ u32 CheckMoveLimitations(u32 battler, u8 unusableMoves, u16 check)
else if (check & MOVE_LIMITATION_ENCORE && gDisableStructs[battler].encoreTimer && gDisableStructs[battler].encoredMove != move)
unusableMoves |= 1u << i;
// Choice Items
else if (check & MOVE_LIMITATION_CHOICE_ITEM && HOLD_EFFECT_CHOICE(holdEffect) && *choicedMove != MOVE_NONE && *choicedMove != MOVE_UNAVAILABLE && *choicedMove != move)
else if (check & MOVE_LIMITATION_CHOICE_ITEM && IsHoldEffectChoice(holdEffect) && *choicedMove != MOVE_NONE && *choicedMove != MOVE_UNAVAILABLE && *choicedMove != move)
unusableMoves |= 1u << i;
// Assault Vest
else if (check & MOVE_LIMITATION_ASSAULT_VEST && holdEffect == HOLD_EFFECT_ASSAULT_VEST && IsBattleMoveStatus(move) && moveEffect != EFFECT_ME_FIRST)
@ -2295,6 +2295,29 @@ static enum MoveCanceller CancellerStanceChangeTwo(void)
return MOVE_STEP_SUCCESS;
}
static enum MoveCanceller CancellerChoiceLock(void)
{
u16 *choicedMoveAtk = &gBattleStruct->choicedMove[gBattlerAttacker];
enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(gBattlerAttacker, TRUE);
if (gChosenMove != MOVE_STRUGGLE
&& (*choicedMoveAtk == MOVE_NONE || *choicedMoveAtk == MOVE_UNAVAILABLE)
&& (IsHoldEffectChoice(holdEffect) || GetBattlerAbility(gBattlerAttacker) == ABILITY_GORILLA_TACTICS))
*choicedMoveAtk = gChosenMove;
u32 moveIndex;
for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++)
{
if (gBattleMons[gBattlerAttacker].moves[moveIndex] == *choicedMoveAtk)
break;
}
if (moveIndex == MAX_MON_MOVES)
*choicedMoveAtk = MOVE_NONE;
return MOVE_STEP_SUCCESS;
}
static enum MoveCanceller CancellerWeatherPrimal(void)
{
enum MoveCanceller effect = MOVE_STEP_SUCCESS;
@ -2564,6 +2587,7 @@ static enum MoveCanceller (*const sMoveSuccessOrderCancellers[])(void) =
[CANCELLER_BIDE] = CancellerBide,
[CANCELLER_THAW] = CancellerThaw,
[CANCELLER_STANCE_CHANGE_2] = CancellerStanceChangeTwo,
[CANCELLER_CHOICE_LOCK] = CancellerChoiceLock,
[CANCELLER_WEATHER_PRIMAL] = CancellerWeatherPrimal,
[CANCELLER_DYNAMAX_BLOCKED] = CancellerDynamaxBlocked,
[CANCELLER_POWDER_STATUS] = CancellerPowderStatus,

View File

@ -50,7 +50,7 @@ const struct TmHmIndexKey gTMHMItemMoveIds[NUM_ALL_MACHINES + 1] =
FOREACH_HM(UNPACK_HM_ITEM_ID)
/*
* Expands to the following:
*
*
* [1] = { ITEM_TM_FOCUS_PUNCH, MOVE_FOCUS_PUNCH },
* [2] = { ITEM_TM_DRAGON_CLAW, MOVE_DRAGON_CLAW },
* [3] = { ITEM_TM_WATER_PULSE, MOVE_WATER_PULSE },
@ -976,3 +976,10 @@ u32 GetItemSellPrice(u32 itemId)
{
return GetItemPrice(itemId) / ITEM_SELL_FACTOR;
}
bool32 IsHoldEffectChoice(enum ItemHoldEffect holdEffect)
{
return holdEffect == HOLD_EFFECT_CHOICE_BAND
|| holdEffect == HOLD_EFFECT_CHOICE_SCARF
|| holdEffect == HOLD_EFFECT_CHOICE_SPECS;
}