summaryrefslogtreecommitdiff
path: root/src/battle_anim_ground.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/battle_anim_ground.c')
-rw-r--r--src/battle_anim_ground.c772
1 files changed, 772 insertions, 0 deletions
diff --git a/src/battle_anim_ground.c b/src/battle_anim_ground.c
new file mode 100644
index 000000000..875ecbd75
--- /dev/null
+++ b/src/battle_anim_ground.c
@@ -0,0 +1,772 @@
+#include "global.h"
+#include "battle_anim.h"
+#include "random.h"
+#include "scanline_effect.h"
+#include "task.h"
+#include "trig.h"
+#include "constants/rgb.h"
+
+static void AnimBonemerangProjectile(struct Sprite *);
+static void AnimBoneHitProjectile(struct Sprite *);
+static void AnimDirtScatter(struct Sprite *);
+static void AnimMudSportDirt(struct Sprite *);
+static void AnimDirtPlumeParticle(struct Sprite *);
+static void AnimDirtPlumeParticle_Step(struct Sprite *);
+static void AnimDigDirtMound(struct Sprite *);
+static void AnimBonemerangProjectile_Step(struct Sprite *);
+static void AnimBonemerangProjectile_End(struct Sprite *);
+static void AnimMudSportDirtRising(struct Sprite *);
+static void AnimMudSportDirtFalling(struct Sprite *);
+static void AnimTask_DigBounceMovement(u8);
+static void AnimTask_DigEndBounceMovementSetInvisible(u8);
+static void AnimTask_DigSetVisibleUnderground(u8);
+static void AnimTask_DigRiseUpFromHole(u8);
+static void sub_81150E0(u8, s16, s16);
+static void AnimTask_ShakeTerrain(u8);
+static void AnimTask_ShakeBattlers(u8);
+static void SetBattlersXOffsetForShake(struct Task *);
+static void sub_81156D0(u8);
+
+static const union AffineAnimCmd sAffineAnim_Bonemerang[] =
+{
+ AFFINEANIMCMD_FRAME(0x0, 0x0, 15, 1),
+ AFFINEANIMCMD_JUMP(0),
+};
+
+static const union AffineAnimCmd sAffineAnim_SpinningBone[] =
+{
+ AFFINEANIMCMD_FRAME(0x0, 0x0, 20, 1),
+ AFFINEANIMCMD_JUMP(0),
+};
+
+static const union AffineAnimCmd *const sAffineAnims_Bonemerang[] =
+{
+ sAffineAnim_Bonemerang,
+};
+
+static const union AffineAnimCmd *const sAffineAnims_SpinningBone[] =
+{
+ sAffineAnim_SpinningBone,
+};
+
+const struct SpriteTemplate gBonemerangSpriteTemplate =
+{
+ .tileTag = ANIM_TAG_BONE,
+ .paletteTag = ANIM_TAG_BONE,
+ .oam = &gOamData_AffineNormal_ObjNormal_32x32,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = sAffineAnims_Bonemerang,
+ .callback = AnimBonemerangProjectile,
+};
+
+const struct SpriteTemplate gSpinningBoneSpriteTemplate =
+{
+ .tileTag = ANIM_TAG_BONE,
+ .paletteTag = ANIM_TAG_BONE,
+ .oam = &gOamData_AffineNormal_ObjNormal_32x32,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = sAffineAnims_SpinningBone,
+ .callback = AnimBoneHitProjectile,
+};
+
+const struct SpriteTemplate gSandAttackDirtSpriteTemplate =
+{
+ .tileTag = ANIM_TAG_MUD_SAND,
+ .paletteTag = ANIM_TAG_MUD_SAND,
+ .oam = &gOamData_AffineOff_ObjNormal_8x8,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = AnimDirtScatter,
+};
+
+static const union AnimCmd sAnim_MudSlapMud[] =
+{
+ ANIMCMD_FRAME(1, 1),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd *const sAnims_MudSlapMud[] =
+{
+ sAnim_MudSlapMud,
+};
+
+const struct SpriteTemplate gMudSlapMudSpriteTemplate =
+{
+ .tileTag = ANIM_TAG_MUD_SAND,
+ .paletteTag = ANIM_TAG_MUD_SAND,
+ .oam = &gOamData_AffineOff_ObjNormal_16x16,
+ .anims = sAnims_MudSlapMud,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = AnimDirtScatter,
+};
+
+const struct SpriteTemplate gMudsportMudSpriteTemplate =
+{
+ .tileTag = ANIM_TAG_MUD_SAND,
+ .paletteTag = ANIM_TAG_MUD_SAND,
+ .oam = &gOamData_AffineOff_ObjNormal_16x16,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = AnimMudSportDirt,
+};
+
+const struct SpriteTemplate gDirtPlumeSpriteTemplate =
+{
+ .tileTag = ANIM_TAG_MUD_SAND,
+ .paletteTag = ANIM_TAG_MUD_SAND,
+ .oam = &gOamData_AffineOff_ObjNormal_8x8,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = AnimDirtPlumeParticle,
+};
+
+const struct SpriteTemplate gDirtMoundSpriteTemplate =
+{
+ .tileTag = ANIM_TAG_DIRT_MOUND,
+ .paletteTag = ANIM_TAG_DIRT_MOUND,
+ .oam = &gOamData_AffineOff_ObjNormal_32x16,
+ .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 = AnimBonemerangProjectile_Step;
+}
+
+static void AnimBonemerangProjectile_Step(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 = AnimBonemerangProjectile_End;
+ }
+}
+
+static void AnimBonemerangProjectile_End(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 = Random2() & 0x1F;
+ yOffset = Random2() & 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 AnimTask_DigDownMovement(u8 taskId)
+{
+ struct Task *task = &gTasks[taskId];
+
+ if (gBattleAnimArgs[0] == FALSE)
+ task->func = AnimTask_DigBounceMovement;
+ else
+ task->func = AnimTask_DigEndBounceMovementSetInvisible;
+
+ task->func(taskId);
+}
+
+static void AnimTask_DigBounceMovement(u8 taskId)
+{
+ u8 var0;
+ struct Task *task = &gTasks[taskId];
+
+ switch (task->data[0])
+ {
+ case 0:
+ task->data[10] = GetAnimBattlerSpriteId(ANIM_ATTACKER);
+ 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_81150E0(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 AnimTask_DigEndBounceMovementSetInvisible(u8 taskId)
+{
+ u8 spriteId = GetAnimBattlerSpriteId(ANIM_ATTACKER);
+ 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 AnimTask_DigUpMovement(u8 taskId)
+{
+ struct Task *task = &gTasks[taskId];
+
+ if (gBattleAnimArgs[0] == FALSE)
+ task->func = AnimTask_DigSetVisibleUnderground;
+ else
+ task->func = AnimTask_DigRiseUpFromHole;
+
+ task->func(taskId);
+}
+
+static void AnimTask_DigSetVisibleUnderground(u8 taskId)
+{
+ struct Task *task = &gTasks[taskId];
+
+ switch (task->data[0])
+ {
+ case 0:
+ task->data[10] = GetAnimBattlerSpriteId(ANIM_ATTACKER);
+ 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 AnimTask_DigRiseUpFromHole(u8 taskId)
+{
+ u8 var0;
+ struct Task *task = &gTasks[taskId];
+
+ switch (task->data[0])
+ {
+ case 0:
+ task->data[10] = GetAnimBattlerSpriteId(ANIM_ATTACKER);
+ 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_81150E0(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_81150E0(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
+void AnimDirtPlumeParticle(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 = AnimDirtPlumeParticle_Step;
+}
+
+static void AnimDirtPlumeParticle_Step(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;
+}
+
+
+#define tState data[0]
+#define tDelay data[1]
+#define tTimer data[2]
+#define tMaxTime data[3]
+#define tbattlerSpriteIds(i) data[9 + (i)]
+#define tNumBattlers data[13] // AnimTask_ShakeBattlers
+#define tInitialX data[13] // AnimTask_ShakeTerrain
+#define tHorizOffset data[14]
+#define tInitHorizOffset data[15]
+
+// Shakes battler(s) or the battle terrain back and forth horizontally. Used by e.g. Earthquake, Eruption
+// arg0: What to shake. 0-3 for any specific battler, MAX_BATTLERS_COUNT for all battlers, MAX_BATTLERS_COUNT + 1 for the terrain
+// arg1: Shake intensity, used to calculate horizontal pixel offset (if 0, use move power instead)
+// arg2: Length of time to shake for
+void AnimTask_HorizontalShake(u8 taskId)
+{
+ u16 i;
+ struct Task *task = &gTasks[taskId];
+
+ if (gBattleAnimArgs[1] != 0)
+ task->tHorizOffset = task->tInitHorizOffset = gBattleAnimArgs[1] + 3;
+ else
+ task->tHorizOffset = task->tInitHorizOffset = (gAnimMovePower / 10) + 3;
+
+ task->tMaxTime = gBattleAnimArgs[2];
+ switch (gBattleAnimArgs[0])
+ {
+ case MAX_BATTLERS_COUNT + 1: // Shake terrain
+ task->tInitialX = gBattle_BG3_X;
+ task->func = AnimTask_ShakeTerrain;
+ break;
+ case MAX_BATTLERS_COUNT: // Shake all battlers
+ task->tNumBattlers = 0;
+ for (i = 0; i < MAX_BATTLERS_COUNT; i++)
+ {
+ if (IsBattlerSpriteVisible(i))
+ {
+ task->tbattlerSpriteIds(task->tNumBattlers) = gBattlerSpriteIds[i];
+ task->tNumBattlers++;
+ }
+ }
+ task->func = AnimTask_ShakeBattlers;
+ break;
+ default: // Shake specific battler
+ task->tbattlerSpriteIds(0) = GetAnimBattlerSpriteId(gBattleAnimArgs[0]);
+ if (task->tbattlerSpriteIds(0) == 0xFF)
+ {
+ DestroyAnimVisualTask(taskId);
+ }
+ else
+ {
+ task->tNumBattlers = 1;
+ task->func = AnimTask_ShakeBattlers;
+ }
+ break;
+ }
+}
+
+static void AnimTask_ShakeTerrain(u8 taskId)
+{
+ struct Task *task = &gTasks[taskId];
+
+ switch (task->tState)
+ {
+ case 0:
+ if (++task->tDelay > 1)
+ {
+ task->tDelay = 0;
+ if ((task->tTimer & 1) == 0)
+ gBattle_BG3_X = task->tInitialX + task->tInitHorizOffset;
+ else
+ gBattle_BG3_X = task->tInitialX - task->tInitHorizOffset;
+
+ if (++task->tTimer == task->tMaxTime)
+ {
+ task->tTimer = 0;
+ task->tHorizOffset--;
+ task->tState++;
+ }
+ }
+ break;
+ case 1:
+ if (++task->tDelay > 1)
+ {
+ task->tDelay = 0;
+ if ((task->tTimer & 1) == 0)
+ gBattle_BG3_X = task->tInitialX + task->tHorizOffset;
+ else
+ gBattle_BG3_X = task->tInitialX - task->tHorizOffset;
+
+ if (++task->tTimer == 4)
+ {
+ task->tTimer = 0;
+ if (--task->tHorizOffset == 0)
+ task->tState++;
+ }
+ }
+ break;
+ case 2:
+ gBattle_BG3_X = task->tInitialX;
+ DestroyAnimVisualTask(taskId);
+ break;
+ }
+}
+
+static void AnimTask_ShakeBattlers(u8 taskId)
+{
+ u16 i;
+ struct Task *task = &gTasks[taskId];
+
+ switch (task->tState)
+ {
+ case 0:
+ if (++task->tDelay > 1)
+ {
+ task->tDelay = 0;
+ SetBattlersXOffsetForShake(task);
+ if (++task->tTimer == task->tMaxTime)
+ {
+ task->tTimer = 0;
+ task->tHorizOffset--;
+ task->tState++;
+ }
+ }
+ break;
+ case 1:
+ if (++task->tDelay > 1)
+ {
+ task->tDelay = 0;
+ SetBattlersXOffsetForShake(task);
+ if (++task->tTimer == 4)
+ {
+ task->tTimer = 0;
+ if (--task->tHorizOffset == 0)
+ task->tState++;
+ }
+ }
+ break;
+ case 2:
+ for (i = 0; i < task->tNumBattlers; i++)
+ gSprites[task->tbattlerSpriteIds(i)].pos2.x = 0;
+
+ DestroyAnimVisualTask(taskId);
+ break;
+ }
+}
+
+static void SetBattlersXOffsetForShake(struct Task *task)
+{
+ u16 i;
+ u16 xOffset;
+
+ if ((task->tTimer & 1) == 0)
+ xOffset = (task->tHorizOffset / 2) + (task->tHorizOffset & 1);
+ else
+ xOffset = -(task->tHorizOffset / 2);
+
+ for (i = 0; i < task->tNumBattlers; i++)
+ {
+ gSprites[task->tbattlerSpriteIds(i)].pos2.x = xOffset;
+ }
+}
+
+#undef tState
+#undef tDelay
+#undef tTimer
+#undef tMaxTime
+#undef tbattlerSpriteIds
+#undef tNumBattlers
+#undef tInitialX
+#undef tHorizOffset
+#undef tInitHorizOffset
+
+void AnimTask_IsPowerOver99(u8 taskId)
+{
+ gBattleAnimArgs[15] = gAnimMovePower > 99;
+ DestroyAnimVisualTask(taskId);
+}
+
+void AnimTask_PositionFissureBgOnBattler(u8 taskId)
+{
+ struct Task *newTask;
+ u8 battler = (gBattleAnimArgs[0] & ANIM_TARGET) ? gBattleAnimTarget : gBattleAnimAttacker;
+
+ if (gBattleAnimArgs[0] > ANIM_TARGET)
+ battler ^= 2;
+
+ newTask = &gTasks[CreateTask(sub_81156D0, 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_81156D0(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];
+ }
+}