battle_interface: overhaul ability pop up (#7227)

This commit is contained in:
mudskipper13
2025-07-11 00:09:52 +07:00
committed by GitHub
parent 95a02dddb9
commit 0d09e5cce8
7 changed files with 269 additions and 333 deletions

View File

@@ -7153,7 +7153,7 @@ BattleScript_AbilityPopUp::
tryactivateabilityshield BS_ABILITY_BATTLER tryactivateabilityshield BS_ABILITY_BATTLER
.if B_ABILITY_POP_UP == TRUE .if B_ABILITY_POP_UP == TRUE
showabilitypopup BS_ABILITY_BATTLER showabilitypopup BS_ABILITY_BATTLER
pause 40 pause B_WAIT_TIME_SHORT
.endif .endif
recordability BS_ABILITY_BATTLER recordability BS_ABILITY_BATTLER
sethword sABILITY_OVERWRITE, 0 sethword sABILITY_OVERWRITE, 0
@@ -7166,13 +7166,13 @@ BattleScript_AbilityPopUpScripting:
BattleScript_AbilityPopUpOverwriteThenNormal: BattleScript_AbilityPopUpOverwriteThenNormal:
setbyte sFIXED_ABILITY_POPUP, TRUE setbyte sFIXED_ABILITY_POPUP, TRUE
showabilitypopup BS_ABILITY_BATTLER showabilitypopup BS_ABILITY_BATTLER
pause 60 pause B_WAIT_TIME_SHORT
sethword sABILITY_OVERWRITE, 0 sethword sABILITY_OVERWRITE, 0
updateabilitypopup BS_ABILITY_BATTLER updateabilitypopup BS_ABILITY_BATTLER
pause 20 pause B_WAIT_TIME_SHORT
recordability BS_ABILITY_BATTLER recordability BS_ABILITY_BATTLER
destroyabilitypopup destroyabilitypopup
pause 40 setbyte sFIXED_ABILITY_POPUP, FALSE
return return
BattleScript_SpeedBoostActivates:: BattleScript_SpeedBoostActivates::
@@ -7401,7 +7401,6 @@ BattleScript_TryIntimidateHoldEffectsRet:
BattleScript_IntimidateActivates:: BattleScript_IntimidateActivates::
savetarget savetarget
call BattleScript_AbilityPopUp call BattleScript_AbilityPopUp
destroyabilitypopup
setbyte gBattlerTarget, 0 setbyte gBattlerTarget, 0
BattleScript_IntimidateLoop: BattleScript_IntimidateLoop:
jumpiftargetally BattleScript_IntimidateLoopIncrement jumpiftargetally BattleScript_IntimidateLoopIncrement
@@ -7964,8 +7963,8 @@ BattleScript_CursedBodyActivates::
BattleScript_MummyActivates:: BattleScript_MummyActivates::
.if B_ABILITY_POP_UP == TRUE .if B_ABILITY_POP_UP == TRUE
call BattleScript_AbilityPopUpTarget
setbyte sFIXED_ABILITY_POPUP, TRUE setbyte sFIXED_ABILITY_POPUP, TRUE
call BattleScript_AbilityPopUpTarget
copybyte gBattlerAbility, gBattlerAttacker copybyte gBattlerAbility, gBattlerAttacker
copyhword sABILITY_OVERWRITE, gLastUsedAbility copyhword sABILITY_OVERWRITE, gLastUsedAbility
call BattleScript_AbilityPopUpOverwriteThenNormal call BattleScript_AbilityPopUpOverwriteThenNormal

Binary file not shown.

Before

Width:  |  Height:  |  Size: 284 B

After

Width:  |  Height:  |  Size: 234 B

View File

@@ -340,6 +340,9 @@ $(UNUSEDGFXDIR)/color_frames.4bpp: %.4bpp: %.png
$(BATINTGFXDIR)/unused_window2bar.4bpp: %.4bpp: %.png $(BATINTGFXDIR)/unused_window2bar.4bpp: %.4bpp: %.png
$(GFX) $< $@ -num_tiles 5 -Wnum_tiles $(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)/composite_1.4bpp: $(JPCONTESTGFXDIR)/frame_1.4bpp \
$(JPCONTESTGFXDIR)/floor.4bpp \ $(JPCONTESTGFXDIR)/floor.4bpp \
$(JPCONTESTGFXDIR)/frame_2.4bpp \ $(JPCONTESTGFXDIR)/frame_2.4bpp \

View File

@@ -324,5 +324,6 @@ void ResetAffineAnimData(void);
u32 GetSpanPerImage(u32 shape, u32 size); u32 GetSpanPerImage(u32 shape, u32 size);
void RequestSpriteFrameImageCopy(u16 index, u16 tileNum, const struct SpriteFrameImage *images); void RequestSpriteFrameImageCopy(u16 index, u16 tileNum, const struct SpriteFrameImage *images);
void SetSpriteOamFlipBits(struct Sprite *sprite, u8 hFlip, u8 vFlip); void SetSpriteOamFlipBits(struct Sprite *sprite, u8 hFlip, u8 vFlip);
u8 IndexOfSpriteTileTag(u16 tag);
#endif //GUARD_SPRITE_H #endif //GUARD_SPRITE_H

View File

@@ -2410,30 +2410,69 @@ static void SafariTextIntoHealthboxObject(void *dest, u8 *windowTileData, u32 wi
CpuCopy32(windowTileData + 256, dest + 256, windowWidth * TILE_SIZE_4BPP); 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 ABILITY_POP_UP_WIN_WIDTH 10
#define tOriginalX data[0] #define ABILITY_POP_UP_STR_WIDTH (ABILITY_POP_UP_WIN_WIDTH * 8)
#define tHide data[1]
#define tFrames data[2]
#define tRightToLeft data[3]
#define tBattlerId data[4]
#define tIsMain data[5]
// for task #define ABILITY_POP_UP_PLAYER_LEFT_WIN_W 6
#define tSpriteId1 data[6] #define ABILITY_POP_UP_PLAYER_RIGHT_WIN_W 4
#define tSpriteId2 data[7] #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 u16 sAbilityPopUpPalette[] = INCBIN_U16("graphics/battle_interface/ability_pop_up.gbapal");
static const struct SpriteSheet sSpriteSheet_AbilityPopUp = 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 = static const struct SpritePalette sSpritePalette_AbilityPopUp =
{ {
sAbilityPopUpPalette, ABILITY_POP_UP_TAG sAbilityPopUpPalette, TAG_ABILITY_POP_UP
}; };
static const struct OamData sOamData_AbilityPopUp = static const struct OamData sOamData_AbilityPopUp =
@@ -2447,8 +2486,8 @@ static const struct OamData sOamData_AbilityPopUp =
static const struct SpriteTemplate sSpriteTemplate_AbilityPopUp = static const struct SpriteTemplate sSpriteTemplate_AbilityPopUp =
{ {
.tileTag = ABILITY_POP_UP_TAG, .tileTag = TAG_NONE, // Changed on the fly.
.paletteTag = ABILITY_POP_UP_TAG, .paletteTag = TAG_ABILITY_POP_UP,
.oam = &sOamData_AbilityPopUp, .oam = &sOamData_AbilityPopUp,
.anims = gDummySpriteAnimTable, .anims = gDummySpriteAnimTable,
.images = NULL, .images = NULL,
@@ -2456,279 +2495,153 @@ static const struct SpriteTemplate sSpriteTemplate_AbilityPopUp =
.callback = SpriteCb_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] = static const s16 sAbilityPopUpCoordsDoubles[MAX_BATTLERS_COUNT][2] =
{ {
{29, 80}, // player left { 24, 80}, // Player left
{186, 19}, // opponent left {178, 19}, // Opponent left
{29, 97}, // player right { 24, 97}, // Player right
{186, 36}, // opponent right {178, 36}, // Opponent right
}; };
static const s16 sAbilityPopUpCoordsSingles[MAX_BATTLERS_COUNT][2] = static const s16 sAbilityPopUpCoordsSingles[MAX_BATTLERS_COUNT][2] =
{ {
{29, 97}, // player { 24, 97}, // Player
{186, 57}, // opponent {178, 57}, // Opponent
}; };
#define POPUP_WINDOW_WIDTH 8 static u8 *AddTextPrinterAndCreateWindowOnAbilityPopUp(const u8 *str, u32 x, u32 y, u32 bgColor, u32 fgColor, u32 shadowColor, u32 *windowId)
#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)
{ {
u32 fontId; u32 fontId;
u8 color[3] = {color1, color2, color3}; u8 color[3] = {bgColor, fgColor, shadowColor};
struct WindowTemplate winTemplate = {0}; struct WindowTemplate winTemplate = {0};
winTemplate.width = POPUP_WINDOW_WIDTH; winTemplate.width = ABILITY_POP_UP_WIN_WIDTH;
winTemplate.height = 2; winTemplate.height = 2;
*windowId = AddWindow(&winTemplate); *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); AddTextPrinterParameterized4(*windowId, fontId, x, y, 0, 0, color, TEXT_SKIP_DRAW, str);
return (u8 *)(GetWindowAttribute(*windowId, WINDOW_TILE_DATA)); 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); #define PIXELS(n) (n * 4)
if (xTileAmount > 0) if (windowWidth > 0)
{ {
do do
{ {
if (arg3) if (printNickname)
CpuCopy32(windowTileData + 16, dest + 16, 16); {
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 else
CpuCopy32(windowTileData + 20, dest + 20, 12); {
dest += 32, windowTileData += 32; CpuCopy32(windowTileData + PIXELS(7), dest + PIXELS(7), PIXELS(1));
xTileAmount--; CpuCopy32(windowTileData + TILE_OFFSET_4BPP(ABILITY_POP_UP_WIN_WIDTH), dest + TILE_OFFSET_4BPP(8), TILE_SIZE_4BPP);
} while (xTileAmount != 0); }
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; u32 windowId, fontId;
u8 *windowTileData; u8 *windowTileData = AddTextPrinterAndCreateWindowOnAbilityPopUp(str, x, y, bgColor, fgColor, shadowColor, &windowId);
u16 width; 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); spriteTileData1 += TILE_OFFSET_4BPP(1);
TextIntoAbilityPopUp(spriteTileData1, windowTileData, 8, (y == 0)); if (IsOnPlayerSide(battler))
RemoveWindow(windowId);
width = GetStringWidth(FONT_SMALL, str, 0);
if (width > MAX_POPUP_STRING_WIDTH - 5)
{ {
windowTileData = AddTextPrinterAndCreateWindowOnAbilityPopUp(str, x2 - MAX_POPUP_STRING_WIDTH, y, color1, color2, color3, &windowId); size1 = ABILITY_POP_UP_PLAYER_LEFT_WIN_W, size2 = ABILITY_POP_UP_PLAYER_RIGHT_WIN_W;
TextIntoAbilityPopUp(spriteTileData2, windowTileData, 3, (y == 0)); // Increment again as the *first* column of the sprite
RemoveWindow(windowId); // is not shown for player's pop up when sliding in.
spriteTileData1 += TILE_OFFSET_4BPP(1);
} }
}
static const u8 sText_Spaces20[]= _(" "); TextIntoAbilityPopUp(spriteTileData1, windowTileData, size1, printNickname);
static void ClearAbilityName(u8 spriteId1, u8 spriteId2) fontId = GetFontIdToFit(str, FONT_SMALL, 0, ABILITY_POP_UP_STR_WIDTH);
{ if (GetStringWidth(fontId, str, 0) > (size1 * 8))
PrintOnAbilityPopUp(sText_Spaces20, {
(void*)(OBJ_VRAM0) + (gSprites[spriteId1].oam.tileNum * 32) + 256, windowTileData += TILE_OFFSET_4BPP(size1);
(void*)(OBJ_VRAM0) + (gSprites[spriteId2].oam.tileNum * 32) + 256, TextIntoAbilityPopUp(spriteTileData2, windowTileData, size2, printNickname);
5, 12, }
4,
7, 9, 1); RemoveWindow(windowId);
} }
static void PrintBattlerOnAbilityPopUp(u8 battler, u8 spriteId1, u8 spriteId2) static void PrintBattlerOnAbilityPopUp(u8 battler, u8 spriteId1, u8 spriteId2)
{ {
int i; u32 totalChar = 0, lastChar;
u8 lastChar;
u8* textPtr;
u8 monName[POKEMON_NAME_LENGTH + 3] = {0};
struct Pokemon *illusionMon = GetIllusionMonPtr(battler); struct Pokemon *illusionMon = GetIllusionMonPtr(battler);
u8 nick[POKEMON_NAME_LENGTH + 1] = {0};
if (illusionMon != NULL) if (illusionMon != NULL)
GetMonData(illusionMon, MON_DATA_NICKNAME, nick); GetMonData(illusionMon, MON_DATA_NICKNAME, gStringVar1);
else else
GetMonData(GetBattlerMon(battler), MON_DATA_NICKNAME, nick); GetMonData(GetBattlerMon(battler), MON_DATA_NICKNAME, gStringVar1);
for (i = 0; i < POKEMON_NAME_LENGTH; ++i) while (gStringVar1[totalChar] != EOS)
{ totalChar++;
if (nick[i] == EOS) // End of string
break;
monName[i] = nick[i]; lastChar = gStringVar1[totalChar - 1];
} StringAppend(gStringVar1, COMPOUND_STRING("'"));
textPtr = monName + i;
lastChar = *(textPtr - 1);
// Make the string say "[NAME]'s" instead of "[NAME]"
textPtr[0] = CHAR_SGL_QUOTE_RIGHT; // apostraphe
textPtr++;
if (lastChar != CHAR_S && lastChar != CHAR_s) if (lastChar != CHAR_S && lastChar != CHAR_s)
{ StringAppend(gStringVar1, COMPOUND_STRING("s"));
textPtr[0] = CHAR_s;
textPtr++;
}
textPtr[0] = EOS; PrintOnAbilityPopUp(gStringVar1,
(void *)(OBJ_VRAM0) + TILE_OFFSET_4BPP(gSprites[spriteId1].oam.tileNum),
PrintOnAbilityPopUp((const u8 *)monName, (void *)(OBJ_VRAM0) + TILE_OFFSET_4BPP(gSprites[spriteId2].oam.tileNum),
(void*)(OBJ_VRAM0) + (gSprites[spriteId1].oam.tileNum * 32), 0, 0,
(void*)(OBJ_VRAM0) + (gSprites[spriteId2].oam.tileNum * 32), ABILITY_POP_UP_BATTLER_BG_TXTCLR, ABILITY_POP_UP_BATTLER_FG_TXTCLR, ABILITY_POP_UP_BATTLER_SH_TXTCLR,
5, 12, TRUE, gSprites[spriteId1].sBattlerId);
0,
2, 7, 1);
} }
static void PrintAbilityOnAbilityPopUp(u32 ability, u8 spriteId1, u8 spriteId2) 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, PrintOnAbilityPopUp(gAbilitiesInfo[ability].name,
(void*)(OBJ_VRAM0) + (gSprites[spriteId1].oam.tileNum * 32) + 256, (void *)(OBJ_VRAM0) + TILE_OFFSET_4BPP(gSprites[spriteId1].oam.tileNum) + TILE_OFFSET_4BPP(8),
(void*)(OBJ_VRAM0) + (gSprites[spriteId2].oam.tileNum * 32) + 256, (void *)(OBJ_VRAM0) + TILE_OFFSET_4BPP(gSprites[spriteId2].oam.tileNum) + TILE_OFFSET_4BPP(8),
5, 12, 0, 4,
4, ABILITY_POP_UP_ABILITY_BG_TXTCLR, ABILITY_POP_UP_ABILITY_FG_TXTCLR, ABILITY_POP_UP_ABILITY_SH_TXTCLR,
7, 9, 1); FALSE, gSprites[spriteId1].sBattlerId);
}
#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);
} }
static inline bool32 IsAnyAbilityPopUpActive(void) static inline bool32 IsAnyAbilityPopUpActive(void)
{ {
u32 activeAbilityPopUps = 0;
for (u32 battler = 0; battler < gBattlersCount; battler++) for (u32 battler = 0; battler < gBattlersCount; battler++)
{ {
if (gBattleStruct->battlerState[battler].activeAbilityPopUps) if (gBattleStruct->battlerState[battler].activeAbilityPopUps)
return TRUE; activeAbilityPopUps++;
} }
return FALSE; return activeAbilityPopUps;
} }
void CreateAbilityPopUp(u8 battler, u32 ability, bool32 isDoubleBattle) void CreateAbilityPopUp(u8 battler, u32 ability, bool32 isDoubleBattle)
{ {
u8 *spriteIds;
u32 xSlide, tileTag, battlerPosition = GetBattlerPosition(battler);
struct SpriteTemplate template;
const s16 (*coords)[2]; const s16 (*coords)[2];
u8 spriteId1, spriteId2, battlerPosition, taskId;
if (B_ABILITY_POP_UP == FALSE) if (!B_ABILITY_POP_UP)
return; return;
if (gBattleScripting.abilityPopupOverwrite != 0) if (gBattleScripting.abilityPopupOverwrite)
ability = gBattleScripting.abilityPopupOverwrite; ability = gBattleScripting.abilityPopupOverwrite;
if (gTestRunnerEnabled) if (gTestRunnerEnabled)
@@ -2739,111 +2652,122 @@ void CreateAbilityPopUp(u8 battler, u32 ability, bool32 isDoubleBattle)
} }
if (!IsAnyAbilityPopUpActive()) if (!IsAnyAbilityPopUpActive())
{
LoadSpriteSheet(&sSpriteSheet_AbilityPopUp);
LoadSpritePalette(&sSpritePalette_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; gBattleStruct->battlerState[battler].activeAbilityPopUps = TRUE;
battlerPosition = GetBattlerPosition(battler);
if (isDoubleBattle) gSprites[spriteIds[0]].sIsMain = TRUE;
coords = sAbilityPopUpCoordsDoubles; gSprites[spriteIds[0]].sBattlerId = battler;
else gSprites[spriteIds[1]].sBattlerId = battler;
coords = sAbilityPopUpCoordsSingles;
if ((battlerPosition & BIT_SIDE) == B_SIDE_PLAYER) PrintBattlerOnAbilityPopUp(battler, spriteIds[0], spriteIds[1]);
{ PrintAbilityOnAbilityPopUp(ability, spriteIds[0], spriteIds[1]);
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));
} }
void UpdateAbilityPopup(u8 battler) void UpdateAbilityPopup(u8 battler)
{ {
u8 spriteId1 = gBattleStruct->abilityPopUpSpriteIds[battler][0]; u8 *spriteIds = gBattleStruct->abilityPopUpSpriteIds[battler];
u8 spriteId2 = gBattleStruct->abilityPopUpSpriteIds[battler][1]; u16 ability = (gBattleScripting.abilityPopupOverwrite) ? gBattleScripting.abilityPopupOverwrite
u16 ability = (gBattleScripting.abilityPopupOverwrite != 0) ? gBattleScripting.abilityPopupOverwrite : gBattleMons[battler].ability; : gBattleMons[battler].ability;
PrintAbilityOnAbilityPopUp(ability, spriteIds[0], spriteIds[1]);
PrintAbilityOnAbilityPopUp(ability, spriteId1, spriteId2);
RestoreOverwrittenPixels((void*)(OBJ_VRAM0) + (gSprites[spriteId1].oam.tileNum * 32));
} }
#define FRAMES_TO_WAIT 48
static void SpriteCb_AbilityPopUp(struct Sprite *sprite) 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); PlaySE(SE_BALL_TRAY_ENTER);
if ((!sprite->tRightToLeft && (sprite->x -= 4) <= sprite->tOriginalX)
|| (sprite->tRightToLeft && (sprite->x += 4) >= sprite->tOriginalX) if (!sIsMain)
) xCoord += ABILITY_POP_UP_POS_X_DIFF;
{
sprite->x = sprite->tOriginalX; if (fullX == xCoord)
sprite->tHide = TRUE; {
sprite->tFrames = FRAMES_TO_WAIT; 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) sState = APU_STATE_SLIDE_OUT;
||(sprite->tRightToLeft && (sprite->x -= 4) <= sprite->tOriginalX - ABILITY_POP_UP_POS_X_SLIDE) break;
)
{
gBattleStruct->battlerState[sprite->tBattlerId].activeAbilityPopUps = FALSE;
DestroySprite(sprite);
}
}
else
{
if (!gBattleScripting.fixedPopup)
sprite->tFrames--;
} }
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) if (gBattleStruct->battlerState[battler].activeAbilityPopUps)
{ {
gSprites[gBattleStruct->abilityPopUpSpriteIds[battler][0]].tFrames = 0; gSprites[gBattleStruct->abilityPopUpSpriteIds[battler][0]].sAutoDestroy = TRUE;
gSprites[gBattleStruct->abilityPopUpSpriteIds[battler][1]].tFrames = 0; gSprites[gBattleStruct->abilityPopUpSpriteIds[battler][1]].sAutoDestroy = TRUE;
} }
gBattleScripting.fixedPopup = FALSE;
} }
static void Task_FreeAbilityPopUpGfx(u8 taskId) static void Task_FreeAbilityPopUpGfx(u8 taskId)
{ {
if (!gSprites[gTasks[taskId].tSpriteId1].inUse if (!IsAnyAbilityPopUpActive())
&& !gSprites[gTasks[taskId].tSpriteId2].inUse
&& !IsAnyAbilityPopUpActive())
{ {
FreeSpriteTilesByTag(ABILITY_POP_UP_TAG); for (u32 battler = 0; battler < gBattlersCount; battler++)
FreeSpritePaletteByTag(ABILITY_POP_UP_TAG); {
if (IndexOfSpriteTileTag(TAG_ABILITY_POP_UP_PLAYER1 + battler) != 0xFF)
FreeSpriteTilesByTag(TAG_ABILITY_POP_UP_PLAYER1 + battler);
}
FreeSpritePaletteByTag(TAG_ABILITY_POP_UP);
DestroyTask(taskId); DestroyTask(taskId);
} }
} }
#undef sState
#undef sAutoDestroy
#undef sTimer
#undef sIsPlayerSide
#undef sBattlerId
#undef sIsMain
// last used ball // last used ball
#define LAST_BALL_WINDOW_TAG 0xD721
static const struct OamData sOamData_LastUsedBall = static const struct OamData sOamData_LastUsedBall =
{ {
@@ -2891,8 +2822,8 @@ static const struct OamData sOamData_LastUsedBall =
static const struct SpriteTemplate sSpriteTemplate_LastUsedBallWindow = static const struct SpriteTemplate sSpriteTemplate_LastUsedBallWindow =
{ {
.tileTag = LAST_BALL_WINDOW_TAG, .tileTag = TAG_LAST_BALL_WINDOW,
.paletteTag = ABILITY_POP_UP_TAG, .paletteTag = TAG_ABILITY_POP_UP,
.oam = &sOamData_LastUsedBall, .oam = &sOamData_LastUsedBall,
.anims = gDummySpriteAnimTable, .anims = gDummySpriteAnimTable,
.images = NULL, .images = NULL,
@@ -2922,7 +2853,7 @@ static const struct OamData sOamData_MoveInfoWindow =
static const struct SpriteTemplate sSpriteTemplate_MoveInfoWindow = static const struct SpriteTemplate sSpriteTemplate_MoveInfoWindow =
{ {
.tileTag = MOVE_INFO_WINDOW_TAG, .tileTag = MOVE_INFO_WINDOW_TAG,
.paletteTag = ABILITY_POP_UP_TAG, .paletteTag = TAG_ABILITY_POP_UP,
.oam = &sOamData_MoveInfoWindow, .oam = &sOamData_MoveInfoWindow,
.anims = gDummySpriteAnimTable, .anims = gDummySpriteAnimTable,
.images = NULL, .images = NULL,
@@ -2941,7 +2872,7 @@ static const struct SpriteTemplate sSpriteTemplate_MoveInfoWindow =
#endif #endif
static const struct SpriteSheet sSpriteSheet_LastUsedBallWindow = 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 #if B_MOVE_DESCRIPTION_BUTTON == R_BUTTON
@@ -3020,7 +2951,7 @@ void TryAddLastUsedBallItemSprites(void)
// window // window
LoadSpritePalette(&sSpritePalette_AbilityPopUp); LoadSpritePalette(&sSpritePalette_AbilityPopUp);
if (GetSpriteTileStartByTag(LAST_BALL_WINDOW_TAG) == 0xFFFF) if (GetSpriteTileStartByTag(TAG_LAST_BALL_WINDOW) == 0xFFFF)
LoadSpriteSheet(&sSpriteSheet_LastUsedBallWindow); LoadSpriteSheet(&sSpriteSheet_LastUsedBallWindow);
if (gBattleStruct->ballSpriteIds[1] == MAX_SPRITES) if (gBattleStruct->ballSpriteIds[1] == MAX_SPRITES)
@@ -3038,8 +2969,8 @@ void TryAddLastUsedBallItemSprites(void)
static void DestroyLastUsedBallWinGfx(struct Sprite *sprite) static void DestroyLastUsedBallWinGfx(struct Sprite *sprite)
{ {
FreeSpriteTilesByTag(LAST_BALL_WINDOW_TAG); FreeSpriteTilesByTag(TAG_LAST_BALL_WINDOW);
FreeSpritePaletteByTag(ABILITY_POP_UP_TAG); FreeSpritePaletteByTag(TAG_ABILITY_POP_UP);
DestroySprite(sprite); DestroySprite(sprite);
gBattleStruct->ballSpriteIds[1] = MAX_SPRITES; gBattleStruct->ballSpriteIds[1] = MAX_SPRITES;
} }
@@ -3076,7 +3007,7 @@ void TryToHideMoveInfoWindow(void)
static void DestroyMoveInfoWinGfx(struct Sprite *sprite) static void DestroyMoveInfoWinGfx(struct Sprite *sprite)
{ {
FreeSpriteTilesByTag(MOVE_INFO_WINDOW_TAG); FreeSpriteTilesByTag(MOVE_INFO_WINDOW_TAG);
FreeSpritePaletteByTag(ABILITY_POP_UP_TAG); FreeSpritePaletteByTag(TAG_ABILITY_POP_UP);
DestroySprite(sprite); DestroySprite(sprite);
gBattleStruct->moveInfoSpriteId = MAX_SPRITES; gBattleStruct->moveInfoSpriteId = MAX_SPRITES;
} }

View File

@@ -10795,7 +10795,10 @@ static void Cmd_various(void)
case VARIOUS_DESTROY_ABILITY_POPUP: case VARIOUS_DESTROY_ABILITY_POPUP:
{ {
VARIOUS_ARGS(); VARIOUS_ARGS();
DestroyAbilityPopUp(battler); for (u32 i = 0; i < gBattlersCount; i++)
{
DestroyAbilityPopUp(i);
}
break; break;
} }
case VARIOUS_TOTEM_BOOST: case VARIOUS_TOTEM_BOOST:

View File

@@ -85,7 +85,6 @@ static void ApplyAffineAnimFrameRelativeAndUpdateMatrix(u8 matrixNum, struct Aff
static s16 ConvertScaleParam(s16 scale); static s16 ConvertScaleParam(s16 scale);
static void GetAffineAnimFrame(u8 matrixNum, struct Sprite *sprite, struct AffineAnimFrameCmd *frameCmd); static void GetAffineAnimFrame(u8 matrixNum, struct Sprite *sprite, struct AffineAnimFrameCmd *frameCmd);
static void ApplyAffineAnimFrame(u8 matrixNum, 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 AllocSpriteTileRange(u16 tag, u16 start, u16 count);
static void DoLoadSpritePalette(const u16 *src, u16 paletteOffset); static void DoLoadSpritePalette(const u16 *src, u16 paletteOffset);
static void UpdateSpriteMatrixAnchorPos(struct Sprite *, s32, s32); static void UpdateSpriteMatrixAnchorPos(struct Sprite *, s32, s32);