diff --git a/graphics/battle_interface/move_info_window_l.png b/graphics/battle_interface/move_info_window_l.png new file mode 100644 index 0000000000..548acf653b Binary files /dev/null and b/graphics/battle_interface/move_info_window_l.png differ diff --git a/graphics/battle_interface/move_info_window_r.png b/graphics/battle_interface/move_info_window_r.png new file mode 100644 index 0000000000..f83e8f7f88 Binary files /dev/null and b/graphics/battle_interface/move_info_window_r.png differ diff --git a/include/battle.h b/include/battle.h index 9a4a57d004..56aad13594 100644 --- a/include/battle.h +++ b/include/battle.h @@ -780,6 +780,7 @@ struct BattleStruct u8 ballSwapped:1; // Used for the last used ball feature u8 throwingPokeBall:1; u8 ballSpriteIds[2]; // item gfx, window gfx + u8 moveInfoSpriteId; // move info, window gfx u8 appearedInBattle; // Bitfield to track which Pokemon appeared in battle. Used for Burmy's form change u8 skyDropTargets[MAX_BATTLERS_COUNT]; // For Sky Drop, to account for if multiple Pokemon use Sky Drop in a double battle. // When using a move which hits multiple opponents which is then bounced by a target, we need to make sure, the move hits both opponents, the one with bounce, and the one without. diff --git a/include/battle_interface.h b/include/battle_interface.h index 3280826ff7..600a9a956d 100644 --- a/include/battle_interface.h +++ b/include/battle_interface.h @@ -128,5 +128,7 @@ void SwapBallToDisplay(bool32 sameBall); void ArrowsChangeColorLastBallCycle(bool32 showArrows); void UpdateAbilityPopup(u8 battlerId); void CategoryIcons_LoadSpritesGfx(void); +void TryToAddMoveInfoWindow(void); +void TryToHideMoveInfoWindow(void); #endif // GUARD_BATTLE_INTERFACE_H diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index fcadd22dc7..77ce6083f9 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -673,6 +673,7 @@ void HandleInputChooseMove(u32 battler) if (JOY_NEW(A_BUTTON) && !gBattleStruct->descriptionSubmenu) { + TryToHideMoveInfoWindow(); PlaySE(SE_SELECT); moveTarget = GetBattlerMoveTargetType(battler, moveInfo->moves[gMoveSelectionCursor[battler]]); @@ -783,6 +784,7 @@ void HandleInputChooseMove(u32 battler) BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, 0xFFFF); HideGimmickTriggerSprite(); PlayerBufferExecCompleted(battler); + TryToHideMoveInfoWindow(); } } else if (JOY_NEW(DPAD_LEFT) && !gBattleStruct->zmove.viewing) @@ -882,7 +884,7 @@ void HandleInputChooseMove(u32 battler) MoveSelectionDisplayMoveType(battler); } } - else if (JOY_NEW(B_MOVE_DESCRIPTION_BUTTON) && B_MOVE_DESCRIPTION_BUTTON != B_LAST_USED_BALL_BUTTON) + else if (JOY_NEW(B_MOVE_DESCRIPTION_BUTTON)) { gBattleStruct->descriptionSubmenu = TRUE; MoveSelectionDisplayMoveDescription(battler); @@ -2133,6 +2135,7 @@ void PlayerHandleChooseMove(u32 battler) InitMoveSelectionsVarsAndStrings(battler); gBattleStruct->gimmick.playerSelect = FALSE; + TryToAddMoveInfoWindow(); AssignUsableZMoves(battler, moveInfo->moves); gBattleStruct->zmove.viable = (gBattleStruct->zmove.possibleZMoves[battler] & (1u << gMoveSelectionCursor[battler])) != 0; diff --git a/src/battle_interface.c b/src/battle_interface.c index 5c514a0d80..0c2aac1898 100644 --- a/src/battle_interface.c +++ b/src/battle_interface.c @@ -206,6 +206,7 @@ static void Task_FreeAbilityPopUpGfx(u8); static void SpriteCB_LastUsedBall(struct Sprite *); static void SpriteCB_LastUsedBallWin(struct Sprite *); +static void SpriteCB_MoveInfoWin(struct Sprite *sprite); static const struct OamData sOamData_64x32 = { @@ -732,6 +733,7 @@ u8 CreateBattlerHealthboxSprites(u8 battlerId) gBattleStruct->ballSpriteIds[0] = MAX_SPRITES; gBattleStruct->ballSpriteIds[1] = MAX_SPRITES; + gBattleStruct->moveInfoSpriteId = MAX_SPRITES; return healthboxLeftSpriteId; } @@ -2874,6 +2876,36 @@ static const struct SpriteTemplate sSpriteTemplate_LastUsedBallWindow = .callback = SpriteCB_LastUsedBallWin }; +#define MOVE_INFO_WINDOW_TAG 0xE722 + +static const struct OamData sOamData_MoveInfoWindow = +{ + .y = 0, + .affineMode = 0, + .objMode = 0, + .mosaic = 0, + .bpp = 0, + .shape = SPRITE_SHAPE(32x32), + .x = 0, + .matrixNum = 0, + .size = SPRITE_SIZE(32x32), + .tileNum = 0, + .priority = 1, + .paletteNum = 0, + .affineParam = 0, +}; + +static const struct SpriteTemplate sSpriteTemplate_MoveInfoWindow = +{ + .tileTag = MOVE_INFO_WINDOW_TAG, + .paletteTag = ABILITY_POP_UP_TAG, + .oam = &sOamData_MoveInfoWindow, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCB_MoveInfoWin +}; + #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 @@ -2888,6 +2920,17 @@ static const struct SpriteSheet sSpriteSheet_LastUsedBallWindow = sLastUsedBallWindowGfx, sizeof(sLastUsedBallWindowGfx), LAST_BALL_WINDOW_TAG }; +#if B_MOVE_DESCRIPTION_BUTTON == R_BUTTON +static const u8 sMoveInfoWindowGfx[] = INCBIN_U8("graphics/battle_interface/move_info_window_r.4bpp"); +#else +static const u8 sMoveInfoWindowGfx[] = INCBIN_U8("graphics/battle_interface/move_info_window_l.4bpp"); +#endif + +static const struct SpriteSheet sSpriteSheet_MoveInfoWindow = +{ + sMoveInfoWindowGfx, sizeof(sMoveInfoWindowGfx), MOVE_INFO_WINDOW_TAG +}; + #define LAST_USED_BALL_X_F 14 #define LAST_USED_BALL_X_0 -14 #define LAST_USED_BALL_Y ((IsDoubleBattle()) ? 78 : 68) @@ -2946,7 +2989,7 @@ void TryAddLastUsedBallItemSprites(void) gBattleStruct->ballSpriteIds[0] = AddItemIconSprite(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 + gSprites[gBattleStruct->ballSpriteIds[0]].sHide = FALSE; gLastUsedBallMenuPresent = TRUE; gSprites[gBattleStruct->ballSpriteIds[0]].callback = SpriteCB_LastUsedBall; } @@ -2961,7 +3004,8 @@ void TryAddLastUsedBallItemSprites(void) gBattleStruct->ballSpriteIds[1] = CreateSprite(&sSpriteTemplate_LastUsedBallWindow, LAST_BALL_WIN_X_0, LAST_USED_WIN_Y, 5); - gSprites[gBattleStruct->ballSpriteIds[1]].sHide = FALSE; // restore + gSprites[gBattleStruct->ballSpriteIds[1]].sHide = FALSE; + gSprites[gBattleStruct->moveInfoSpriteId].sHide = TRUE; gLastUsedBallMenuPresent = TRUE; } if (B_LAST_USED_BALL_CYCLE == TRUE) @@ -2984,6 +3028,32 @@ static void DestroyLastUsedBallGfx(struct Sprite *sprite) gBattleStruct->ballSpriteIds[0] = MAX_SPRITES; } +void TryToAddMoveInfoWindow(void) +{ + LoadSpritePalette(&sSpritePalette_AbilityPopUp); + if (GetSpriteTileStartByTag(MOVE_INFO_WINDOW_TAG) == 0xFFFF) + LoadSpriteSheet(&sSpriteSheet_MoveInfoWindow); + + if (gBattleStruct->moveInfoSpriteId == MAX_SPRITES) + { + gBattleStruct->moveInfoSpriteId = CreateSprite(&sSpriteTemplate_MoveInfoWindow, LAST_BALL_WIN_X_0, LAST_USED_WIN_Y + 32, 6); + gSprites[gBattleStruct->moveInfoSpriteId].sHide = FALSE; + } +} + +void TryToHideMoveInfoWindow(void) +{ + gSprites[gBattleStruct->moveInfoSpriteId].sHide = TRUE; +} + +static void DestroyMoveInfoWinGfx(struct Sprite *sprite) +{ + FreeSpriteTilesByTag(MOVE_INFO_WINDOW_TAG); + FreeSpritePaletteByTag(ABILITY_POP_UP_TAG); + DestroySprite(sprite); + gBattleStruct->moveInfoSpriteId = MAX_SPRITES; +} + static void SpriteCB_LastUsedBallWin(struct Sprite *sprite) { if (sprite->sHide) @@ -3021,6 +3091,23 @@ static void SpriteCB_LastUsedBall(struct Sprite *sprite) } } +static void SpriteCB_MoveInfoWin(struct Sprite *sprite) +{ + if (sprite->sHide) + { + if (sprite->x != LAST_BALL_WIN_X_0) + sprite->x--; + + if (sprite->x == LAST_BALL_WIN_X_0) + DestroyMoveInfoWinGfx(sprite); + } + else + { + if (sprite->x != LAST_BALL_WIN_X_F) + sprite->x++; + } +} + static void TryHideOrRestoreLastUsedBall(u8 caseId) { if (B_LAST_USED_BALL == FALSE) @@ -3032,16 +3119,16 @@ static void TryHideOrRestoreLastUsedBall(u8 caseId) { case 0: // hide if (gBattleStruct->ballSpriteIds[0] != MAX_SPRITES) - gSprites[gBattleStruct->ballSpriteIds[0]].sHide = TRUE; // hide + gSprites[gBattleStruct->ballSpriteIds[0]].sHide = TRUE; if (gBattleStruct->ballSpriteIds[1] != MAX_SPRITES) - gSprites[gBattleStruct->ballSpriteIds[1]].sHide = TRUE; // hide + gSprites[gBattleStruct->ballSpriteIds[1]].sHide = TRUE; gLastUsedBallMenuPresent = FALSE; break; case 1: // restore if (gBattleStruct->ballSpriteIds[0] != MAX_SPRITES) - gSprites[gBattleStruct->ballSpriteIds[0]].sHide = FALSE; // restore + gSprites[gBattleStruct->ballSpriteIds[0]].sHide = FALSE; if (gBattleStruct->ballSpriteIds[1] != MAX_SPRITES) - gSprites[gBattleStruct->ballSpriteIds[1]].sHide = FALSE; // restore + gSprites[gBattleStruct->ballSpriteIds[1]].sHide = FALSE; gLastUsedBallMenuPresent = TRUE; break; }