summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/battle_anim_mon_movement.c28
-rw-r--r--src/battle_anim_mons.c2253
-rw-r--r--src/battle_anim_sound_tasks.c313
-rw-r--r--src/battle_anim_utility_funcs.c946
-rw-r--r--src/battle_controller_player.c4
-rw-r--r--src/battle_intro.c495
-rw-r--r--src/dark.c921
-rw-r--r--src/daycare.c4
-rw-r--r--src/dragon.c431
-rw-r--r--src/ground.c724
-rw-r--r--src/normal.c916
11 files changed, 7017 insertions, 18 deletions
diff --git a/src/battle_anim_mon_movement.c b/src/battle_anim_mon_movement.c
index 88fbce6da..21d07246f 100644
--- a/src/battle_anim_mon_movement.c
+++ b/src/battle_anim_mon_movement.c
@@ -92,7 +92,7 @@ const struct SpriteTemplate gUnknown_83D4EB4 =
// arg 4: frame delay
void AnimTask_ShakeMon(u8 taskId)
{
- u8 spriteId = GetAnimBankSpriteId(gBattleAnimArgs[0]);
+ u8 spriteId = GetAnimBattlerSpriteId(gBattleAnimArgs[0]);
if (spriteId == 0xFF)
DestroyAnimVisualTask(taskId);
@@ -150,7 +150,7 @@ void AnimTask_ShakeMon2(u8 taskId)
if (gBattleAnimArgs[0] < MAX_BATTLERS_COUNT)
{
- spriteId = GetAnimBankSpriteId(gBattleAnimArgs[0]);
+ spriteId = GetAnimBattlerSpriteId(gBattleAnimArgs[0]);
if (spriteId == 0xFF)
abort = TRUE;
}
@@ -228,7 +228,7 @@ static void AnimTask_ShakeMon2Step(u8 taskId)
// arg 4: delay
void AnimTask_ShakeMonInPlace(u8 taskId)
{
- u8 spriteId = GetAnimBankSpriteId(gBattleAnimArgs[0]);
+ u8 spriteId = GetAnimBattlerSpriteId(gBattleAnimArgs[0]);
if (spriteId == 0xFF)
DestroyAnimVisualTask(taskId);
@@ -290,7 +290,7 @@ static void AnimTask_ShakeMonInPlaceStep(u8 taskId)
// arg 4: duration
void AnimTask_ShakeAndSinkMon(u8 taskId)
{
- u8 spriteId = GetAnimBankSpriteId(gBattleAnimArgs[0]);
+ u8 spriteId = GetAnimBattlerSpriteId(gBattleAnimArgs[0]);
gSprites[spriteId].pos2.x = gBattleAnimArgs[1];
gTasks[taskId].data[0] = spriteId;
@@ -331,7 +331,7 @@ void AnimTask_TranslateMonElliptical(u8 taskId)
{
u8 wavePeriod = 1;
u8 i;
- u8 spriteId = GetAnimBankSpriteId(gBattleAnimArgs[0]);
+ u8 spriteId = GetAnimBattlerSpriteId(gBattleAnimArgs[0]);
if (gBattleAnimArgs[4] > 5)
gBattleAnimArgs[4] = 5;
for (i = 0; i < gBattleAnimArgs[4]; i++)
@@ -414,7 +414,7 @@ static void DoVerticalDip(struct Sprite * sprite)
{
u8 spriteId;
sprite->invisible = TRUE;
- spriteId = GetAnimBankSpriteId(gBattleAnimArgs[2]);
+ spriteId = GetAnimBattlerSpriteId(gBattleAnimArgs[2]);
sprite->data[0] = gBattleAnimArgs[0];
sprite->data[1] = 0;
sprite->data[2] = gBattleAnimArgs[1];
@@ -581,7 +581,7 @@ void AnimTask_WindUpLunge(u8 taskId)
gBattleAnimArgs[1] = -gBattleAnimArgs[1];
gBattleAnimArgs[5] = -gBattleAnimArgs[5];
}
- gTasks[taskId].data[0] = GetAnimBankSpriteId(gBattleAnimArgs[0]);
+ gTasks[taskId].data[0] = GetAnimBattlerSpriteId(gBattleAnimArgs[0]);
gTasks[taskId].data[1] = gBattleAnimArgs[1] * 256 / gBattleAnimArgs[3];
gTasks[taskId].data[2] = gBattleAnimArgs[2];
gTasks[taskId].data[3] = gBattleAnimArgs[3];
@@ -627,7 +627,7 @@ void sub_80995FC(u8 taskId)
{
case 0:
case 1:
- spriteId = GetAnimBankSpriteId(gBattleAnimArgs[0]);
+ spriteId = GetAnimBattlerSpriteId(gBattleAnimArgs[0]);
break;
case 2:
if (!IsBattlerSpriteVisible(gBattleAnimAttacker ^ BIT_FLANK))
@@ -678,7 +678,7 @@ void AnimTask_SwayMon(u8 taskId)
u8 spriteId;
if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
gBattleAnimArgs[1] = -gBattleAnimArgs[1];
- spriteId = GetAnimBankSpriteId(gBattleAnimArgs[4]);
+ spriteId = GetAnimBattlerSpriteId(gBattleAnimArgs[4]);
gTasks[taskId].data[0] = gBattleAnimArgs[0];
gTasks[taskId].data[1] = gBattleAnimArgs[1];
gTasks[taskId].data[2] = gBattleAnimArgs[2];
@@ -735,7 +735,7 @@ static void AnimTask_SwayMonStep(u8 taskId)
// arg 4: sprite object mode
void AnimTask_ScaleMonAndRestore(u8 taskId)
{
- u8 spriteId = GetAnimBankSpriteId(gBattleAnimArgs[3]);
+ u8 spriteId = GetAnimBattlerSpriteId(gBattleAnimArgs[3]);
PrepareBattlerSpriteForRotScale(spriteId, gBattleAnimArgs[4]);
gTasks[taskId].data[0] = gBattleAnimArgs[0];
gTasks[taskId].data[1] = gBattleAnimArgs[1];
@@ -773,7 +773,7 @@ static void AnimTask_ScaleMonAndRestoreStep(u8 taskId)
void sub_8099980(u8 taskId)
{
- u8 spriteId = GetAnimBankSpriteId(gBattleAnimArgs[2]);
+ u8 spriteId = GetAnimBattlerSpriteId(gBattleAnimArgs[2]);
PrepareBattlerSpriteForRotScale(spriteId, 0);
gTasks[taskId].data[1] = 0;
gTasks[taskId].data[2] = gBattleAnimArgs[0];
@@ -806,7 +806,7 @@ void sub_8099980(u8 taskId)
void sub_8099A78(u8 taskId)
{
- u8 spriteId = GetAnimBankSpriteId(gBattleAnimArgs[2]);
+ u8 spriteId = GetAnimBattlerSpriteId(gBattleAnimArgs[2]);
PrepareBattlerSpriteForRotScale(spriteId, 0);
gTasks[taskId].data[1] = 0;
gTasks[taskId].data[2] = gBattleAnimArgs[0];
@@ -844,7 +844,7 @@ static void sub_8099B54(u8 taskId)
gTasks[taskId].data[3] += gTasks[taskId].data[4];
SetSpriteRotScale(gTasks[taskId].data[5], 0x100, 0x100, gTasks[taskId].data[3]);
if (gTasks[taskId].data[7])
- sub_80759DC(gTasks[taskId].data[5]);
+ SetBattlerSpriteYOffsetFromRotation(gTasks[taskId].data[5]);
if (++gTasks[taskId].data[1] >= gTasks[taskId].data[2])
{
switch (gTasks[taskId].data[6])
@@ -888,7 +888,7 @@ void sub_8099BD4(u8 taskId)
gTasks[taskId].data[12] = 0;
gTasks[taskId].data[10] = gBattleAnimArgs[3];
gTasks[taskId].data[11] = gBattleAnimArgs[4];
- gTasks[taskId].data[7] = GetAnimBankSpriteId(1);
+ gTasks[taskId].data[7] = GetAnimBattlerSpriteId(1);
gTasks[taskId].data[8] = gSprites[gTasks[taskId].data[7]].pos2.x;
gTasks[taskId].data[9] = gSprites[gTasks[taskId].data[7]].pos2.y;
gTasks[taskId].data[0] = 0;
diff --git a/src/battle_anim_mons.c b/src/battle_anim_mons.c
new file mode 100644
index 000000000..ed9c9bc2b
--- /dev/null
+++ b/src/battle_anim_mons.c
@@ -0,0 +1,2253 @@
+#include "global.h"
+#include "battle_anim.h"
+#include "bg.h"
+#include "data.h"
+#include "decompress.h"
+#include "dma3.h"
+#include "gpu_regs.h"
+#include "malloc.h"
+#include "palette.h"
+#include "pokemon_icon.h"
+#include "sprite.h"
+#include "task.h"
+#include "trig.h"
+#include "util.h"
+#include "constants/battle_anim.h"
+#include "constants/species.h"
+
+#define GET_UNOWN_LETTER(personality) (( \
+ (((personality & 0x03000000) >> 24) << 6) \
+ | (((personality & 0x00030000) >> 16) << 4) \
+ | (((personality & 0x00000300) >> 8) << 2) \
+ | (((personality & 0x00000003) >> 0) << 0) \
+) % 28)
+
+#define IS_DOUBLE_BATTLE() (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
+
+static u8 GetBattlerSpriteFinal_Y(u8 battlerId, u16 species, bool8 a3);
+static void sub_8075658(struct Sprite *sprite);
+static void sub_80757E8(struct Sprite *sprite);
+static bool8 sub_80758DC(void);
+static void sub_8075EF0(struct Sprite *sprite);
+static void sub_80760D0(u8 taskId);
+static void AnimTask_BlendMonInAndOutSetup(struct Task *task);
+static void AnimTask_BlendMonInAndOutStep(u8 taskId);
+static u16 GetBattlerYDeltaFromSpriteId(u8 spriteId);
+static void sub_8077118(u8 taskId);
+static void sub_80771E4(struct Task *task, u8 taskId);
+static void sub_8077268(struct Sprite *sprite);
+static void sub_80772F4(struct Sprite *sprite);
+
+static EWRAM_DATA union AffineAnimCmd *sAnimTaskAffineAnim = NULL;
+static EWRAM_DATA u32 gUnknown_2037F2C = 0; // not used
+
+static const struct UCoords8 sBattlerCoords[][4] =
+{
+ {
+ { 72, 80 },
+ { 176, 40 },
+ { 48, 40 },
+ { 112, 80 },
+ },
+ {
+ { 32, 80 },
+ { 200, 40 },
+ { 90, 88 },
+ { 152, 32 },
+ },
+};
+
+// One entry for each of the four Castform forms.
+const struct MonCoords gCastformFrontSpriteCoords[] =
+{
+ { .size = 0x44, .y_offset = 17 }, // NORMAL
+ { .size = 0x66, .y_offset = 9 }, // SUN
+ { .size = 0x46, .y_offset = 9 }, // RAIN
+ { .size = 0x86, .y_offset = 8 }, // HAIL
+};
+
+static const u8 sCastformElevations[] =
+{
+ 13, // NORMAL
+ 14, // SUN
+ 13, // RAIN
+ 13, // HAIL
+};
+
+// Y position of the backsprite for each of the four Castform forms.
+static const u8 sCastformBackSpriteYCoords[] =
+{
+ 0, // NORMAL
+ 0, // SUN
+ 0, // RAIN
+ 0, // HAIL
+};
+
+static const struct SpriteTemplate gUnknown_83AE054[] =
+{
+ {
+ .tileTag = 0xD755,
+ .paletteTag = 0xD755,
+ .oam = &gOamData_83ACA40,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCallbackDummy,
+ },
+ {
+ .tileTag = 0xD756,
+ .paletteTag = 0xD756,
+ .oam = &gOamData_83ACA40,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCallbackDummy,
+ }
+};
+
+static const struct SpriteSheet gUnknown_83AE084[] =
+{
+ { gMiscBlank_Gfx, 0x800, 0xD755 },
+ { gMiscBlank_Gfx, 0x800, 0xD756 },
+};
+
+u8 GetBattlerSpriteCoord(u8 battlerId, u8 coordType)
+{
+ u8 retVal;
+ u16 species;
+ struct BattleSpriteInfo *spriteInfo;
+
+ switch (coordType)
+ {
+ case BATTLER_COORD_X:
+ case BATTLER_COORD_X_2:
+ retVal = sBattlerCoords[IS_DOUBLE_BATTLE()][GetBattlerPosition(battlerId)].x;
+ break;
+ case BATTLER_COORD_Y:
+ retVal = sBattlerCoords[IS_DOUBLE_BATTLE()][GetBattlerPosition(battlerId)].y;
+ break;
+ case BATTLER_COORD_Y_PIC_OFFSET:
+ case BATTLER_COORD_Y_PIC_OFFSET_DEFAULT:
+ default:
+ if (GetBattlerSide(battlerId) != B_SIDE_PLAYER)
+ {
+ spriteInfo = gBattleSpritesDataPtr->battlerData;
+ if (!spriteInfo[battlerId].transformSpecies)
+ species = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES);
+ else
+ species = spriteInfo[battlerId].transformSpecies;
+ }
+ else
+ {
+ spriteInfo = gBattleSpritesDataPtr->battlerData;
+ if (!spriteInfo[battlerId].transformSpecies)
+ species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES);
+ else
+ species = spriteInfo[battlerId].transformSpecies;
+ }
+ if (coordType == BATTLER_COORD_Y_PIC_OFFSET)
+ retVal = GetBattlerSpriteFinal_Y(battlerId, species, TRUE);
+ else
+ retVal = GetBattlerSpriteFinal_Y(battlerId, species, FALSE);
+ break;
+ }
+ return retVal;
+}
+
+static u8 GetBattlerYDelta(u8 battlerId, u16 species)
+{
+ u16 letter;
+ u32 personality;
+ struct BattleSpriteInfo *spriteInfo;
+ u8 ret;
+ u16 coordSpecies;
+
+ if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
+ {
+ if (species == SPECIES_UNOWN)
+ {
+ spriteInfo = gBattleSpritesDataPtr->battlerData;
+ if (!spriteInfo[battlerId].transformSpecies)
+ personality = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_PERSONALITY);
+ else
+ personality = gTransformedPersonalities[battlerId];
+ letter = GET_UNOWN_LETTER(personality);
+ if (!letter)
+ coordSpecies = species;
+ else
+ coordSpecies = letter + SPECIES_UNOWN_B - 1;
+ ret = gMonBackPicCoords[coordSpecies].y_offset;
+ }
+ else if (species == SPECIES_CASTFORM)
+ {
+ ret = sCastformBackSpriteYCoords[gBattleMonForms[battlerId]];
+ }
+ else if (species > NUM_SPECIES)
+ {
+ ret = gMonBackPicCoords[0].y_offset;
+ }
+ else
+ {
+ ret = gMonBackPicCoords[species].y_offset;
+ }
+ }
+ else
+ {
+ if (species == SPECIES_UNOWN)
+ {
+ spriteInfo = gBattleSpritesDataPtr->battlerData;
+ if (!spriteInfo[battlerId].transformSpecies)
+ personality = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerId]], MON_DATA_PERSONALITY);
+ else
+ personality = gTransformedPersonalities[battlerId];
+ letter = GET_UNOWN_LETTER(personality);
+ if (!letter)
+ coordSpecies = species;
+ else
+ coordSpecies = letter + SPECIES_UNOWN_B - 1;
+ ret = gMonFrontPicCoords[coordSpecies].y_offset;
+ }
+ else if (species == SPECIES_CASTFORM)
+ {
+ ret = gCastformFrontSpriteCoords[gBattleMonForms[battlerId]].y_offset;
+ }
+ else if (species > NUM_SPECIES)
+ {
+ ret = gMonFrontPicCoords[0].y_offset;
+ }
+ else
+ {
+ ret = gMonFrontPicCoords[species].y_offset;
+ }
+ }
+ return ret;
+}
+
+static u8 GetBattlerElevation(u8 battlerId, u16 species)
+{
+ u8 ret = 0;
+
+ if (GetBattlerSide(battlerId) == B_SIDE_OPPONENT)
+ {
+ if (species == SPECIES_CASTFORM)
+ ret = sCastformElevations[gBattleMonForms[battlerId]];
+ else if (species > NUM_SPECIES)
+ ret = gEnemyMonElevation[0];
+ else
+ ret = gEnemyMonElevation[species];
+ }
+ return ret;
+}
+
+static u8 GetBattlerSpriteFinal_Y(u8 battlerId, u16 species, bool8 a3)
+{
+ u16 offset;
+ u8 y;
+
+ if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
+ {
+ offset = GetBattlerYDelta(battlerId, species);
+ }
+ else
+ {
+ offset = GetBattlerYDelta(battlerId, species);
+ offset -= GetBattlerElevation(battlerId, species);
+ }
+ y = offset + sBattlerCoords[IS_DOUBLE_BATTLE()][GetBattlerPosition(battlerId)].y;
+ if (a3)
+ {
+ if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
+ y += 8;
+ if (y > 104)
+ y = 104;
+ }
+ return y;
+}
+
+u8 GetBattlerSpriteCoord2(u8 battlerId, u8 coordType)
+{
+ u16 species;
+ struct BattleSpriteInfo *spriteInfo;
+
+ if (coordType == BATTLER_COORD_Y_PIC_OFFSET || coordType == BATTLER_COORD_Y_PIC_OFFSET_DEFAULT)
+ {
+ spriteInfo = gBattleSpritesDataPtr->battlerData;
+ if (!spriteInfo[battlerId].transformSpecies)
+ species = gAnimBattlerSpecies[battlerId];
+ else
+ species = spriteInfo[battlerId].transformSpecies;
+ if (coordType == BATTLER_COORD_Y_PIC_OFFSET)
+ return GetBattlerSpriteFinal_Y(battlerId, species, TRUE);
+ else
+ return GetBattlerSpriteFinal_Y(battlerId, species, FALSE);
+ }
+ else
+ {
+ return GetBattlerSpriteCoord(battlerId, coordType);
+ }
+}
+
+u8 GetBattlerSpriteDefault_Y(u8 battlerId)
+{
+ return GetBattlerSpriteCoord(battlerId, BATTLER_COORD_Y_PIC_OFFSET_DEFAULT);
+}
+
+u8 GetSubstituteSpriteDefault_Y(u8 battlerId)
+{
+ u16 y;
+
+ if (GetBattlerSide(battlerId) != B_SIDE_PLAYER)
+ y = GetBattlerSpriteCoord(battlerId, BATTLER_COORD_Y) + 16;
+ else
+ y = GetBattlerSpriteCoord(battlerId, BATTLER_COORD_Y) + 17;
+ return y;
+}
+
+u8 GetGhostSpriteDefault_Y(u8 battlerId)
+{
+ if (GetBattlerSide(battlerId) != B_SIDE_OPPONENT)
+ return GetBattlerSpriteCoord(battlerId, BATTLER_COORD_Y_PIC_OFFSET_DEFAULT);
+ else
+ return GetBattlerSpriteCoord(battlerId, BATTLER_COORD_Y);
+}
+
+u8 GetBattlerYCoordWithElevation(u8 battlerId)
+{
+ u16 species;
+ u8 y;
+ struct BattleSpriteInfo *spriteInfo;
+
+ y = GetBattlerSpriteCoord(battlerId, BATTLER_COORD_Y);
+ if (GetBattlerSide(battlerId) != B_SIDE_PLAYER)
+ {
+ spriteInfo = gBattleSpritesDataPtr->battlerData;
+ if (!spriteInfo[battlerId].transformSpecies)
+ species = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES);
+ else
+ species = spriteInfo[battlerId].transformSpecies;
+ }
+ else
+ {
+ spriteInfo = gBattleSpritesDataPtr->battlerData;
+ if (!spriteInfo[battlerId].transformSpecies)
+ species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES);
+ else
+ species = spriteInfo[battlerId].transformSpecies;
+ }
+ if (GetBattlerSide(battlerId) != B_SIDE_PLAYER)
+ y -= GetBattlerElevation(battlerId, species);
+ return y;
+}
+
+u8 GetAnimBattlerSpriteId(u8 animBattler)
+{
+ u8 *sprites;
+
+ if (animBattler == ANIM_ATTACKER)
+ {
+ if (IsBattlerSpritePresent(gBattleAnimAttacker))
+ {
+ sprites = gBattlerSpriteIds;
+ return sprites[gBattleAnimAttacker];
+ }
+ else
+ {
+ return 0xFF;
+ }
+ }
+ else if (animBattler == ANIM_TARGET)
+ {
+ if (IsBattlerSpritePresent(gBattleAnimTarget))
+ {
+ sprites = gBattlerSpriteIds;
+ return sprites[gBattleAnimTarget];
+ }
+ else
+ {
+ return 0xFF;
+ }
+ }
+ else if (animBattler == ANIM_ATK_PARTNER)
+ {
+ if (!IsBattlerSpriteVisible(BATTLE_PARTNER(gBattleAnimAttacker)))
+ return 0xFF;
+ else
+ return gBattlerSpriteIds[BATTLE_PARTNER(gBattleAnimAttacker)];
+ }
+ else
+ {
+ if (IsBattlerSpriteVisible(BATTLE_PARTNER(gBattleAnimTarget)))
+ return gBattlerSpriteIds[BATTLE_PARTNER(gBattleAnimTarget)];
+ else
+ return 0xFF;
+ }
+}
+
+void StoreSpriteCallbackInData6(struct Sprite *sprite, SpriteCallback callback)
+{
+ sprite->data[6] = (u32)(callback) & 0xFFFF;
+ sprite->data[7] = (u32)(callback) >> 16;
+}
+
+static void SetCallbackToStoredInData6(struct Sprite *sprite)
+{
+ u32 callback = (u16)sprite->data[6] | (sprite->data[7] << 16);
+
+ sprite->callback = (SpriteCallback)callback;
+}
+
+void TranslateSpriteInCircleOverDuration(struct Sprite *sprite)
+{
+ if (sprite->data[3])
+ {
+ sprite->pos2.x = Sin(sprite->data[0], sprite->data[1]);
+ sprite->pos2.y = Cos(sprite->data[0], sprite->data[1]);
+ sprite->data[0] += sprite->data[2];
+ if (sprite->data[0] >= 0x100)
+ sprite->data[0] -= 0x100;
+ else if (sprite->data[0] < 0)
+ sprite->data[0] += 0x100;
+ --sprite->data[3];
+ }
+ else
+ {
+ SetCallbackToStoredInData6(sprite);
+ }
+}
+
+void TranslateSpriteInGrowingCircleOverDuration(struct Sprite *sprite)
+{
+ if (sprite->data[3])
+ {
+ sprite->pos2.x = Sin(sprite->data[0], (sprite->data[5] >> 8) + sprite->data[1]);
+ sprite->pos2.y = Cos(sprite->data[0], (sprite->data[5] >> 8) + sprite->data[1]);
+ sprite->data[0] += sprite->data[2];
+ sprite->data[5] += sprite->data[4];
+ if (sprite->data[0] >= 0x100)
+ sprite->data[0] -= 0x100;
+ else if (sprite->data[0] < 0)
+ sprite->data[0] += 0x100;
+ --sprite->data[3];
+ }
+ else
+ {
+ SetCallbackToStoredInData6(sprite);
+ }
+}
+
+// not used
+static void sub_8074B5C(struct Sprite *sprite)
+{
+ if (sprite->data[3])
+ {
+ sprite->pos2.x = Sin(sprite->data[0], sprite->data[1]);
+ sprite->pos2.y = Cos(sprite->data[4], sprite->data[1]);
+ sprite->data[0] += sprite->data[2];
+ sprite->data[4] += sprite->data[5];
+ if (sprite->data[0] >= 0x100)
+ sprite->data[0] -= 0x100;
+ else if (sprite->data[0] < 0)
+ sprite->data[0] += 0x100;
+ if (sprite->data[4] >= 0x100)
+ sprite->data[4] -= 0x100;
+ else if (sprite->data[4] < 0)
+ sprite->data[4] += 0x100;
+ --sprite->data[3];
+ }
+ else
+ {
+ SetCallbackToStoredInData6(sprite);
+ }
+}
+
+void TranslateSpriteInEllipseOverDuration(struct Sprite *sprite)
+{
+ if (sprite->data[3])
+ {
+ sprite->pos2.x = Sin(sprite->data[0], sprite->data[1]);
+ sprite->pos2.y = Cos(sprite->data[0], sprite->data[4]);
+ sprite->data[0] += sprite->data[2];
+ if (sprite->data[0] >= 0x100)
+ sprite->data[0] -= 0x100;
+ else if (sprite->data[0] < 0)
+ sprite->data[0] += 0x100;
+ --sprite->data[3];
+ }
+ else
+ {
+ SetCallbackToStoredInData6(sprite);
+ }
+}
+
+// Simply waits until the sprite's data[0] hits zero.
+// This is used to let sprite anims or affine anims to run for a designated
+// duration.
+void WaitAnimForDuration(struct Sprite *sprite)
+{
+ if (sprite->data[0] > 0)
+ --sprite->data[0];
+ else
+ SetCallbackToStoredInData6(sprite);
+}
+
+static void sub_8074C64(struct Sprite *sprite)
+{
+ sub_8074C80(sprite);
+ sprite->callback = TranslateSpriteLinear;
+ sprite->callback(sprite);
+}
+
+void sub_8074C80(struct Sprite *sprite)
+{
+ s16 old;
+ s32 xDiff;
+
+ if (sprite->data[1] > sprite->data[2])
+ sprite->data[0] = -sprite->data[0];
+ xDiff = sprite->data[2] - sprite->data[1];
+ old = sprite->data[0];
+ sprite->data[0] = abs(xDiff / sprite->data[0]);
+ sprite->data[2] = (sprite->data[4] - sprite->data[3]) / sprite->data[0];
+ sprite->data[1] = old;
+}
+
+void TranslateSpriteLinear(struct Sprite *sprite)
+{
+ if (sprite->data[0] > 0)
+ {
+ --sprite->data[0];
+ sprite->pos2.x += sprite->data[1];
+ sprite->pos2.y += sprite->data[2];
+ }
+ else
+ {
+ SetCallbackToStoredInData6(sprite);
+ }
+}
+
+void TranslateSpriteLinearFixedPoint(struct Sprite *sprite)
+{
+ if (sprite->data[0] > 0)
+ {
+ --sprite->data[0];
+ sprite->data[3] += sprite->data[1];
+ sprite->data[4] += sprite->data[2];
+ sprite->pos2.x = sprite->data[3] >> 8;
+ sprite->pos2.y = sprite->data[4] >> 8;
+ }
+ else
+ {
+ SetCallbackToStoredInData6(sprite);
+ }
+}
+
+static void TranslateSpriteLinearFixedPointIconFrame(struct Sprite *sprite)
+{
+ if (sprite->data[0] > 0)
+ {
+ --sprite->data[0];
+ sprite->data[3] += sprite->data[1];
+ sprite->data[4] += sprite->data[2];
+ sprite->pos2.x = sprite->data[3] >> 8;
+ sprite->pos2.y = sprite->data[4] >> 8;
+ }
+ else
+ {
+ SetCallbackToStoredInData6(sprite);
+ }
+
+ UpdateMonIconFrame(sprite);
+}
+
+// not used
+static void sub_8074D80(struct Sprite *sprite)
+{
+ sprite->data[1] = sprite->pos1.x + sprite->pos2.x;
+ sprite->data[3] = sprite->pos1.y + sprite->pos2.y;
+ sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2);
+ sprite->data[4] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y_PIC_OFFSET);
+ sprite->callback = sub_8074C64;
+}
+
+void TranslateMonSpriteLinear(struct Sprite *sprite)
+{
+ if (sprite->data[0] > 0)
+ {
+ --sprite->data[0];
+ gSprites[sprite->data[3]].pos2.x += sprite->data[1];
+ gSprites[sprite->data[3]].pos2.y += sprite->data[2];
+ }
+ else
+ {
+ SetCallbackToStoredInData6(sprite);
+ }
+}
+
+void TranslateMonSpriteLinearFixedPoint(struct Sprite *sprite)
+{
+ if (sprite->data[0] > 0)
+ {
+ --sprite->data[0];
+ sprite->data[3] += sprite->data[1];
+ sprite->data[4] += sprite->data[2];
+ gSprites[sprite->data[5]].pos2.x = sprite->data[3] >> 8;
+ gSprites[sprite->data[5]].pos2.y = sprite->data[4] >> 8;
+ }
+ else
+ {
+ SetCallbackToStoredInData6(sprite);
+ }
+}
+
+void TranslateSpriteLinearAndFlicker(struct Sprite *sprite)
+{
+ if (sprite->data[0] > 0)
+ {
+ --sprite->data[0];
+ sprite->pos2.x = sprite->data[2] >> 8;
+ sprite->data[2] += sprite->data[1];
+ sprite->pos2.y = sprite->data[4] >> 8;
+ sprite->data[4] += sprite->data[3];
+ if (sprite->data[0] % sprite->data[5] == 0)
+ {
+ if (sprite->data[5])
+ sprite->invisible ^= 1;
+ }
+ }
+ else
+ {
+ SetCallbackToStoredInData6(sprite);
+ }
+}
+
+void DestroySpriteAndMatrix(struct Sprite *sprite)
+{
+ FreeSpriteOamMatrix(sprite);
+ DestroyAnimSprite(sprite);
+}
+
+// not used
+static void sub_8074EF4(struct Sprite *sprite)
+{
+ sprite->data[1] = sprite->pos1.x + sprite->pos2.x;
+ sprite->data[3] = sprite->pos1.y + sprite->pos2.y;
+ sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_X_2);
+ sprite->data[4] = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_Y_PIC_OFFSET);
+ sprite->callback = sub_8074C64;
+}
+
+// not used
+static void sub_8074F38(struct Sprite *sprite)
+{
+ ResetPaletteStructByUid(sprite->data[5]);
+ DestroySpriteAndMatrix(sprite);
+}
+
+void RunStoredCallbackWhenAffineAnimEnds(struct Sprite *sprite)
+{
+ if (sprite->affineAnimEnded)
+ SetCallbackToStoredInData6(sprite);
+}
+
+void RunStoredCallbackWhenAnimEnds(struct Sprite *sprite)
+{
+ if (sprite->animEnded)
+ SetCallbackToStoredInData6(sprite);
+}
+
+void DestroyAnimSpriteAndDisableBlend(struct Sprite *sprite)
+{
+ SetGpuReg(REG_OFFSET_BLDCNT, 0);
+ SetGpuReg(REG_OFFSET_BLDALPHA, 0);
+ DestroyAnimSprite(sprite);
+}
+
+void DestroyAnimVisualTaskAndDisableBlend(u8 taskId)
+{
+ SetGpuReg(REG_OFFSET_BLDCNT, 0);
+ SetGpuReg(REG_OFFSET_BLDALPHA, 0);
+ DestroyAnimVisualTask(taskId);
+}
+
+void SetSpriteCoordsToAnimAttackerCoords(struct Sprite *sprite)
+{
+ sprite->pos1.x = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_X_2);
+ sprite->pos1.y = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_Y_PIC_OFFSET);
+}
+
+// Sets the initial x offset of the anim sprite depending on the horizontal orientation
+// of the two involved mons.
+void SetAnimSpriteInitialXOffset(struct Sprite *sprite, s16 xOffset)
+{
+ u16 attackerX = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_X);
+ u16 targetX = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X);
+
+ if (attackerX > targetX)
+ {
+ sprite->pos1.x -= xOffset;
+ }
+ else if (attackerX < targetX)
+ {
+ sprite->pos1.x += xOffset;
+ }
+ else
+ {
+ if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
+ sprite->pos1.x -= xOffset;
+ else
+ sprite->pos1.x += xOffset;
+ }
+}
+
+void InitAnimArcTranslation(struct Sprite *sprite)
+{
+ sprite->data[1] = sprite->pos1.x;
+ sprite->data[3] = sprite->pos1.y;
+ InitAnimLinearTranslation(sprite);
+ sprite->data[6] = 0x8000 / sprite->data[0];
+ sprite->data[7] = 0;
+}
+
+bool8 TranslateAnimHorizontalArc(struct Sprite *sprite)
+{
+ if (AnimTranslateLinear(sprite))
+ return TRUE;
+ sprite->data[7] += sprite->data[6];
+ sprite->pos2.y += Sin((u8)(sprite->data[7] >> 8), sprite->data[5]);
+ return FALSE;
+}
+
+bool8 TranslateAnimVerticalArc(struct Sprite *sprite)
+{
+ if (AnimTranslateLinear(sprite))
+ return TRUE;
+ sprite->data[7] += sprite->data[6];
+ sprite->pos2.x += Sin((u8)(sprite->data[7] >> 8), sprite->data[5]);
+ return FALSE;
+}
+
+void SetSpritePrimaryCoordsFromSecondaryCoords(struct Sprite *sprite)
+{
+ sprite->pos1.x += sprite->pos2.x;
+ sprite->pos1.y += sprite->pos2.y;
+ sprite->pos2.x = 0;
+ sprite->pos2.y = 0;
+}
+
+void InitSpritePosToAnimTarget(struct Sprite *sprite, bool8 respectMonPicOffsets)
+{
+ // Battle anim sprites are automatically created at the anim target's center, which
+ // is why there is no else clause for the "respectMonPicOffsets" check.
+ if (!respectMonPicOffsets)
+ {
+ sprite->pos1.x = GetBattlerSpriteCoord2(gBattleAnimTarget, BATTLER_COORD_X);
+ sprite->pos1.y = GetBattlerSpriteCoord2(gBattleAnimTarget, BATTLER_COORD_Y);
+ }
+ SetAnimSpriteInitialXOffset(sprite, gBattleAnimArgs[0]);
+ sprite->pos1.y += gBattleAnimArgs[1];
+}
+
+void InitSpritePosToAnimAttacker(struct Sprite *sprite, bool8 respectMonPicOffsets)
+{
+ if (!respectMonPicOffsets)
+ {
+ sprite->pos1.x = GetBattlerSpriteCoord2(gBattleAnimAttacker, BATTLER_COORD_X);
+ sprite->pos1.y = GetBattlerSpriteCoord2(gBattleAnimAttacker, BATTLER_COORD_Y);
+ }
+ else
+ {
+ sprite->pos1.x = GetBattlerSpriteCoord2(gBattleAnimAttacker, BATTLER_COORD_X_2);
+ sprite->pos1.y = GetBattlerSpriteCoord2(gBattleAnimAttacker, BATTLER_COORD_Y_PIC_OFFSET);
+ }
+ SetAnimSpriteInitialXOffset(sprite, gBattleAnimArgs[0]);
+ sprite->pos1.y += gBattleAnimArgs[1];
+}
+
+u8 GetBattlerSide(u8 battlerId)
+{
+ return GET_BATTLER_SIDE2(battlerId);
+}
+
+u8 GetBattlerPosition(u8 battlerId)
+{
+ return GET_BATTLER_POSITION(battlerId);
+}
+
+u8 GetBattlerAtPosition(u8 position)
+{
+ u8 i;
+
+ for (i = 0; i < gBattlersCount; ++i)
+ if (gBattlerPositions[i] == position)
+ break;
+ return i;
+}
+
+bool8 IsBattlerSpritePresent(u8 battlerId)
+{
+ if (gBattlerPositions[battlerId] == 0xFF)
+ {
+ return FALSE;
+ }
+ else if (GetBattlerSide(battlerId) != B_SIDE_PLAYER)
+ {
+ if (GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerId]], MON_DATA_HP) != 0)
+ return TRUE;
+ }
+ else
+ {
+ if (GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_HP) != 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+bool8 IsDoubleBattle(void)
+{
+ return IS_DOUBLE_BATTLE();
+}
+
+void sub_80752A0(struct BattleAnimBgData *animBgData)
+{
+ animBgData->bgTiles = gUnknown_2022BB8;
+ animBgData->bgTilemap = (u16 *)gUnknown_2022BBC;
+ animBgData->paletteId = 8;
+ animBgData->bgId = 1;
+ animBgData->tilesOffset = 0x200;
+ animBgData->unused = 0;
+}
+
+void sub_80752C8(struct BattleAnimBgData *animBgData, u32 arg1)
+{
+ if (arg1 == 1)
+ {
+ sub_80752A0(animBgData);
+ }
+ else
+ {
+ animBgData->bgTiles = gUnknown_2022BB8;
+ animBgData->bgTilemap = (u16 *)gUnknown_2022BBC;
+ animBgData->paletteId = 9;
+ animBgData->bgId = 2;
+ animBgData->tilesOffset = 0x300;
+ animBgData->unused = 0;
+ }
+}
+
+void sub_8075300(struct BattleAnimBgData *animBgData, u8 unused)
+{
+ animBgData->bgTiles = gUnknown_2022BB8;
+ animBgData->bgTilemap = (u16 *)gUnknown_2022BBC;
+ if (GetBattlerSpriteBGPriorityRank(gBattleAnimAttacker) == 1)
+ {
+ animBgData->paletteId = 8;
+ animBgData->bgId = 1;
+ animBgData->tilesOffset = 0x200;
+ animBgData->unused = 0;
+ }
+ else
+ {
+ animBgData->paletteId = 9;
+ animBgData->bgId = 2;
+ animBgData->tilesOffset = 0x300;
+ animBgData->unused = 0;
+ }
+}
+
+void sub_8075358(u32 bgId)
+{
+ struct BattleAnimBgData animBgData;
+
+ sub_80752C8(&animBgData, bgId);
+ CpuFill32(0, animBgData.bgTiles, 0x2000);
+ LoadBgTiles(bgId, animBgData.bgTiles, 0x2000, animBgData.tilesOffset);
+ FillBgTilemapBufferRect(bgId, 0, 0, 0, 32, 64, 17);
+ CopyBgTilemapBufferToVram(bgId);
+}
+
+void AnimLoadCompressedBgGfx(u32 bgId, const u32 *src, u32 tilesOffset)
+{
+ CpuFill32(0, gUnknown_2022BB8, 0x2000);
+ LZDecompressWram(src, gUnknown_2022BB8);
+ LoadBgTiles(bgId, gUnknown_2022BB8, 0x2000, tilesOffset);
+}
+
+void InitAnimBgTilemapBuffer(u32 bgId, const void *src)
+{
+ FillBgTilemapBufferRect(bgId, 0, 0, 0, 32, 64, 17);
+ CopyToBgTilemapBuffer(bgId, src, 0, 0);
+}
+
+void AnimLoadCompressedBgTilemap(u32 bgId, const u32 *src)
+{
+ InitAnimBgTilemapBuffer(bgId, src);
+ CopyBgTilemapBufferToVram(bgId);
+}
+
+u8 sub_8075454(void)
+{
+ return 2;
+}
+
+void sub_8075458(bool8 arg0)
+{
+ if (!arg0)
+ {
+ SetAnimBgAttribute(3, BG_ANIM_SCREEN_SIZE, 0);
+ SetAnimBgAttribute(3, BG_ANIM_AREA_OVERFLOW_MODE, 1);
+ }
+ else
+ {
+ SetAnimBgAttribute(3, BG_ANIM_SCREEN_SIZE, 1);
+ SetAnimBgAttribute(3, BG_ANIM_AREA_OVERFLOW_MODE, 0);
+ }
+}
+
+void sub_8075490(struct Sprite *sprite)
+{
+ sprite->data[1] = sprite->pos1.x;
+ sprite->data[3] = sprite->pos1.y;
+ InitSpriteDataForLinearTranslation(sprite);
+ sprite->callback = TranslateSpriteLinearFixedPointIconFrame;
+ sprite->callback(sprite);
+}
+
+void InitSpriteDataForLinearTranslation(struct Sprite *sprite)
+{
+ s16 x = (sprite->data[2] - sprite->data[1]) << 8;
+ s16 y = (sprite->data[4] - sprite->data[3]) << 8;
+
+ sprite->data[1] = x / sprite->data[0];
+ sprite->data[2] = y / sprite->data[0];
+ sprite->data[4] = 0;
+ sprite->data[3] = 0;
+}
+
+void InitAnimLinearTranslation(struct Sprite *sprite)
+{
+ s32 x = sprite->data[2] - sprite->data[1];
+ s32 y = sprite->data[4] - sprite->data[3];
+ bool8 movingLeft = x < 0;
+ bool8 movingUp = y < 0;
+ u16 xDelta = abs(x) << 8;
+ u16 yDelta = abs(y) << 8;
+
+ xDelta = xDelta / sprite->data[0];
+ yDelta = yDelta / sprite->data[0];
+
+ if (movingLeft)
+ xDelta |= 1;
+ else
+ xDelta &= ~1;
+
+ if (movingUp)
+ yDelta |= 1;
+ else
+ yDelta &= ~1;
+
+ sprite->data[1] = xDelta;
+ sprite->data[2] = yDelta;
+ sprite->data[4] = 0;
+ sprite->data[3] = 0;
+}
+
+void StartAnimLinearTranslation(struct Sprite *sprite)
+{
+ sprite->data[1] = sprite->pos1.x;
+ sprite->data[3] = sprite->pos1.y;
+ InitAnimLinearTranslation(sprite);
+ sprite->callback = sub_807563C;
+ sprite->callback(sprite);
+}
+
+void sub_80755B8(struct Sprite *sprite)
+{
+ sprite->data[1] = sprite->pos1.x;
+ sprite->data[3] = sprite->pos1.y;
+ InitAnimLinearTranslation(sprite);
+ sprite->callback = sub_8075658;
+ sprite->callback(sprite);
+}
+
+bool8 AnimTranslateLinear(struct Sprite *sprite)
+{
+ u16 v1, v2, x, y;
+
+ if (!sprite->data[0])
+ return TRUE;
+ v1 = sprite->data[1];
+ v2 = sprite->data[2];
+ x = sprite->data[3];
+ y = sprite->data[4];
+ x += v1;
+ y += v2;
+ if (v1 & 1)
+ sprite->pos2.x = -(x >> 8);
+ else
+ sprite->pos2.x = x >> 8;
+
+ if (v2 & 1)
+ sprite->pos2.y = -(y >> 8);
+ else
+ sprite->pos2.y = y >> 8;
+ sprite->data[3] = x;
+ sprite->data[4] = y;
+ --sprite->data[0];
+ return FALSE;
+}
+
+void sub_807563C(struct Sprite *sprite)
+{
+ if (AnimTranslateLinear(sprite))
+ SetCallbackToStoredInData6(sprite);
+}
+
+static void sub_8075658(struct Sprite *sprite)
+{
+ sub_801236C(sprite);
+ if (AnimTranslateLinear(sprite))
+ SetCallbackToStoredInData6(sprite);
+}
+
+void sub_8075678(struct Sprite *sprite)
+{
+ s32 v1 = abs(sprite->data[2] - sprite->data[1]) << 8;
+
+ sprite->data[0] = v1 / sprite->data[0];
+ InitAnimLinearTranslation(sprite);
+}
+
+void sub_80756A4(struct Sprite *sprite)
+{
+ sprite->data[1] = sprite->pos1.x;
+ sprite->data[3] = sprite->pos1.y;
+ sub_8075678(sprite);
+ sprite->callback = sub_807563C;
+ sprite->callback(sprite);
+}
+
+static void InitAnimFastLinearTranslation(struct Sprite *sprite)
+{
+ s32 xDiff = sprite->data[2] - sprite->data[1];
+ s32 yDiff = sprite->data[4] - sprite->data[3];
+ bool8 xSign = xDiff < 0;
+ bool8 ySign = yDiff < 0;
+ u16 x2 = abs(xDiff) << 4;
+ u16 y2 = abs(yDiff) << 4;
+
+ x2 /= sprite->data[0];
+ y2 /= sprite->data[0];
+ if (xSign)
+ x2 |= 1;
+ else
+ x2 &= ~1;
+ if (ySign)
+ y2 |= 1;
+ else
+ y2 &= ~1;
+ sprite->data[1] = x2;
+ sprite->data[2] = y2;
+ sprite->data[4] = 0;
+ sprite->data[3] = 0;
+}
+
+void InitAndRunAnimFastLinearTranslation(struct Sprite *sprite)
+{
+ sprite->data[1] = sprite->pos1.x;
+ sprite->data[3] = sprite->pos1.y;
+ InitAnimFastLinearTranslation(sprite);
+ sprite->callback = sub_80757E8;
+ sprite->callback(sprite);
+}
+
+bool8 AnimFastTranslateLinear(struct Sprite *sprite)
+{
+ u16 v1, v2, x, y;
+
+ if (!sprite->data[0])
+ return TRUE;
+ v1 = sprite->data[1];
+ v2 = sprite->data[2];
+ x = sprite->data[3];
+ y = sprite->data[4];
+ x += v1;
+ y += v2;
+ if (v1 & 1)
+ sprite->pos2.x = -(x >> 4);
+ else
+ sprite->pos2.x = x >> 4;
+ if (v2 & 1)
+ sprite->pos2.y = -(y >> 4);
+ else
+ sprite->pos2.y = y >> 4;
+ sprite->data[3] = x;
+ sprite->data[4] = y;
+ --sprite->data[0];
+ return FALSE;
+}
+
+static void sub_80757E8(struct Sprite *sprite)
+{
+ if (AnimFastTranslateLinear(sprite))
+ SetCallbackToStoredInData6(sprite);
+}
+
+void InitAnimFastLinearTranslationWithSpeed(struct Sprite *sprite)
+{
+ s32 xDiff = abs(sprite->data[2] - sprite->data[1]) << 4;
+
+ sprite->data[0] = xDiff / sprite->data[0];
+ InitAnimFastLinearTranslation(sprite);
+}
+
+void sub_8075830(struct Sprite *sprite)
+{
+ sprite->data[1] = sprite->pos1.x;
+ sprite->data[3] = sprite->pos1.y;
+ InitAnimFastLinearTranslationWithSpeed(sprite);
+ sprite->callback = sub_80757E8;
+ sprite->callback(sprite);
+}
+
+void SetSpriteRotScale(u8 spriteId, s16 xScale, s16 yScale, u16 rotation)
+{
+ s32 i;
+ struct ObjAffineSrcData src;
+ struct OamMatrix matrix;
+
+ src.xScale = xScale;
+ src.yScale = yScale;
+ src.rotation = rotation;
+ if (sub_80758DC())
+ src.xScale = -src.xScale;
+ i = gSprites[spriteId].oam.matrixNum;
+ ObjAffineSet(&src, &matrix, 1, 2);
+ gOamMatrices[i].a = matrix.a;
+ gOamMatrices[i].b = matrix.b;
+ gOamMatrices[i].c = matrix.c;
+ gOamMatrices[i].d = matrix.d;
+}
+
+static bool8 sub_80758DC(void)
+{
+ return FALSE;
+}
+
+void PrepareBattlerSpriteForRotScale(u8 spriteId, u8 objMode)
+{
+ u8 battlerId = gSprites[spriteId].data[0];
+
+ if (IsBattlerSpriteVisible(battlerId))
+ gSprites[spriteId].invisible = FALSE;
+ gSprites[spriteId].oam.objMode = objMode;
+ gSprites[spriteId].affineAnimPaused = TRUE;
+ if (!gSprites[spriteId].oam.affineMode)
+ gSprites[spriteId].oam.matrixNum = gBattleSpritesDataPtr->healthBoxesData[battlerId].matrixNum;
+ gSprites[spriteId].oam.affineMode = ST_OAM_AFFINE_DOUBLE;
+ CalcCenterToCornerVec(&gSprites[spriteId], gSprites[spriteId].oam.shape, gSprites[spriteId].oam.size, gSprites[spriteId].oam.affineMode);
+}
+
+void ResetSpriteRotScale(u8 spriteId)
+{
+ SetSpriteRotScale(spriteId, 0x100, 0x100, 0);
+ gSprites[spriteId].oam.affineMode = ST_OAM_AFFINE_NORMAL;
+ gSprites[spriteId].oam.objMode = 0;
+ gSprites[spriteId].affineAnimPaused = FALSE;
+ CalcCenterToCornerVec(&gSprites[spriteId], gSprites[spriteId].oam.shape, gSprites[spriteId].oam.size, gSprites[spriteId].oam.affineMode);
+}
+
+// Sets the sprite's y offset equal to the y displacement caused by the
+// matrix's rotation.
+void SetBattlerSpriteYOffsetFromRotation(u8 spriteId)
+{
+ u16 matrixNum = gSprites[spriteId].oam.matrixNum;
+ // The "c" component of the battler sprite matrix contains the sine of the rotation angle divided by some scale amount.
+ s16 c = gOamMatrices[matrixNum].c;
+
+ if (c < 0)
+ c = -c;
+ gSprites[spriteId].pos2.y = c >> 3;
+}
+
+void TrySetSpriteRotScale(struct Sprite *sprite, bool8 recalcCenterVector, s16 xScale, s16 yScale, u16 rotation)
+{
+ s32 i;
+ struct ObjAffineSrcData src;
+ struct OamMatrix matrix;
+
+ if (sprite->oam.affineMode & 1)
+ {
+ sprite->affineAnimPaused = TRUE;
+ if (recalcCenterVector)
+ CalcCenterToCornerVec(sprite, sprite->oam.shape, sprite->oam.size, sprite->oam.affineMode);
+ src.xScale = xScale;
+ src.yScale = yScale;
+ src.rotation = rotation;
+ if (sub_80758DC())
+ src.xScale = -src.xScale;
+ i = sprite->oam.matrixNum;
+ ObjAffineSet(&src, &matrix, 1, 2);
+ gOamMatrices[i].a = matrix.a;
+ gOamMatrices[i].b = matrix.b;
+ gOamMatrices[i].c = matrix.c;
+ gOamMatrices[i].d = matrix.d;
+ }
+}
+
+void sub_8075AD8(struct Sprite *sprite)
+{
+ TrySetSpriteRotScale(sprite, TRUE, 0x100, 0x100, 0);
+ sprite->affineAnimPaused = FALSE;
+ CalcCenterToCornerVec(sprite, sprite->oam.shape, sprite->oam.size, sprite->oam.affineMode);
+}
+
+static u16 ArcTan2_(s16 a, s16 b)
+{
+ return ArcTan2(a, b);
+}
+
+u16 ArcTan2Neg(s16 a, s16 b)
+{
+ u16 var = ArcTan2_(a, b);
+ return -var;
+}
+
+void SetGreyscaleOrOriginalPalette(u16 paletteNum, bool8 restoreOriginalColor)
+{
+ s32 i;
+ struct PlttData *originalColor;
+ struct PlttData *destColor;
+ u16 average;
+
+ paletteNum *= 16;
+
+ if (!restoreOriginalColor)
+ {
+ for (i = 0; i < 16; ++i)
+ {
+ originalColor = (struct PlttData *)&gPlttBufferUnfaded[paletteNum + i];
+ average = originalColor->r + originalColor->g + originalColor->b;
+ average /= 3;
+ destColor = (struct PlttData *)&gPlttBufferFaded[paletteNum + i];
+ destColor->r = average;
+ destColor->g = average;
+ destColor->b = average;
+ }
+ }
+ else
+ {
+ CpuCopy32(&gPlttBufferUnfaded[paletteNum], &gPlttBufferFaded[paletteNum], 32);
+ }
+}
+
+u32 sub_8075BE8(u8 battleBackground, u8 attacker, u8 target, u8 attackerPartner, u8 targetPartner, u8 a6, u8 a7)
+{
+ u32 selectedPalettes = 0;
+ u32 shift;
+
+ if (battleBackground)
+ {
+ selectedPalettes = 0xe;
+ }
+ if (attacker)
+ {
+ shift = gBattleAnimAttacker + 16;
+ selectedPalettes |= 1 << shift;
+ }
+ if (target)
+ {
+ shift = gBattleAnimTarget + 16;
+ selectedPalettes |= 1 << shift;
+ }
+ if (attackerPartner)
+ {
+ if (IsBattlerSpriteVisible(BATTLE_PARTNER(gBattleAnimAttacker)))
+ {
+ shift = BATTLE_PARTNER(gBattleAnimAttacker) + 16;
+ selectedPalettes |= 1 << shift;
+ }
+ }
+ if (targetPartner)
+ {
+ if (IsBattlerSpriteVisible(BATTLE_PARTNER(gBattleAnimTarget)))
+ {
+ shift = BATTLE_PARTNER(gBattleAnimTarget) + 16;
+ selectedPalettes |= 1 << shift;
+ }
+ }
+ if (a6)
+ {
+ selectedPalettes |= 0x100;
+ }
+ if (a7)
+ {
+ selectedPalettes |= 0x200;
+ }
+ return selectedPalettes;
+}
+
+u32 sub_8075CB8(u8 a1, u8 a2, u8 a3, u8 a4)
+{
+ u32 var = 0;
+ u32 shift;
+
+ if (a1)
+ {
+ if (IsBattlerSpriteVisible(GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)))
+ {
+ var |= 1 << (GetBattlerAtPosition(B_POSITION_PLAYER_LEFT) + 16);
+ }
+ }
+ if (a2)
+ {
+ if (IsBattlerSpriteVisible(GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT)))
+ {
+ shift = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT) + 16;
+ var |= 1 << shift;
+ }
+ }
+ if (a3)
+ {
+ if (IsBattlerSpriteVisible(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT)))
+ {
+ shift = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT) + 16;
+ var |= 1 << shift;
+ }
+ }
+ if (a4)
+ {
+ if (IsBattlerSpriteVisible(GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT)))
+ {
+ shift = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT) + 16;
+ var |= 1 << shift;
+ }
+ }
+ return var;
+}
+
+u8 sub_8075D80(u8 a1)
+{
+ return a1;
+}
+
+// not used
+static u8 GetBattlerAtPosition_(u8 position)
+{
+ return GetBattlerAtPosition(position);
+}
+
+void sub_8075D9C(struct Sprite *sprite)
+{
+ bool8 var;
+
+ if (!sprite->data[0])
+ {
+ if (!gBattleAnimArgs[3])
+ var = TRUE;
+ else
+ var = FALSE;
+ if (!gBattleAnimArgs[2])
+ InitSpritePosToAnimAttacker(sprite, var);
+ else
+ InitSpritePosToAnimTarget(sprite, var);
+ ++sprite->data[0];
+
+ }
+ else if (sprite->animEnded || sprite->affineAnimEnded)
+ {
+ DestroySpriteAndMatrix(sprite);
+ }
+}
+
+// Linearly translates a sprite to a target position on the
+// other mon's sprite.
+// arg 0: initial x offset
+// arg 1: initial y offset
+// arg 2: target x offset
+// arg 3: target y offset
+// arg 4: duration
+// arg 5: lower 8 bits = location on attacking mon, upper 8 bits = location on target mon pick to target
+void TranslateAnimSpriteToTargetMonLocation(struct Sprite *sprite)
+{
+ bool8 v1;
+ u8 coordType;
+
+ if (!(gBattleAnimArgs[5] & 0xFF00))
+ v1 = TRUE;
+ else
+ v1 = FALSE;
+ if (!(gBattleAnimArgs[5] & 0xFF))
+ coordType = BATTLER_COORD_Y_PIC_OFFSET;
+ else
+ coordType = BATTLER_COORD_Y;
+ InitSpritePosToAnimAttacker(sprite, v1);
+ if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
+ gBattleAnimArgs[2] = -gBattleAnimArgs[2];
+ sprite->data[0] = gBattleAnimArgs[4];
+ sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2) + gBattleAnimArgs[2];
+ sprite->data[4] = GetBattlerSpriteCoord(gBattleAnimTarget, coordType) + gBattleAnimArgs[3];
+ sprite->callback = StartAnimLinearTranslation;
+ StoreSpriteCallbackInData6(sprite, DestroyAnimSprite);
+}
+
+void sub_8075E80(struct Sprite *sprite)
+{
+ InitSpritePosToAnimAttacker(sprite, 1);
+ if (GetBattlerSide(gBattleAnimAttacker))
+ gBattleAnimArgs[2] = -gBattleAnimArgs[2];
+ sprite->data[0] = gBattleAnimArgs[4];
+ sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2) + gBattleAnimArgs[2];
+ sprite->data[4] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y_PIC_OFFSET) + gBattleAnimArgs[3];
+ sprite->data[5] = gBattleAnimArgs[5];
+ InitAnimArcTranslation(sprite);
+ sprite->callback = sub_8075EF0;
+}
+
+static void sub_8075EF0(struct Sprite *sprite)
+{
+ if (TranslateAnimHorizontalArc(sprite))
+ DestroyAnimSprite(sprite);
+}
+
+void sub_8075F0C(struct Sprite *sprite)
+{
+ bool8 r4;
+ u8 battlerId, coordType;
+
+ if (!gBattleAnimArgs[6])
+ {
+ r4 = TRUE;
+ coordType = BATTLER_COORD_Y_PIC_OFFSET;
+ }
+ else
+ {
+ r4 = FALSE;
+ coordType = BATTLER_COORD_Y;
+ }
+ if (!gBattleAnimArgs[5])
+ {
+ InitSpritePosToAnimAttacker(sprite, r4);
+ battlerId = gBattleAnimAttacker;
+ }
+ else
+ {
+ InitSpritePosToAnimTarget(sprite, r4);
+ battlerId = gBattleAnimTarget;
+ }
+ if (GetBattlerSide(gBattleAnimAttacker))
+ gBattleAnimArgs[2] = -gBattleAnimArgs[2];
+ InitSpritePosToAnimTarget(sprite, r4);
+ sprite->data[0] = gBattleAnimArgs[4];
+ sprite->data[2] = GetBattlerSpriteCoord(battlerId, BATTLER_COORD_X_2) + gBattleAnimArgs[2];
+ sprite->data[4] = GetBattlerSpriteCoord(battlerId, coordType) + gBattleAnimArgs[3];
+ sprite->callback = StartAnimLinearTranslation;
+ StoreSpriteCallbackInData6(sprite, DestroyAnimSprite);
+}
+
+s16 CloneBattlerSpriteWithBlend(u8 animBattler)
+{
+ u16 i;
+ u8 spriteId = GetAnimBattlerSpriteId(animBattler);
+
+ if (spriteId != 0xFF)
+ {
+ for (i = 0; i < MAX_SPRITES; ++i)
+ {
+ if (!gSprites[i].inUse)
+ {
+ gSprites[i] = gSprites[spriteId];
+ gSprites[i].oam.objMode = ST_OAM_OBJ_BLEND;
+ gSprites[i].invisible = FALSE;
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+void obj_delete_but_dont_free_vram(struct Sprite *sprite)
+{
+ sprite->usingSheet = TRUE;
+ DestroySprite(sprite);
+}
+
+void sub_8076048(u8 taskId)
+{
+ s16 v1 = 0, v2 = 0;
+
+ if (gBattleAnimArgs[2] > gBattleAnimArgs[0])
+ v2 = 1;
+ if (gBattleAnimArgs[2] < gBattleAnimArgs[0])
+ v2 = -1;
+ if (gBattleAnimArgs[3] > gBattleAnimArgs[1])
+ v1 = 1;
+ if (gBattleAnimArgs[3] < gBattleAnimArgs[1])
+ v1 = -1;
+ gTasks[taskId].data[0] = 0;
+ gTasks[taskId].data[1] = gBattleAnimArgs[4];
+ gTasks[taskId].data[2] = 0;
+ gTasks[taskId].data[3] = gBattleAnimArgs[0];
+ gTasks[taskId].data[4] = gBattleAnimArgs[1];
+ gTasks[taskId].data[5] = v2;
+ gTasks[taskId].data[6] = v1;
+ gTasks[taskId].data[7] = gBattleAnimArgs[2];
+ gTasks[taskId].data[8] = gBattleAnimArgs[3];
+ SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(gBattleAnimArgs[0], gBattleAnimArgs[1]));
+ gTasks[taskId].func = sub_80760D0;
+}
+
+static void sub_80760D0(u8 taskId)
+{
+ struct Task *task = &gTasks[taskId];
+
+ if (++task->data[0] > task->data[1])
+ {
+ task->data[0] = 0;
+ if (++task->data[2] & 1)
+ {
+ if (task->data[3] != task->data[7])
+ task->data[3] += task->data[5];
+ }
+ else
+ {
+ if (task->data[4] != task->data[8])
+ task->data[4] += task->data[6];
+ }
+ SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(task->data[3], task->data[4]));
+ if (task->data[3] == task->data[7] && task->data[4] == task->data[8])
+ {
+ DestroyAnimVisualTask(taskId);
+ return;
+ }
+ }
+}
+
+// Linearly blends a mon's sprite colors with a target color with increasing
+// strength, and then blends out to the original color.
+// arg 0: anim bank
+// arg 1: blend color
+// arg 2: target blend coefficient
+// arg 3: initial delay
+// arg 4: number of times to blend in and out
+void AnimTask_BlendMonInAndOut(u8 task)
+{
+ u8 spriteId = GetAnimBattlerSpriteId(gBattleAnimArgs[0]);
+
+ if (spriteId == 0xFF)
+ {
+ DestroyAnimVisualTask(task);
+ return;
+ }
+ gTasks[task].data[0] = (gSprites[spriteId].oam.paletteNum * 0x10) + 0x101;
+ AnimTask_BlendMonInAndOutSetup(&gTasks[task]);
+}
+
+static void AnimTask_BlendMonInAndOutSetup(struct Task *task)
+{
+ task->data[1] = gBattleAnimArgs[1];
+ task->data[2] = 0;
+ task->data[3] = gBattleAnimArgs[2];
+ task->data[4] = 0;
+ task->data[5] = gBattleAnimArgs[3];
+ task->data[6] = 0;
+ task->data[7] = gBattleAnimArgs[4];
+ task->func = AnimTask_BlendMonInAndOutStep;
+}
+
+static void AnimTask_BlendMonInAndOutStep(u8 taskId)
+{
+ struct Task *task = &gTasks[taskId];
+
+ if (++task->data[4] >= task->data[5])
+ {
+ task->data[4] = 0;
+ if (!task->data[6])
+ {
+ ++task->data[2];
+ BlendPalette(task->data[0], 15, task->data[2], task->data[1]);
+ if (task->data[2] == task->data[3])
+ task->data[6] = 1;
+ }
+ else
+ {
+ --task->data[2];
+ BlendPalette(task->data[0], 15, task->data[2], task->data[1]);
+ if (!task->data[2])
+ {
+ if (--task->data[7])
+ {
+ task->data[4] = 0;
+ task->data[6] = 0;
+ }
+ else
+ {
+ DestroyAnimVisualTask(taskId);
+ return;
+ }
+ }
+ }
+ }
+}
+
+void sub_8076288(u8 taskId)
+{
+ u8 palette = IndexOfSpritePaletteTag(gBattleAnimArgs[0]);
+
+ if (palette == 0xFF)
+ {
+ DestroyAnimVisualTask(taskId);
+ return;
+ }
+ gTasks[taskId].data[0] = (palette * 0x10) + 0x101;
+ AnimTask_BlendMonInAndOutSetup(&gTasks[taskId]);
+}
+
+void PrepareAffineAnimInTaskData(struct Task *task, u8 spriteId, const union AffineAnimCmd *affineAnimCmds)
+{
+ task->data[7] = 0;
+ task->data[8] = 0;
+ task->data[9] = 0;
+ task->data[15] = spriteId;
+ task->data[10] = 0x100;
+ task->data[11] = 0x100;
+ task->data[12] = 0;
+ StorePointerInVars(&task->data[13], &task->data[14], affineAnimCmds);
+ PrepareBattlerSpriteForRotScale(spriteId, ST_OAM_OBJ_NORMAL);
+}
+
+bool8 RunAffineAnimFromTaskData(struct Task *task)
+{
+ sAnimTaskAffineAnim = LoadPointerFromVars(task->data[13], task->data[14]) + (task->data[7] << 3);
+ switch (sAnimTaskAffineAnim->type)
+ {
+ default:
+ if (!sAnimTaskAffineAnim->frame.duration)
+ {
+ task->data[10] = sAnimTaskAffineAnim->frame.xScale;
+ task->data[11] = sAnimTaskAffineAnim->frame.yScale;
+ task->data[12] = sAnimTaskAffineAnim->frame.rotation;
+ ++task->data[7];
+ ++sAnimTaskAffineAnim;
+ }
+ task->data[10] += sAnimTaskAffineAnim->frame.xScale;
+ task->data[11] += sAnimTaskAffineAnim->frame.yScale;
+ task->data[12] += sAnimTaskAffineAnim->frame.rotation;
+ SetSpriteRotScale(task->data[15], task->data[10], task->data[11], task->data[12]);
+ SetBattlerSpriteYOffsetFromYScale(task->data[15]);
+ if (++task->data[8] >= sAnimTaskAffineAnim->frame.duration)
+ {
+ task->data[8] = 0;
+ ++task->data[7];
+ }
+ break;
+ case AFFINEANIMCMDTYPE_JUMP:
+ task->data[7] = sAnimTaskAffineAnim->jump.target;
+ break;
+ case AFFINEANIMCMDTYPE_LOOP:
+ if (sAnimTaskAffineAnim->loop.count)
+ {
+ if (task->data[9])
+ {
+ if (!--task->data[9])
+ {
+ ++task->data[7];
+ break;
+ }
+ }
+ else
+ {
+ task->data[9] = sAnimTaskAffineAnim->loop.count;
+ }
+ if (!task->data[7])
+ {
+ break;
+ }
+ while (TRUE)
+ {
+ --task->data[7];
+ --sAnimTaskAffineAnim;
+ if (sAnimTaskAffineAnim->type == AFFINEANIMCMDTYPE_LOOP)
+ {
+ ++task->data[7];
+ return TRUE;
+ }
+ if (!task->data[7])
+ return TRUE;
+ }
+ }
+ ++task->data[7];
+ break;
+ case AFFINEANIMCMDTYPE_END:
+ gSprites[task->data[15]].pos2.y = 0;
+ ResetSpriteRotScale(task->data[15]);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+// Sets the sprite's y offset equal to the y displacement caused by the
+// matrix's scale in the y dimension.
+void SetBattlerSpriteYOffsetFromYScale(u8 spriteId)
+{
+ s32 var = 64 - GetBattlerYDeltaFromSpriteId(spriteId) * 2;
+ u16 matrix = gSprites[spriteId].oam.matrixNum;
+ s32 var2 = (var << 8) / gOamMatrices[matrix].d;
+
+ if (var2 > 128)
+ var2 = 128;
+ gSprites[spriteId].pos2.y = (var - var2) / 2;
+}
+
+// Sets the sprite's y offset equal to the y displacement caused by another sprite
+// matrix's scale in the y dimension.
+void SetBattlerSpriteYOffsetFromOtherYScale(u8 spriteId, u8 otherSpriteId)
+{
+ s32 var = 64 - GetBattlerYDeltaFromSpriteId(otherSpriteId) * 2;
+ u16 matrix = gSprites[spriteId].oam.matrixNum;
+ s32 var2 = (var << 8) / gOamMatrices[matrix].d;
+
+ if (var2 > 128)
+ var2 = 128;
+ gSprites[spriteId].pos2.y = (var - var2) / 2;
+}
+
+static u16 GetBattlerYDeltaFromSpriteId(u8 spriteId)
+{
+ struct BattleSpriteInfo *spriteInfo;
+ u8 battlerId = gSprites[spriteId].data[0];
+ u16 species;
+ u16 i;
+
+ for (i = 0; i < MAX_BATTLERS_COUNT; ++i)
+ {
+ if (gBattlerSpriteIds[i] == spriteId)
+ {
+ if (GetBattlerSide(i) == B_SIDE_PLAYER)
+ {
+ spriteInfo = gBattleSpritesDataPtr->battlerData;
+ if (!spriteInfo[battlerId].transformSpecies)
+ species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[i]], MON_DATA_SPECIES);
+ else
+ species = spriteInfo[battlerId].transformSpecies;
+ return gMonBackPicCoords[species].y_offset;
+ }
+ else
+ {
+ spriteInfo = gBattleSpritesDataPtr->battlerData;
+ if (!spriteInfo[battlerId].transformSpecies)
+ species = GetMonData(&gEnemyParty[gBattlerPartyIndexes[i]], MON_DATA_SPECIES);
+ else
+ species = spriteInfo[battlerId].transformSpecies;
+ return gMonFrontPicCoords[species].y_offset;
+ }
+ }
+ }
+ return 64;
+}
+
+void StorePointerInVars(s16 *lo, s16 *hi, const void *ptr)
+{
+ *lo = ((intptr_t)ptr) & 0xffff;
+ *hi = (((intptr_t)ptr) >> 16) & 0xffff;
+}
+
+void *LoadPointerFromVars(s16 lo, s16 hi)
+{
+ return (void *)((u16)lo | ((u16)hi << 16));
+}
+
+void sub_80765D4(struct Task *task, u8 spriteId, s16 a3, s16 a4, s16 a5, s16 a6, u16 a7)
+{
+ task->data[8] = a7;
+ task->data[15] = spriteId;
+ task->data[9] = a3;
+ task->data[10] = a4;
+ task->data[13] = a5;
+ task->data[14] = a6;
+ task->data[11] = (a5 - a3) / a7;
+ task->data[12] = (a6 - a4) / a7;
+}
+
+u8 sub_8076640(struct Task *task)
+{
+ if (!task->data[8])
+ return 0;
+ if (--task->data[8] != 0)
+ {
+ task->data[9] += task->data[11];
+ task->data[10] += task->data[12];
+ }
+ else
+ {
+ task->data[9] = task->data[13];
+ task->data[10] = task->data[14];
+ }
+ SetSpriteRotScale(task->data[15], task->data[9], task->data[10], 0);
+ if (task->data[8])
+ SetBattlerSpriteYOffsetFromYScale(task->data[15]);
+ else
+ gSprites[task->data[15]].pos2.y = 0;
+ return task->data[8];
+}
+
+void AnimTask_GetFrustrationPowerLevel(u8 taskId)
+{
+ u16 powerLevel;
+
+ if (gAnimFriendship <= 30)
+ powerLevel = 0;
+ else if (gAnimFriendship <= 100)
+ powerLevel = 1;
+ else if (gAnimFriendship <= 200)
+ powerLevel = 2;
+ else
+ powerLevel = 3;
+ gBattleAnimArgs[7] = powerLevel;
+ DestroyAnimVisualTask(taskId);
+}
+
+// not used
+static void sub_80766EC(u8 priority)
+{
+ if (IsBattlerSpriteVisible(gBattleAnimTarget))
+ gSprites[gBattlerSpriteIds[gBattleAnimTarget]].oam.priority = priority;
+ if (IsBattlerSpriteVisible(gBattleAnimAttacker))
+ gSprites[gBattlerSpriteIds[gBattleAnimAttacker]].oam.priority = priority;
+ if (IsBattlerSpriteVisible(BATTLE_PARTNER(gBattleAnimTarget)))
+ gSprites[gBattlerSpriteIds[BATTLE_PARTNER(gBattleAnimTarget)]].oam.priority = priority;
+ if (IsBattlerSpriteVisible(BATTLE_PARTNER(gBattleAnimAttacker)))
+ gSprites[gBattlerSpriteIds[BATTLE_PARTNER(gBattleAnimAttacker)]].oam.priority = priority;
+}
+
+void sub_80767F0(void)
+{
+ s32 i;
+
+ for (i = 0; i < gBattlersCount; ++i)
+ {
+ if (IsBattlerSpriteVisible(i))
+ {
+ gSprites[gBattlerSpriteIds[i]].subpriority = GetBattlerSpriteSubpriority(i);
+ gSprites[gBattlerSpriteIds[i]].oam.priority = 2;
+ }
+ }
+}
+
+u8 GetBattlerSpriteSubpriority(u8 battlerId)
+{
+ u8 subpriority;
+ u8 position = GetBattlerPosition(battlerId);
+
+ if (position == B_POSITION_PLAYER_LEFT)
+ subpriority = 30;
+ else if (position == B_POSITION_PLAYER_RIGHT)
+ subpriority = 20;
+ else if (position == B_POSITION_OPPONENT_LEFT)
+ subpriority = 40;
+ else
+ subpriority = 50;
+ return subpriority;
+}
+
+u8 GetBattlerSpriteBGPriority(u8 battlerId)
+{
+ u8 position = GetBattlerPosition(battlerId);
+
+ if (position == B_POSITION_PLAYER_LEFT || position == B_POSITION_OPPONENT_RIGHT)
+ return GetAnimBgAttribute(2, BG_ANIM_PRIORITY);
+ else
+ return GetAnimBgAttribute(1, BG_ANIM_PRIORITY);
+}
+
+u8 GetBattlerSpriteBGPriorityRank(u8 battlerId)
+{
+ u8 position = GetBattlerPosition(battlerId);
+
+ if (position == B_POSITION_PLAYER_LEFT || position == B_POSITION_OPPONENT_RIGHT)
+ return 2;
+ else
+ return 1;
+}
+
+u8 sub_80768D0(u16 species, bool8 isBackpic, u8 a3, s16 x, s16 y, u8 subpriority, u32 personality, u32 trainerId, u32 battlerId, u32 a10)
+{
+ u8 spriteId;
+ u16 sheet = LoadSpriteSheet(&gUnknown_83AE084[a3]);
+ u16 palette = AllocSpritePalette(gUnknown_83AE054[a3].paletteTag);
+
+ if (gMonSpritesGfxPtr != NULL && gMonSpritesGfxPtr->field_17C == NULL)
+ gMonSpritesGfxPtr->field_17C = AllocZeroed(0x2000);
+ if (!isBackpic)
+ {
+ LoadCompressedPalette(GetMonSpritePalFromSpeciesAndPersonality(species, trainerId, personality), (palette * 0x10) + 0x100, 0x20);
+ if (a10 == 1 || sub_804455C(5, battlerId) == 1 || gBattleSpritesDataPtr->battlerData[battlerId].transformSpecies != 0)
+ LoadSpecialPokePic_DontHandleDeoxys(&gMonFrontPicTable[species],
+ gMonSpritesGfxPtr->field_17C,
+ species,
+ personality,
+ TRUE);
+ else
+ LoadSpecialPokePic(&gMonFrontPicTable[species],
+ gMonSpritesGfxPtr->field_17C,
+ species,
+ personality,
+ TRUE);
+ }
+ else
+ {
+ LoadCompressedPalette(GetMonSpritePalFromSpeciesAndPersonality(species, trainerId, personality), (palette * 0x10) + 0x100, 0x20);
+ if (a10 == 1 || sub_804455C(5, battlerId) == 1 || gBattleSpritesDataPtr->battlerData[battlerId].transformSpecies != 0)
+ LoadSpecialPokePic_DontHandleDeoxys(&gMonBackPicTable[species],
+ gMonSpritesGfxPtr->field_17C,
+ species,
+ personality,
+ FALSE);
+ else
+ LoadSpecialPokePic(&gMonBackPicTable[species],
+ gMonSpritesGfxPtr->field_17C,
+ species,
+ personality,
+ FALSE);
+ }
+ RequestDma3Copy(gMonSpritesGfxPtr->field_17C, (void *)(OBJ_VRAM0 + (sheet * 0x20)), 0x800, 1);
+ FREE_AND_SET_NULL(gMonSpritesGfxPtr->field_17C);
+ if (!isBackpic)
+ spriteId = CreateSprite(&gUnknown_83AE054[a3], x, y + gMonFrontPicCoords[species].y_offset, subpriority);
+ else
+ spriteId = CreateSprite(&gUnknown_83AE054[a3], x, y + gMonBackPicCoords[species].y_offset, subpriority);
+ return spriteId;
+}
+
+void DestroySpriteAndFreeResources_(struct Sprite *sprite)
+{
+ DestroySpriteAndFreeResources(sprite);
+}
+
+s16 GetBattlerSpriteCoordAttr(u8 battlerId, u8 attr)
+{
+ u16 species;
+ u32 personality;
+ u16 letter;
+ u16 unownSpecies;
+ s32 ret;
+ const struct MonCoords *coords;
+ struct BattleSpriteInfo *spriteInfo;
+
+ if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
+ {
+ spriteInfo = gBattleSpritesDataPtr->battlerData;
+ if (!spriteInfo[battlerId].transformSpecies)
+ {
+ species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES);
+ personality = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_PERSONALITY);
+ }
+ else
+ {
+ species = spriteInfo[battlerId].transformSpecies;
+ personality = gTransformedPersonalities[battlerId];
+ }
+ if (species == SPECIES_UNOWN)
+ {
+ letter = GET_UNOWN_LETTER(personality);
+ if (!letter)
+ unownSpecies = SPECIES_UNOWN;
+ else
+ unownSpecies = letter + SPECIES_UNOWN_B - 1;
+ coords = &gMonBackPicCoords[unownSpecies];
+ }
+ else if (species > NUM_SPECIES)
+ {
+ coords = &gMonBackPicCoords[0];
+ }
+ else
+ {
+ coords = &gMonBackPicCoords[species];
+ }
+ }
+ else
+ {
+ spriteInfo = gBattleSpritesDataPtr->battlerData;
+ if (!spriteInfo[battlerId].transformSpecies)
+ {
+ species = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES);
+ personality = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerId]], MON_DATA_PERSONALITY);
+ }
+ else
+ {
+ species = spriteInfo[battlerId].transformSpecies;
+ personality = gTransformedPersonalities[battlerId];
+ }
+
+ if (species == SPECIES_UNOWN)
+ {
+ letter = GET_UNOWN_LETTER(personality);
+ if (!letter)
+ unownSpecies = SPECIES_UNOWN;
+ else
+ unownSpecies = letter + SPECIES_UNOWN_B - 1;
+ coords = &gMonFrontPicCoords[unownSpecies];
+ }
+ else if (species == SPECIES_CASTFORM)
+ {
+ coords = &gCastformFrontSpriteCoords[gBattleMonForms[battlerId]];
+ }
+ else if (species > NUM_SPECIES)
+ {
+ coords = &gMonFrontPicCoords[0];
+ }
+ else
+ {
+ coords = &gMonFrontPicCoords[species];
+ }
+ }
+ switch (attr)
+ {
+ case BATTLER_COORD_ATTR_HEIGHT:
+ return (coords->size & 0xf) * 8;
+ case BATTLER_COORD_ATTR_WIDTH:
+ return (coords->size >> 4) * 8;
+ case BATTLER_COORD_ATTR_LEFT:
+ return GetBattlerSpriteCoord(battlerId, BATTLER_COORD_X_2) - ((coords->size >> 4) * 4);
+ case BATTLER_COORD_ATTR_RIGHT:
+ return GetBattlerSpriteCoord(battlerId, BATTLER_COORD_X_2) + ((coords->size >> 4) * 4);
+ case BATTLER_COORD_ATTR_TOP:
+ return GetBattlerSpriteCoord(battlerId, BATTLER_COORD_Y_PIC_OFFSET) - ((coords->size & 0xf) * 4);
+ case BATTLER_COORD_ATTR_BOTTOM:
+ return GetBattlerSpriteCoord(battlerId, BATTLER_COORD_Y_PIC_OFFSET) + ((coords->size & 0xf) * 4);
+ case BATTLER_COORD_ATTR_RAW_BOTTOM:
+ ret = GetBattlerSpriteCoord(battlerId, BATTLER_COORD_Y) + 31;
+ return ret - coords->y_offset;
+ default:
+ return 0;
+ }
+}
+
+void SetAverageBattlerPositions(u8 battlerId, bool8 respectMonPicOffsets, s16 *x, s16 *y)
+{
+ u8 xCoordType, yCoordType;
+ s16 battlerX, battlerY;
+ s16 partnerX, partnerY;
+
+ if (!respectMonPicOffsets)
+ {
+ xCoordType = BATTLER_COORD_X;
+ yCoordType = BATTLER_COORD_Y;
+ }
+ else
+ {
+ xCoordType = BATTLER_COORD_X_2;
+ yCoordType = BATTLER_COORD_Y_PIC_OFFSET;
+ }
+ battlerX = GetBattlerSpriteCoord(battlerId, xCoordType);
+ battlerY = GetBattlerSpriteCoord(battlerId, yCoordType);
+ if (IsDoubleBattle())
+ {
+ partnerX = GetBattlerSpriteCoord(BATTLE_PARTNER(battlerId), xCoordType);
+ partnerY = GetBattlerSpriteCoord(BATTLE_PARTNER(battlerId), yCoordType);
+ }
+ else
+ {
+ partnerX = battlerX;
+ partnerY = battlerY;
+ }
+ *x = (battlerX + partnerX) / 2;
+ *y = (battlerY + partnerY) / 2;
+}
+
+u8 sub_8076E34(s32 battlerId, u8 spriteId, s32 species)
+{
+ u8 newSpriteId = CreateInvisibleSpriteWithCallback(SpriteCallbackDummy);
+
+ gSprites[newSpriteId] = gSprites[spriteId];
+ gSprites[newSpriteId].usingSheet = TRUE;
+ gSprites[newSpriteId].oam.priority = 0;
+ gSprites[newSpriteId].oam.objMode = 2;
+ gSprites[newSpriteId].oam.tileNum = gSprites[spriteId].oam.tileNum;
+ gSprites[newSpriteId].callback = SpriteCallbackDummy;
+ return newSpriteId;
+}
+
+void sub_8076ED8(struct Sprite *sprite)
+{
+ SetSpriteCoordsToAnimAttackerCoords(sprite);
+ if (GetBattlerSide(gBattleAnimAttacker))
+ {
+ sprite->pos1.x -= gBattleAnimArgs[0];
+ gBattleAnimArgs[3] = -gBattleAnimArgs[3];
+ sprite->hFlip = TRUE;
+ }
+ else
+ {
+ sprite->pos1.x += gBattleAnimArgs[0];
+ }
+ sprite->pos1.y += gBattleAnimArgs[1];
+ sprite->data[0] = gBattleAnimArgs[2];
+ sprite->data[1] = gBattleAnimArgs[3];
+ sprite->data[3] = gBattleAnimArgs[4];
+ sprite->data[5] = gBattleAnimArgs[5];
+ StoreSpriteCallbackInData6(sprite, DestroySpriteAndMatrix);
+ sprite->callback = TranslateSpriteLinearAndFlicker;
+}
+
+void sub_8076F58(struct Sprite *sprite)
+{
+ if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
+ {
+ sprite->pos1.x -= gBattleAnimArgs[0];
+ gBattleAnimArgs[3] *= -1;
+ }
+ else
+ {
+ sprite->pos1.x += gBattleAnimArgs[0];
+ }
+ sprite->pos1.y += gBattleAnimArgs[1];
+ sprite->data[0] = gBattleAnimArgs[2];
+ sprite->data[1] = gBattleAnimArgs[3];
+ sprite->data[3] = gBattleAnimArgs[4];
+ sprite->data[5] = gBattleAnimArgs[5];
+ StartSpriteAnim(sprite, gBattleAnimArgs[6]);
+ StoreSpriteCallbackInData6(sprite, DestroySpriteAndMatrix);
+ sprite->callback = TranslateSpriteLinearAndFlicker;
+}
+
+void sub_8076FD0(struct Sprite *sprite)
+{
+ SetSpriteCoordsToAnimAttackerCoords(sprite);
+ if (GetBattlerSide(gBattleAnimAttacker))
+ sprite->pos1.x -= gBattleAnimArgs[0];
+ else
+ sprite->pos1.x += gBattleAnimArgs[0];
+ sprite->pos1.y += gBattleAnimArgs[1];
+ sprite->callback = RunStoredCallbackWhenAnimEnds;
+ StoreSpriteCallbackInData6(sprite, DestroyAnimSprite);
+}
+
+void sub_8077030(u8 taskId)
+{
+ u16 src;
+ u16 dest;
+ struct Task *task = &gTasks[taskId];
+
+ task->data[0] = GetAnimBattlerSpriteId(ANIM_ATTACKER);
+ task->data[1] = ((GetBattlerSide(gBattleAnimAttacker)) != B_SIDE_PLAYER) ? -8 : 8;
+ task->data[2] = 0;
+ task->data[3] = 0;
+ gSprites[task->data[0]].pos2.x -= task->data[0];
+ task->data[4] = AllocSpritePalette(10097);
+ task->data[5] = 0;
+ dest = (task->data[4] + 0x10) * 0x10;
+ src = (gSprites[task->data[0]].oam.paletteNum + 0x10) * 0x10;
+ task->data[6] = GetBattlerSpriteSubpriority(gBattleAnimAttacker);
+ if (task->data[6] == 20 || task->data[6] == 40)
+ task->data[6] = 2;
+ else
+ task->data[6] = 3;
+ CpuCopy32(&gPlttBufferUnfaded[src], &gPlttBufferFaded[dest], 0x20);
+ BlendPalette(dest, 16, gBattleAnimArgs[1], gBattleAnimArgs[0]);
+ task->func = sub_8077118;
+}
+
+static void sub_8077118(u8 taskId)
+{
+ struct Task *task = &gTasks[taskId];
+ switch (task->data[2])
+ {
+ case 0:
+ sub_80771E4(task, taskId);
+ gSprites[task->data[0]].pos2.x += task->data[1];
+ if (++task->data[3] == 5)
+ {
+ --task->data[3];
+ ++task->data[2];
+ }
+ break;
+ case 1:
+ sub_80771E4(task, taskId);
+ gSprites[task->data[0]].pos2.x -= task->data[1];
+ if (--task->data[3] == 0)
+ {
+ gSprites[task->data[0]].pos2.x = 0;
+ ++task->data[2];
+ }
+ break;
+ case 2:
+ if (!task->data[5])
+ {
+ FreeSpritePaletteByTag(ANIM_TAG_BENT_SPOON);
+ DestroyAnimVisualTask(taskId);
+ }
+ break;
+ }
+}
+
+static void sub_80771E4(struct Task *task, u8 taskId)
+{
+ s16 spriteId = CloneBattlerSpriteWithBlend(0);
+ if (spriteId >= 0)
+ {
+ gSprites[spriteId].oam.priority = task->data[6];
+ gSprites[spriteId].oam.paletteNum = task->data[4];
+ gSprites[spriteId].data[0] = 8;
+ gSprites[spriteId].data[1] = taskId;
+ gSprites[spriteId].data[2] = spriteId;
+ gSprites[spriteId].pos2.x = gSprites[task->data[0]].pos2.x;
+ gSprites[spriteId].callback = sub_8077268;
+ ++task->data[5];
+ }
+}
+
+static void sub_8077268(struct Sprite *sprite)
+{
+ if (--sprite->data[0] == 0)
+ {
+ --gTasks[sprite->data[1]].data[5];
+ obj_delete_but_dont_free_vram(sprite);
+ }
+}
+
+void sub_807729C(struct Sprite *sprite)
+{
+ sprite->pos1.x = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_X_2);
+ sprite->pos1.y = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_Y_PIC_OFFSET);
+ if (!GetBattlerSide(gBattleAnimAttacker))
+ sprite->data[0] = 5;
+ else
+ sprite->data[0] = -10;
+ sprite->data[1] = -40;
+ sprite->callback = sub_80772F4;
+}
+
+static void sub_80772F4(struct Sprite *sprite)
+{
+ sprite->data[2] += sprite->data[0];
+ sprite->data[3] += sprite->data[1];
+ sprite->pos2.x = sprite->data[2] / 10;
+ sprite->pos2.y = sprite->data[3] / 10;
+ if (sprite->data[1] < -20)
+ ++sprite->data[1];
+ if (sprite->pos1.y + sprite->pos2.y < -32)
+ DestroyAnimSprite(sprite);
+}
+
+void sub_8077350(struct Sprite *sprite)
+{
+ s32 x;
+
+ sprite->data[0] = gBattleAnimArgs[2];
+ sprite->data[2] = sprite->pos1.x + gBattleAnimArgs[4];
+ sprite->data[4] = sprite->pos1.y + gBattleAnimArgs[5];
+ if (!GetBattlerSide(gBattleAnimTarget))
+ {
+ x = (u16)gBattleAnimArgs[4] + 30;
+ sprite->pos1.x += x;
+ sprite->pos1.y = gBattleAnimArgs[5] - 20;
+ }
+ else
+ {
+ x = (u16)gBattleAnimArgs[4] - 30;
+ sprite->pos1.x += x;
+ sprite->pos1.y = gBattleAnimArgs[5] - 80;
+ }
+ sprite->callback = StartAnimLinearTranslation;
+ StoreSpriteCallbackInData6(sprite, DestroyAnimSprite);
+}
diff --git a/src/battle_anim_sound_tasks.c b/src/battle_anim_sound_tasks.c
new file mode 100644
index 000000000..e67c91bfa
--- /dev/null
+++ b/src/battle_anim_sound_tasks.c
@@ -0,0 +1,313 @@
+#include "global.h"
+#include "battle.h"
+#include "battle_anim.h"
+#include "sound.h"
+#include "task.h"
+#include "constants/battle_anim.h"
+#include "constants/species.h"
+
+static void sub_80DCE78(u8 taskId);
+static void sub_80DCEE4(u8 taskId);
+static void sub_80DCFE8(u8 taskId);
+static void sub_80DD270(u8 taskId);
+static void sub_80DD390(u8 taskId);
+static void sub_80DD4D4(u8 taskId);
+
+void sub_80DCE10(u8 taskId)
+{
+ s8 pan1, pan2, panIncrement;
+
+ gTasks[taskId].data[0] = gBattleAnimArgs[0];
+ gTasks[taskId].data[1] = gBattleAnimArgs[1];
+ pan1 = BattleAnimAdjustPanning(SOUND_PAN_ATTACKER);
+ pan2 = BattleAnimAdjustPanning(SOUND_PAN_TARGET);
+ panIncrement = CalculatePanIncrement(pan1, pan2, 2);
+ gTasks[taskId].data[2] = pan1;
+ gTasks[taskId].data[3] = pan2;
+ gTasks[taskId].data[4] = panIncrement;
+ gTasks[taskId].data[10] = 10;
+ gTasks[taskId].func = sub_80DCE78;
+}
+
+static void sub_80DCE78(u8 taskId)
+{
+ s16 pan = gTasks[taskId].data[2];
+ s8 panIncrement = gTasks[taskId].data[4];
+
+ if (++gTasks[taskId].data[11] == 111)
+ {
+ gTasks[taskId].data[10] = 5;
+ gTasks[taskId].data[11] = 0;
+ gTasks[taskId].func = sub_80DCEE4;
+ }
+ else
+ {
+ if (++gTasks[taskId].data[10] == 11)
+ {
+ gTasks[taskId].data[10] = 0;
+ PlaySE12WithPanning(gTasks[taskId].data[0], pan);
+ }
+ pan += panIncrement;
+ gTasks[taskId].data[2] = KeepPanInRange(pan, panIncrement);
+ }
+}
+
+static void sub_80DCEE4(u8 taskId)
+{
+ if (++gTasks[taskId].data[10] == 6)
+ {
+ s8 pan;
+
+ gTasks[taskId].data[10] = 0;
+ pan = BattleAnimAdjustPanning(SOUND_PAN_TARGET);
+ PlaySE12WithPanning(gTasks[taskId].data[1], pan);
+ if (++gTasks[taskId].data[11] == 2)
+ DestroyAnimSoundTask(taskId);
+ }
+}
+
+void mas_80DCF38(u8 taskId)
+{
+ u16 songId = gBattleAnimArgs[0];
+ s8 targetPan = gBattleAnimArgs[2];
+ s8 panIncrement = gBattleAnimArgs[3];
+ u8 r10 = gBattleAnimArgs[4];
+ u8 r7 = gBattleAnimArgs[5];
+ u8 r9 = gBattleAnimArgs[6];
+ s8 sourcePan = BattleAnimAdjustPanning(gBattleAnimArgs[1]);
+
+ targetPan = BattleAnimAdjustPanning(targetPan);
+ panIncrement = CalculatePanIncrement(sourcePan, targetPan, panIncrement);
+ gTasks[taskId].data[0] = songId;
+ gTasks[taskId].data[1] = sourcePan;
+ gTasks[taskId].data[2] = targetPan;
+ gTasks[taskId].data[3] = panIncrement;
+ gTasks[taskId].data[4] = r10;
+ gTasks[taskId].data[5] = r7;
+ gTasks[taskId].data[6] = r9;
+ gTasks[taskId].data[10] = 0;
+ gTasks[taskId].data[11] = sourcePan;
+ gTasks[taskId].data[12] = r9;
+ gTasks[taskId].func = sub_80DCFE8;
+ sub_80DCFE8(taskId);
+}
+
+static void sub_80DCFE8(u8 taskId)
+{
+ if (gTasks[taskId].data[12]++ == gTasks[taskId].data[6])
+ {
+ gTasks[taskId].data[12] = 0;
+ PlaySE12WithPanning(gTasks[taskId].data[0], gTasks[taskId].data[11]);
+ if (--gTasks[taskId].data[4] == 0)
+ {
+ DestroyAnimSoundTask(taskId);
+ return;
+ }
+ }
+ if (gTasks[taskId].data[10]++ == gTasks[taskId].data[5])
+ {
+ u16 dPan, oldPan;
+
+ gTasks[taskId].data[10] = 0;
+ dPan = gTasks[taskId].data[3];
+ oldPan = gTasks[taskId].data[11] ;
+ gTasks[taskId].data[11] = dPan + oldPan;
+ gTasks[taskId].data[11] = KeepPanInRange(gTasks[taskId].data[11], oldPan);
+ }
+}
+
+void sub_80DD06C(u8 taskId)
+{
+ u16 species = SPECIES_NONE;
+ u8 battlerId;
+ s8 pan = BattleAnimAdjustPanning(SOUND_PAN_ATTACKER);
+
+ // Get wanted battler.
+ if (gBattleAnimArgs[0] == ANIM_ATTACKER)
+ battlerId = gBattleAnimAttacker;
+ else if (gBattleAnimArgs[0] == ANIM_TARGET)
+ battlerId = gBattleAnimTarget;
+ else if (gBattleAnimArgs[0] == ANIM_ATK_PARTNER)
+ battlerId = BATTLE_PARTNER(gBattleAnimAttacker);
+ else
+ battlerId = BATTLE_PARTNER(gBattleAnimTarget);
+ // Check if battler is visible.
+ if ((gBattleAnimArgs[0] == ANIM_TARGET || gBattleAnimArgs[0] == ANIM_DEF_PARTNER)
+ && !IsBattlerSpriteVisible(battlerId))
+ {
+ DestroyAnimVisualTask(taskId);
+ return;
+ }
+ if (GetBattlerSide(battlerId) != B_SIDE_PLAYER)
+ species = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES);
+ else
+ species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES);
+ if (species != SPECIES_NONE)
+ PlayCry3(species, pan, 3);
+ DestroyAnimVisualTask(taskId);
+}
+
+void sub_80DD148(u8 taskId)
+{
+ u16 species = SPECIES_NONE;
+ u8 battlerId;
+ s8 pan = BattleAnimAdjustPanning(SOUND_PAN_ATTACKER);
+
+ // Get wanted battler.
+ if (gBattleAnimArgs[0] == ANIM_ATTACKER)
+ battlerId = gBattleAnimAttacker;
+ else if (gBattleAnimArgs[0] == ANIM_TARGET)
+ battlerId = gBattleAnimTarget;
+ else if (gBattleAnimArgs[0] == ANIM_ATK_PARTNER)
+ battlerId = BATTLE_PARTNER(gBattleAnimAttacker);
+ else
+ battlerId = BATTLE_PARTNER(gBattleAnimTarget);
+ // Check if battler is visible.
+ if ((gBattleAnimArgs[0] == ANIM_TARGET || gBattleAnimArgs[0] == ANIM_DEF_PARTNER)
+ && !IsBattlerSpriteVisible(battlerId))
+ {
+ DestroyAnimVisualTask(taskId);
+ return;
+ }
+ if (GetBattlerSide(battlerId) != B_SIDE_PLAYER)
+ species = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES);
+ else
+ species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES);
+ gTasks[taskId].data[0] = gBattleAnimArgs[1];
+ gTasks[taskId].data[1] = species;
+ gTasks[taskId].data[2] = pan;
+ if (species != SPECIES_NONE)
+ {
+ if (gBattleAnimArgs[1] == TASK_NONE)
+ PlayCry3(species, pan, 9);
+ else
+ PlayCry3(species, pan, 7);
+ gTasks[taskId].func = sub_80DD270;
+ }
+ else
+ {
+ DestroyAnimVisualTask(taskId);
+ }
+}
+
+static void sub_80DD270(u8 taskId)
+{
+ u16 species = gTasks[taskId].data[1];
+ s8 pan = gTasks[taskId].data[2];
+
+ if (gTasks[taskId].data[9] < 2)
+ {
+ ++gTasks[taskId].data[9];
+ }
+ else if (gTasks[taskId].data[0] == TASK_NONE)
+ {
+ if (!IsCryPlaying())
+ {
+ PlayCry3(species, pan, 10);
+ DestroyAnimVisualTask(taskId);
+ }
+ }
+ else if (!IsCryPlaying())
+ {
+ PlayCry3(species, pan, 8);
+ DestroyAnimVisualTask(taskId);
+ }
+}
+
+void sub_80DD2F4(u8 taskId)
+{
+ if (gTasks[taskId].data[9] < 2)
+ ++gTasks[taskId].data[9];
+ else if (!IsCryPlaying())
+ DestroyAnimVisualTask(taskId);
+}
+
+void sub_80DD334(u8 taskId)
+{
+ u16 species;
+ s8 pan;
+
+ pan = BattleAnimAdjustPanning(SOUND_PAN_ATTACKER);
+ species = gAnimBattlerSpecies[gBattleAnimAttacker];
+ gTasks[taskId].data[1] = species;
+ gTasks[taskId].data[2] = pan;
+ if (species != SPECIES_NONE)
+ {
+ PlayCry3(species, pan, 4);
+ gTasks[taskId].func = sub_80DD390;
+ }
+ else
+ {
+ DestroyAnimVisualTask(taskId);
+ }
+}
+
+static void sub_80DD390(u8 taskId)
+{
+
+ if (gTasks[taskId].data[9] < 2)
+ {
+ ++gTasks[taskId].data[9];
+ }
+ else if (!IsCryPlaying())
+ {
+ u16 species = gTasks[taskId].data[1];
+ s8 pan = gTasks[taskId].data[2];
+
+ PlayCry3(species, pan, 6);
+ DestroyAnimVisualTask(taskId);
+ }
+}
+
+void sub_80DD3DC(u8 taskId)
+{
+ u16 songId = gBattleAnimArgs[0];
+ s8 pan = BattleAnimAdjustPanning(gBattleAnimArgs[1]);
+
+ PlaySE1WithPanning(songId, pan);
+ DestroyAnimVisualTask(taskId);
+}
+
+void sub_80DD410(u8 taskId)
+{
+ u16 songId = gBattleAnimArgs[0];
+ s8 pan = BattleAnimAdjustPanning(gBattleAnimArgs[1]);
+
+ PlaySE2WithPanning(songId, pan);
+ DestroyAnimVisualTask(taskId);
+}
+
+void sub_80DD444(u8 taskId)
+{
+ s8 targetPan = gBattleAnimArgs[1];
+ s8 panIncrement = gBattleAnimArgs[2];
+ u16 r9 = gBattleAnimArgs[3];
+ s8 sourcePan = BattleAnimAdjustPanning(gBattleAnimArgs[0]);
+
+ targetPan = BattleAnimAdjustPanning(targetPan);
+ panIncrement = CalculatePanIncrement(sourcePan, targetPan, panIncrement);
+ gTasks[taskId].data[1] = sourcePan;
+ gTasks[taskId].data[2] = targetPan;
+ gTasks[taskId].data[3] = panIncrement;
+ gTasks[taskId].data[5] = r9;
+ gTasks[taskId].data[10] = 0;
+ gTasks[taskId].data[11] = sourcePan;
+ gTasks[taskId].func = sub_80DD4D4;
+ sub_80DD4D4(taskId);
+}
+
+static void sub_80DD4D4(u8 taskId)
+{
+ u16 oldPan, panIncrement = gTasks[taskId].data[3];
+
+ if (gTasks[taskId].data[10]++ == gTasks[taskId].data[5])
+ {
+ gTasks[taskId].data[10] = 0;
+ oldPan = gTasks[taskId].data[11];
+ gTasks[taskId].data[11] = panIncrement + oldPan;
+ gTasks[taskId].data[11] = KeepPanInRange(gTasks[taskId].data[11], oldPan);
+ }
+ gUnknown_2037F24 = gTasks[taskId].data[11];
+ if (gTasks[taskId].data[11] == gTasks[taskId].data[2])
+ DestroyAnimVisualTask(taskId);
+}
diff --git a/src/battle_anim_utility_funcs.c b/src/battle_anim_utility_funcs.c
new file mode 100644
index 000000000..14c5ef6c8
--- /dev/null
+++ b/src/battle_anim_utility_funcs.c
@@ -0,0 +1,946 @@
+#include "global.h"
+#include "battle.h"
+#include "battle_anim.h"
+#include "gpu_regs.h"
+#include "graphics.h"
+#include "malloc.h"
+#include "palette.h"
+#include "sound.h"
+#include "sprite.h"
+#include "task.h"
+#include "util.h"
+#include "constants/songs.h"
+
+struct AnimStatsChangeData
+{
+ u8 battler1;
+ u8 battler2;
+ u8 higherPriority;
+ s16 data[8];
+ u16 species;
+};
+
+static void StartBlendAnimSpriteColor(u8 taskId, u32 selectedPalettes);
+static void AnimTask_BlendSpriteColor_Step2(u8 taskId);
+static void sub_80BAB78(u8 taskId);
+static void sub_80BABD0(u8 taskId);
+static void sub_80BACA8(struct Sprite *sprite);
+static void sub_80BAF38(u8 taskId);
+static void sub_80BB0D8(u8 taskId);
+static void sub_80BB2A0(u8 taskId);
+static void sub_80BB4B8(u8 taskId);
+static void sub_80BB6CC(u8 taskId);
+static void sub_80BB790(u32 selectedPalettes, u16 color);
+static void sub_80BB8A4(u8 taskId);
+static void sub_80BBC2C(u8 taskId);
+static void sub_80BC19C(u8 taskId);
+
+static EWRAM_DATA struct AnimStatsChangeData *sAnimStatsChangeData = NULL;
+
+static const u16 gUnknown_83E7CC8[] = { RGB(31, 31, 31) };
+const u8 gUnknown_83E7CCA[] = { REG_OFFSET_BG0CNT, REG_OFFSET_BG1CNT, REG_OFFSET_BG2CNT, REG_OFFSET_BG3CNT };
+const u8 gUnknown_83E7CCE[] = { REG_OFFSET_BG0CNT, REG_OFFSET_BG1CNT, REG_OFFSET_BG2CNT, REG_OFFSET_BG3CNT };
+
+void sub_80BA7F8(u8 taskId)
+{
+ u32 selectedPalettes = UnpackSelectedBattleAnimPalettes(gBattleAnimArgs[0]);
+
+ selectedPalettes |= sub_8075CB8((gBattleAnimArgs[0] >> 7) & 1,
+ (gBattleAnimArgs[0] >> 8) & 1,
+ (gBattleAnimArgs[0] >> 9) & 1,
+ (gBattleAnimArgs[0] >> 10) & 1);
+ StartBlendAnimSpriteColor(taskId, selectedPalettes);
+}
+
+void sub_80BA83C(u8 taskId)
+{
+ u8 battler;
+ u32 selectedPalettes;
+ u8 animBattlers[2];
+
+ animBattlers[1] = 0xFF;
+ selectedPalettes = UnpackSelectedBattleAnimPalettes(1);
+ switch (gBattleAnimArgs[0])
+ {
+ case 2:
+ selectedPalettes = 0;
+ // fall through
+ case 0:
+ animBattlers[0] = gBattleAnimAttacker;
+ break;
+ case 3:
+ selectedPalettes = 0;
+ // fall through
+ case 1:
+ animBattlers[0] = gBattleAnimTarget;
+ break;
+ case 4:
+ animBattlers[0] = gBattleAnimAttacker;
+ animBattlers[1] = gBattleAnimTarget;
+ break;
+ case 5:
+ animBattlers[0] = 0xFF;
+ break;
+ case 6:
+ selectedPalettes = 0;
+ animBattlers[0] = BATTLE_PARTNER(gBattleAnimAttacker);
+ break;
+ case 7:
+ selectedPalettes = 0;
+ animBattlers[0] = BATTLE_PARTNER(gBattleAnimTarget);
+ break;
+ }
+ for (battler = 0; battler < MAX_BATTLERS_COUNT; ++battler)
+ {
+ if (battler != animBattlers[0]
+ && battler != animBattlers[1]
+ && IsBattlerSpriteVisible(battler))
+ selectedPalettes |= 0x10000 << sub_8075D80(battler);
+ }
+ StartBlendAnimSpriteColor(taskId, selectedPalettes);
+}
+
+void AnimTask_SetCamouflageBlend(u8 taskId)
+{
+ u32 selectedPalettes = UnpackSelectedBattleAnimPalettes(gBattleAnimArgs[0]);
+
+ switch (gBattleTerrain)
+ {
+ case BATTLE_TERRAIN_GRASS:
+ gBattleAnimArgs[4] = RGB(12, 24, 2);
+ break;
+ case BATTLE_TERRAIN_LONG_GRASS:
+ gBattleAnimArgs[4] = RGB(0, 15, 2);
+ break;
+ case BATTLE_TERRAIN_SAND:
+ gBattleAnimArgs[4] = RGB(30, 24, 11);
+ break;
+ case BATTLE_TERRAIN_UNDERWATER:
+ gBattleAnimArgs[4] = RGB(0, 0, 18);
+ break;
+ case BATTLE_TERRAIN_WATER:
+ gBattleAnimArgs[4] = RGB(11, 22, 31);
+ break;
+ case BATTLE_TERRAIN_POND:
+ gBattleAnimArgs[4] = RGB(11, 22, 31);
+ break;
+ case BATTLE_TERRAIN_MOUNTAIN:
+ gBattleAnimArgs[4] = RGB(22, 16, 10);
+ break;
+ case BATTLE_TERRAIN_CAVE:
+ gBattleAnimArgs[4] = RGB(14, 9, 3);
+ break;
+ case BATTLE_TERRAIN_BUILDING:
+ gBattleAnimArgs[4] = RGB(31, 31, 31);
+ break;
+ case BATTLE_TERRAIN_PLAIN:
+ gBattleAnimArgs[4] = RGB(31, 31, 31);
+ break;
+ }
+ StartBlendAnimSpriteColor(taskId, selectedPalettes);
+}
+
+void AnimTask_BlendParticle(u8 taskId)
+{
+ u8 paletteIndex = IndexOfSpritePaletteTag(gBattleAnimArgs[0]);
+ u32 selectedPalettes = 1 << (paletteIndex + 16);
+
+ StartBlendAnimSpriteColor(taskId, selectedPalettes);
+}
+
+static void StartBlendAnimSpriteColor(u8 taskId, u32 selectedPalettes)
+{
+ gTasks[taskId].data[0] = selectedPalettes;
+ gTasks[taskId].data[1] = selectedPalettes >> 16;
+ gTasks[taskId].data[2] = gBattleAnimArgs[1];
+ gTasks[taskId].data[3] = gBattleAnimArgs[2];
+ gTasks[taskId].data[4] = gBattleAnimArgs[3];
+ gTasks[taskId].data[5] = gBattleAnimArgs[4];
+ gTasks[taskId].data[10] = gBattleAnimArgs[2];
+ gTasks[taskId].func = AnimTask_BlendSpriteColor_Step2;
+ gTasks[taskId].func(taskId);
+}
+
+static void AnimTask_BlendSpriteColor_Step2(u8 taskId)
+{
+ u32 selectedPalettes;
+ u16 singlePaletteMask = 0;
+
+ if (gTasks[taskId].data[9] == gTasks[taskId].data[2])
+ {
+ gTasks[taskId].data[9] = 0;
+ selectedPalettes = gTasks[taskId].data[0] | (gTasks[taskId].data[1] << 16);
+ while (selectedPalettes)
+ {
+ if (selectedPalettes & 1)
+ BlendPalette(singlePaletteMask, 16, gTasks[taskId].data[10], gTasks[taskId].data[5]);
+ singlePaletteMask += 0x10;
+ selectedPalettes >>= 1;
+ }
+ if (gTasks[taskId].data[10] < gTasks[taskId].data[4])
+ ++gTasks[taskId].data[10];
+ else if (gTasks[taskId].data[10] > gTasks[taskId].data[4])
+ --gTasks[taskId].data[10];
+ else
+ DestroyAnimVisualTask(taskId);
+ }
+ else
+ {
+ ++gTasks[taskId].data[9];
+ }
+}
+
+void sub_80BAB38(u8 taskId)
+{
+ BeginHardwarePaletteFade(gBattleAnimArgs[0],
+ gBattleAnimArgs[1],
+ gBattleAnimArgs[2],
+ gBattleAnimArgs[3],
+ gBattleAnimArgs[4]);
+ gTasks[taskId].func = sub_80BAB78;
+}
+
+static void sub_80BAB78(u8 taskId)
+{
+ if (!gPaletteFade.active)
+ DestroyAnimVisualTask(taskId);
+}
+
+void sub_80BAB98(u8 taskId)
+{
+ struct Task *task = &gTasks[taskId];
+
+ task->data[0] = gBattleAnimArgs[0];
+ task->data[1] = 0;
+ task->data[2] = gBattleAnimArgs[1];
+ task->data[3] = gBattleAnimArgs[2];
+ task->data[4] = gBattleAnimArgs[3];
+ task->data[5] = 0;
+ task->func = sub_80BABD0;
+}
+static void sub_80BABD0(u8 taskId)
+{
+ struct Task *task = &gTasks[taskId];
+
+ if (task->data[4])
+ {
+ if (task->data[1])
+ {
+ --task->data[1];
+ }
+ else
+ {
+ task->data[6] = CloneBattlerSpriteWithBlend(task->data[0]);
+ if (task->data[6] >= 0)
+ {
+ gSprites[task->data[6]].oam.priority = task->data[0] ? 1 : 2;
+ gSprites[task->data[6]].data[0] = task->data[3];
+ gSprites[task->data[6]].data[1] = taskId;
+ gSprites[task->data[6]].data[2] = 5;
+ gSprites[task->data[6]].callback = sub_80BACA8;
+ ++task->data[5];
+ }
+ --task->data[4];
+ task->data[1] = task->data[2];
+ }
+ }
+ else if (task->data[5] == 0)
+ {
+ DestroyAnimVisualTask(taskId);
+ }
+}
+
+static void sub_80BACA8(struct Sprite *sprite)
+{
+ if (sprite->data[0])
+ {
+ --sprite->data[0];
+ }
+ else
+ {
+ --gTasks[sprite->data[1]].data[sprite->data[2]];
+ obj_delete_but_dont_free_vram(sprite);
+ }
+}
+
+void sub_80BACEC(u8 taskId)
+{
+ u16 species;
+ s32 newSpriteId;
+ u16 var0;
+ u16 bg1Cnt;
+ u8 spriteId;
+ struct BattleAnimBgData animBgData;
+
+ var0 = 0;
+ gBattle_WIN0H = 0;
+ gBattle_WIN0V = 0;
+ SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR
+ | WININ_WIN1_BG_ALL | WININ_WIN1_OBJ | WININ_WIN1_CLR);
+ SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG0 | WINOUT_WIN01_BG2 | WINOUT_WIN01_BG3 | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR
+ | WINOUT_WINOBJ_BG_ALL | WINOUT_WINOBJ_OBJ | WINOUT_WINOBJ_CLR);
+ SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_OBJWIN_ON);
+ SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG1 | BLDCNT_TGT2_ALL | BLDCNT_EFFECT_BLEND);
+ SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(8, 12));
+ bg1Cnt = GetGpuReg(REG_OFFSET_BG1CNT);
+ ((struct BgCnt *)&bg1Cnt)->priority = 0;
+ ((struct BgCnt *)&bg1Cnt)->screenSize = 0;
+ SetGpuReg(REG_OFFSET_BG1CNT, bg1Cnt);
+ if (!IsContest())
+ {
+ ((struct BgCnt *)&bg1Cnt)->charBaseBlock = 1;
+ SetGpuReg(REG_OFFSET_BG1CNT, bg1Cnt);
+ }
+ if (IsDoubleBattle() && !IsContest())
+ {
+ if (GetBattlerPosition(gBattleAnimAttacker) == B_POSITION_OPPONENT_RIGHT
+ || GetBattlerPosition(gBattleAnimAttacker) == B_POSITION_PLAYER_LEFT)
+ {
+ if (IsBattlerSpriteVisible(BATTLE_PARTNER(gBattleAnimAttacker)) == TRUE)
+ {
+ gSprites[gBattlerSpriteIds[BATTLE_PARTNER(gBattleAnimAttacker)]].oam.priority -= 1;
+ ((struct BgCnt *)&bg1Cnt)->priority = 1;
+ SetGpuReg(REG_OFFSET_BG1CNT, bg1Cnt);
+ var0 = 1;
+ }
+ }
+ }
+ if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
+ species = GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattleAnimAttacker]], MON_DATA_SPECIES);
+ else
+ species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gBattleAnimAttacker]], MON_DATA_SPECIES);
+ spriteId = GetAnimBattlerSpriteId(0);
+ newSpriteId = sub_8076E34(gBattleAnimAttacker, spriteId, species);
+ sub_80752A0(&animBgData);
+ AnimLoadCompressedBgTilemap(animBgData.bgId, gFile_graphics_battle_anims_masks_curse_tilemap);
+ if (IsContest())
+ sub_80730C0(animBgData.paletteId, animBgData.bgTilemap, 0, 0);
+ AnimLoadCompressedBgGfx(animBgData.bgId, gFile_graphics_battle_anims_masks_curse_sheet, animBgData.tilesOffset);
+ LoadPalette(gUnknown_83E7CC8, animBgData.paletteId * 16 + 1, 2);
+ gBattle_BG1_X = -gSprites[spriteId].pos1.x + 32;
+ gBattle_BG1_Y = -gSprites[spriteId].pos1.y + 32;
+ gTasks[taskId].data[0] = newSpriteId;
+ gTasks[taskId].data[6] = var0;
+ gTasks[taskId].func = sub_80BAF38;
+}
+
+static void sub_80BAF38(u8 taskId)
+{
+ struct BattleAnimBgData animBgData;
+ struct Sprite *sprite;
+ u16 bg1Cnt;
+
+ gTasks[taskId].data[10] += 4;
+ gBattle_BG1_Y -= 4;
+ if (gTasks[taskId].data[10] == 64)
+ {
+ gTasks[taskId].data[10] = 0;
+ gBattle_BG1_Y += 64;
+ if (++gTasks[taskId].data[11] == 4)
+ {
+ sub_8073128(0);
+ gBattle_WIN0H = 0;
+ gBattle_WIN0V = 0;
+ SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR
+ | WININ_WIN1_BG_ALL | WININ_WIN1_OBJ | WININ_WIN1_CLR);
+ SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR
+ | WINOUT_WINOBJ_BG_ALL | WINOUT_WINOBJ_OBJ | WINOUT_WINOBJ_CLR);
+ if (!IsContest())
+ {
+ bg1Cnt = GetGpuReg(REG_OFFSET_BG1CNT);
+ ((struct BgCnt *)&bg1Cnt)->charBaseBlock = 0;
+ SetGpuReg(REG_OFFSET_BG1CNT, bg1Cnt);
+ }
+ SetGpuReg(REG_OFFSET_DISPCNT, GetGpuReg(REG_OFFSET_DISPCNT) ^ DISPCNT_OBJWIN_ON);
+ SetGpuReg(REG_OFFSET_BLDCNT, 0);
+ SetGpuReg(REG_OFFSET_BLDALPHA, 0);
+ sprite = &gSprites[GetAnimBattlerSpriteId(0)]; // unused
+ sprite = &gSprites[gTasks[taskId].data[0]];
+ DestroySprite(sprite);
+ sub_80752A0(&animBgData);
+ sub_8075358(animBgData.bgId);
+ if (gTasks[taskId].data[6] == 1)
+ ++gSprites[gBattlerSpriteIds[BATTLE_PARTNER(gBattleAnimAttacker)]].oam.priority;
+ gBattle_BG1_Y = 0;
+ DestroyAnimVisualTask(taskId);
+ }
+ }
+}
+
+void sub_80BB088(u8 taskId)
+{
+ u8 i;
+
+ sAnimStatsChangeData = AllocZeroed(sizeof(struct AnimStatsChangeData));
+ for (i = 0; i < 8; ++i)
+ sAnimStatsChangeData->data[i] = gBattleAnimArgs[i];
+ gTasks[taskId].func = sub_80BB0D8;
+}
+
+static void sub_80BB0D8(u8 taskId)
+{
+ if (sAnimStatsChangeData->data[2] == 0)
+ sAnimStatsChangeData->battler1 = gBattleAnimAttacker;
+ else
+ sAnimStatsChangeData->battler1 = gBattleAnimTarget;
+ sAnimStatsChangeData->battler2 = BATTLE_PARTNER(sAnimStatsChangeData->battler1);
+ if (IsContest() || (sAnimStatsChangeData->data[3] && !IsBattlerSpriteVisible(sAnimStatsChangeData->battler2)))
+ sAnimStatsChangeData->data[3] = 0;
+ gBattle_WIN0H = 0;
+ gBattle_WIN0V = 0;
+ SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR
+ | WININ_WIN1_BG_ALL | WININ_WIN1_OBJ | WININ_WIN1_CLR);
+ SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG0 | WINOUT_WIN01_BG2 | WINOUT_WIN01_BG3 | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR
+ | WINOUT_WINOBJ_BG_ALL | WINOUT_WINOBJ_OBJ | WINOUT_WINOBJ_CLR);
+ SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_OBJWIN_ON);
+ SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG1 | BLDCNT_TGT2_ALL | BLDCNT_EFFECT_BLEND);
+ SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(0, 16));
+ SetAnimBgAttribute(1, BG_ANIM_PRIORITY, 0);
+ SetAnimBgAttribute(1, BG_ANIM_SCREEN_SIZE, 0);
+ if (!IsContest())
+ SetAnimBgAttribute(1, BG_ANIM_CHAR_BASE_BLOCK, 1);
+ if (IsDoubleBattle() && sAnimStatsChangeData->data[3] == 0)
+ {
+ if (GetBattlerPosition(sAnimStatsChangeData->battler1) == B_POSITION_OPPONENT_RIGHT
+ || GetBattlerPosition(sAnimStatsChangeData->battler1) == B_POSITION_PLAYER_LEFT)
+ {
+ if (IsBattlerSpriteVisible(sAnimStatsChangeData->battler2) == TRUE)
+ {
+ gSprites[gBattlerSpriteIds[sAnimStatsChangeData->battler2]].oam.priority -= 1;
+ SetAnimBgAttribute(1, BG_ANIM_PRIORITY, 1);
+ sAnimStatsChangeData->higherPriority = 1;
+ }
+ }
+ }
+ if (GetBattlerSide(sAnimStatsChangeData->battler1) != B_SIDE_PLAYER)
+ sAnimStatsChangeData->species = GetMonData(&gEnemyParty[gBattlerPartyIndexes[sAnimStatsChangeData->battler1]], MON_DATA_SPECIES);
+ else
+ sAnimStatsChangeData->species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[sAnimStatsChangeData->battler1]], MON_DATA_SPECIES);
+ gTasks[taskId].func = sub_80BB2A0;
+}
+
+static void sub_80BB2A0(u8 taskId)
+{
+ struct BattleAnimBgData animBgData;
+ u8 spriteId, newSpriteId = 0;
+ u8 battlerSpriteId;
+
+ battlerSpriteId = gBattlerSpriteIds[sAnimStatsChangeData->battler1];
+ spriteId = sub_8076E34(sAnimStatsChangeData->battler1, battlerSpriteId, sAnimStatsChangeData->species);
+ if (sAnimStatsChangeData->data[3])
+ {
+ battlerSpriteId = gBattlerSpriteIds[sAnimStatsChangeData->battler2];
+ newSpriteId = sub_8076E34(sAnimStatsChangeData->battler2, battlerSpriteId, sAnimStatsChangeData->species);
+ }
+ sub_80752A0(&animBgData);
+ if (sAnimStatsChangeData->data[0] == 0)
+ AnimLoadCompressedBgTilemap(animBgData.bgId, gBattleStatMask1_Tilemap);
+ else
+ AnimLoadCompressedBgTilemap(animBgData.bgId, gBattleStatMask2_Tilemap);
+ if (IsContest())
+ sub_80730C0(animBgData.paletteId, animBgData.bgTilemap, 0, 0);
+ AnimLoadCompressedBgGfx(animBgData.bgId, gBattleStatMask_Gfx, animBgData.tilesOffset);
+ switch (sAnimStatsChangeData->data[1])
+ {
+ case 0:
+ LoadCompressedPalette(gBattleStatMask2_Pal, animBgData.paletteId * 16, 32);
+ break;
+ case 1:
+ LoadCompressedPalette(gBattleStatMask1_Pal, animBgData.paletteId * 16, 32);
+ break;
+ case 2:
+ LoadCompressedPalette(gBattleStatMask3_Pal, animBgData.paletteId * 16, 32);
+ break;
+ case 3:
+ LoadCompressedPalette(gBattleStatMask4_Pal, animBgData.paletteId * 16, 32);
+ break;
+ case 4:
+ LoadCompressedPalette(gBattleStatMask6_Pal, animBgData.paletteId * 16, 32);
+ break;
+ case 5:
+ LoadCompressedPalette(gBattleStatMask7_Pal, animBgData.paletteId * 16, 32);
+ break;
+ case 6:
+ LoadCompressedPalette(gBattleStatMask8_Pal, animBgData.paletteId * 16, 32);
+ break;
+ default:
+ LoadCompressedPalette(gBattleStatMask5_Pal, animBgData.paletteId * 16, 32);
+ break;
+ }
+ gBattle_BG1_X = 0;
+ gBattle_BG1_Y = 0;
+ if (sAnimStatsChangeData->data[0] == 1)
+ {
+ gBattle_BG1_X = 64;
+ gTasks[taskId].data[1] = -3;
+ }
+ else
+ {
+ gTasks[taskId].data[1] = 3;
+ }
+
+ if (sAnimStatsChangeData->data[4] == 0)
+ {
+ gTasks[taskId].data[4] = 10;
+ gTasks[taskId].data[5] = 20;
+ }
+ else
+ {
+ gTasks[taskId].data[4] = 13;
+ gTasks[taskId].data[5] = 30;
+ }
+ gTasks[taskId].data[0] = spriteId;
+ gTasks[taskId].data[2] = sAnimStatsChangeData->data[3];
+ gTasks[taskId].data[3] = newSpriteId;
+ gTasks[taskId].data[6] = sAnimStatsChangeData->higherPriority;
+ gTasks[taskId].data[7] = gBattlerSpriteIds[sAnimStatsChangeData->battler2];
+ gTasks[taskId].func = sub_80BB4B8;
+ if (sAnimStatsChangeData->data[0] == 0)
+ PlaySE12WithPanning(SE_W287, BattleAnimAdjustPanning2(PAN_SIDE_PLAYER));
+ else
+ PlaySE12WithPanning(SE_W287B, BattleAnimAdjustPanning2(PAN_SIDE_PLAYER));
+}
+
+static void sub_80BB4B8(u8 taskId)
+{
+ gBattle_BG1_Y += gTasks[taskId].data[1];
+ switch (gTasks[taskId].data[15])
+ {
+ case 0:
+ if (gTasks[taskId].data[11]++ > 0)
+ {
+ gTasks[taskId].data[11] = 0;
+ ++gTasks[taskId].data[12];
+ SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(gTasks[taskId].data[12], 16 - gTasks[taskId].data[12]));
+ if (gTasks[taskId].data[12] == gTasks[taskId].data[4])
+ ++gTasks[taskId].data[15];
+ }
+ break;
+ case 1:
+ if (++gTasks[taskId].data[10] == gTasks[taskId].data[5])
+ ++gTasks[taskId].data[15];
+ break;
+ case 2:
+ if (gTasks[taskId].data[11]++ > 0)
+ {
+ gTasks[taskId].data[11] = 0;
+ --gTasks[taskId].data[12];
+ SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(gTasks[taskId].data[12], 16 - gTasks[taskId].data[12]));
+ if (gTasks[taskId].data[12] == 0)
+ {
+ sub_8073128(0);
+ ++gTasks[taskId].data[15];
+ }
+ }
+ break;
+ case 3:
+ gBattle_WIN0H = 0;
+ gBattle_WIN0V = 0;
+ SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR
+ | WININ_WIN1_BG_ALL | WININ_WIN1_OBJ | WININ_WIN1_CLR);
+ SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR
+ | WINOUT_WINOBJ_BG_ALL | WINOUT_WINOBJ_OBJ | WINOUT_WINOBJ_CLR);
+ if (!IsContest())
+ SetAnimBgAttribute(1, BG_ANIM_CHAR_BASE_BLOCK, 0);
+ SetGpuReg(REG_OFFSET_DISPCNT, GetGpuReg(REG_OFFSET_DISPCNT) ^ DISPCNT_OBJWIN_ON);
+ SetGpuReg(REG_OFFSET_BLDCNT, 0);
+ SetGpuReg(REG_OFFSET_BLDALPHA, 0);
+ DestroySprite(&gSprites[gTasks[taskId].data[0]]);
+ if (gTasks[taskId].data[2])
+ DestroySprite(&gSprites[gTasks[taskId].data[3]]);
+ if (gTasks[taskId].data[6] == 1)
+ ++gSprites[gTasks[taskId].data[7]].oam.priority;
+ Free(sAnimStatsChangeData);
+ sAnimStatsChangeData = NULL;
+ DestroyAnimVisualTask(taskId);
+ break;
+ }
+}
+
+void sub_80BB660(u8 taskId)
+{
+ u32 selectedPalettes = sub_8075CB8(1, 1, 1, 1);
+
+ sub_80BB790(selectedPalettes, 0);
+ gTasks[taskId].data[14] = selectedPalettes >> 16;
+ selectedPalettes = sub_8075BE8(1, 0, 0, 0, 0, 0, 0) & 0xFFFF;
+ sub_80BB790(selectedPalettes, 0xFFFF);
+ gTasks[taskId].data[15] = selectedPalettes;
+ gTasks[taskId].data[0] = 0;
+ gTasks[taskId].data[1] = 0;
+ gTasks[taskId].func = sub_80BB6CC;
+}
+
+static void sub_80BB6CC(u8 taskId)
+{
+ u16 i;
+ struct Task *task = &gTasks[taskId];
+
+ switch (task->data[0])
+ {
+ case 0:
+ if (++task->data[1] > 6)
+ {
+ task->data[1] = 0;
+ task->data[2] = 16;
+ ++task->data[0];
+ }
+ break;
+ case 1:
+ if (++task->data[1] > 1)
+ {
+ task->data[1] = 0;
+ --task->data[2];
+ for (i = 0; i < 16; ++i)
+ {
+ if ((task->data[15] >> i) & 1)
+ {
+ u16 paletteOffset = i * 16;
+ BlendPalette(paletteOffset, 16, task->data[2], 0xFFFF);
+ }
+
+ if ((task->data[14] >> i) & 1)
+ {
+ u16 paletteOffset = i * 16 + 0x100;
+ BlendPalette(paletteOffset, 16, task->data[2], 0);
+ }
+ }
+
+ if (task->data[2] == 0)
+ ++task->data[0];
+ }
+ break;
+ case 2:
+ DestroyAnimVisualTask(taskId);
+ break;
+ }
+}
+
+static void sub_80BB790(u32 selectedPalettes, u16 color)
+{
+ u16 i, curOffset, paletteOffset;
+
+ for (i = 0; i < 32; selectedPalettes >>= 1, ++i)
+ if (selectedPalettes & 1)
+ for (curOffset = i * 16, paletteOffset = curOffset; curOffset < paletteOffset + 16; ++curOffset)
+ gPlttBufferFaded[curOffset] = color;
+}
+
+void sub_80BB7DC(u8 taskId)
+{
+ s32 j;
+ u32 battler, selectedPalettes = 0;
+
+ for (battler = 0; battler < MAX_BATTLERS_COUNT; ++battler)
+ if (gBattleAnimAttacker != battler)
+ selectedPalettes |= 1 << (battler + 16);
+ for (j = 5; j != 0; --j)
+ gBattleAnimArgs[j] = gBattleAnimArgs[j - 1];
+ StartBlendAnimSpriteColor(taskId, selectedPalettes);
+}
+
+void sub_80BB82C(u8 taskId)
+{
+ u8 newTaskId;
+
+ sub_8075458(0);
+ newTaskId = CreateTask(sub_80BB8A4, 5);
+ if (gBattleAnimArgs[2] && GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
+ {
+ gBattleAnimArgs[0] = -gBattleAnimArgs[0];
+ gBattleAnimArgs[1] = -gBattleAnimArgs[1];
+ }
+ gTasks[newTaskId].data[1] = gBattleAnimArgs[0];
+ gTasks[newTaskId].data[2] = gBattleAnimArgs[1];
+ gTasks[newTaskId].data[3] = gBattleAnimArgs[3];
+ ++gTasks[newTaskId].data[0];
+ DestroyAnimVisualTask(taskId);
+}
+
+static void sub_80BB8A4(u8 taskId)
+{
+ gTasks[taskId].data[10] += gTasks[taskId].data[1];
+ gTasks[taskId].data[11] += gTasks[taskId].data[2];
+ gBattle_BG3_X += gTasks[taskId].data[10] >> 8;
+ gBattle_BG3_Y += gTasks[taskId].data[11] >> 8;
+ gTasks[taskId].data[10] &= 0xFF;
+ gTasks[taskId].data[11] &= 0xFF;
+ if (gBattleAnimArgs[7] == gTasks[taskId].data[3])
+ {
+ gBattle_BG3_X = 0;
+ gBattle_BG3_Y = 0;
+ sub_8075458(1);
+ DestroyTask(taskId);
+ }
+}
+
+void AnimTask_GetAttackerSide(u8 taskId)
+{
+ gBattleAnimArgs[7] = GetBattlerSide(gBattleAnimAttacker);
+ DestroyAnimVisualTask(taskId);
+}
+
+void AnimTask_GetTargetSide(u8 taskId)
+{
+ gBattleAnimArgs[7] = GetBattlerSide(gBattleAnimTarget);
+ DestroyAnimVisualTask(taskId);
+}
+
+void AnimTask_GetTargetIsAttackerPartner(u8 taskId)
+{
+ gBattleAnimArgs[7] = BATTLE_PARTNER(gBattleAnimAttacker) == gBattleAnimTarget;
+ DestroyAnimVisualTask(taskId);
+}
+
+void sub_80BB9B0(u8 taskId)
+{
+ u16 battler;
+
+ for (battler = 0; battler < MAX_BATTLERS_COUNT; ++battler)
+ if (battler != gBattleAnimAttacker && IsBattlerSpriteVisible(battler))
+ gSprites[gBattlerSpriteIds[battler]].invisible = gBattleAnimArgs[0];
+ DestroyAnimVisualTask(taskId);
+}
+
+void sub_80BBA20(u8 taskId, s32 unused, u16 arg2, u8 battler1, u8 arg4, u8 arg5, u8 arg6, u8 arg7, const u32 *gfx, const u32 *tilemap, const u32 *palette)
+{
+ u16 species;
+ u8 spriteId, newSpriteId = 0;
+ u16 bg1Cnt;
+ struct BattleAnimBgData animBgData;
+ u8 battler2 = BATTLE_PARTNER(battler1);
+
+ if (IsContest() || (arg4 && !IsBattlerSpriteVisible(battler2)))
+ arg4 = 0;
+ gBattle_WIN0H = 0;
+ gBattle_WIN0V = 0;
+ SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR
+ | WININ_WIN1_BG_ALL | WININ_WIN1_OBJ | WININ_WIN1_CLR);
+ SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG0 | WINOUT_WIN01_BG2 | WINOUT_WIN01_BG3 | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR
+ | WINOUT_WINOBJ_BG_ALL | WINOUT_WINOBJ_OBJ | WINOUT_WINOBJ_CLR);
+ SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_OBJWIN_ON);
+ SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG1 | BLDCNT_TGT2_ALL | BLDCNT_EFFECT_BLEND);
+ SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(0, 16));
+ bg1Cnt = GetGpuReg(REG_OFFSET_BG1CNT);
+ ((vBgCnt *)&bg1Cnt)->priority = 0;
+ ((vBgCnt *)&bg1Cnt)->screenSize = 0;
+ ((vBgCnt *)&bg1Cnt)->areaOverflowMode = 1;
+ if (!IsContest())
+ ((vBgCnt *)&bg1Cnt)->charBaseBlock = 1;
+ SetGpuReg(REG_OFFSET_BG1CNT, bg1Cnt);
+ if (GetBattlerSide(battler1) != B_SIDE_PLAYER)
+ species = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler1]], MON_DATA_SPECIES);
+ else
+ species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battler1]], MON_DATA_SPECIES);
+ spriteId = sub_8076E34(battler1, gBattlerSpriteIds[battler1], species);
+ if (arg4)
+ newSpriteId = sub_8076E34(battler2, gBattlerSpriteIds[battler2], species);
+ sub_80752A0(&animBgData);
+ AnimLoadCompressedBgTilemap(animBgData.bgId, tilemap);
+ if (IsContest())
+ sub_80730C0(animBgData.paletteId, animBgData.bgTilemap, 0, 0);
+ AnimLoadCompressedBgGfx(animBgData.bgId, gfx, animBgData.tilesOffset);
+ LoadCompressedPalette(palette, animBgData.paletteId * 16, 32);
+ gBattle_BG1_X = 0;
+ gBattle_BG1_Y = 0;
+ gTasks[taskId].data[1] = arg2;
+ gTasks[taskId].data[4] = arg5;
+ gTasks[taskId].data[5] = arg7;
+ gTasks[taskId].data[6] = arg6;
+ gTasks[taskId].data[0] = spriteId;
+ gTasks[taskId].data[2] = arg4;
+ gTasks[taskId].data[3] = newSpriteId;
+ gTasks[taskId].func = sub_80BBC2C;
+}
+
+static void sub_80BBC2C(u8 taskId)
+{
+ gTasks[taskId].data[13] += gTasks[taskId].data[1] < 0 ? -gTasks[taskId].data[1] : gTasks[taskId].data[1];
+ if (gTasks[taskId].data[1] < 0)
+ gBattle_BG1_Y -= gTasks[taskId].data[13] >> 8;
+ else
+ gBattle_BG1_Y += gTasks[taskId].data[13] >> 8;
+ gTasks[taskId].data[13] &= 0xFF;
+ switch (gTasks[taskId].data[15])
+ {
+ case 0:
+ if (gTasks[taskId].data[11]++ >= gTasks[taskId].data[6])
+ {
+ gTasks[taskId].data[11] = 0;
+ ++gTasks[taskId].data[12];
+ SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(gTasks[taskId].data[12], 16 - gTasks[taskId].data[12]));
+ if (gTasks[taskId].data[12] == gTasks[taskId].data[4])
+ ++gTasks[taskId].data[15];
+ }
+ break;
+ case 1:
+ if (++gTasks[taskId].data[10] == gTasks[taskId].data[5])
+ ++gTasks[taskId].data[15];
+ break;
+ case 2:
+ if (gTasks[taskId].data[11]++ >= gTasks[taskId].data[6])
+ {
+ gTasks[taskId].data[11] = 0;
+ --gTasks[taskId].data[12];
+ SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(gTasks[taskId].data[12], 16 - gTasks[taskId].data[12]));
+ if (gTasks[taskId].data[12] == 0)
+ {
+ sub_8073128(0);
+ gBattle_WIN0H = 0;
+ gBattle_WIN0V = 0;
+ SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR
+ | WININ_WIN1_BG_ALL | WININ_WIN1_OBJ | WININ_WIN1_CLR);
+ SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR
+ | WINOUT_WINOBJ_BG_ALL | WINOUT_WINOBJ_OBJ | WINOUT_WINOBJ_CLR);
+ if (!IsContest())
+ {
+ u16 bg1Cnt = GetGpuReg(REG_OFFSET_BG1CNT);
+ ((vBgCnt *)&bg1Cnt)->charBaseBlock = 0;
+ SetGpuReg(REG_OFFSET_BG1CNT, bg1Cnt);
+ }
+ SetGpuReg(REG_OFFSET_DISPCNT, GetGpuReg(REG_OFFSET_DISPCNT) ^ DISPCNT_OBJWIN_ON);
+ SetGpuReg(REG_OFFSET_BLDCNT, 0);
+ SetGpuReg(REG_OFFSET_BLDALPHA, 0);
+ DestroySprite(&gSprites[gTasks[taskId].data[0]]);
+ if (gTasks[taskId].data[2])
+ DestroySprite(&gSprites[gTasks[taskId].data[3]]);
+ DestroyAnimVisualTask(taskId);
+ }
+ }
+ break;
+ }
+}
+
+void AnimTask_GetBattleTerrain(u8 taskId)
+{
+ gBattleAnimArgs[0] = gBattleTerrain;
+ DestroyAnimVisualTask(taskId);
+}
+
+void sub_80BBE10(u8 taskId)
+{
+ gMonSpritesGfxPtr->field_17C = AllocZeroed(0x2000);
+ DestroyAnimVisualTask(taskId);
+}
+
+void sub_80BBE3C(u8 taskId)
+{
+ FREE_AND_SET_NULL(gMonSpritesGfxPtr->field_17C);
+ DestroyAnimVisualTask(taskId);
+}
+
+void sub_80BBE6C(u8 taskId)
+{
+ u32 selectedPalettes;
+ s32 paletteIndex = 0;
+
+ if (gBattleAnimArgs[0] == 0)
+ for (selectedPalettes = sub_8075BE8(1, 0, 0, 0, 0, 0, 0);
+ (selectedPalettes & 1) == 0;
+ ++paletteIndex)
+ selectedPalettes >>= 1;
+ else if (gBattleAnimArgs[0] == 1)
+ paletteIndex = gBattleAnimAttacker + 16;
+ else if (gBattleAnimArgs[0] == 2)
+ paletteIndex = gBattleAnimTarget + 16;
+ memcpy(&gMonSpritesGfxPtr->field_17C[gBattleAnimArgs[1] * 16], &gPlttBufferUnfaded[paletteIndex * 16], 32);
+ DestroyAnimVisualTask(taskId);
+}
+
+void sub_80BBF08(u8 taskId)
+{
+ u32 selectedPalettes;
+ s32 paletteIndex = 0;
+
+ if (gBattleAnimArgs[0] == 0)
+ for (selectedPalettes = sub_8075BE8(1, 0, 0, 0, 0, 0, 0);
+ (selectedPalettes & 1) == 0;
+ ++paletteIndex)
+ selectedPalettes >>= 1;
+ else if (gBattleAnimArgs[0] == 1)
+ paletteIndex = gBattleAnimAttacker + 16;
+ else if (gBattleAnimArgs[0] == 2)
+ paletteIndex = gBattleAnimTarget + 16;
+ memcpy(&gPlttBufferUnfaded[paletteIndex * 16], &gMonSpritesGfxPtr->field_17C[gBattleAnimArgs[1] * 16], 32);
+ DestroyAnimVisualTask(taskId);
+}
+
+void sub_80BBFA4(u8 taskId)
+{
+ u32 selectedPalettes;
+ s32 paletteIndex = 0;
+
+ if (gBattleAnimArgs[0] == 0)
+ for (selectedPalettes = sub_8075BE8(1, 0, 0, 0, 0, 0, 0);
+ (selectedPalettes & 1) == 0;
+ ++paletteIndex)
+ selectedPalettes >>= 1;
+ else if (gBattleAnimArgs[0] == 1)
+ paletteIndex = gBattleAnimAttacker + 16;
+ else if (gBattleAnimArgs[0] == 2)
+ paletteIndex = gBattleAnimTarget + 16;
+ memcpy(&gPlttBufferUnfaded[paletteIndex * 16], &gPlttBufferFaded[paletteIndex * 16], 32);
+ DestroyAnimVisualTask(taskId);
+}
+
+void AnimTask_IsContest(u8 taskId)
+{
+ if (IsContest())
+ gBattleAnimArgs[7] = 1;
+ else
+ gBattleAnimArgs[7] = 0;
+ DestroyAnimVisualTask(taskId);
+}
+
+void sub_80BC060(u8 taskId)
+{
+ gBattleAnimAttacker = gBattlerTarget;
+ gBattleAnimTarget = gEffectBattler;
+ DestroyAnimVisualTask(taskId);
+}
+
+void AnimTask_IsTargetSameSide(u8 taskId)
+{
+ if (GetBattlerSide(gBattleAnimAttacker) == GetBattlerSide(gBattleAnimTarget))
+ gBattleAnimArgs[7] = 1;
+ else
+ gBattleAnimArgs[7] = 0;
+ DestroyAnimVisualTask(taskId);
+}
+
+void sub_80BC0DC(u8 taskId)
+{
+ gBattleAnimTarget = gBattlerTarget;
+ DestroyAnimVisualTask(taskId);
+}
+
+void sub_80BC0FC(u8 taskId)
+{
+ gBattleAnimAttacker = gBattlerAttacker;
+ gBattleAnimTarget = gEffectBattler;
+ DestroyAnimVisualTask(taskId);
+}
+
+void sub_80BC12C(u8 taskId)
+{
+ if (IsContest())
+ {
+ DestroyAnimVisualTask(taskId);
+ }
+ else
+ {
+ gTasks[taskId].data[0] = gBattleSpritesDataPtr->battlerData[gBattleAnimAttacker].invisible;
+ gBattleSpritesDataPtr->battlerData[gBattleAnimAttacker].invisible = 1;
+ gTasks[taskId].func = sub_80BC19C;
+ --gAnimVisualTaskCount;
+ }
+}
+
+static void sub_80BC19C(u8 taskId)
+{
+ if (gBattleAnimArgs[7] == 0x1000)
+ {
+ gBattleSpritesDataPtr->battlerData[gBattleAnimAttacker].invisible = (u8)gTasks[taskId].data[0] & 1;
+ DestroyTask(taskId);
+ }
+}
diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c
index 0d827c8db..a9bb5bc6e 100644
--- a/src/battle_controller_player.c
+++ b/src/battle_controller_player.c
@@ -1191,7 +1191,7 @@ static void sub_80303A8(u8 taskId)
{
s16 *data = gTasks[taskId].data;
u8 battlerId = tExpTask_battler;
- u16 v5 = sub_80768B0(battlerId);
+ u16 v5 = GetBattlerSpriteBGPriorityRank(battlerId);
bool32 v6 = ((v5 ^ BIT_SIDE)) != B_SIDE_PLAYER;
struct Sprite *sprite = &gSprites[gBattlerSpriteIds[battlerId]];
@@ -1222,7 +1222,7 @@ static void sub_80303A8(u8 taskId)
u32 battlerIdAlt = battlerId;
bool32 v6Alt = v6;
- sub_8072E48(battlerIdAlt, v6Alt);
+ MoveBattlerSpriteToBG(battlerIdAlt, v6Alt);
}
++data[15];
break;
diff --git a/src/battle_intro.c b/src/battle_intro.c
new file mode 100644
index 000000000..93141f2ca
--- /dev/null
+++ b/src/battle_intro.c
@@ -0,0 +1,495 @@
+#include "global.h"
+#include "battle.h"
+#include "battle_anim.h"
+#include "battle_setup.h"
+#include "bg.h"
+#include "gpu_regs.h"
+#include "main.h"
+#include "scanline_effect.h"
+#include "task.h"
+#include "trig.h"
+#include "constants/trainers.h"
+
+static EWRAM_DATA u16 sBgCnt = 0;
+
+extern const u8 gUnknown_83E7CCA[];
+extern const u8 gUnknown_83E7CCE[];
+
+static void BattleIntroSlide1(u8 taskId);
+static void BattleIntroSlide2(u8 taskId);
+static void BattleIntroSlide3(u8 taskId);
+static void BattleIntroSlideLink(u8 taskId);
+
+static const TaskFunc sBattleIntroSlideFuncs[] =
+{
+ BattleIntroSlide1, // BATTLE_TERRAIN_GRASS
+ BattleIntroSlide1, // BATTLE_TERRAIN_LONG_GRASS
+ BattleIntroSlide2, // BATTLE_TERRAIN_SAND
+ BattleIntroSlide2, // BATTLE_TERRAIN_UNDERWATER
+ BattleIntroSlide2, // BATTLE_TERRAIN_WATER
+ BattleIntroSlide1, // BATTLE_TERRAIN_POND
+ BattleIntroSlide1, // BATTLE_TERRAIN_MOUNTAIN
+ BattleIntroSlide1, // BATTLE_TERRAIN_CAVE
+ BattleIntroSlide3, // BATTLE_TERRAIN_BUILDING
+ BattleIntroSlide3, // BATTLE_TERRAIN_PLAIN
+};
+
+void SetAnimBgAttribute(u8 bgId, u8 attributeId, u8 value)
+{
+ if (bgId < 4)
+ {
+ sBgCnt = GetGpuReg(gUnknown_83E7CCA[bgId]);
+ switch (attributeId)
+ {
+ case BG_ANIM_SCREEN_SIZE:
+ ((struct BgCnt *)&sBgCnt)->screenSize = value;
+ break;
+ case BG_ANIM_AREA_OVERFLOW_MODE:
+ ((struct BgCnt *)&sBgCnt)->areaOverflowMode = value;
+ break;
+ case BG_ANIM_MOSAIC:
+ ((struct BgCnt *)&sBgCnt)->mosaic = value;
+ break;
+ case BG_ANIM_CHAR_BASE_BLOCK:
+ ((struct BgCnt *)&sBgCnt)->charBaseBlock = value;
+ break;
+ case BG_ANIM_PRIORITY:
+ ((struct BgCnt *)&sBgCnt)->priority = value;
+ break;
+ case BG_ANIM_PALETTES_MODE:
+ ((struct BgCnt *)&sBgCnt)->palettes = value;
+ break;
+ case BG_ANIM_SCREEN_BASE_BLOCK:
+ ((struct BgCnt *)&sBgCnt)->screenBaseBlock = value;
+ break;
+ }
+ SetGpuReg(gUnknown_83E7CCA[bgId], sBgCnt);
+ }
+}
+
+s32 GetAnimBgAttribute(u8 bgId, u8 attributeId)
+{
+ u16 bgCnt;
+
+ if (bgId < 4)
+ {
+ bgCnt = GetGpuReg(gUnknown_83E7CCE[bgId]);
+ switch (attributeId)
+ {
+ case BG_ANIM_SCREEN_SIZE:
+ return ((struct BgCnt *)&bgCnt)->screenSize;
+ case BG_ANIM_AREA_OVERFLOW_MODE:
+ return ((struct BgCnt *)&bgCnt)->areaOverflowMode;
+ case BG_ANIM_MOSAIC:
+ return ((struct BgCnt *)&bgCnt)->mosaic;
+ case BG_ANIM_CHAR_BASE_BLOCK:
+ return ((struct BgCnt *)&bgCnt)->charBaseBlock;
+ case BG_ANIM_PRIORITY:
+ return ((struct BgCnt *)&bgCnt)->priority;
+ case BG_ANIM_PALETTES_MODE:
+ return ((struct BgCnt *)&bgCnt)->palettes;
+ case BG_ANIM_SCREEN_BASE_BLOCK:
+ return ((struct BgCnt *)&bgCnt)->screenBaseBlock;
+ }
+ }
+ return 0;
+}
+
+void HandleIntroSlide(u8 terrain)
+{
+ u8 taskId;
+
+ if (gBattleTypeFlags & BATTLE_TYPE_LINK)
+ {
+ taskId = CreateTask(BattleIntroSlideLink, 0);
+ }
+ else if ((gBattleTypeFlags & BATTLE_TYPE_KYOGRE_GROUDON) && gGameVersion != VERSION_RUBY)
+ {
+ terrain = BATTLE_TERRAIN_UNDERWATER;
+ taskId = CreateTask(BattleIntroSlide2, 0);
+ }
+ else
+ {
+ taskId = CreateTask(sBattleIntroSlideFuncs[terrain], 0);
+ }
+ gTasks[taskId].data[0] = 0;
+ gTasks[taskId].data[1] = terrain;
+ gTasks[taskId].data[2] = 0;
+ gTasks[taskId].data[3] = 0;
+ gTasks[taskId].data[4] = 0;
+ gTasks[taskId].data[5] = 0;
+ gTasks[taskId].data[6] = 0;
+}
+
+void sub_80BC41C(u8 taskId)
+{
+ DestroyTask(taskId);
+ gBattle_BG1_X = 0;
+ gBattle_BG1_Y = 0;
+ gBattle_BG2_X = 0;
+ gBattle_BG2_Y = 0;
+ SetGpuReg(REG_OFFSET_BLDCNT, 0);
+ SetGpuReg(REG_OFFSET_BLDALPHA, 0);
+ SetGpuReg(REG_OFFSET_BLDY, 0);
+ SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR | WININ_WIN1_BG_ALL | WININ_WIN1_OBJ | WININ_WIN1_CLR);
+ SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR | WINOUT_WINOBJ_BG_ALL | WINOUT_WINOBJ_OBJ | WINOUT_WINOBJ_CLR);
+}
+
+static void BattleIntroSlide1(u8 taskId)
+{
+ s32 i;
+
+ gBattle_BG1_X += 6;
+ switch (gTasks[taskId].data[0])
+ {
+ case 0:
+ if (gBattleTypeFlags & BATTLE_TYPE_LINK)
+ {
+ gTasks[taskId].data[2] = 16;
+ ++gTasks[taskId].data[0];
+ }
+ else
+ {
+ gTasks[taskId].data[2] = 1;
+ ++gTasks[taskId].data[0];
+ }
+ break;
+ case 1:
+ if (--gTasks[taskId].data[2] == 0)
+ {
+ ++gTasks[taskId].data[0];
+ SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR);
+ }
+ break;
+ case 2:
+ gBattle_WIN0V -= 0xFF;
+ if ((gBattle_WIN0V & 0xFF00) == 0x3000)
+ {
+ ++gTasks[taskId].data[0];
+ gTasks[taskId].data[2] = 240;
+ gTasks[taskId].data[3] = 32;
+ gIntroSlideFlags &= ~1;
+ }
+ break;
+ case 3:
+ if (gTasks[taskId].data[3])
+ {
+ --gTasks[taskId].data[3];
+ }
+ else
+ {
+ if (gTasks[taskId].data[1] == 1)
+ {
+ if (gBattle_BG1_Y != 0xFFB0)
+ gBattle_BG1_Y -= 2;
+ }
+ else if (gBattle_BG1_Y != 0xFFC8)
+ {
+ gBattle_BG1_Y -= 1;
+ }
+ }
+ if (gBattle_WIN0V & 0xFF00)
+ gBattle_WIN0V -= 0x3FC;
+ if (gTasks[taskId].data[2])
+ gTasks[taskId].data[2] -= 2;
+ // Scanline settings have already been set in CB2_InitBattleInternal
+ for (i = 0; i < 80; ++i)
+ gScanlineEffectRegBuffers[gScanlineEffect.srcBuffer][i] = gTasks[taskId].data[2];
+ while (i < 160)
+ gScanlineEffectRegBuffers[gScanlineEffect.srcBuffer][i++] = -gTasks[taskId].data[2];
+ if (!gTasks[taskId].data[2])
+ {
+ gScanlineEffect.state = 3;
+ ++gTasks[taskId].data[0];
+ CpuFill32(0, (void *)BG_SCREEN_ADDR(28), BG_SCREEN_SIZE);
+ SetBgAttribute(1, BG_ATTR_CHARBASEINDEX, 0);
+ SetBgAttribute(2, BG_ATTR_CHARBASEINDEX, 0);
+ SetGpuReg(REG_OFFSET_BG1CNT, BGCNT_PRIORITY(0) | BGCNT_CHARBASE(0) | BGCNT_16COLOR | BGCNT_SCREENBASE(28) | BGCNT_TXT256x512);
+ SetGpuReg(REG_OFFSET_BG2CNT, BGCNT_PRIORITY(0) | BGCNT_CHARBASE(0) | BGCNT_16COLOR | BGCNT_SCREENBASE(30) | BGCNT_TXT512x256);
+ }
+ break;
+ case 4:
+ sub_80BC41C(taskId);
+ break;
+ }
+}
+
+static void BattleIntroSlide2(u8 taskId)
+{
+ s32 i;
+
+ switch (gTasks[taskId].data[1])
+ {
+ case 2:
+ case 4:
+ gBattle_BG1_X += 8;
+ break;
+ case 3:
+ gBattle_BG1_X += 6;
+ break;
+ }
+ if (gTasks[taskId].data[1] == 4)
+ {
+ gBattle_BG1_Y = Cos2(gTasks[taskId].data[6]) / 512 - 8;
+ if (gTasks[taskId].data[6] < 180)
+ gTasks[taskId].data[6] += 4;
+ else
+ gTasks[taskId].data[6] += 6;
+ if (gTasks[taskId].data[6] == 360)
+ gTasks[taskId].data[6] = 0;
+ }
+ switch (gTasks[taskId].data[0])
+ {
+ case 0:
+ gTasks[taskId].data[4] = 16;
+ if (gBattleTypeFlags & BATTLE_TYPE_LINK)
+ {
+ gTasks[taskId].data[2] = 16;
+ ++gTasks[taskId].data[0];
+ }
+ else
+ {
+ gTasks[taskId].data[2] = 1;
+ ++gTasks[taskId].data[0];
+ }
+ break;
+ case 1:
+ if (--gTasks[taskId].data[2] == 0)
+ {
+ ++gTasks[taskId].data[0];
+ SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR);
+ }
+ break;
+ case 2:
+ gBattle_WIN0V -= 0xFF;
+ if ((gBattle_WIN0V & 0xFF00) == 0x3000)
+ {
+ ++gTasks[taskId].data[0];
+ gTasks[taskId].data[2] = 240;
+ gTasks[taskId].data[3] = 32;
+ gTasks[taskId].data[5] = 1;
+ gIntroSlideFlags &= ~1;
+ }
+ break;
+ case 3:
+ if (gTasks[taskId].data[3])
+ {
+ if (--gTasks[taskId].data[3] == 0)
+ {
+ SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG1 | BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_BG3 | BLDCNT_TGT2_OBJ);
+ SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(15, 0));
+ SetGpuReg(REG_OFFSET_BLDY, 0);
+ }
+ }
+ else if ((gTasks[taskId].data[4] & 0x1F) && --gTasks[taskId].data[5] == 0)
+ {
+ gTasks[taskId].data[4] += 0xFF;
+ gTasks[taskId].data[5] = 4;
+ }
+ if (gBattle_WIN0V & 0xFF00)
+ gBattle_WIN0V -= 0x3FC;
+
+ if (gTasks[taskId].data[2])
+ gTasks[taskId].data[2] -= 2;
+ // Scanline settings have already been set in CB2_InitBattleInternal()
+ for (i = 0; i < 80; ++i)
+ gScanlineEffectRegBuffers[gScanlineEffect.srcBuffer][i] = gTasks[taskId].data[2];
+ while (i < 160)
+ gScanlineEffectRegBuffers[gScanlineEffect.srcBuffer][i++] = -gTasks[taskId].data[2];
+ if (!gTasks[taskId].data[2])
+ {
+ gScanlineEffect.state = 3;
+ ++gTasks[taskId].data[0];
+ CpuFill32(0, (void *)BG_SCREEN_ADDR(28), BG_SCREEN_SIZE);
+ SetBgAttribute(1, BG_ATTR_CHARBASEINDEX, 0);
+ SetBgAttribute(2, BG_ATTR_CHARBASEINDEX, 0);
+ SetGpuReg(REG_OFFSET_BG1CNT, BGCNT_PRIORITY(0) | BGCNT_CHARBASE(0) | BGCNT_16COLOR | BGCNT_SCREENBASE(28) | BGCNT_TXT256x512);
+ SetGpuReg(REG_OFFSET_BG2CNT, BGCNT_PRIORITY(0) | BGCNT_CHARBASE(0) | BGCNT_16COLOR | BGCNT_SCREENBASE(30) | BGCNT_TXT512x256);
+ }
+ break;
+ case 4:
+ sub_80BC41C(taskId);
+ break;
+ }
+ if (gTasks[taskId].data[0] != 4)
+ SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(gTasks[taskId].data[4], 0));
+}
+
+static void BattleIntroSlide3(u8 taskId)
+{
+ s32 i;
+
+ gBattle_BG1_X += 8;
+ switch (gTasks[taskId].data[0])
+ {
+ case 0:
+ SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG1 | BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_BG3 | BLDCNT_TGT2_OBJ);
+ SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(8, 8));
+ SetGpuReg(REG_OFFSET_BLDY, 0);
+ gTasks[taskId].data[4] = BLDALPHA_BLEND(8, 8);
+ if (gBattleTypeFlags & BATTLE_TYPE_LINK)
+ {
+ gTasks[taskId].data[2] = 16;
+ ++gTasks[taskId].data[0];
+ }
+ else
+ {
+ gTasks[taskId].data[2] = 1;
+ ++gTasks[taskId].data[0];
+ }
+ break;
+ case 1:
+ if (--gTasks[taskId].data[2] == 0)
+ {
+ ++gTasks[taskId].data[0];
+ SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR);
+ }
+ break;
+ case 2:
+ gBattle_WIN0V -= 0xFF;
+ if ((gBattle_WIN0V & 0xFF00) == 0x3000)
+ {
+ ++gTasks[taskId].data[0];
+ gTasks[taskId].data[2] = 240;
+ gTasks[taskId].data[3] = 32;
+ gTasks[taskId].data[5] = 1;
+ gIntroSlideFlags &= ~1;
+ }
+ break;
+ case 3:
+ if (gTasks[taskId].data[3])
+ {
+ --gTasks[taskId].data[3];
+ }
+ else if ((gTasks[taskId].data[4] & 0xF) && --gTasks[taskId].data[5] == 0)
+ {
+ gTasks[taskId].data[4] += 0xFF;
+ gTasks[taskId].data[5] = 6;
+ }
+ if (gBattle_WIN0V & 0xFF00)
+ gBattle_WIN0V -= 0x3FC;
+ if (gTasks[taskId].data[2])
+ gTasks[taskId].data[2] -= 2;
+ // Scanline settings have already been set in CB2_InitBattleInternal()
+ for (i = 0; i < 80; ++i)
+ gScanlineEffectRegBuffers[gScanlineEffect.srcBuffer][i] = gTasks[taskId].data[2];
+ while (i < 160)
+ gScanlineEffectRegBuffers[gScanlineEffect.srcBuffer][i++] = -gTasks[taskId].data[2];
+ if (!gTasks[taskId].data[2])
+ {
+ gScanlineEffect.state = 3;
+ ++gTasks[taskId].data[0];
+ CpuFill32(0, (void *)BG_SCREEN_ADDR(28), BG_SCREEN_SIZE);
+ SetBgAttribute(1, BG_ATTR_CHARBASEINDEX, 0);
+ SetBgAttribute(2, BG_ATTR_CHARBASEINDEX, 0);
+ SetGpuReg(REG_OFFSET_BG1CNT, BGCNT_PRIORITY(0) | BGCNT_CHARBASE(0) | BGCNT_16COLOR | BGCNT_SCREENBASE(28) | BGCNT_TXT256x512);
+ SetGpuReg(REG_OFFSET_BG2CNT, BGCNT_PRIORITY(0) | BGCNT_CHARBASE(0) | BGCNT_16COLOR | BGCNT_SCREENBASE(30) | BGCNT_TXT512x256);
+ }
+ break;
+ case 4:
+ sub_80BC41C(taskId);
+ break;
+ }
+ if (gTasks[taskId].data[0] != 4)
+ SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(gTasks[taskId].data[4], 0));
+}
+
+static void BattleIntroSlideLink(u8 taskId)
+{
+ s32 i;
+
+ if (gTasks[taskId].data[0] > 1 && !gTasks[taskId].data[4])
+ {
+ u16 var0 = gBattle_BG1_X & 0x8000;
+
+ if (var0 || gBattle_BG1_X < 80)
+ {
+ gBattle_BG1_X += 3;
+ gBattle_BG2_X -= 3;
+ }
+ else
+ {
+ CpuFill32(0, (void *)BG_SCREEN_ADDR(28), BG_SCREEN_SIZE);
+ CpuFill32(0, (void *)BG_SCREEN_ADDR(30), BG_SCREEN_SIZE);
+ gTasks[taskId].data[4] = 1;
+ }
+ }
+ switch (gTasks[taskId].data[0])
+ {
+ case 0:
+ gTasks[taskId].data[2] = 32;
+ ++gTasks[taskId].data[0];
+ break;
+ case 1:
+ if (--gTasks[taskId].data[2] == 0)
+ {
+ ++gTasks[taskId].data[0];
+ gSprites[gBattleStruct->linkBattleVsSpriteId_V].oam.objMode = ST_OAM_OBJ_WINDOW;
+ gSprites[gBattleStruct->linkBattleVsSpriteId_V].callback = sub_801182C;
+ gSprites[gBattleStruct->linkBattleVsSpriteId_S].oam.objMode = ST_OAM_OBJ_WINDOW;
+ gSprites[gBattleStruct->linkBattleVsSpriteId_S].callback = sub_801182C;
+ SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR);
+ SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WINOBJ_BG_ALL | WINOUT_WINOBJ_OBJ | WINOUT_WINOBJ_CLR | WINOUT_WIN01_BG1 | WINOUT_WIN01_BG2);
+ }
+ break;
+ case 2:
+ gBattle_WIN0V -= 0xFF;
+ if ((gBattle_WIN0V & 0xFF00) == 0x3000)
+ {
+ ++gTasks[taskId].data[0];
+ gTasks[taskId].data[2] = 240;
+ gTasks[taskId].data[3] = 32;
+ gIntroSlideFlags &= ~1;
+ }
+ break;
+ case 3:
+ if (gBattle_WIN0V & 0xFF00)
+ gBattle_WIN0V -= 0x3FC;
+ if (gTasks[taskId].data[2])
+ gTasks[taskId].data[2] -= 2;
+ // Scanline settings have already been set in CB2_InitBattleInternal()
+ for (i = 0; i < 80; ++i)
+ gScanlineEffectRegBuffers[gScanlineEffect.srcBuffer][i] = gTasks[taskId].data[2];
+ while (i < 160)
+ gScanlineEffectRegBuffers[gScanlineEffect.srcBuffer][i++] = -gTasks[taskId].data[2];
+ if (!gTasks[taskId].data[2])
+ {
+ gScanlineEffect.state = 3;
+ ++gTasks[taskId].data[0];
+ SetBgAttribute(1, BG_ATTR_CHARBASEINDEX, 0);
+ SetBgAttribute(2, BG_ATTR_CHARBASEINDEX, 0);
+ SetGpuReg(REG_OFFSET_BG1CNT, BGCNT_PRIORITY(0) | BGCNT_CHARBASE(0) | BGCNT_16COLOR | BGCNT_SCREENBASE(28) | BGCNT_TXT256x512);
+ SetGpuReg(REG_OFFSET_BG2CNT, BGCNT_PRIORITY(0) | BGCNT_CHARBASE(0) | BGCNT_16COLOR | BGCNT_SCREENBASE(30) | BGCNT_TXT512x256);
+ }
+ break;
+ case 4:
+ sub_80BC41C(taskId);
+ break;
+ }
+}
+
+void sub_80BCEF4(s32 bgId, u8 arg1, u8 arg2, u8 battlerPosition, u8 arg4, u8 *arg5, u16 *arg6, u16 tilesOffset)
+{
+ s32 i, j;
+ u8 battler = GetBattlerAtPosition(battlerPosition);
+ s32 offset = tilesOffset;
+
+ CpuCopy16(gMonSpritesGfxPtr->sprites[battlerPosition] + BG_SCREEN_SIZE * gBattleMonForms[battler], arg5, BG_SCREEN_SIZE);
+ LoadBgTiles(bgId, arg5, 0x1000, tilesOffset);
+ for (i = arg2; i < arg2 + 8; ++i)
+ for (j = arg1; j < arg1 + 8; ++j)
+ arg6[i * 32 + j] = offset++ | (arg4 << 12);
+ LoadBgTilemap(bgId, arg6, BG_SCREEN_SIZE, 0);
+}
+
+// not used
+static void sub_80BCFCC(u8 arg0, u8 arg1, u8 battlerPosition, u8 arg3, u8 arg4, u16 arg5, u8 arg6, u8 arg7)
+{
+ s32 i, j, offset;
+
+ DmaCopy16(3, gMonSpritesGfxPtr->sprites[battlerPosition] + BG_SCREEN_SIZE * arg3, (void *)BG_SCREEN_ADDR(0) + arg5, BG_SCREEN_SIZE);
+ offset = (arg5 >> 5) - (arg7 << 9);
+ for (i = arg1; i < arg1 + 8; ++i)
+ for (j = arg0; j < arg0 + 8; ++j)
+ *((u16 *)(BG_VRAM) + (i * 32) + (j + (arg6 << 10))) = offset++ | (arg4 << 12);
+}
diff --git a/src/dark.c b/src/dark.c
new file mode 100644
index 000000000..c080e6243
--- /dev/null
+++ b/src/dark.c
@@ -0,0 +1,921 @@
+#include "global.h"
+#include "battle_anim.h"
+#include "gpu_regs.h"
+#include "graphics.h"
+#include "palette.h"
+#include "scanline_effect.h"
+#include "trig.h"
+#include "util.h"
+
+static void sub_80B7ACC(struct Sprite *sprite);
+static void sub_80B7BD4(struct Sprite *sprite);
+static void sub_80B7C88(struct Sprite *sprite);
+static void sub_80B86B0(struct Sprite *sprite);
+static void sub_80B7954(u8 taskId);
+static void sub_80B7A14(u8 taskId);
+static void sub_80B7B48(struct Sprite *sprite);
+static void sub_80B7C10(struct Sprite *sprite);
+static void sub_80B7C50(struct Sprite *sprite);
+static void sub_80B7D88(struct Sprite *sprite);
+static void sub_80B856C(u8 priority);
+static void sub_80B7F58(u8 taskId);
+static void sub_80B843C(struct Task *task);
+static void sub_80B82C0(u8 taskId);
+static void sub_80B8920(u8 taskId);
+
+const struct SpriteTemplate gUnknown_83E7878 =
+{
+ .tileTag = ANIM_TAG_TIED_BAG,
+ .paletteTag = ANIM_TAG_TIED_BAG,
+ .oam = &gOamData_83AC9D0,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = sub_80B7ACC,
+};
+
+static const union AffineAnimCmd gUnknown_83E7890[] =
+{
+ AFFINEANIMCMD_FRAME(0x0, 0x0, 0, 1),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd gUnknown_83E78A0[] =
+{
+ AFFINEANIMCMD_FRAME(0x0, 0x0, 32, 1),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd gUnknown_83E78B0[] =
+{
+ AFFINEANIMCMD_FRAME(0x0, 0x0, 64, 1),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd gUnknown_83E78C0[] =
+{
+ AFFINEANIMCMD_FRAME(0x0, 0x0, 96, 1),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd gUnknown_83E78D0[] =
+{
+ AFFINEANIMCMD_FRAME(0x0, 0x0, -128, 1),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd gUnknown_83E78E0[] =
+{
+ AFFINEANIMCMD_FRAME(0x0, 0x0, -96, 1),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd gUnknown_83E78F0[] =
+{
+ AFFINEANIMCMD_FRAME(0x0, 0x0, -64, 1),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd gUnknown_83E7900[] =
+{
+ AFFINEANIMCMD_FRAME(0x0, 0x0, -32, 1),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd *const gUnknown_83E7910[] =
+{
+ gUnknown_83E7890,
+ gUnknown_83E78A0,
+ gUnknown_83E78B0,
+ gUnknown_83E78C0,
+ gUnknown_83E78D0,
+ gUnknown_83E78E0,
+ gUnknown_83E78F0,
+ gUnknown_83E7900,
+};
+
+const struct SpriteTemplate gUnknown_83E7930 =
+{
+ .tileTag = ANIM_TAG_SHARP_TEETH,
+ .paletteTag = ANIM_TAG_SHARP_TEETH,
+ .oam = &gOamData_83ACB60,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gUnknown_83E7910,
+ .callback = sub_80B7BD4,
+};
+
+const struct SpriteTemplate gUnknown_83E7948 =
+{
+ .tileTag = ANIM_TAG_CLAMP,
+ .paletteTag = ANIM_TAG_CLAMP,
+ .oam = &gOamData_83ACB60,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gUnknown_83E7910,
+ .callback = sub_80B7BD4,
+};
+
+static const union AffineAnimCmd gUnknown_83E7960[] =
+{
+ AFFINEANIMCMD_FRAME(0xC0, 0xC0, 80, 0),
+ AFFINEANIMCMD_FRAME(0x0, 0x0, -2, 8),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd gUnknown_83E7978[] =
+{
+ AFFINEANIMCMD_FRAME(0xC0, 0xC0, -80, 0),
+ AFFINEANIMCMD_FRAME(0x0, 0x0, 2, 8),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd *const gUnknown_83E7990[] =
+{
+ gUnknown_83E7960,
+ gUnknown_83E7978,
+};
+
+const struct SpriteTemplate gUnknown_83E7998 =
+{
+ .tileTag = ANIM_TAG_SMALL_BUBBLES,
+ .paletteTag = ANIM_TAG_SMALL_BUBBLES,
+ .oam = &gOamData_83ACA30,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gUnknown_83E7990,
+ .callback = sub_80B7C88,
+};
+
+static const union AnimCmd gUnknown_83E79B0[] =
+{
+ ANIMCMD_FRAME(0, 4),
+ ANIMCMD_FRAME(16, 4),
+ ANIMCMD_FRAME(32, 4),
+ ANIMCMD_FRAME(48, 4),
+ ANIMCMD_FRAME(64, 4),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_83E79C8[] =
+{
+ ANIMCMD_FRAME(0, 4, .hFlip = TRUE),
+ ANIMCMD_FRAME(16, 4, .hFlip = TRUE),
+ ANIMCMD_FRAME(32, 4, .hFlip = TRUE),
+ ANIMCMD_FRAME(48, 4, .hFlip = TRUE),
+ ANIMCMD_FRAME(64, 4, .hFlip = TRUE),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd *const gUnknown_83E79E0[] =
+{
+ gUnknown_83E79B0,
+ gUnknown_83E79C8,
+};
+
+const struct SpriteTemplate gUnknown_83E79E8 =
+{
+ .tileTag = ANIM_TAG_CLAW_SLASH,
+ .paletteTag = ANIM_TAG_CLAW_SLASH,
+ .oam = &gOamData_83AC9D8,
+ .anims = gUnknown_83E79E0,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = sub_80B86B0,
+};
+
+void sub_80B78E0(u8 taskId)
+{
+ s32 battler;
+
+ gTasks[taskId].data[0] = gBattleAnimArgs[0];
+ battler = gBattleAnimAttacker;
+ gTasks[taskId].data[1] = 16;
+ SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(16, 0));
+ if (GetBattlerSpriteBGPriorityRank(battler) == 1)
+ SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT2_ALL | BLDCNT_EFFECT_BLEND | BLDCNT_TGT1_BG1);
+ else
+ SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT2_ALL | BLDCNT_EFFECT_BLEND | BLDCNT_TGT1_BG2);
+ gTasks[taskId].func = sub_80B7954;
+}
+
+static void sub_80B7954(u8 taskId)
+{
+ u8 blendA = gTasks[taskId].data[1] >> 8;
+ u8 blendB = gTasks[taskId].data[1];
+
+ if (gTasks[taskId].data[2] == (u8)gTasks[taskId].data[0])
+ {
+ ++blendA;
+ --blendB;
+ gTasks[taskId].data[1] = BLDALPHA_BLEND(blendB, blendA);
+ SetGpuReg(REG_OFFSET_BLDALPHA, gTasks[taskId].data[1]);
+ gTasks[taskId].data[2] = 0;
+ if (blendA == 16)
+ {
+ gSprites[gBattlerSpriteIds[gBattleAnimAttacker]].invisible = 1;
+ DestroyAnimVisualTask(taskId);
+ }
+ }
+ else
+ {
+ ++gTasks[taskId].data[2];
+ }
+}
+
+void sub_80B79DC(u8 taskId)
+{
+ gTasks[taskId].data[0] = gBattleAnimArgs[0];
+ gTasks[taskId].data[1] = BLDALPHA_BLEND(0, 16);
+ gTasks[taskId].func = sub_80B7A14;
+ SetGpuReg(REG_OFFSET_BLDALPHA, gTasks[taskId].data[1]);
+}
+
+static void sub_80B7A14(u8 taskId)
+{
+ u8 blendA = gTasks[taskId].data[1] >> 8;
+ u8 blendB = gTasks[taskId].data[1];
+
+ if (gTasks[taskId].data[2] == (u8)gTasks[taskId].data[0])
+ {
+ --blendA;
+ ++blendB;
+ gTasks[taskId].data[1] = (blendA << 8) | blendB;
+ SetGpuReg(REG_OFFSET_BLDALPHA, gTasks[taskId].data[1]);
+ gTasks[taskId].data[2] = 0;
+ if (blendA == 0)
+ {
+ SetGpuReg(REG_OFFSET_BLDCNT, 0);
+ SetGpuReg(REG_OFFSET_BLDALPHA, 0);
+ DestroyAnimVisualTask(taskId);
+ }
+ }
+ else
+ {
+ ++gTasks[taskId].data[2];
+ }
+}
+
+void sub_80B7A80(u8 taskId)
+{
+ SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(0, 16));
+ if (GetBattlerSpriteBGPriorityRank(gBattleAnimAttacker) == 1)
+ SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT2_ALL | BLDCNT_EFFECT_BLEND | BLDCNT_TGT1_BG1);
+ else
+ SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT2_ALL | BLDCNT_EFFECT_BLEND | BLDCNT_TGT1_BG2);
+ DestroyAnimVisualTask(taskId);
+}
+
+static void sub_80B7ACC(struct Sprite *sprite)
+{
+ sprite->data[1] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2);
+ sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_X_2);
+ sprite->data[3] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y_PIC_OFFSET);
+ sprite->data[4] = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_Y_PIC_OFFSET);
+ sprite->data[0] = 0x7E;
+ InitSpriteDataForLinearTranslation(sprite);
+ sprite->data[3] = -sprite->data[1];
+ sprite->data[4] = -sprite->data[2];
+ sprite->data[6] = 0xFFD8;
+ sprite->callback = sub_80B7B48;
+ sprite->callback(sprite);
+}
+
+static void sub_80B7B48(struct Sprite *sprite)
+{
+ sprite->data[3] += sprite->data[1];
+ sprite->data[4] += sprite->data[2];
+ sprite->pos2.x = sprite->data[3] >> 8;
+ sprite->pos2.y = sprite->data[4] >> 8;
+ if (sprite->data[7] == 0)
+ {
+ sprite->data[3] += sprite->data[1];
+ sprite->data[4] += sprite->data[2];
+ sprite->pos2.x = sprite->data[3] >> 8;
+ sprite->pos2.y = sprite->data[4] >> 8;
+ --sprite->data[0];
+ }
+ sprite->pos2.y += Sin(sprite->data[5], sprite->data[6]);
+ sprite->data[5] = (sprite->data[5] + 3) & 0xFF;
+ if (sprite->data[5] > 0x7F)
+ {
+ sprite->data[5] = 0;
+ sprite->data[6] += 20;
+ ++sprite->data[7];
+ }
+ if (--sprite->data[0] == 0)
+ DestroyAnimSprite(sprite);
+}
+
+static void sub_80B7BD4(struct Sprite *sprite)
+{
+ sprite->pos1.x += gBattleAnimArgs[0];
+ sprite->pos1.y += gBattleAnimArgs[1];
+ StartSpriteAffineAnim(sprite, gBattleAnimArgs[2]);
+ sprite->data[0] = gBattleAnimArgs[3];
+ sprite->data[1] = gBattleAnimArgs[4];
+ sprite->data[2] = gBattleAnimArgs[5];
+ sprite->callback = sub_80B7C10;
+}
+
+static void sub_80B7C10(struct Sprite *sprite)
+{
+ sprite->data[4] += sprite->data[0];
+ sprite->data[5] += sprite->data[1];
+ sprite->pos2.x = sprite->data[4] >> 8;
+ sprite->pos2.y = sprite->data[5] >> 8;
+ if (++sprite->data[3] == sprite->data[2])
+ sprite->callback = sub_80B7C50;
+}
+
+static void sub_80B7C50(struct Sprite *sprite)
+{
+ sprite->data[4] -= sprite->data[0];
+ sprite->data[5] -= sprite->data[1];
+ sprite->pos2.x = sprite->data[4] >> 8;
+ sprite->pos2.y = sprite->data[5] >> 8;
+ if (--sprite->data[3] == 0)
+ DestroySpriteAndMatrix(sprite);
+}
+
+static void sub_80B7C88(struct Sprite *sprite)
+{
+ u8 battler;
+ s8 xOffset;
+
+ if (gBattleAnimArgs[0] == 0)
+ battler = gBattleAnimAttacker;
+ else
+ battler = gBattleAnimTarget;
+ xOffset = 20;
+ sprite->oam.tileNum += 4;
+ switch (gBattleAnimArgs[1])
+ {
+ case 0:
+ sprite->pos1.x = GetBattlerSpriteCoordAttr(battler, BATTLER_COORD_ATTR_RIGHT) - 8;
+ sprite->pos1.y = GetBattlerSpriteCoordAttr(battler, BATTLER_COORD_ATTR_TOP) + 8;
+ break;
+ case 1:
+ sprite->pos1.x = GetBattlerSpriteCoordAttr(battler, BATTLER_COORD_ATTR_RIGHT) - 14;
+ sprite->pos1.y = GetBattlerSpriteCoordAttr(battler, BATTLER_COORD_ATTR_TOP) + 16;
+ break;
+ case 2:
+ sprite->pos1.x = GetBattlerSpriteCoordAttr(battler, BATTLER_COORD_ATTR_LEFT) + 8;
+ sprite->pos1.y = GetBattlerSpriteCoordAttr(battler, BATTLER_COORD_ATTR_TOP) + 8;
+ StartSpriteAffineAnim(sprite, 1);
+ xOffset = -20;
+ break;
+ case 3:
+ sprite->pos1.x = GetBattlerSpriteCoordAttr(battler, BATTLER_COORD_ATTR_LEFT) + 14;
+ sprite->pos1.y = GetBattlerSpriteCoordAttr(battler, BATTLER_COORD_ATTR_TOP) + 16;
+ StartSpriteAffineAnim(sprite, 1);
+ xOffset = -20;
+ break;
+ }
+ sprite->data[0] = 32;
+ sprite->data[2] = sprite->pos1.x + xOffset;
+ sprite->data[4] = sprite->pos1.y + 12;
+ sprite->data[5] = -12;
+ InitAnimArcTranslation(sprite);
+ sprite->callback = sub_80B7D88;
+}
+
+static void sub_80B7D88(struct Sprite *sprite)
+{
+ if (TranslateAnimHorizontalArc(sprite))
+ DestroySpriteAndMatrix(sprite);
+}
+
+void sub_80B7DA4(u8 taskId)
+{
+ struct ScanlineEffectParams scanlineParams;
+ struct BattleAnimBgData animBg;
+ u16 i;
+ u8 pos;
+ s32 var0;
+ struct Task *task = &gTasks[taskId];
+
+ task->data[7] = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_Y) + 31;
+ task->data[6] = GetBattlerSpriteCoordAttr(gBattleAnimAttacker, BATTLER_COORD_ATTR_TOP) - 7;
+ task->data[5] = task->data[7];
+ task->data[4] = task->data[6];
+ task->data[13] = (task->data[7] - task->data[6]) << 8;
+ pos = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_X);
+ task->data[14] = pos - 32;
+ task->data[15] = pos + 32;
+ if (GetBattlerSide(gBattleAnimAttacker) == B_SIDE_PLAYER)
+ task->data[8] = -12;
+ else
+ task->data[8] = -64;
+ task->data[3] = GetBattlerSpriteBGPriorityRank(gBattleAnimAttacker);
+ if (task->data[3] == 1)
+ {
+ sub_80752A0(&animBg);
+ task->data[10] = gBattle_BG1_Y;
+ SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT2_ALL | BLDCNT_EFFECT_BLEND | BLDCNT_TGT1_BG1);
+ FillPalette(0, animBg.paletteId * 16, 32);
+ scanlineParams.dmaDest = &REG_BG1VOFS;
+ var0 = WINOUT_WIN01_BG1;
+ if (!IsContest())
+ gBattle_BG2_X += 240;
+ }
+ else
+ {
+ task->data[10] = gBattle_BG2_Y;
+ SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT2_ALL | BLDCNT_EFFECT_BLEND | BLDCNT_TGT1_BG2);
+ FillPalette(0, 144, 32);
+ scanlineParams.dmaDest = &REG_BG2VOFS;
+ var0 = WINOUT_WIN01_BG2;
+ if (!IsContest())
+ gBattle_BG1_X += 240;
+ }
+ scanlineParams.dmaControl = SCANLINE_EFFECT_DMACNT_16BIT;
+ scanlineParams.initState = 1;
+ scanlineParams.unused9 = 0;
+ task->data[11] = 0;
+ task->data[12] = 16;
+ task->data[0] = 0;
+ task->data[1] = 0;
+ task->data[2] = 0;
+ sub_80B856C(3);
+ for (i = 0; i < 112; ++i)
+ {
+ gScanlineEffectRegBuffers[0][i] = task->data[10];
+ gScanlineEffectRegBuffers[1][i] = task->data[10];
+ }
+ ScanlineEffect_SetParams(scanlineParams);
+ SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WINOBJ_BG_ALL | WINOUT_WINOBJ_OBJ | WINOUT_WINOBJ_CLR | (var0 ^ (WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR)));
+ SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR | WININ_WIN1_BG_ALL | WININ_WIN1_OBJ | WININ_WIN1_CLR);
+ gBattle_WIN0H = (task->data[14] << 8) | task->data[15];
+ gBattle_WIN0V = 160;
+
+ task->func = sub_80B7F58;
+}
+
+static void sub_80B7F58(u8 taskId)
+{
+ struct Task *task = &gTasks[taskId];
+
+ switch (task->data[0])
+ {
+ case 0:
+ if (++task->data[1] > 1)
+ {
+ task->data[1] = 0;
+ if (++task->data[2] & 1)
+ {
+ if (task->data[11] != 12)
+ ++task->data[11];
+ }
+ else if (task->data[12] != 8)
+ {
+ --task->data[12];
+ }
+ SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(task->data[11], task->data[12]));
+ if (task->data[11] == 12 && task->data[12] == 8)
+ ++task->data[0];
+ }
+ break;
+ case 1:
+ task->data[4] -= 8;
+ sub_80B843C(task);
+ if (task->data[4] < task->data[8])
+ ++task->data[0];
+ break;
+ case 2:
+ task->data[4] -= 8;
+ sub_80B843C(task);
+ task->data[14] += 4;
+ task->data[15] -= 4;
+ if (task->data[14] >= task->data[15])
+ task->data[14] = task->data[15];
+ gBattle_WIN0H = (task->data[14] << 8) | task->data[15];
+ if (task->data[14] == task->data[15])
+ ++task->data[0];
+ break;
+ case 3:
+ gScanlineEffect.state = 3;
+ ++task->data[0];
+ break;
+ case 4:
+ DestroyAnimVisualTask(taskId);
+ break;
+ }
+}
+
+void sub_80B8070(u8 taskId)
+{
+ struct BattleAnimBgData animBg;
+ struct ScanlineEffectParams scanlineParams;
+ u8 x;
+ u16 i;
+ struct Task *task = &gTasks[taskId];
+
+ switch (task->data[0])
+ {
+ case 0:
+ if (IsContest() == TRUE)
+ {
+ gBattle_WIN0H = 0;
+ gBattle_WIN0V = 0;
+ SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR | WININ_WIN1_BG_ALL | WININ_WIN1_OBJ | WININ_WIN1_CLR);
+ SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WINOBJ_BG_ALL | WINOUT_WINOBJ_OBJ | WINOUT_WINOBJ_CLR | WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR);
+ DestroyAnimVisualTask(taskId);
+ }
+ else
+ {
+ task->data[3] = GetBattlerSpriteBGPriorityRank(gBattleAnimTarget);
+ if (task->data[3] == 1)
+ {
+ SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT2_ALL | BLDCNT_EFFECT_BLEND | BLDCNT_TGT1_BG1);
+ gBattle_BG2_X += 240;
+ }
+ else
+ {
+ SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT2_ALL | BLDCNT_EFFECT_BLEND | BLDCNT_TGT1_BG2);
+ gBattle_BG1_X += 240;
+ }
+ ++task->data[0];
+ }
+ break;
+ case 1:
+ if (task->data[3] == 1)
+ {
+ sub_80752A0(&animBg);
+ task->data[10] = gBattle_BG1_Y;
+ FillPalette(0, animBg.paletteId * 16, 32);
+ }
+ else
+ {
+ task->data[10] = gBattle_BG2_Y;
+ FillPalette(0, 9 * 16, 32);
+ }
+ sub_80B856C(3);
+ ++task->data[0];
+ break;
+ case 2:
+ task->data[7] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y) + 31;
+ task->data[6] = GetBattlerSpriteCoordAttr(gBattleAnimTarget, BATTLER_COORD_ATTR_TOP) - 7;
+ task->data[13] = (task->data[7] - task->data[6]) << 8;
+ x = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X);
+ task->data[14] = x - 4;
+ task->data[15] = x + 4;
+ if (GetBattlerSide(gBattleAnimTarget) == B_SIDE_PLAYER)
+ task->data[8] = -12;
+ else
+ task->data[8] = -64;
+ task->data[4] = task->data[8];
+ task->data[5] = task->data[8];
+ task->data[11] = 12;
+ task->data[12] = 8;
+ ++task->data[0];
+ break;
+ case 3:
+ if (task->data[3] == 1)
+ scanlineParams.dmaDest = &REG_BG1VOFS;
+ else
+ scanlineParams.dmaDest = &REG_BG2VOFS;
+ for (i = 0; i < 112; ++i)
+ {
+ gScanlineEffectRegBuffers[0][i] = task->data[10] + (159 - i);
+ gScanlineEffectRegBuffers[1][i] = task->data[10] + (159 - i);
+ }
+ scanlineParams.dmaControl = SCANLINE_EFFECT_DMACNT_16BIT;
+ scanlineParams.initState = 1;
+ scanlineParams.unused9 = 0;
+ ScanlineEffect_SetParams(scanlineParams);
+ ++task->data[0];
+ break;
+ case 4:
+ if (task->data[3] == 1)
+ SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WINOBJ_BG_ALL | WINOUT_WINOBJ_OBJ | WINOUT_WINOBJ_CLR | WINOUT_WIN01_BG0 | WINOUT_WIN01_BG2 | WINOUT_WIN01_BG3 | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR);
+ else
+ SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WINOBJ_BG_ALL | WINOUT_WINOBJ_OBJ | WINOUT_WINOBJ_CLR | WINOUT_WIN01_BG0 | WINOUT_WIN01_BG1 | WINOUT_WIN01_BG3 | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR);
+ SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR | WININ_WIN1_BG_ALL | WININ_WIN1_OBJ | WININ_WIN1_CLR);
+ gBattle_WIN0H = (task->data[14] << 8) | task->data[15];
+ gBattle_WIN0V = 160;
+ task->data[0] = 0;
+ task->data[1] = 0;
+ task->data[2] = 0;
+ SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(12, 8));
+ task->func = sub_80B82C0;
+ break;
+ }
+}
+
+static void sub_80B82C0(u8 taskId)
+{
+ u8 pos;
+ u16 i;
+ struct Task *task = &gTasks[taskId];
+
+ switch (task->data[0])
+ {
+ case 0:
+ task->data[5] += 8;
+ if (task->data[5] >= task->data[7])
+ task->data[5] = task->data[7];
+ sub_80B843C(task);
+ if (task->data[5] == task->data[7])
+ ++task->data[0];
+ break;
+ case 1:
+ if (task->data[15] - task->data[14] < 0x40)
+ {
+ task->data[14] -= 4;
+ task->data[15] += 4;
+ }
+ else
+ {
+ task->data[1] = 1;
+ }
+ gBattle_WIN0H = (task->data[14] << 8) | task->data[15];
+ task->data[4] += 8;
+ if (task->data[4] >= task->data[6])
+ task->data[4] = task->data[6];
+ sub_80B843C(task);
+ if (task->data[4] == task->data[6] && task->data[1])
+ {
+ task->data[1] = 0;
+ ++task->data[0];
+ }
+ break;
+ case 2:
+ if (++task->data[1] > 1)
+ {
+ task->data[1] = 0;
+ ++task->data[2];
+ if (task->data[2] & 1)
+ {
+ if (task->data[11])
+ --task->data[11];
+ }
+ else if (task->data[12] < 16)
+ {
+ ++task->data[12];
+ }
+ SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(task->data[11], task->data[12]));
+ if (task->data[11] == 0 && task->data[12] == 16)
+ ++task->data[0];
+ }
+ break;
+ case 3:
+ gScanlineEffect.state = 3;
+ ++task->data[0];
+ break;
+ case 4:
+ gBattle_WIN0H = 0;
+ gBattle_WIN0V = 0;
+ SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR | WININ_WIN1_BG_ALL | WININ_WIN1_OBJ | WININ_WIN1_CLR);
+ SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WINOBJ_BG_ALL | WINOUT_WINOBJ_OBJ | WINOUT_WINOBJ_CLR | WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR);
+ DestroyAnimVisualTask(taskId);
+ break;
+ }
+}
+
+static void sub_80B843C(struct Task *task)
+{
+ s32 var0, var1, var4;
+ s16 var2, i;
+
+ var2 = task->data[5] - task->data[4];
+ if (var2 != 0)
+ {
+ var0 = task->data[13] / var2;
+ var1 = task->data[6] << 8;
+ for (i = 0; i < task->data[4]; ++i)
+ gScanlineEffectRegBuffers[gScanlineEffect.srcBuffer][i] = task->data[10] - (i - 159);
+ for (i = task->data[4]; i <= task->data[5]; ++i)
+ {
+ if (i >= 0)
+ {
+ s16 var3 = (var1 >> 8) - i;
+
+ gScanlineEffectRegBuffers[gScanlineEffect.srcBuffer][i] = var3 + task->data[10];
+ }
+ var1 += var0;
+ }
+ var4 = task->data[10] - (i - 159);
+ for (; i < task->data[7]; ++i)
+ if (i >= 0)
+ gScanlineEffectRegBuffers[gScanlineEffect.srcBuffer][i] = var4--;
+ }
+ else
+ {
+ var4 = task->data[10] + 159;
+ for (i = 0; i < 112; ++i)
+ {
+ gScanlineEffectRegBuffers[0][i] = var4;
+ gScanlineEffectRegBuffers[1][i] = var4;
+ --var4;
+ }
+ }
+}
+
+static void sub_80B856C(u8 priority)
+{
+ u16 i;
+
+ for (i = 0; i < MAX_BATTLERS_COUNT; ++i)
+ {
+ u8 spriteId = GetAnimBattlerSpriteId(i);
+
+ if (spriteId != 0xFF)
+ gSprites[spriteId].oam.priority = priority;
+ }
+}
+
+void sub_80B85B8(u8 taskId)
+{
+ u8 toBG2 = GetBattlerSpriteBGPriorityRank(gBattleAnimAttacker) ^ 1 ? 1 : 0;
+
+ MoveBattlerSpriteToBG(gBattleAnimAttacker, toBG2);
+ gSprites[gBattlerSpriteIds[gBattleAnimAttacker]].invisible = 0;
+ if (IsBattlerSpriteVisible(BATTLE_PARTNER(gBattleAnimAttacker)))
+ {
+ MoveBattlerSpriteToBG(gBattleAnimAttacker ^ 2, toBG2 ^ 1);
+ gSprites[gBattlerSpriteIds[gBattleAnimAttacker ^ 2]].invisible = 0;
+ }
+ DestroyAnimVisualTask(taskId);
+}
+
+void sub_80B8664(u8 taskId)
+{
+ u8 toBG2 = GetBattlerSpriteBGPriorityRank(gBattleAnimAttacker) ^ 1 ? 1 : 0;
+
+ sub_8073128(toBG2);
+ if (IsBattlerSpriteVisible(BATTLE_PARTNER(gBattleAnimAttacker)))
+ sub_8073128(toBG2 ^ 1);
+ DestroyAnimVisualTask(taskId);
+}
+
+static void sub_80B86B0(struct Sprite *sprite)
+{
+ sprite->pos1.x += gBattleAnimArgs[0];
+ sprite->pos1.y += gBattleAnimArgs[1];
+ StartSpriteAnim(sprite, gBattleAnimArgs[2]);
+ sprite->callback = RunStoredCallbackWhenAnimEnds;
+ StoreSpriteCallbackInData6(sprite, DestroyAnimSprite);
+}
+
+// Makes the attacker metallic and shining.
+// Used by MOVE_HARDEN and MOVE_IRON_DEFENSE.
+// arg0: if true won't change battler's palette back
+// arg1: if true, use custom color
+// arg2: custom color
+// Custom color argument is used in MOVE_POISON_TAIL to make the mon turn purplish/pinkish as if became cloaked in poison.
+void AnimTask_MetallicShine(u8 taskId)
+{
+ u16 species;
+ u8 spriteId, newSpriteId;
+ u16 paletteNum;
+ struct BattleAnimBgData animBg;
+ bool32 priorityChanged = FALSE;
+
+ gBattle_WIN0H = 0;
+ gBattle_WIN0V = 0;
+ SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR | WININ_WIN1_BG_ALL | WININ_WIN1_OBJ | WININ_WIN1_CLR);
+ SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WINOBJ_BG_ALL | WINOUT_WINOBJ_OBJ | WINOUT_WINOBJ_CLR | WINOUT_WIN01_BG0 | WINOUT_WIN01_BG2 | WINOUT_WIN01_BG3 | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR);
+ SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_OBJWIN_ON);
+ SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT2_ALL | BLDCNT_EFFECT_BLEND | BLDCNT_TGT1_BG1);
+ SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(8, 12));
+ SetAnimBgAttribute(1, BG_ANIM_PRIORITY, 0);
+ SetAnimBgAttribute(1, BG_ANIM_SCREEN_SIZE, 0);
+ if (!IsContest())
+ SetAnimBgAttribute(1, BG_ANIM_CHAR_BASE_BLOCK, 1);
+ if (IsDoubleBattle() && !IsContest())
+ {
+ if (GetBattlerPosition(gBattleAnimAttacker) == B_POSITION_OPPONENT_RIGHT || GetBattlerPosition(gBattleAnimAttacker) == B_POSITION_PLAYER_LEFT)
+ {
+ if (IsBattlerSpriteVisible(BATTLE_PARTNER(gBattleAnimAttacker)) == TRUE)
+ {
+ gSprites[gBattlerSpriteIds[BATTLE_PARTNER(gBattleAnimAttacker)]].oam.priority--;
+ SetAnimBgAttribute(1, BG_ANIM_PRIORITY, 1);
+ priorityChanged = TRUE;
+ }
+ }
+ }
+ if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
+ species = GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattleAnimAttacker]], MON_DATA_SPECIES);
+ else
+ species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gBattleAnimAttacker]], MON_DATA_SPECIES);
+ spriteId = GetAnimBattlerSpriteId(ANIM_ATTACKER);
+ newSpriteId = sub_8076E34(gBattleAnimAttacker, spriteId, species);
+ sub_80752A0(&animBg);
+ AnimLoadCompressedBgTilemap(animBg.bgId, gMetalShineTilemap);
+ AnimLoadCompressedBgGfx(animBg.bgId, gMetalShineGfx, animBg.tilesOffset);
+ LoadCompressedPalette(gMetalShinePalette, animBg.paletteId * 16, 32);
+ gBattle_BG1_X = -gSprites[spriteId].pos1.x + 96;
+ gBattle_BG1_Y = -gSprites[spriteId].pos1.y + 32;
+ paletteNum = 16 + gSprites[spriteId].oam.paletteNum;
+ if (gBattleAnimArgs[1] == 0)
+ SetGreyscaleOrOriginalPalette(paletteNum, FALSE);
+ else
+ BlendPalette(paletteNum * 16, 16, 11, gBattleAnimArgs[2]);
+ gTasks[taskId].data[0] = newSpriteId;
+ gTasks[taskId].data[1] = gBattleAnimArgs[0];
+ gTasks[taskId].data[2] = gBattleAnimArgs[1];
+ gTasks[taskId].data[3] = gBattleAnimArgs[2];
+ gTasks[taskId].data[6] = priorityChanged;
+ gTasks[taskId].func = sub_80B8920;
+}
+
+static void sub_80B8920(u8 taskId)
+{
+ struct BattleAnimBgData animBg;
+ u16 paletteNum;
+ u8 spriteId;
+
+ gTasks[taskId].data[10] += 4;
+ gBattle_BG1_X -= 4;
+ if (gTasks[taskId].data[10] == 128)
+ {
+ gTasks[taskId].data[10] = 0;
+ gBattle_BG1_X += 128;
+ gTasks[taskId].data[11]++;
+ if (gTasks[taskId].data[11] == 2)
+ {
+ spriteId = GetAnimBattlerSpriteId(ANIM_ATTACKER);
+ paletteNum = 16 + gSprites[spriteId].oam.paletteNum;
+ if (gTasks[taskId].data[1] == 0)
+ SetGreyscaleOrOriginalPalette(paletteNum, 1);
+ DestroySprite(&gSprites[gTasks[taskId].data[0]]);
+ sub_80752A0(&animBg);
+ sub_8075358(animBg.bgId);
+ if (gTasks[taskId].data[6] == 1)
+ gSprites[gBattlerSpriteIds[BATTLE_PARTNER(gBattleAnimAttacker)]].oam.priority++;
+ }
+ else if (gTasks[taskId].data[11] == 3)
+ {
+ gBattle_WIN0H = 0;
+ gBattle_WIN0V = 0;
+ SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR | WININ_WIN1_BG_ALL | WININ_WIN1_OBJ | WININ_WIN1_CLR);
+ SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WINOBJ_BG_ALL | WINOUT_WINOBJ_OBJ | WINOUT_WINOBJ_CLR | WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR);
+ if (!IsContest())
+ SetAnimBgAttribute(1, BG_ANIM_CHAR_BASE_BLOCK, 0);
+ SetGpuReg(REG_OFFSET_DISPCNT, GetGpuReg(REG_OFFSET_DISPCNT) ^ DISPCNT_OBJWIN_ON);
+ SetGpuReg(REG_OFFSET_BLDCNT, 0);
+ SetGpuReg(REG_OFFSET_BLDALPHA, 0);
+ DestroyAnimVisualTask(taskId);
+ }
+ }
+}
+
+// Changes battler's palette to either greyscale or original.
+// arg0: which battler
+// arg1: 0 grayscale, 1 original
+void AnimTask_SetGreyscaleOrOriginalPal(u8 taskId)
+{
+ u8 spriteId, battler;
+ bool8 calcSpriteId = FALSE;
+ u8 position = B_POSITION_PLAYER_LEFT;
+
+ switch (gBattleAnimArgs[0])
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ spriteId = GetAnimBattlerSpriteId(gBattleAnimArgs[0]);
+ break;
+ case 4:
+ position = B_POSITION_PLAYER_LEFT;
+ calcSpriteId = TRUE;
+ break;
+ case 5:
+ position = B_POSITION_PLAYER_RIGHT;
+ calcSpriteId = TRUE;
+ break;
+ case 6:
+ position = B_POSITION_OPPONENT_LEFT;
+ calcSpriteId = TRUE;
+ break;
+ case 7:
+ position = B_POSITION_OPPONENT_RIGHT;
+ calcSpriteId = TRUE;
+ break;
+ default:
+ spriteId = 0xFF;
+ break;
+ }
+ if (calcSpriteId)
+ {
+ battler = GetBattlerAtPosition(position);
+ if (IsBattlerSpriteVisible(battler))
+ spriteId = gBattlerSpriteIds[battler];
+ else
+ spriteId = 0xFF;
+ }
+ if (spriteId != 0xFF)
+ SetGreyscaleOrOriginalPalette(gSprites[spriteId].oam.paletteNum + 16, gBattleAnimArgs[1]);
+ DestroyAnimVisualTask(taskId);
+}
+
+void sub_80B8B38(u8 taskId)
+{
+ if (gAnimMoveTurn < 2)
+ gBattleAnimArgs[7] = 0;
+ if (gAnimMoveTurn == 2)
+ gBattleAnimArgs[7] = 1;
+ DestroyAnimVisualTask(taskId);
+}
diff --git a/src/daycare.c b/src/daycare.c
index 837a2c4e6..fede86156 100644
--- a/src/daycare.c
+++ b/src/daycare.c
@@ -2087,7 +2087,7 @@ struct UnkStruct_82349CC
u8 field_3;
};
-extern const struct UnkStruct_82349CC gUnknown_82349CC[NUM_SPECIES];
+extern const struct UnkStruct_82349CC gMonFrontPicCoords[NUM_SPECIES];
static void SpriteCB_Egg_2(struct Sprite* sprite)
{
@@ -2101,7 +2101,7 @@ static void SpriteCB_Egg_2(struct Sprite* sprite)
sprite->data[0] = 0;
species = GetMonData(&gPlayerParty[sEggHatchData->eggPartyID], MON_DATA_SPECIES);
gSprites[sEggHatchData->pokeSpriteID].pos2.x = 0;
- gSprites[sEggHatchData->pokeSpriteID].pos2.y = gUnknown_82349CC[species].field_1;
+ gSprites[sEggHatchData->pokeSpriteID].pos2.y = gMonFrontPicCoords[species].field_1;
}
else
{
diff --git a/src/dragon.c b/src/dragon.c
new file mode 100644
index 000000000..34f97ba74
--- /dev/null
+++ b/src/dragon.c
@@ -0,0 +1,431 @@
+#include "global.h"
+#include "battle_anim.h"
+#include "scanline_effect.h"
+#include "task.h"
+#include "trig.h"
+
+static void sub_80B725C(struct Sprite *sprite);
+static void sub_80B741C(struct Sprite *sprite);
+static void sub_80B73AC(struct Sprite *sprite);
+static void sub_80B7448(struct Sprite *sprite);
+static void sub_80B77E4(struct Sprite *sprite);
+static void sub_80B74D8(struct Sprite *sprite);
+static void sub_80B76B0(u8 taskId);
+static void sub_80B776C(struct Task *task);
+static void sub_80B7894(struct Sprite *sprite);
+
+static EWRAM_DATA u16 gUnknown_20399A4[7] = {0};
+
+static const union AnimCmd gUnknown_83E7710[] =
+{
+ ANIMCMD_FRAME(0, 4),
+ ANIMCMD_FRAME(16, 4),
+ ANIMCMD_FRAME(32, 4),
+ ANIMCMD_FRAME(48, 4),
+ ANIMCMD_FRAME(64, 4),
+ ANIMCMD_JUMP(0),
+};
+
+static const union AnimCmd *const gUnknown_83E7728[] =
+{
+ gUnknown_83E7710,
+};
+
+const struct SpriteTemplate gUnknown_83E772C =
+{
+ .tileTag = ANIM_TAG_SMALL_EMBER,
+ .paletteTag = ANIM_TAG_SMALL_EMBER,
+ .oam = &gOamData_83AC9D8,
+ .anims = gUnknown_83E7728,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = sub_80B725C,
+};
+
+static const union AnimCmd gUnknown_83E7744[] =
+{
+ ANIMCMD_FRAME(16, 3),
+ ANIMCMD_FRAME(32, 3),
+ ANIMCMD_FRAME(48, 3),
+ ANIMCMD_JUMP(0),
+};
+
+static const union AnimCmd gUnknown_83E7754[] =
+{
+ ANIMCMD_FRAME(16, 3, .vFlip = TRUE, .hFlip = TRUE),
+ ANIMCMD_FRAME(32, 3, .vFlip = TRUE, .hFlip = TRUE),
+ ANIMCMD_FRAME(48, 3, .vFlip = TRUE, .hFlip = TRUE),
+ ANIMCMD_JUMP(0),
+};
+
+static const union AnimCmd *const gUnknown_83E7764[] =
+{
+ gUnknown_83E7744,
+ gUnknown_83E7754,
+};
+
+static const union AffineAnimCmd gUnknown_83E776C[] =
+{
+ AFFINEANIMCMD_FRAME(0x50, 0x50, 127, 0),
+ AFFINEANIMCMD_FRAME(0xD, 0xD, 0, 100),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd gUnknown_83E7784[] =
+{
+ AFFINEANIMCMD_FRAME(0x50, 0x50, 0, 0),
+ AFFINEANIMCMD_FRAME(0xD, 0xD, 0, 100),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd *const gUnknown_83E779C[] =
+{
+ gUnknown_83E776C,
+ gUnknown_83E7784,
+};
+
+const struct SpriteTemplate gUnknown_83E77A4 =
+{
+ .tileTag = ANIM_TAG_SMALL_EMBER,
+ .paletteTag = ANIM_TAG_SMALL_EMBER,
+ .oam = &gOamData_83ACA98,
+ .anims = gUnknown_83E7764,
+ .images = NULL,
+ .affineAnims = gUnknown_83E779C,
+ .callback = sub_80B741C,
+};
+
+const union AnimCmd gUnknown_83E77BC[] =
+{
+ ANIMCMD_FRAME(0, 5),
+ ANIMCMD_FRAME(16, 5),
+ ANIMCMD_FRAME(32, 5),
+ ANIMCMD_FRAME(48, 5),
+ ANIMCMD_FRAME(64, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd *const gUnknown_83E77D4[] =
+{
+ gUnknown_83E77BC,
+};
+
+const struct SpriteTemplate gUnknown_83E77D8 =
+{
+ .tileTag = ANIM_TAG_FIRE_PLUME,
+ .paletteTag = ANIM_TAG_FIRE_PLUME,
+ .oam = &gOamData_83AC9D8,
+ .anims = gUnknown_83E77D4,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = sub_80B73AC,
+};
+
+static const union AnimCmd gUnknown_83E77F0[] =
+{
+ ANIMCMD_FRAME(16, 3),
+ ANIMCMD_FRAME(32, 3),
+ ANIMCMD_FRAME(48, 3),
+ ANIMCMD_JUMP(0),
+};
+
+static const union AnimCmd *const gUnknown_83E7800[] =
+{
+ gUnknown_83E77F0,
+ gUnknown_83E77F0,
+};
+
+static const union AffineAnimCmd gUnknown_83E7808[] =
+{
+ AFFINEANIMCMD_FRAME(0x64, 0x64, 127, 1),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd gUnknown_83E7818[] =
+{
+ AFFINEANIMCMD_FRAME(0x64, 0x64, 0, 1),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd *const gUnknown_83E7828[] =
+{
+ gUnknown_83E7808,
+ gUnknown_83E7818,
+};
+
+const struct SpriteTemplate gUnknown_83E7830 =
+{
+ .tileTag = ANIM_TAG_SMALL_EMBER,
+ .paletteTag = ANIM_TAG_SMALL_EMBER,
+ .oam = &gOamData_83ACA98,
+ .anims = gUnknown_83E7800,
+ .images = NULL,
+ .affineAnims = gUnknown_83E7828,
+ .callback = sub_80B741C,
+};
+
+const struct SpriteTemplate gUnknown_83E7848 =
+{
+ .tileTag = ANIM_TAG_HOLLOW_ORB,
+ .paletteTag = ANIM_TAG_HOLLOW_ORB,
+ .oam = &gOamData_83AC9D0,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = sub_80B7448,
+};
+
+const struct SpriteTemplate gUnknown_83E7860 =
+{
+ .tileTag = ANIM_TAG_SMALL_EMBER,
+ .paletteTag = ANIM_TAG_SMALL_EMBER,
+ .oam = &gOamData_83AC9D8,
+ .anims = gUnknown_83E7728,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = sub_80B77E4,
+};
+
+static void sub_80B725C(struct Sprite *sprite)
+{
+ sprite->pos1.x = GetBattlerSpriteCoord(gBattleAnimAttacker, 2);
+ sprite->pos1.y = GetBattlerSpriteCoord(gBattleAnimAttacker, 3);
+ if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
+ {
+ sprite->pos1.x -= gBattleAnimArgs[0];
+ gBattleAnimArgs[3] = -gBattleAnimArgs[3];
+ gBattleAnimArgs[4] = -gBattleAnimArgs[4];
+ }
+ else
+ {
+ sprite->pos1.x += gBattleAnimArgs[0];
+ }
+ sprite->pos1.y += gBattleAnimArgs[1];
+ sprite->data[0] = gBattleAnimArgs[2];
+ sprite->data[1] = gBattleAnimArgs[3];
+ sprite->data[3] = gBattleAnimArgs[4];
+ sprite->data[5] = gBattleAnimArgs[5];
+ sprite->invisible = TRUE;
+ StoreSpriteCallbackInData6(sprite, DestroySpriteAndMatrix);
+ sprite->callback = TranslateSpriteLinearAndFlicker;
+}
+
+static void sub_80B72F8(struct Sprite *sprite)
+{
+ SetSpriteCoordsToAnimAttackerCoords(sprite);
+ sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimTarget, 2);
+ sprite->data[4] = GetBattlerSpriteCoord(gBattleAnimTarget, 3);
+ if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
+ {
+ sprite->pos1.x -= gBattleAnimArgs[1];
+ sprite->pos1.y += gBattleAnimArgs[1];
+ sprite->data[2] -= gBattleAnimArgs[2];
+ sprite->data[4] += gBattleAnimArgs[3];
+ }
+ else
+ {
+ sprite->pos1.x += gBattleAnimArgs[0];
+ sprite->pos1.y += gBattleAnimArgs[1];
+ sprite->data[2] += gBattleAnimArgs[2];
+ sprite->data[4] += gBattleAnimArgs[3];
+ StartSpriteAnim(sprite, 1);
+ }
+ sprite->data[0] = gBattleAnimArgs[4];
+ sprite->callback = StartAnimLinearTranslation;
+ StoreSpriteCallbackInData6(sprite, DestroySpriteAndMatrix);
+}
+
+static void sub_80B73AC(struct Sprite *sprite)
+{
+ if (gBattleAnimArgs[0] == 0)
+ {
+ sprite->pos1.x = GetBattlerSpriteCoord(gBattleAnimAttacker, 0);
+ sprite->pos1.y = GetBattlerSpriteCoord(gBattleAnimAttacker, 1);
+ }
+ else
+ {
+ sprite->pos1.x = GetBattlerSpriteCoord(gBattleAnimTarget, 0);
+ sprite->pos1.y = GetBattlerSpriteCoord(gBattleAnimTarget, 1);
+ }
+ SetAnimSpriteInitialXOffset(sprite, gBattleAnimArgs[1]);
+ sprite->pos1.y += gBattleAnimArgs[2];
+ sprite->callback = RunStoredCallbackWhenAnimEnds;
+ StoreSpriteCallbackInData6(sprite, DestroySpriteAndMatrix);
+}
+
+static void sub_80B741C(struct Sprite *sprite)
+{
+ if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
+ StartSpriteAffineAnim(sprite, 1);
+ sub_80B72F8(sprite);
+}
+
+static void sub_80B7448(struct Sprite *sprite)
+{
+ u16 r5;
+ u16 r0;
+
+ sprite->pos1.x = GetBattlerSpriteCoord(gBattleAnimAttacker, 2);
+ sprite->pos1.y = GetBattlerSpriteCoord(gBattleAnimAttacker, 3);
+ sprite->data[4] = 0;
+ sprite->data[5] = 1;
+ sprite->data[6] = gBattleAnimArgs[0];
+ r5 = GetBattlerSpriteCoordAttr(gBattlerAttacker, BATTLER_COORD_ATTR_HEIGHT);
+ r0 = GetBattlerSpriteCoordAttr(gBattlerAttacker, BATTLER_COORD_ATTR_WIDTH);
+ if (r5 > r0)
+ sprite->data[7] = r5 / 2;
+ else
+ sprite->data[7] = r0 / 2;
+ sprite->pos2.x = Cos(sprite->data[6], sprite->data[7]);
+ sprite->pos2.y = Sin(sprite->data[6], sprite->data[7]);
+ sprite->callback = sub_80B74D8;
+}
+
+static void sub_80B74D8(struct Sprite *sprite)
+{
+ switch (sprite->data[0])
+ {
+ case 0:
+ sprite->data[6] = (sprite->data[6] - sprite->data[5]) & 0xFF;
+ sprite->pos2.x = Cos(sprite->data[6], sprite->data[7]);
+ sprite->pos2.y = Sin(sprite->data[6], sprite->data[7]);
+ if (++sprite->data[4] > 5)
+ {
+ sprite->data[4] = 0;
+ if (sprite->data[5] <= 15 && ++sprite->data[5] > 15)
+ sprite->data[5] = 16;
+ }
+ if (++sprite->data[3] > 0x3C)
+ {
+ sprite->data[3] = 0;
+ ++sprite->data[0];
+ }
+ break;
+ case 1:
+ sprite->data[6] = (sprite->data[6] - sprite->data[5]) & 0xFF;
+ if (sprite->data[7] <= 0x95 && (sprite->data[7] += 8) > 0x95)
+ sprite->data[7] = 0x96;
+ sprite->pos2.x = Cos(sprite->data[6], sprite->data[7]);
+ sprite->pos2.y = Sin(sprite->data[6], sprite->data[7]);
+ if (++sprite->data[4] > 5)
+ {
+ sprite->data[4] = 0;
+ if (sprite->data[5] <= 15 && ++sprite->data[5] > 15)
+ sprite->data[5] = 16;
+ }
+ if (++sprite->data[3] > 20)
+ DestroyAnimSprite(sprite);
+ break;
+ }
+}
+
+void sub_80B75E0(u8 taskId)
+{
+ struct ScanlineEffectParams sp;
+ struct Task *task = &gTasks[taskId];
+ u16 i;
+ u8 r1;
+
+ if (GetBattlerSpriteBGPriorityRank(gBattleAnimAttacker) == 1)
+ {
+ sp.dmaDest = &REG_BG1HOFS;
+ task->data[2] = gBattle_BG1_X;
+ }
+ else
+ {
+ sp.dmaDest = &REG_BG2HOFS;
+ task->data[2] = gBattle_BG2_X;
+ }
+ sp.dmaControl = 0xA2600001;
+ sp.initState = 1;
+ sp.unused9 = 0;
+ r1 = GetBattlerYCoordWithElevation(gBattleAnimAttacker);
+ task->data[3] = r1 - 32;
+ task->data[4] = r1 + 32;
+ if (task->data[3] < 0)
+ task->data[3] = 0;
+ for (i = task->data[3]; i <= task->data[4]; ++i)
+ {
+ gScanlineEffectRegBuffers[0][i] = task->data[2];
+ gScanlineEffectRegBuffers[1][i] = task->data[2];
+ }
+ ScanlineEffect_SetParams(sp);
+ task->func = sub_80B76B0;
+}
+
+static void sub_80B76B0(u8 taskId)
+{
+ struct Task *task = &gTasks[taskId];
+
+ switch (task->data[0])
+ {
+ case 0:
+ if (++task->data[7] > 1)
+ {
+ task->data[7] = 0;
+ if (++task->data[6] == 3)
+ ++task->data[0];
+ }
+ sub_80B776C(task);
+ break;
+ case 1:
+ if (++task->data[1] > 0x3C)
+ ++task->data[0];
+ sub_80B776C(task);
+ break;
+ case 2:
+ if (++task->data[7] > 1)
+ {
+ task->data[7] = 0;
+ if (--task->data[6] == 0)
+ ++task->data[0];
+ }
+ sub_80B776C(task);
+ break;
+ case 3:
+ gScanlineEffect.state = 3;
+ ++task->data[0];
+ break;
+ case 4:
+ DestroyAnimVisualTask(taskId);
+ break;
+ }
+}
+
+static void sub_80B776C(struct Task *task)
+{
+ u16 i, r3 = task->data[5];
+
+ for (i = task->data[3]; i <= task->data[4]; ++i)
+ {
+ gScanlineEffectRegBuffers[gScanlineEffect.srcBuffer][i] = ((gSineTable[r3] * task->data[6]) >> 7) + task->data[2];
+ r3 = (r3 + 8) & 0xFF;
+ }
+ task->data[5] = (task->data[5] + 9) & 0xFF;
+}
+
+static void sub_80B77E4(struct Sprite *sprite)
+{
+ s32 i, r6 = (gBattleAnimArgs[2] * 3) / 5;
+
+ sprite->pos1.x = GetBattlerSpriteCoord(gBattleAnimAttacker, 2);
+ sprite->pos1.y = GetBattlerSpriteCoord(gBattleAnimAttacker, 3) + gBattleAnimArgs[4];
+ sprite->data[1] = Cos(gBattleAnimArgs[1], gBattleAnimArgs[2]);
+ sprite->data[2] = Sin(gBattleAnimArgs[1], r6);
+ sprite->pos1.x += sprite->data[1] * gBattleAnimArgs[0];
+ sprite->pos1.y += sprite->data[2] * gBattleAnimArgs[0];
+ sprite->data[3] = gBattleAnimArgs[3];
+ sprite->callback = sub_80B7894;
+ for (i = 0; i < 7; ++i)
+ gUnknown_20399A4[i] = sprite->data[i];
+}
+
+static void sub_80B7894(struct Sprite *sprite)
+{
+ sprite->data[4] += sprite->data[1];
+ sprite->data[5] += sprite->data[2];
+ sprite->pos2.x = sprite->data[4] / 10;
+ sprite->pos2.y = sprite->data[5] / 10;
+ if (++sprite->data[0] > sprite->data[3])
+ DestroyAnimSprite(sprite);
+}
diff --git a/src/ground.c b/src/ground.c
new file mode 100644
index 000000000..4ae4d8370
--- /dev/null
+++ b/src/ground.c
@@ -0,0 +1,724 @@
+#include "global.h"
+#include "battle_anim.h"
+#include "random.h"
+#include "scanline_effect.h"
+#include "task.h"
+#include "trig.h"
+
+static void AnimBonemerangProjectile(struct Sprite *sprite);
+static void AnimBoneHitProjectile(struct Sprite *sprite);
+static void AnimDirtScatter(struct Sprite *sprite);
+static void AnimMudSportDirt(struct Sprite *sprite);
+static void AnimFissureDirtPlumeParticle(struct Sprite *sprite);
+static void AnimDigDirtMound(struct Sprite *sprite);
+static void AnimBonemerangProjectileStep(struct Sprite *sprite);
+static void AnimBonemerangProjectileEnd(struct Sprite *sprite);
+static void AnimMudSportDirtRising(struct Sprite *sprite);
+static void AnimMudSportDirtFalling(struct Sprite *sprite);
+static void sub_80B8ED4(u8 taskId);
+static void sub_80B908C(u8 taskId);
+static void sub_80B92B8(u8 useBg1, s16 y, s16 endY);
+static void sub_80B912C(u8 taskId);
+static void sub_80B91B0(u8 taskId);
+static void AnimFissureDirtPlumeParticleStep(struct Sprite *sprite);
+static void sub_80B9584(u8 taskId);
+static void sub_80B967C(u8 taskId);
+static void sub_80B9760(struct Task *task);
+static void sub_80B98A8(u8 taskId);
+
+static const union AffineAnimCmd gUnknown_83E7A00[] =
+{
+ AFFINEANIMCMD_FRAME(0x0, 0x0, 15, 1),
+ AFFINEANIMCMD_JUMP(0),
+};
+
+static const union AffineAnimCmd gUnknown_83E7A10[] =
+{
+ AFFINEANIMCMD_FRAME(0x0, 0x0, 20, 1),
+ AFFINEANIMCMD_JUMP(0),
+};
+
+static const union AffineAnimCmd *const gUnknown_83E7A20[] =
+{
+ gUnknown_83E7A00,
+};
+
+static const union AffineAnimCmd *const gUnknown_83E7A24[] =
+{
+ gUnknown_83E7A10,
+};
+
+const struct SpriteTemplate gUnknown_83E7A28 =
+{
+ .tileTag = ANIM_TAG_BONE,
+ .paletteTag = ANIM_TAG_BONE,
+ .oam = &gOamData_83ACA38,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gUnknown_83E7A20,
+ .callback = AnimBonemerangProjectile,
+};
+
+const struct SpriteTemplate gUnknown_83E7A40 =
+{
+ .tileTag = ANIM_TAG_BONE,
+ .paletteTag = ANIM_TAG_BONE,
+ .oam = &gOamData_83ACA38,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gUnknown_83E7A24,
+ .callback = AnimBoneHitProjectile,
+};
+
+const struct SpriteTemplate gUnknown_83E7A58 =
+{
+ .tileTag = ANIM_TAG_MUD_SAND,
+ .paletteTag = ANIM_TAG_MUD_SAND,
+ .oam = &gOamData_83AC9C8,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = AnimDirtScatter,
+};
+
+static const union AnimCmd gUnknown_83E7A70[] =
+{
+ ANIMCMD_FRAME(1, 1),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd *const gUnknown_83E7A78[] =
+{
+ gUnknown_83E7A70,
+};
+
+const struct SpriteTemplate gUnknown_83E7A7C =
+{
+ .tileTag = ANIM_TAG_MUD_SAND,
+ .paletteTag = ANIM_TAG_MUD_SAND,
+ .oam = &gOamData_83AC9D0,
+ .anims = gUnknown_83E7A78,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = AnimDirtScatter,
+};
+
+const struct SpriteTemplate gUnknown_83E7A94 =
+{
+ .tileTag = ANIM_TAG_MUD_SAND,
+ .paletteTag = ANIM_TAG_MUD_SAND,
+ .oam = &gOamData_83AC9D0,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = AnimMudSportDirt,
+};
+
+const struct SpriteTemplate gUnknown_83E7AAC =
+{
+ .tileTag = ANIM_TAG_MUD_SAND,
+ .paletteTag = ANIM_TAG_MUD_SAND,
+ .oam = &gOamData_83AC9C8,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = AnimFissureDirtPlumeParticle,
+};
+
+const struct SpriteTemplate gUnknown_83E7AC4 =
+{
+ .tileTag = ANIM_TAG_DIRT_MOUND,
+ .paletteTag = ANIM_TAG_DIRT_MOUND,
+ .oam = &gOamData_83AC9F8,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = AnimDigDirtMound,
+};
+
+// Moves a bone projectile towards the target mon, which moves like
+// a boomerang. After hitting the target mon, it comes back to the user.
+static void AnimBonemerangProjectile(struct Sprite *sprite)
+{
+ sprite->pos1.x = GetBattlerSpriteCoord(gBattleAnimAttacker, 2);
+ sprite->pos1.y = GetBattlerSpriteCoord(gBattleAnimAttacker, 3);
+ sprite->data[0] = 20;
+ sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimTarget, 2);
+ sprite->data[4] = GetBattlerSpriteCoord(gBattleAnimTarget, 3);
+ sprite->data[5] = -40;
+ InitAnimArcTranslation(sprite);
+ sprite->callback = AnimBonemerangProjectileStep;
+}
+
+static void AnimBonemerangProjectileStep(struct Sprite *sprite)
+{
+ if (TranslateAnimHorizontalArc(sprite))
+ {
+ sprite->pos1.x += sprite->pos2.x;
+ sprite->pos1.y += sprite->pos2.y;
+ sprite->pos2.y = 0;
+ sprite->pos2.x = 0;
+ sprite->data[0] = 20;
+ sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimAttacker, 2);
+ sprite->data[4] = GetBattlerSpriteCoord(gBattleAnimAttacker, 3);
+ sprite->data[5] = 40;
+ InitAnimArcTranslation(sprite);
+ sprite->callback = AnimBonemerangProjectileEnd;
+ }
+}
+
+static void AnimBonemerangProjectileEnd(struct Sprite *sprite)
+{
+ if (TranslateAnimHorizontalArc(sprite))
+ DestroyAnimSprite(sprite);
+}
+
+// Moves a bone projectile towards the target mon, starting right next to
+// the target mon.
+// arg 0: initial x pixel offset
+// arg 1: initial y pixel offset
+// arg 2: target x pixel offset
+// arg 3: target y pixel offset
+// arg 4: duration
+static void AnimBoneHitProjectile(struct Sprite *sprite)
+{
+ InitSpritePosToAnimTarget(sprite, TRUE);
+ if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
+ gBattleAnimArgs[2] = -gBattleAnimArgs[2];
+ sprite->data[0] = gBattleAnimArgs[4];
+ sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimTarget, 2) + gBattleAnimArgs[2];
+ sprite->data[4] = GetBattlerSpriteCoord(gBattleAnimTarget, 3) + gBattleAnimArgs[3];
+ sprite->callback = StartAnimLinearTranslation;
+ StoreSpriteCallbackInData6(sprite, DestroyAnimSprite);
+}
+
+// Moves a small dirt projectile towards the target mon.
+// arg 0: initial x pixel offset
+// arg 1: initial y pixel offset
+// arg 2: duration
+// arg 3: target x pixel offset
+// arg 4: target y pixel offset
+static void AnimDirtScatter(struct Sprite *sprite)
+{
+ u8 targetXPos, targetYPos;
+ s16 xOffset, yOffset;
+
+ InitSpritePosToAnimAttacker(sprite, 1);
+ targetXPos = GetBattlerSpriteCoord2(gBattleAnimTarget, 2);
+ targetYPos = GetBattlerSpriteCoord2(gBattleAnimTarget, 3);
+ xOffset = Random() & 0x1F;
+ yOffset = Random() & 0x1F;
+ if (xOffset > 16)
+ xOffset = 16 - xOffset;
+ if (yOffset > 16)
+ yOffset = 16 - yOffset;
+ sprite->data[0] = gBattleAnimArgs[2];
+ sprite->data[2] = targetXPos + xOffset;
+ sprite->data[4] = targetYPos + yOffset;
+ sprite->callback = StartAnimLinearTranslation;
+ StoreSpriteCallbackInData6(sprite, DestroySpriteAndMatrix);
+}
+
+// Moves a particle of dirt in the Mud Sport animation.
+// The dirt can either be rising upward, or falling down.
+// arg 0: 0 = dirt is rising into the air, 1 = dirt is falling down
+// arg 1: initial x pixel offset
+// arg 2: initial y pixel offset
+static void AnimMudSportDirt(struct Sprite *sprite)
+{
+ ++sprite->oam.tileNum;
+ if (gBattleAnimArgs[0] == 0)
+ {
+ sprite->pos1.x = GetBattlerSpriteCoord(gBattleAnimAttacker, 2) + gBattleAnimArgs[1];
+ sprite->pos1.y = GetBattlerSpriteCoord(gBattleAnimAttacker, 3) + gBattleAnimArgs[2];
+ sprite->data[0] = gBattleAnimArgs[1] > 0 ? 1 : -1;
+ sprite->callback = AnimMudSportDirtRising;
+ }
+ else
+ {
+ sprite->pos1.x = gBattleAnimArgs[1];
+ sprite->pos1.y = gBattleAnimArgs[2];
+ sprite->pos2.y = -gBattleAnimArgs[2];
+ sprite->callback = AnimMudSportDirtFalling;
+ }
+}
+
+static void AnimMudSportDirtRising(struct Sprite *sprite)
+{
+ if (++sprite->data[1] > 1)
+ {
+ sprite->data[1] = 0;
+ sprite->pos1.x += sprite->data[0];
+ }
+ sprite->pos1.y -= 4;
+ if (sprite->pos1.y < -4)
+ DestroyAnimSprite(sprite);
+}
+
+static void AnimMudSportDirtFalling(struct Sprite *sprite)
+{
+ switch (sprite->data[0])
+ {
+ case 0:
+ sprite->pos2.y += 4;
+ if (sprite->pos2.y >= 0)
+ {
+ sprite->pos2.y = 0;
+ ++sprite->data[0];
+ }
+ break;
+ case 1:
+ if (++sprite->data[1] > 0)
+ {
+ sprite->data[1] = 0;
+ sprite->invisible ^= 1;
+ if (++sprite->data[2] == 10)
+ DestroyAnimSprite(sprite);
+ }
+ break;
+ }
+}
+
+void sub_80B8E94(u8 taskId)
+{
+ struct Task *task = &gTasks[taskId];
+
+ if (gBattleAnimArgs[0] == 0)
+ task->func = sub_80B8ED4;
+ else
+ task->func = sub_80B908C;
+ task->func(taskId);
+}
+
+static void sub_80B8ED4(u8 taskId)
+{
+ u8 var0;
+ struct Task *task = &gTasks[taskId];
+
+ switch (task->data[0])
+ {
+ case 0:
+ task->data[10] = GetAnimBattlerSpriteId(0);
+ task->data[11] = GetBattlerSpriteBGPriorityRank(gBattleAnimAttacker);
+ if (task->data[11] == 1)
+ {
+ task->data[12] = gBattle_BG1_X;
+ task->data[13] = gBattle_BG1_Y;
+ }
+ else
+ {
+ task->data[12] = gBattle_BG2_X;
+ task->data[13] = gBattle_BG2_Y;
+ }
+ var0 = GetBattlerYCoordWithElevation(gBattleAnimAttacker);
+ task->data[14] = var0 - 32;
+ task->data[15] = var0 + 32;
+ if (task->data[14] < 0)
+ task->data[14] = 0;
+ gSprites[task->data[10]].invisible = TRUE;
+ ++task->data[0];
+ break;
+ case 1:
+ sub_80B92B8(task->data[11], task->data[14], task->data[15]);
+ ++task->data[0];
+ break;
+ case 2:
+ task->data[2] = (task->data[2] + 6) & 0x7F;
+ if (++task->data[4] > 2)
+ {
+ task->data[4] = 0;
+ ++task->data[3];
+ }
+ task->data[5] = task->data[3] + (gSineTable[task->data[2]] >> 4);
+ if (task->data[11] == 1)
+ gBattle_BG1_Y = task->data[13] - task->data[5];
+ else
+ gBattle_BG2_Y = task->data[13] - task->data[5];
+
+ if (task->data[5] > 63)
+ {
+ task->data[5] = 120 - task->data[14];
+ if (task->data[11] == 1)
+ gBattle_BG1_Y = task->data[13] - task->data[5];
+ else
+ gBattle_BG2_Y = task->data[13] - task->data[5];
+
+ gSprites[task->data[10]].pos2.x = 272 - gSprites[task->data[10]].pos1.x;
+ ++task->data[0];
+ }
+ break;
+ case 3:
+ gScanlineEffect.state = 3;
+ ++task->data[0];
+ break;
+ case 4:
+ DestroyAnimVisualTask(taskId);
+ gSprites[task->data[10]].invisible = TRUE;
+ break;
+ }
+}
+
+static void sub_80B908C(u8 taskId)
+{
+ u8 spriteId = GetAnimBattlerSpriteId(0);
+
+ gSprites[spriteId].invisible = TRUE;
+ gSprites[spriteId].pos2.x = 0;
+ gSprites[spriteId].pos2.y = 0;
+ if (GetBattlerSpriteBGPriorityRank(gBattleAnimAttacker) == 1)
+ gBattle_BG1_Y = 0;
+ else
+ gBattle_BG2_Y = 0;
+ DestroyAnimVisualTask(taskId);
+}
+
+void sub_80B90EC(u8 taskId)
+{
+ struct Task *task = &gTasks[taskId];
+
+ if (gBattleAnimArgs[0] == 0)
+ task->func = sub_80B912C;
+ else
+ task->func = sub_80B91B0;
+
+ task->func(taskId);
+}
+
+static void sub_80B912C(u8 taskId)
+{
+ struct Task *task = &gTasks[taskId];
+
+ switch (task->data[0])
+ {
+ case 0:
+ task->data[10] = GetAnimBattlerSpriteId(0);
+ gSprites[task->data[10]].invisible = FALSE;
+ gSprites[task->data[10]].pos2.x = 0;
+ gSprites[task->data[10]].pos2.y = 160 - gSprites[task->data[10]].pos1.y;
+ ++task->data[0];
+ break;
+ case 1:
+ DestroyAnimVisualTask(taskId);
+ }
+}
+
+static void sub_80B91B0(u8 taskId)
+{
+ u8 var0;
+ struct Task *task = &gTasks[taskId];
+
+ switch (task->data[0])
+ {
+ case 0:
+ task->data[10] = GetAnimBattlerSpriteId(0);
+ task->data[11] = GetBattlerSpriteBGPriorityRank(gBattleAnimAttacker);
+ if (task->data[11] == 1)
+ task->data[12] = gBattle_BG1_X;
+ else
+ task->data[12] = gBattle_BG2_X;
+
+ var0 = GetBattlerYCoordWithElevation(gBattleAnimAttacker);
+ task->data[14] = var0 - 32;
+ task->data[15] = var0 + 32;
+ ++task->data[0];
+ break;
+ case 1:
+ sub_80B92B8(task->data[11], 0, task->data[15]);
+ ++task->data[0];
+ break;
+ case 2:
+ gSprites[task->data[10]].pos2.y = 96;
+ ++task->data[0];
+ break;
+ case 3:
+ gSprites[task->data[10]].pos2.y -= 8;
+ if (gSprites[task->data[10]].pos2.y == 0)
+ {
+ gScanlineEffect.state = 3;
+ ++task->data[0];
+ }
+ break;
+ case 4:
+ DestroyAnimVisualTask(taskId);
+ break;
+ }
+}
+
+static void sub_80B92B8(u8 useBG1, s16 y, s16 endY)
+{
+ s16 bgX;
+ struct ScanlineEffectParams scanlineParams;
+
+ if (useBG1 == 1)
+ {
+ bgX = gBattle_BG1_X;
+ scanlineParams.dmaDest = &REG_BG1HOFS;
+ }
+ else
+ {
+ bgX = gBattle_BG2_X;
+ scanlineParams.dmaDest = &REG_BG2HOFS;
+ }
+ if (y < 0)
+ y = 0;
+ while (y < endY)
+ {
+ gScanlineEffectRegBuffers[0][y] = bgX;
+ gScanlineEffectRegBuffers[1][y] = bgX;
+ ++y;
+ }
+ while (y < 160)
+ {
+ gScanlineEffectRegBuffers[0][y] = bgX + 240;
+ gScanlineEffectRegBuffers[1][y] = bgX + 240;
+ ++y;
+ }
+ scanlineParams.dmaControl = SCANLINE_EFFECT_DMACNT_16BIT;
+ scanlineParams.initState = 1;
+ scanlineParams.unused9 = 0;
+ ScanlineEffect_SetParams(scanlineParams);
+}
+
+// Moves a particle of dirt in a plume of dirt. Used in Fissure and Dig.
+// arg 0: which mon (0 = attacker, 1 = target)
+// arg 1: which side of mon (0 = left, 1 = right)
+// arg 2: target x offset
+// arg 3: target y offset
+// arg 4: wave amplitude
+// arg 5: duration
+static void AnimFissureDirtPlumeParticle(struct Sprite *sprite)
+{
+ s8 battler;
+ s16 xOffset;
+
+ if (gBattleAnimArgs[0] == 0)
+ battler = gBattleAnimAttacker;
+ else
+ battler = gBattleAnimTarget;
+ xOffset = 24;
+ if (gBattleAnimArgs[1] == 1)
+ {
+ xOffset *= -1;
+ gBattleAnimArgs[2] *= -1;
+ }
+ sprite->pos1.x = GetBattlerSpriteCoord(battler, 2) + xOffset;
+ sprite->pos1.y = GetBattlerYCoordWithElevation(battler) + 30;
+ sprite->data[0] = gBattleAnimArgs[5];
+ sprite->data[2] = sprite->pos1.x + gBattleAnimArgs[2];
+ sprite->data[4] = sprite->pos1.y + gBattleAnimArgs[3];
+ sprite->data[5] = gBattleAnimArgs[4];
+ InitAnimArcTranslation(sprite);
+ sprite->callback = AnimFissureDirtPlumeParticleStep;
+}
+
+static void AnimFissureDirtPlumeParticleStep(struct Sprite *sprite)
+{
+ if (TranslateAnimHorizontalArc(sprite))
+ DestroyAnimSprite(sprite);
+}
+
+// Displays the dirt mound seen in the move Dig for set duration.
+// The dirt mound image is too large for a single sprite, so two
+// sprites are lined up next to each other.
+// arg 0: which mon (0 = attacker, 1 = target)
+// arg 1: oam tile num (0 = left half of image, 1 = right half of image)
+// arg 2: duration
+static void AnimDigDirtMound(struct Sprite *sprite)
+{
+ s8 battler;
+
+ if (gBattleAnimArgs[0] == 0)
+ battler = gBattleAnimAttacker;
+ else
+ battler = gBattleAnimTarget;
+ sprite->pos1.x = GetBattlerSpriteCoord(battler, 0) - 16 + (gBattleAnimArgs[1] * 32);
+ sprite->pos1.y = GetBattlerYCoordWithElevation(battler) + 32;
+ sprite->oam.tileNum += gBattleAnimArgs[1] * 8;
+ StoreSpriteCallbackInData6(sprite, DestroyAnimSprite);
+ sprite->data[0] = gBattleAnimArgs[2];
+ sprite->callback = WaitAnimForDuration;
+}
+
+void sub_80B94B4(u8 taskId)
+{
+ u16 i;
+ struct Task *task = &gTasks[taskId];
+
+ if (gBattleAnimArgs[1])
+ task->data[14] = task->data[15] = gBattleAnimArgs[1] + 3;
+ else
+ task->data[14] = task->data[15] = (gAnimMovePower / 10) + 3;
+
+ task->data[3] = gBattleAnimArgs[2];
+ switch (gBattleAnimArgs[0])
+ {
+ case 5:
+ task->data[13] = gBattle_BG3_X;
+ task->func = sub_80B9584;
+ break;
+ case 4:
+ task->data[13] = 0;
+ for (i = 0; i < MAX_BATTLERS_COUNT; ++i)
+ {
+ if (IsBattlerSpriteVisible(i))
+ {
+ task->data[task->data[13] + 9] = gBattlerSpriteIds[i];
+ ++task->data[13];
+ }
+ }
+ task->func = sub_80B967C;
+ break;
+ default:
+ task->data[9] = GetAnimBattlerSpriteId(gBattleAnimArgs[0]);
+ if (task->data[9] == 0xFF)
+ {
+ DestroyAnimVisualTask(taskId);
+ }
+ else
+ {
+ task->data[13] = 1;
+ task->func = sub_80B967C;
+ }
+
+ break;
+ }
+}
+
+static void sub_80B9584(u8 taskId)
+{
+ struct Task *task = &gTasks[taskId];
+
+ switch (task->data[0])
+ {
+ case 0:
+ if (++task->data[1] > 1)
+ {
+ task->data[1] = 0;
+ if ((task->data[2] & 1) == 0)
+ gBattle_BG3_X = task->data[13] + task->data[15];
+ else
+ gBattle_BG3_X = task->data[13] - task->data[15];
+
+ if (++task->data[2] == task->data[3])
+ {
+ task->data[2] = 0;
+ --task->data[14];
+ ++task->data[0];
+ }
+ }
+ break;
+ case 1:
+ if (++task->data[1] > 1)
+ {
+ task->data[1] = 0;
+ if ((task->data[2] & 1) == 0)
+ gBattle_BG3_X = task->data[13] + task->data[14];
+ else
+ gBattle_BG3_X = task->data[13] - task->data[14];
+
+ if (++task->data[2] == 4)
+ {
+ task->data[2] = 0;
+ if (--task->data[14] == 0)
+ ++task->data[0];
+ }
+ }
+ break;
+ case 2:
+ gBattle_BG3_X = task->data[13];
+ DestroyAnimVisualTask(taskId);
+ break;
+ }
+}
+
+static void sub_80B967C(u8 taskId)
+{
+ u16 i;
+ struct Task *task = &gTasks[taskId];
+
+ switch (task->data[0])
+ {
+ case 0:
+ if (++task->data[1] > 1)
+ {
+ task->data[1] = 0;
+ sub_80B9760(task);
+ if (++task->data[2] == task->data[3])
+ {
+ task->data[2] = 0;
+ --task->data[14];
+ ++task->data[0];
+ }
+ }
+ break;
+ case 1:
+ if (++task->data[1] > 1)
+ {
+ task->data[1] = 0;
+ sub_80B9760(task);
+ if (++task->data[2] == 4)
+ {
+ task->data[2] = 0;
+ if (--task->data[14] == 0)
+ ++task->data[0];
+ }
+ }
+ break;
+ case 2:
+ for (i = 0; i < task->data[13]; ++i)
+ gSprites[task->data[9 + i]].pos2.x = 0;
+ DestroyAnimVisualTask(taskId);
+ break;
+ }
+}
+
+static void sub_80B9760(struct Task *task)
+{
+ u16 i, xOffset;
+
+ if ((task->data[2] & 1) == 0)
+ xOffset = (task->data[14] / 2) + (task->data[14] & 1);
+ else
+ xOffset = -(task->data[14] / 2);
+ for (i = 0; i < task->data[13]; ++i)
+ gSprites[task->data[9 + i]].pos2.x = xOffset;
+}
+
+void AnimTask_IsPowerOver99(u8 taskId)
+{
+ gBattleAnimArgs[15] = gAnimMovePower > 99;
+ DestroyAnimVisualTask(taskId);
+}
+
+void sub_80B9800(u8 taskId)
+{
+ struct Task *newTask;
+ u8 battler = (gBattleAnimArgs[0] & 1) ? gBattleAnimTarget : gBattleAnimAttacker;
+
+ if (gBattleAnimArgs[0] > 1)
+ battler ^= BIT_FLANK;
+ newTask = &gTasks[CreateTask(sub_80B98A8, gBattleAnimArgs[1])];
+ newTask->data[1] = (32 - GetBattlerSpriteCoord(battler, 2)) & 0x1FF;
+ newTask->data[2] = (64 - GetBattlerSpriteCoord(battler, 3)) & 0xFF;
+ gBattle_BG3_X = newTask->data[1];
+ gBattle_BG3_Y = newTask->data[2];
+ newTask->data[3] = gBattleAnimArgs[2];
+ DestroyAnimVisualTask(taskId);
+}
+
+static void sub_80B98A8(u8 taskId)
+{
+ struct Task *task = &gTasks[taskId];
+
+ if (gBattleAnimArgs[7] == task->data[3])
+ {
+ gBattle_BG3_X = 0;
+ gBattle_BG3_Y = 0;
+ DestroyTask(taskId);
+ }
+ else
+ {
+ gBattle_BG3_X = task->data[1];
+ gBattle_BG3_Y = task->data[2];
+ }
+}
diff --git a/src/normal.c b/src/normal.c
new file mode 100644
index 000000000..4d86b55a6
--- /dev/null
+++ b/src/normal.c
@@ -0,0 +1,916 @@
+#include "global.h"
+#include "battle_anim.h"
+#include "palette.h"
+#include "random.h"
+#include "task.h"
+#include "trig.h"
+
+static void AnimConfusionDuck(struct Sprite *sprite);
+static void AnimSimplePaletteBlend(struct Sprite *sprite);
+static void sub_80B9A7C(struct Sprite *sprite);
+static void sub_80B9B8C(struct Sprite *sprite);
+static void sub_80BA27C(struct Sprite *sprite);
+static void sub_80BA560(struct Sprite *sprite);
+static void sub_80BA5F8(struct Sprite *sprite);
+static void sub_80BA630(struct Sprite *sprite);
+static void sub_80BA6C8(struct Sprite *sprite);
+static void sub_80BA738(struct Sprite *sprite);
+static void sub_80BA780(struct Sprite *sprite);
+static void sub_80BA5A8(struct Sprite *sprite);
+static void AnimConfusionDuckStep(struct Sprite *sprite);
+static void AnimSimplePaletteBlendStep(struct Sprite *sprite);
+static void sub_80B9AD0(struct Sprite *sprite);
+static void sub_80B9B5C(struct Sprite *sprite);
+static void sub_80B9C2C(u8 taskId, u8 initialBlendAmount, u8 targetBlendAmount);
+static void sub_80B9C7C(u8 taskId);
+static void sub_80B9DA0(u8 taskId, u8 initialBlendAmount, u8 targetBlendAmount);
+static void sub_80B9DF0(u8 taskId);
+static void sub_80B9EA8(u8 taskId, u8 initialBlendAmount, u8 targetBlendAmount);
+static void sub_80B9F04(u8 taskId);
+static void sub_80B9FD8(u8 taskId);
+static void sub_80BA090(u8 taskId);
+static void sub_80BA3CC(void);
+static void sub_80BA320(struct Sprite *sprite);
+static void sub_80BA4D0(u8 taskId);
+static void sub_80BA7BC(struct Sprite *sprite);
+
+
+static const union AnimCmd gUnknown_83E7ADC[] =
+{
+ ANIMCMD_FRAME(0, 8),
+ ANIMCMD_FRAME(4, 8),
+ ANIMCMD_FRAME(0, 8, .hFlip = TRUE),
+ ANIMCMD_FRAME(8, 8),
+ ANIMCMD_JUMP(0),
+};
+
+static const union AnimCmd gUnknown_83E7AF0[] =
+{
+ ANIMCMD_FRAME(0, 8, .hFlip = TRUE),
+ ANIMCMD_FRAME(4, 8),
+ ANIMCMD_FRAME(0, 8),
+ ANIMCMD_FRAME(8, 8),
+ ANIMCMD_JUMP(0),
+};
+
+static const union AnimCmd *const gUnknown_83E7B04[] =
+{
+ gUnknown_83E7ADC,
+ gUnknown_83E7AF0,
+};
+
+const struct SpriteTemplate gConfusionDuckSpriteTemplate =
+{
+ .tileTag = ANIM_TAG_DUCK,
+ .paletteTag = ANIM_TAG_DUCK,
+ .oam = &gOamData_83AC9D0,
+ .anims = gUnknown_83E7B04,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = AnimConfusionDuck,
+};
+
+const struct SpriteTemplate gSimplePaletteBlendSpriteTemplate =
+{
+ .tileTag = 0,
+ .paletteTag = 0,
+ .oam = &gDummyOamData,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = AnimSimplePaletteBlend,
+};
+
+const struct SpriteTemplate gComplexPaletteBlendSpriteTemplate =
+{
+ .tileTag = 0,
+ .paletteTag = 0,
+ .oam = &gDummyOamData,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = sub_80B9A7C,
+};
+
+static const union AnimCmd gUnknown_83E7B54[] =
+{
+ ANIMCMD_FRAME(0, 3),
+ ANIMCMD_FRAME(16, 3),
+ ANIMCMD_FRAME(32, 3),
+ ANIMCMD_FRAME(48, 3),
+ ANIMCMD_FRAME(64, 3),
+ ANIMCMD_JUMP(0),
+};
+
+static const union AnimCmd *const gUnknown_83E7B6C[] =
+{
+ gUnknown_83E7B54,
+};
+
+const struct SpriteTemplate gUnknown_83E7B70 =
+{
+ .tileTag = ANIM_TAG_SPARKLE_4,
+ .paletteTag = ANIM_TAG_SPARKLE_4,
+ .oam = &gOamData_83AC9D8,
+ .anims = gUnknown_83E7B6C,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = sub_80B9B8C,
+};
+
+const struct SpriteTemplate gUnknown_83E7B88 =
+{
+ .tileTag = 0,
+ .paletteTag = 0,
+ .oam = &gDummyOamData,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = sub_80BA27C,
+};
+
+static const union AffineAnimCmd gUnknown_83E7BA0[] =
+{
+ AFFINEANIMCMD_FRAME(0x0, 0x0, 0, 8),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd gUnknown_83E7BB0[] =
+{
+ AFFINEANIMCMD_FRAME(0xD8, 0xD8, 0, 0),
+ AFFINEANIMCMD_FRAME(0x0, 0x0, 0, 8),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd gUnknown_83E7BC8[] =
+{
+ AFFINEANIMCMD_FRAME(0xB0, 0xB0, 0, 0),
+ AFFINEANIMCMD_FRAME(0x0, 0x0, 0, 8),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd gUnknown_83E7BE0[] =
+{
+ AFFINEANIMCMD_FRAME(0x80, 0x80, 0, 0),
+ AFFINEANIMCMD_FRAME(0x0, 0x0, 0, 8),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd *const gUnknown_83E7BF8[] =
+{
+ gUnknown_83E7BA0,
+ gUnknown_83E7BB0,
+ gUnknown_83E7BC8,
+ gUnknown_83E7BE0,
+};
+
+const struct SpriteTemplate gBasicHitSplatSpriteTemplate =
+{
+ .tileTag = ANIM_TAG_IMPACT,
+ .paletteTag = ANIM_TAG_IMPACT,
+ .oam = &gOamData_83ACB58,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gUnknown_83E7BF8,
+ .callback = sub_80BA560,
+};
+
+const struct SpriteTemplate gUnknown_83E7C20 =
+{
+ .tileTag = ANIM_TAG_IMPACT,
+ .paletteTag = ANIM_TAG_IMPACT,
+ .oam = &gOamData_83ACB58,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gUnknown_83E7BF8,
+ .callback = sub_80BA5F8,
+};
+
+const struct SpriteTemplate gUnknown_83E7C38 =
+{
+ .tileTag = ANIM_TAG_WATER_IMPACT,
+ .paletteTag = ANIM_TAG_WATER_IMPACT,
+ .oam = &gOamData_83ACB58,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gUnknown_83E7BF8,
+ .callback = sub_80BA560,
+};
+
+const struct SpriteTemplate gUnknown_83E7C50 =
+{
+ .tileTag = ANIM_TAG_IMPACT,
+ .paletteTag = ANIM_TAG_IMPACT,
+ .oam = &gOamData_83ACB58,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gUnknown_83E7BF8,
+ .callback = sub_80BA630,
+};
+
+const struct SpriteTemplate gUnknown_83E7C68 =
+{
+ .tileTag = ANIM_TAG_IMPACT,
+ .paletteTag = ANIM_TAG_IMPACT,
+ .oam = &gOamData_83ACB58,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gUnknown_83E7BF8,
+ .callback = sub_80BA6C8,
+};
+
+const struct SpriteTemplate gUnknown_83E7C80 =
+{
+ .tileTag = ANIM_TAG_CROSS_IMPACT,
+ .paletteTag = ANIM_TAG_CROSS_IMPACT,
+ .oam = &gOamData_83ACAF8,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = sub_80BA738,
+};
+
+const struct SpriteTemplate gUnknown_83E7C98 =
+{
+ .tileTag = ANIM_TAG_IMPACT,
+ .paletteTag = ANIM_TAG_IMPACT,
+ .oam = &gOamData_83ACA38,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gUnknown_83E7BF8,
+ .callback = sub_80BA780,
+};
+
+const struct SpriteTemplate gUnknown_83E7CB0 =
+{
+ .tileTag = ANIM_TAG_IMPACT,
+ .paletteTag = ANIM_TAG_IMPACT,
+ .oam = &gOamData_83ACB58,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gUnknown_83E7BF8,
+ .callback = sub_80BA5A8,
+};
+
+// Moves a spinning duck around the mon's head.
+// arg 0: initial x pixel offset
+// arg 1: initial y pixel offset
+// arg 2: initial wave offset
+// arg 3: wave period (higher means faster wave)
+// arg 4: duration
+static void AnimConfusionDuck(struct Sprite *sprite)
+{
+ sprite->pos1.x += gBattleAnimArgs[0];
+ sprite->pos1.y += gBattleAnimArgs[1];
+ sprite->data[0] = gBattleAnimArgs[2];
+ if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
+ {
+ sprite->data[1] = -gBattleAnimArgs[3];
+ sprite->data[4] = 1;
+ }
+ else
+ {
+ sprite->data[1] = gBattleAnimArgs[3];
+ sprite->data[4] = 0;
+ StartSpriteAnim(sprite, 1);
+ }
+ sprite->data[3] = gBattleAnimArgs[4];
+ sprite->callback = AnimConfusionDuckStep;
+ sprite->callback(sprite);
+}
+
+static void AnimConfusionDuckStep(struct Sprite *sprite)
+{
+ sprite->pos2.x = Cos(sprite->data[0], 30);
+ sprite->pos2.y = Sin(sprite->data[0], 10);
+ if ((u16)sprite->data[0] < 128)
+ sprite->oam.priority = 1;
+ else
+ sprite->oam.priority = 3;
+ sprite->data[0] = (sprite->data[0] + sprite->data[1]) & 0xFF;
+ if (++sprite->data[2] == sprite->data[3])
+ DestroyAnimSprite(sprite);
+}
+
+// Performs a simple color blend on a specified sprite.
+// arg 0: palette selector
+// arg 1: delay
+// arg 2: start blend amount
+// arg 3: end blend amount
+// arg 4: blend color
+static void AnimSimplePaletteBlend(struct Sprite *sprite)
+{
+ u32 selectedPalettes = UnpackSelectedBattleAnimPalettes(gBattleAnimArgs[0]);
+
+ BeginNormalPaletteFade(selectedPalettes, gBattleAnimArgs[1], gBattleAnimArgs[2], gBattleAnimArgs[3], gBattleAnimArgs[4]);
+ sprite->invisible = TRUE;
+ sprite->callback = AnimSimplePaletteBlendStep;
+}
+
+// Unpacks a bitfield and returns a bitmask of its selected palettes.
+// Bits 0-6 of the selector parameter result in the following palettes being selected:
+// 0: battle background palettes (BG palettes 1, 2, and 3)
+// 1: gBattleAnimAttacker OBJ palette
+// 2: gBattleAnimTarget OBJ palette
+// 3: gBattleAnimAttacker partner OBJ palette
+// 4: gBattleAnimTarget partner OBJ palette
+// 5: BG palette 4
+// 6: BG palette 5
+u32 UnpackSelectedBattleAnimPalettes(s16 selector)
+{
+ u8 battleBackground = selector & 1;
+ u8 attacker = (selector >> 1) & 1;
+ u8 target = (selector >> 2) & 1;
+ u8 attackerPartner = (selector >> 3) & 1;
+ u8 targetPartner = (selector >> 4) & 1;
+ u8 arg5 = (selector >> 5) & 1;
+ u8 arg6 = (selector >> 6) & 1;
+
+ return sub_8075BE8(battleBackground, attacker, target, attackerPartner, targetPartner, arg5, arg6);
+}
+
+static void AnimSimplePaletteBlendStep(struct Sprite *sprite)
+{
+ if (!gPaletteFade.active)
+ DestroyAnimSprite(sprite);
+}
+
+static void sub_80B9A7C(struct Sprite *sprite)
+{
+ u32 selectedPalettes;
+
+ sprite->data[0] = gBattleAnimArgs[1];
+ sprite->data[1] = gBattleAnimArgs[1];
+ sprite->data[2] = gBattleAnimArgs[2];
+ sprite->data[3] = gBattleAnimArgs[3];
+ sprite->data[4] = gBattleAnimArgs[4];
+ sprite->data[5] = gBattleAnimArgs[5];
+ sprite->data[6] = gBattleAnimArgs[6];
+ sprite->data[7] = gBattleAnimArgs[0];
+ selectedPalettes = UnpackSelectedBattleAnimPalettes(sprite->data[7]);
+ BlendPalettes(selectedPalettes, gBattleAnimArgs[4], gBattleAnimArgs[3]);
+ sprite->invisible = TRUE;
+ sprite->callback = sub_80B9AD0;
+}
+
+static void sub_80B9AD0(struct Sprite *sprite)
+{
+ u32 selectedPalettes;
+
+ if (sprite->data[0] > 0)
+ {
+ --sprite->data[0];
+ return;
+ }
+ if (gPaletteFade.active)
+ return;
+ if (sprite->data[2] == 0)
+ {
+ sprite->callback = sub_80B9B5C;
+ return;
+ }
+ selectedPalettes = UnpackSelectedBattleAnimPalettes(sprite->data[7]);
+ if (sprite->data[1] & 0x100)
+ BlendPalettes(selectedPalettes, sprite->data[4], sprite->data[3]);
+ else
+ BlendPalettes(selectedPalettes, sprite->data[6], sprite->data[5]);
+ sprite->data[1] ^= 0x100;
+ sprite->data[0] = sprite->data[1] & 0xFF;
+ --sprite->data[2];
+}
+
+static void sub_80B9B5C(struct Sprite *sprite)
+{
+ u32 selectedPalettes;
+
+ if (!gPaletteFade.active)
+ {
+ selectedPalettes = UnpackSelectedBattleAnimPalettes(sprite->data[7]);
+ BlendPalettes(selectedPalettes, 0, 0);
+ DestroyAnimSprite(sprite);
+ }
+}
+
+static void sub_80B9B8C(struct Sprite *sprite)
+{
+ sprite->pos1.x += gBattleAnimArgs[0];
+ sprite->pos1.y += gBattleAnimArgs[1];
+ sprite->data[0] = 0;
+ sprite->data[1] = 10;
+ sprite->data[2] = 8;
+ sprite->data[3] = 40;
+ sprite->data[4] = 112;
+ sprite->data[5] = 0;
+ StoreSpriteCallbackInData6(sprite, DestroySpriteAndMatrix);
+ sprite->callback = TranslateSpriteInGrowingCircleOverDuration;
+ sprite->callback(sprite);
+}
+
+void sub_80B9BDC(u8 taskId)
+{
+ gTasks[taskId].data[0] = gBattleAnimArgs[0];
+ gTasks[taskId].data[1] = gBattleAnimArgs[1];
+ gTasks[taskId].data[2] = gBattleAnimArgs[2];
+ gTasks[taskId].data[3] = gBattleAnimArgs[3];
+ gTasks[taskId].data[4] = gBattleAnimArgs[4];
+ gTasks[taskId].data[5] = gBattleAnimArgs[5];
+ gTasks[taskId].data[8] = 0;
+ sub_80B9C2C(taskId, 0, gTasks[taskId].data[4]);
+ gTasks[taskId].func = sub_80B9C7C;
+}
+
+static void sub_80B9C2C(u8 taskId, u8 initialBlendAmount, u8 targetBlendAmount)
+{
+ u32 selectedPalettes = UnpackSelectedBattleAnimPalettes(gTasks[taskId].data[0]);
+
+ BeginNormalPaletteFade(selectedPalettes,
+ gTasks[taskId].data[1],
+ initialBlendAmount,
+ targetBlendAmount,
+ gTasks[taskId].data[5]);
+ --gTasks[taskId].data[2];
+ gTasks[taskId].data[8] ^= 1;
+}
+
+static void sub_80B9C7C(u8 taskId)
+{
+ u8 initialBlendAmount, targetBlendAmount;
+
+ if (!gPaletteFade.active)
+ {
+ if (gTasks[taskId].data[2] > 0)
+ {
+ if (gTasks[taskId].data[8] == 0)
+ {
+ initialBlendAmount = gTasks[taskId].data[3];
+ targetBlendAmount = gTasks[taskId].data[4];
+ }
+ else
+ {
+ initialBlendAmount = gTasks[taskId].data[4];
+ targetBlendAmount = gTasks[taskId].data[3];
+ }
+ if (gTasks[taskId].data[2] == 1)
+ targetBlendAmount = 0;
+ sub_80B9C2C(taskId, initialBlendAmount, targetBlendAmount);
+ }
+ else
+ {
+ DestroyAnimVisualTask(taskId);
+ }
+ }
+}
+
+void sub_80B9CE4(u8 taskId)
+{
+ s32 battler;
+ u32 selectedPalettes = 0;
+
+ gTasks[taskId].data[0] = gBattleAnimArgs[0];
+ gTasks[taskId].data[1] = gBattleAnimArgs[1];
+ gTasks[taskId].data[2] = gBattleAnimArgs[2];
+ gTasks[taskId].data[3] = gBattleAnimArgs[3];
+ gTasks[taskId].data[4] = gBattleAnimArgs[4];
+ gTasks[taskId].data[5] = gBattleAnimArgs[5];
+ gTasks[taskId].data[8] = 0;
+ for (battler = 0; battler < gBattlersCount; ++battler)
+ if (battler != gBattleAnimAttacker && battler != gBattleAnimTarget)
+ selectedPalettes |= 1 << (battler + 16);
+ if (gBattleAnimArgs[0] == 1)
+ selectedPalettes |= 0xE;
+ gTasks[taskId].data[9] = selectedPalettes >> 16;
+ gTasks[taskId].data[10] = selectedPalettes & 0xFF;
+ sub_80B9DA0(taskId, 0, gTasks[taskId].data[4]);
+ gTasks[taskId].func = sub_80B9DF0;
+}
+
+static void sub_80B9DA0(u8 taskId, u8 initialBlendAmount, u8 targetBlendAmount)
+{
+ u32 selectedPalettes = ((u16)gTasks[taskId].data[9] << 16) | (u16)gTasks[taskId].data[10];
+
+ BeginNormalPaletteFade(selectedPalettes,
+ gTasks[taskId].data[1],
+ initialBlendAmount,
+ targetBlendAmount,
+ gTasks[taskId].data[5]);
+ --gTasks[taskId].data[2];
+ gTasks[taskId].data[8] ^= 1;
+}
+
+static void sub_80B9DF0(u8 taskId)
+{
+ u8 initialBlendAmount, targetBlendAmount;
+
+ if (!gPaletteFade.active)
+ {
+ if (gTasks[taskId].data[2] > 0)
+ {
+ if (gTasks[taskId].data[8] == 0)
+ {
+ initialBlendAmount = gTasks[taskId].data[3];
+ targetBlendAmount = gTasks[taskId].data[4];
+ }
+ else
+ {
+ initialBlendAmount = gTasks[taskId].data[4];
+ targetBlendAmount = gTasks[taskId].data[3];
+ }
+
+ if (gTasks[taskId].data[2] == 1)
+ targetBlendAmount = 0;
+ sub_80B9DA0(taskId, initialBlendAmount, targetBlendAmount);
+ }
+ else
+ {
+ DestroyAnimVisualTask(taskId);
+ }
+ }
+}
+
+void sub_80B9E58(u8 taskId)
+{
+ u8 paletteIndex;
+
+ gTasks[taskId].data[0] = gBattleAnimArgs[0];
+ gTasks[taskId].data[1] = gBattleAnimArgs[1];
+ gTasks[taskId].data[2] = gBattleAnimArgs[2];
+ gTasks[taskId].data[3] = gBattleAnimArgs[3];
+ gTasks[taskId].data[4] = gBattleAnimArgs[4];
+ gTasks[taskId].data[5] = gBattleAnimArgs[5];
+ gTasks[taskId].data[8] = 0;
+ sub_80B9EA8(taskId, 0, gTasks[taskId].data[4]);
+ gTasks[taskId].func = sub_80B9F04;
+}
+
+static void sub_80B9EA8(u8 taskId, u8 initialBlendAmount, u8 targetBlendAmount)
+{
+ u8 paletteIndex = IndexOfSpritePaletteTag(gTasks[taskId].data[0]);
+
+ BeginNormalPaletteFade(1 << (paletteIndex + 16),
+ gTasks[taskId].data[1],
+ initialBlendAmount,
+ targetBlendAmount,
+ gTasks[taskId].data[5]);
+ --gTasks[taskId].data[2];
+ gTasks[taskId].data[8] ^= 1;
+}
+
+static void sub_80B9F04(u8 taskId)
+{
+ u8 initialBlendAmount, targetBlendAmount;
+
+ if (!gPaletteFade.active)
+ {
+ if (gTasks[taskId].data[2] > 0)
+ {
+ if (gTasks[taskId].data[8] == 0)
+ {
+ initialBlendAmount = gTasks[taskId].data[3];
+ targetBlendAmount = gTasks[taskId].data[4];
+ }
+ else
+ {
+ initialBlendAmount = gTasks[taskId].data[4];
+ targetBlendAmount = gTasks[taskId].data[3];
+ }
+
+ if (gTasks[taskId].data[2] == 1)
+ targetBlendAmount = 0;
+ sub_80B9EA8(taskId, initialBlendAmount, targetBlendAmount);
+ }
+ else
+ {
+ DestroyAnimVisualTask(taskId);
+ }
+ }
+}
+
+void sub_80B9F6C(u8 taskId)
+{
+ u8 paletteIndex;
+
+ gTasks[taskId].data[0] = gBattleAnimArgs[1];
+ gTasks[taskId].data[1] = gBattleAnimArgs[1];
+ gTasks[taskId].data[2] = gBattleAnimArgs[2];
+ gTasks[taskId].data[3] = gBattleAnimArgs[3];
+ gTasks[taskId].data[4] = gBattleAnimArgs[4];
+ gTasks[taskId].data[5] = gBattleAnimArgs[5];
+ gTasks[taskId].data[6] = gBattleAnimArgs[6];
+ gTasks[taskId].data[7] = gBattleAnimArgs[0];
+ paletteIndex = IndexOfSpritePaletteTag(gBattleAnimArgs[0]);
+ BeginNormalPaletteFade(1 << (paletteIndex + 16),
+ 0,
+ gBattleAnimArgs[4],
+ gBattleAnimArgs[4],
+ gBattleAnimArgs[3]);
+ gTasks[taskId].func = sub_80B9FD8;
+}
+
+static void sub_80B9FD8(u8 taskId)
+{
+ u32 selectedPalettes;
+
+ if (gTasks[taskId].data[0] > 0)
+ {
+ --gTasks[taskId].data[0];
+ return;
+ }
+ if (gPaletteFade.active)
+ return;
+ if (gTasks[taskId].data[2] == 0)
+ {
+ gTasks[taskId].func = sub_80BA090;
+ return;
+ }
+ selectedPalettes = 1 << (IndexOfSpritePaletteTag(gTasks[taskId].data[7]) + 16);
+ if (gTasks[taskId].data[1] & 0x100)
+ BeginNormalPaletteFade(selectedPalettes,
+ 0,
+ gTasks[taskId].data[4],
+ gTasks[taskId].data[4],
+ gTasks[taskId].data[3]);
+ else
+ BeginNormalPaletteFade(selectedPalettes,
+ 0,
+ gTasks[taskId].data[6],
+ gTasks[taskId].data[6],
+ gTasks[taskId].data[5]);
+ gTasks[taskId].data[1] ^= 0x100;
+ gTasks[taskId].data[0] = gTasks[taskId].data[1] & 0xFF;
+ --gTasks[taskId].data[2];
+}
+
+static void sub_80BA090(u8 taskId)
+{
+ u32 selectedPalettes;
+
+ if (!gPaletteFade.active)
+ {
+ selectedPalettes = 1 << (IndexOfSpritePaletteTag(gTasks[taskId].data[7]) + 16);
+ BeginNormalPaletteFade(selectedPalettes, 0, 0, 0, RGB(0, 0, 0));
+ DestroyAnimVisualTask(taskId);
+ }
+}
+
+void sub_80BA0E8(u8 taskId)
+{
+ u32 selectedPalettes = 0;
+ u8 attackerBattler = gBattleAnimAttacker;
+ u8 targetBattler = gBattleAnimTarget;
+
+ if (gBattleAnimArgs[0] & 0x100)
+ selectedPalettes = sub_8075BE8(1, 0, 0, 0, 0, 0, 0);
+ if (gBattleAnimArgs[1] & 0x100)
+ selectedPalettes |= (0x10000 << attackerBattler);
+ if (gBattleAnimArgs[2] & 0x100)
+ selectedPalettes |= (0x10000 << targetBattler);
+ InvertPlttBuffer(selectedPalettes);
+ DestroyAnimVisualTask(taskId);
+}
+
+// not used
+static void sub_80BA16C(u8 taskId)
+{
+ u8 attackerBattler;
+ u8 targetBattler;
+ u8 paletteIndex;
+ u32 selectedPalettes = 0;
+
+ if (gTasks[taskId].data[0] == 0)
+ {
+ gTasks[taskId].data[2] = gBattleAnimArgs[0];
+ gTasks[taskId].data[3] = gBattleAnimArgs[1];
+ gTasks[taskId].data[4] = gBattleAnimArgs[2];
+ gTasks[taskId].data[1] = gBattleAnimArgs[3];
+ gTasks[taskId].data[5] = gBattleAnimArgs[4];
+ gTasks[taskId].data[6] = gBattleAnimArgs[5];
+ gTasks[taskId].data[7] = gBattleAnimArgs[6];
+ }
+ ++gTasks[taskId].data[0];
+ attackerBattler = gBattleAnimAttacker;
+ targetBattler = gBattleAnimTarget;
+ if (gTasks[taskId].data[2] & 0x100)
+ selectedPalettes = 0x0000FFFF;
+ if (gTasks[taskId].data[2] & 0x1)
+ {
+ paletteIndex = IndexOfSpritePaletteTag(gSprites[gHealthboxSpriteIds[attackerBattler]].template->paletteTag);
+ selectedPalettes |= (1 << paletteIndex) << 16;
+ }
+ if (gTasks[taskId].data[3] & 0x100)
+ selectedPalettes |= (1 << attackerBattler) << 16;
+ if (gTasks[taskId].data[4] & 0x100)
+ selectedPalettes |= (1 << targetBattler) << 16;
+ TintPlttBuffer(selectedPalettes, gTasks[taskId].data[5], gTasks[taskId].data[6], gTasks[taskId].data[7]);
+ if (gTasks[taskId].data[0] == gTasks[taskId].data[1])
+ {
+ UnfadePlttBuffer(selectedPalettes);
+ DestroyAnimVisualTask(taskId);
+ }
+}
+
+static void sub_80BA27C(struct Sprite *sprite)
+{
+ u16 var0;
+
+ sprite->invisible = TRUE;
+ sprite->data[0] = -gBattleAnimArgs[0];
+ sprite->data[1] = gBattleAnimArgs[1];
+ sprite->data[2] = gBattleAnimArgs[1];
+ sprite->data[3] = gBattleAnimArgs[2];
+
+ switch (gBattleAnimArgs[3])
+ {
+ case 0:
+ StoreSpriteCallbackInData6(sprite, (void *)&gBattle_BG3_X);
+ break;
+ case 1:
+ StoreSpriteCallbackInData6(sprite, (void *)&gBattle_BG3_Y);
+ break;
+ case 2:
+ StoreSpriteCallbackInData6(sprite, (void *)&gSpriteCoordOffsetX);
+ break;
+ default:
+ StoreSpriteCallbackInData6(sprite, (void *)&gSpriteCoordOffsetY);
+ break;
+ }
+ sprite->data[4] = *(u16 *)(sprite->data[6] | (sprite->data[7] << 16));
+ sprite->data[5] = gBattleAnimArgs[3];
+ var0 = sprite->data[5] - 2;
+ if (var0 < 2)
+ sub_80BA3CC();
+ sprite->callback = sub_80BA320;
+}
+
+static void sub_80BA320(struct Sprite *sprite)
+{
+ u8 i;
+ u16 var0;
+
+ if (sprite->data[3] > 0)
+ {
+ --sprite->data[3];
+ if (sprite->data[1] > 0)
+ {
+ --sprite->data[1];
+ }
+ else
+ {
+ sprite->data[1] = sprite->data[2];
+ *(u16 *)(sprite->data[6] | (sprite->data[7] << 16)) += sprite->data[0];
+ sprite->data[0] = -sprite->data[0];
+ }
+ }
+ else
+ {
+ *(u16 *)(sprite->data[6] | (sprite->data[7] << 16)) = sprite->data[4];
+ var0 = sprite->data[5] - 2;
+ if (var0 < 2)
+ for (i = 0; i < gBattlersCount; ++i)
+ gSprites[gBattlerSpriteIds[i]].coordOffsetEnabled = 0;
+ DestroyAnimSprite(sprite);
+ }
+}
+
+static void sub_80BA3CC(void)
+{
+ gSprites[gBattlerSpriteIds[gBattleAnimAttacker]].coordOffsetEnabled = 0;
+ gSprites[gBattlerSpriteIds[gBattleAnimTarget]].coordOffsetEnabled = 0;
+ if (gBattleAnimArgs[4] == 2)
+ {
+ gSprites[gBattlerSpriteIds[gBattleAnimAttacker]].coordOffsetEnabled = 1;
+ gSprites[gBattlerSpriteIds[gBattleAnimTarget]].coordOffsetEnabled = 1;
+ }
+ else
+ {
+ if (gBattleAnimArgs[4] == 0)
+ gSprites[gBattlerSpriteIds[gBattleAnimAttacker]].coordOffsetEnabled = 1;
+ else
+ gSprites[gBattlerSpriteIds[gBattleAnimTarget]].coordOffsetEnabled = 1;
+ }
+}
+
+void sub_80BA47C(u8 taskId)
+{
+ gTasks[taskId].data[0] = gBattleAnimArgs[0];
+ gTasks[taskId].data[1] = gBattleAnimArgs[1];
+ gTasks[taskId].data[2] = gBattleAnimArgs[2];
+ gTasks[taskId].data[3] = gBattleAnimArgs[3];
+ gTasks[taskId].data[8] = gBattleAnimArgs[3];
+ gBattle_BG3_X = gBattleAnimArgs[0];
+ gBattle_BG3_Y = gBattleAnimArgs[1];
+ gTasks[taskId].func = sub_80BA4D0;
+ gTasks[taskId].func(taskId);
+}
+
+static void sub_80BA4D0(u8 taskId)
+{
+ if (gTasks[taskId].data[3] == 0)
+ {
+ if (gBattle_BG3_X == gTasks[taskId].data[0])
+ gBattle_BG3_X = -gTasks[taskId].data[0];
+ else
+ gBattle_BG3_X = gTasks[taskId].data[0];
+
+ if (gBattle_BG3_Y == -gTasks[taskId].data[1])
+ gBattle_BG3_Y = 0;
+ else
+ gBattle_BG3_Y = -gTasks[taskId].data[1];
+
+ gTasks[taskId].data[3] = gTasks[taskId].data[8];
+ if (--gTasks[taskId].data[2] == 0)
+ {
+ gBattle_BG3_X = 0;
+ gBattle_BG3_Y = 0;
+ DestroyAnimVisualTask(taskId);
+ }
+ }
+ else
+ {
+ --gTasks[taskId].data[3];
+ }
+}
+
+static void sub_80BA560(struct Sprite *sprite)
+{
+ StartSpriteAffineAnim(sprite, gBattleAnimArgs[3]);
+ if (gBattleAnimArgs[2] == 0)
+ InitSpritePosToAnimAttacker(sprite, 1);
+ else
+ InitSpritePosToAnimTarget(sprite, TRUE);
+ sprite->callback = RunStoredCallbackWhenAffineAnimEnds;
+ StoreSpriteCallbackInData6(sprite, DestroyAnimSprite);
+}
+
+static void sub_80BA5A8(struct Sprite *sprite)
+{
+ StartSpriteAffineAnim(sprite, gBattleAnimArgs[3]);
+ if (gBattleAnimArgs[2] == 0)
+ InitSpritePosToAnimAttacker(sprite, 1);
+ else
+ InitSpritePosToAnimTarget(sprite, TRUE);
+ sprite->data[0] = gBattleAnimArgs[4];
+ sprite->callback = RunStoredCallbackWhenAffineAnimEnds;
+ StoreSpriteCallbackInData6(sprite, sub_80B1D3C);
+}
+
+static void sub_80BA5F8(struct Sprite *sprite)
+{
+ if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER && !IsContest())
+ gBattleAnimArgs[1] = -gBattleAnimArgs[1];
+ sub_80BA560(sprite);
+}
+
+static void sub_80BA630(struct Sprite *sprite)
+{
+ if (gBattleAnimArgs[1] == -1)
+ gBattleAnimArgs[1] = Random() & 3;
+ StartSpriteAffineAnim(sprite, gBattleAnimArgs[1]);
+ if (gBattleAnimArgs[0] == 0)
+ InitSpritePosToAnimAttacker(sprite, 0);
+ else
+ InitSpritePosToAnimTarget(sprite, FALSE);
+ sprite->pos2.x += (Random() % 48) - 24;
+ sprite->pos2.y += (Random() % 24) - 12;
+ StoreSpriteCallbackInData6(sprite, DestroySpriteAndMatrix);
+ sprite->callback = RunStoredCallbackWhenAffineAnimEnds;
+}
+
+static void sub_80BA6C8(struct Sprite *sprite)
+{
+ sprite->data[0] = GetAnimBattlerSpriteId(gBattleAnimArgs[0]);
+ sprite->pos1.x = gSprites[sprite->data[0]].pos1.x + gSprites[sprite->data[0]].pos2.x;
+ sprite->pos1.y = gSprites[sprite->data[0]].pos1.y + gSprites[sprite->data[0]].pos2.y;
+ sprite->pos2.x = gBattleAnimArgs[1];
+ sprite->pos2.y = gBattleAnimArgs[2];
+ StartSpriteAffineAnim(sprite, gBattleAnimArgs[3]);
+ StoreSpriteCallbackInData6(sprite, DestroySpriteAndMatrix);
+ sprite->callback = RunStoredCallbackWhenAffineAnimEnds;
+}
+
+static void sub_80BA738(struct Sprite *sprite)
+{
+ if (gBattleAnimArgs[2] == 0)
+ InitSpritePosToAnimAttacker(sprite, 1);
+ else
+ InitSpritePosToAnimTarget(sprite, TRUE);
+ sprite->data[0] = gBattleAnimArgs[3];
+ StoreSpriteCallbackInData6(sprite, DestroyAnimSprite);
+ sprite->callback = WaitAnimForDuration;
+}
+
+static void sub_80BA780(struct Sprite *sprite)
+{
+ StartSpriteAffineAnim(sprite, gBattleAnimArgs[3]);
+ if (gBattleAnimArgs[2] == 0)
+ InitSpritePosToAnimAttacker(sprite, 1);
+ else
+ InitSpritePosToAnimTarget(sprite, TRUE);
+ sprite->callback = sub_80BA7BC;
+}
+
+static void sub_80BA7BC(struct Sprite *sprite)
+{
+ sprite->invisible ^= 1;
+ if (sprite->data[0]++ > 12)
+ DestroyAnimSprite(sprite);
+}