add last used ball feature

This commit is contained in:
cawtds
2024-07-24 21:25:31 +02:00
parent c48d2b698e
commit 1f11ff06e9
14 changed files with 509 additions and 23 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 B

View File

@@ -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;

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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");