Fixes choiced moves not locked in after ability block (#5738)
This commit is contained in:
parent
987264caea
commit
0ca588943b
5 changed files with 77 additions and 47 deletions
|
@ -802,8 +802,8 @@ struct BattleStruct
|
|||
u8 categoryOverride; // for Z-Moves and Max Moves
|
||||
u32 stellarBoostFlags[NUM_BATTLE_SIDES]; // stored as a bitfield of flags for all types for each side
|
||||
u8 fickleBeamBoosted:1;
|
||||
u8 obedienceResult:3;
|
||||
u8 redCardActivates:1;
|
||||
u8 padding:6;
|
||||
u8 usedMicleBerry;
|
||||
};
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@ enum
|
|||
CANCELLER_SKY_DROP,
|
||||
CANCELLER_ASLEEP,
|
||||
CANCELLER_FROZEN,
|
||||
CANCELLER_OBEDIENCE,
|
||||
CANCELLER_TRUANT,
|
||||
CANCELLER_RECHARGE,
|
||||
CANCELLER_FLINCH,
|
||||
|
|
|
@ -1282,46 +1282,6 @@ static void Cmd_attackcanceler(void)
|
|||
|
||||
gHitMarker &= ~HITMARKER_ALLOW_NO_PP;
|
||||
|
||||
if (!(gHitMarker & HITMARKER_OBEYS) && !(gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS))
|
||||
{
|
||||
switch (gBattleStruct->obedienceResult)
|
||||
{
|
||||
case OBEYS:
|
||||
break;
|
||||
case DISOBEYS_LOAFS:
|
||||
// Randomly select, then print a disobedient string
|
||||
// B_MSG_LOAFING, B_MSG_WONT_OBEY, B_MSG_TURNED_AWAY, or B_MSG_PRETEND_NOT_NOTICE
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = MOD(Random(), NUM_LOAF_STRINGS);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedLoafingAround;
|
||||
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
||||
return;
|
||||
case DISOBEYS_HITS_SELF:
|
||||
gBattlerTarget = gBattlerAttacker;
|
||||
gBattleMoveDamage = CalculateMoveDamage(MOVE_NONE, gBattlerAttacker, gBattlerAttacker, TYPE_MYSTERY, 40, FALSE, FALSE, TRUE);
|
||||
gBattlescriptCurrInstr = BattleScript_IgnoresAndHitsItself;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
gHitMarker |= HITMARKER_OBEYS;
|
||||
return;
|
||||
case DISOBEYS_FALL_ASLEEP:
|
||||
gBattlescriptCurrInstr = BattleScript_IgnoresAndFallsAsleep;
|
||||
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
||||
return;
|
||||
case DISOBEYS_WHILE_ASLEEP:
|
||||
gBattlescriptCurrInstr = BattleScript_IgnoresWhileAsleep;
|
||||
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
||||
return;
|
||||
case DISOBEYS_RANDOM_MOVE:
|
||||
gCalledMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos];
|
||||
SetAtkCancellerForCalledMove();
|
||||
gBattlescriptCurrInstr = BattleScript_IgnoresAndUsesRandomMove;
|
||||
gBattlerTarget = GetMoveTarget(gCalledMove, NO_TARGET_OVERRIDE);
|
||||
gHitMarker |= HITMARKER_DISOBEDIENT_MOVE;
|
||||
gHitMarker |= HITMARKER_OBEYS;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
gHitMarker |= HITMARKER_OBEYS;
|
||||
// Check if no available target present on the field or if Sky Battles ban the move
|
||||
if ((NoTargetPresent(gBattlerAttacker, gCurrentMove)
|
||||
&& (!gBattleMoveEffects[gMovesInfo[gCurrentMove].effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)))
|
||||
|
|
|
@ -145,8 +145,6 @@ void HandleAction_UseMove(void)
|
|||
gBattleScripting.savedMoveEffect = 0;
|
||||
gCurrMovePos = gChosenMovePos = *(gBattleStruct->chosenMovePositions + gBattlerAttacker);
|
||||
|
||||
gBattleStruct->obedienceResult = GetAttackerObedienceForAction();
|
||||
|
||||
// choose move
|
||||
if (gProtectStructs[gBattlerAttacker].noValidMoves)
|
||||
{
|
||||
|
@ -3222,7 +3220,8 @@ void SetAtkCancellerForCalledMove(void)
|
|||
|
||||
u8 AtkCanceller_UnableToUseMove(u32 moveType)
|
||||
{
|
||||
u8 effect = 0;
|
||||
u32 effect = 0;
|
||||
u32 obedienceResult;
|
||||
do
|
||||
{
|
||||
switch (gBattleStruct->atkCancellerTracker)
|
||||
|
@ -3306,6 +3305,53 @@ u8 AtkCanceller_UnableToUseMove(u32 moveType)
|
|||
}
|
||||
gBattleStruct->atkCancellerTracker++;
|
||||
break;
|
||||
case CANCELLER_OBEDIENCE:
|
||||
obedienceResult = GetAttackerObedienceForAction();
|
||||
if (obedienceResult != OBEYS
|
||||
&& !(gHitMarker & HITMARKER_NO_PPDEDUCT) // Don't check obedience after first hit of multi target move or multi hit moves
|
||||
&& !(gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS))
|
||||
{
|
||||
switch (obedienceResult)
|
||||
{
|
||||
case DISOBEYS_LOAFS:
|
||||
// Randomly select, then print a disobedient string
|
||||
// B_MSG_LOAFING, B_MSG_WONT_OBEY, B_MSG_TURNED_AWAY, or B_MSG_PRETEND_NOT_NOTICE
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = MOD(Random(), NUM_LOAF_STRINGS);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedLoafingAround;
|
||||
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
||||
break;
|
||||
case DISOBEYS_HITS_SELF:
|
||||
gBattlerTarget = gBattlerAttacker;
|
||||
gBattleMoveDamage = CalculateMoveDamage(MOVE_NONE, gBattlerAttacker, gBattlerAttacker, TYPE_MYSTERY, 40, FALSE, FALSE, TRUE);
|
||||
gBattlescriptCurrInstr = BattleScript_IgnoresAndHitsItself;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
gHitMarker |= HITMARKER_OBEYS;
|
||||
break;
|
||||
case DISOBEYS_FALL_ASLEEP:
|
||||
gBattlescriptCurrInstr = BattleScript_IgnoresAndFallsAsleep;
|
||||
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
||||
break;
|
||||
case DISOBEYS_WHILE_ASLEEP:
|
||||
gBattlescriptCurrInstr = BattleScript_IgnoresWhileAsleep;
|
||||
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
||||
break;
|
||||
case DISOBEYS_RANDOM_MOVE:
|
||||
gCalledMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos];
|
||||
SetAtkCancellerForCalledMove();
|
||||
gBattlescriptCurrInstr = BattleScript_IgnoresAndUsesRandomMove;
|
||||
gBattlerTarget = GetMoveTarget(gCalledMove, NO_TARGET_OVERRIDE);
|
||||
gHitMarker |= HITMARKER_DISOBEDIENT_MOVE;
|
||||
gHitMarker |= HITMARKER_OBEYS;
|
||||
break;
|
||||
}
|
||||
effect = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
gHitMarker |= HITMARKER_OBEYS;
|
||||
}
|
||||
gBattleStruct->atkCancellerTracker++;
|
||||
break;
|
||||
case CANCELLER_TRUANT: // truant
|
||||
if (GetBattlerAbility(gBattlerAttacker) == ABILITY_TRUANT && gDisableStructs[gBattlerAttacker].truantCounter)
|
||||
{
|
||||
|
@ -3554,7 +3600,6 @@ u8 AtkCanceller_UnableToUseMove(u32 moveType)
|
|||
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 4;
|
||||
|
||||
if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE
|
||||
|| gBattleStruct->obedienceResult != OBEYS
|
||||
|| HasTrainerUsedGimmick(gBattlerAttacker, GIMMICK_Z_MOVE))
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedPowder;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
|
@ -3575,8 +3620,7 @@ u8 AtkCanceller_UnableToUseMove(u32 moveType)
|
|||
gBattleStruct->atkCancellerTracker++;
|
||||
break;
|
||||
case CANCELLER_Z_MOVES:
|
||||
if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE
|
||||
&& gBattleStruct->obedienceResult == OBEYS)
|
||||
if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE)
|
||||
{
|
||||
// For Z-Mirror Move, so it doesn't play the animation twice.
|
||||
bool32 alreadyUsed = HasTrainerUsedGimmick(gBattlerAttacker, GIMMICK_Z_MOVE);
|
||||
|
|
|
@ -805,3 +805,28 @@ AI_SINGLE_BATTLE_TEST("AI uses a guaranteed KO move instead of the move with the
|
|||
NOT MESSAGE("Wobbuffet fainted!");
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI stays choice locked into moves in spite of the player's ability disabling them")
|
||||
{
|
||||
u32 playerMon, ability, aiMove;
|
||||
PARAMETRIZE { ability = ABILITY_DAZZLING; playerMon = SPECIES_BRUXISH; aiMove = MOVE_QUICK_ATTACK; }
|
||||
PARAMETRIZE { ability = ABILITY_QUEENLY_MAJESTY; playerMon = SPECIES_TSAREENA; aiMove = MOVE_QUICK_ATTACK; }
|
||||
PARAMETRIZE { ability = ABILITY_ARMOR_TAIL; playerMon = SPECIES_FARIGIRAF; aiMove = MOVE_QUICK_ATTACK; }
|
||||
PARAMETRIZE { ability = ABILITY_SOUNDPROOF; playerMon = SPECIES_EXPLOUD; aiMove = MOVE_BOOMBURST; }
|
||||
PARAMETRIZE { ability = ABILITY_BULLETPROOF; playerMon = SPECIES_CHESNAUGHT; aiMove = MOVE_BULLET_SEED; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_CHOICE_BAND].holdEffect == HOLD_EFFECT_CHOICE_BAND);
|
||||
ASSUME(gMovesInfo[MOVE_QUICK_ATTACK].priority == 1);
|
||||
ASSUME(gMovesInfo[MOVE_BOOMBURST].soundMove == TRUE);
|
||||
ASSUME(gMovesInfo[MOVE_BULLET_SEED].ballisticMove == TRUE);
|
||||
ASSUME(gMovesInfo[MOVE_TAIL_WHIP].category == DAMAGE_CATEGORY_STATUS);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(playerMon) { Ability(ability); }
|
||||
OPPONENT(SPECIES_SMEARGLE) { Item(ITEM_CHOICE_BAND); Moves(aiMove, MOVE_TACKLE); }
|
||||
} WHEN {
|
||||
TURN { SWITCH(player, 1); EXPECT_MOVE(opponent, aiMove); }
|
||||
TURN { EXPECT_MOVE(opponent, aiMove); }
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue