pokeruby/src/pokeball.c
Eduardo Quezada f6e2a5901e
Some checks failed
CI / build (push) Has been cancelled
Port Wally Controller documentation from pokeemerald (#891)
2026-02-19 21:49:14 -05:00

1204 lines
32 KiB
C

#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 DoPokeballSendOutAnimation(u16 a, u8 side)
{
u8 taskId;
gDoingBattleAnim = 1;
gBattleHealthBoxInfo[gActiveBattler].ballAnimActive = 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:
PlayCry_Normal(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;
gBattleHealthBoxInfo[r4].ballAnimActive = 0;
FreeSpriteOamMatrix(sprite);
DestroySprite(sprite);
for (r3 = 0, i = 0; i < 4; i++)
{
if (gBattleHealthBoxInfo[i].ballAnimActive == 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)
gBattleHealthBoxInfo[r7].ballAnimActive = 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 StartHealthboxSlideIn(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 DoHitAnimHealthboxEffect(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);
}