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

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
$(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 \

View File

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

View File

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

View File

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

View File

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