Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ally Switch extra battlerId tracking #5823

Merged
merged 1 commit into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions src/battle_anim_effects_1.c
Original file line number Diff line number Diff line change
Expand Up @@ -6642,6 +6642,79 @@ static void ReloadBattlerSprites(u32 battler, struct Pokemon *party)
}
}

static void TrySwapSkyDropTargets(u32 battlerAtk, u32 battlerPartner)
{
u32 i, temp;

// battlerAtk is using Ally Switch
// check if our partner is the target of sky drop
// If so, change that index to battlerAtk
for (i = 0; i < gBattlersCount; i++) {
if (gBattleStruct->skyDropTargets[i] == battlerPartner) {
gBattleStruct->skyDropTargets[i] = battlerAtk;
break;
}
}

// Then swap our own sky drop targets with the partner in case our partner is mid-skydrop
SWAP(gBattleStruct->skyDropTargets[battlerAtk], gBattleStruct->skyDropTargets[battlerPartner], temp);
}

#define TRY_SIDE_TIMER_BATTLER_ID_SWAP(battlerAtk, battlerPartner, side, field) \
if (gSideTimers[side].field == battlerAtk) \
gSideTimers[side].field = battlerPartner; \
else if (gSideTimers[side].field == battlerPartner) \
gSideTimers[side].field = battlerAtk;

static void TrySwapStickyWebBattlerId(u32 battlerAtk, u32 battlerPartner)
{
u32 atkSide = GetBattlerSide(battlerAtk);
u32 oppSide = GetBattlerSide(BATTLE_OPPOSITE(battlerAtk));

// not all of these are needed to be swapped, but are done so to be robust to anything in the future that might care about them
TRY_SIDE_TIMER_BATTLER_ID_SWAP(battlerAtk, battlerPartner, atkSide, reflectBattlerId);
TRY_SIDE_TIMER_BATTLER_ID_SWAP(battlerAtk, battlerPartner, atkSide, lightscreenBattlerId);
TRY_SIDE_TIMER_BATTLER_ID_SWAP(battlerAtk, battlerPartner, atkSide, mistBattlerId);
TRY_SIDE_TIMER_BATTLER_ID_SWAP(battlerAtk, battlerPartner, atkSide, safeguardBattlerId);
TRY_SIDE_TIMER_BATTLER_ID_SWAP(battlerAtk, battlerPartner, atkSide, auroraVeilBattlerId);
TRY_SIDE_TIMER_BATTLER_ID_SWAP(battlerAtk, battlerPartner, atkSide, tailwindBattlerId);
TRY_SIDE_TIMER_BATTLER_ID_SWAP(battlerAtk, battlerPartner, atkSide, luckyChantBattlerId);

// if we've set sticky web on the opposing side, need to swap stickyWebBattlerId for mirror armor
TRY_SIDE_TIMER_BATTLER_ID_SWAP(battlerAtk, battlerPartner, oppSide, stickyWebBattlerId);
}
#undef TRY_SIDE_TIMER_BATTLER_ID_SWAP

static void TrySwapWishBattlerIds(u32 battlerAtk, u32 battlerPartner)
{
u32 i, temp;
u32 oppSide = GetBattlerSide(BATTLE_OPPOSITE(battlerAtk));

// if used future sight on opposing side, properly track who used it
if (gSideStatuses[oppSide] & SIDE_STATUS_FUTUREATTACK) {
for (i = 0; i < gBattlersCount; i++) {
if (IsAlly(i,battlerAtk))
continue; // only on opposing side
if (gWishFutureKnock.futureSightBattlerIndex[i] == battlerAtk) {
// if target was attacked with future sight from us, now they'll be the partner slot
gWishFutureKnock.futureSightBattlerIndex[i] = battlerPartner;
gWishFutureKnock.futureSightPartyIndex[i] = gBattlerPartyIndexes[battlerPartner];
break;
} else if (gWishFutureKnock.futureSightBattlerIndex[i] == battlerPartner) {
gWishFutureKnock.futureSightBattlerIndex[i] = battlerAtk;
gWishFutureKnock.futureSightPartyIndex[i] = gBattlerPartyIndexes[battlerAtk];
break;
}
}
}

// swap wish party indices
if (gWishFutureKnock.wishCounter[battlerAtk] > 0
|| gWishFutureKnock.wishCounter[battlerPartner] > 0) {
SWAP(gWishFutureKnock.wishPartyId[battlerAtk], gWishFutureKnock.wishPartyId[battlerPartner], temp);
}
}

static void AnimTask_AllySwitchDataSwap(u8 taskId)
{
s32 i, j;
Expand Down Expand Up @@ -6692,6 +6765,10 @@ static void AnimTask_AllySwitchDataSwap(u8 taskId)
SwitchTwoBattlersInParty(battlerAtk, battlerPartner);
SWAP(gBattlerPartyIndexes[battlerAtk], gBattlerPartyIndexes[battlerPartner], temp);

TrySwapSkyDropTargets(battlerAtk, battlerPartner);
TrySwapStickyWebBattlerId(battlerAtk, battlerPartner);
TrySwapWishBattlerIds(battlerAtk, battlerPartner);

// For Snipe Shot and abilities Stalwart/Propeller Tail - keep the original target.
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
{
Expand Down
74 changes: 74 additions & 0 deletions test/battle/move_effect/ally_switch.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,5 +203,79 @@ DOUBLE_BATTLE_TEST("Ally Switch works if ally used two-turn move like Dig")
}
}

