diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 3bec1be182..f7d988026d 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -7153,7 +7153,7 @@ BattleScript_AbilityPopUp:: tryactivateabilityshield BS_ABILITY_BATTLER .if B_ABILITY_POP_UP == TRUE showabilitypopup BS_ABILITY_BATTLER - pause 40 + pause B_WAIT_TIME_SHORT .endif recordability BS_ABILITY_BATTLER sethword sABILITY_OVERWRITE, 0 @@ -7166,13 +7166,13 @@ BattleScript_AbilityPopUpScripting: BattleScript_AbilityPopUpOverwriteThenNormal: setbyte sFIXED_ABILITY_POPUP, TRUE showabilitypopup BS_ABILITY_BATTLER - pause 60 + pause B_WAIT_TIME_SHORT sethword sABILITY_OVERWRITE, 0 updateabilitypopup BS_ABILITY_BATTLER - pause 20 + pause B_WAIT_TIME_SHORT recordability BS_ABILITY_BATTLER destroyabilitypopup - pause 40 + setbyte sFIXED_ABILITY_POPUP, FALSE return BattleScript_SpeedBoostActivates:: @@ -7401,7 +7401,6 @@ BattleScript_TryIntimidateHoldEffectsRet: BattleScript_IntimidateActivates:: savetarget call BattleScript_AbilityPopUp - destroyabilitypopup setbyte gBattlerTarget, 0 BattleScript_IntimidateLoop: jumpiftargetally BattleScript_IntimidateLoopIncrement @@ -7964,8 +7963,8 @@ BattleScript_CursedBodyActivates:: BattleScript_MummyActivates:: .if B_ABILITY_POP_UP == TRUE - call BattleScript_AbilityPopUpTarget setbyte sFIXED_ABILITY_POPUP, TRUE + call BattleScript_AbilityPopUpTarget copybyte gBattlerAbility, gBattlerAttacker copyhword sABILITY_OVERWRITE, gLastUsedAbility call BattleScript_AbilityPopUpOverwriteThenNormal diff --git a/graphics/battle_interface/ability_pop_up.png b/graphics/battle_interface/ability_pop_up.png index ede0a7b5d7..fa0f09dba3 100644 Binary files a/graphics/battle_interface/ability_pop_up.png and b/graphics/battle_interface/ability_pop_up.png differ diff --git a/graphics_file_rules.mk b/graphics_file_rules.mk index 75460992f8..2b9cb9df8b 100644 --- a/graphics_file_rules.mk +++ b/graphics_file_rules.mk @@ -340,6 +340,9 @@ $(UNUSEDGFXDIR)/color_frames.4bpp: %.4bpp: %.png $(BATINTGFXDIR)/unused_window2bar.4bpp: %.4bpp: %.png $(GFX) $< $@ -num_tiles 5 -Wnum_tiles +$(BATINTGFXDIR)/ability_pop_up.4bpp: %.4bpp: %.png + $(GFX) $< $@ -mwidth 8 -mheight 4 + $(JPCONTESTGFXDIR)/composite_1.4bpp: $(JPCONTESTGFXDIR)/frame_1.4bpp \ $(JPCONTESTGFXDIR)/floor.4bpp \ $(JPCONTESTGFXDIR)/frame_2.4bpp \ diff --git a/include/sprite.h b/include/sprite.h index 5b5fd5e62f..7919075053 100644 --- a/include/sprite.h +++ b/include/sprite.h @@ -324,5 +324,6 @@ void ResetAffineAnimData(void); u32 GetSpanPerImage(u32 shape, u32 size); void RequestSpriteFrameImageCopy(u16 index, u16 tileNum, const struct SpriteFrameImage *images); void SetSpriteOamFlipBits(struct Sprite *sprite, u8 hFlip, u8 vFlip); +u8 IndexOfSpriteTileTag(u16 tag); #endif //GUARD_SPRITE_H diff --git a/src/battle_interface.c b/src/battle_interface.c index f26a7af98f..2aee6460cb 100644 --- a/src/battle_interface.c +++ b/src/battle_interface.c @@ -2410,30 +2410,69 @@ static void SafariTextIntoHealthboxObject(void *dest, u8 *windowTileData, u32 wi CpuCopy32(windowTileData + 256, dest + 256, windowWidth * TILE_SIZE_4BPP); } -#define ABILITY_POP_UP_TAG 0xD720 +#define ABILITY_POP_UP_POS_X_DIFF 64 +#define ABILITY_POP_UP_POS_X_SLIDE 128 +#define ABILITY_POP_UP_POS_X_SPEED 4 -// for sprite -#define tOriginalX data[0] -#define tHide data[1] -#define tFrames data[2] -#define tRightToLeft data[3] -#define tBattlerId data[4] -#define tIsMain data[5] +#define ABILITY_POP_UP_WIN_WIDTH 10 +#define ABILITY_POP_UP_STR_WIDTH (ABILITY_POP_UP_WIN_WIDTH * 8) -// for task -#define tSpriteId1 data[6] -#define tSpriteId2 data[7] +#define ABILITY_POP_UP_PLAYER_LEFT_WIN_W 6 +#define ABILITY_POP_UP_PLAYER_RIGHT_WIN_W 4 +#define ABILITY_POP_UP_OPPONENT_LEFT_WIN_W 7 +#define ABILITY_POP_UP_OPPONENT_RIGHT_WIN_W 3 -static const u8 ALIGNED(4) sAbilityPopUpGfx[] = INCBIN_U8("graphics/battle_interface/ability_pop_up.4bpp"); +#define ABILITY_POP_UP_WAIT_FRAMES 48 + +/* + * BG = BackGround + * FG = ForeGround + * SH = SHadow + */ +#define ABILITY_POP_UP_BATTLER_BG_TXTCLR 2 +#define ABILITY_POP_UP_BATTLER_FG_TXTCLR 7 +#define ABILITY_POP_UP_BATTLER_SH_TXTCLR 1 + +#define ABILITY_POP_UP_ABILITY_BG_TXTCLR 7 +#define ABILITY_POP_UP_ABILITY_FG_TXTCLR 9 +#define ABILITY_POP_UP_ABILITY_SH_TXTCLR 1 + +#define sState data[0] +#define sAutoDestroy data[1] +#define sTimer data[2] +#define sIsPlayerSide data[3] +#define sBattlerId data[4] +#define sIsMain data[5] + +enum +{ + APU_STATE_SLIDE_IN = 0, + APU_STATE_IDLE, + APU_STATE_SLIDE_OUT, + APU_STATE_END +}; + +enum +{ + TAG_ABILITY_POP_UP = 0xD720, // Only used for the SpritePalette, the rest below is for the SpriteSheets. + TAG_ABILITY_POP_UP_PLAYER1 = TAG_ABILITY_POP_UP, + TAG_ABILITY_POP_UP_OPPONENT1, + TAG_ABILITY_POP_UP_PLAYER2, + TAG_ABILITY_POP_UP_OPPONENT2, + TAG_LAST_BALL_WINDOW, +}; + +static const u32 sAbilityPopUpGfx[] = INCBIN_U32("graphics/battle_interface/ability_pop_up.4bpp"); static const u16 sAbilityPopUpPalette[] = INCBIN_U16("graphics/battle_interface/ability_pop_up.gbapal"); static const struct SpriteSheet sSpriteSheet_AbilityPopUp = { - sAbilityPopUpGfx, sizeof(sAbilityPopUpGfx), ABILITY_POP_UP_TAG + sAbilityPopUpGfx, sizeof(sAbilityPopUpGfx), TAG_ABILITY_POP_UP }; + static const struct SpritePalette sSpritePalette_AbilityPopUp = { - sAbilityPopUpPalette, ABILITY_POP_UP_TAG + sAbilityPopUpPalette, TAG_ABILITY_POP_UP }; static const struct OamData sOamData_AbilityPopUp = @@ -2447,8 +2486,8 @@ static const struct OamData sOamData_AbilityPopUp = static const struct SpriteTemplate sSpriteTemplate_AbilityPopUp = { - .tileTag = ABILITY_POP_UP_TAG, - .paletteTag = ABILITY_POP_UP_TAG, + .tileTag = TAG_NONE, // Changed on the fly. + .paletteTag = TAG_ABILITY_POP_UP, .oam = &sOamData_AbilityPopUp, .anims = gDummySpriteAnimTable, .images = NULL, @@ -2456,279 +2495,153 @@ static const struct SpriteTemplate sSpriteTemplate_AbilityPopUp = .callback = SpriteCb_AbilityPopUp }; -#define ABILITY_POP_UP_POS_X_DIFF (64 - 7) // Hide second sprite underneath to gain proper letter spacing -#define ABILITY_POP_UP_POS_X_SLIDE 68 - static const s16 sAbilityPopUpCoordsDoubles[MAX_BATTLERS_COUNT][2] = { - {29, 80}, // player left - {186, 19}, // opponent left - {29, 97}, // player right - {186, 36}, // opponent right + { 24, 80}, // Player left + {178, 19}, // Opponent left + { 24, 97}, // Player right + {178, 36}, // Opponent right }; static const s16 sAbilityPopUpCoordsSingles[MAX_BATTLERS_COUNT][2] = { - {29, 97}, // player - {186, 57}, // opponent + { 24, 97}, // Player + {178, 57}, // Opponent }; -#define POPUP_WINDOW_WIDTH 8 -#define MAX_POPUP_STRING_WIDTH (POPUP_WINDOW_WIDTH * 8) - -static u8* AddTextPrinterAndCreateWindowOnAbilityPopUp(const u8 *str, u32 x, u32 y, u32 color1, u32 color2, u32 color3, u32 *windowId) +static u8 *AddTextPrinterAndCreateWindowOnAbilityPopUp(const u8 *str, u32 x, u32 y, u32 bgColor, u32 fgColor, u32 shadowColor, u32 *windowId) { u32 fontId; - u8 color[3] = {color1, color2, color3}; + u8 color[3] = {bgColor, fgColor, shadowColor}; struct WindowTemplate winTemplate = {0}; - winTemplate.width = POPUP_WINDOW_WIDTH; + winTemplate.width = ABILITY_POP_UP_WIN_WIDTH; winTemplate.height = 2; *windowId = AddWindow(&winTemplate); - FillWindowPixelBuffer(*windowId, PIXEL_FILL(color1)); + FillWindowPixelBuffer(*windowId, PIXEL_FILL(bgColor)); - fontId = GetFontIdToFit(str, FONT_SMALL, 0, 76); + fontId = GetFontIdToFit(str, FONT_SMALL, 0, ABILITY_POP_UP_STR_WIDTH); AddTextPrinterParameterized4(*windowId, fontId, x, y, 0, 0, color, TEXT_SKIP_DRAW, str); + return (u8 *)(GetWindowAttribute(*windowId, WINDOW_TILE_DATA)); } -static void TextIntoAbilityPopUp(void *dest, u8 *windowTileData, s32 xTileAmount, bool32 arg3) +static void TextIntoAbilityPopUp(void *dest, u8 *windowTileData, s32 windowWidth, bool32 printNickname) { - CpuCopy32(windowTileData + 256, dest + 256, xTileAmount * 32); - if (xTileAmount > 0) + #define PIXELS(n) (n * 4) + if (windowWidth > 0) { do { - if (arg3) - CpuCopy32(windowTileData + 16, dest + 16, 16); + if (printNickname) + { + CpuCopy32(windowTileData + PIXELS(3), dest + PIXELS(3), PIXELS(5)); + CpuCopy32(windowTileData + TILE_OFFSET_4BPP(ABILITY_POP_UP_WIN_WIDTH), dest + TILE_OFFSET_4BPP(8), PIXELS(5)); + } else - CpuCopy32(windowTileData + 20, dest + 20, 12); - dest += 32, windowTileData += 32; - xTileAmount--; - } while (xTileAmount != 0); + { + CpuCopy32(windowTileData + PIXELS(7), dest + PIXELS(7), PIXELS(1)); + CpuCopy32(windowTileData + TILE_OFFSET_4BPP(ABILITY_POP_UP_WIN_WIDTH), dest + TILE_OFFSET_4BPP(8), TILE_SIZE_4BPP); + } + + dest += TILE_SIZE_4BPP, windowTileData += TILE_SIZE_4BPP; + windowWidth--; + } while (windowWidth != 0); } + #undef PIXELS } -static void PrintOnAbilityPopUp(const u8 *str, u8 *spriteTileData1, u8 *spriteTileData2, u32 x1, u32 x2, u32 y, u32 color1, u32 color2, u32 color3) +static void PrintOnAbilityPopUp(const u8 *str, u8 *spriteTileData1, u8 *spriteTileData2, u32 x, u32 y, u32 bgColor, u32 fgColor, u32 shadowColor, u32 printNickname, u32 battler) { - u32 windowId; - u8 *windowTileData; - u16 width; + u32 windowId, fontId; + u8 *windowTileData = AddTextPrinterAndCreateWindowOnAbilityPopUp(str, x, y, bgColor, fgColor, shadowColor, &windowId); + u32 size1 = ABILITY_POP_UP_OPPONENT_LEFT_WIN_W, size2 = ABILITY_POP_UP_OPPONENT_RIGHT_WIN_W; - windowTileData = AddTextPrinterAndCreateWindowOnAbilityPopUp(str, x1, y, color1, color2, color3, &windowId); - TextIntoAbilityPopUp(spriteTileData1, windowTileData, 8, (y == 0)); - RemoveWindow(windowId); - - width = GetStringWidth(FONT_SMALL, str, 0); - - if (width > MAX_POPUP_STRING_WIDTH - 5) + spriteTileData1 += TILE_OFFSET_4BPP(1); + if (IsOnPlayerSide(battler)) { - windowTileData = AddTextPrinterAndCreateWindowOnAbilityPopUp(str, x2 - MAX_POPUP_STRING_WIDTH, y, color1, color2, color3, &windowId); - TextIntoAbilityPopUp(spriteTileData2, windowTileData, 3, (y == 0)); - RemoveWindow(windowId); + size1 = ABILITY_POP_UP_PLAYER_LEFT_WIN_W, size2 = ABILITY_POP_UP_PLAYER_RIGHT_WIN_W; + // Increment again as the *first* column of the sprite + // is not shown for player's pop up when sliding in. + spriteTileData1 += TILE_OFFSET_4BPP(1); } -} -static const u8 sText_Spaces20[]= _(" "); -static void ClearAbilityName(u8 spriteId1, u8 spriteId2) -{ - PrintOnAbilityPopUp(sText_Spaces20, - (void*)(OBJ_VRAM0) + (gSprites[spriteId1].oam.tileNum * 32) + 256, - (void*)(OBJ_VRAM0) + (gSprites[spriteId2].oam.tileNum * 32) + 256, - 5, 12, - 4, - 7, 9, 1); + TextIntoAbilityPopUp(spriteTileData1, windowTileData, size1, printNickname); + fontId = GetFontIdToFit(str, FONT_SMALL, 0, ABILITY_POP_UP_STR_WIDTH); + if (GetStringWidth(fontId, str, 0) > (size1 * 8)) + { + windowTileData += TILE_OFFSET_4BPP(size1); + TextIntoAbilityPopUp(spriteTileData2, windowTileData, size2, printNickname); + } + + RemoveWindow(windowId); } static void PrintBattlerOnAbilityPopUp(u8 battler, u8 spriteId1, u8 spriteId2) { - int i; - u8 lastChar; - u8* textPtr; - u8 monName[POKEMON_NAME_LENGTH + 3] = {0}; + u32 totalChar = 0, lastChar; struct Pokemon *illusionMon = GetIllusionMonPtr(battler); - u8 nick[POKEMON_NAME_LENGTH + 1] = {0}; if (illusionMon != NULL) - GetMonData(illusionMon, MON_DATA_NICKNAME, nick); + GetMonData(illusionMon, MON_DATA_NICKNAME, gStringVar1); else - GetMonData(GetBattlerMon(battler), MON_DATA_NICKNAME, nick); + GetMonData(GetBattlerMon(battler), MON_DATA_NICKNAME, gStringVar1); - for (i = 0; i < POKEMON_NAME_LENGTH; ++i) - { - if (nick[i] == EOS) // End of string - break; + while (gStringVar1[totalChar] != EOS) + totalChar++; - monName[i] = nick[i]; - } - - textPtr = monName + i; - - lastChar = *(textPtr - 1); - - // Make the string say "[NAME]'s" instead of "[NAME]" - textPtr[0] = CHAR_SGL_QUOTE_RIGHT; // apostraphe - textPtr++; + lastChar = gStringVar1[totalChar - 1]; + StringAppend(gStringVar1, COMPOUND_STRING("'")); if (lastChar != CHAR_S && lastChar != CHAR_s) - { - textPtr[0] = CHAR_s; - textPtr++; - } + StringAppend(gStringVar1, COMPOUND_STRING("s")); - textPtr[0] = EOS; - - PrintOnAbilityPopUp((const u8 *)monName, - (void*)(OBJ_VRAM0) + (gSprites[spriteId1].oam.tileNum * 32), - (void*)(OBJ_VRAM0) + (gSprites[spriteId2].oam.tileNum * 32), - 5, 12, - 0, - 2, 7, 1); + PrintOnAbilityPopUp(gStringVar1, + (void *)(OBJ_VRAM0) + TILE_OFFSET_4BPP(gSprites[spriteId1].oam.tileNum), + (void *)(OBJ_VRAM0) + TILE_OFFSET_4BPP(gSprites[spriteId2].oam.tileNum), + 0, 0, + ABILITY_POP_UP_BATTLER_BG_TXTCLR, ABILITY_POP_UP_BATTLER_FG_TXTCLR, ABILITY_POP_UP_BATTLER_SH_TXTCLR, + TRUE, gSprites[spriteId1].sBattlerId); } static void PrintAbilityOnAbilityPopUp(u32 ability, u8 spriteId1, u8 spriteId2) { - ClearAbilityName(spriteId1, spriteId2); + PrintOnAbilityPopUp(COMPOUND_STRING(" "), + (void *)(OBJ_VRAM0) + TILE_OFFSET_4BPP(gSprites[spriteId1].oam.tileNum) + TILE_OFFSET_4BPP(8), + (void *)(OBJ_VRAM0) + TILE_OFFSET_4BPP(gSprites[spriteId2].oam.tileNum) + TILE_OFFSET_4BPP(8), + 0, 4, + ABILITY_POP_UP_ABILITY_BG_TXTCLR, ABILITY_POP_UP_ABILITY_FG_TXTCLR, ABILITY_POP_UP_ABILITY_SH_TXTCLR, + FALSE, gSprites[spriteId1].sBattlerId); PrintOnAbilityPopUp(gAbilitiesInfo[ability].name, - (void*)(OBJ_VRAM0) + (gSprites[spriteId1].oam.tileNum * 32) + 256, - (void*)(OBJ_VRAM0) + (gSprites[spriteId2].oam.tileNum * 32) + 256, - 5, 12, - 4, - 7, 9, 1); -} - -#define PIXEL_COORDS_TO_OFFSET(x, y)( \ -/*Add tiles by X*/ \ -((y / 8) * 32 * 8) \ -/*Add tiles by X*/ \ -+ ((x / 8) * 32) \ -/*Add pixels by Y*/ \ -+ ((((y) - ((y / 8) * 8))) * 4) \ -/*Add pixels by X*/ \ -+ ((((x) - ((x / 8) * 8)) / 2))) - -static const u16 sOverwrittenPixelsTable[][2] = -{ - {PIXEL_COORDS_TO_OFFSET(0, 0), 5}, - {PIXEL_COORDS_TO_OFFSET(0, 1), 5}, - {PIXEL_COORDS_TO_OFFSET(0, 2), 5}, - {PIXEL_COORDS_TO_OFFSET(0, 3), 5}, - {PIXEL_COORDS_TO_OFFSET(0, 4), 5}, - {PIXEL_COORDS_TO_OFFSET(0, 5), 5}, - {PIXEL_COORDS_TO_OFFSET(0, 6), 5}, - {PIXEL_COORDS_TO_OFFSET(0, 7), 3}, - {PIXEL_COORDS_TO_OFFSET(0, 8), 3}, - {PIXEL_COORDS_TO_OFFSET(0, 9), 3}, - {PIXEL_COORDS_TO_OFFSET(0, 10), 3}, - {PIXEL_COORDS_TO_OFFSET(0, 11), 3}, - {PIXEL_COORDS_TO_OFFSET(0, 12), 3}, - {PIXEL_COORDS_TO_OFFSET(0, 13), 8}, - - {PIXEL_COORDS_TO_OFFSET(8, 13), 8}, - {PIXEL_COORDS_TO_OFFSET(16, 13), 8}, - {PIXEL_COORDS_TO_OFFSET(24, 13), 8}, - {PIXEL_COORDS_TO_OFFSET(32, 13), 8}, - {PIXEL_COORDS_TO_OFFSET(40, 13), 8}, - {PIXEL_COORDS_TO_OFFSET(48, 13), 8}, - {PIXEL_COORDS_TO_OFFSET(56, 13), 8}, - - {PIXEL_COORDS_TO_OFFSET(0, 14), 8}, - {PIXEL_COORDS_TO_OFFSET(8, 14), 8}, - {PIXEL_COORDS_TO_OFFSET(16, 14), 8}, - {PIXEL_COORDS_TO_OFFSET(24, 14), 8}, - {PIXEL_COORDS_TO_OFFSET(32, 14), 8}, - {PIXEL_COORDS_TO_OFFSET(40, 14), 8}, - {PIXEL_COORDS_TO_OFFSET(48, 14), 8}, - {PIXEL_COORDS_TO_OFFSET(56, 14), 8}, - - {PIXEL_COORDS_TO_OFFSET(0, 15), 3}, - {PIXEL_COORDS_TO_OFFSET(0, 16), 3}, - {PIXEL_COORDS_TO_OFFSET(0, 17), 3}, - {PIXEL_COORDS_TO_OFFSET(0, 18), 3}, - {PIXEL_COORDS_TO_OFFSET(0, 19), 3}, - {PIXEL_COORDS_TO_OFFSET(0, 20), 3}, - {PIXEL_COORDS_TO_OFFSET(0, 21), 3}, - {PIXEL_COORDS_TO_OFFSET(0, 22), 3}, - {PIXEL_COORDS_TO_OFFSET(0, 23), 3}, - {PIXEL_COORDS_TO_OFFSET(0, 24), 3}, - {PIXEL_COORDS_TO_OFFSET(0, 25), 3}, - {PIXEL_COORDS_TO_OFFSET(0, 26), 3}, - -//Second Row Of Image - {PIXEL_COORDS_TO_OFFSET(0, 45), 8}, - {PIXEL_COORDS_TO_OFFSET(0, 46), 8}, - {PIXEL_COORDS_TO_OFFSET(0, 47), 8}, - {PIXEL_COORDS_TO_OFFSET(8, 45), 8}, - {PIXEL_COORDS_TO_OFFSET(8, 46), 8}, - {PIXEL_COORDS_TO_OFFSET(8, 47), 8}, - {PIXEL_COORDS_TO_OFFSET(16, 45), 8}, - {PIXEL_COORDS_TO_OFFSET(16, 46), 8}, - {PIXEL_COORDS_TO_OFFSET(16, 47), 8}, -}; - -static inline void CopyPixels(u8 *dest, const u8 *src, u32 pixelCount) -{ - u32 i = 0; - - if (pixelCount & 1) - { - while (pixelCount != 0) - { - dest[i] &= ~(0xF); - dest[i] |= (src[i] & 0xF); - if (--pixelCount != 0) - { - dest[i] &= ~(0xF0); - dest[i] |= (src[i] & 0xF0); - pixelCount--; - } - i++; - } - } - else - { - for (i = 0; i < pixelCount / 2; i++) - dest[i] = src[i]; - } -} - -static void RestoreOverwrittenPixels(u8 *tiles) -{ - u32 i; - u8 *buffer = Alloc(sizeof(sAbilityPopUpGfx) * 2); - - CpuCopy32(tiles, buffer, sizeof(sAbilityPopUpGfx)); - - for (i = 0; i < ARRAY_COUNT(sOverwrittenPixelsTable); i++) - { - CopyPixels(buffer + sOverwrittenPixelsTable[i][0], - sAbilityPopUpGfx + sOverwrittenPixelsTable[i][0], - sOverwrittenPixelsTable[i][1]); - } - - CpuCopy32(buffer, tiles, sizeof(sAbilityPopUpGfx)); - Free(buffer); + (void *)(OBJ_VRAM0) + TILE_OFFSET_4BPP(gSprites[spriteId1].oam.tileNum) + TILE_OFFSET_4BPP(8), + (void *)(OBJ_VRAM0) + TILE_OFFSET_4BPP(gSprites[spriteId2].oam.tileNum) + TILE_OFFSET_4BPP(8), + 0, 4, + ABILITY_POP_UP_ABILITY_BG_TXTCLR, ABILITY_POP_UP_ABILITY_FG_TXTCLR, ABILITY_POP_UP_ABILITY_SH_TXTCLR, + FALSE, gSprites[spriteId1].sBattlerId); } static inline bool32 IsAnyAbilityPopUpActive(void) { + u32 activeAbilityPopUps = 0; for (u32 battler = 0; battler < gBattlersCount; battler++) { if (gBattleStruct->battlerState[battler].activeAbilityPopUps) - return TRUE; + activeAbilityPopUps++; } - return FALSE; + return activeAbilityPopUps; } void CreateAbilityPopUp(u8 battler, u32 ability, bool32 isDoubleBattle) { + u8 *spriteIds; + u32 xSlide, tileTag, battlerPosition = GetBattlerPosition(battler); + struct SpriteTemplate template; const s16 (*coords)[2]; - u8 spriteId1, spriteId2, battlerPosition, taskId; - if (B_ABILITY_POP_UP == FALSE) + if (!B_ABILITY_POP_UP) return; - if (gBattleScripting.abilityPopupOverwrite != 0) + if (gBattleScripting.abilityPopupOverwrite) ability = gBattleScripting.abilityPopupOverwrite; if (gTestRunnerEnabled) @@ -2739,111 +2652,122 @@ void CreateAbilityPopUp(u8 battler, u32 ability, bool32 isDoubleBattle) } if (!IsAnyAbilityPopUpActive()) - { - LoadSpriteSheet(&sSpriteSheet_AbilityPopUp); LoadSpritePalette(&sSpritePalette_AbilityPopUp); + + tileTag = (TAG_ABILITY_POP_UP_PLAYER1 + battler); + if (IndexOfSpriteTileTag(tileTag) == 0xFF) + { + struct SpriteSheet sheet = sSpriteSheet_AbilityPopUp; + sheet.tag = tileTag; + LoadSpriteSheet(&sheet); } + coords = isDoubleBattle ? sAbilityPopUpCoordsDoubles : sAbilityPopUpCoordsSingles; + xSlide = IsOnPlayerSide(battler) ? -ABILITY_POP_UP_POS_X_SLIDE : ABILITY_POP_UP_POS_X_SLIDE; + + template = sSpriteTemplate_AbilityPopUp; + template.tileTag = tileTag; + spriteIds = gBattleStruct->abilityPopUpSpriteIds[battler]; + spriteIds[0] = CreateSprite(&template, coords[battlerPosition][0] + xSlide, + coords[battlerPosition][1], 0); + spriteIds[1] = CreateSprite(&template, coords[battlerPosition][0] + xSlide + ABILITY_POP_UP_POS_X_DIFF, + coords[battlerPosition][1], 0); + + if (IsOnPlayerSide(battler)) + { + gSprites[spriteIds[0]].sIsPlayerSide = TRUE; + gSprites[spriteIds[1]].sIsPlayerSide = TRUE; + } + + gSprites[spriteIds[1]].oam.tileNum += 32; // Second half of the pop up tiles. + + // Create only one instance, as it's only used for + // tracking the SpriteSheet(s) and SpritePalette. + if (!IsAnyAbilityPopUpActive()) + CreateTask(Task_FreeAbilityPopUpGfx, 5); + gBattleStruct->battlerState[battler].activeAbilityPopUps = TRUE; - battlerPosition = GetBattlerPosition(battler); - if (isDoubleBattle) - coords = sAbilityPopUpCoordsDoubles; - else - coords = sAbilityPopUpCoordsSingles; + gSprites[spriteIds[0]].sIsMain = TRUE; + gSprites[spriteIds[0]].sBattlerId = battler; + gSprites[spriteIds[1]].sBattlerId = battler; - if ((battlerPosition & BIT_SIDE) == B_SIDE_PLAYER) - { - spriteId1 = CreateSprite(&sSpriteTemplate_AbilityPopUp, - coords[battlerPosition][0] - ABILITY_POP_UP_POS_X_SLIDE, - coords[battlerPosition][1], 0); - spriteId2 = CreateSprite(&sSpriteTemplate_AbilityPopUp, - coords[battlerPosition][0] - ABILITY_POP_UP_POS_X_SLIDE + ABILITY_POP_UP_POS_X_DIFF, - coords[battlerPosition][1], 1); //Appears below - - gSprites[spriteId1].tRightToLeft = TRUE; - gSprites[spriteId2].tRightToLeft = TRUE; - } - else - { - spriteId1 = CreateSprite(&sSpriteTemplate_AbilityPopUp, - coords[battlerPosition][0] + ABILITY_POP_UP_POS_X_SLIDE, - coords[battlerPosition][1], 0); - spriteId2 = CreateSprite(&sSpriteTemplate_AbilityPopUp, - coords[battlerPosition][0] + ABILITY_POP_UP_POS_X_SLIDE + ABILITY_POP_UP_POS_X_DIFF, - coords[battlerPosition][1], 1); //Appears below - - gSprites[spriteId1].tRightToLeft = FALSE; - gSprites[spriteId2].tRightToLeft = FALSE; - } - - gSprites[spriteId1].tOriginalX = coords[battlerPosition][0]; - gSprites[spriteId2].tOriginalX = coords[battlerPosition][0] + ABILITY_POP_UP_POS_X_DIFF; - gSprites[spriteId2].oam.tileNum += (8 * 4); //Second half of pop up - - gBattleStruct->abilityPopUpSpriteIds[battler][0] = spriteId1; - gBattleStruct->abilityPopUpSpriteIds[battler][1] = spriteId2; - - taskId = CreateTask(Task_FreeAbilityPopUpGfx, 5); - gTasks[taskId].tSpriteId1 = spriteId1; - gTasks[taskId].tSpriteId2 = spriteId2; - - gSprites[spriteId1].tIsMain = TRUE; - gSprites[spriteId1].tBattlerId = battler; - gSprites[spriteId2].tBattlerId = battler; - - StartSpriteAnim(&gSprites[spriteId1], 0); - StartSpriteAnim(&gSprites[spriteId2], 0); - - PrintBattlerOnAbilityPopUp(battler, spriteId1, spriteId2); - PrintAbilityOnAbilityPopUp(ability, spriteId1, spriteId2); - RestoreOverwrittenPixels((void*)(OBJ_VRAM0) + (gSprites[spriteId1].oam.tileNum * 32)); + PrintBattlerOnAbilityPopUp(battler, spriteIds[0], spriteIds[1]); + PrintAbilityOnAbilityPopUp(ability, spriteIds[0], spriteIds[1]); } void UpdateAbilityPopup(u8 battler) { - u8 spriteId1 = gBattleStruct->abilityPopUpSpriteIds[battler][0]; - u8 spriteId2 = gBattleStruct->abilityPopUpSpriteIds[battler][1]; - u16 ability = (gBattleScripting.abilityPopupOverwrite != 0) ? gBattleScripting.abilityPopupOverwrite : gBattleMons[battler].ability; - - PrintAbilityOnAbilityPopUp(ability, spriteId1, spriteId2); - RestoreOverwrittenPixels((void*)(OBJ_VRAM0) + (gSprites[spriteId1].oam.tileNum * 32)); + u8 *spriteIds = gBattleStruct->abilityPopUpSpriteIds[battler]; + u16 ability = (gBattleScripting.abilityPopupOverwrite) ? gBattleScripting.abilityPopupOverwrite + : gBattleMons[battler].ability; + PrintAbilityOnAbilityPopUp(ability, spriteIds[0], spriteIds[1]); } -#define FRAMES_TO_WAIT 48 - static void SpriteCb_AbilityPopUp(struct Sprite *sprite) { - if (!sprite->tHide) // Show + s16 *data = sprite->data; + u32 battlerPosition = GetBattlerPosition(sBattlerId); + u32 fullX = sprite->x + sprite->x2; + u32 speed; + + switch (sState) { - if (sprite->tIsMain && ++sprite->tFrames == 4) + case APU_STATE_SLIDE_IN: + { + const s16 (*coords)[2] = IsDoubleBattle() ? sAbilityPopUpCoordsDoubles : sAbilityPopUpCoordsSingles; + u32 xCoord = coords[battlerPosition][0]; + + if (sIsMain && ++sTimer == 4) PlaySE(SE_BALL_TRAY_ENTER); - if ((!sprite->tRightToLeft && (sprite->x -= 4) <= sprite->tOriginalX) - || (sprite->tRightToLeft && (sprite->x += 4) >= sprite->tOriginalX) - ) - { - sprite->x = sprite->tOriginalX; - sprite->tHide = TRUE; - sprite->tFrames = FRAMES_TO_WAIT; - } + + if (!sIsMain) + xCoord += ABILITY_POP_UP_POS_X_DIFF; + + if (fullX == xCoord) + { + sTimer = ABILITY_POP_UP_WAIT_FRAMES; + sState = APU_STATE_IDLE; + break; + } + + speed = sIsPlayerSide ? ABILITY_POP_UP_POS_X_SPEED : -ABILITY_POP_UP_POS_X_SPEED; + sprite->x2 += speed; + break; } - else // Hide + case APU_STATE_IDLE: { - if (sprite->tFrames == 0) + if (!sTimer || sAutoDestroy) { - if ((!sprite->tRightToLeft && (sprite->x += 4) >= sprite->tOriginalX + ABILITY_POP_UP_POS_X_SLIDE) - ||(sprite->tRightToLeft && (sprite->x -= 4) <= sprite->tOriginalX - ABILITY_POP_UP_POS_X_SLIDE) - ) - { - gBattleStruct->battlerState[sprite->tBattlerId].activeAbilityPopUps = FALSE; - DestroySprite(sprite); - } - } - else - { - if (!gBattleScripting.fixedPopup) - sprite->tFrames--; + sState = APU_STATE_SLIDE_OUT; + break; } + + if (!gBattleScripting.fixedPopup) + sTimer--; + + break; + } + case APU_STATE_SLIDE_OUT: + { + if (fullX == sprite->x) + { + sState = APU_STATE_END; + break; + } + + speed = sIsPlayerSide ? -ABILITY_POP_UP_POS_X_SPEED : ABILITY_POP_UP_POS_X_SPEED; + sprite->x2 += speed; + break; + } + case APU_STATE_END: + { + if (sIsMain) + gBattleStruct->battlerState[sBattlerId].activeAbilityPopUps = FALSE; + + DestroySprite(sprite); + break; + } } } @@ -2851,26 +2775,33 @@ void DestroyAbilityPopUp(u8 battler) { if (gBattleStruct->battlerState[battler].activeAbilityPopUps) { - gSprites[gBattleStruct->abilityPopUpSpriteIds[battler][0]].tFrames = 0; - gSprites[gBattleStruct->abilityPopUpSpriteIds[battler][1]].tFrames = 0; + gSprites[gBattleStruct->abilityPopUpSpriteIds[battler][0]].sAutoDestroy = TRUE; + gSprites[gBattleStruct->abilityPopUpSpriteIds[battler][1]].sAutoDestroy = TRUE; } - gBattleScripting.fixedPopup = FALSE; } static void Task_FreeAbilityPopUpGfx(u8 taskId) { - if (!gSprites[gTasks[taskId].tSpriteId1].inUse - && !gSprites[gTasks[taskId].tSpriteId2].inUse - && !IsAnyAbilityPopUpActive()) + if (!IsAnyAbilityPopUpActive()) { - FreeSpriteTilesByTag(ABILITY_POP_UP_TAG); - FreeSpritePaletteByTag(ABILITY_POP_UP_TAG); + for (u32 battler = 0; battler < gBattlersCount; battler++) + { + if (IndexOfSpriteTileTag(TAG_ABILITY_POP_UP_PLAYER1 + battler) != 0xFF) + FreeSpriteTilesByTag(TAG_ABILITY_POP_UP_PLAYER1 + battler); + } + FreeSpritePaletteByTag(TAG_ABILITY_POP_UP); DestroyTask(taskId); } } +#undef sState +#undef sAutoDestroy +#undef sTimer +#undef sIsPlayerSide +#undef sBattlerId +#undef sIsMain + // last used ball -#define LAST_BALL_WINDOW_TAG 0xD721 static const struct OamData sOamData_LastUsedBall = { @@ -2891,8 +2822,8 @@ static const struct OamData sOamData_LastUsedBall = static const struct SpriteTemplate sSpriteTemplate_LastUsedBallWindow = { - .tileTag = LAST_BALL_WINDOW_TAG, - .paletteTag = ABILITY_POP_UP_TAG, + .tileTag = TAG_LAST_BALL_WINDOW, + .paletteTag = TAG_ABILITY_POP_UP, .oam = &sOamData_LastUsedBall, .anims = gDummySpriteAnimTable, .images = NULL, @@ -2922,7 +2853,7 @@ static const struct OamData sOamData_MoveInfoWindow = static const struct SpriteTemplate sSpriteTemplate_MoveInfoWindow = { .tileTag = MOVE_INFO_WINDOW_TAG, - .paletteTag = ABILITY_POP_UP_TAG, + .paletteTag = TAG_ABILITY_POP_UP, .oam = &sOamData_MoveInfoWindow, .anims = gDummySpriteAnimTable, .images = NULL, @@ -2941,7 +2872,7 @@ static const struct SpriteTemplate sSpriteTemplate_MoveInfoWindow = #endif static const struct SpriteSheet sSpriteSheet_LastUsedBallWindow = { - sLastUsedBallWindowGfx, sizeof(sLastUsedBallWindowGfx), LAST_BALL_WINDOW_TAG + sLastUsedBallWindowGfx, sizeof(sLastUsedBallWindowGfx), TAG_LAST_BALL_WINDOW }; #if B_MOVE_DESCRIPTION_BUTTON == R_BUTTON @@ -3020,7 +2951,7 @@ void TryAddLastUsedBallItemSprites(void) // window LoadSpritePalette(&sSpritePalette_AbilityPopUp); - if (GetSpriteTileStartByTag(LAST_BALL_WINDOW_TAG) == 0xFFFF) + if (GetSpriteTileStartByTag(TAG_LAST_BALL_WINDOW) == 0xFFFF) LoadSpriteSheet(&sSpriteSheet_LastUsedBallWindow); if (gBattleStruct->ballSpriteIds[1] == MAX_SPRITES) @@ -3038,8 +2969,8 @@ void TryAddLastUsedBallItemSprites(void) static void DestroyLastUsedBallWinGfx(struct Sprite *sprite) { - FreeSpriteTilesByTag(LAST_BALL_WINDOW_TAG); - FreeSpritePaletteByTag(ABILITY_POP_UP_TAG); + FreeSpriteTilesByTag(TAG_LAST_BALL_WINDOW); + FreeSpritePaletteByTag(TAG_ABILITY_POP_UP); DestroySprite(sprite); gBattleStruct->ballSpriteIds[1] = MAX_SPRITES; } @@ -3076,7 +3007,7 @@ void TryToHideMoveInfoWindow(void) static void DestroyMoveInfoWinGfx(struct Sprite *sprite) { FreeSpriteTilesByTag(MOVE_INFO_WINDOW_TAG); - FreeSpritePaletteByTag(ABILITY_POP_UP_TAG); + FreeSpritePaletteByTag(TAG_ABILITY_POP_UP); DestroySprite(sprite); gBattleStruct->moveInfoSpriteId = MAX_SPRITES; } diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index f148129b2d..c0842af259 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -10795,7 +10795,10 @@ static void Cmd_various(void) case VARIOUS_DESTROY_ABILITY_POPUP: { VARIOUS_ARGS(); - DestroyAbilityPopUp(battler); + for (u32 i = 0; i < gBattlersCount; i++) + { + DestroyAbilityPopUp(i); + } break; } case VARIOUS_TOTEM_BOOST: diff --git a/src/sprite.c b/src/sprite.c index 225c181f42..1b89a50be1 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -85,7 +85,6 @@ static void ApplyAffineAnimFrameRelativeAndUpdateMatrix(u8 matrixNum, struct Aff static s16 ConvertScaleParam(s16 scale); static void GetAffineAnimFrame(u8 matrixNum, struct Sprite *sprite, struct AffineAnimFrameCmd *frameCmd); static void ApplyAffineAnimFrame(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd); -static u8 IndexOfSpriteTileTag(u16 tag); static void AllocSpriteTileRange(u16 tag, u16 start, u16 count); static void DoLoadSpritePalette(const u16 *src, u16 paletteOffset); static void UpdateSpriteMatrixAnchorPos(struct Sprite *, s32, s32);