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 000000000..90fcef373 Binary files /dev/null and b/graphics/battle_interface/last_used_ball_l.png differ 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 000000000..58115f5a5 Binary files /dev/null and b/graphics/battle_interface/last_used_ball_l_cycle.png differ diff --git a/graphics/battle_interface/last_used_ball_r.png b/graphics/battle_interface/last_used_ball_r.png new file mode 100644 index 000000000..581569cf1 Binary files /dev/null and b/graphics/battle_interface/last_used_ball_r.png differ 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 000000000..0a73148e1 Binary files /dev/null and b/graphics/battle_interface/last_used_ball_r_cycle.png differ diff --git a/include/battle.h b/include/battle.h index 9a5c265ca..22e9d948e 100644 --- a/include/battle.h +++ b/include/battle.h @@ -72,6 +72,7 @@ #define B_ACTION_CANCEL_PARTNER 12 // when choosing an action #define B_ACTION_NOTHING_FAINTED 13 // when choosing an action #define B_ACTION_DEBUG 20 +#define B_ACTION_THROW_BALL 21 // R to throw last used ball #define B_ACTION_NONE 0xFF @@ -1077,6 +1078,7 @@ extern bool8 gHasFetchedBall; extern u8 gLastUsedBall; extern u16 gLastThrownBall; extern u16 gBallToDisplay; +extern bool8 gLastUsedBallMenuPresent; extern struct QueuedStatBoost gQueuedStatBoosts[MAX_BATTLERS_COUNT]; extern struct BattlePokemon gBattleMons[MAX_BATTLERS_COUNT]; extern u8 gAbsentBattlerFlags; diff --git a/include/battle_interface.h b/include/battle_interface.h index 98714d300..6c66fe336 100644 --- a/include/battle_interface.h +++ b/include/battle_interface.h @@ -139,6 +139,14 @@ void HideTriggerSprites(void); void CreateAbilityPopUp(u8 battlerId, u32 ability, bool32 isDoubleBattle); void DestroyAbilityPopUp(u8 battlerId); void UpdateAbilityPopup(u8 battlerId); + +bool32 CanThrowLastUsedBall(void); +void TryHideLastUsedBall(void); +void TryRestoreLastUsedBall(void); +void TryAddLastUsedBallItemSprites(void); +void SwapBallToDisplay(bool32 sameBall); +void ArrowsChangeColorLastBallCycle(bool32 showArrows); + void CategoryIcons_LoadSpritesGfx(void); #endif // GUARD_BATTLE_INTERFACE_H diff --git a/include/constants/item.h b/include/constants/item.h index 5e6d46475..e8910553d 100644 --- a/include/constants/item.h +++ b/include/constants/item.h @@ -10,12 +10,12 @@ #define POCKET_BERRIES 5 #define NUM_BAG_POCKETS 5 -// #define ITEMS_POCKET 0 -// #define BALLS_POCKET 1 -// #define TMHM_POCKET 2 -// #define BERRIES_POCKET 3 -// #define KEYITEMS_POCKET 4 -// #define POCKETS_COUNT 5 +#define ITEMS_POCKET 0 +#define KEYITEMS_POCKET 1 +#define BALLS_POCKET 2 +#define TMHM_POCKET 3 +#define BERRIES_POCKET 4 +#define POCKETS_COUNT 5 #define REPEL_LURE_MASK (1 << 15) #define IS_LAST_USED_LURE(var) (var & REPEL_LURE_MASK) diff --git a/include/item_use.h b/include/item_use.h index 3e0ece927..54d4ed927 100644 --- a/include/item_use.h +++ b/include/item_use.h @@ -57,6 +57,7 @@ enum { BALL_THROW_UNABLE_DISABLED_FLAG, }; +bool32 CanThrowBall(void); bool32 CannotUseItemsInBattle(u16 itemId, struct Pokemon *mon); #endif //GUARD_ITEM_USE_H diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index 0e898bd49..11de7d909 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -189,12 +189,115 @@ static void CompleteOnBattlerSpritePosX_0(u32 battler) PlayerBufferExecCompleted(battler); } +static u16 GetPrevBall(u16 ballId) +{ + u16 ballPrev; + s32 i, j; + SortAndCompactBagPocket(&gBagPockets[BALLS_POCKET]); + for (i = 0; i < gBagPockets[BALLS_POCKET].capacity; i++) + { + if (ballId == gBagPockets[BALLS_POCKET].itemSlots[i].itemId) + { + if (i <= 0) + { + for (j = gBagPockets[BALLS_POCKET].capacity - 1; j >= 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");