From 1f11ff06e9f3adf71d962eb8aa075021dbda1c10 Mon Sep 17 00:00:00 2001 From: cawtds <38510667+cawtds@users.noreply.github.com> Date: Wed, 24 Jul 2024 21:25:31 +0200 Subject: [PATCH] add last used ball feature --- .../battle_interface/last_used_ball_l.png | Bin 0 -> 214 bytes .../last_used_ball_l_cycle.png | Bin 0 -> 335 bytes .../battle_interface/last_used_ball_r.png | Bin 0 -> 223 bytes .../last_used_ball_r_cycle.png | Bin 0 -> 344 bytes include/battle.h | 2 + include/battle_interface.h | 8 + include/constants/item.h | 12 +- include/item_use.h | 1 + src/battle_controller_player.c | 118 +++++- src/battle_interface.c | 349 ++++++++++++++++++ src/battle_main.c | 16 +- src/battle_util.c | 20 +- src/item.c | 1 - src/item_use.c | 5 + 14 files changed, 509 insertions(+), 23 deletions(-) create mode 100644 graphics/battle_interface/last_used_ball_l.png create mode 100644 graphics/battle_interface/last_used_ball_l_cycle.png create mode 100644 graphics/battle_interface/last_used_ball_r.png create mode 100644 graphics/battle_interface/last_used_ball_r_cycle.png diff --git a/graphics/battle_interface/last_used_ball_l.png b/graphics/battle_interface/last_used_ball_l.png new file mode 100644 index 0000000000000000000000000000000000000000..90fcef37398ed2b8bef3c2cc0649bc4ad9a8fac1 GIT binary patch literal 214 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvg8-ipSH_Le)y2(0UQw2Yj+z{f zK*sa;Uw{7n50nRj?BZfCCy?fA*Uq){^Z*&j&Z>)mRHCPgV~EDY^unv_P&x8 zS#yg)?8er2d6p7uYPU)$efU;Y`Lk$&!&Tdk1N(LxH11ySDHySpEAoNZk!hg?jk{ML zNYHg+U~^;L!1<<%`?2$5R*B*OhF;5_9Y;HAOBfhR1(d!8PtREbw2Z;i)z4*}Q$iB} D1m#Ns literal 0 HcmV?d00001 diff --git a/graphics/battle_interface/last_used_ball_l_cycle.png b/graphics/battle_interface/last_used_ball_l_cycle.png new file mode 100644 index 0000000000000000000000000000000000000000..58115f5a578d6a81bebaf6cc83b628db2b51bed0 GIT binary patch literal 335 zcmeAS@N?(olHy`uVBq!ia0vp^3P9|@!VDxk7i7!@QtTz3zOL-gS!G38W$w-OumlQ; zm$*ih1m~xflqVLYGPwJ=0F6;7OD$3`)-x$=UGfm9grlUu&mAaZ3}iESHE7BMDVB6c zUq=Rpjs4tz5?O(Kg8-ipSH_Le)y2(0UQw2Yj+z{fK*sa;Uw{7npIuz+46icq@FhB2)hQ>C^SuxkBzXbG+HjExhCRERn|0)e~6r9CIRB#dqxH;<={8l8_M6 zP{m~ajH%Li0*jR+lX3Mzrrq}rg*Yfn&yZQbFiXZjh{tV`lp6y>zf6c>c9>xZ(0T?> LS3j3^P6)mRF^unv_P&x8 zS#yg)?8er2d6p7uYPU)$efU;Y`E%9Nr%yw_D=__j$HY1FVdQ&MBb@0Cx9FNdN!< literal 0 HcmV?d00001 diff --git a/graphics/battle_interface/last_used_ball_r_cycle.png b/graphics/battle_interface/last_used_ball_r_cycle.png new file mode 100644 index 0000000000000000000000000000000000000000..0a73148e15f5019de534aa76f794372d159a51e6 GIT binary patch literal 344 zcmeAS@N?(olHy`uVBq!ia0vp^3P9|@!VDxk7i7!@QtTz3zOL-gS!G3;b=Jw<7X}K6 zm$*ih1m~xflqVLYGPwJ=0F6;7OD$3`)-x$=UGfm9grlUu&mAaZ3}iESHE7BMDVB6c zUq=Rpjs4tz5?O(Kg8-ipSH_Le)y2(0UQw2Yj+z{fK*sa;Uw{7npIuz+!(j&9~BoDSIV!n;k{l!LZxWHgLm023=yoG7}~f(8lwfG!w#~( zTgTMAm4i`2LUh5r1HC&P?(wKJ`b{`+CT_)nb=wU@FPvagW7lX= 0; j--) + { + ballPrev = gBagPockets[BALLS_POCKET].itemSlots[j].itemId; + if (ballPrev != ITEM_NONE) + return ballPrev; + } + } + i--; + break; + } + } + return gBagPockets[BALLS_POCKET].itemSlots[i].itemId; +} + +static u32 GetNextBall(u32 ballId) +{ + u32 ballNext = ITEM_NONE; + s32 i; + SortAndCompactBagPocket(&gBagPockets[BALLS_POCKET]); + for (i = 1; i < gBagPockets[BALLS_POCKET].capacity; i++) + { + if (ballId == gBagPockets[BALLS_POCKET].itemSlots[i-1].itemId) + { + ballNext = gBagPockets[BALLS_POCKET].itemSlots[i].itemId; + break; + } + } + if (ballNext == ITEM_NONE) + return gBagPockets[BALLS_POCKET].itemSlots[0].itemId; // Zeroth slot + else + return ballNext; +} + static void HandleInputChooseAction(u32 battler) { u16 itemId = gBattleResources->bufferA[battler][2] | (gBattleResources->bufferA[battler][3] << 8); DoBounceEffect(battler, BOUNCE_HEALTHBOX, 7, 1); DoBounceEffect(battler, BOUNCE_MON, 7, 1); + + if (B_LAST_USED_BALL == TRUE && B_LAST_USED_BALL_CYCLE == TRUE) + { + if (!gLastUsedBallMenuPresent) + { + gBattleStruct->ackBallUseBtn = FALSE; + } + else if (JOY_NEW(B_LAST_USED_BALL_BUTTON)) + { + gBattleStruct->ackBallUseBtn = TRUE; + gBattleStruct->ballSwapped = FALSE; + ArrowsChangeColorLastBallCycle(TRUE); + } + + if (gBattleStruct->ackBallUseBtn) + { + if (JOY_HELD(B_LAST_USED_BALL_BUTTON) && (JOY_NEW(DPAD_DOWN) || JOY_NEW(DPAD_RIGHT))) + { + bool32 sameBall = FALSE; + u32 nextBall = GetNextBall(gBallToDisplay); + gBattleStruct->ballSwapped = TRUE; + if (gBallToDisplay == nextBall) + sameBall = TRUE; + else + gBallToDisplay = nextBall; + SwapBallToDisplay(sameBall); + PlaySE(SE_SELECT); + } + else if (JOY_HELD(B_LAST_USED_BALL_BUTTON) && (JOY_NEW(DPAD_UP) || JOY_NEW(DPAD_LEFT))) + { + bool32 sameBall = FALSE; + u32 prevBall = GetPrevBall(gBallToDisplay); + gBattleStruct->ballSwapped = TRUE; + if (gBallToDisplay == prevBall) + sameBall = TRUE; + else + gBallToDisplay = prevBall; + SwapBallToDisplay(sameBall); + PlaySE(SE_SELECT); + } + else if (JOY_NEW(B_BUTTON) || (!JOY_HELD(B_LAST_USED_BALL_BUTTON) && gBattleStruct->ballSwapped)) + { + gBattleStruct->ackBallUseBtn = FALSE; + gBattleStruct->ballSwapped = FALSE; + ArrowsChangeColorLastBallCycle(FALSE); + } + else if (!JOY_HELD(B_LAST_USED_BALL_BUTTON) && CanThrowLastUsedBall()) + { + gBattleStruct->ackBallUseBtn = FALSE; + PlaySE(SE_SELECT); + ArrowsChangeColorLastBallCycle(FALSE); + TryHideLastUsedBall(); + BtlController_EmitTwoReturnValues(battler, BUFFER_B, B_ACTION_THROW_BALL, 0); + PlayerBufferExecCompleted(battler); + } + return; + } + } + if (JOY_NEW(A_BUTTON)) { PlaySE(SE_SELECT); @@ -287,13 +390,19 @@ static void HandleInputChooseAction(u32 battler) { SwapHpBarsWithHpText(); } -#if DEBUG_BATTLE_MENU == TRUE - else if (JOY_NEW(SELECT_BUTTON)) + else if (DEBUG_BATTLE_MENU == TRUE && JOY_NEW(SELECT_BUTTON)) { BtlController_EmitTwoReturnValues(battler, BUFFER_B, B_ACTION_DEBUG, 0); PlayerBufferExecCompleted(battler); } -#endif + else if (B_LAST_USED_BALL == TRUE && B_LAST_USED_BALL_CYCLE == FALSE + && JOY_NEW(B_LAST_USED_BALL_BUTTON) && CanThrowLastUsedBall()) + { + PlaySE(SE_SELECT); + TryHideLastUsedBall(); + BtlController_EmitTwoReturnValues(battler, BUFFER_B, B_ACTION_THROW_BALL, 0); + PlayerBufferExecCompleted(battler); + } } static void HandleInputChooseTarget(u32 battler) @@ -1851,8 +1960,11 @@ static void PlayerHandleChooseAction(u32 battler) gBattlerControllerFuncs[battler] = HandleChooseActionAfterDma3; BattlePutTextOnWindow(gText_BattleMenu, B_WIN_ACTION_MENU); + for (i = 0; i < 4; i++) ActionSelectionDestroyCursorAt(i); + + TryRestoreLastUsedBall(); ActionSelectionCreateCursorAt(gActionSelectionCursor[battler], 0); PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, battler, gBattlerPartyIndexes[battler]); BattleStringExpandPlaceholdersToDisplayedString(gText_WhatWillPkmnDo); diff --git a/src/battle_interface.c b/src/battle_interface.c index 5c6c7ed0e..8e097ef55 100644 --- a/src/battle_interface.c +++ b/src/battle_interface.c @@ -7,6 +7,9 @@ #include "battle_z_move.h" #include "decompress.h" #include "graphics.h" +#include "item.h" +#include "item_menu_icons.h" +#include "item_use.h" #include "menu.h" #include "pokedex.h" #include "pokemon_summary_screen.h" @@ -85,6 +88,9 @@ static void TextIntoHealthboxObject(void *dest, u8 *windowTileData, s32 windowWi static void SpriteCb_AbilityPopUp(struct Sprite *); static void Task_FreeAbilityPopUpGfx(u8); +static void SpriteCB_LastUsedBall(struct Sprite *); +static void SpriteCB_LastUsedBallWin(struct Sprite *); + static const struct OamData sOamData_Healthbox = { .shape = SPRITE_SHAPE(64x32), .size = SPRITE_SIZE(64x32), @@ -544,6 +550,9 @@ u8 CreateBattlerHealthboxSprites(u8 battlerId) CreateIndicatorSprite(battlerId); + gBattleStruct->ballSpriteIds[0] = MAX_SPRITES; + gBattleStruct->ballSpriteIds[1] = MAX_SPRITES; + return healthboxSpriteId; } @@ -2619,6 +2628,346 @@ static void Task_FreeAbilityPopUpGfx(u8 taskId) } } +// last used ball +#define LAST_BALL_WINDOW_TAG 0xD721 + +static const struct OamData sOamData_LastUsedBall = +{ + .y = 0, + .affineMode = 0, + .objMode = 0, + .mosaic = 0, + .bpp = 0, + .shape = (B_LAST_USED_BALL_CYCLE == TRUE ? SPRITE_SHAPE(32x64) : SPRITE_SHAPE(32x32)), + .x = 0, + .matrixNum = 0, + .size = (B_LAST_USED_BALL_CYCLE == TRUE ? SPRITE_SIZE(32x64) : SPRITE_SIZE(32x32)), + .tileNum = 0, + .priority = 1, + .paletteNum = 0, + .affineParam = 0, +}; + +static const struct SpriteTemplate sSpriteTemplate_LastUsedBallWindow = +{ + .tileTag = LAST_BALL_WINDOW_TAG, + .paletteTag = ABILITY_POP_UP_TAG, + .oam = &sOamData_LastUsedBall, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCB_LastUsedBallWin +}; + +#if B_LAST_USED_BALL_BUTTON == R_BUTTON && B_LAST_USED_BALL_CYCLE == TRUE + static const u8 ALIGNED(4) sLastUsedBallWindowGfx[] = INCBIN_U8("graphics/battle_interface/last_used_ball_r_cycle.4bpp"); +#elif B_LAST_USED_BALL_CYCLE == TRUE + static const u8 ALIGNED(4) sLastUsedBallWindowGfx[] = INCBIN_U8("graphics/battle_interface/last_used_ball_l_cycle.4bpp"); +#elif B_LAST_USED_BALL_BUTTON == R_BUTTON + static const u8 ALIGNED(4) sLastUsedBallWindowGfx[] = INCBIN_U8("graphics/battle_interface/last_used_ball_r.4bpp"); +#else + static const u8 ALIGNED(4) sLastUsedBallWindowGfx[] = INCBIN_U8("graphics/battle_interface/last_used_ball_l.4bpp"); +#endif +static const struct SpriteSheet sSpriteSheet_LastUsedBallWindow = +{ + sLastUsedBallWindowGfx, sizeof(sLastUsedBallWindowGfx), LAST_BALL_WINDOW_TAG +}; + +#define LAST_USED_BALL_X_F 14 +#define LAST_USED_BALL_X_0 -14 +#define LAST_USED_BALL_Y ((IsDoubleBattle()) ? 78 : 68) +#define LAST_USED_BALL_Y_BNC ((IsDoubleBattle()) ? 76 : 66) + +#define LAST_BALL_WIN_X_F (LAST_USED_BALL_X_F - 0) +#define LAST_BALL_WIN_X_0 (LAST_USED_BALL_X_0 - 0) +#define LAST_USED_WIN_Y (LAST_USED_BALL_Y - 8) + +#define sHide data[0] +#define sTimer data[1] +#define sMoving data[2] +#define sBounce data[3] // 0 = Bounce down; 1 = Bounce up + +#define sState data[0] +#define sSameBall data[1] + +bool32 CanThrowLastUsedBall(void) +{ + if (B_LAST_USED_BALL == FALSE) + return FALSE; + if (!CanThrowBall()) + return FALSE; + if (gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FRONTIER)) + return FALSE; + if (!CheckBagHasItem(gBallToDisplay, 1)) + return FALSE; + + return TRUE; +} + +void TryAddLastUsedBallItemSprites(void) +{ + if (B_LAST_USED_BALL == FALSE) + return; + if (gLastThrownBall == 0 + || (gLastThrownBall != 0 && !CheckBagHasItem(gLastThrownBall, 1))) + { + // we're out of the last used ball, so just set it to the first ball in the bag + u16 firstBall; + + // we have to compact the bag first bc it is typically only compacted when you open it + SortAndCompactBagPocket(&gBagPockets[BALLS_POCKET]); + + firstBall = gBagPockets[BALLS_POCKET].itemSlots[0].itemId; + if (firstBall > ITEM_NONE) + gBallToDisplay = firstBall; + } + + if (!CanThrowLastUsedBall()) + return; + + // ball + if (gBattleStruct->ballSpriteIds[0] == MAX_SPRITES) + { + gBattleStruct->ballSpriteIds[0] = AddItemIconObject(102, 102, gBallToDisplay); + gSprites[gBattleStruct->ballSpriteIds[0]].x = LAST_USED_BALL_X_0; + gSprites[gBattleStruct->ballSpriteIds[0]].y = LAST_USED_BALL_Y; + gSprites[gBattleStruct->ballSpriteIds[0]].sHide = FALSE; // restore + gLastUsedBallMenuPresent = TRUE; + gSprites[gBattleStruct->ballSpriteIds[0]].callback = SpriteCB_LastUsedBall; + } + + // window + LoadSpritePalette(&sSpritePalette_AbilityPopUp); + if (GetSpriteTileStartByTag(LAST_BALL_WINDOW_TAG) == 0xFFFF) + LoadSpriteSheet(&sSpriteSheet_LastUsedBallWindow); + + if (gBattleStruct->ballSpriteIds[1] == MAX_SPRITES) + { + gBattleStruct->ballSpriteIds[1] = CreateSprite(&sSpriteTemplate_LastUsedBallWindow, + LAST_BALL_WIN_X_0, + LAST_USED_WIN_Y, 5); + gSprites[gBattleStruct->ballSpriteIds[1]].sHide = FALSE; // restore + gLastUsedBallMenuPresent = TRUE; + } + if (B_LAST_USED_BALL_CYCLE == TRUE) + ArrowsChangeColorLastBallCycle(0); //Default the arrows to be invisible +} + +static void DestroyLastUsedBallWinGfx(struct Sprite *sprite) +{ + FreeSpriteTilesByTag(LAST_BALL_WINDOW_TAG); + FreeSpritePaletteByTag(ABILITY_POP_UP_TAG); + DestroySprite(sprite); + gBattleStruct->ballSpriteIds[1] = MAX_SPRITES; +} + +static void DestroyLastUsedBallGfx(struct Sprite *sprite) +{ + FreeSpriteTilesByTag(102); + FreeSpritePaletteByTag(102); + DestroySprite(sprite); + gBattleStruct->ballSpriteIds[0] = MAX_SPRITES; +} + +static void SpriteCB_LastUsedBallWin(struct Sprite *sprite) +{ + if (sprite->sHide) + { + if (sprite->x != LAST_BALL_WIN_X_0) + sprite->x--; + + if (sprite->x == LAST_BALL_WIN_X_0) + DestroyLastUsedBallWinGfx(sprite); + } + else + { + if (sprite->x != LAST_BALL_WIN_X_F) + sprite->x++; + } +} + +static void SpriteCB_LastUsedBall(struct Sprite *sprite) +{ + if (sprite->sHide) + { + if (sprite->y < LAST_USED_BALL_Y) // Used to recover from an incomplete bounce before hiding the window + sprite->y++; + + if (sprite->x != LAST_USED_BALL_X_0) + sprite->x--; + + if (sprite->x == LAST_USED_BALL_X_0) + DestroyLastUsedBallGfx(sprite); + } + else + { + if (sprite->x != LAST_USED_BALL_X_F) + sprite->x++; + } +} + +static void TryHideOrRestoreLastUsedBall(u8 caseId) +{ + if (B_LAST_USED_BALL == FALSE) + return; + if (gBattleStruct->ballSpriteIds[0] == MAX_SPRITES) + return; + + switch (caseId) + { + case 0: // hide + if (gBattleStruct->ballSpriteIds[0] != MAX_SPRITES) + gSprites[gBattleStruct->ballSpriteIds[0]].sHide = TRUE; // hide + if (gBattleStruct->ballSpriteIds[1] != MAX_SPRITES) + gSprites[gBattleStruct->ballSpriteIds[1]].sHide = TRUE; // hide + gLastUsedBallMenuPresent = FALSE; + break; + case 1: // restore + if (gBattleStruct->ballSpriteIds[0] != MAX_SPRITES) + gSprites[gBattleStruct->ballSpriteIds[0]].sHide = FALSE; // restore + if (gBattleStruct->ballSpriteIds[1] != MAX_SPRITES) + gSprites[gBattleStruct->ballSpriteIds[1]].sHide = FALSE; // restore + gLastUsedBallMenuPresent = TRUE; + break; + } + if (B_LAST_USED_BALL_CYCLE == TRUE) + ArrowsChangeColorLastBallCycle(0); //Default the arrows to be invisible +} + +void TryHideLastUsedBall(void) +{ + if (B_LAST_USED_BALL == TRUE) + TryHideOrRestoreLastUsedBall(0); +} + +void TryRestoreLastUsedBall(void) +{ + if (B_LAST_USED_BALL == FALSE) + return; + + if (gBattleStruct->ballSpriteIds[0] != MAX_SPRITES) + TryHideOrRestoreLastUsedBall(1); + else + TryAddLastUsedBallItemSprites(); +} + +static void SpriteCB_LastUsedBallBounce(struct Sprite *sprite) +{ + if ((sprite->sTimer++ % 4) != 0) // Change the image every 4 frame + return; + if (sprite->sBounce) + { + if (sprite->y > LAST_USED_BALL_Y_BNC) + sprite->y--; + else + sprite->sMoving = FALSE; + } + else + { + if (sprite->y < LAST_USED_BALL_Y) + sprite->y++; + else + sprite->sMoving = FALSE; + } +} + +static void Task_BounceBall(u8 taskId) +{ + struct Sprite *sprite = &gSprites[gBattleStruct->ballSpriteIds[0]]; + struct Task *task = &gTasks[taskId]; + switch(task->sState) + { + case 0: // Bounce up + sprite->sBounce = TRUE; + sprite->sMoving = TRUE; + sprite->callback = SpriteCB_LastUsedBallBounce; + if (task->sSameBall) + task->sState = 3; + else + task->sState = 1; + break; + case 1: // Destroy Icon + if (!sprite->sMoving) + { + DestroyLastUsedBallGfx(sprite); + task->sState++; + } // Passthrough + case 2: //Create New Icon + if (!sprite->inUse) + { + gBattleStruct->ballSpriteIds[0] = AddItemIconObject(102, 102, gBallToDisplay); + gSprites[gBattleStruct->ballSpriteIds[0]].x = LAST_USED_BALL_X_F; + gSprites[gBattleStruct->ballSpriteIds[0]].y = LAST_USED_BALL_Y_BNC; + task->sState++; + } // Fallthrough + case 3: // Bounce Down + if (!sprite->sMoving) + { + sprite->sBounce = FALSE; + sprite->sMoving = TRUE; + sprite->callback = SpriteCB_LastUsedBallBounce; //Show and bounce down + task->sState++; + } + break; + case 4: // Destroy Task + if(!sprite->sMoving) + { + sprite->callback = SpriteCB_LastUsedBall; + DestroyTask(taskId); + } + } + if (!gLastUsedBallMenuPresent) + { + // Used to check if the R button was released before the animation was complete + sprite->callback = SpriteCB_LastUsedBall; + DestroyTask(taskId); + } +} + +void SwapBallToDisplay(bool32 sameBall) +{ + u8 taskId; + taskId = CreateTask(Task_BounceBall, 10); + gTasks[taskId].sSameBall = sameBall; +} + +void ArrowsChangeColorLastBallCycle(bool32 showArrows) +{ +#if B_LAST_USED_BALL == TRUE && B_LAST_USED_BALL_CYCLE == TRUE + u16 paletteNum = 16 + gSprites[gBattleStruct->ballSpriteIds[1]].oam.paletteNum; + struct PlttData *defaultPlttArrow; + struct PlttData *defaultPlttOutline; + struct PlttData *pltArrow; + struct PlttData *pltOutline; + if (gBattleStruct->ballSpriteIds[1] == MAX_SPRITES) + return; + paletteNum *= 16; + pltArrow = (struct PlttData *)&gPlttBufferFaded[paletteNum + 9]; // Arrow color is in idx 9 + pltOutline = (struct PlttData *)&gPlttBufferFaded[paletteNum + 8]; // Arrow outline is in idx 8 + if (!showArrows) //Make invisible + { + defaultPlttArrow = (struct PlttData *)&gPlttBufferFaded[paletteNum + 13]; // Background color is idx 13 + pltArrow->r = defaultPlttArrow->r; + pltArrow->g = defaultPlttArrow->g; + pltArrow->b = defaultPlttArrow->b; + pltOutline->r = defaultPlttArrow->r; + pltOutline->g = defaultPlttArrow->g; + pltOutline->b = defaultPlttArrow->b; + } + else // Make gray + { + defaultPlttArrow = (struct PlttData *)&gPlttBufferFaded[paletteNum + 11]; // Grey color is idx 11 + defaultPlttOutline = (struct PlttData *)&gPlttBufferFaded[paletteNum + 10]; //Light grey color for outline is idx 10 + pltArrow->r = defaultPlttArrow->r; + pltArrow->g = defaultPlttArrow->g; + pltArrow->b = defaultPlttArrow->b; + pltOutline->r = defaultPlttOutline->r; + pltOutline->g = defaultPlttOutline->g; + pltOutline->b = defaultPlttOutline->b; + } +#endif +} + void CategoryIcons_LoadSpritesGfx(void) { LoadCompressedSpriteSheet(&gSpriteSheet_CategoryIcons); diff --git a/src/battle_main.c b/src/battle_main.c index fe8b71edd..fa5b2492f 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -199,6 +199,7 @@ EWRAM_DATA bool8 gHasFetchedBall = FALSE; EWRAM_DATA u8 gLastUsedBall = 0; EWRAM_DATA u16 gLastThrownBall = 0; EWRAM_DATA u16 gBallToDisplay = 0; +EWRAM_DATA bool8 gLastUsedBallMenuPresent = FALSE; EWRAM_DATA struct QueuedStatBoost gQueuedStatBoosts[MAX_BATTLERS_COUNT] = {0}; EWRAM_DATA static u8 sTriedEvolving = 0; EWRAM_DATA u8 gCategoryIconSpriteId = 0; @@ -388,6 +389,7 @@ static void (*const sTurnActionsFuncsTable[])(void) = [B_ACTION_TRY_FINISH] = HandleAction_TryFinish, [B_ACTION_FINISHED] = HandleAction_ActionFinished, [B_ACTION_NOTHING_FAINTED] = HandleAction_NothingIsFainted, + [B_ACTION_THROW_BALL] = HandleAction_ThrowBall, }; static void (*const sEndTurnFuncsTable[])(void) = @@ -3506,6 +3508,10 @@ static void HandleTurnActionSelectionState(void) return; } break; + case B_ACTION_THROW_BALL: + gBattleStruct->throwingPokeBall = TRUE; + gBattleCommunication[battler]++; + break; case B_ACTION_CANCEL_PARTNER: gBattleCommunication[battler] = STATE_WAIT_SET_BEFORE_ACTION; gBattleCommunication[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)))] = STATE_BEFORE_ACTION_CHOSEN; @@ -4113,7 +4119,8 @@ static void SetActionsAndBattlersTurnOrder(void) for (battler = 0; battler < gBattlersCount; battler++) { if (gChosenActionByBattler[battler] == B_ACTION_USE_ITEM - || gChosenActionByBattler[battler] == B_ACTION_SWITCH) + || gChosenActionByBattler[battler] == B_ACTION_SWITCH + || gChosenActionByBattler[battler] == B_ACTION_THROW_BALL) { gActionsByTurnOrder[turnOrderId] = gChosenActionByBattler[battler]; gBattlerByTurnOrder[turnOrderId] = battler; @@ -4123,7 +4130,8 @@ static void SetActionsAndBattlersTurnOrder(void) for (battler = 0; battler < gBattlersCount; battler++) { if (gChosenActionByBattler[battler] != B_ACTION_USE_ITEM - && gChosenActionByBattler[battler] != B_ACTION_SWITCH) + && gChosenActionByBattler[battler] != B_ACTION_SWITCH + && gChosenActionByBattler[battler] != B_ACTION_THROW_BALL) { gActionsByTurnOrder[turnOrderId] = gChosenActionByBattler[battler]; gBattlerByTurnOrder[turnOrderId] = battler; @@ -4142,7 +4150,9 @@ static void SetActionsAndBattlersTurnOrder(void) if (gActionsByTurnOrder[i] != B_ACTION_USE_ITEM && gActionsByTurnOrder[j] != B_ACTION_USE_ITEM && gActionsByTurnOrder[i] != B_ACTION_SWITCH - && gActionsByTurnOrder[j] != B_ACTION_SWITCH) + && gActionsByTurnOrder[j] != B_ACTION_SWITCH + && gActionsByTurnOrder[i] != B_ACTION_THROW_BALL + && gActionsByTurnOrder[j] != B_ACTION_THROW_BALL) { if (GetWhichBattlerFaster(battler1, battler2, FALSE) == -1) SwapTurnOrder(i, j); diff --git a/src/battle_util.c b/src/battle_util.c index 2f43a187e..482d8feb9 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -560,16 +560,16 @@ void HandleAction_SafariZoneBallThrow(void) gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; } -// void HandleAction_ThrowBall(void) -// { -// gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; -// gBattle_BG0_X = 0; -// gBattle_BG0_Y = 0; -// gLastUsedItem = gBallToDisplay; -// RemoveBagItem(gLastUsedItem, 1); -// gBattlescriptCurrInstr = BattleScript_BallThrow; -// gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; -// } +void HandleAction_ThrowBall(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + gLastUsedItem = gBallToDisplay; + RemoveBagItem(gLastUsedItem, 1); + gBattlescriptCurrInstr = BattleScript_BallThrow; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; +} void HandleAction_ThrowBait(void) { diff --git a/src/item.c b/src/item.c index a58a88bc6..192483f0a 100644 --- a/src/item.c +++ b/src/item.c @@ -18,7 +18,6 @@ EWRAM_DATA struct BagPocket gBagPockets[NUM_BAG_POCKETS] = {}; -void SortAndCompactBagPocket(struct BagPocket * pocket); static const u8 *ItemId_GetPluralName(u16); static bool32 DoesItemHavePluralName(u16); diff --git a/src/item_use.c b/src/item_use.c index 12d2af8df..9bc37bb30 100644 --- a/src/item_use.c +++ b/src/item_use.c @@ -936,6 +936,11 @@ static u32 GetBallThrowableState(void) return BALL_THROW_ABLE; } +bool32 CanThrowBall(void) +{ + return (GetBallThrowableState() == BALL_THROW_ABLE); +} + static const u8 sText_CantThrowPokeBall_TwoMons[] = _("Cannot throw a ball!\nThere are two Pokémon out there!\p"); static const u8 sText_CantThrowPokeBall_SemiInvulnerable[] = _("Cannot throw a ball!\nThere's no Pokémon in sight!\p"); static const u8 sText_CantThrowPokeBall_Disabled[] = _("POKé BALLS cannot be used\nright now!\p");