#include "global.h" #include "gba/m4a_internal.h" #include "battle.h" #include "battle_anim_special.h" #include "decompress.h" #include "graphics.h" #include "m4a.h" #include "main.h" #include "pokeball.h" #include "pokemon.h" #include "rom_8077ABC.h" #include "constants/songs.h" #include "sound.h" #include "sprite.h" #include "task.h" #include "trig.h" #include "util.h" #include "ewram.h" extern struct MusicPlayerInfo gMPlayInfo_BGM; extern u16 gBattleTypeFlags; extern u8 gBattlerTarget; extern u8 gActiveBattler; extern u16 gBattlerPartyIndexes[]; extern u8 gBattlerSpriteIds[]; extern u8 gDoingBattleAnim; extern u8 gHealthboxSpriteIds[]; #define GFX_TAG_POKEBALL 55000 #define GFX_TAG_GREATBALL 55001 #define GFX_TAG_SAFARIBALL 55002 #define GFX_TAG_ULTRABALL 55003 #define GFX_TAG_MASTERBALL 55004 #define GFX_TAG_NETBALL 55005 #define GFX_TAG_DIVEBALL 55006 #define GFX_TAG_NESTBALL 55007 #define GFX_TAG_REPEATBALL 55008 #define GFX_TAG_TIMERBALL 55009 #define GFX_TAG_LUXURYBALL 55010 #define GFX_TAG_PREMIERBALL 55011 static const struct CompressedSpriteSheet sBallSpriteSheets[] = { {gInterfaceGfx_PokeBall, 384, GFX_TAG_POKEBALL}, {gInterfaceGfx_GreatBall, 384, GFX_TAG_GREATBALL}, {gInterfaceGfx_SafariBall, 384, GFX_TAG_SAFARIBALL}, {gInterfaceGfx_UltraBall, 384, GFX_TAG_ULTRABALL}, {gInterfaceGfx_MasterBall, 384, GFX_TAG_MASTERBALL}, {gInterfaceGfx_NetBall, 384, GFX_TAG_NETBALL}, {gInterfaceGfx_DiveBall, 384, GFX_TAG_DIVEBALL}, {gInterfaceGfx_NestBall, 384, GFX_TAG_NESTBALL}, {gInterfaceGfx_RepeatBall, 384, GFX_TAG_REPEATBALL}, {gInterfaceGfx_TimerBall, 384, GFX_TAG_TIMERBALL}, {gInterfaceGfx_LuxuryBall, 384, GFX_TAG_LUXURYBALL}, {gInterfaceGfx_PremierBall, 384, GFX_TAG_PREMIERBALL}, }; static const struct CompressedSpritePalette sBallSpritePalettes[] = { {gInterfacePal_PokeBall, GFX_TAG_POKEBALL}, {gInterfacePal_GreatBall, GFX_TAG_GREATBALL}, {gInterfacePal_SafariBall, GFX_TAG_SAFARIBALL}, {gInterfacePal_UltraBall, GFX_TAG_ULTRABALL}, {gInterfacePal_MasterBall, GFX_TAG_MASTERBALL}, {gInterfacePal_NetBall, GFX_TAG_NETBALL}, {gInterfacePal_DiveBall, GFX_TAG_DIVEBALL}, {gInterfacePal_NestBall, GFX_TAG_NESTBALL}, {gInterfacePal_RepeatBall, GFX_TAG_REPEATBALL}, {gInterfacePal_TimerBall, GFX_TAG_TIMERBALL}, {gInterfacePal_LuxuryBall, GFX_TAG_LUXURYBALL}, {gInterfacePal_PremierBall, GFX_TAG_PREMIERBALL}, }; static const struct OamData sBallOamData = { .y = 0, .affineMode = 3, .objMode = 0, .mosaic = 0, .bpp = 0, .shape = 0, .x = 0, .matrixNum = 0, .size = 1, .tileNum = 0, .priority = 2, .paletteNum = 0, .affineParam = 0, }; static const union AnimCmd sBallAnimSeq3[] = { ANIMCMD_FRAME(0, 5), ANIMCMD_JUMP(0), }; static const union AnimCmd sBallAnimSeq5[] = { ANIMCMD_FRAME(4, 1), ANIMCMD_JUMP(0), }; static const union AnimCmd sBallAnimSeq4[] = { ANIMCMD_FRAME(8, 5), ANIMCMD_JUMP(0), }; static const union AnimCmd sBallAnimSeq6[] = { ANIMCMD_FRAME(12, 1), ANIMCMD_JUMP(0), }; static const union AnimCmd sBallAnimSeq0[] = { ANIMCMD_FRAME(0, 1), ANIMCMD_END, }; static const union AnimCmd sBallAnimSeq1[] = { ANIMCMD_FRAME(4, 5), ANIMCMD_FRAME(8, 5), ANIMCMD_END, }; static const union AnimCmd sBallAnimSeq2[] = { ANIMCMD_FRAME(4, 5), ANIMCMD_FRAME(0, 5), ANIMCMD_END, }; static const union AnimCmd *const sBallAnimSequences[] = { sBallAnimSeq0, sBallAnimSeq1, sBallAnimSeq2, // unused? sBallAnimSeq3, sBallAnimSeq4, sBallAnimSeq5, sBallAnimSeq6, }; static const union AffineAnimCmd sBallAffineAnimSeq0[] = { AFFINEANIMCMD_FRAME(0, 0, 0, 1), AFFINEANIMCMD_JUMP(0), }; static const union AffineAnimCmd sBallAffineAnimSeq1[] = { AFFINEANIMCMD_FRAME(0, 0, -3, 1), AFFINEANIMCMD_JUMP(0), }; static const union AffineAnimCmd sBallAffineAnimSeq2[] = { AFFINEANIMCMD_FRAME(0, 0, 3, 1), AFFINEANIMCMD_JUMP(0), }; static const union AffineAnimCmd sBallAffineAnimSeq3[] = { AFFINEANIMCMD_FRAME(256, 256, 0, 0), AFFINEANIMCMD_END, }; static const union AffineAnimCmd sBallAffineAnimSeq4[] = { AFFINEANIMCMD_FRAME(0, 0, 25, 1), AFFINEANIMCMD_JUMP(0), }; static const union AffineAnimCmd *const sBallAffineAnimSequences[] = { sBallAffineAnimSeq0, sBallAffineAnimSeq1, sBallAffineAnimSeq2, sBallAffineAnimSeq3, sBallAffineAnimSeq4, }; static void objc_0804ABD4(struct Sprite *sprite); const struct SpriteTemplate gBallSpriteTemplates[] = { { .tileTag = GFX_TAG_POKEBALL, .paletteTag = GFX_TAG_POKEBALL, .oam = &sBallOamData, .anims = sBallAnimSequences, .images = NULL, .affineAnims = sBallAffineAnimSequences, .callback = objc_0804ABD4, }, { .tileTag = GFX_TAG_GREATBALL, .paletteTag = GFX_TAG_GREATBALL, .oam = &sBallOamData, .anims = sBallAnimSequences, .images = NULL, .affineAnims = sBallAffineAnimSequences, .callback = objc_0804ABD4, }, { .tileTag = GFX_TAG_SAFARIBALL, .paletteTag = GFX_TAG_SAFARIBALL, .oam = &sBallOamData, .anims = sBallAnimSequences, .images = NULL, .affineAnims = sBallAffineAnimSequences, .callback = objc_0804ABD4, }, { .tileTag = GFX_TAG_ULTRABALL, .paletteTag = GFX_TAG_ULTRABALL, .oam = &sBallOamData, .anims = sBallAnimSequences, .images = NULL, .affineAnims = sBallAffineAnimSequences, .callback = objc_0804ABD4, }, { .tileTag = GFX_TAG_MASTERBALL, .paletteTag = GFX_TAG_MASTERBALL, .oam = &sBallOamData, .anims = sBallAnimSequences, .images = NULL, .affineAnims = sBallAffineAnimSequences, .callback = objc_0804ABD4, }, { .tileTag = GFX_TAG_NETBALL, .paletteTag = GFX_TAG_NETBALL, .oam = &sBallOamData, .anims = sBallAnimSequences, .images = NULL, .affineAnims = sBallAffineAnimSequences, .callback = objc_0804ABD4, }, { .tileTag = GFX_TAG_DIVEBALL, .paletteTag = GFX_TAG_DIVEBALL, .oam = &sBallOamData, .anims = sBallAnimSequences, .images = NULL, .affineAnims = sBallAffineAnimSequences, .callback = objc_0804ABD4, }, { .tileTag = GFX_TAG_NESTBALL, .paletteTag = GFX_TAG_NESTBALL, .oam = &sBallOamData, .anims = sBallAnimSequences, .images = NULL, .affineAnims = sBallAffineAnimSequences, .callback = objc_0804ABD4, }, { .tileTag = GFX_TAG_REPEATBALL, .paletteTag = GFX_TAG_REPEATBALL, .oam = &sBallOamData, .anims = sBallAnimSequences, .images = NULL, .affineAnims = sBallAffineAnimSequences, .callback = objc_0804ABD4, }, { .tileTag = GFX_TAG_TIMERBALL, .paletteTag = GFX_TAG_TIMERBALL, .oam = &sBallOamData, .anims = sBallAnimSequences, .images = NULL, .affineAnims = sBallAffineAnimSequences, .callback = objc_0804ABD4, }, { .tileTag = GFX_TAG_LUXURYBALL, .paletteTag = GFX_TAG_LUXURYBALL, .oam = &sBallOamData, .anims = sBallAnimSequences, .images = NULL, .affineAnims = sBallAffineAnimSequences, .callback = objc_0804ABD4, }, { .tileTag = GFX_TAG_PREMIERBALL, .paletteTag = GFX_TAG_PREMIERBALL, .oam = &sBallOamData, .anims = sBallAnimSequences, .images = NULL, .affineAnims = sBallAffineAnimSequences, .callback = objc_0804ABD4, }, }; extern void InitAnimArcTranslation(); extern bool8 TranslateAnimArc(struct Sprite *); static void SendOutMonAnimation(u8); static void sub_80466E8(struct Sprite *); static void sub_80466F4(struct Sprite *); static void sub_8046760(struct Sprite *); static void sub_80467F8(struct Sprite *); static void sub_804684C(struct Sprite *); static void sub_8046944(struct Sprite *); static void sub_8046984(struct Sprite *); static void sub_8046C78(struct Sprite *); static void sub_8046E7C(struct Sprite *); static void sub_8046E9C(struct Sprite *); static void sub_8046FBC(struct Sprite *); static void SendOutPlayerMonAnimation_Step0(struct Sprite *); static void SendOutPlayerMonAnimation_Step1(struct Sprite *); static void SendOutMonAnimation_Delay(struct Sprite *); static void SendOutOpponentMonAnimation_Step0(struct Sprite *); static void sub_80473D0(struct Sprite *); static void sub_804748C(struct Sprite *); static void sub_8047638(struct Sprite *); static void sub_80476E0(struct Sprite *); static void sub_8047754(struct Sprite *); static void sub_804780C(struct Sprite *); static void sub_8047830(struct Sprite *); static void oamc_804BEB4(struct Sprite *); static u16 GetBattlerBall(u8); u8 StartSendOutMonAnimation(u16 a, u8 side) { u8 taskId; gDoingBattleAnim = 1; ewram17810[gActiveBattler].unk0_3 = 1; taskId = CreateTask(SendOutMonAnimation, 5); gTasks[taskId].data[1] = a; gTasks[taskId].data[2] = side; gTasks[taskId].data[3] = gActiveBattler; return 0; } static void SendOutMonAnimation(u8 taskId) { bool8 debug = FALSE; u16 side; u8 battler; u16 ball; u8 ballIndex; u8 spriteId; if (gTasks[taskId].data[0] == 0) { gTasks[taskId].data[0]++; return; } side = gTasks[taskId].data[2]; battler = gTasks[taskId].data[3]; if (GetBattlerSide(battler) != B_SIDE_PLAYER) ball = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler]], MON_DATA_POKEBALL); else ball = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battler]], MON_DATA_POKEBALL); ballIndex = ball_number_to_ball_processing_index(ball); LoadBallGraphics(ballIndex); spriteId = CreateSprite(&gBallSpriteTemplates[ballIndex], 32, 80, 29); gSprites[spriteId].data[0] = 0x80; gSprites[spriteId].data[1] = 0; gSprites[spriteId].data[7] = side; switch (side) { case 0xFF: // Player's side gBattlerTarget = battler; gSprites[spriteId].x = 24; gSprites[spriteId].y = 68; gSprites[spriteId].callback = SendOutPlayerMonAnimation_Step0; break; case 0xFE: // Opponent's side gSprites[spriteId].x = GetBattlerSpriteCoord(battler, 0); gSprites[spriteId].y = GetBattlerSpriteCoord(battler, 1) + 24; gBattlerTarget = battler; gSprites[spriteId].data[0] = 0; gSprites[spriteId].callback = SendOutOpponentMonAnimation_Step0; break; default: gBattlerTarget = GetBattlerAtPosition(1); debug = TRUE; break; } gSprites[spriteId].data[6] = gBattlerTarget; if (!debug) { DestroyTask(taskId); return; } gSprites[spriteId].data[0] = 0x22; gSprites[spriteId].data[2] = GetBattlerSpriteCoord(gBattlerTarget, 0); gSprites[spriteId].data[4] = GetBattlerSpriteCoord(gBattlerTarget, 1) - 16; gSprites[spriteId].data[5] = -40; InitAnimArcTranslation(&gSprites[spriteId]); gSprites[spriteId].oam.affineParam = taskId; gTasks[taskId].data[4] = gBattlerTarget; gTasks[taskId].func = TaskDummy; PlaySE(SE_BALL_THROW); } static void objc_0804ABD4(struct Sprite *sprite) { if (TranslateAnimArc(sprite)) { u8 taskId = sprite->oam.affineParam; u8 r5 = gTasks[taskId].data[4]; u8 r8 = gTasks[taskId].data[2]; u32 r4; // not sure of this type StartSpriteAnim(sprite, 1); sprite->affineAnimPaused = TRUE; sprite->x += sprite->x2; sprite->y += sprite->y2; sprite->x2 = 0; sprite->y2 = 0; sprite->data[5] = 0; r4 = ball_number_to_ball_processing_index(GetBattlerBall(r5)); AnimateBallOpenParticles(sprite->x, sprite->y - 5, 1, 0x1C, r4); sprite->data[0] = sub_8141314(0, r5, 14, r4); sprite->data[6] = r5; sprite->data[7] = r8; DestroyTask(taskId); sprite->callback = sub_80466E8; } } static void sub_80466E8(struct Sprite *sprite) { sprite->callback = sub_80466F4; } static void sub_80466F4(struct Sprite *sprite) { sprite->data[5]++; if (sprite->data[5] == 10) { sprite->data[5] = 0; sprite->callback = sub_8046760; StartSpriteAffineAnim(&gSprites[gBattlerSpriteIds[sprite->data[6]]], 2); AnimateSprite(&gSprites[gBattlerSpriteIds[sprite->data[6]]]); gSprites[gBattlerSpriteIds[sprite->data[6]]].data[1] = 0; } } static void sub_8046760(struct Sprite *sprite) { sprite->data[5]++; if (sprite->data[5] == 11) PlaySE(SE_BALL_TRADE); if (gSprites[gBattlerSpriteIds[sprite->data[6]]].affineAnimEnded) { StartSpriteAnim(sprite, 2); gSprites[gBattlerSpriteIds[sprite->data[6]]].invisible = TRUE; sprite->data[5] = 0; sprite->callback = sub_80467F8; } else { gSprites[gBattlerSpriteIds[sprite->data[6]]].data[1] += 0x60; gSprites[gBattlerSpriteIds[sprite->data[6]]].y2 = -gSprites[gBattlerSpriteIds[sprite->data[6]]].data[1] >> 8; } } static void sub_80467F8(struct Sprite *sprite) { if (sprite->animEnded) { sprite->data[5]++; if (sprite->data[5] == 1) { sprite->data[3] = 0; sprite->data[4] = 32; sprite->data[5] = 0; sprite->y += Cos(0, 32); sprite->y2 = -Cos(0, sprite->data[4]); sprite->callback = sub_804684C; } } } static void sub_804684C(struct Sprite *sprite) { bool8 r5 = FALSE; switch (sprite->data[3] & 0xFF) { case 0: sprite->y2 = -Cos(sprite->data[5], sprite->data[4]); sprite->data[5] += 4 + (sprite->data[3] >> 8); if (sprite->data[5] >= 64) { sprite->data[4] -= 10; sprite->data[3] += 0x101; if (sprite->data[3] >> 8 == 4) r5 = TRUE; switch (sprite->data[3] >> 8) { case 1: PlaySE(SE_BALL_BOUNCE_1); break; case 2: PlaySE(SE_BALL_BOUNCE_2); break; case 3: PlaySE(SE_BALL_BOUNCE_3); break; default: PlaySE(SE_BALL_BOUNCE_4); break; } } break; case 1: sprite->y2 = -Cos(sprite->data[5], sprite->data[4]); sprite->data[5] -= 4 + (sprite->data[3] >> 8); if (sprite->data[5] <= 0) { sprite->data[5] = 0; sprite->data[3] &= 0xFF00; } break; } if (r5) { sprite->data[3] = 0; sprite->y += Cos(64, 32); sprite->y2 = 0; if (sprite->data[7] == 0) { sprite->callback = sub_8046C78; } else { sprite->callback = sub_8046944; sprite->data[4] = 1; sprite->data[5] = 0; } } } static void sub_8046944(struct Sprite *sprite) { sprite->data[3]++; if (sprite->data[3] == 31) { sprite->data[3] = 0; sprite->affineAnimPaused = TRUE; StartSpriteAffineAnim(sprite, 1); sprite->callback = sub_8046984; PlaySE(SE_BALL); } } static void sub_8046984(struct Sprite *sprite) { switch (sprite->data[3] & 0xFF) { case 0: case 2: sprite->x2 += sprite->data[4]; sprite->data[5] += sprite->data[4]; sprite->affineAnimPaused = FALSE; if (sprite->data[5] > 3 || sprite->data[5] < -3) { sprite->data[3]++; sprite->data[5] = 0; } break; case 1: sprite->data[5]++; if (sprite->data[5] == 1) { sprite->data[5] = 0; sprite->data[4] = -sprite->data[4]; sprite->data[3]++; sprite->affineAnimPaused = FALSE; if (sprite->data[4] < 0) ChangeSpriteAffineAnim(sprite, 2); else ChangeSpriteAffineAnim(sprite, 1); } else { sprite->affineAnimPaused = TRUE; } break; case 3: sprite->data[3] += 0x100; if (sprite->data[3] >> 8 == sprite->data[7]) { sprite->callback = sub_8046C78; } else { if (sprite->data[7] == 4 && sprite->data[3] >> 8 == 3) { sprite->callback = sub_8046E7C; sprite->affineAnimPaused = TRUE; } else { sprite->data[3]++; sprite->affineAnimPaused = TRUE; } } break; case 4: default: sprite->data[5]++; if (sprite->data[5] == 31) { sprite->data[5] = 0; sprite->data[3] &= 0xFF00; StartSpriteAffineAnim(sprite, 3); if (sprite->data[4] < 0) StartSpriteAffineAnim(sprite, 2); else StartSpriteAffineAnim(sprite, 1); PlaySE(SE_BALL); } break; } } static void sub_8046AD0(u8 taskId) { u8 r6 = gTasks[taskId].data[2]; u8 r3 = gTasks[taskId].data[1]; u16 species = gTasks[taskId].data[0]; switch (gTasks[taskId].data[15]) { case 0: default: if (gTasks[taskId].data[8] < 3) gTasks[taskId].data[8]++; else gTasks[taskId].data[15] = r6 + 1; break; case 1: PlayCry1(species, r3); DestroyTask(taskId); break; case 2: StopCryAndClearCrySongs(); gTasks[taskId].data[10] = 3; gTasks[taskId].data[15] = 20; break; case 20: if (gTasks[taskId].data[10] != 0) { gTasks[taskId].data[10]--; break; } PlayCry4(species, r3, 1); DestroyTask(taskId); break; case 3: gTasks[taskId].data[10] = 6; gTasks[taskId].data[15] = 30; break; case 30: if (gTasks[taskId].data[10] != 0) { gTasks[taskId].data[10]--; break; } gTasks[taskId].data[15]++; // fall through case 31: if (!IsCryPlayingOrClearCrySongs()) { StopCryAndClearCrySongs(); gTasks[taskId].data[10] = 3; gTasks[taskId].data[15]++; } break; case 32: if (gTasks[taskId].data[10] != 0) { gTasks[taskId].data[10]--; break; } PlayCry4(species, r3, 0); DestroyTask(taskId); break; } } static void sub_8046C78(struct Sprite *sprite) { int ballIndex; u8 battler = sprite->data[6]; StartSpriteAnim(sprite, 1); ballIndex = ball_number_to_ball_processing_index(GetBattlerBall(battler)); AnimateBallOpenParticles(sprite->x, sprite->y - 5, 1, 28, ballIndex); sprite->data[0] = sub_8141314(1, sprite->data[6], 14, ballIndex); sprite->callback = sub_8046E9C; if (gMain.inBattle) { struct Pokemon *mon; u16 species; s8 cryPanning; u16 cryBehavior; u8 taskId; if (GetBattlerSide(battler) != 0) { mon = &gEnemyParty[gBattlerPartyIndexes[battler]]; cryPanning = 25; } else { mon = &gPlayerParty[gBattlerPartyIndexes[battler]]; cryPanning = -25; } species = GetMonData(mon, MON_DATA_SPECIES); if ((battler == GetBattlerAtPosition(0) || battler == GetBattlerAtPosition(1)) && IsDoubleBattle() && ewram17840.unk9_0) { if (gBattleTypeFlags & BATTLE_TYPE_MULTI) { if (IsBGMPlaying()) m4aMPlayStop(&gMPlayInfo_BGM); } else { m4aMPlayVolumeControl(&gMPlayInfo_BGM, 0xFFFF, 128); } } if (!IsDoubleBattle() || !ewram17840.unk9_0) cryBehavior = 0; else if (battler == GetBattlerAtPosition(0) || battler == GetBattlerAtPosition(1)) cryBehavior = 1; else cryBehavior = 2; taskId = CreateTask(sub_8046AD0, 3); gTasks[taskId].data[0] = species; gTasks[taskId].data[1] = cryPanning; gTasks[taskId].data[2] = cryBehavior; gTasks[taskId].data[15] = 0; } StartSpriteAffineAnim(&gSprites[gBattlerSpriteIds[sprite->data[6]]], 1); AnimateSprite(&gSprites[gBattlerSpriteIds[sprite->data[6]]]); gSprites[gBattlerSpriteIds[sprite->data[6]]].data[1] = 0x1000; } static void sub_8046E7C(struct Sprite *sprite) { sprite->animPaused = TRUE; sprite->callback = sub_8046FBC; sprite->data[3] = 0; sprite->data[4] = 0; sprite->data[5] = 0; } static void sub_8046E9C(struct Sprite *sprite) { bool8 r7 = FALSE; u8 r4 = sprite->data[6]; gSprites[gBattlerSpriteIds[r4]].invisible = FALSE; if (sprite->animEnded) sprite->invisible = TRUE; if (gSprites[gBattlerSpriteIds[r4]].affineAnimEnded) { StartSpriteAffineAnim(&gSprites[gBattlerSpriteIds[r4]], 0); r7 = TRUE; } else { gSprites[gBattlerSpriteIds[r4]].data[1] -= 288; gSprites[gBattlerSpriteIds[r4]].y2 = gSprites[gBattlerSpriteIds[r4]].data[1] >> 8; } if (sprite->animEnded && r7) { s32 i; u32 r3; gSprites[gBattlerSpriteIds[r4]].y2 = 0; gDoingBattleAnim = 0; ewram17810[r4].unk0_3 = 0; FreeSpriteOamMatrix(sprite); DestroySprite(sprite); for (r3 = 0, i = 0; i < 4; i++) { if (ewram17810[i].unk0_3 == 0) r3++; } if (r3 == 4) { for (i = 0; i < 12; i++) FreeBallGraphics(i); } } } static void sub_8046FBC(struct Sprite *sprite) { u8 r7 = sprite->data[6]; sprite->data[4]++; if (sprite->data[4] == 40) { return; } else if (sprite->data[4] == 95) { gDoingBattleAnim = 0; m4aMPlayAllStop(); PlaySE(MUS_EVOLVED); } else if (sprite->data[4] == 315) { FreeOamMatrix(gSprites[gBattlerSpriteIds[sprite->data[6]]].oam.matrixNum); DestroySprite(&gSprites[gBattlerSpriteIds[sprite->data[6]]]); DestroySpriteAndFreeResources(sprite); if (gMain.inBattle) ewram17810[r7].unk0_3 = 0; } } static void SendOutPlayerMonAnimation_Step0(struct Sprite *sprite) { sprite->data[0] = 25; sprite->data[2] = GetBattlerSpriteCoord(sprite->data[6], 2); sprite->data[4] = GetBattlerSpriteCoord(sprite->data[6], 3) + 24; sprite->data[5] = -30; sprite->oam.affineParam = sprite->data[6]; InitAnimArcTranslation(sprite); sprite->callback = SendOutPlayerMonAnimation_Step1; } #define HIBYTE(x) (((x) >> 8) & 0xFF) static void SendOutPlayerMonAnimation_Step1(struct Sprite *sprite) { u32 r6; u32 r7; if (HIBYTE(sprite->data[7]) >= 35 && HIBYTE(sprite->data[7]) < 80) { s16 r4; if ((sprite->oam.affineParam & 0xFF00) == 0) { r6 = sprite->data[1] & 1; r7 = sprite->data[2] & 1; sprite->data[1] = ((sprite->data[1] / 3) & ~1) | r6; sprite->data[2] = ((sprite->data[2] / 3) & ~1) | r7; StartSpriteAffineAnim(sprite, 4); } r4 = sprite->data[0]; TranslateAnimLinear(sprite); sprite->data[7] += sprite->data[6] / 3; sprite->y2 += Sin(HIBYTE(sprite->data[7]), sprite->data[5]); sprite->oam.affineParam += 0x100; if ((sprite->oam.affineParam >> 8) % 3 != 0) sprite->data[0] = r4; else sprite->data[0] = r4 - 1; if (HIBYTE(sprite->data[7]) >= 80) { r6 = sprite->data[1] & 1; r7 = sprite->data[2] & 1; sprite->data[1] = ((sprite->data[1] * 3) & ~1) | r6; sprite->data[2] = ((sprite->data[2] * 3) & ~1) | r7; } } else { if (TranslateAnimArc(sprite)) { sprite->x += sprite->x2; sprite->y += sprite->y2; sprite->y2 = 0; sprite->x2 = 0; sprite->data[6] = sprite->oam.affineParam & 0xFF; sprite->data[0] = 0; if (IsDoubleBattle() && ewram17840.unk9_0 && sprite->data[6] == GetBattlerAtPosition(2)) sprite->callback = SendOutMonAnimation_Delay; else sprite->callback = sub_8046C78; StartSpriteAffineAnim(sprite, 0); } } } static void SendOutMonAnimation_Delay(struct Sprite *sprite) { if (sprite->data[0]++ > 24) { sprite->data[0] = 0; sprite->callback = sub_8046C78; } } static void SendOutOpponentMonAnimation_Step0(struct Sprite *sprite) { sprite->data[0]++; if (sprite->data[0] > 15) { sprite->data[0] = 0; if (IsDoubleBattle() && ewram17840.unk9_0 && sprite->data[6] == GetBattlerAtPosition(3)) sprite->callback = SendOutMonAnimation_Delay; else sprite->callback = sub_8046C78; } } static u8 sub_80472B0(u8 a, u8 b, u8 c, u8 d) { return AnimateBallOpenParticles(a, b, c, d, 0); } static u8 sub_80472D8(u8 a, u8 b, u32 c) { return sub_8141314(a, b, c, 0); } void CreatePokeballSprite(u8 a, u8 b, u8 x, u8 y, u8 e, u8 f, u8 g, u32 h) { u8 spriteId; LoadCompressedObjectPic(&sBallSpriteSheets[0]); LoadCompressedObjectPalette(&sBallSpritePalettes[0]); spriteId = CreateSprite(&gBallSpriteTemplates[0], x, y, f); gSprites[spriteId].data[0] = a; gSprites[spriteId].data[5] = gSprites[a].x; gSprites[spriteId].data[6] = gSprites[a].y; gSprites[a].x = x; gSprites[a].y = y; gSprites[spriteId].data[1] = g; gSprites[spriteId].data[2] = b; gSprites[spriteId].data[3] = h; gSprites[spriteId].data[4] = h >> 16; gSprites[spriteId].oam.priority = e; gSprites[spriteId].callback = sub_80473D0; gSprites[a].invisible = TRUE; } static void sub_80473D0(struct Sprite *sprite) { if (sprite->data[1] == 0) { u8 r5; u8 r7 = sprite->data[0]; u8 r8 = sprite->data[2]; u32 r4 = (u16)sprite->data[3] | ((u16)sprite->data[4] << 16); if (sprite->subpriority != 0) r5 = sprite->subpriority - 1; else r5 = 0; StartSpriteAnim(sprite, 1); sub_80472B0(sprite->x, sprite->y - 5, sprite->oam.priority, r5); sprite->data[1] = sub_80472D8(1, r8, r4); sprite->callback = sub_804748C; gSprites[r7].invisible = FALSE; StartSpriteAffineAnim(&gSprites[r7], 1); AnimateSprite(&gSprites[r7]); gSprites[r7].data[1] = 0x1000; sprite->data[7] = 0; } else { sprite->data[1]--; } } static void sub_804748C(struct Sprite *sprite) { bool8 r12 = FALSE; bool8 r6 = FALSE; u8 r3 = sprite->data[0]; u16 var1; u16 var2; if (sprite->animEnded) sprite->invisible = TRUE; if (gSprites[r3].affineAnimEnded) { StartSpriteAffineAnim(&gSprites[r3], 0); r12 = TRUE; } var1 = (sprite->data[5] - sprite->x) * sprite->data[7] / 128 + sprite->x; var2 = (sprite->data[6] - sprite->y) * sprite->data[7] / 128 + sprite->y; gSprites[r3].x = var1; gSprites[r3].y = var2; if (sprite->data[7] < 128) { s16 sine = -(gSineTable[(u8)sprite->data[7]] / 8); sprite->data[7] += 4; gSprites[r3].x2 = sine; gSprites[r3].y2 = sine; } else { gSprites[r3].x = sprite->data[5]; gSprites[r3].y = sprite->data[6]; gSprites[r3].x2 = 0; gSprites[r3].y2 = 0; r6 = TRUE; } if (sprite->animEnded && r12 && r6) DestroySpriteAndFreeResources(sprite); } u8 sub_8047580(u8 a, u8 b, u8 x, u8 y, u8 e, u8 f, u8 g, u32 h) { u8 spriteId; LoadCompressedObjectPic(&sBallSpriteSheets[0]); LoadCompressedObjectPalette(&sBallSpritePalettes[0]); spriteId = CreateSprite(&gBallSpriteTemplates[0], x, y, f); gSprites[spriteId].data[0] = a; gSprites[spriteId].data[1] = g; gSprites[spriteId].data[2] = b; gSprites[spriteId].data[3] = h; gSprites[spriteId].data[4] = h >> 16; gSprites[spriteId].oam.priority = e; gSprites[spriteId].callback = sub_8047638; return spriteId; } static void sub_8047638(struct Sprite *sprite) { if (sprite->data[1] == 0) { u8 r6; u8 r7 = sprite->data[0]; u8 r8 = sprite->data[2]; u32 r5 = (u16)sprite->data[3] | ((u16)sprite->data[4] << 16); if (sprite->subpriority != 0) r6 = sprite->subpriority - 1; else r6 = 0; StartSpriteAnim(sprite, 1); sub_80472B0(sprite->x, sprite->y - 5, sprite->oam.priority, r6); sprite->data[1] = sub_80472D8(1, r8, r5); sprite->callback = sub_80476E0; StartSpriteAffineAnim(&gSprites[r7], 2); AnimateSprite(&gSprites[r7]); gSprites[r7].data[1] = 0; } else { sprite->data[1]--; } } static void sub_80476E0(struct Sprite *sprite) { u8 r1; sprite->data[5]++; if (sprite->data[5] == 11) PlaySE(SE_BALL_TRADE); r1 = sprite->data[0]; if (gSprites[r1].affineAnimEnded) { StartSpriteAnim(sprite, 2); gSprites[r1].invisible = TRUE; sprite->data[5] = 0; sprite->callback = sub_8047754; } else { gSprites[r1].data[1] += 96; gSprites[r1].y2 = -gSprites[r1].data[1] >> 8; } } static void sub_8047754(struct Sprite *sprite) { if (sprite->animEnded) sprite->callback = SpriteCallbackDummy; } void obj_delete_and_free_associated_resources_(struct Sprite *sprite) { DestroySpriteAndFreeResources(sprite); } void sub_804777C(u8 a) { struct Sprite *sprite = &gSprites[gHealthboxSpriteIds[a]]; sprite->data[0] = 5; sprite->data[1] = 0; sprite->x2 = 0x73; sprite->y2 = 0; sprite->callback = sub_8047830; if (GetBattlerSide(a) != 0) { sprite->data[0] = -sprite->data[0]; sprite->data[1] = -sprite->data[1]; sprite->x2 = -sprite->x2; sprite->y2 = -sprite->y2; } gSprites[sprite->data[5]].callback(&gSprites[sprite->data[5]]); if (GetBattlerPosition(a) == 2) sprite->callback = sub_804780C; } static void sub_804780C(struct Sprite *sprite) { sprite->data[1]++; if (sprite->data[1] == 20) { sprite->data[1] = 0; sprite->callback = sub_8047830; } } static void sub_8047830(struct Sprite *sprite) { sprite->x2 -= sprite->data[0]; sprite->y2 -= sprite->data[1]; if (sprite->x2 == 0 && sprite->y2 == 0) sprite->callback = SpriteCallbackDummy; } void sub_8047858(u8 a) { u8 spriteId; spriteId = CreateInvisibleSpriteWithCallback(oamc_804BEB4); gSprites[spriteId].data[0] = 1; gSprites[spriteId].data[1] = gHealthboxSpriteIds[a]; gSprites[spriteId].callback = oamc_804BEB4; } static void oamc_804BEB4(struct Sprite *sprite) { u8 r1 = sprite->data[1]; gSprites[r1].y2 = sprite->data[0]; sprite->data[0] = -sprite->data[0]; sprite->data[2]++; if (sprite->data[2] == 21) { gSprites[r1].x2 = 0; gSprites[r1].y2 = 0; DestroySprite(sprite); } } void LoadBallGraphics(u8 ballIndex) { u16 tileStart; if (GetSpriteTileStartByTag(sBallSpriteSheets[ballIndex].tag) == 0xFFFF) { LoadCompressedObjectPic(&sBallSpriteSheets[ballIndex]); LoadCompressedObjectPalette(&sBallSpritePalettes[ballIndex]); } switch (ballIndex) { case 6: case 10: case 11: break; default: tileStart = GetSpriteTileStartByTag(sBallSpriteSheets[ballIndex].tag); LZDecompressVram(gUnknown_08D030D0, (void *)(VRAM + 0x10100 + tileStart * 32)); break; } } void FreeBallGraphics(u8 ballIndex) { FreeSpriteTilesByTag(sBallSpriteSheets[ballIndex].tag); FreeSpritePaletteByTag(sBallSpritePalettes[ballIndex].tag); } static u16 GetBattlerBall(u8 battler) { if (GetBattlerSide(battler) == B_SIDE_PLAYER) return GetMonData(&gPlayerParty[gBattlerPartyIndexes[battler]], MON_DATA_POKEBALL); else return GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler]], MON_DATA_POKEBALL); }