From 2c9b4f4b177ed177a98abb79a3c358bd9668863f Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Tue, 14 Jul 2020 10:39:54 +0200 Subject: [PATCH] Show targets in double battles while hitting multiple pokemon at once --- include/constants/battle_config.h | 1 + src/battle_controller_player.c | 102 +++++++++++++++++++++++------- 2 files changed, 79 insertions(+), 24 deletions(-) diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index d02cd5f6c1..2571972ba0 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -96,6 +96,7 @@ // Other #define B_FAST_INTRO TRUE // If set to TRUE, battle intro texts print at the same time as animation of a Pokémon, as opposing to waiting for the animation to end. +#define B_SHOW_TARGETS TRUE // If set to TRUE, all available targets, for moves hitting 2 or 3 Pokémon, will be shown before selecting a move. #define B_SLEEP_TURNS GEN_6 // In Gen5+, sleep lasts for 1-3 turns instead of 2-5 turns. #define B_PARALYZE_ELECTRIC GEN_6 // In Gen6+, Electric type Pokémon can't be paralyzed. #define B_POWDER_GRASS GEN_6 // In Gen6+, Grass type Pokémon are immune to powder and spore moves. diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index 87effc2f7c..751e1ae6df 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -29,6 +29,7 @@ #include "util.h" #include "window.h" #include "constants/battle_anim.h" +#include "constants/battle_config.h" #include "constants/items.h" #include "constants/moves.h" #include "constants/party_menu.h" @@ -186,8 +187,6 @@ static void (*const sPlayerBufferCommands[CONTROLLER_CMDS_COUNT])(void) = PlayerCmdEnd }; -static const u8 sTargetIdentities[] = {B_POSITION_PLAYER_LEFT, B_POSITION_PLAYER_RIGHT, B_POSITION_OPPONENT_RIGHT, B_POSITION_OPPONENT_LEFT}; - // unknown unused data static const u8 sUnknown_0831C5FC[] = {0x48, 0x48, 0x20, 0x5a, 0x50, 0x50, 0x50, 0x58}; @@ -349,22 +348,14 @@ static void sub_80577F0(void) // unused static void HandleInputChooseTarget(void) { s32 i; - u8 identities[4]; + static const u8 identities[4] = {B_POSITION_PLAYER_LEFT, B_POSITION_PLAYER_RIGHT, B_POSITION_OPPONENT_RIGHT, B_POSITION_OPPONENT_LEFT}; u16 move = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_MOVE1 + gMoveSelectionCursor[gActiveBattler]); - memcpy(identities, sTargetIdentities, ARRAY_COUNT(sTargetIdentities)); DoBounceEffect(gMultiUsePlayerCursor, BOUNCE_HEALTHBOX, 15, 1); - - // what a weird loop - i = 0; - if (gBattlersCount != 0) + for (i = 0; i < gBattlersCount; i++) { - do - { - if (i != gMultiUsePlayerCursor) - EndBounceEffect(i, BOUNCE_HEALTHBOX); - i++; - } while (i < gBattlersCount); + if (i != gMultiUsePlayerCursor) + EndBounceEffect(i, BOUNCE_HEALTHBOX); } if (gMain.heldKeys & DPAD_ANY && gSaveBlock2Ptr->optionsButtonMode == 2) @@ -494,9 +485,60 @@ static void HandleInputChooseTarget(void) } } +static void HideShownTargets(void) +{ + s32 i; + for (i = 0; i < MAX_BATTLERS_COUNT; i++) + { + if (IsBattlerAlive(i) && gBattleSpritesDataPtr->healthBoxesData[i].healthboxIsBouncing && i != gActiveBattler) + { + gSprites[gBattlerSpriteIds[i]].callback = sub_8039B2C; + EndBounceEffect(i, BOUNCE_HEALTHBOX); + } + } +} + +static void HandleInputShowTargets(void) +{ + if (gMain.heldKeys & DPAD_ANY && gSaveBlock2Ptr->optionsButtonMode == OPTIONS_BUTTON_MODE_L_EQUALS_A) + gPlayerDpadHoldFrames++; + else + gPlayerDpadHoldFrames = 0; + + if (gMain.newKeys & A_BUTTON) + { + PlaySE(SE_SELECT); + HideShownTargets(); + if (gBattleStruct->mega.playerSelect) + BtlController_EmitTwoReturnValues(1, 10, gMoveSelectionCursor[gActiveBattler] | RET_MEGA_EVOLUTION | (gMultiUsePlayerCursor << 8)); + else + BtlController_EmitTwoReturnValues(1, 10, gMoveSelectionCursor[gActiveBattler] | (gMultiUsePlayerCursor << 8)); + HideMegaTriggerSprite(); + PlayerBufferExecCompleted(); + } + else if (gMain.newKeys & B_BUTTON || gPlayerDpadHoldFrames > 59) + { + PlaySE(SE_SELECT); + HideShownTargets(); + gBattlerControllerFuncs[gActiveBattler] = HandleInputChooseMove; + DoBounceEffect(gActiveBattler, BOUNCE_HEALTHBOX, 7, 1); + DoBounceEffect(gActiveBattler, BOUNCE_MON, 7, 1); + } +} + +static void TryShowAsTarget(u32 battlerId) +{ + if (IsBattlerAlive(battlerId)) + { + DoBounceEffect(battlerId, BOUNCE_HEALTHBOX, 15, 1); + gSprites[gBattlerSpriteIds[battlerId]].callback = sub_8039AD8; + } +} + static void HandleInputChooseMove(void) { - bool32 canSelectTarget = FALSE; + u8 moveTarget; + u32 canSelectTarget = 0; struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct*)(&gBattleResources->bufferA[gActiveBattler][4]); if (gMain.heldKeys & DPAD_ANY && gSaveBlock2Ptr->optionsButtonMode == OPTIONS_BUTTON_MODE_L_EQUALS_A) @@ -506,8 +548,6 @@ static void HandleInputChooseMove(void) if (gMain.newKeys & A_BUTTON) { - u8 moveTarget; - PlaySE(SE_SELECT); if (moveInfo->moves[gMoveSelectionCursor[gActiveBattler]] == MOVE_CURSE) { @@ -529,27 +569,37 @@ static void HandleInputChooseMove(void) if (!gBattleResources->bufferA[gActiveBattler][1]) // not a double battle { if (moveTarget & MOVE_TARGET_USER_OR_SELECTED && !gBattleResources->bufferA[gActiveBattler][2]) - canSelectTarget++; + canSelectTarget = 1; } else // double battle { if (!(moveTarget & (MOVE_TARGET_RANDOM | MOVE_TARGET_BOTH | MOVE_TARGET_DEPENDS | MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_USER | MOVE_TARGET_ALLY))) - canSelectTarget++; // either selected or user + canSelectTarget = 1; // either selected or user if (moveTarget == (MOVE_TARGET_USER | MOVE_TARGET_ALLY) && IsBattlerAlive(BATTLE_PARTNER(gActiveBattler))) - canSelectTarget++; + canSelectTarget = 1; if (moveInfo->currentPp[gMoveSelectionCursor[gActiveBattler]] == 0) { - canSelectTarget = FALSE; + canSelectTarget = 0; } else if (!(moveTarget & (MOVE_TARGET_USER | MOVE_TARGET_USER_OR_SELECTED)) && CountAliveMonsInBattle(BATTLE_ALIVE_EXCEPT_ACTIVE) <= 1) { gMultiUsePlayerCursor = GetDefaultMoveTarget(gActiveBattler); - canSelectTarget = FALSE; + canSelectTarget = 0; + } + + // Show all available targets for multi-target moves + if (B_SHOW_TARGETS && moveTarget & (MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)) + { + TryShowAsTarget(gMultiUsePlayerCursor); + TryShowAsTarget(BATTLE_PARTNER(gMultiUsePlayerCursor)); + if (moveTarget & MOVE_TARGET_FOES_AND_ALLY) + TryShowAsTarget(BATTLE_PARTNER(gActiveBattler)); + canSelectTarget = 2; } } - if (!canSelectTarget) + if (canSelectTarget == 0) { if (gBattleStruct->mega.playerSelect) BtlController_EmitTwoReturnValues(1, 10, gMoveSelectionCursor[gActiveBattler] | RET_MEGA_EVOLUTION | (gMultiUsePlayerCursor << 8)); @@ -558,7 +608,7 @@ static void HandleInputChooseMove(void) HideMegaTriggerSprite(); PlayerBufferExecCompleted(); } - else + else if (canSelectTarget == 1) { gBattlerControllerFuncs[gActiveBattler] = HandleInputChooseTarget; @@ -571,6 +621,10 @@ static void HandleInputChooseMove(void) gSprites[gBattlerSpriteIds[gMultiUsePlayerCursor]].callback = sub_8039AD8; } + else + { + gBattlerControllerFuncs[gActiveBattler] = HandleInputShowTargets; + } } else if (gMain.newKeys & B_BUTTON || gPlayerDpadHoldFrames > 59) {