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
|
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
|
u32 stellarBoostFlags[NUM_BATTLE_SIDES]; // stored as a bitfield of flags for all types for each side
|
||||||
u8 fickleBeamBoosted:1;
|
u8 fickleBeamBoosted:1;
|
||||||
u8 obedienceResult:3;
|
|
||||||
u8 redCardActivates:1;
|
u8 redCardActivates:1;
|
||||||
|
u8 padding:6;
|
||||||
u8 usedMicleBerry;
|
u8 usedMicleBerry;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,7 @@ enum
|
||||||
CANCELLER_SKY_DROP,
|
CANCELLER_SKY_DROP,
|
||||||
CANCELLER_ASLEEP,
|
CANCELLER_ASLEEP,
|
||||||
CANCELLER_FROZEN,
|
CANCELLER_FROZEN,
|
||||||
|
CANCELLER_OBEDIENCE,
|
||||||
CANCELLER_TRUANT,
|
CANCELLER_TRUANT,
|
||||||
CANCELLER_RECHARGE,
|
CANCELLER_RECHARGE,
|
||||||
CANCELLER_FLINCH,
|
CANCELLER_FLINCH,
|
||||||
|
|
|
@ -1282,46 +1282,6 @@ static void Cmd_attackcanceler(void)
|
||||||
|
|
||||||
gHitMarker &= ~HITMARKER_ALLOW_NO_PP;
|
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
|
// Check if no available target present on the field or if Sky Battles ban the move
|
||||||
if ((NoTargetPresent(gBattlerAttacker, gCurrentMove)
|
if ((NoTargetPresent(gBattlerAttacker, gCurrentMove)
|
||||||
&& (!gBattleMoveEffects[gMovesInfo[gCurrentMove].effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)))
|
&& (!gBattleMoveEffects[gMovesInfo[gCurrentMove].effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)))
|
||||||
|
|
|
@ -145,8 +145,6 @@ void HandleAction_UseMove(void)
|
||||||
gBattleScripting.savedMoveEffect = 0;
|
gBattleScripting.savedMoveEffect = 0;
|
||||||
gCurrMovePos = gChosenMovePos = *(gBattleStruct->chosenMovePositions + gBattlerAttacker);
|
gCurrMovePos = gChosenMovePos = *(gBattleStruct->chosenMovePositions + gBattlerAttacker);
|
||||||
|
|
||||||
gBattleStruct->obedienceResult = GetAttackerObedienceForAction();
|
|
||||||
|
|
||||||
// choose move
|
// choose move
|
||||||
if (gProtectStructs[gBattlerAttacker].noValidMoves)
|
if (gProtectStructs[gBattlerAttacker].noValidMoves)
|
||||||
{
|
{
|
||||||
|
@ -3222,7 +3220,8 @@ void SetAtkCancellerForCalledMove(void)
|
||||||
|
|
||||||
u8 AtkCanceller_UnableToUseMove(u32 moveType)
|
u8 AtkCanceller_UnableToUseMove(u32 moveType)
|
||||||
{
|
{
|
||||||
u8 effect = 0;
|
u32 effect = 0;
|
||||||
|
u32 obedienceResult;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
switch (gBattleStruct->atkCancellerTracker)
|
switch (gBattleStruct->atkCancellerTracker)
|
||||||
|
@ -3306,6 +3305,53 @@ u8 AtkCanceller_UnableToUseMove(u32 moveType)
|
||||||
}
|
}
|
||||||
gBattleStruct->atkCancellerTracker++;
|
gBattleStruct->atkCancellerTracker++;
|
||||||
break;
|
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
|
case CANCELLER_TRUANT: // truant
|
||||||
if (GetBattlerAbility(gBattlerAttacker) == ABILITY_TRUANT && gDisableStructs[gBattlerAttacker].truantCounter)
|
if (GetBattlerAbility(gBattlerAttacker) == ABILITY_TRUANT && gDisableStructs[gBattlerAttacker].truantCounter)
|
||||||
{
|
{
|
||||||
|
@ -3554,7 +3600,6 @@ u8 AtkCanceller_UnableToUseMove(u32 moveType)
|
||||||
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 4;
|
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 4;
|
||||||
|
|
||||||
if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE
|
if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE
|
||||||
|| gBattleStruct->obedienceResult != OBEYS
|
|
||||||
|| HasTrainerUsedGimmick(gBattlerAttacker, GIMMICK_Z_MOVE))
|
|| HasTrainerUsedGimmick(gBattlerAttacker, GIMMICK_Z_MOVE))
|
||||||
gBattlescriptCurrInstr = BattleScript_MoveUsedPowder;
|
gBattlescriptCurrInstr = BattleScript_MoveUsedPowder;
|
||||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||||
|
@ -3575,8 +3620,7 @@ u8 AtkCanceller_UnableToUseMove(u32 moveType)
|
||||||
gBattleStruct->atkCancellerTracker++;
|
gBattleStruct->atkCancellerTracker++;
|
||||||
break;
|
break;
|
||||||
case CANCELLER_Z_MOVES:
|
case CANCELLER_Z_MOVES:
|
||||||
if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE
|
if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE)
|
||||||
&& gBattleStruct->obedienceResult == OBEYS)
|
|
||||||
{
|
{
|
||||||
// For Z-Mirror Move, so it doesn't play the animation twice.
|
// For Z-Mirror Move, so it doesn't play the animation twice.
|
||||||
bool32 alreadyUsed = HasTrainerUsedGimmick(gBattlerAttacker, GIMMICK_Z_MOVE);
|
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!");
|
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