summaryrefslogtreecommitdiff
path: root/src/pokeball.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pokeball.c')
-rw-r--r--src/pokeball.c1203
1 files changed, 1203 insertions, 0 deletions
diff --git a/src/pokeball.c b/src/pokeball.c
new file mode 100644
index 000000000..7162ee6ac
--- /dev/null
+++ b/src/pokeball.c
@@ -0,0 +1,1203 @@
+#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 gMPlay_BGM;
+extern u16 gBattleTypeFlags;
+extern u8 gBankTarget;
+extern u8 gActiveBattler;
+extern u16 gBattlerPartyIndexes[];
+extern u8 gBankSpriteIds[];
+extern u8 gDoingBattleAnim;
+extern u8 gHealthboxIDs[];
+
+#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
+ gBankTarget = battler;
+ gSprites[spriteId].pos1.x = 24;
+ gSprites[spriteId].pos1.y = 68;
+ gSprites[spriteId].callback = SendOutPlayerMonAnimation_Step0;
+ break;
+ case 0xFE: // Opponent's side
+ gSprites[spriteId].pos1.x = GetBattlerSpriteCoord(battler, 0);
+ gSprites[spriteId].pos1.y = GetBattlerSpriteCoord(battler, 1) + 24;
+ gBankTarget = battler;
+ gSprites[spriteId].data[0] = 0;
+ gSprites[spriteId].callback = SendOutOpponentMonAnimation_Step0;
+ break;
+ default:
+ gBankTarget = GetBattlerAtPosition(1);
+ debug = TRUE;
+ break;
+ }
+
+ gSprites[spriteId].data[6] = gBankTarget;
+ if (!debug)
+ {
+ DestroyTask(taskId);
+ return;
+ }
+
+ gSprites[spriteId].data[0] = 0x22;
+ gSprites[spriteId].data[2] = GetBattlerSpriteCoord(gBankTarget, 0);
+ gSprites[spriteId].data[4] = GetBattlerSpriteCoord(gBankTarget, 1) - 16;
+ gSprites[spriteId].data[5] = -40;
+ InitAnimArcTranslation(&gSprites[spriteId]);
+ gSprites[spriteId].oam.affineParam = taskId;
+ gTasks[taskId].data[4] = gBankTarget;
+ gTasks[taskId].func = TaskDummy;
+ PlaySE(SE_NAGERU);
+}
+
+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->pos1.x += sprite->pos2.x;
+ sprite->pos1.y += sprite->pos2.y;
+ sprite->pos2.x = 0;
+ sprite->pos2.y = 0;
+ sprite->data[5] = 0;
+ r4 = ball_number_to_ball_processing_index(GetBattlerBall(r5));
+ AnimateBallOpenParticles(sprite->pos1.x, sprite->pos1.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[gBankSpriteIds[sprite->data[6]]], 2);
+ AnimateSprite(&gSprites[gBankSpriteIds[sprite->data[6]]]);
+ gSprites[gBankSpriteIds[sprite->data[6]]].data[1] = 0;
+ }
+}
+
+static void sub_8046760(struct Sprite *sprite)
+{
+ sprite->data[5]++;
+ if (sprite->data[5] == 11)
+ PlaySE(SE_SUIKOMU);
+ if (gSprites[gBankSpriteIds[sprite->data[6]]].affineAnimEnded)
+ {
+ StartSpriteAnim(sprite, 2);
+ gSprites[gBankSpriteIds[sprite->data[6]]].invisible = TRUE;
+ sprite->data[5] = 0;
+ sprite->callback = sub_80467F8;
+ }
+ else
+ {
+ gSprites[gBankSpriteIds[sprite->data[6]]].data[1] += 0x60;
+ gSprites[gBankSpriteIds[sprite->data[6]]].pos2.y = -gSprites[gBankSpriteIds[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->pos1.y += Cos(0, 32);
+ sprite->pos2.y = -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->pos2.y = -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_KON);
+ break;
+ case 2:
+ PlaySE(SE_KON2);
+ break;
+ case 3:
+ PlaySE(SE_KON3);
+ break;
+ default:
+ PlaySE(SE_KON4);
+ break;
+ }
+ }
+ break;
+ case 1:
+ sprite->pos2.y = -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->pos1.y += Cos(64, 32);
+ sprite->pos2.y = 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_BOWA);
+ }
+}
+
+static void sub_8046984(struct Sprite *sprite)
+{
+ switch (sprite->data[3] & 0xFF)
+ {
+ case 0:
+ case 2:
+ sprite->pos2.x += 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_BOWA);
+ }
+ 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->pos1.x, sprite->pos1.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(&gMPlay_BGM);
+ }
+ else
+ {
+ m4aMPlayVolumeControl(&gMPlay_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[gBankSpriteIds[sprite->data[6]]], 1);
+ AnimateSprite(&gSprites[gBankSpriteIds[sprite->data[6]]]);
+ gSprites[gBankSpriteIds[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[gBankSpriteIds[r4]].invisible = FALSE;
+ if (sprite->animEnded)
+ sprite->invisible = TRUE;
+ if (gSprites[gBankSpriteIds[r4]].affineAnimEnded)
+ {
+ StartSpriteAffineAnim(&gSprites[gBankSpriteIds[r4]], 0);
+ r7 = TRUE;
+ }
+ else
+ {
+ gSprites[gBankSpriteIds[r4]].data[1] -= 288;
+ gSprites[gBankSpriteIds[r4]].pos2.y = gSprites[gBankSpriteIds[r4]].data[1] >> 8;
+ }
+ if (sprite->animEnded && r7)
+ {
+ s32 i;
+ u32 r3;
+
+ gSprites[gBankSpriteIds[r4]].pos2.y = 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_FANFA5);
+ }
+ else if (sprite->data[4] == 315)
+ {
+ FreeOamMatrix(gSprites[gBankSpriteIds[sprite->data[6]]].oam.matrixNum);
+ DestroySprite(&gSprites[gBankSpriteIds[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->pos2.y += 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->pos1.x += sprite->pos2.x;
+ sprite->pos1.y += sprite->pos2.y;
+ sprite->pos2.y = 0;
+ sprite->pos2.x = 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].pos1.x;
+ gSprites[spriteId].data[6] = gSprites[a].pos1.y;
+ gSprites[a].pos1.x = x;
+ gSprites[a].pos1.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->pos1.x, sprite->pos1.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->pos1.x) * sprite->data[7] / 128 + sprite->pos1.x;
+ var2 = (sprite->data[6] - sprite->pos1.y) * sprite->data[7] / 128 + sprite->pos1.y;
+ gSprites[r3].pos1.x = var1;
+ gSprites[r3].pos1.y = var2;
+ if (sprite->data[7] < 128)
+ {
+ s16 sine = -(gSineTable[(u8)sprite->data[7]] / 8);
+
+ sprite->data[7] += 4;
+ gSprites[r3].pos2.x = sine;
+ gSprites[r3].pos2.y = sine;
+ }
+ else
+ {
+ gSprites[r3].pos1.x = sprite->data[5];
+ gSprites[r3].pos1.y = sprite->data[6];
+ gSprites[r3].pos2.x = 0;
+ gSprites[r3].pos2.y = 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->pos1.x, sprite->pos1.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_SUIKOMU);
+ 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].pos2.y = -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[gHealthboxIDs[a]];
+
+ sprite->data[0] = 5;
+ sprite->data[1] = 0;
+ sprite->pos2.x = 0x73;
+ sprite->pos2.y = 0;
+ sprite->callback = sub_8047830;
+ if (GetBattlerSide(a) != 0)
+ {
+ sprite->data[0] = -sprite->data[0];
+ sprite->data[1] = -sprite->data[1];
+ sprite->pos2.x = -sprite->pos2.x;
+ sprite->pos2.y = -sprite->pos2.y;
+ }
+ 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->pos2.x -= sprite->data[0];
+ sprite->pos2.y -= sprite->data[1];
+ if (sprite->pos2.x == 0 && sprite->pos2.y == 0)
+ sprite->callback = SpriteCallbackDummy;
+}
+
+void sub_8047858(u8 a)
+{
+ u8 spriteId;
+
+ spriteId = CreateInvisibleSpriteWithCallback(oamc_804BEB4);
+ gSprites[spriteId].data[0] = 1;
+ gSprites[spriteId].data[1] = gHealthboxIDs[a];
+ gSprites[spriteId].callback = oamc_804BEB4;
+}
+
+static void oamc_804BEB4(struct Sprite *sprite)
+{
+ u8 r1 = sprite->data[1];
+
+ gSprites[r1].pos2.y = sprite->data[0];
+ sprite->data[0] = -sprite->data[0];
+ sprite->data[2]++;
+ if (sprite->data[2] == 21)
+ {
+ gSprites[r1].pos2.x = 0;
+ gSprites[r1].pos2.y = 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);
+}