From d342b373f086d470af2648a1a841934ecaa2ade1 Mon Sep 17 00:00:00 2001 From: Bivurnum <147376167+Bivurnum@users.noreply.github.com> Date: Sat, 19 Apr 2025 07:15:13 -0500 Subject: [PATCH 1/2] Fix no eligible mons when only the partner wins in multi battle (#6626) --- src/battle_script_commands.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 4837fb970e..4e090e3257 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -5344,6 +5344,7 @@ bool32 NoAliveMonsForPlayer(void) u32 i; u32 maxI = PARTY_SIZE; u32 HP_count = 0; + u32 ineligibleMonsCount = 0; if (B_MULTI_BATTLE_WHITEOUT < GEN_4 && gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER)) maxI = MULTI_PARTY_SIZE; @@ -5356,6 +5357,28 @@ bool32 NoAliveMonsForPlayer(void) { HP_count += GetMonData(&gPlayerParty[i], MON_DATA_HP); } + + // Get the number of fainted mons or eggs (not empty slots) in the first three party slots. + if (i < 3 && ((GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) && !GetMonData(&gPlayerParty[i], MON_DATA_HP)) + || GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG))) + ineligibleMonsCount++; + } + + // Get the number of inelligible slots in the saved player party. + if (B_MULTI_BATTLE_WHITEOUT > GEN_3 && gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER) + && !(gBattleTypeFlags & BATTLE_TYPE_ARENA)) + { + for (i = 0; i < PARTY_SIZE; i++) + { + if (!GetMonData(&gSaveBlock1Ptr->playerParty[i], MON_DATA_SPECIES) + || !GetMonData(&gSaveBlock1Ptr->playerParty[i], MON_DATA_HP) + || GetMonData(&gSaveBlock1Ptr->playerParty[i], MON_DATA_IS_EGG)) + ineligibleMonsCount++; + } + + // If the total number of ineligible mons is 6 or more, lose the battle. + if (ineligibleMonsCount >= 6) + return TRUE; } return (HP_count == 0); From bd64ab599b09798612661e1e00e11f31eda260b9 Mon Sep 17 00:00:00 2001 From: PhallenTree <168426989+PhallenTree@users.noreply.github.com> Date: Sat, 19 Apr 2025 19:24:00 +0100 Subject: [PATCH 2/2] Fixes Ally Switch cancelling partner's moves targeting that side of the field (#6647) --- src/battle_anim_effects_1.c | 10 +++++++--- src/battle_util.c | 20 +++++++++++++++----- test/battle/move_effect/acupressure.c | 26 +++++++++++++++++++++++--- test/battle/move_effect/ally_switch.c | 18 ++++++++++++++++++ 4 files changed, 63 insertions(+), 11 deletions(-) diff --git a/src/battle_anim_effects_1.c b/src/battle_anim_effects_1.c index 8e1e39d629..96e0aad14a 100644 --- a/src/battle_anim_effects_1.c +++ b/src/battle_anim_effects_1.c @@ -6914,11 +6914,11 @@ static void AnimTask_AllySwitchDataSwap(u8 taskId) SWAP(gMoveSelectionCursor[battlerAtk], gMoveSelectionCursor[battlerPartner], temp); // Swap turn order, so that all the battlers take action SWAP(gChosenActionByBattler[battlerAtk], gChosenActionByBattler[battlerPartner], temp); - for (i = 0; i < MAX_BATTLERS_COUNT; i++) + for (i = 0; i < gBattlersCount; i++) { if (gBattlerByTurnOrder[i] == battlerAtk || gBattlerByTurnOrder[i] == battlerPartner) { - for (j = i + 1; j < MAX_BATTLERS_COUNT; j++) + for (j = i + 1; j < gBattlersCount; j++) { if (gBattlerByTurnOrder[j] == battlerAtk || gBattlerByTurnOrder[j] == battlerPartner) break; @@ -6938,9 +6938,13 @@ static void AnimTask_AllySwitchDataSwap(u8 taskId) TrySwapWishBattlerIds(battlerAtk, battlerPartner); // For Snipe Shot and abilities Stalwart/Propeller Tail - keep the original target. - for (i = 0; i < MAX_BATTLERS_COUNT; i++) + for (i = 0; i < gBattlersCount; i++) { u16 ability = GetBattlerAbility(i); + // if not targeting a slot that got switched, continue + if (!IsBattlerAlly(gBattleStruct->moveTarget[i], battlerAtk)) + continue; + if (gChosenMoveByBattler[i] == MOVE_SNIPE_SHOT || ability == ABILITY_PROPELLER_TAIL || ability == ABILITY_STALWART) gBattleStruct->moveTarget[i] ^= BIT_FLANK; } diff --git a/src/battle_util.c b/src/battle_util.c index 0a95f4e59c..d38135dbb2 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -309,7 +309,7 @@ bool32 HandleMoveTargetRedirection(void) // Functions void HandleAction_UseMove(void) { - u32 i; + u32 i, moveTarget; gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; if (gBattleStruct->battlerState[gBattlerAttacker].absentBattlerFlags @@ -393,9 +393,10 @@ void HandleAction_UseMove(void) gCurrentMove = gChosenMove = GetMaxMove(gBattlerAttacker, gCurrentMove); } + moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); + if (!HandleMoveTargetRedirection()) { - u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); if (IsDoubleBattle() && moveTarget & MOVE_TARGET_RANDOM) { gBattlerTarget = SetRandomTarget(gBattlerAttacker); @@ -407,7 +408,7 @@ void HandleAction_UseMove(void) } else if (moveTarget == MOVE_TARGET_ALLY) { - if (IsBattlerAlive(BATTLE_PARTNER(gBattlerAttacker))) + if (IsBattlerAlive(BATTLE_PARTNER(gBattlerAttacker)) && !gProtectStructs[BATTLE_PARTNER(gBattlerAttacker)].usedAllySwitch) gBattlerTarget = BATTLE_PARTNER(gBattlerAttacker); else gBattlerTarget = gBattlerAttacker; @@ -422,6 +423,10 @@ void HandleAction_UseMove(void) break; } } + else if (moveTarget == MOVE_TARGET_USER) + { + gBattlerTarget = gBattlerAttacker; + } else { gBattlerTarget = *(gBattleStruct->moveTarget + gBattlerAttacker); @@ -455,8 +460,13 @@ void HandleAction_UseMove(void) } } - if ((IsBattlerAlly(gBattlerAttacker, gBattlerTarget)) - && (!IsBattlerAlive(gBattlerTarget) || gProtectStructs[BATTLE_PARTNER(gBattlerAttacker)].usedAllySwitch)) + if (IsBattlerAlly(gBattlerAttacker, gBattlerTarget) && !IsBattlerAlive(gBattlerTarget)) + { + gBattlescriptCurrInstr = BattleScript_FailedFromAtkCanceler; + } + // If originally targetting an ally but now targetting user due to Ally Switch + else if (moveTarget & MOVE_TARGET_ALLY && gBattlerAttacker == gBattlerTarget + && gProtectStructs[BATTLE_PARTNER(gBattlerAttacker)].usedAllySwitch) { gBattlescriptCurrInstr = BattleScript_FailedFromAtkCanceler; } diff --git a/test/battle/move_effect/acupressure.c b/test/battle/move_effect/acupressure.c index d59a3faee3..02be60725d 100644 --- a/test/battle/move_effect/acupressure.c +++ b/test/battle/move_effect/acupressure.c @@ -16,20 +16,40 @@ DOUBLE_BATTLE_TEST("Acupressure fails on the user if it targeted its ally but sw OPPONENT(SPECIES_KADABRA); OPPONENT(SPECIES_ABRA); } WHEN { - TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); MOVE(playerRight, MOVE_ACUPRESSURE, target:playerLeft); } + TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); MOVE(playerRight, MOVE_ACUPRESSURE, target: playerLeft); } } SCENE { MESSAGE("Wobbuffet used Ally Switch!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, playerLeft); MESSAGE("Wobbuffet and Wynaut switched places!"); - + MESSAGE("Wynaut used Acupressure!"); MESSAGE("But it failed!"); NONE_OF { - ANIMATION(ANIM_TYPE_MOVE, MOVE_ACUPRESSURE); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ACUPRESSURE, playerLeft); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft); } } } +DOUBLE_BATTLE_TEST("Acupressure works on the ally if it targeted itself but switched positions via Ally Switch") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_KADABRA); + OPPONENT(SPECIES_ABRA); + } WHEN { + TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); MOVE(playerRight, MOVE_ACUPRESSURE, target: playerRight); } + } SCENE { + MESSAGE("Wobbuffet used Ally Switch!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, playerLeft); + MESSAGE("Wobbuffet and Wynaut switched places!"); + MESSAGE("Wynaut used Acupressure!"); + NOT MESSAGE("But it failed!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ACUPRESSURE, playerLeft); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); + } +} + TO_DO_BATTLE_TEST("Acupressure works on the user if its side is protected by Crafty Shield"); TO_DO_BATTLE_TEST("Acupressure fails on the ally if its side is protected by Crafty Shield"); diff --git a/test/battle/move_effect/ally_switch.c b/test/battle/move_effect/ally_switch.c index 520de60106..ba2ac1a053 100644 --- a/test/battle/move_effect/ally_switch.c +++ b/test/battle/move_effect/ally_switch.c @@ -167,6 +167,24 @@ DOUBLE_BATTLE_TEST("Ally Switch - move fails if the target was ally which change } } +DOUBLE_BATTLE_TEST("Ally Switch doesn't make self-targeting status moves fail") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_HARDEN].target == MOVE_TARGET_USER); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); MOVE(playerRight, MOVE_HARDEN); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, playerLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_HARDEN, playerLeft); + } THEN { + EXPECT_EQ(playerLeft->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1); + } +} + DOUBLE_BATTLE_TEST("Ally Switch increases the Protect-like moves counter") { GIVEN {