1562 lines
44 KiB
C
1562 lines
44 KiB
C
#include "global.h"
|
|
#include "gflib.h"
|
|
#include "data.h"
|
|
#include "decompress.h"
|
|
#include "dynamic_placeholder_text_util.h"
|
|
#include "item.h"
|
|
#include "item_menu_icons.h"
|
|
#include "menu.h"
|
|
#include "new_menu_helpers.h"
|
|
#include "pokemon_special_anim_internal.h"
|
|
#include "random.h"
|
|
#include "strings.h"
|
|
#include "text_window.h"
|
|
#include "trig.h"
|
|
#include "constants/songs.h"
|
|
|
|
static void LoadBgGfxByAnimType(u16 animType);
|
|
static void Task_ZoomAnim(u8 taskId);
|
|
static void SetSpriteWithCloseness(struct Sprite *sprite, u8 closeness);
|
|
static bool8 IsZoomSpriteCBActive(struct Sprite *sprite);
|
|
static void MonSpriteZoom_UpdateYPos(struct Sprite *sprite, u8 closeness);
|
|
static void ItemSpriteZoom_UpdateYPos(struct Sprite *sprite, u8 closeness);
|
|
static void StartMonWiggleAnim(struct PokemonSpecialAnimScene * scene, u8 frameLen, u8 niter, u8 amplitude);
|
|
static void StopMonWiggleAnim(struct PokemonSpecialAnimScene * scene);
|
|
static void SpriteCallback_MonSpriteWiggle(struct Sprite *sprite);
|
|
static void LoadMonSpriteGraphics(u16 *tilees, u16 *palette);
|
|
static struct Sprite *PSA_CreateItemIconObject(u16 itemId);
|
|
static u16 GetBlendColorByItemId(u16 itemId);
|
|
static void Task_ItemUseOnMonAnim(u8 taskId);
|
|
static void CreateSprites_UseItem_OutwardSpiralDots(u8 taskId, s16 *data, struct Sprite *sprite);
|
|
static void SpriteCB_OutwardSpiralDots(struct Sprite *sprite);
|
|
static void InitItemIconSpriteState(struct PokemonSpecialAnimScene * scene, struct Sprite *sprite, u8 closeness);
|
|
static void MachineSetWobbleInit(void);
|
|
static void MachineSetWobble_SetCB(struct Sprite *sprite);
|
|
static bool8 MachineSetWobbleCBIsRunning(void);
|
|
static void SpriteCB_MachineSetWobble(struct Sprite *sprite);
|
|
static void StartZoomOutAnimForUseTM(u8 closeness);
|
|
static void CreateStarSprites(struct PokemonSpecialAnimScene * scene);
|
|
static bool8 AnyStarSpritesActive(void);
|
|
static void SpriteCB_Star(struct Sprite *sprite);
|
|
static void PSAScene_SeedRandomInTask(struct PokemonSpecialAnimScene * scene);
|
|
static void StopMakingOutwardSpiralDots(void);
|
|
static void Task_UseItem_OutwardSpiralDots(u8 taskId);
|
|
static u16 PSAScene_RandomFromTask(u8 taskId);
|
|
static void SpriteCallback_UseItem_OutwardSpiralDots(struct Sprite *sprite);
|
|
static void LoadOutwardSpiralDotsGfx(void);
|
|
static bool32 IsOutwardSpiralDotsTaskRunning(void);
|
|
static void Task_LevelUpVerticalSprites(u8 taskId);
|
|
static void CreateLevelUpVerticalSprite(u8 taskId, s16 *data);
|
|
static void SpriteCB_LevelUpVertical(struct Sprite *sprite);
|
|
|
|
static const u16 sBg_Pal[] = INCBIN_U16("graphics/pokemon_special_anim/bg.gbapal");
|
|
static const u16 sBg_TmHm_Pal[] = INCBIN_U16("graphics/pokemon_special_anim/bg_tm_hm.gbapal");
|
|
static const u32 sBg_Gfx[] = INCBIN_U32("graphics/pokemon_special_anim/bg.4bpp.lz");
|
|
static const u32 sBg_Tilemap[] = INCBIN_U32("graphics/pokemon_special_anim/bg.bin.lz");
|
|
static const u16 sLevelUp_Pal[] = INCBIN_U16("graphics/pokemon_special_anim/level_up.gbapal");
|
|
static const u32 sLevelUp_Gfx[] = INCBIN_U32("graphics/pokemon_special_anim/level_up.4bpp.lz");
|
|
static const u16 sStar_Pal[] = INCBIN_U16("graphics/pokemon_special_anim/star.gbapal");
|
|
static const u32 sStar_Gfx[] = INCBIN_U32("graphics/pokemon_special_anim/star.4bpp.lz");
|
|
static const u16 sOutwardSpiralDots_Pal[] = INCBIN_U16("graphics/pokemon_special_anim/outward_spiral_dots.gbapal");
|
|
static const u32 sOutwardSpiralDots_Gfx[] = INCBIN_U32("graphics/pokemon_special_anim/outward_spiral_dots.4bpp.lz");
|
|
|
|
static const struct BgTemplate sBgTemplates[] = {
|
|
{
|
|
.bg = 0,
|
|
.charBaseIndex = 0,
|
|
.mapBaseIndex = 31,
|
|
.screenSize = 0,
|
|
.paletteMode = 0,
|
|
.priority = 0,
|
|
.baseTile = 0x001
|
|
}, {
|
|
.bg = 3,
|
|
.charBaseIndex = 3,
|
|
.mapBaseIndex = 28,
|
|
.screenSize = 0,
|
|
.paletteMode = 0,
|
|
.priority = 3,
|
|
.baseTile = 0x000
|
|
}
|
|
};
|
|
|
|
static const struct WindowTemplate sWindowTemplates[] = {
|
|
{
|
|
.bg = 0,
|
|
.tilemapLeft = 1,
|
|
.tilemapTop = 15,
|
|
.width = 28,
|
|
.height = 4,
|
|
.paletteNum = 15,
|
|
.baseBlock = 0x00a
|
|
}, DUMMY_WIN_TEMPLATE
|
|
};
|
|
|
|
static const u8 *const s1_2_and_Poof_textPtrs[] = {
|
|
gText_Counting_1,
|
|
gText_Counting_2And,
|
|
gText_Poof,
|
|
};
|
|
|
|
static const u16 sUnusedArray[] = {
|
|
0, 16, 68
|
|
};
|
|
|
|
static const u16 sAffineScales[] = {
|
|
0x100,
|
|
0x155,
|
|
0x1AA,
|
|
0x200
|
|
};
|
|
|
|
static const s8 sStarCoordOffsets[][2] = {
|
|
{-8, -8},
|
|
{ 6, -13},
|
|
{ 8, -8}
|
|
};
|
|
|
|
static const struct CompressedSpriteSheet sSpriteSheet_Star = {
|
|
sStar_Gfx,
|
|
0x80,
|
|
2
|
|
};
|
|
|
|
static const struct SpritePalette sSpritePalette_Star = {
|
|
sStar_Pal,
|
|
2
|
|
};
|
|
|
|
static const struct CompressedSpriteSheet sSpriteSheet_UseItem_OutwardSpiralDots = {
|
|
sOutwardSpiralDots_Gfx,
|
|
0x60,
|
|
5
|
|
};
|
|
|
|
static const struct SpritePalette sSpritePalette_UseItem_OutwardSpiralDots = {
|
|
sOutwardSpiralDots_Pal,
|
|
5
|
|
};
|
|
|
|
static const struct OamData sOamData_MonSprite = {
|
|
.y = 0,
|
|
.affineMode = ST_OAM_AFFINE_DOUBLE,
|
|
.objMode = ST_OAM_OBJ_NORMAL,
|
|
.mosaic = FALSE,
|
|
.bpp = ST_OAM_4BPP,
|
|
.shape = SPRITE_SHAPE(64x64),
|
|
.x = 0,
|
|
.matrixNum = 0,
|
|
.size = SPRITE_SIZE(64x64),
|
|
.tileNum = 0x000,
|
|
.priority = 1,
|
|
.paletteNum = 0
|
|
};
|
|
|
|
|
|
static const union AffineAnimCmd sAffineAnim_Zoom_0[] = {
|
|
AFFINEANIMCMD_FRAME(0x100, 0x100, 0, 0),
|
|
AFFINEANIMCMD_END
|
|
};
|
|
|
|
static const union AffineAnimCmd sAffineAnim_Zoom_1[] = {
|
|
AFFINEANIMCMD_FRAME(0x155, 0x155, 0, 0),
|
|
AFFINEANIMCMD_END
|
|
};
|
|
|
|
static const union AffineAnimCmd sAffineAnim_Zoom_2[] = {
|
|
AFFINEANIMCMD_FRAME(0x1AA, 0x1AA, 0, 0),
|
|
AFFINEANIMCMD_END
|
|
};
|
|
|
|
static const union AffineAnimCmd sAffineAnim_Zoom_3[] = {
|
|
AFFINEANIMCMD_FRAME(0x200, 0x200, 0, 0),
|
|
AFFINEANIMCMD_END
|
|
};
|
|
|
|
static const union AffineAnimCmd *const sAffineAnimTable_Zoom[] = {
|
|
sAffineAnim_Zoom_0,
|
|
sAffineAnim_Zoom_1,
|
|
sAffineAnim_Zoom_2,
|
|
sAffineAnim_Zoom_3
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_MonSprite = {
|
|
.tileTag = 0,
|
|
.paletteTag = 0,
|
|
.oam = &sOamData_MonSprite,
|
|
.anims = gDummySpriteAnimTable,
|
|
.images = NULL,
|
|
.affineAnims = sAffineAnimTable_Zoom,
|
|
.callback = SpriteCallbackDummy
|
|
};
|
|
|
|
static const union AffineAnimCmd sAffineAnim_ItemZoom_0[] = {
|
|
AFFINEANIMCMD_FRAME(0x100, 0x100, 0, 0),
|
|
AFFINEANIMCMD_FRAME(-28, -28, 0, 8),
|
|
AFFINEANIMCMD_END
|
|
};
|
|
|
|
static const union AffineAnimCmd sAffineAnim_ItemZoom_1[] = {
|
|
AFFINEANIMCMD_FRAME(0x155, 0x155, 0, 0),
|
|
AFFINEANIMCMD_FRAME(-37, -37, 0, 8),
|
|
AFFINEANIMCMD_END
|
|
};
|
|
|
|
static const union AffineAnimCmd sAffineAnim_ItemZoom_2[] = {
|
|
AFFINEANIMCMD_FRAME(0x1AA, 0x1AA, 0, 0),
|
|
AFFINEANIMCMD_FRAME(-47, -47, 0, 8),
|
|
AFFINEANIMCMD_END
|
|
};
|
|
|
|
static const union AffineAnimCmd sAffineAnim_ItemZoom_3[] = {
|
|
AFFINEANIMCMD_FRAME(0x200, 0x200, 0, 0),
|
|
AFFINEANIMCMD_FRAME(-56, -56, 0, 8),
|
|
AFFINEANIMCMD_END
|
|
};
|
|
|
|
static const union AffineAnimCmd *const sAffineAnimTable_ItemZoom[] = {
|
|
sAffineAnim_ItemZoom_0,
|
|
sAffineAnim_ItemZoom_1,
|
|
sAffineAnim_ItemZoom_2,
|
|
sAffineAnim_ItemZoom_3
|
|
};
|
|
|
|
static const struct OamData sOamData_LevelUpVertical = {
|
|
.y = 0,
|
|
.affineMode = ST_OAM_AFFINE_OFF,
|
|
.objMode = ST_OAM_OBJ_BLEND,
|
|
.mosaic = FALSE,
|
|
.bpp = ST_OAM_4BPP,
|
|
.shape = SPRITE_SHAPE(8x16),
|
|
.x = 0,
|
|
.matrixNum = 0,
|
|
.size = SPRITE_SIZE(8x16),
|
|
.tileNum = 0x000,
|
|
.priority = 1,
|
|
.paletteNum = 0
|
|
};
|
|
|
|
static const union AnimCmd sAnim_LevelUpVertical[] = {
|
|
ANIMCMD_FRAME(0, 3),
|
|
ANIMCMD_END
|
|
};
|
|
|
|
static const union AnimCmd *const sAnimTable_LevelUpVertical[] = {
|
|
sAnim_LevelUpVertical
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_LevelUpVertical = {
|
|
.tileTag = 0,
|
|
.paletteTag = 0,
|
|
.oam = &sOamData_LevelUpVertical,
|
|
.anims = sAnimTable_LevelUpVertical,
|
|
.images = NULL,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCB_LevelUpVertical
|
|
};
|
|
|
|
static const struct OamData sOamData_Star = {
|
|
.y = 0,
|
|
.affineMode = ST_OAM_AFFINE_OFF,
|
|
.objMode = ST_OAM_OBJ_NORMAL,
|
|
.mosaic = FALSE,
|
|
.bpp = ST_OAM_4BPP,
|
|
.shape = SPRITE_SHAPE(16x16),
|
|
.x = 0,
|
|
.matrixNum = 0,
|
|
.size = SPRITE_SIZE(16x16),
|
|
.tileNum = 0x000,
|
|
.priority = 1,
|
|
.paletteNum = 0
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_Star = {
|
|
.tileTag = 2,
|
|
.paletteTag = 2,
|
|
.oam = &sOamData_Star,
|
|
.anims = gDummySpriteAnimTable,
|
|
.images = NULL,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCB_Star
|
|
};
|
|
|
|
static const struct OamData sOamData_UseItem_OutwardSpiralDots = {
|
|
.y = 0,
|
|
.affineMode = ST_OAM_AFFINE_OFF,
|
|
.objMode = ST_OAM_OBJ_NORMAL,
|
|
.mosaic = FALSE,
|
|
.bpp = ST_OAM_4BPP,
|
|
.shape = SPRITE_SHAPE(8x8),
|
|
.x = 0,
|
|
.matrixNum = 0,
|
|
.size = SPRITE_SIZE(8x8),
|
|
.tileNum = 0x000,
|
|
.priority = 0,
|
|
.paletteNum = 0
|
|
};
|
|
|
|
static const union AnimCmd sAnim_UseItem_OutwardSpiralDots_0[] = {
|
|
ANIMCMD_FRAME(0, 16),
|
|
ANIMCMD_FRAME(1, 8),
|
|
ANIMCMD_FRAME(2, 4),
|
|
ANIMCMD_END
|
|
};
|
|
|
|
static const union AnimCmd sAnim_UseItem_OutwardSpiralDots_1[] = {
|
|
ANIMCMD_FRAME(1, 4),
|
|
ANIMCMD_FRAME(0, 4),
|
|
ANIMCMD_END
|
|
};
|
|
|
|
static const union AnimCmd *const sAnimTable_UseItem_OutwardSpiralDots[] = {
|
|
sAnim_UseItem_OutwardSpiralDots_0,
|
|
sAnim_UseItem_OutwardSpiralDots_1
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_UseItem_OutwardSpiralDots = {
|
|
.tileTag = 5,
|
|
.paletteTag = 5,
|
|
.oam = &sOamData_UseItem_OutwardSpiralDots,
|
|
.anims = sAnimTable_UseItem_OutwardSpiralDots,
|
|
.images = NULL,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCallback_UseItem_OutwardSpiralDots
|
|
};
|
|
|
|
void InitPokemonSpecialAnimScene(struct PokemonSpecialAnimScene * buffer, u16 animType)
|
|
{
|
|
FreeAllWindowBuffers();
|
|
ResetTempTileDataBuffers();
|
|
SetGpuReg(REG_OFFSET_DISPCNT, 0);
|
|
ResetBgsAndClearDma3BusyFlags(FALSE);
|
|
InitBgsFromTemplates(0, sBgTemplates, NELEMS(sBgTemplates));
|
|
InitWindows(sWindowTemplates);
|
|
ChangeBgX(0, 0, 0);
|
|
ChangeBgY(0, 0, 0);
|
|
ChangeBgX(3, 0, 0);
|
|
ChangeBgY(3, 0, 0);
|
|
SetBgTilemapBuffer(0, buffer->field_0914);
|
|
SetBgTilemapBuffer(3, buffer->field_1914);
|
|
RequestDma3Fill(0, (void *)BG_VRAM, 0x20, DMA3_32BIT);
|
|
FillBgTilemapBufferRect_Palette0(0, 0x000, 0, 0, 32, 32);
|
|
LoadBgGfxByAnimType(animType);
|
|
FillWindowPixelBuffer(0, PIXEL_FILL(0));
|
|
LoadUserWindowGfx(0, 0x000, BG_PLTT_ID(14));
|
|
CopyWindowToVram(0, COPYWIN_FULL);
|
|
ShowBg(0);
|
|
ShowBg(3);
|
|
HideBg(1);
|
|
HideBg(2);
|
|
CopyBgTilemapBufferToVram(0);
|
|
CopyBgTilemapBufferToVram(3);
|
|
SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_MODE_0 | DISPCNT_OBJ_1D_MAP | DISPCNT_OBJ_ON);
|
|
SetGpuReg(REG_OFFSET_BLDCNT, 0);
|
|
}
|
|
|
|
bool8 PokemonSpecialAnimSceneInitIsNotFinished(void)
|
|
{
|
|
if (!FreeTempTileDataBuffersIfPossible())
|
|
return IsDma3ManagerBusyWithBgCopy();
|
|
else
|
|
return TRUE;
|
|
}
|
|
|
|
void PSA_FreeWindowBuffers(void)
|
|
{
|
|
FreeAllWindowBuffers();
|
|
}
|
|
|
|
void PSA_ShowMessageWindow(void)
|
|
{
|
|
PutWindowTilemap(0);
|
|
FillWindowPixelBuffer(0, PIXEL_FILL(1));
|
|
DrawTextBorderOuter(0, 0x001, 14);
|
|
CopyWindowToVram(0, COPYWIN_FULL);
|
|
}
|
|
|
|
void PSA_HideMessageWindow(void)
|
|
{
|
|
ClearWindowTilemap(0);
|
|
ClearStdWindowAndFrameToTransparent(0, FALSE);
|
|
CopyWindowToVram(0, COPYWIN_MAP);
|
|
}
|
|
|
|
void PSA_PrintMessage(u8 messageId)
|
|
{
|
|
struct PokemonSpecialAnimScene * scene = PSA_GetSceneWork();
|
|
u16 itemId = PSA_GetItemId();
|
|
u16 strWidth = 0;
|
|
u8 textSpeed = GetTextSpeedSetting();
|
|
struct Pokemon * pokemon = PSA_GetPokemon();
|
|
u16 level;
|
|
u8 *str;
|
|
|
|
switch (messageId)
|
|
{
|
|
case 0: // Item was used on Mon
|
|
str = StringCopy(scene->textBuf, ItemId_GetName(itemId));
|
|
str = StringCopy(str, gText_WasUsedOn);
|
|
GetMonData(pokemon, MON_DATA_NICKNAME, str);
|
|
StringAppend(scene->textBuf, gText_Period);
|
|
break;
|
|
case 1: // Mon's level was elevated to level
|
|
level = GetMonData(pokemon, MON_DATA_LEVEL);
|
|
GetMonData(pokemon, MON_DATA_NICKNAME, scene->textBuf);
|
|
str = StringAppend(scene->textBuf, gText_LevelRoseTo);
|
|
if (level < MAX_LEVEL)
|
|
level++;
|
|
str = ConvertIntToDecimalStringN(str, level, STR_CONV_MODE_LEFT_ALIGN, level < MAX_LEVEL ? 2 : 3);
|
|
StringAppend(str, gText_Period2);
|
|
break;
|
|
case 9: // Mon learned move
|
|
DynamicPlaceholderTextUtil_Reset();
|
|
DynamicPlaceholderTextUtil_SetPlaceholderPtr(0, PSA_GetMonNickname());
|
|
DynamicPlaceholderTextUtil_SetPlaceholderPtr(1, PSA_GetNameOfMoveToTeach());
|
|
DynamicPlaceholderTextUtil_ExpandPlaceholders(scene->textBuf, gText_MonLearnedTMHM);
|
|
break;
|
|
case 4:
|
|
strWidth += GetStringWidth(FONT_NORMAL, gText_Counting_2And, -1);
|
|
// fallthrough
|
|
case 3:
|
|
strWidth += GetStringWidth(FONT_NORMAL, gText_Counting_1, -1);
|
|
// fallthrough
|
|
case 2: // 1
|
|
StringCopy(scene->textBuf, s1_2_and_Poof_textPtrs[messageId - 2]);
|
|
textSpeed = 1;
|
|
break;
|
|
case 5:
|
|
DynamicPlaceholderTextUtil_Reset();
|
|
DynamicPlaceholderTextUtil_SetPlaceholderPtr(0, PSA_GetMonNickname());
|
|
DynamicPlaceholderTextUtil_SetPlaceholderPtr(1, PSA_GetNameOfMoveForgotten());
|
|
DynamicPlaceholderTextUtil_ExpandPlaceholders(scene->textBuf, gText_MonForgotMove);
|
|
break;
|
|
case 6:
|
|
StringCopy(scene->textBuf, gText_And);
|
|
break;
|
|
case 7:
|
|
StringCopy(scene->textBuf, gText_MachineSet);
|
|
break;
|
|
case 8:
|
|
StringCopy(scene->textBuf, gText_Huh);
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
AddTextPrinterParameterized5(0, FONT_NORMAL, scene->textBuf, strWidth, 0, textSpeed, NULL, 0, 4);
|
|
}
|
|
|
|
void PSA_AfterPoof_ClearMessageWindow(void)
|
|
{
|
|
FillWindowPixelBuffer(0, PIXEL_FILL(1));
|
|
CopyWindowToVram(0, COPYWIN_GFX);
|
|
}
|
|
|
|
bool8 PSA_IsMessagePrintTaskActive(void)
|
|
{
|
|
return IsTextPrinterActive(0);
|
|
}
|
|
|
|
void PSA_DarkenMonSprite(void)
|
|
{
|
|
struct PokemonSpecialAnimScene * scene = PSA_GetSceneWork();
|
|
scene->state = 0;
|
|
BlendPalettes((0x10000 << IndexOfSpritePaletteTag(0)) | 4, 16, RGB_BLACK);
|
|
CreateStarSprites(scene);
|
|
}
|
|
|
|
bool8 PSA_RunPoofAnim(void)
|
|
{
|
|
struct PokemonSpecialAnimScene * scene = PSA_GetSceneWork();
|
|
|
|
switch (scene->state)
|
|
{
|
|
case 0:
|
|
if (!AnyStarSpritesActive())
|
|
{
|
|
BeginNormalPaletteFade((0x10000 << IndexOfSpritePaletteTag(0)) | 4, -1, 16, 0, RGB_BLACK);
|
|
scene->state++;
|
|
}
|
|
break;
|
|
case 1:
|
|
if (!gPaletteFade.active)
|
|
return FALSE;
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void PSA_UseTM_SetUpZoomOutAnim(void)
|
|
{
|
|
struct PokemonSpecialAnimScene * scene = PSA_GetSceneWork();
|
|
scene->state = 0;
|
|
}
|
|
|
|
void PSA_UseTM_CleanUpForCancel(void)
|
|
{
|
|
StopMakingOutwardSpiralDots();
|
|
ResetPaletteFadeControl();
|
|
}
|
|
|
|
bool8 PSA_UseTM_RunZoomOutAnim(void)
|
|
{
|
|
struct PokemonSpecialAnimScene * scene = PSA_GetSceneWork();
|
|
switch (scene->state)
|
|
{
|
|
case 0:
|
|
StartZoomOutAnimForUseTM(0);
|
|
scene->state++;
|
|
break;
|
|
case 1:
|
|
if (!PSA_IsZoomTaskActive())
|
|
{
|
|
scene->field_0004 = 0;
|
|
scene->state++;
|
|
}
|
|
break;
|
|
case 2:
|
|
scene->field_0004++;
|
|
if (scene->field_0004 > 20)
|
|
scene->state++;
|
|
break;
|
|
case 3:
|
|
StartMonWiggleAnim(scene, 1, 0, 1);
|
|
scene->field_0004 = 0;
|
|
scene->state++;
|
|
break;
|
|
case 4:
|
|
scene->field_0004++;
|
|
if (scene->field_0004 > 0)
|
|
{
|
|
scene->field_0004 = 0;
|
|
PlaySE(SE_M_MEGA_KICK);
|
|
BeginNormalPaletteFade(0x00000001, 2, 0, 12, RGB(8, 13, 31));
|
|
PSAScene_SeedRandomInTask(scene);
|
|
scene->state++;
|
|
}
|
|
break;
|
|
case 5:
|
|
scene->field_0004++;
|
|
if (scene->field_0004 > 70)
|
|
{
|
|
StopMonWiggleAnim(scene);
|
|
BeginNormalPaletteFade(0x00000001, 6, 12, 0, RGB(8, 13, 31));
|
|
scene->field_0004 = 0;
|
|
scene->state++;
|
|
}
|
|
break;
|
|
case 6:
|
|
scene->field_0004++;
|
|
if (!IsOutwardSpiralDotsTaskRunning() && scene->field_0004 > 40)
|
|
{
|
|
scene->field_0004 = 0;
|
|
scene->state++;
|
|
}
|
|
break;
|
|
case 7:
|
|
scene->field_0004++;
|
|
if (scene->field_0004 > 20)
|
|
{
|
|
scene->state++;
|
|
}
|
|
break;
|
|
case 8:
|
|
PlaySE(SE_EXP_MAX);
|
|
DestroySprite(scene->itemIconSprite);
|
|
scene->state++;
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void PSA_UseTM_SetUpMachineSetWobble(void)
|
|
{
|
|
struct PokemonSpecialAnimScene * scene = PSA_GetSceneWork();
|
|
scene->state = 0;
|
|
}
|
|
|
|
bool8 PSA_UseTM_RunMachineSetWobble(void)
|
|
{
|
|
struct PokemonSpecialAnimScene * scene = PSA_GetSceneWork();
|
|
|
|
switch (scene->state)
|
|
{
|
|
case 0:
|
|
MachineSetWobbleInit();
|
|
PlaySE(SE_SWITCH);
|
|
scene->state++;
|
|
break;
|
|
case 1:
|
|
return MachineSetWobbleCBIsRunning();
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
// There may once have been plans to put the battle level up
|
|
// anim in with using Rare Candy, but they were scrapped
|
|
// at a later stage of development
|
|
|
|
// Unused
|
|
void PSA_CreateLevelUpVerticalSpritesTask(void)
|
|
{
|
|
CreateLevelUpVerticalSpritesTask(120, 56, 4, 4, 2, 0);
|
|
}
|
|
|
|
bool8 PSA_LevelUpVerticalSpritesTaskIsRunning(void)
|
|
{
|
|
return LevelUpVerticalSpritesTaskIsRunning();
|
|
}
|
|
|
|
// Unused
|
|
void PSA_DrawLevelUpWindowPg1(u16 *statsBefore, u16 *statsAfter)
|
|
{
|
|
DrawTextBorderOuter(1, 0x001, 14);
|
|
DrawLevelUpWindowPg1(1, statsBefore, statsAfter, TEXT_COLOR_WHITE, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_LIGHT_GRAY);
|
|
PutWindowTilemap(1);
|
|
CopyWindowToVram(1, COPYWIN_FULL);
|
|
}
|
|
|
|
// Unused
|
|
void PSA_DrawLevelUpWindowPg2(u16 *currStats)
|
|
{
|
|
DrawLevelUpWindowPg2(1, currStats, TEXT_COLOR_WHITE, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_LIGHT_GRAY);
|
|
CopyWindowToVram(1, COPYWIN_GFX);
|
|
}
|
|
|
|
// Unused
|
|
bool8 PSA_IsCopyingLevelUpWindowToVram(void)
|
|
{
|
|
return IsDma3ManagerBusyWithBgCopy();
|
|
}
|
|
|
|
static void LoadBgGfxByAnimType(u16 animType)
|
|
{
|
|
CopyToBgTilemapBuffer(3, sBg_Tilemap, 0, 0x000);
|
|
DecompressAndCopyTileDataToVram(3, sBg_Gfx, 0, 0x000, 0);
|
|
if (animType != 4)
|
|
LoadPalette(sBg_Pal, BG_PLTT_ID(0), sizeof(sBg_Pal));
|
|
else
|
|
LoadPalette(sBg_TmHm_Pal, BG_PLTT_ID(0), sizeof(sBg_TmHm_Pal));
|
|
}
|
|
|
|
void PSA_CreateMonSpriteAtCloseness(u8 closeness)
|
|
{
|
|
struct PokemonSpecialAnimScene * scene = PSA_GetSceneWork();
|
|
struct Pokemon * pokemon = PSA_GetPokemon();
|
|
u16 species = GetMonData(pokemon, MON_DATA_SPECIES);
|
|
u32 personality = GetMonData(pokemon, MON_DATA_PERSONALITY);
|
|
u8 r1 = Menu2_GetMonSpriteAnchorCoord(species, personality, 2);
|
|
void *r6;
|
|
void *r9;
|
|
void *r4;
|
|
u8 spriteId;
|
|
|
|
if (r1 != 0xFF)
|
|
{
|
|
scene->monSpriteY1 = 0x48;
|
|
scene->monSpriteY2 = r1 + 0x30;
|
|
}
|
|
else
|
|
{
|
|
scene->monSpriteY1 = 0x48;
|
|
scene->monSpriteY2 = 0x60;
|
|
}
|
|
|
|
r6 = Alloc(0x2000);
|
|
r9 = Alloc(0x2000);
|
|
r4 = Alloc(0x100);
|
|
if (r6 != NULL && r9 != NULL && r4 != NULL)
|
|
{
|
|
HandleLoadSpecialPokePic(&gMonFrontPicTable[species], r6, species, personality);
|
|
LZ77UnCompWram(GetMonFrontSpritePal(pokemon), r4);
|
|
LoadMonSpriteGraphics(r6, r4);
|
|
spriteId = CreateSprite(&sSpriteTemplate_MonSprite, 120, scene->monSpriteY1, 4);
|
|
if (spriteId != MAX_SPRITES)
|
|
{
|
|
scene->monSprite = &gSprites[spriteId];
|
|
MonSpriteZoom_UpdateYPos(scene->monSprite, closeness);
|
|
}
|
|
else
|
|
scene->monSprite = NULL;
|
|
scene->lastCloseness = closeness;
|
|
}
|
|
if (r6 != NULL) Free(r6);
|
|
if (r9 != NULL) Free(r9);
|
|
if (r4 != NULL) Free(r4);
|
|
}
|
|
|
|
#define tState data[0]
|
|
#define tCurrCloseness data[1]
|
|
#define tFinalCloseness data[2]
|
|
#define tDeltaCloseness data[3]
|
|
#define tTimer data[4]
|
|
#define tDelay data[5]
|
|
#define tOff_MonSprite 6
|
|
#define tHasItemSprite data[8]
|
|
#define tOff_ItemSprite 9
|
|
|
|
void PSA_SetUpZoomAnim(u8 closeness)
|
|
{
|
|
struct PokemonSpecialAnimScene * scene = PSA_GetSceneWork();
|
|
u8 taskId;
|
|
if (closeness != scene->lastCloseness)
|
|
{
|
|
taskId = CreateTask(Task_ZoomAnim, 4);
|
|
SetWordTaskArg(taskId, tOff_MonSprite, (uintptr_t)scene->monSprite);
|
|
gTasks[taskId].tCurrCloseness = scene->lastCloseness;
|
|
gTasks[taskId].tFinalCloseness = closeness;
|
|
gTasks[taskId].tDelay = 6;
|
|
if (closeness > scene->lastCloseness)
|
|
gTasks[taskId].tDeltaCloseness = 1;
|
|
else
|
|
gTasks[taskId].tDeltaCloseness = -1;
|
|
}
|
|
}
|
|
|
|
bool8 PSA_IsZoomTaskActive(void)
|
|
{
|
|
return FuncIsActiveTask(Task_ZoomAnim);
|
|
}
|
|
|
|
static void Task_ZoomAnim(u8 taskId)
|
|
{
|
|
s16 *data = gTasks[taskId].data;
|
|
struct Sprite *sprite = (void *)GetWordTaskArg(taskId, tOff_MonSprite);
|
|
switch (tState)
|
|
{
|
|
case 0:
|
|
SetSpriteWithCloseness(sprite, tCurrCloseness);
|
|
if (tHasItemSprite)
|
|
SetSpriteWithCloseness((void *)GetWordTaskArg(taskId, tOff_ItemSprite), tCurrCloseness);
|
|
tCurrCloseness += tDeltaCloseness;
|
|
tState++;
|
|
break;
|
|
case 1:
|
|
if (!IsZoomSpriteCBActive(sprite))
|
|
{
|
|
PlaySE(SE_BALL_TRAY_EXIT);
|
|
MonSpriteZoom_UpdateYPos(sprite, tCurrCloseness);
|
|
if (tHasItemSprite)
|
|
ItemSpriteZoom_UpdateYPos((void *)GetWordTaskArg(taskId, tOff_ItemSprite), tCurrCloseness);
|
|
if (tCurrCloseness == tFinalCloseness)
|
|
{
|
|
PSA_GetSceneWork()->lastCloseness = tFinalCloseness;
|
|
DestroyTask(taskId);
|
|
}
|
|
else
|
|
{
|
|
tTimer = 0;
|
|
tState = 2;
|
|
}
|
|
}
|
|
break;
|
|
case 2:
|
|
tTimer++;
|
|
if (tTimer > tDelay)
|
|
tState = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void SetSpriteWithCloseness(struct Sprite *sprite, u8 closeness)
|
|
{
|
|
sprite->data[0] = 0;
|
|
sprite->data[1] = 0;
|
|
sprite->data[2] = closeness;
|
|
}
|
|
|
|
static bool8 IsZoomSpriteCBActive(struct Sprite *sprite)
|
|
{
|
|
return sprite->callback != SpriteCallbackDummy;
|
|
}
|
|
|
|
static s16 GetSpriteOffsetByScale(s16 pos, u8 closeness)
|
|
{
|
|
return (pos * sAffineScales[closeness]) >> 8;
|
|
}
|
|
|
|
// FIXME: better math
|
|
static u16 GetYPosByScale(u16 pos)
|
|
{
|
|
struct PokemonSpecialAnimScene * scene = PSA_GetSceneWork();
|
|
s32 v = ((((((scene->monSpriteY2 - scene->monSpriteY1) << 16) >> 8) / 256 * (pos - 256)) << 8) >> 16);
|
|
return v += scene->monSpriteY1;
|
|
}
|
|
|
|
static void MonSpriteZoom_UpdateYPos(struct Sprite *sprite, u8 closeness)
|
|
{
|
|
if (closeness > 3)
|
|
closeness = 3;
|
|
PSA_GetSceneWork(); // return value not used
|
|
StartSpriteAffineAnim(sprite, closeness);
|
|
sprite->y = GetYPosByScale(sAffineScales[closeness]);
|
|
}
|
|
|
|
static void ItemSpriteZoom_UpdateYPos(struct Sprite *sprite, u8 closeness)
|
|
{
|
|
MonSpriteZoom_UpdateYPos(sprite, closeness);
|
|
sprite->x2 = GetSpriteOffsetByScale(sprite->data[6] - 32, closeness);
|
|
sprite->y2 = GetSpriteOffsetByScale(sprite->data[7] - 32, closeness);
|
|
}
|
|
|
|
static void StartMonWiggleAnim(struct PokemonSpecialAnimScene * scene, u8 frameLen, u8 niter, u8 amplitude)
|
|
{
|
|
// frameLen: frame duration
|
|
// niter = 0: iterate ad infinitum
|
|
scene->monSprite->data[0] = frameLen;
|
|
scene->monSprite->data[1] = niter;
|
|
scene->monSprite->data[2] = amplitude;
|
|
scene->monSprite->callback = SpriteCallback_MonSpriteWiggle;
|
|
}
|
|
|
|
static void StopMonWiggleAnim(struct PokemonSpecialAnimScene * scene)
|
|
{
|
|
scene->monSprite->x2 = 0;
|
|
scene->monSprite->callback = SpriteCallbackDummy;
|
|
}
|
|
|
|
static void SpriteCallback_MonSpriteWiggle(struct Sprite *sprite)
|
|
{
|
|
sprite->data[7]++;
|
|
if (sprite->data[7] > sprite->data[0])
|
|
{
|
|
sprite->data[7] = 0;
|
|
sprite->data[6]++;
|
|
if (sprite->data[1] != 0 && sprite->data[6] >= sprite->data[1])
|
|
{
|
|
sprite->x2 = 0;
|
|
sprite->callback = SpriteCallbackDummy;
|
|
}
|
|
else if (sprite->data[6] & 1)
|
|
sprite->x2 = sprite->data[2];
|
|
else
|
|
sprite->x2 = -sprite->data[2];
|
|
}
|
|
}
|
|
|
|
static void LoadMonSpriteGraphics(u16 *tiles, u16 *palette)
|
|
{
|
|
struct SpriteSheet spriteSheet;
|
|
struct SpritePalette spritePalette;
|
|
|
|
spriteSheet.data = tiles;
|
|
spriteSheet.size = 0x800;
|
|
spriteSheet.tag = 0;
|
|
spritePalette.data = palette;
|
|
spritePalette.tag = 0;
|
|
LoadSpriteSheet(&spriteSheet);
|
|
LoadSpritePalette(&spritePalette);
|
|
}
|
|
|
|
#undef tOff_ItemSprite
|
|
#undef tHasItemSprite
|
|
#undef tOff_MonSprite
|
|
#undef tDelay
|
|
#undef tTimer
|
|
#undef tDeltaCloseness
|
|
#undef tFinalCloseness
|
|
#undef tCurrCloseness
|
|
#undef tState
|
|
|
|
#define tState data[0]
|
|
#define tTimer data[1]
|
|
#define tCloseness data[2]
|
|
#define tYpos data[3]
|
|
#define tOff_ItemSprite 4
|
|
#define tData6 data[6]
|
|
#define tData7 data[7]
|
|
#define tActiveSprCt data[8]
|
|
#define tBlendColor data[9]
|
|
#define tTimerReset data[10]
|
|
#define tSuppressDots data[11]
|
|
|
|
void PSA_SetUpItemUseOnMonAnim(u16 itemId, u8 closeness, bool32 a2)
|
|
{
|
|
struct PokemonSpecialAnimScene * scene = PSA_GetSceneWork();
|
|
u8 taskId;
|
|
scene->itemIconSprite = PSA_CreateItemIconObject(itemId);
|
|
if (scene->itemIconSprite != NULL)
|
|
{
|
|
InitItemIconSpriteState(scene, scene->itemIconSprite, closeness);
|
|
StartSpriteAffineAnim(scene->itemIconSprite, closeness);
|
|
scene->itemIconSprite->invisible = TRUE;
|
|
taskId = CreateTask(Task_ItemUseOnMonAnim, 2);
|
|
SetWordTaskArg(taskId, tOff_ItemSprite, (uintptr_t)scene->itemIconSprite);
|
|
gTasks[taskId].tCloseness = closeness;
|
|
gTasks[taskId].tYpos = GetYPosByScale(sAffineScales[closeness]);
|
|
gTasks[taskId].tData6 = a2;
|
|
gTasks[taskId].tBlendColor = GetBlendColorByItemId(itemId);
|
|
}
|
|
}
|
|
|
|
static u16 GetBlendColorByItemId(u16 itemId)
|
|
{
|
|
return RGB_WHITE;
|
|
}
|
|
|
|
void CreateItemIconSpriteAtMaxCloseness(u16 itemId)
|
|
{
|
|
struct PokemonSpecialAnimScene * scene = PSA_GetSceneWork();
|
|
scene->itemIconSprite = PSA_CreateItemIconObject(itemId);
|
|
if (scene->itemIconSprite != NULL)
|
|
{
|
|
StartSpriteAffineAnim(scene->itemIconSprite, 3);
|
|
InitItemIconSpriteState(scene, scene->itemIconSprite, 3);
|
|
}
|
|
}
|
|
|
|
static struct Sprite *PSA_CreateItemIconObject(u16 itemId)
|
|
{
|
|
u8 spriteId;
|
|
struct Sprite *sprite;
|
|
spriteId = AddItemIconObject(1, 1, itemId);
|
|
if (spriteId == MAX_SPRITES)
|
|
return NULL;
|
|
gSprites[spriteId].oam.affineMode = ST_OAM_AFFINE_DOUBLE;
|
|
gSprites[spriteId].oam.priority = 1;
|
|
gSprites[spriteId].subpriority = 1;
|
|
gSprites[spriteId].affineAnims = sAffineAnimTable_Zoom;
|
|
gSprites[spriteId].callback = SpriteCallbackDummy;
|
|
InitSpriteAffineAnim(&gSprites[spriteId]);
|
|
return &gSprites[spriteId];
|
|
}
|
|
|
|
bool8 PSA_IsItemUseOnMonAnimActive(void)
|
|
{
|
|
return FuncIsActiveTask(Task_ItemUseOnMonAnim);
|
|
}
|
|
|
|
static void Task_ItemUseOnMonAnim(u8 taskId)
|
|
{
|
|
s16 *data = gTasks[taskId].data;
|
|
struct Sprite *sprite = (void *)GetWordTaskArg(taskId, tOff_ItemSprite);
|
|
switch (tState)
|
|
{
|
|
case 0:
|
|
tTimer++;
|
|
if (tTimer > 20)
|
|
{
|
|
tTimer = 0;
|
|
PlaySE(SE_M_SWAGGER2);
|
|
sprite->invisible = FALSE;
|
|
if (!tSuppressDots)
|
|
LoadOutwardSpiralDotsGfx();
|
|
tState = 1;
|
|
}
|
|
break;
|
|
case 1:
|
|
tTimer++;
|
|
if (tTimer > 30)
|
|
{
|
|
tTimer = 0;
|
|
sprite->affineAnims = sAffineAnimTable_ItemZoom;
|
|
StartSpriteAffineAnim(sprite, tCloseness);
|
|
BeginNormalPaletteFade(0x10000 << IndexOfSpritePaletteTag(1), -2, 0, 12, tBlendColor);
|
|
tState = 2;
|
|
PlaySE(SE_M_MILK_DRINK);
|
|
}
|
|
break;
|
|
case 2:
|
|
if (sprite->affineAnimEnded)
|
|
{
|
|
sprite->invisible = TRUE;
|
|
tTimerReset = 20;
|
|
tState = 3;
|
|
}
|
|
break;
|
|
case 3:
|
|
tTimer++;
|
|
if (tTimer > tTimerReset)
|
|
{
|
|
tTimer = 0;
|
|
if (!tSuppressDots)
|
|
CreateSprites_UseItem_OutwardSpiralDots(taskId, data, sprite);
|
|
if (tData7 == 0)
|
|
PlaySE(SE_M_REVERSAL);
|
|
tData7++;
|
|
if (tData7 > 2)
|
|
tState = 4;
|
|
else
|
|
tTimerReset = 8;
|
|
}
|
|
break;
|
|
case 4:
|
|
if (tActiveSprCt == 0)
|
|
{
|
|
if (tData6)
|
|
DestroySprite(sprite);
|
|
DestroyTask(taskId);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void CreateSprites_UseItem_OutwardSpiralDots(u8 taskId, s16 *data, struct Sprite *sprite)
|
|
{
|
|
int x = sprite->x + sprite->x2 - 4;
|
|
int y = sprite->y + sprite->y2 - 4;
|
|
u8 spriteId;
|
|
int i;
|
|
BlendPalettes(0x10000 << IndexOfSpritePaletteTag(5), 16, tBlendColor);
|
|
for (i = 0; i < 15; i++)
|
|
{
|
|
spriteId = CreateSprite(&sSpriteTemplate_UseItem_OutwardSpiralDots, x, y, 0);
|
|
if (spriteId != MAX_SPRITES)
|
|
{
|
|
gSprites[spriteId].data[1] = i << 4;
|
|
gSprites[spriteId].data[7] = taskId;
|
|
gSprites[spriteId].callback = SpriteCB_OutwardSpiralDots;
|
|
StartSpriteAnim(&gSprites[spriteId], 1);
|
|
tActiveSprCt++;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void SpriteCB_OutwardSpiralDots(struct Sprite *sprite)
|
|
{
|
|
s16 *data = sprite->data;
|
|
if (data[0] < 16)
|
|
{
|
|
data[0]++;
|
|
data[1] += 7;
|
|
data[1] &= 0xFF;
|
|
data[2] += 4;
|
|
sprite->x2 = (data[2] * gSineTable[data[1] + 0x40]) >> 8;
|
|
sprite->y2 = (data[2] * gSineTable[data[1]]) >> 8;
|
|
}
|
|
else
|
|
{
|
|
gTasks[data[7]].tActiveSprCt--;
|
|
DestroySprite(sprite);
|
|
}
|
|
}
|
|
|
|
void PSA_UseItem_CleanUpForCancel(void)
|
|
{
|
|
u8 taskId = FindTaskIdByFunc(Task_ItemUseOnMonAnim);
|
|
if (taskId != 0xFF)
|
|
{
|
|
gTasks[taskId].tSuppressDots = TRUE;
|
|
}
|
|
}
|
|
|
|
static void InitItemIconSpriteState(struct PokemonSpecialAnimScene * scene, struct Sprite *sprite, u8 closeness)
|
|
{
|
|
u16 species, x, y;
|
|
u32 personality;
|
|
if (closeness == 3)
|
|
{
|
|
sprite->x = 120;
|
|
sprite->y = scene->monSpriteY2;
|
|
}
|
|
else
|
|
{
|
|
sprite->x = 120;
|
|
sprite->y = scene->monSpriteY1;
|
|
}
|
|
sprite->x += 4;
|
|
sprite->y += 4;
|
|
species = PSA_GetMonSpecies();
|
|
personality = PSA_GetMonPersonality();
|
|
switch (PSA_GetAnimType())
|
|
{
|
|
case 4:
|
|
{
|
|
x = Menu2_GetMonSpriteAnchorCoord(species, personality, 0);
|
|
y = Menu2_GetMonSpriteAnchorCoord(species, personality, 1);
|
|
if (x == 0xFF)
|
|
x = 0;
|
|
if (y == 0xFF)
|
|
y = 0;
|
|
sprite->data[6] = x;
|
|
sprite->data[7] = y;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
x = Menu2_GetMonSpriteAnchorCoord(species, personality, 3);
|
|
y = Menu2_GetMonSpriteAnchorCoord(species, personality, 4);
|
|
if (x == 0xFF)
|
|
x = 0;
|
|
if (y == 0xFF)
|
|
y = 0;
|
|
sprite->data[6] = x;
|
|
sprite->data[7] = y;
|
|
break;
|
|
}
|
|
}
|
|
ItemSpriteZoom_UpdateYPos(sprite, closeness);
|
|
}
|
|
|
|
#undef tSuppressDots
|
|
#undef tTimerReset
|
|
#undef tBlendColor
|
|
#undef tActiveSprCt
|
|
#undef tData7
|
|
#undef tData6
|
|
#undef tOff_ItemSprite
|
|
#undef tYpos
|
|
#undef tCloseness
|
|
#undef tTimer
|
|
#undef tState
|
|
|
|
static void MachineSetWobbleInit(void)
|
|
{
|
|
struct PokemonSpecialAnimScene * scene = PSA_GetSceneWork();
|
|
MachineSetWobble_SetCB(scene->monSprite);
|
|
MachineSetWobble_SetCB(scene->itemIconSprite);
|
|
}
|
|
|
|
static void MachineSetWobble_SetCB(struct Sprite *sprite)
|
|
{
|
|
sprite->data[0] = 0;
|
|
sprite->data[1] = 0;
|
|
sprite->callback = SpriteCB_MachineSetWobble;
|
|
}
|
|
|
|
static bool8 MachineSetWobbleCBIsRunning(void)
|
|
{
|
|
struct PokemonSpecialAnimScene * scene = PSA_GetSceneWork();
|
|
return scene->monSprite->callback != SpriteCallbackDummy;
|
|
}
|
|
|
|
static void SpriteCB_MachineSetWobble(struct Sprite *sprite)
|
|
{
|
|
switch (sprite->data[0])
|
|
{
|
|
case 0:
|
|
sprite->x += 3;
|
|
sprite->data[0]++;
|
|
break;
|
|
case 1:
|
|
sprite->data[1]++;
|
|
if (sprite->data[1] > 30)
|
|
{
|
|
sprite->x -= 3;
|
|
sprite->callback = SpriteCallbackDummy;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Redefined from above
|
|
#define tState data[0]
|
|
#define tCurrCloseness data[1]
|
|
#define tFinalCloseness data[2]
|
|
#define tDeltaCloseness data[3]
|
|
#define tTimer data[4]
|
|
#define tDelay data[5]
|
|
#define tOff_MonSprite 6
|
|
#define tHasItemSprite data[8]
|
|
#define tOff_ItemSprite 9
|
|
|
|
static void StartZoomOutAnimForUseTM(u8 closeness)
|
|
{
|
|
struct PokemonSpecialAnimScene * scene = PSA_GetSceneWork();
|
|
u8 taskId;
|
|
if (closeness != scene->lastCloseness)
|
|
{
|
|
taskId = CreateTask(Task_ZoomAnim, 1);
|
|
SetWordTaskArg(taskId, tOff_MonSprite, (uintptr_t)scene->monSprite);
|
|
SetWordTaskArg(taskId, tOff_ItemSprite, (uintptr_t)scene->itemIconSprite);
|
|
gTasks[taskId].tCurrCloseness = scene->lastCloseness;
|
|
gTasks[taskId].tFinalCloseness = closeness;
|
|
gTasks[taskId].tHasItemSprite = 1;
|
|
gTasks[taskId].tDelay = 6;
|
|
if (closeness > scene->lastCloseness)
|
|
gTasks[taskId].tDeltaCloseness = 1;
|
|
else
|
|
gTasks[taskId].tDeltaCloseness = -1;
|
|
}
|
|
}
|
|
|
|
#undef tOff_ItemSprite
|
|
#undef tHasItemSprite
|
|
#undef tOff_MonSprite
|
|
#undef tDelay
|
|
#undef tTimer
|
|
#undef tDeltaCloseness
|
|
#undef tFinalCloseness
|
|
#undef tCurrCloseness
|
|
#undef tState
|
|
|
|
static void CreateStarSprites(struct PokemonSpecialAnimScene * scene)
|
|
{
|
|
int i;
|
|
u8 spriteId;
|
|
u16 species;
|
|
u32 personality;
|
|
LoadCompressedSpriteSheet(&sSpriteSheet_Star);
|
|
LoadSpritePalette(&sSpritePalette_Star);
|
|
scene->field_0002 = 0;
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
spriteId = CreateSprite(&sSpriteTemplate_Star, 120 + sStarCoordOffsets[i][0], scene->monSpriteY2 + sStarCoordOffsets[i][1], 2);
|
|
if (spriteId != MAX_SPRITES)
|
|
{
|
|
species = PSA_GetMonSpecies();
|
|
personality = PSA_GetMonPersonality();
|
|
gSprites[spriteId].data[3] = sStarCoordOffsets[i][0] * 8;
|
|
gSprites[spriteId].data[4] = sStarCoordOffsets[i][1] * 8;
|
|
gSprites[spriteId].x += GetSpriteOffsetByScale(Menu2_GetMonSpriteAnchorCoordMinusx20(species, personality, 0), 3);
|
|
gSprites[spriteId].y += GetSpriteOffsetByScale(Menu2_GetMonSpriteAnchorCoordMinusx20(species, personality, 1), 3);
|
|
scene->field_0002++;
|
|
}
|
|
}
|
|
}
|
|
|
|
static u8 AnyStarSpritesActive(void)
|
|
{
|
|
return PSA_GetSceneWork()->field_0002;
|
|
}
|
|
|
|
static void SpriteCB_Star(struct Sprite *sprite)
|
|
{
|
|
sprite->data[0]++;
|
|
if (sprite->data[0] < 10)
|
|
{
|
|
sprite->data[1] += sprite->data[3];
|
|
sprite->data[2] += sprite->data[4];
|
|
sprite->x2 = sprite->data[1] >> 4;
|
|
sprite->y2 = sprite->data[2] >> 4;
|
|
}
|
|
else
|
|
{
|
|
PSA_GetSceneWork()->field_0002--;
|
|
DestroySprite(sprite);
|
|
}
|
|
}
|
|
|
|
// ========================================================
|
|
|
|
#define tState data[0]
|
|
#define tTimer data[1]
|
|
#define tActiveSprCt data[2]
|
|
#define tOff_RngState 3
|
|
#define tAngle data[5]
|
|
#define tMadeSprCt data[6]
|
|
|
|
#define tsRadius data[0]
|
|
#define tsSpeed data[1]
|
|
#define tsXinit data[2]
|
|
#define tsYinit data[3]
|
|
#define tsXorig data[4]
|
|
#define tsYorig data[5]
|
|
#define tsTaskId data[6]
|
|
|
|
static void PSAScene_SeedRandomInTask(struct PokemonSpecialAnimScene * scene)
|
|
{
|
|
u8 taskId;
|
|
LoadOutwardSpiralDotsGfx();
|
|
taskId = CreateTask(Task_UseItem_OutwardSpiralDots, 1);
|
|
SetWordTaskArg(taskId, tOff_RngState, 2022069025);
|
|
gTasks[taskId].tAngle = 0xE0;
|
|
}
|
|
|
|
static void StopMakingOutwardSpiralDots(void)
|
|
{
|
|
u8 taskId = FindTaskIdByFunc(Task_UseItem_OutwardSpiralDots);
|
|
if (taskId != 0xFF)
|
|
gTasks[taskId].tState = 1;
|
|
}
|
|
|
|
static void Task_UseItem_OutwardSpiralDots(u8 taskId)
|
|
{
|
|
s16 *data = gTasks[taskId].data;
|
|
|
|
switch (tState)
|
|
{
|
|
case 0:
|
|
if (tTimer == 0)
|
|
{
|
|
u32 spriteId, x, y, x2, y2, ampl;
|
|
struct Sprite *sprite = PSA_GetSceneWork()->itemIconSprite;
|
|
x = sprite->x + sprite->x2;
|
|
y = sprite->y + sprite->y2;
|
|
ampl = (PSAScene_RandomFromTask(taskId) % 21) + 70;
|
|
x2 = x + ((u32)(gSineTable[tAngle + 0x40] * ampl) >> 8);
|
|
y2 = y + ((u32)(gSineTable[tAngle ] * ampl) >> 8);
|
|
tAngle += 0x4C;
|
|
tAngle &= 0xFF;
|
|
spriteId = CreateSprite(&sSpriteTemplate_UseItem_OutwardSpiralDots, x2, y2, 0);
|
|
if (spriteId != MAX_SPRITES)
|
|
{
|
|
gSprites[spriteId].tsRadius = 0;
|
|
gSprites[spriteId].tsSpeed = (PSAScene_RandomFromTask(taskId) & 1) + 6;
|
|
gSprites[spriteId].tsXinit = x2;
|
|
gSprites[spriteId].tsYinit = y2;
|
|
gSprites[spriteId].tsXorig = x;
|
|
gSprites[spriteId].tsYorig = y;
|
|
gSprites[spriteId].tsTaskId = taskId;
|
|
tActiveSprCt++;
|
|
}
|
|
tMadeSprCt++;
|
|
if (tMadeSprCt > 47)
|
|
tState++;
|
|
}
|
|
else
|
|
tTimer--;
|
|
break;
|
|
case 1:
|
|
if (tActiveSprCt == 0)
|
|
DestroyTask(taskId);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static u16 PSAScene_RandomFromTask(u8 taskId)
|
|
{
|
|
u32 state = GetWordTaskArg(taskId, tOff_RngState);
|
|
state = ISO_RANDOMIZE1(state);
|
|
SetWordTaskArg(taskId, tOff_RngState, state);
|
|
return state >> 16;
|
|
}
|
|
|
|
static void SpriteCallback_UseItem_OutwardSpiralDots(struct Sprite *sprite)
|
|
{
|
|
int x;
|
|
int y;
|
|
sprite->tsRadius += sprite->tsSpeed;
|
|
if (sprite->tsRadius > 255)
|
|
{
|
|
gTasks[sprite->tsTaskId].tActiveSprCt--;
|
|
DestroySprite(sprite);
|
|
}
|
|
else
|
|
{
|
|
x = (sprite->tsXorig - sprite->tsXinit) * sprite->tsRadius;
|
|
y = (sprite->tsYorig - sprite->tsYinit) * sprite->tsRadius;
|
|
sprite->x = (x >> 8) + sprite->tsXinit;
|
|
sprite->y = (y >> 8) + sprite->tsYinit;
|
|
}
|
|
}
|
|
|
|
static void LoadOutwardSpiralDotsGfx(void)
|
|
{
|
|
LoadCompressedSpriteSheet(&sSpriteSheet_UseItem_OutwardSpiralDots);
|
|
LoadSpritePalette(&sSpritePalette_UseItem_OutwardSpiralDots);
|
|
}
|
|
|
|
static bool32 IsOutwardSpiralDotsTaskRunning(void)
|
|
{
|
|
return FuncIsActiveTask(Task_UseItem_OutwardSpiralDots);
|
|
}
|
|
|
|
#undef tsTaskId
|
|
#undef tsYorig
|
|
#undef tsXorig
|
|
#undef tsYinit
|
|
#undef tsXinit
|
|
#undef tsSpeed
|
|
#undef tsRadius
|
|
|
|
#undef tMadeSprCt
|
|
#undef tAngle
|
|
#undef tOff_RngState
|
|
#undef tActiveSprCt
|
|
#undef tTimer
|
|
#undef tState
|
|
|
|
// ========================================================
|
|
|
|
#define tState data[0]
|
|
#define tActiveSprCt data[1]
|
|
#define tMadeSprCt data[2]
|
|
#define tTimer data[3]
|
|
#define tXpos data[4]
|
|
#define tYpos data[5]
|
|
#define tTileTag data[6]
|
|
#define tPaletteTag data[7]
|
|
#define tPriority data[8]
|
|
#define tSubpriority data[9]
|
|
|
|
#define tsYsubpixel data[1]
|
|
#define tsSpeed data[2]
|
|
#define tsTaskId data[7]
|
|
|
|
void CreateLevelUpVerticalSpritesTask(u16 x, u16 y, u16 tileTag, u16 paletteTag, u16 priority, u16 subpriority)
|
|
{
|
|
static struct CompressedSpriteSheet spriteSheet;
|
|
static struct SpritePalette spritePalette;
|
|
u8 taskId;
|
|
spriteSheet.tag = tileTag;
|
|
spriteSheet.data = sLevelUp_Gfx;
|
|
spriteSheet.size = sLevelUp_Gfx[0] >> 8;
|
|
spritePalette.data = sLevelUp_Pal;
|
|
spritePalette.tag = paletteTag;
|
|
LoadCompressedSpriteSheet(&spriteSheet);
|
|
LoadSpritePalette(&spritePalette);
|
|
taskId = CreateTask(Task_LevelUpVerticalSprites, 0);
|
|
gTasks[taskId].tXpos = x - 32;
|
|
gTasks[taskId].tYpos = y + 32;
|
|
gTasks[taskId].tTileTag = tileTag;
|
|
gTasks[taskId].tPaletteTag = paletteTag;
|
|
gTasks[taskId].tPriority = priority;
|
|
gTasks[taskId].tSubpriority = subpriority;
|
|
SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_EFFECT_NONE | BLDCNT_TGT2_ALL);
|
|
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(12, 6));
|
|
}
|
|
|
|
bool8 LevelUpVerticalSpritesTaskIsRunning(void)
|
|
{
|
|
return FuncIsActiveTask(Task_LevelUpVerticalSprites);
|
|
}
|
|
|
|
static void Task_LevelUpVerticalSprites(u8 taskId)
|
|
{
|
|
s16 *data = gTasks[taskId].data;
|
|
switch (tState)
|
|
{
|
|
case 0:
|
|
if (tTimer == 0)
|
|
{
|
|
tTimer++;
|
|
CreateLevelUpVerticalSprite(taskId, data);
|
|
if (tMadeSprCt > 17)
|
|
tState++;
|
|
}
|
|
else
|
|
{
|
|
tTimer++;
|
|
if (tTimer == 2)
|
|
tTimer = 0;
|
|
}
|
|
break;
|
|
case 1:
|
|
if (tActiveSprCt == 0)
|
|
{
|
|
FreeSpriteTilesByTag(tTileTag);
|
|
FreeSpritePaletteByTag(tPaletteTag);
|
|
DestroyTask(taskId);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void CreateLevelUpVerticalSprite(u8 taskId, s16 *data)
|
|
{
|
|
u8 spriteId;
|
|
struct SpriteTemplate template = sSpriteTemplate_LevelUpVertical;
|
|
template.tileTag = tTileTag;
|
|
template.paletteTag = tPaletteTag;
|
|
tMadeSprCt++;
|
|
spriteId = CreateSprite(&template, ((tMadeSprCt * 219) & 0x3F) + tXpos, tYpos, tSubpriority);
|
|
if (spriteId != MAX_SPRITES)
|
|
{
|
|
gSprites[spriteId].oam.priority = tPriority;
|
|
gSprites[spriteId].tsYsubpixel = 0;
|
|
gSprites[spriteId].tsSpeed = (ISO_RANDOMIZE1(tMadeSprCt) & 0x3F) + 0x20;
|
|
gSprites[spriteId].tsTaskId = taskId;
|
|
tActiveSprCt++;
|
|
}
|
|
}
|
|
|
|
static void SpriteCB_LevelUpVertical(struct Sprite *sprite)
|
|
{
|
|
sprite->tsYsubpixel -= sprite->tsSpeed;
|
|
sprite->y2 = sprite->tsYsubpixel >> 4;
|
|
if (sprite->y2 < -0x40)
|
|
{
|
|
gTasks[sprite->tsTaskId].tActiveSprCt--;
|
|
DestroySprite(sprite);
|
|
}
|
|
}
|
|
|
|
#undef tsTaskId
|
|
#undef tsSpeed
|
|
#undef tsYsubpixel
|
|
|
|
#undef tSubpriority
|
|
#undef tPriority
|
|
#undef tPaletteTag
|
|
#undef tTileTag
|
|
#undef tYpos
|
|
#undef tXpos
|
|
#undef tTimer
|
|
#undef tMadeSprCt
|
|
#undef tActiveSprCt
|
|
#undef tState
|
|
|
|
// ========================================================
|
|
|
|
static const u8 *const sLevelUpWindowStatNames[] = {
|
|
gText_LevelUp_MaxHP,
|
|
gText_LevelUp_Attack,
|
|
gText_LevelUp_Defense,
|
|
gText_LevelUp_SpAtk,
|
|
gText_LevelUp_SpDef,
|
|
gText_LevelUp_Speed
|
|
};
|
|
|
|
void DrawLevelUpWindowPg1(u16 windowId, u16 *beforeStats, u16 *afterStats, u8 bgColor, u8 fgColor, u8 shadowColor)
|
|
{
|
|
s16 diffStats[6];
|
|
u8 textbuf[12];
|
|
u8 textColor[3];
|
|
u16 i;
|
|
u8 x;
|
|
|
|
FillWindowPixelBuffer(windowId, PIXEL_FILL(bgColor));
|
|
|
|
diffStats[0] = afterStats[0] - beforeStats[0];
|
|
diffStats[1] = afterStats[1] - beforeStats[1];
|
|
diffStats[2] = afterStats[2] - beforeStats[2];
|
|
diffStats[3] = afterStats[4] - beforeStats[4];
|
|
diffStats[4] = afterStats[5] - beforeStats[5];
|
|
diffStats[5] = afterStats[3] - beforeStats[3];
|
|
|
|
textColor[0] = bgColor;
|
|
textColor[1] = fgColor;
|
|
textColor[2] = shadowColor;
|
|
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
AddTextPrinterParameterized3(windowId, FONT_NORMAL, 0, i * 15, textColor, TEXT_SKIP_DRAW, sLevelUpWindowStatNames[i]);
|
|
StringCopy(textbuf, diffStats[i] >= 0 ? gText_LevelUp_Plus : gText_LevelUp_Minus);
|
|
AddTextPrinterParameterized3(windowId, FONT_NORMAL, 56, i * 15, textColor, TEXT_SKIP_DRAW, textbuf);
|
|
textbuf[0] = CHAR_SPACE;
|
|
x = abs(diffStats[i]) < 10 ? 12 : 6;
|
|
ConvertIntToDecimalStringN(textbuf + 1, abs(diffStats[i]), STR_CONV_MODE_LEFT_ALIGN, 2);
|
|
AddTextPrinterParameterized3(windowId, FONT_NORMAL, x + 56, i * 15, textColor, TEXT_SKIP_DRAW, textbuf);
|
|
}
|
|
}
|
|
|
|
void DrawLevelUpWindowPg2(u16 windowId, u16 *currStats, u8 bgColor, u8 fgColor, u8 shadowColor)
|
|
{
|
|
s16 statsRearrange[6];
|
|
u8 textbuf[12];
|
|
u8 textColor[3];
|
|
u16 i;
|
|
u8 ndigits;
|
|
u16 x;
|
|
|
|
FillWindowPixelBuffer(windowId, PIXEL_FILL(bgColor));
|
|
|
|
statsRearrange[0] = currStats[0];
|
|
statsRearrange[1] = currStats[1];
|
|
statsRearrange[2] = currStats[2];
|
|
statsRearrange[3] = currStats[4];
|
|
statsRearrange[4] = currStats[5];
|
|
statsRearrange[5] = currStats[3];
|
|
|
|
textColor[0] = bgColor;
|
|
textColor[1] = fgColor;
|
|
textColor[2] = shadowColor;
|
|
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
if (statsRearrange[i] >= 100)
|
|
ndigits = 3;
|
|
else if (statsRearrange[i] >= 10)
|
|
ndigits = 2;
|
|
else
|
|
ndigits = 1;
|
|
ConvertIntToDecimalStringN(textbuf, statsRearrange[i], STR_CONV_MODE_LEFT_ALIGN, ndigits);
|
|
x = 6 * (4 - ndigits);
|
|
AddTextPrinterParameterized3(windowId, FONT_NORMAL, 0, i * 15, textColor, TEXT_SKIP_DRAW, sLevelUpWindowStatNames[i]);
|
|
AddTextPrinterParameterized3(windowId, FONT_NORMAL, 56 + x, i * 15, textColor, TEXT_SKIP_DRAW, textbuf);
|
|
}
|
|
}
|