From 736826e86309afa32354c838e05e8397ed04584f Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Sun, 27 Jan 2019 20:54:34 +0100 Subject: [PATCH] New feature - battle 2 vs 1 opponent --- .../scripts.inc | 2 +- include/battle_ai_switch_items.h | 1 + include/constants/battle.h | 1 + src/battle_ai_switch_items.c | 92 ++++++------------- src/battle_controller_opponent.c | 26 ++---- src/battle_controllers.c | 13 ++- src/battle_main.c | 6 +- src/battle_message.c | 12 ++- src/battle_script_commands.c | 37 ++++++-- src/battle_tower.c | 12 ++- src/battle_util.c | 25 ++++- 11 files changed, 125 insertions(+), 102 deletions(-) diff --git a/data/maps/EverGrandeCity_PokemonLeague_1F/scripts.inc b/data/maps/EverGrandeCity_PokemonLeague_1F/scripts.inc index 6df9f946e..a0a2cf1fb 100644 --- a/data/maps/EverGrandeCity_PokemonLeague_1F/scripts.inc +++ b/data/maps/EverGrandeCity_PokemonLeague_1F/scripts.inc @@ -48,7 +48,7 @@ EverGrandeCity_PokemonLeague_1F_Pokemart_229624: @ 8229624 EverGrandeCity_PokemonLeague_1F_EventScript_229636:: @ 8229636 special SavePlayerParty - trainerbattle 10, TRAINER_ALBERT, 0, NULL, EverGrandeCity_PokemonLeague_1F_Text_2296E8 + trainerbattle 10, TRAINER_WALLACE, 0, NULL, EverGrandeCity_PokemonLeague_1F_Text_2296E8 trainerbattle 11, TRAINER_ALEXA, 0, NULL, EverGrandeCity_PokemonLeague_1F_Text_2297EF setvar VAR_0x8004, SPECIAL_BATTLE_MULTI diff --git a/include/battle_ai_switch_items.h b/include/battle_ai_switch_items.h index 0a230e7f6..9780fae70 100644 --- a/include/battle_ai_switch_items.h +++ b/include/battle_ai_switch_items.h @@ -11,6 +11,7 @@ enum AI_ITEM_NOT_RECOGNIZABLE }; +void GetAIPartyIndexes(u32 battlerId, s32 *firstId, s32 *lastId); void AI_TrySwitchOrUseItem(void); u8 GetMostSuitableMonToSwitchInto(void); diff --git a/include/constants/battle.h b/include/constants/battle.h index bf94f48e7..8b8bcda5c 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -80,6 +80,7 @@ #define BATTLE_TYPE_FRONTIER_NO_PYRAMID (BATTLE_TYPE_BATTLE_TOWER | BATTLE_TYPE_DOME | BATTLE_TYPE_PALACE | BATTLE_TYPE_ARENA | BATTLE_TYPE_FACTORY | BATTLE_TYPE_PIKE) #define WILD_DOUBLE_BATTLE ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_TRAINER)))) +#define BATTLE_TWO_VS_ONE_OPPONENT ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gTrainerBattleOpponent_B == 0xFFFF)) // Battle Outcome defines #define B_OUTCOME_WON 0x1 diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index a046a0e2c..ec0d20ad0 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -2,6 +2,7 @@ #include "battle.h" #include "battle_ai_script_commands.h" #include "battle_controllers.h" +#include "battle_setup.h" #include "pokemon.h" #include "random.h" #include "util.h" @@ -15,6 +16,25 @@ static bool8 HasSuperEffectiveMoveAgainstOpponents(bool8 noRng); static bool8 FindMonWithFlagsAndSuperEffective(u16 flags, u8 moduloPercent); static bool8 ShouldUseItem(void); +void GetAIPartyIndexes(u32 battlerId, s32 *firstId, s32 *lastId) +{ + if (BATTLE_TWO_VS_ONE_OPPONENT && (battlerId & BIT_SIDE) == B_SIDE_OPPONENT) + { + *firstId = 0, *lastId = 6; + } + else if (gBattleTypeFlags & (BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_x800000)) + { + if ((battlerId & BIT_FLANK) == B_FLANK_LEFT) + *firstId = 0, *lastId = 3; + else + *firstId = 3, *lastId = 6; + } + else + { + *firstId = 0, *lastId = 6; + } +} + static bool8 ShouldSwitchIfPerishSong(void) { if (gStatuses3[gActiveBattler] & STATUS3_PERISH_SONG @@ -60,17 +80,7 @@ static bool8 ShouldSwitchIfWonderGuard(void) } // Get party information. - if (gBattleTypeFlags & (BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_x800000)) - { - if ((gActiveBattler & BIT_FLANK) == B_FLANK_LEFT) - firstId = 0, lastId = 3; - else - firstId = 3, lastId = 6; - } - else - { - firstId = 0, lastId = 6; - } + GetAIPartyIndexes(gActiveBattler, &firstId, &lastId); if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) party = gPlayerParty; @@ -152,17 +162,7 @@ static bool8 FindMonThatAbsorbsOpponentsMove(void) if (gBattleMons[gActiveBattler].ability == absorbingTypeAbility) return FALSE; - if (gBattleTypeFlags & (BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_x800000)) - { - if ((gActiveBattler & BIT_FLANK) == B_FLANK_LEFT) - firstId = 0, lastId = 3; - else - firstId = 3, lastId = 6; - } - else - { - firstId = 0, lastId = 6; - } + GetAIPartyIndexes(gActiveBattler, &firstId, &lastId); if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) party = gPlayerParty; @@ -343,17 +343,7 @@ static bool8 FindMonWithFlagsAndSuperEffective(u16 flags, u8 moduloPercent) battlerIn2 = gActiveBattler; } - if (gBattleTypeFlags & (BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_x800000)) - { - if ((gActiveBattler & BIT_FLANK) == 0) - firstId = 0, lastId = 3; - else - firstId = 3, lastId = 6; - } - else - { - firstId = 0, lastId = 6; - } + GetAIPartyIndexes(gActiveBattler, &firstId, &lastId); if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) party = gPlayerParty; @@ -453,17 +443,7 @@ static bool8 ShouldSwitch(void) battlerIn2 = *activeBattlerPtr; } - if (gBattleTypeFlags & (BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_x800000)) - { - if ((gActiveBattler & BIT_FLANK) == B_FLANK_LEFT) - firstId = 0, lastId = 3; - else - firstId = 3, lastId = 6; - } - else - { - firstId = 0, lastId = 6; - } + GetAIPartyIndexes(gActiveBattler, &firstId, &lastId); if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) party = gPlayerParty; @@ -544,17 +524,7 @@ void AI_TrySwitchOrUseItem(void) battlerIn2 = GetBattlerAtPosition(battlerIdentity ^ BIT_FLANK); } - if (gBattleTypeFlags & (BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_x800000)) - { - if ((gActiveBattler & BIT_FLANK) == B_FLANK_LEFT) - firstId = 0, lastId = 3; - else - firstId = 3, lastId = 6; - } - else - { - firstId = 0, lastId = 6; - } + GetAIPartyIndexes(gActiveBattler, &firstId, &lastId); for (monToSwitchId = firstId; monToSwitchId < lastId; monToSwitchId++) { @@ -626,17 +596,7 @@ u8 GetMostSuitableMonToSwitchInto(void) battlerIn2 = gActiveBattler; } - if (gBattleTypeFlags & (BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_x800000)) - { - if ((gActiveBattler & BIT_FLANK) == B_FLANK_LEFT) - firstId = 0, lastId = 3; - else - firstId = 3, lastId = 6; - } - else - { - firstId = 0, lastId = 6; - } + GetAIPartyIndexes(gActiveBattler, &firstId, &lastId); if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) party = gPlayerParty; diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c index 4a44d9ed8..29ef07729 100644 --- a/src/battle_controller_opponent.c +++ b/src/battle_controller_opponent.c @@ -234,7 +234,7 @@ static void sub_805F2F0(void) bool8 var = FALSE; bool8 var2; - if (!IsDoubleBattle() || ((IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI)) || (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS))) + if (!IsDoubleBattle() || ((IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI) && !BATTLE_TWO_VS_ONE_OPPONENT) || (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS))) { if (gSprites[gHealthboxSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy) var = TRUE; @@ -297,13 +297,13 @@ static void sub_805F560(void) if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].flag_x80 && !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].ballAnimActive && !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].field_1_x1) sub_8172EF0(gActiveBattler, &gEnemyParty[gBattlerPartyIndexes[gActiveBattler]]); - if (!(gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) && !(gBattleTypeFlags & BATTLE_TYPE_MULTI) && IsDoubleBattle() && !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler ^ BIT_FLANK].flag_x80 && !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler ^ BIT_FLANK].ballAnimActive && !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler ^ BIT_FLANK].field_1_x1) + if (!(gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) && (!(gBattleTypeFlags & BATTLE_TYPE_MULTI) || BATTLE_TWO_VS_ONE_OPPONENT) && IsDoubleBattle() && !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler ^ BIT_FLANK].flag_x80 && !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler ^ BIT_FLANK].ballAnimActive && !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler ^ BIT_FLANK].field_1_x1) sub_8172EF0(gActiveBattler ^ BIT_FLANK, &gEnemyParty[gBattlerPartyIndexes[gActiveBattler ^ BIT_FLANK]]); if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].ballAnimActive && !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler ^ BIT_FLANK].ballAnimActive) { if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].field_1_x80) { - if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI)) + if (IsDoubleBattle() && (!(gBattleTypeFlags & BATTLE_TYPE_MULTI) || BATTLE_TWO_VS_ONE_OPPONENT)) { UpdateHealthboxAttribute(gHealthboxSpriteIds[gActiveBattler ^ BIT_FLANK], &gEnemyParty[gBattlerPartyIndexes[gActiveBattler ^ BIT_FLANK]], HEALTHBOX_ALL); sub_8076918(gActiveBattler ^ BIT_FLANK); @@ -335,7 +335,7 @@ static void sub_805F560(void) sp = TRUE; } - if (!IsDoubleBattle() || (IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI))) + if (!IsDoubleBattle() || (IsDoubleBattle() && gBattleTypeFlags & BATTLE_TYPE_MULTI && !BATTLE_TWO_VS_ONE_OPPONENT)) { if (gSprites[gUnknown_03005D7C[gActiveBattler]].callback == SpriteCallbackDummy && gSprites[gBattlerSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy) @@ -356,7 +356,7 @@ static void sub_805F560(void) if (sp && r10) { - if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI)) + if (IsDoubleBattle() && (!(gBattleTypeFlags & BATTLE_TYPE_MULTI) || BATTLE_TWO_VS_ONE_OPPONENT)) { DestroySprite(&gSprites[gUnknown_03005D7C[gActiveBattler ^ BIT_FLANK]]); SetBattlerShadowSpriteCallback(gActiveBattler ^ BIT_FLANK, GetMonData(&gEnemyParty[gBattlerPartyIndexes[gActiveBattler ^ BIT_FLANK]], MON_DATA_SPECIES)); @@ -1278,7 +1278,7 @@ static void OpponentHandleDrawTrainerPic(void) trainerPicId = gTrainers[gTrainerBattleOpponent_A].trainerPic; } - if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS)) + if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS) && !BATTLE_TWO_VS_ONE_OPPONENT) { if ((GetBattlerPosition(gActiveBattler) & BIT_FLANK) != 0) // second mon xPos = 152; @@ -1624,17 +1624,7 @@ static void OpponentHandleChoosePokemon(void) battler2 = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); } - if (gBattleTypeFlags & (BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_x800000)) - { - if (gActiveBattler == 1) - firstId = 0, lastId = 3; - else - firstId = 3, lastId = 6; - } - else - { - firstId = 0, lastId = 6; - } + GetAIPartyIndexes(gActiveBattler, &firstId, &lastId); for (chosenMonId = firstId; chosenMonId < lastId; chosenMonId++) { @@ -1884,7 +1874,7 @@ static void sub_8062828(u8 taskId) u8 savedActiveBank = gActiveBattler; gActiveBattler = gTasks[taskId].data[0]; - if (!IsDoubleBattle() || (gBattleTypeFlags & BATTLE_TYPE_MULTI)) + if ((!IsDoubleBattle() || (gBattleTypeFlags & BATTLE_TYPE_MULTI)) && !BATTLE_TWO_VS_ONE_OPPONENT) { gBattleResources->bufferA[gActiveBattler][1] = gBattlerPartyIndexes[gActiveBattler]; sub_80613DC(gActiveBattler, FALSE); diff --git a/src/battle_controllers.c b/src/battle_controllers.c index 166fc6119..49a400bea 100644 --- a/src/battle_controllers.c +++ b/src/battle_controllers.c @@ -4,6 +4,7 @@ #include "battle_anim.h" #include "battle_controllers.h" #include "battle_message.h" +#include "battle_setup.h" #include "cable_club.h" #include "link.h" #include "party_menu.h" @@ -153,8 +154,16 @@ static void InitSinglePlayerBtlControllers(void) gBattlerPartyIndexes[0] = 0; gBattlerPartyIndexes[1] = 0; - gBattlerPartyIndexes[2] = 3; - gBattlerPartyIndexes[3] = 3; + if (BATTLE_TWO_VS_ONE_OPPONENT) + { + gBattlerPartyIndexes[2] = 3; + gBattlerPartyIndexes[3] = 1; + } + else + { + gBattlerPartyIndexes[2] = 3; + gBattlerPartyIndexes[3] = 3; + } } else if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) { diff --git a/src/battle_main.c b/src/battle_main.c index 8f76622f6..c18e72bf6 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -573,7 +573,7 @@ static void CB2_InitBattleInternal(void) if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED))) { CreateNPCTrainerParty(&gEnemyParty[0], gTrainerBattleOpponent_A, TRUE); - if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && !BATTLE_TWO_VS_ONE_OPPONENT) CreateNPCTrainerParty(&gEnemyParty[3], gTrainerBattleOpponent_B, FALSE); SetWildMonHeldItem(); } @@ -3245,7 +3245,7 @@ static void DoBattleIntro(void) case B_POSITION_OPPONENT_RIGHT: if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) { - if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS)) // opponent 2 if exists + if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS) && !BATTLE_TWO_VS_ONE_OPPONENT) // opponent 2 if exists { BtlController_EmitDrawTrainerPic(0); MarkBattlerForControllerExec(gActiveBattler); @@ -3373,7 +3373,7 @@ static void DoBattleIntro(void) case 12: // nothing (*state)++; case 13: // second opponent's mon send out - if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS)) + if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS) && !BATTLE_TWO_VS_ONE_OPPONENT) { if (gBattleTypeFlags & BATTLE_TYPE_x2000000 && !(gBattleTypeFlags & BATTLE_TYPE_x80000000)) gActiveBattler = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); diff --git a/src/battle_message.c b/src/battle_message.c index afc8e614d..4ee5b1a6b 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -2302,7 +2302,9 @@ void BufferStringBattle(u16 stringID) } else { - if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + if (BATTLE_TWO_VS_ONE_OPPONENT) + stringPtr = sText_Trainer1WantsToBattle; + else if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER)) stringPtr = sText_TwoTrainersWantToBattle; else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) stringPtr = sText_TwoTrainersWantToBattle; @@ -2345,7 +2347,9 @@ void BufferStringBattle(u16 stringID) { if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) { - if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + if (BATTLE_TWO_VS_ONE_OPPONENT) + stringPtr = sText_Trainer1SentOutTwoPkmn; + else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) stringPtr = sText_TwoTrainersSentPkmn; else if (gBattleTypeFlags & BATTLE_TYPE_x800000) stringPtr = sText_TwoTrainersSentPkmn; @@ -2659,7 +2663,7 @@ static const u8 *BattleStringGetOpponentName(u8 *text, u8 multiplayerId, u8 batt toCpy = BattleStringGetOpponentNameByTrainerId(gTrainerBattleOpponent_A, text, multiplayerId, battlerId); break; case B_POSITION_OPPONENT_RIGHT: - if (gBattleTypeFlags & (BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_MULTI)) + if (gBattleTypeFlags & (BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_MULTI) && !BATTLE_TWO_VS_ONE_OPPONENT) toCpy = BattleStringGetOpponentNameByTrainerId(gTrainerBattleOpponent_B, text, multiplayerId, battlerId); else toCpy = BattleStringGetOpponentNameByTrainerId(gTrainerBattleOpponent_A, text, multiplayerId, battlerId); @@ -3098,7 +3102,7 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst) toCpy = BattleStringGetOpponentClassByTrainerId(gTrainerBattleOpponent_A); break; case B_POSITION_OPPONENT_RIGHT: - if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && !BATTLE_TWO_VS_ONE_OPPONENT) toCpy = BattleStringGetOpponentClassByTrainerId(gTrainerBattleOpponent_B); else toCpy = BattleStringGetOpponentClassByTrainerId(gTrainerBattleOpponent_A); diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 2b5faf22d..24cd9ce42 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -4541,6 +4541,7 @@ static void atk4F_jumpifcantswitch(void) { s32 i; s32 lastMonId; + u8 battlerIn1, battlerIn2; struct Pokemon *party; gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1] & ~(ATK4F_DONT_CHECK_STATUSES)); @@ -4551,11 +4552,28 @@ static void atk4F_jumpifcantswitch(void) { gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 2); } + else if (BATTLE_TWO_VS_ONE_OPPONENT && GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT) + { + battlerIn1 = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + battlerIn2 = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); + party = gEnemyParty; + + for (i = 0; i < PARTY_SIZE; i++) + { + if (GetMonData(&party[i], MON_DATA_HP) != 0 + && GetMonData(&party[i], MON_DATA_SPECIES) != SPECIES_NONE + && !GetMonData(&party[i], MON_DATA_IS_EGG) + && i != gBattlerPartyIndexes[battlerIn1] && i != gBattlerPartyIndexes[battlerIn2]) + break; + } + + if (i == PARTY_SIZE) + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; + } else if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) { - #ifndef NONMATCHING - asm("":::"r5"); - #endif // NONMATCHING if (GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT) party = gEnemyParty; else @@ -4651,8 +4669,6 @@ static void atk4F_jumpifcantswitch(void) } else { - u8 battlerIn1, battlerIn2; - if (GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT) { battlerIn1 = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); @@ -7952,7 +7968,16 @@ static void atk8F_forcerandomswitch(void) else party = gEnemyParty; - if ((gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER && gBattleTypeFlags & BATTLE_TYPE_LINK) + if (BATTLE_TWO_VS_ONE_OPPONENT && (gBattlerTarget & BIT_SIDE) == B_SIDE_OPPONENT) + { + firstMonId = 0; + lastMonId = 6; + monsCount = 6; + minNeeded = 2; + battler2PartyId = gBattlerPartyIndexes[gBattlerTarget]; + battler1PartyId = gBattlerPartyIndexes[gBattlerTarget ^ BIT_FLANK]; + } + else if ((gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER && gBattleTypeFlags & BATTLE_TYPE_LINK) || (gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER && gBattleTypeFlags & BATTLE_TYPE_x2000000) || (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)) { diff --git a/src/battle_tower.c b/src/battle_tower.c index f96d9a1df..079c1edc0 100644 --- a/src/battle_tower.c +++ b/src/battle_tower.c @@ -2374,10 +2374,20 @@ void DoSpecialTrainerBattle(void) BattleTransition_StartOnField(B_TRANSITION_MAGMA); break; case SPECIAL_BATTLE_MULTI: - if (gSpecialVar_0x8005 & 1) + if (gSpecialVar_0x8005 & 1) // Player + AI against wild mon + { gBattleTypeFlags = BATTLE_TYPE_DOUBLE | BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER; + } + else if (gSpecialVar_0x8005 & 2) // Player + AI against one trainer + { + gTrainerBattleOpponent_B = 0xFFFF; + gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER; + } else + { gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER; + } + gPartnerSpriteId = gSpecialVar_0x8007; FillPartnerParty(gSpecialVar_0x8006 + TRAINER_CUSTOM_PARTNER); gPartnerTrainerId = gSpecialVar_0x8006 + TRAINER_CUSTOM_PARTNER; diff --git a/src/battle_util.c b/src/battle_util.c index ccae0d4df..c72ef5de4 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -2,6 +2,7 @@ #include "battle.h" #include "battle_controllers.h" #include "battle_interface.h" +#include "battle_setup.h" #include "constants/battle_script_commands.h" #include "constants/abilities.h" #include "constants/moves.h" @@ -2333,7 +2334,29 @@ bool8 HasNoMonsToSwitch(u8 battler, u8 partyIdBattlerOn1, u8 partyIdBattlerOn2) if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) return FALSE; - if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + if (BATTLE_TWO_VS_ONE_OPPONENT && GetBattlerSide(battler) == B_SIDE_OPPONENT) + { + id2 = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + id1 = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); + party = gEnemyParty; + + if (partyIdBattlerOn1 == PARTY_SIZE) + partyIdBattlerOn1 = gBattlerPartyIndexes[id2]; + if (partyIdBattlerOn2 == PARTY_SIZE) + partyIdBattlerOn2 = gBattlerPartyIndexes[id1]; + + for (i = 0; i < PARTY_SIZE; i++) + { + if (GetMonData(&party[i], MON_DATA_HP) != 0 + && GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_NONE + && GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG + && i != partyIdBattlerOn1 && i != partyIdBattlerOn2 + && i != *(gBattleStruct->monToSwitchIntoId + id2) && i != id1[gBattleStruct->monToSwitchIntoId]) + break; + } + return (i == PARTY_SIZE); + } + else if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) { if (GetBattlerSide(battler) == B_SIDE_PLAYER) party = gPlayerParty;