DOUBLE_BATTLE_TEST("Ally switch swaps sky drop targets if being used by partner")
{
u8 visibility;
GIVEN {
ASSUME(gMovesInfo[MOVE_SKY_DROP].effect == EFFECT_SKY_DROP);
PLAYER(SPECIES_FEAROW) { Speed(100); }
PLAYER(SPECIES_XATU) { Speed(150); }
OPPONENT(SPECIES_ARON) { Speed(25); Ability(ABILITY_STURDY); }
OPPONENT(SPECIES_WYNAUT) { Speed(30); }
} WHEN {
TURN { MOVE(playerLeft, MOVE_SKY_DROP, target: opponentLeft); }
TURN { MOVE(playerRight, MOVE_ALLY_SWITCH); SKIP_TURN(playerLeft); MOVE(opponentRight, MOVE_MUD_SPORT); MOVE(opponentLeft, MOVE_IRON_DEFENSE); }
} SCENE {
MESSAGE("Fearow used Sky Drop!");
MESSAGE("Fearow took the opposing Aron into the sky!");
// turn 2
MESSAGE("Xatu used Ally Switch!");
MESSAGE("Xatu and Fearow switched places!");
MESSAGE("Fearow used Sky Drop!");
HP_BAR(opponentLeft);
MESSAGE("The opposing Wynaut used Mud Sport!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_MUD_SPORT, opponentRight);
MESSAGE("The opposing Aron used Iron Defense!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_IRON_DEFENSE, opponentLeft);
} THEN {
// all battlers should be visible
visibility = gBattleSpritesDataPtr->battlerData[0].invisible;
EXPECT_EQ(visibility, 0);
visibility = gBattleSpritesDataPtr->battlerData[1].invisible;
EXPECT_EQ(visibility, 0);
visibility = gBattleSpritesDataPtr->battlerData[2].invisible;
EXPECT_EQ(visibility, 0);
visibility = gBattleSpritesDataPtr->battlerData[3].invisible;
EXPECT_EQ(visibility, 0);
}
}

DOUBLE_BATTLE_TEST("Ally switch swaps opposing sky drop targets if partner is being held in the air")
{
u8 visibility;
GIVEN {
ASSUME(gMovesInfo[MOVE_SKY_DROP].effect == EFFECT_SKY_DROP);
PLAYER(SPECIES_ARON) { Speed(25); Ability(ABILITY_STURDY); }
PLAYER(SPECIES_WYNAUT) { Speed(30); }
OPPONENT(SPECIES_FEAROW) { Speed(100); }
OPPONENT(SPECIES_XATU) { Speed(150); }
} WHEN {
TURN { MOVE(opponentLeft, MOVE_SKY_DROP, target: playerLeft); }
TURN { MOVE(opponentRight, MOVE_ALLY_SWITCH); SKIP_TURN(opponentLeft); MOVE(playerRight, MOVE_MUD_SPORT); MOVE(playerLeft, MOVE_IRON_DEFENSE); }
} SCENE {
MESSAGE("The opposing Fearow used Sky Drop!");
MESSAGE("The opposing Fearow took Aron into the sky!");
// turn 2
MESSAGE("The opposing Xatu used Ally Switch!");
MESSAGE("The opposing Xatu and the opposing Fearow switched places!");
MESSAGE("The opposing Fearow used Sky Drop!");
HP_BAR(playerLeft);
MESSAGE("Wynaut used Mud Sport!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_MUD_SPORT, playerRight);
MESSAGE("Aron used Iron Defense!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_IRON_DEFENSE, playerLeft);
} THEN {
// all battlers should be visible
visibility = gBattleSpritesDataPtr->battlerData[0].invisible;
EXPECT_EQ(visibility, 0);
visibility = gBattleSpritesDataPtr->battlerData[1].invisible;
EXPECT_EQ(visibility, 0);
visibility = gBattleSpritesDataPtr->battlerData[2].invisible;
EXPECT_EQ(visibility, 0);
visibility = gBattleSpritesDataPtr->battlerData[3].invisible;
EXPECT_EQ(visibility, 0);
}
}

// Triple Battles required to test
//TO_DO_BATTLE_TEST("Ally Switch fails if the user is in the middle of the field in a Triple Battle");
28 changes: 28 additions & 0 deletions test/battle/move_effect/sticky_web.c
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,31 @@ SINGLE_BATTLE_TEST("Sticky Web is placed on the correct side after Memento")
MESSAGE("A sticky web has been laid out on the ground around your team!");
}
}

DOUBLE_BATTLE_TEST("Sticky Web setter has their speed lowered with Mirror Armor even after Ally Switch")
{
GIVEN {
PLAYER(SPECIES_SQUIRTLE);
PLAYER(SPECIES_CHARMANDER);
PLAYER(SPECIES_CORVIKNIGHT) { Ability(ABILITY_MIRROR_ARMOR); Item(ITEM_IRON_BALL); } // Iron Ball, so that flying type Corviknight is affected by Sticky Web.
OPPONENT(SPECIES_CATERPIE);
OPPONENT(SPECIES_NATU);
} WHEN {
TURN { MOVE(opponentLeft, MOVE_STICKY_WEB); }
TURN { MOVE(opponentRight, MOVE_ALLY_SWITCH); }
TURN { SWITCH(playerRight, 2); }
} SCENE {
// Turn 1 - set up sticky web
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, opponentLeft);
MESSAGE("A sticky web has been laid out on the ground around your team!");
// Turn 2 - ally switch
MESSAGE("The opposing Natu used Ally Switch!");
// turn 3 - send our corviknight
SEND_IN_MESSAGE("Corviknight");
MESSAGE("Corviknight was caught in a sticky web!");
ABILITY_POPUP(playerRight, ABILITY_MIRROR_ARMOR);
// sticky web setter - caterpie (now opponentRight) gets speed lowered
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
MESSAGE("The opposing Caterpie's Speed fell!");
}
}
Loading