#include "global.h"
#include "battle.h"
#include "palette.h"
#include "pokemon.h"
#include "pokemon_animation.h"
#include "sprite.h"
#include "task.h"
#include "trig.h"
#include "util.h"
#include "data.h"
#include "constants/battle_anim.h"
#include "constants/rgb.h"

/*
    This file handles the movements of the Pokémon intro animations.

    Each animation type is identified by an ANIM_* constant that
    refers to a sprite callback to start the animation. These functions
    are named Anim_<name> or Anim_<name>_<variant>. Many of these
    functions share additional movement functions to do a variation of the
    same movement (e.g. a faster or larger movement).
    Vertical and Horizontal are frequently shortened to V and H.

    Every front animation uses 1 of these ANIMs, and every back animation
    uses a BACK_ANIM_* that refers to a set of 3 ANIM functions. Which of the
    3 that gets used depends on the Pokémon's nature (see sBackAnimationIds).

    The table linking species to a BACK_ANIM is in this file (sSpeciesToBackAnimSet)
    while the table linking species to an ANIM for their front animation is in
    pokemon.c (sMonFrontAnimIdsTable).

    These are the functions that will start an animation:
    - LaunchAnimationTaskForFrontSprite
    - LaunchAnimationTaskForBackSprite
    - StartMonSummaryAnimation
*/

#define sDontFlip data[1]  // TRUE if a normal animation, FALSE if Summary Screen animation

struct PokemonAnimData
{
    u16 delay;
    s16 speed; // Only used by 2 sets of animations
    s16 runs; // Number of times to do the animation
    s16 rotation;
    s16 data; // General use
};

struct YellowFlashData
{
    bool8 isYellow;
    u8 time;
};

static void Anim_VerticalSquishBounce(struct Sprite *sprite);
static void Anim_CircularStretchTwice(struct Sprite *sprite);
static void Anim_HorizontalVibrate(struct Sprite *sprite);
static void Anim_HorizontalSlide(struct Sprite *sprite);
static void Anim_VerticalSlide(struct Sprite *sprite);
static void Anim_BounceRotateToSides(struct Sprite *sprite);
static void Anim_VerticalJumpsHorizontalJumps(struct Sprite *sprite);
static void Anim_RotateToSides(struct Sprite *sprite);
static void Anim_RotateToSides_Twice(struct Sprite *sprite);
static void Anim_GrowVibrate(struct Sprite *sprite);
static void Anim_ZigzagFast(struct Sprite *sprite);
static void Anim_SwingConcave(struct Sprite *sprite);
static void Anim_SwingConcave_Fast(struct Sprite *sprite);
static void Anim_SwingConvex(struct Sprite *sprite);
static void Anim_SwingConvex_Fast(struct Sprite *sprite);
static void Anim_HorizontalShake(struct Sprite *sprite);
static void Anim_VerticalShake(struct Sprite *sprite);
static void Anim_CircularVibrate(struct Sprite *sprite);
static void Anim_Twist(struct Sprite *sprite);
static void Anim_ShrinkGrow(struct Sprite *sprite);
static void Anim_CircleCounterclockwise(struct Sprite *sprite);
static void Anim_GlowBlack(struct Sprite *sprite);
static void Anim_HorizontalStretch(struct Sprite *sprite);
static void Anim_VerticalStretch(struct Sprite *sprite);
static void Anim_RisingWobble(struct Sprite *sprite);
static void Anim_VerticalShakeTwice(struct Sprite *sprite);
static void Anim_TipMoveForward(struct Sprite *sprite);
static void Anim_HorizontalPivot(struct Sprite *sprite);
static void Anim_VerticalSlideWobble(struct Sprite *sprite);
static void Anim_HorizontalSlideWobble(struct Sprite *sprite);
static void Anim_VerticalJumps_Big(struct Sprite *sprite);
static void Anim_Spin_Long(struct Sprite *sprite);
static void Anim_GlowOrange(struct Sprite *sprite);
static void Anim_GlowRed(struct Sprite *sprite);
static void Anim_GlowBlue(struct Sprite *sprite);
static void Anim_GlowYellow(struct Sprite *sprite);
static void Anim_GlowPurple(struct Sprite *sprite);
static void Anim_BackAndLunge(struct Sprite *sprite);
static void Anim_BackFlip(struct Sprite *sprite);
static void Anim_Flicker(struct Sprite *sprite);
static void Anim_BackFlipBig(struct Sprite *sprite);
static void Anim_FrontFlip(struct Sprite *sprite);
static void Anim_TumblingFrontFlip(struct Sprite *sprite);
static void Anim_Figure8(struct Sprite *sprite);
static void Anim_FlashYellow(struct Sprite *sprite);
static void Anim_SwingConcave_FastShort(struct Sprite *sprite);
static void Anim_SwingConvex_FastShort(struct Sprite *sprite);
static void Anim_RotateUpSlamDown(struct Sprite *sprite);
static void Anim_DeepVerticalSquishBounce(struct Sprite *sprite);
static void Anim_HorizontalJumps(struct Sprite *sprite);
static void Anim_HorizontalJumpsVerticalStretch(struct Sprite *sprite);
static void Anim_RotateToSides_Fast(struct Sprite *sprite);
static void Anim_RotateUpToSides(struct Sprite *sprite);
static void Anim_FlickerIncreasing(struct Sprite *sprite);
static void Anim_TipHopForward(struct Sprite *sprite);
static void Anim_PivotShake(struct Sprite *sprite);
static void Anim_TipAndShake(struct Sprite *sprite);
static void Anim_VibrateToCorners(struct Sprite *sprite);
static void Anim_GrowInStages(struct Sprite *sprite);
static void Anim_VerticalSpring(struct Sprite *sprite);
static void Anim_VerticalRepeatedSpring(struct Sprite *sprite);
static void Anim_SpringRising(struct Sprite *sprite);
static void Anim_HorizontalSpring(struct Sprite *sprite);
static void Anim_HorizontalRepeatedSpring_Slow(struct Sprite *sprite);
static void Anim_HorizontalSlideShrink(struct Sprite *sprite);
static void Anim_LungeGrow(struct Sprite *sprite);
static void Anim_CircleIntoBackground(struct Sprite *sprite);
static void Anim_RapidHorizontalHops(struct Sprite *sprite);
static void Anim_FourPetal(struct Sprite *sprite);
static void Anim_VerticalSquishBounce_Slow(struct Sprite *sprite);
static void Anim_HorizontalSlide_Slow(struct Sprite *sprite);
static void Anim_VerticalSlide_Slow(struct Sprite *sprite);
static void Anim_BounceRotateToSides_Small(struct Sprite *sprite);
static void Anim_BounceRotateToSides_Slow(struct Sprite *sprite);
static void Anim_BounceRotateToSides_SmallSlow(struct Sprite *sprite);
static void Anim_ZigzagSlow(struct Sprite *sprite);
static void Anim_HorizontalShake_Slow(struct Sprite *sprite);
static void Anim_VertialShake_Slow(struct Sprite *sprite);
static void Anim_Twist_Twice(struct Sprite *sprite);
static void Anim_CircleCounterclockwise_Slow(struct Sprite *sprite);
static void Anim_VerticalShakeTwice_Slow(struct Sprite *sprite);
static void Anim_VerticalSlideWobble_Small(struct Sprite *sprite);
static void Anim_VerticalJumps_Small(struct Sprite *sprite);
static void Anim_Spin(struct Sprite *sprite);
static void Anim_TumblingFrontFlip_Twice(struct Sprite *sprite);
static void Anim_DeepVerticalSquishBounce_Twice(struct Sprite *sprite);
static void Anim_HorizontalJumpsVerticalStretch_Twice(struct Sprite *sprite);
static void Anim_VerticalShakeBack(struct Sprite *sprite);
static void Anim_VerticalShakeBack_Slow(struct Sprite *sprite);
static void Anim_VerticalShakeHorizontalSlide_Slow(struct Sprite *sprite);
static void Anim_VerticalStretchBothEnds_Slow(struct Sprite *sprite);
static void Anim_HorizontalStretchFar_Slow(struct Sprite *sprite);
static void Anim_VerticalShakeLowTwice(struct Sprite *sprite);
static void Anim_HorizontalShake_Fast(struct Sprite *sprite);
static void Anim_HorizontalSlide_Fast(struct Sprite *sprite);
static void Anim_HorizontalVibrate_Fast(struct Sprite *sprite);
static void Anim_HorizontalVibrate_Fastest(struct Sprite *sprite);
static void Anim_VerticalShakeBack_Fast(struct Sprite *sprite);
static void Anim_VerticalShakeLowTwice_Slow(struct Sprite *sprite);
static void Anim_VerticalShakeLowTwice_Fast(struct Sprite *sprite);
static void Anim_CircleCounterclockwise_Long(struct Sprite *sprite);
static void Anim_GrowStutter_Slow(struct Sprite *sprite);
static void Anim_VerticalShakeHorizontalSlide(struct Sprite *sprite);
static void Anim_VerticalShakeHorizontalSlide_Fast(struct Sprite *sprite);
static void Anim_TriangleDown_Slow(struct Sprite *sprite);
static void Anim_TriangleDown(struct Sprite *sprite);
static void Anim_TriangleDown_Fast(struct Sprite *sprite);
static void Anim_Grow(struct Sprite *sprite);
static void Anim_Grow_Twice(struct Sprite *sprite);
static void Anim_HorizontalSpring_Fast(struct Sprite *sprite);
static void Anim_HorizontalSpring_Slow(struct Sprite *sprite);
static void Anim_HorizontalRepeatedSpring_Fast(struct Sprite *sprite);
static void Anim_HorizontalRepeatedSpring(struct Sprite *sprite);
static void Anim_ShrinkGrow_Fast(struct Sprite *sprite);
static void Anim_ShrinkGrow_Slow(struct Sprite *sprite);
static void Anim_VerticalStretchBothEnds(struct Sprite *sprite);
static void Anim_VerticalStretchBothEnds_Twice(struct Sprite *sprite);
static void Anim_HorizontalStretchFar_Twice(struct Sprite *sprite);
static void Anim_HorizontalStretchFar(struct Sprite *sprite);
static void Anim_GrowStutter_Twice(struct Sprite *sprite);
static void Anim_GrowStutter(struct Sprite *sprite);
static void Anim_ConcaveArcLarge_Slow(struct Sprite *sprite);
static void Anim_ConcaveArcLarge(struct Sprite *sprite);
static void Anim_ConcaveArcLarge_Twice(struct Sprite *sprite);
static void Anim_ConvexDoubleArc_Slow(struct Sprite *sprite);
static void Anim_ConvexDoubleArc(struct Sprite *sprite);
static void Anim_ConvexDoubleArc_Twice(struct Sprite *sprite);
static void Anim_ConcaveArcSmall_Slow(struct Sprite *sprite);
static void Anim_ConcaveArcSmall(struct Sprite *sprite);
static void Anim_ConcaveArcSmall_Twice(struct Sprite *sprite);
static void Anim_HorizontalDip(struct Sprite *sprite);
static void Anim_HorizontalDip_Fast(struct Sprite *sprite);
static void Anim_HorizontalDip_Twice(struct Sprite *sprite);
static void Anim_ShrinkGrowVibrate_Fast(struct Sprite *sprite);
static void Anim_ShrinkGrowVibrate(struct Sprite *sprite);
static void Anim_ShrinkGrowVibrate_Slow(struct Sprite *sprite);
static void Anim_JoltRight_Fast(struct Sprite *sprite);
static void Anim_JoltRight(struct Sprite *sprite);
static void Anim_JoltRight_Slow(struct Sprite *sprite);
static void Anim_ShakeFlashYellow_Fast(struct Sprite *sprite);
static void Anim_ShakeFlashYellow(struct Sprite *sprite);
static void Anim_ShakeFlashYellow_Slow(struct Sprite *sprite);
static void Anim_ShakeGlowRed_Fast(struct Sprite *sprite);
static void Anim_ShakeGlowRed(struct Sprite *sprite);
static void Anim_ShakeGlowRed_Slow(struct Sprite *sprite);
static void Anim_ShakeGlowGreen_Fast(struct Sprite *sprite);
static void Anim_ShakeGlowGreen(struct Sprite *sprite);
static void Anim_ShakeGlowGreen_Slow(struct Sprite *sprite);
static void Anim_ShakeGlowBlue_Fast(struct Sprite *sprite);
static void Anim_ShakeGlowBlue(struct Sprite *sprite);
static void Anim_ShakeGlowBlue_Slow(struct Sprite *sprite);

static void WaitAnimEnd(struct Sprite *sprite);

static struct PokemonAnimData sAnims[MAX_BATTLERS_COUNT];
static u8 sAnimIdx;
static bool32 sIsSummaryAnim;

static const u8 sSpeciesToBackAnimSet[] =
{
    [SPECIES_BULBASAUR]  = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_IVYSAUR]    = BACK_ANIM_H_SLIDE,
    [SPECIES_VENUSAUR]   = BACK_ANIM_H_SHAKE,
    [SPECIES_CHARMANDER] = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_CHARMELEON] = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_CHARIZARD]  = BACK_ANIM_SHAKE_GLOW_RED,
    [SPECIES_SQUIRTLE]   = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_WARTORTLE]  = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_BLASTOISE]  = BACK_ANIM_SHAKE_GLOW_BLUE,
    [SPECIES_CATERPIE]   = BACK_ANIM_H_SLIDE,
    [SPECIES_METAPOD]    = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_BUTTERFREE] = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_WEEDLE]     = BACK_ANIM_H_SLIDE,
    [SPECIES_KAKUNA]     = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_BEEDRILL]   = BACK_ANIM_H_VIBRATE,
    [SPECIES_PIDGEY]     = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_PIDGEOTTO]  = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_PIDGEOT]    = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_RATTATA]    = BACK_ANIM_V_SHAKE_H_SLIDE,
    [SPECIES_RATICATE]   = BACK_ANIM_V_SHAKE_H_SLIDE,
    [SPECIES_SPEAROW]    = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_FEAROW]     = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_EKANS]      = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_ARBOK]      = BACK_ANIM_V_SHAKE,
    [SPECIES_PIKACHU]    = BACK_ANIM_SHAKE_FLASH_YELLOW,
    [SPECIES_RAICHU]     = BACK_ANIM_SHAKE_FLASH_YELLOW,
    [SPECIES_SANDSHREW]  = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_SANDSLASH]  = BACK_ANIM_CONCAVE_ARC_LARGE,
    [SPECIES_NIDORAN_F]  = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_NIDORINA]   = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_NIDOQUEEN]  = BACK_ANIM_V_SHAKE,
    [SPECIES_NIDORAN_M]  = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_NIDORINO]   = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_NIDOKING]   = BACK_ANIM_V_SHAKE,
    [SPECIES_CLEFAIRY]   = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_CLEFABLE]   = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_VULPIX]     = BACK_ANIM_CONCAVE_ARC_LARGE,
    [SPECIES_NINETALES]  = BACK_ANIM_H_VIBRATE,
    [SPECIES_JIGGLYPUFF] = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_WIGGLYTUFF] = BACK_ANIM_GROW,
    [SPECIES_ZUBAT]      = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_GOLBAT]     = BACK_ANIM_V_SHAKE,
    [SPECIES_ODDISH]     = BACK_ANIM_H_SLIDE,
    [SPECIES_GLOOM]      = BACK_ANIM_H_SLIDE,
    [SPECIES_VILEPLUME]  = BACK_ANIM_SHRINK_GROW_VIBRATE,
    [SPECIES_PARAS]      = BACK_ANIM_H_SLIDE,
    [SPECIES_PARASECT]   = BACK_ANIM_H_SHAKE,
    [SPECIES_VENONAT]    = BACK_ANIM_V_SHAKE_H_SLIDE,
    [SPECIES_VENOMOTH]   = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_DIGLETT]    = BACK_ANIM_V_SHAKE,
    [SPECIES_DUGTRIO]    = BACK_ANIM_V_SHAKE,
    [SPECIES_MEOWTH]     = BACK_ANIM_CONCAVE_ARC_LARGE,
    [SPECIES_PERSIAN]    = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_PSYDUCK]    = BACK_ANIM_H_SLIDE,
    [SPECIES_GOLDUCK]    = BACK_ANIM_SHRINK_GROW_VIBRATE,
    [SPECIES_MANKEY]     = BACK_ANIM_CONCAVE_ARC_LARGE,
    [SPECIES_PRIMEAPE]   = BACK_ANIM_CONCAVE_ARC_LARGE,
    [SPECIES_GROWLITHE]  = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_ARCANINE]   = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_POLIWAG]    = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_POLIWHIRL]  = BACK_ANIM_V_SHAKE,
    [SPECIES_POLIWRATH]  = BACK_ANIM_V_SHAKE_LOW,
    [SPECIES_ABRA]       = BACK_ANIM_SHRINK_GROW_VIBRATE,
    [SPECIES_KADABRA]    = BACK_ANIM_SHRINK_GROW_VIBRATE,
    [SPECIES_ALAKAZAM]   = BACK_ANIM_GROW_STUTTER,
    [SPECIES_MACHOP]     = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_MACHOKE]    = BACK_ANIM_V_SHAKE,
    [SPECIES_MACHAMP]    = BACK_ANIM_V_SHAKE,
    [SPECIES_BELLSPROUT] = BACK_ANIM_V_STRETCH,
    [SPECIES_WEEPINBELL] = BACK_ANIM_V_STRETCH,
    [SPECIES_VICTREEBEL] = BACK_ANIM_V_STRETCH,
    [SPECIES_TENTACOOL]  = BACK_ANIM_H_SLIDE,
    [SPECIES_TENTACRUEL] = BACK_ANIM_H_SLIDE,
    [SPECIES_GEODUDE]    = BACK_ANIM_V_SHAKE_LOW,
    [SPECIES_GRAVELER]   = BACK_ANIM_H_SHAKE,
    [SPECIES_GOLEM]      = BACK_ANIM_H_SHAKE,
    [SPECIES_PONYTA]     = BACK_ANIM_SHAKE_GLOW_RED,
    [SPECIES_RAPIDASH]   = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_SLOWPOKE]   = BACK_ANIM_H_SLIDE,
    [SPECIES_SLOWBRO]    = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_MAGNEMITE]  = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_MAGNETON]   = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_FARFETCHD]  = BACK_ANIM_H_SLIDE,
    [SPECIES_DODUO]      = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_DODRIO]     = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_SEEL]       = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_DEWGONG]    = BACK_ANIM_H_SLIDE,
    [SPECIES_GRIMER]     = BACK_ANIM_V_STRETCH,
    [SPECIES_MUK]        = BACK_ANIM_H_STRETCH,
    [SPECIES_SHELLDER]   = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_CLOYSTER]   = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_GASTLY]     = BACK_ANIM_H_VIBRATE,
    [SPECIES_HAUNTER]    = BACK_ANIM_H_VIBRATE,
    [SPECIES_GENGAR]     = BACK_ANIM_SHRINK_GROW_VIBRATE,
    [SPECIES_ONIX]       = BACK_ANIM_V_SHAKE,
    [SPECIES_DROWZEE]    = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_HYPNO]      = BACK_ANIM_SHRINK_GROW_VIBRATE,
    [SPECIES_KRABBY]     = BACK_ANIM_V_SHAKE_H_SLIDE,
    [SPECIES_KINGLER]    = BACK_ANIM_V_SHAKE,
    [SPECIES_VOLTORB]    = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_ELECTRODE]  = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_EXEGGCUTE]  = BACK_ANIM_H_SLIDE,
    [SPECIES_EXEGGUTOR]  = BACK_ANIM_CONCAVE_ARC_LARGE,
    [SPECIES_CUBONE]     = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_MAROWAK]    = BACK_ANIM_CONCAVE_ARC_LARGE,
    [SPECIES_HITMONLEE]  = BACK_ANIM_H_SLIDE,
    [SPECIES_HITMONCHAN] = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_LICKITUNG]  = BACK_ANIM_H_SLIDE,
    [SPECIES_KOFFING]    = BACK_ANIM_GROW,
    [SPECIES_WEEZING]    = BACK_ANIM_GROW,
    [SPECIES_RHYHORN]    = BACK_ANIM_V_SHAKE_LOW,
    [SPECIES_RHYDON]     = BACK_ANIM_V_SHAKE_LOW,
    [SPECIES_CHANSEY]    = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_TANGELA]    = BACK_ANIM_V_STRETCH,
    [SPECIES_KANGASKHAN] = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_HORSEA]     = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_SEADRA]     = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_GOLDEEN]    = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_SEAKING]    = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_STARYU]     = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_STARMIE]    = BACK_ANIM_SHAKE_GLOW_BLUE,
    [SPECIES_MR_MIME]    = BACK_ANIM_SHRINK_GROW_VIBRATE,
    [SPECIES_SCYTHER]    = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_JYNX]       = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_ELECTABUZZ] = BACK_ANIM_SHAKE_FLASH_YELLOW,
    [SPECIES_MAGMAR]     = BACK_ANIM_SHAKE_GLOW_RED,
    [SPECIES_PINSIR]     = BACK_ANIM_V_SHAKE_LOW,
    [SPECIES_TAUROS]     = BACK_ANIM_V_SHAKE_LOW,
    [SPECIES_MAGIKARP]   = BACK_ANIM_CONCAVE_ARC_LARGE,
    [SPECIES_GYARADOS]   = BACK_ANIM_V_SHAKE,
    [SPECIES_LAPRAS]     = BACK_ANIM_SHAKE_GLOW_BLUE,
    [SPECIES_DITTO]      = BACK_ANIM_SHRINK_GROW,
    [SPECIES_EEVEE]      = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_VAPOREON]   = BACK_ANIM_SHAKE_GLOW_BLUE,
    [SPECIES_JOLTEON]    = BACK_ANIM_SHAKE_FLASH_YELLOW,
    [SPECIES_FLAREON]    = BACK_ANIM_SHAKE_GLOW_RED,
    [SPECIES_PORYGON]    = BACK_ANIM_H_VIBRATE,
    [SPECIES_OMANYTE]    = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_OMASTAR]    = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_KABUTO]     = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_KABUTOPS]   = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_AERODACTYL] = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_SNORLAX]    = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_ARTICUNO]   = BACK_ANIM_SHAKE_GLOW_BLUE,
    [SPECIES_ZAPDOS]     = BACK_ANIM_SHAKE_FLASH_YELLOW,
    [SPECIES_MOLTRES]    = BACK_ANIM_SHAKE_GLOW_RED,
    [SPECIES_DRATINI]    = BACK_ANIM_H_SLIDE,
    [SPECIES_DRAGONAIR]  = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_DRAGONITE]  = BACK_ANIM_V_SHAKE,
    [SPECIES_MEWTWO]     = BACK_ANIM_GROW_STUTTER,
    [SPECIES_MEW]        = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_CHIKORITA]  = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_BAYLEEF]    = BACK_ANIM_H_SLIDE,
    [SPECIES_MEGANIUM]   = BACK_ANIM_V_SHAKE,
    [SPECIES_CYNDAQUIL]  = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_QUILAVA]    = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_TYPHLOSION] = BACK_ANIM_SHAKE_GLOW_RED,
    [SPECIES_TOTODILE]   = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_CROCONAW]   = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_FERALIGATR] = BACK_ANIM_V_SHAKE,
    [SPECIES_SENTRET]    = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_FURRET]     = BACK_ANIM_CONCAVE_ARC_LARGE,
    [SPECIES_HOOTHOOT]   = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_NOCTOWL]    = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_LEDYBA]     = BACK_ANIM_V_SHAKE_H_SLIDE,
    [SPECIES_LEDIAN]     = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_SPINARAK]   = BACK_ANIM_V_SHAKE_H_SLIDE,
    [SPECIES_ARIADOS]    = BACK_ANIM_H_SLIDE,
    [SPECIES_CROBAT]     = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_CHINCHOU]   = BACK_ANIM_V_STRETCH,
    [SPECIES_LANTURN]    = BACK_ANIM_SHAKE_FLASH_YELLOW,
    [SPECIES_PICHU]      = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_CLEFFA]     = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_IGGLYBUFF]  = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_TOGEPI]     = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_TOGETIC]    = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_NATU]       = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_XATU]       = BACK_ANIM_SHRINK_GROW_VIBRATE,
    [SPECIES_MAREEP]     = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_FLAAFFY]    = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_AMPHAROS]   = BACK_ANIM_SHAKE_FLASH_YELLOW,
    [SPECIES_BELLOSSOM]  = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_MARILL]     = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_AZUMARILL]  = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_SUDOWOODO]  = BACK_ANIM_H_SLIDE,
    [SPECIES_POLITOED]   = BACK_ANIM_CONCAVE_ARC_LARGE,
    [SPECIES_HOPPIP]     = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_SKIPLOOM]   = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_JUMPLUFF]   = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_AIPOM]      = BACK_ANIM_CONCAVE_ARC_LARGE,
    [SPECIES_SUNKERN]    = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_SUNFLORA]   = BACK_ANIM_H_SLIDE,
    [SPECIES_YANMA]      = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_WOOPER]     = BACK_ANIM_V_STRETCH,
    [SPECIES_QUAGSIRE]   = BACK_ANIM_H_SLIDE,
    [SPECIES_ESPEON]     = BACK_ANIM_SHRINK_GROW_VIBRATE,
    [SPECIES_UMBREON]    = BACK_ANIM_SHRINK_GROW_VIBRATE,
    [SPECIES_MURKROW]    = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_SLOWKING]   = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_MISDREAVUS] = BACK_ANIM_H_VIBRATE,
    [SPECIES_UNOWN]      = BACK_ANIM_SHRINK_GROW_VIBRATE,
    [SPECIES_WOBBUFFET]  = BACK_ANIM_V_STRETCH,
    [SPECIES_GIRAFARIG]  = BACK_ANIM_SHRINK_GROW_VIBRATE,
    [SPECIES_PINECO]     = BACK_ANIM_H_SHAKE,
    [SPECIES_FORRETRESS] = BACK_ANIM_V_SHAKE,
    [SPECIES_DUNSPARCE]  = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_GLIGAR]     = BACK_ANIM_SHRINK_GROW,
    [SPECIES_STEELIX]    = BACK_ANIM_V_SHAKE,
    [SPECIES_SNUBBULL]   = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_GRANBULL]   = BACK_ANIM_V_SHAKE,
    [SPECIES_QWILFISH]   = BACK_ANIM_GROW_STUTTER,
    [SPECIES_SCIZOR]     = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_SHUCKLE]    = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_HERACROSS]  = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_SNEASEL]    = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_TEDDIURSA]  = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_URSARING]   = BACK_ANIM_V_SHAKE,
    [SPECIES_SLUGMA]     = BACK_ANIM_SHAKE_GLOW_RED,
    [SPECIES_MAGCARGO]   = BACK_ANIM_SHAKE_GLOW_RED,
    [SPECIES_SWINUB]     = BACK_ANIM_V_SHAKE_H_SLIDE,
    [SPECIES_PILOSWINE]  = BACK_ANIM_H_SHAKE,
    [SPECIES_CORSOLA]    = BACK_ANIM_H_SLIDE,
    [SPECIES_REMORAID]   = BACK_ANIM_H_SLIDE,
    [SPECIES_OCTILLERY]  = BACK_ANIM_SHRINK_GROW,
    [SPECIES_DELIBIRD]   = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_MANTINE]    = BACK_ANIM_H_SLIDE,
    [SPECIES_SKARMORY]   = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_HOUNDOUR]   = BACK_ANIM_V_SHAKE,
    [SPECIES_HOUNDOOM]   = BACK_ANIM_V_SHAKE,
    [SPECIES_KINGDRA]    = BACK_ANIM_SHAKE_GLOW_BLUE,
    [SPECIES_PHANPY]     = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_DONPHAN]    = BACK_ANIM_V_SHAKE_LOW,
    [SPECIES_PORYGON2]   = BACK_ANIM_H_VIBRATE,
    [SPECIES_STANTLER]   = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_SMEARGLE]   = BACK_ANIM_H_SLIDE,
    [SPECIES_TYROGUE]    = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_HITMONTOP]  = BACK_ANIM_CIRCLE_COUNTERCLOCKWISE,
    [SPECIES_SMOOCHUM]   = BACK_ANIM_H_SLIDE,
    [SPECIES_ELEKID]     = BACK_ANIM_H_SHAKE,
    [SPECIES_MAGBY]      = BACK_ANIM_SHAKE_GLOW_RED,
    [SPECIES_MILTANK]    = BACK_ANIM_H_SLIDE,
    [SPECIES_BLISSEY]    = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_RAIKOU]     = BACK_ANIM_SHAKE_FLASH_YELLOW,
    [SPECIES_ENTEI]      = BACK_ANIM_SHAKE_GLOW_RED,
    [SPECIES_SUICUNE]    = BACK_ANIM_SHAKE_GLOW_BLUE,
    [SPECIES_LARVITAR]   = BACK_ANIM_V_SHAKE_LOW,
    [SPECIES_PUPITAR]    = BACK_ANIM_V_SHAKE,
    [SPECIES_TYRANITAR]  = BACK_ANIM_V_SHAKE_LOW,
    [SPECIES_LUGIA]      = BACK_ANIM_SHAKE_GLOW_BLUE,
    [SPECIES_HO_OH]      = BACK_ANIM_SHAKE_GLOW_RED,
    [SPECIES_CELEBI]     = BACK_ANIM_SHAKE_GLOW_GREEN,
    [SPECIES_TREECKO]    = BACK_ANIM_CONCAVE_ARC_LARGE,
    [SPECIES_GROVYLE]    = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_SCEPTILE]   = BACK_ANIM_V_SHAKE,
    [SPECIES_TORCHIC]    = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_COMBUSKEN]  = BACK_ANIM_CONCAVE_ARC_LARGE,
    [SPECIES_BLAZIKEN]   = BACK_ANIM_SHAKE_GLOW_RED,
    [SPECIES_MUDKIP]     = BACK_ANIM_H_SLIDE,
    [SPECIES_MARSHTOMP]  = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_SWAMPERT]   = BACK_ANIM_SHAKE_GLOW_BLUE,
    [SPECIES_POOCHYENA]  = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_MIGHTYENA]  = BACK_ANIM_H_SHAKE,
    [SPECIES_ZIGZAGOON]  = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_LINOONE]    = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_WURMPLE]    = BACK_ANIM_V_STRETCH,
    [SPECIES_SILCOON]    = BACK_ANIM_H_SHAKE,
    [SPECIES_BEAUTIFLY]  = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_CASCOON]    = BACK_ANIM_H_SHAKE,
    [SPECIES_DUSTOX]     = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_LOTAD]      = BACK_ANIM_H_SLIDE,
    [SPECIES_LOMBRE]     = BACK_ANIM_CONCAVE_ARC_LARGE,
    [SPECIES_LUDICOLO]   = BACK_ANIM_CONCAVE_ARC_LARGE,
    [SPECIES_SEEDOT]     = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_NUZLEAF]    = BACK_ANIM_V_SHAKE,
    [SPECIES_SHIFTRY]    = BACK_ANIM_SHRINK_GROW_VIBRATE,
    [SPECIES_NINCADA]    = BACK_ANIM_V_SHAKE_H_SLIDE,
    [SPECIES_NINJASK]    = BACK_ANIM_H_VIBRATE,
    [SPECIES_SHEDINJA]   = BACK_ANIM_SHRINK_GROW_VIBRATE,
    [SPECIES_TAILLOW]    = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_SWELLOW]    = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_SHROOMISH]  = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_BRELOOM]    = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_SPINDA]     = BACK_ANIM_CIRCLE_COUNTERCLOCKWISE,
    [SPECIES_WINGULL]    = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_PELIPPER]   = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_SURSKIT]    = BACK_ANIM_H_SPRING,
    [SPECIES_MASQUERAIN] = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_WAILMER]    = BACK_ANIM_SHAKE_GLOW_BLUE,
    [SPECIES_WAILORD]    = BACK_ANIM_SHAKE_GLOW_BLUE,
    [SPECIES_SKITTY]     = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_DELCATTY]   = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_KECLEON]    = BACK_ANIM_H_VIBRATE,
    [SPECIES_BALTOY]     = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_CLAYDOL]    = BACK_ANIM_SHRINK_GROW_VIBRATE,
    [SPECIES_NOSEPASS]   = BACK_ANIM_V_SHAKE_LOW,
    [SPECIES_TORKOAL]    = BACK_ANIM_SHAKE_GLOW_RED,
    [SPECIES_SABLEYE]    = BACK_ANIM_H_VIBRATE,
    [SPECIES_BARBOACH]   = BACK_ANIM_V_STRETCH,
    [SPECIES_WHISCASH]   = BACK_ANIM_V_SHAKE,
    [SPECIES_LUVDISC]    = BACK_ANIM_H_SPRING_REPEATED,
    [SPECIES_CORPHISH]   = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_CRAWDAUNT]  = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_FEEBAS]     = BACK_ANIM_H_SPRING,
    [SPECIES_MILOTIC]    = BACK_ANIM_SHAKE_GLOW_BLUE,
    [SPECIES_CARVANHA]   = BACK_ANIM_H_SPRING_REPEATED,
    [SPECIES_SHARPEDO]   = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_TRAPINCH]   = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_VIBRAVA]    = BACK_ANIM_H_VIBRATE,
    [SPECIES_FLYGON]     = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_MAKUHITA]   = BACK_ANIM_V_SHAKE_LOW,
    [SPECIES_HARIYAMA]   = BACK_ANIM_V_SHAKE_LOW,
    [SPECIES_ELECTRIKE]  = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_MANECTRIC]  = BACK_ANIM_V_SHAKE,
    [SPECIES_NUMEL]      = BACK_ANIM_V_SHAKE_LOW,
    [SPECIES_CAMERUPT]   = BACK_ANIM_SHAKE_GLOW_RED,
    [SPECIES_SPHEAL]     = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_SEALEO]     = BACK_ANIM_V_SHAKE,
    [SPECIES_WALREIN]    = BACK_ANIM_V_SHAKE,
    [SPECIES_CACNEA]     = BACK_ANIM_V_SHAKE_H_SLIDE,
    [SPECIES_CACTURNE]   = BACK_ANIM_H_SHAKE,
    [SPECIES_SNORUNT]    = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_GLALIE]     = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_LUNATONE]   = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_SOLROCK]    = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_AZURILL]    = BACK_ANIM_CONCAVE_ARC_LARGE,
    [SPECIES_SPOINK]     = BACK_ANIM_CONCAVE_ARC_LARGE,
    [SPECIES_GRUMPIG]    = BACK_ANIM_SHRINK_GROW_VIBRATE,
    [SPECIES_PLUSLE]     = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_MINUN]      = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_MAWILE]     = BACK_ANIM_V_SHAKE,
    [SPECIES_MEDITITE]   = BACK_ANIM_SHRINK_GROW_VIBRATE,
    [SPECIES_MEDICHAM]   = BACK_ANIM_SHRINK_GROW_VIBRATE,
    [SPECIES_SWABLU]     = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_ALTARIA]    = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_WYNAUT]     = BACK_ANIM_CONCAVE_ARC_SMALL,
    [SPECIES_DUSKULL]    = BACK_ANIM_H_VIBRATE,
    [SPECIES_DUSCLOPS]   = BACK_ANIM_H_VIBRATE,
    [SPECIES_ROSELIA]    = BACK_ANIM_SHAKE_GLOW_GREEN,
    [SPECIES_SLAKOTH]    = BACK_ANIM_H_SLIDE,
    [SPECIES_VIGOROTH]   = BACK_ANIM_CONCAVE_ARC_LARGE,
    [SPECIES_SLAKING]    = BACK_ANIM_H_SHAKE,
    [SPECIES_GULPIN]     = BACK_ANIM_V_STRETCH,
    [SPECIES_SWALOT]     = BACK_ANIM_V_STRETCH,
    [SPECIES_TROPIUS]    = BACK_ANIM_V_SHAKE_LOW,
    [SPECIES_WHISMUR]    = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_LOUDRED]    = BACK_ANIM_V_SHAKE,
    [SPECIES_EXPLOUD]    = BACK_ANIM_GROW_STUTTER,
    [SPECIES_CLAMPERL]   = BACK_ANIM_DIP_RIGHT_SIDE,
    [SPECIES_HUNTAIL]    = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_GOREBYSS]   = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_ABSOL]      = BACK_ANIM_SHRINK_GROW_VIBRATE,
    [SPECIES_SHUPPET]    = BACK_ANIM_H_VIBRATE,
    [SPECIES_BANETTE]    = BACK_ANIM_H_VIBRATE,
    [SPECIES_SEVIPER]    = BACK_ANIM_V_STRETCH,
    [SPECIES_ZANGOOSE]   = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_RELICANTH]  = BACK_ANIM_H_SLIDE,
    [SPECIES_ARON]       = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_LAIRON]     = BACK_ANIM_V_SHAKE,
    [SPECIES_AGGRON]     = BACK_ANIM_V_SHAKE_LOW,
    [SPECIES_CASTFORM]   = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_VOLBEAT]    = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_ILLUMISE]   = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_LILEEP]     = BACK_ANIM_H_STRETCH,
    [SPECIES_CRADILY]    = BACK_ANIM_V_STRETCH,
    [SPECIES_ANORITH]    = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_ARMALDO]    = BACK_ANIM_V_SHAKE,
    [SPECIES_RALTS]      = BACK_ANIM_SHRINK_GROW_VIBRATE,
    [SPECIES_KIRLIA]     = BACK_ANIM_SHRINK_GROW_VIBRATE,
    [SPECIES_GARDEVOIR]  = BACK_ANIM_SHRINK_GROW_VIBRATE,
    [SPECIES_BAGON]      = BACK_ANIM_V_SHAKE,
    [SPECIES_SHELGON]    = BACK_ANIM_V_SHAKE,
    [SPECIES_SALAMENCE]  = BACK_ANIM_H_SHAKE,
    [SPECIES_BELDUM]     = BACK_ANIM_TRIANGLE_DOWN,
    [SPECIES_METANG]     = BACK_ANIM_JOLT_RIGHT,
    [SPECIES_METAGROSS]  = BACK_ANIM_V_SHAKE,
    [SPECIES_REGIROCK]   = BACK_ANIM_V_SHAKE,
    [SPECIES_REGICE]     = BACK_ANIM_V_SHAKE,
    [SPECIES_REGISTEEL]  = BACK_ANIM_V_SHAKE,
    [SPECIES_KYOGRE]     = BACK_ANIM_SHAKE_GLOW_BLUE,
    [SPECIES_GROUDON]    = BACK_ANIM_SHAKE_GLOW_RED,
    [SPECIES_RAYQUAZA]   = BACK_ANIM_GROW_STUTTER,
    [SPECIES_LATIAS]     = BACK_ANIM_H_VIBRATE,
    [SPECIES_LATIOS]     = BACK_ANIM_H_VIBRATE,
    [SPECIES_JIRACHI]    = BACK_ANIM_CONVEX_DOUBLE_ARC,
    [SPECIES_DEOXYS]     = BACK_ANIM_SHRINK_GROW_VIBRATE,
    [SPECIES_CHIMECHO]   = BACK_ANIM_CONVEX_DOUBLE_ARC,
};

// Equivalent to struct YellowFlashData, but doesn't match as a struct
static const u8 sYellowFlashData[][2] =
{
    {FALSE,  5},
    { TRUE,  1},
    {FALSE, 15},
    { TRUE,  4},
    {FALSE,  2},
    { TRUE,  2},
    {FALSE,  2},
    { TRUE,  2},
    {FALSE,  2},
    { TRUE,  2},
    {FALSE,  2},
    { TRUE,  2},
    {FALSE,  2},
    {FALSE, -1}
};

static const u8 sVerticalShakeData[][2] =
{
    { 6,  30},
    {-2,  15},
    { 6,  30},
    {-1,   0}
};

static void (*const sMonAnimFunctions[])(struct Sprite *sprite) =
{
    [ANIM_V_SQUISH_AND_BOUNCE]               = Anim_VerticalSquishBounce,
    [ANIM_CIRCULAR_STRETCH_TWICE]            = Anim_CircularStretchTwice,
    [ANIM_H_VIBRATE]                         = Anim_HorizontalVibrate,
    [ANIM_H_SLIDE]                           = Anim_HorizontalSlide,
    [ANIM_V_SLIDE]                           = Anim_VerticalSlide,
    [ANIM_BOUNCE_ROTATE_TO_SIDES]            = Anim_BounceRotateToSides,
    [ANIM_V_JUMPS_H_JUMPS]                   = Anim_VerticalJumpsHorizontalJumps,
    [ANIM_ROTATE_TO_SIDES]                   = Anim_RotateToSides, // Unused
    [ANIM_ROTATE_TO_SIDES_TWICE]             = Anim_RotateToSides_Twice,
    [ANIM_GROW_VIBRATE]                      = Anim_GrowVibrate,
    [ANIM_ZIGZAG_FAST]                       = Anim_ZigzagFast,
    [ANIM_SWING_CONCAVE]                     = Anim_SwingConcave,
    [ANIM_SWING_CONCAVE_FAST]                = Anim_SwingConcave_Fast,
    [ANIM_SWING_CONVEX]                      = Anim_SwingConvex,
    [ANIM_SWING_CONVEX_FAST]                 = Anim_SwingConvex_Fast,
    [ANIM_H_SHAKE]                           = Anim_HorizontalShake,
    [ANIM_V_SHAKE]                           = Anim_VerticalShake,
    [ANIM_CIRCULAR_VIBRATE]                  = Anim_CircularVibrate,
    [ANIM_TWIST]                             = Anim_Twist,
    [ANIM_SHRINK_GROW]                       = Anim_ShrinkGrow,
    [ANIM_CIRCLE_C_CLOCKWISE]                = Anim_CircleCounterclockwise,
    [ANIM_GLOW_BLACK]                        = Anim_GlowBlack,
    [ANIM_H_STRETCH]                         = Anim_HorizontalStretch,
    [ANIM_V_STRETCH]                         = Anim_VerticalStretch,
    [ANIM_RISING_WOBBLE]                     = Anim_RisingWobble,
    [ANIM_V_SHAKE_TWICE]                     = Anim_VerticalShakeTwice,
    [ANIM_TIP_MOVE_FORWARD]                  = Anim_TipMoveForward,
    [ANIM_H_PIVOT]                           = Anim_HorizontalPivot,
    [ANIM_V_SLIDE_WOBBLE]                    = Anim_VerticalSlideWobble,
    [ANIM_H_SLIDE_WOBBLE]                    = Anim_HorizontalSlideWobble,
    [ANIM_V_JUMPS_BIG]                       = Anim_VerticalJumps_Big,
    [ANIM_SPIN_LONG]                         = Anim_Spin_Long, // Unused
    [ANIM_GLOW_ORANGE]                       = Anim_GlowOrange,
    [ANIM_GLOW_RED]                          = Anim_GlowRed, // Unused
    [ANIM_GLOW_BLUE]                         = Anim_GlowBlue,
    [ANIM_GLOW_YELLOW]                       = Anim_GlowYellow, // Unused
    [ANIM_GLOW_PURPLE]                       = Anim_GlowPurple, // Unused
    [ANIM_BACK_AND_LUNGE]                    = Anim_BackAndLunge,
    [ANIM_BACK_FLIP]                         = Anim_BackFlip, // Unused
    [ANIM_FLICKER]                           = Anim_Flicker, // Unused
    [ANIM_BACK_FLIP_BIG]                     = Anim_BackFlipBig, // Unused
    [ANIM_FRONT_FLIP]                        = Anim_FrontFlip,
    [ANIM_TUMBLING_FRONT_FLIP]               = Anim_TumblingFrontFlip, // Unused
    [ANIM_FIGURE_8]                          = Anim_Figure8,
    [ANIM_FLASH_YELLOW]                      = Anim_FlashYellow,
    [ANIM_SWING_CONCAVE_FAST_SHORT]          = Anim_SwingConcave_FastShort,
    [ANIM_SWING_CONVEX_FAST_SHORT]           = Anim_SwingConvex_FastShort, // Unused
    [ANIM_ROTATE_UP_SLAM_DOWN]               = Anim_RotateUpSlamDown,
    [ANIM_DEEP_V_SQUISH_AND_BOUNCE]          = Anim_DeepVerticalSquishBounce,
    [ANIM_H_JUMPS]                           = Anim_HorizontalJumps,
    [ANIM_H_JUMPS_V_STRETCH]                 = Anim_HorizontalJumpsVerticalStretch,
    [ANIM_ROTATE_TO_SIDES_FAST]              = Anim_RotateToSides_Fast, // Unused
    [ANIM_ROTATE_UP_TO_SIDES]                = Anim_RotateUpToSides,
    [ANIM_FLICKER_INCREASING]                = Anim_FlickerIncreasing,
    [ANIM_TIP_HOP_FORWARD]                   = Anim_TipHopForward, // Unused
    [ANIM_PIVOT_SHAKE]                       = Anim_PivotShake, // Unused
    [ANIM_TIP_AND_SHAKE]                     = Anim_TipAndShake, // Unused
    [ANIM_VIBRATE_TO_CORNERS]                = Anim_VibrateToCorners, // Unused
    [ANIM_GROW_IN_STAGES]                    = Anim_GrowInStages,
    [ANIM_V_SPRING]                          = Anim_VerticalSpring, // Unused
    [ANIM_V_REPEATED_SPRING]                 = Anim_VerticalRepeatedSpring, // Unused
    [ANIM_SPRING_RISING]                     = Anim_SpringRising, // Unused
    [ANIM_H_SPRING]                          = Anim_HorizontalSpring,
    [ANIM_H_REPEATED_SPRING_SLOW]            = Anim_HorizontalRepeatedSpring_Slow,
    [ANIM_H_SLIDE_SHRINK]                    = Anim_HorizontalSlideShrink, // Unused
    [ANIM_LUNGE_GROW]                        = Anim_LungeGrow,
    [ANIM_CIRCLE_INTO_BG]                    = Anim_CircleIntoBackground,
    [ANIM_RAPID_H_HOPS]                      = Anim_RapidHorizontalHops,
    [ANIM_FOUR_PETAL]                        = Anim_FourPetal,
    [ANIM_V_SQUISH_AND_BOUNCE_SLOW]          = Anim_VerticalSquishBounce_Slow,
    [ANIM_H_SLIDE_SLOW]                      = Anim_HorizontalSlide_Slow,
    [ANIM_V_SLIDE_SLOW]                      = Anim_VerticalSlide_Slow,
    [ANIM_BOUNCE_ROTATE_TO_SIDES_SMALL]      = Anim_BounceRotateToSides_Small,
    [ANIM_BOUNCE_ROTATE_TO_SIDES_SLOW]       = Anim_BounceRotateToSides_Slow,
    [ANIM_BOUNCE_ROTATE_TO_SIDES_SMALL_SLOW] = Anim_BounceRotateToSides_SmallSlow,
    [ANIM_ZIGZAG_SLOW]                       = Anim_ZigzagSlow,
    [ANIM_H_SHAKE_SLOW]                      = Anim_HorizontalShake_Slow,
    [ANIM_V_SHAKE_SLOW]                      = Anim_VertialShake_Slow, // Unused
    [ANIM_TWIST_TWICE]                       = Anim_Twist_Twice,
    [ANIM_CIRCLE_C_CLOCKWISE_SLOW]           = Anim_CircleCounterclockwise_Slow,
    [ANIM_V_SHAKE_TWICE_SLOW]                = Anim_VerticalShakeTwice_Slow, // Unused
    [ANIM_V_SLIDE_WOBBLE_SMALL]              = Anim_VerticalSlideWobble_Small,
    [ANIM_V_JUMPS_SMALL]                     = Anim_VerticalJumps_Small,
    [ANIM_SPIN]                              = Anim_Spin,
    [ANIM_TUMBLING_FRONT_FLIP_TWICE]         = Anim_TumblingFrontFlip_Twice,
    [ANIM_DEEP_V_SQUISH_AND_BOUNCE_TWICE]    = Anim_DeepVerticalSquishBounce_Twice, // Unused
    [ANIM_H_JUMPS_V_STRETCH_TWICE]           = Anim_HorizontalJumpsVerticalStretch_Twice,
    [ANIM_V_SHAKE_BACK]                      = Anim_VerticalShakeBack,
    [ANIM_V_SHAKE_BACK_SLOW]                 = Anim_VerticalShakeBack_Slow,
    [ANIM_V_SHAKE_H_SLIDE_SLOW]              = Anim_VerticalShakeHorizontalSlide_Slow,
    [ANIM_V_STRETCH_BOTH_ENDS_SLOW]          = Anim_VerticalStretchBothEnds_Slow,
    [ANIM_H_STRETCH_FAR_SLOW]                = Anim_HorizontalStretchFar_Slow,
    [ANIM_V_SHAKE_LOW_TWICE]                 = Anim_VerticalShakeLowTwice,
    [ANIM_H_SHAKE_FAST]                      = Anim_HorizontalShake_Fast,
    [ANIM_H_SLIDE_FAST]                      = Anim_HorizontalSlide_Fast,
    [ANIM_H_VIBRATE_FAST]                    = Anim_HorizontalVibrate_Fast,
    [ANIM_H_VIBRATE_FASTEST]                 = Anim_HorizontalVibrate_Fastest,
    [ANIM_V_SHAKE_BACK_FAST]                 = Anim_VerticalShakeBack_Fast,
    [ANIM_V_SHAKE_LOW_TWICE_SLOW]            = Anim_VerticalShakeLowTwice_Slow,
    [ANIM_V_SHAKE_LOW_TWICE_FAST]            = Anim_VerticalShakeLowTwice_Fast,
    [ANIM_CIRCLE_C_CLOCKWISE_LONG]           = Anim_CircleCounterclockwise_Long,
    [ANIM_GROW_STUTTER_SLOW]                 = Anim_GrowStutter_Slow,
    [ANIM_V_SHAKE_H_SLIDE]                   = Anim_VerticalShakeHorizontalSlide,
    [ANIM_V_SHAKE_H_SLIDE_FAST]              = Anim_VerticalShakeHorizontalSlide_Fast,
    [ANIM_TRIANGLE_DOWN_SLOW]                = Anim_TriangleDown_Slow,
    [ANIM_TRIANGLE_DOWN]                     = Anim_TriangleDown,
    [ANIM_TRIANGLE_DOWN_TWICE]               = Anim_TriangleDown_Fast,
    [ANIM_GROW]                              = Anim_Grow,
    [ANIM_GROW_TWICE]                        = Anim_Grow_Twice,
    [ANIM_H_SPRING_FAST]                     = Anim_HorizontalSpring_Fast,
    [ANIM_H_SPRING_SLOW]                     = Anim_HorizontalSpring_Slow,
    [ANIM_H_REPEATED_SPRING_FAST]            = Anim_HorizontalRepeatedSpring_Fast,
    [ANIM_H_REPEATED_SPRING]                 = Anim_HorizontalRepeatedSpring,
    [ANIM_SHRINK_GROW_FAST]                  = Anim_ShrinkGrow_Fast,
    [ANIM_SHRINK_GROW_SLOW]                  = Anim_ShrinkGrow_Slow,
    [ANIM_V_STRETCH_BOTH_ENDS]               = Anim_VerticalStretchBothEnds,
    [ANIM_V_STRETCH_BOTH_ENDS_TWICE]         = Anim_VerticalStretchBothEnds_Twice,
    [ANIM_H_STRETCH_FAR_TWICE]               = Anim_HorizontalStretchFar_Twice,
    [ANIM_H_STRETCH_FAR]                     = Anim_HorizontalStretchFar,
    [ANIM_GROW_STUTTER_TWICE]                = Anim_GrowStutter_Twice,
    [ANIM_GROW_STUTTER]                      = Anim_GrowStutter,
    [ANIM_CONCAVE_ARC_LARGE_SLOW]            = Anim_ConcaveArcLarge_Slow,
    [ANIM_CONCAVE_ARC_LARGE]                 = Anim_ConcaveArcLarge,
    [ANIM_CONCAVE_ARC_LARGE_TWICE]           = Anim_ConcaveArcLarge_Twice,
    [ANIM_CONVEX_DOUBLE_ARC_SLOW]            = Anim_ConvexDoubleArc_Slow,
    [ANIM_CONVEX_DOUBLE_ARC]                 = Anim_ConvexDoubleArc,
    [ANIM_CONVEX_DOUBLE_ARC_TWICE]           = Anim_ConvexDoubleArc_Twice,
    [ANIM_CONCAVE_ARC_SMALL_SLOW]            = Anim_ConcaveArcSmall_Slow,
    [ANIM_CONCAVE_ARC_SMALL]                 = Anim_ConcaveArcSmall,
    [ANIM_CONCAVE_ARC_SMALL_TWICE]           = Anim_ConcaveArcSmall_Twice,
    [ANIM_H_DIP]                             = Anim_HorizontalDip,
    [ANIM_H_DIP_FAST]                        = Anim_HorizontalDip_Fast,
    [ANIM_H_DIP_TWICE]                       = Anim_HorizontalDip_Twice,
    [ANIM_SHRINK_GROW_VIBRATE_FAST]          = Anim_ShrinkGrowVibrate_Fast,
    [ANIM_SHRINK_GROW_VIBRATE]               = Anim_ShrinkGrowVibrate,
    [ANIM_SHRINK_GROW_VIBRATE_SLOW]          = Anim_ShrinkGrowVibrate_Slow,
    [ANIM_JOLT_RIGHT_FAST]                   = Anim_JoltRight_Fast,
    [ANIM_JOLT_RIGHT]                        = Anim_JoltRight,
    [ANIM_JOLT_RIGHT_SLOW]                   = Anim_JoltRight_Slow,
    [ANIM_SHAKE_FLASH_YELLOW_FAST]           = Anim_ShakeFlashYellow_Fast,
    [ANIM_SHAKE_FLASH_YELLOW]                = Anim_ShakeFlashYellow,
    [ANIM_SHAKE_FLASH_YELLOW_SLOW]           = Anim_ShakeFlashYellow_Slow,
    [ANIM_SHAKE_GLOW_RED_FAST]               = Anim_ShakeGlowRed_Fast,
    [ANIM_SHAKE_GLOW_RED]                    = Anim_ShakeGlowRed,
    [ANIM_SHAKE_GLOW_RED_SLOW]               = Anim_ShakeGlowRed_Slow,
    [ANIM_SHAKE_GLOW_GREEN_FAST]             = Anim_ShakeGlowGreen_Fast,
    [ANIM_SHAKE_GLOW_GREEN]                  = Anim_ShakeGlowGreen,
    [ANIM_SHAKE_GLOW_GREEN_SLOW]             = Anim_ShakeGlowGreen_Slow,
    [ANIM_SHAKE_GLOW_BLUE_FAST]              = Anim_ShakeGlowBlue_Fast,
    [ANIM_SHAKE_GLOW_BLUE]                   = Anim_ShakeGlowBlue,
    [ANIM_SHAKE_GLOW_BLUE_SLOW]              = Anim_ShakeGlowBlue_Slow
};

// Each back anim set has 3 possible animations depending on nature
// Each of the 3 animations is a slight variation of the others
// BACK_ANIM_NONE is skipped below. GetSpeciesBackAnimSet subtracts 1 from the back anim id
static const u8 sBackAnimationIds[] =
{
    [(BACK_ANIM_H_VIBRATE - 1) * 3]               = ANIM_H_VIBRATE_FASTEST, ANIM_H_VIBRATE_FAST, ANIM_H_VIBRATE,
    [(BACK_ANIM_H_SLIDE - 1) * 3]                 = ANIM_H_SLIDE_FAST, ANIM_H_SLIDE, ANIM_H_SLIDE_SLOW,
    [(BACK_ANIM_H_SPRING - 1) * 3]                = ANIM_H_SPRING_FAST, ANIM_H_SPRING, ANIM_H_SPRING_SLOW,
    [(BACK_ANIM_H_SPRING_REPEATED - 1) * 3]       = ANIM_H_REPEATED_SPRING_FAST, ANIM_H_REPEATED_SPRING, ANIM_H_REPEATED_SPRING_SLOW,
    [(BACK_ANIM_SHRINK_GROW - 1) * 3]             = ANIM_SHRINK_GROW_FAST, ANIM_SHRINK_GROW, ANIM_SHRINK_GROW_SLOW,
    [(BACK_ANIM_GROW - 1) * 3]                    = ANIM_GROW_TWICE, ANIM_GROW, ANIM_GROW_IN_STAGES,
    [(BACK_ANIM_CIRCLE_COUNTERCLOCKWISE - 1) * 3] = ANIM_CIRCLE_C_CLOCKWISE_LONG, ANIM_CIRCLE_C_CLOCKWISE, ANIM_CIRCLE_C_CLOCKWISE_SLOW,
    [(BACK_ANIM_H_SHAKE - 1) * 3]                 = ANIM_H_SHAKE_FAST, ANIM_H_SHAKE, ANIM_H_SHAKE_SLOW,
    [(BACK_ANIM_V_SHAKE - 1) * 3]                 = ANIM_V_SHAKE_BACK_FAST, ANIM_V_SHAKE_BACK, ANIM_V_SHAKE_BACK_SLOW,
    [(BACK_ANIM_V_SHAKE_H_SLIDE - 1) * 3]         = ANIM_V_SHAKE_H_SLIDE_FAST, ANIM_V_SHAKE_H_SLIDE, ANIM_V_SHAKE_H_SLIDE_SLOW,
    [(BACK_ANIM_V_STRETCH - 1) * 3]               = ANIM_V_STRETCH_BOTH_ENDS_TWICE, ANIM_V_STRETCH_BOTH_ENDS, ANIM_V_STRETCH_BOTH_ENDS_SLOW,
    [(BACK_ANIM_H_STRETCH - 1) * 3]               = ANIM_H_STRETCH_FAR_TWICE, ANIM_H_STRETCH_FAR, ANIM_H_STRETCH_FAR_SLOW,
    [(BACK_ANIM_GROW_STUTTER - 1) * 3]            = ANIM_GROW_STUTTER_TWICE, ANIM_GROW_STUTTER, ANIM_GROW_STUTTER_SLOW,
    [(BACK_ANIM_V_SHAKE_LOW - 1) * 3]             = ANIM_V_SHAKE_LOW_TWICE_FAST, ANIM_V_SHAKE_LOW_TWICE, ANIM_V_SHAKE_LOW_TWICE_SLOW,
    [(BACK_ANIM_TRIANGLE_DOWN - 1) * 3]           = ANIM_TRIANGLE_DOWN_TWICE, ANIM_TRIANGLE_DOWN, ANIM_TRIANGLE_DOWN_SLOW,
    [(BACK_ANIM_CONCAVE_ARC_LARGE - 1) * 3]       = ANIM_CONCAVE_ARC_LARGE_TWICE, ANIM_CONCAVE_ARC_LARGE, ANIM_CONCAVE_ARC_LARGE_SLOW,
    [(BACK_ANIM_CONVEX_DOUBLE_ARC - 1) * 3]       = ANIM_CONVEX_DOUBLE_ARC_TWICE, ANIM_CONVEX_DOUBLE_ARC, ANIM_CONVEX_DOUBLE_ARC_SLOW,
    [(BACK_ANIM_CONCAVE_ARC_SMALL - 1) * 3]       = ANIM_CONCAVE_ARC_SMALL_TWICE, ANIM_CONCAVE_ARC_SMALL, ANIM_CONCAVE_ARC_SMALL_SLOW,
    [(BACK_ANIM_DIP_RIGHT_SIDE - 1) * 3]          = ANIM_H_DIP_TWICE, ANIM_H_DIP, ANIM_H_DIP_FAST,
    [(BACK_ANIM_SHRINK_GROW_VIBRATE - 1) * 3]     = ANIM_SHRINK_GROW_VIBRATE_FAST, ANIM_SHRINK_GROW_VIBRATE, ANIM_SHRINK_GROW_VIBRATE_SLOW,
    [(BACK_ANIM_JOLT_RIGHT - 1) * 3]              = ANIM_JOLT_RIGHT_FAST, ANIM_JOLT_RIGHT, ANIM_JOLT_RIGHT_SLOW,
    [(BACK_ANIM_SHAKE_FLASH_YELLOW - 1) * 3]      = ANIM_SHAKE_FLASH_YELLOW_FAST, ANIM_SHAKE_FLASH_YELLOW, ANIM_SHAKE_FLASH_YELLOW_SLOW,
    [(BACK_ANIM_SHAKE_GLOW_RED - 1) * 3]          = ANIM_SHAKE_GLOW_RED_FAST, ANIM_SHAKE_GLOW_RED, ANIM_SHAKE_GLOW_RED_SLOW,
    [(BACK_ANIM_SHAKE_GLOW_GREEN - 1) * 3]        = ANIM_SHAKE_GLOW_GREEN_FAST, ANIM_SHAKE_GLOW_GREEN, ANIM_SHAKE_GLOW_GREEN_SLOW,
    [(BACK_ANIM_SHAKE_GLOW_BLUE - 1) * 3]         = ANIM_SHAKE_GLOW_BLUE_FAST,  ANIM_SHAKE_GLOW_BLUE, ANIM_SHAKE_GLOW_BLUE_SLOW,
};

static const u8 sBackAnimNatureModTable[NUM_NATURES] =
{
    [NATURE_HARDY]   = 0,
    [NATURE_LONELY]  = 2,
    [NATURE_BRAVE]   = 0,
    [NATURE_ADAMANT] = 0,
    [NATURE_NAUGHTY] = 0,
    [NATURE_BOLD]    = 1,
    [NATURE_DOCILE]  = 1,
    [NATURE_RELAXED] = 1,
    [NATURE_IMPISH]  = 0,
    [NATURE_LAX]     = 1,
    [NATURE_TIMID]   = 2,
    [NATURE_HASTY]   = 0,
    [NATURE_SERIOUS] = 1,
    [NATURE_JOLLY]   = 0,
    [NATURE_NAIVE]   = 0,
    [NATURE_MODEST]  = 2,
    [NATURE_MILD]    = 2,
    [NATURE_QUIET]   = 2,
    [NATURE_BASHFUL] = 2,
    [NATURE_RASH]    = 1,
    [NATURE_CALM]    = 1,
    [NATURE_GENTLE]  = 2,
    [NATURE_SASSY]   = 1,
    [NATURE_CAREFUL] = 2,
    [NATURE_QUIRKY]  = 1,
};

static const union AffineAnimCmd sMonAffineAnim_0[] =
{
    AFFINEANIMCMD_FRAME(256, 256, 0, 0),
    {AFFINEANIMCMDTYPE_END}
};

static const union AffineAnimCmd sMonAffineAnim_1[] =
{
    AFFINEANIMCMD_FRAME(-256, 256, 0, 0),
    {AFFINEANIMCMDTYPE_END}
};

static const union AffineAnimCmd *const sMonAffineAnims[] =
{
    sMonAffineAnim_0,
    sMonAffineAnim_1
};

static void MonAnimDummySpriteCallback(struct Sprite *sprite)
{
}

static void SetPosForRotation(struct Sprite *sprite, u16 index, s16 amplitudeX, s16 amplitudeY)
{
    s16 xAdder, yAdder;

    amplitudeX *= -1;
    amplitudeY *= -1;

    xAdder = Cos(index, amplitudeX) - Sin(index, amplitudeY);
    yAdder = Cos(index, amplitudeY) + Sin(index, amplitudeX);

    amplitudeX *= -1;
    amplitudeY *= -1;

    sprite->x2 = xAdder + amplitudeX;
    sprite->y2 = yAdder + amplitudeY;
}

u8 GetSpeciesBackAnimSet(u16 species)
{
    if (sSpeciesToBackAnimSet[species] != BACK_ANIM_NONE)
        return sSpeciesToBackAnimSet[species] - 1;
    else
        return 0;
}

#define tState  data[0]
#define tPtrHi  data[1]
#define tPtrLo  data[2]
#define tAnimId data[3]
#define tBattlerId data[4]
#define tSpeciesId data[5]

// BUG: In vanilla, tPtrLo is read as an s16, so if bit 15 of the
// address were to be set it would cause the pointer to be read
// as 0xFFFFXXXX instead of the desired 0x02YYXXXX.
// By dumb luck, this is not an issue in vanilla. However,
// changing the link order revealed this bug.
#if MODERN || defined(BUGFIX)
#define ANIM_SPRITE(taskId)   ((struct Sprite *)((gTasks[taskId].tPtrHi << 16) | ((u16)gTasks[taskId].tPtrLo)))
#else
#define ANIM_SPRITE(taskId)   ((struct Sprite *)((gTasks[taskId].tPtrHi << 16) | (gTasks[taskId].tPtrLo)))
#endif //MODERN || BUGFIX

static void Task_HandleMonAnimation(u8 taskId)
{
    u32 i;
    struct Sprite *sprite = ANIM_SPRITE(taskId);

    if (gTasks[taskId].tState == 0)
    {
        gTasks[taskId].tBattlerId = sprite->data[0];
        gTasks[taskId].tSpeciesId = sprite->data[2];
        sprite->sDontFlip = TRUE;
        sprite->data[0] = 0;

        for (i = 2; i < ARRAY_COUNT(sprite->data); i++)
            sprite->data[i] = 0;

        sprite->callback = sMonAnimFunctions[gTasks[taskId].tAnimId];
        sIsSummaryAnim = FALSE;

        gTasks[taskId].tState++;
    }
    if (sprite->callback == SpriteCallbackDummy)
    {
        sprite->data[0] = gTasks[taskId].tBattlerId;
        sprite->data[2] = gTasks[taskId].tSpeciesId;
        sprite->data[1] = 0;

        DestroyTask(taskId);
    }
}

void LaunchAnimationTaskForFrontSprite(struct Sprite *sprite, u8 frontAnimId)
{
    u8 taskId = CreateTask(Task_HandleMonAnimation, 128);
    gTasks[taskId].tPtrHi = (u32)(sprite) >> 16;
    gTasks[taskId].tPtrLo = (u32)(sprite);
    gTasks[taskId].tAnimId = frontAnimId;
}

void StartMonSummaryAnimation(struct Sprite *sprite, u8 frontAnimId)
{
    // sDontFlip is expected to still be FALSE here, not explicitly cleared
    sIsSummaryAnim = TRUE;
    sprite->callback = sMonAnimFunctions[frontAnimId];
}

void LaunchAnimationTaskForBackSprite(struct Sprite *sprite, u8 backAnimSet)
{
    u8 nature, taskId, animId, battler;

    taskId = CreateTask(Task_HandleMonAnimation, 128);
    gTasks[taskId].tPtrHi = (u32)(sprite) >> 16;
    gTasks[taskId].tPtrLo = (u32)(sprite);

    battler = sprite->data[0];
    nature = GetNature(&gPlayerParty[gBattlerPartyIndexes[battler]]);

    // * 3 below because each back anim has 3 variants depending on nature
    animId = 3 * backAnimSet + sBackAnimNatureModTable[nature];
    gTasks[taskId].tAnimId = sBackAnimationIds[animId];
}

#undef tState
#undef tPtrHi
#undef tPtrLo
#undef tAnimId
#undef tBattlerId
#undef tSpeciesId

void SetSpriteCB_MonAnimDummy(struct Sprite *sprite)
{
    sprite->callback = MonAnimDummySpriteCallback;
}

static void SetAffineData(struct Sprite *sprite, s16 xScale, s16 yScale, u16 rotation)
{
    u8 matrixNum;
    struct ObjAffineSrcData affineSrcData;
    struct OamMatrix dest;

    affineSrcData.xScale = xScale;
    affineSrcData.yScale = yScale;
    affineSrcData.rotation = rotation;

    matrixNum = sprite->oam.matrixNum;

    ObjAffineSet(&affineSrcData, &dest, 1, 2);
    gOamMatrices[matrixNum].a = dest.a;
    gOamMatrices[matrixNum].b = dest.b;
    gOamMatrices[matrixNum].c = dest.c;
    gOamMatrices[matrixNum].d = dest.d;
}

static void HandleStartAffineAnim(struct Sprite *sprite)
{
    sprite->oam.affineMode = ST_OAM_AFFINE_DOUBLE;
    sprite->affineAnims = sMonAffineAnims;

    if (sIsSummaryAnim == TRUE)
        InitSpriteAffineAnim(sprite);

    if (!sprite->sDontFlip)
        StartSpriteAffineAnim(sprite, 1);
    else
        StartSpriteAffineAnim(sprite, 0);

    CalcCenterToCornerVec(sprite, sprite->oam.shape, sprite->oam.size, sprite->oam.affineMode);
    sprite->affineAnimPaused = TRUE;
}

static void HandleSetAffineData(struct Sprite *sprite, s16 xScale, s16 yScale, u16 rotation)
{
    if (!sprite->sDontFlip)
    {
        xScale *= -1;
        rotation *= -1;
    }

    SetAffineData(sprite, xScale, yScale, rotation);
}

static void TryFlipX(struct Sprite *sprite)
{
    if (!sprite->sDontFlip)
        sprite->x2 *= -1;
}

static bool32 InitAnimData(u8 id)
{
    if (id >= MAX_BATTLERS_COUNT)
    {
        return FALSE;
    }
    else
    {
        sAnims[id].rotation = 0;
        sAnims[id].delay = 0;
        sAnims[id].runs = 1;
        sAnims[id].speed = 0;
        sAnims[id].data = 0;
        return TRUE;
    }
}

static u8 AddNewAnim(void)
{
    sAnimIdx = (sAnimIdx + 1) % MAX_BATTLERS_COUNT;
    InitAnimData(sAnimIdx);
    return sAnimIdx;
}

static void ResetSpriteAfterAnim(struct Sprite *sprite)
{
    sprite->oam.affineMode = ST_OAM_AFFINE_NORMAL;
    CalcCenterToCornerVec(sprite, sprite->oam.shape, sprite->oam.size, sprite->oam.affineMode);

    if (sIsSummaryAnim == TRUE)
    {
        if (!sprite->sDontFlip)
            sprite->hFlip = TRUE;
        else
            sprite->hFlip = FALSE;

        FreeOamMatrix(sprite->oam.matrixNum);
        sprite->oam.matrixNum |= (sprite->hFlip << 3);
        sprite->oam.affineMode = ST_OAM_AFFINE_OFF;
    }
#ifdef BUGFIX
    else
    {
        // FIX: Reset these back to normal after they were changed so Poké Ball catch/release
        // animations without a screen transition in between don't break
        sprite->affineAnims = gAffineAnims_BattleSpriteOpponentSide;
    }
#endif // BUGFIX
}

static void Anim_CircularStretchTwice(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
        HandleStartAffineAnim(sprite);

    if (sprite->data[2] > 40)
    {
        HandleSetAffineData(sprite, 256, 256, 0);
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        s16 var = (sprite->data[2] * 512 / 40) % 256;

        sprite->data[4] = Sin(var, 32) + 256;
        sprite->data[5] = Cos(var, 32) + 256;
        HandleSetAffineData(sprite, sprite->data[4], sprite->data[5], 0);
    }

    sprite->data[2]++;
}

static void Anim_HorizontalVibrate(struct Sprite *sprite)
{
    if (sprite->data[2] > 40)
    {
        sprite->callback = WaitAnimEnd;
        sprite->x2 = 0;
    }
    else
    {
        s8 sign;
        if (!(sprite->data[2] & 1))
            sign = 1;
        else
            sign = -1;

        sprite->x2 = Sin((sprite->data[2] * 128 / 40) % 256, 6) * sign;
    }

    sprite->data[2]++;
}

static void HorizontalSlide(struct Sprite *sprite)
{
    TryFlipX(sprite);

    if (sprite->data[2] > sprite->data[0])
    {
        sprite->callback = WaitAnimEnd;
        sprite->x2 = 0;
    }
    else
    {
        sprite->x2 = Sin((sprite->data[2] * 384 / sprite->data[0]) % 256, 6);
    }

    sprite->data[2]++;
    TryFlipX(sprite);
}

static void Anim_HorizontalSlide(struct Sprite *sprite)
{
    sprite->data[0] = 40;
    HorizontalSlide(sprite);
    sprite->callback = HorizontalSlide;
}

static void VerticalSlide(struct Sprite *sprite)
{
    TryFlipX(sprite);

    if (sprite->data[2] > sprite->data[0])
    {
        sprite->callback = WaitAnimEnd;
        sprite->y2 = 0;
    }
    else
    {
        sprite->y2 = -(Sin((sprite->data[2] * 384 / sprite->data[0]) % 256, 6));
    }

    sprite->data[2]++;
    TryFlipX(sprite);
}

static void Anim_VerticalSlide(struct Sprite *sprite)
{
    sprite->data[0] = 40;
    VerticalSlide(sprite);
    sprite->callback = VerticalSlide;
}

static void VerticalJumps(struct Sprite *sprite)
{
    s32 counter = sprite->data[2];
    if (counter > 384)
    {
        sprite->callback = WaitAnimEnd;
        sprite->x2 = 0;
        sprite->y2 = 0;
    }
    else
    {
        s16 divCounter = counter / 128;
        switch (divCounter)
        {
        case 0:
        case 1:
            sprite->y2 = -(Sin(counter % 128, sprite->data[0] * 2));
            break;
        case 2:
        case 3:
            counter -= 256;
            sprite->y2 = -(Sin(counter, sprite->data[0] * 3));
            break;
        }
    }

    sprite->data[2] += 12;
}

static void Anim_VerticalJumps_Big(struct Sprite *sprite)
{
    sprite->data[0] = 4;
    VerticalJumps(sprite);
    sprite->callback = VerticalJumps;
}

static void Anim_VerticalJumpsHorizontalJumps(struct Sprite *sprite)
{
    s32 counter = sprite->data[2];

    if (counter > 768)
    {
        sprite->callback = WaitAnimEnd;
        sprite->x2 = 0;
        sprite->y2 = 0;
    }
    else
    {
        s16 divCounter = counter / 128;

        switch (divCounter)
        {
        case 0:
        case 1:
            sprite->x2 = 0;
            break;
        case 2:
            counter = 0;
            break;
        case 3:
            sprite->x2 = -(counter % 128 * 8) / 128;
            break;
        case 4:
            sprite->x2 = (counter % 128) / 8 - 8;
            break;
        case 5:
            sprite->x2 = -(counter % 128 * 8) / 128 + 8;
            break;
        }

        sprite->y2 = -(Sin(counter % 128, 8));
    }

    sprite->data[2] += 12;
}

static void Anim_GrowVibrate(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
        HandleStartAffineAnim(sprite);

    if (sprite->data[2] > 40)
    {
        HandleSetAffineData(sprite, 256, 256, 0);
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        s16 index = (sprite->data[2] * 256 / 40) % 256;

        if (sprite->data[2] % 2 == 0)
        {
            sprite->data[4] = Sin(index, 32) + 256;
            sprite->data[5] = Sin(index, 32) + 256;
        }
        else
        {
            sprite->data[4] = Sin(index, 8) + 256;
            sprite->data[5] = Sin(index, 8) + 256;
        }

        HandleSetAffineData(sprite, sprite->data[4], sprite->data[5], 0);
    }

    sprite->data[2]++;
}

// x delta, y delta, time
static const s8 sZigzagData[][3] =
{
    {-1, -1, 6},
    { 2,  0, 6},
    {-2,  2, 6},
    { 2,  0, 6},
    {-2, -2, 6},
    { 2,  0, 6},
    {-2,  2, 6},
    { 2,  0, 6},
    {-1, -1, 6},
    { 0,  0, 0},
};

static void Zigzag(struct Sprite *sprite)
{
    TryFlipX(sprite);

    if (sprite->data[2] == 0)
        sprite->data[3] = 0;

    if (sZigzagData[sprite->data[3]][2] == sprite->data[2])
    {
        if (sZigzagData[sprite->data[3]][2] == 0)
        {
            sprite->callback = WaitAnimEnd;
        }
        else
        {
            sprite->data[3]++;
            sprite->data[2] = 0;
        }
    }

    if (sZigzagData[sprite->data[3]][2] == 0)
    {
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        sprite->x2 += sZigzagData[sprite->data[3]][0];
        sprite->y2 += sZigzagData[sprite->data[3]][1];
        sprite->data[2]++;
        TryFlipX(sprite);
    }
}

static void Anim_ZigzagFast(struct Sprite *sprite)
{
    Zigzag(sprite);
    sprite->callback = Zigzag;
}

static void HorizontalShake(struct Sprite *sprite)
{
    s32 counter = sprite->data[2];

    if (counter > 2304)
    {
        sprite->callback = WaitAnimEnd;
        sprite->x2 = 0;
    }
    else
    {
        sprite->x2 = Sin(counter % 256, sprite->data[7]);
    }

    sprite->data[2] += sprite->data[0];
}

static void Anim_HorizontalShake(struct Sprite *sprite)
{
    sprite->data[0] = 60;
    sprite->data[7] = 3;
    HorizontalShake(sprite);
    sprite->callback = HorizontalShake;
}

static void VerticalShake(struct Sprite *sprite)
{
    s32 counter = sprite->data[2];

    if (counter > 2304)
    {
        sprite->callback = WaitAnimEnd;
        sprite->y2 = 0;
    }
    else
    {
        sprite->y2 = Sin(counter % 256, 3);
    }

    sprite->data[2] += sprite->data[0];
}

static void Anim_VerticalShake(struct Sprite *sprite)
{
    sprite->data[0] = 60;
    VerticalShake(sprite);
    sprite->callback = VerticalShake;
}

static void Anim_CircularVibrate(struct Sprite *sprite)
{
    if (sprite->data[2] > 512)
    {
        sprite->callback = WaitAnimEnd;
        sprite->x2 = 0;
        sprite->y2 = 0;
    }
    else
    {
        s8 sign;
        s32 index, amplitude;

        if (!(sprite->data[2] & 1))
            sign = 1;
        else
            sign = -1;

        amplitude = Sin(sprite->data[2] / 4, 8);
        index = sprite->data[2] % 256;

        sprite->y2 = Sin(index, amplitude) * sign;
        sprite->x2 = Cos(index, amplitude) * sign;
    }

    sprite->data[2] += 9;
}

static void Twist(struct Sprite *sprite)
{
    s16 id = sprite->data[0];

    if (sAnims[id].delay != 0)
    {
        sAnims[id].delay--;
    }
    else
    {
        if (sprite->data[2] == 0 && sAnims[id].data == 0)
        {
            HandleStartAffineAnim(sprite);
            sAnims[id].data++;
        }

        if (sprite->data[2] > sAnims[id].rotation)
        {
            HandleSetAffineData(sprite, 256, 256, 0);

            if (sAnims[id].runs > 1)
            {
                sAnims[id].runs--;
                sAnims[id].delay = 10;
                sprite->data[2] = 0;
            }
            else
            {
                ResetSpriteAfterAnim(sprite);
                sprite->callback = WaitAnimEnd;
            }
        }
        else
        {
            sprite->data[6] = Sin(sprite->data[2] % 256, 4096);
            HandleSetAffineData(sprite, 256, 256, sprite->data[6]);
        }

        sprite->data[2] += 16;
    }
}

static void Anim_Twist(struct Sprite *sprite)
{
    u8 id = sprite->data[0] = AddNewAnim();

    sAnims[id].rotation = 512;
    sAnims[id].delay = 0;
    Twist(sprite);
    sprite->callback = Twist;
}

static void Spin(struct Sprite *sprite)
{
    u8 id = sprite->data[0];

    if (sprite->data[2] == 0)
        HandleStartAffineAnim(sprite);

    if (sprite->data[2] > sAnims[id].delay)
    {
        HandleSetAffineData(sprite, 256, 256, 0);
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        sprite->data[6] = (65536 / sAnims[id].data) * sprite->data[2];
        HandleSetAffineData(sprite, 256, 256, sprite->data[6]);
    }

    sprite->data[2]++;
}

static void Anim_Spin_Long(struct Sprite *sprite)
{
    u8 id = sprite->data[0] = AddNewAnim();

    sAnims[id].delay = 60;
    sAnims[id].data = 20;
    Spin(sprite);
    sprite->callback = Spin;
}

static void CircleCounterclockwise(struct Sprite *sprite)
{
    u8 id = sprite->data[0];

    TryFlipX(sprite);

    if (sprite->data[2] > sAnims[id].rotation)
    {
        sprite->x2 = 0;
        sprite->y2 = 0;
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        s16 index = (sprite->data[2] + 192) % 256;

        sprite->x2 = -(Cos(index, sAnims[id].data * 2));
        sprite->y2 = Sin(index, sAnims[id].data) + sAnims[id].data;
    }

    sprite->data[2] += sAnims[id].speed;
    TryFlipX(sprite);
}

static void Anim_CircleCounterclockwise(struct Sprite *sprite)
{
    u8 id = sprite->data[0] = AddNewAnim();

    sAnims[id].rotation = 512;
    sAnims[id].data = 6;
    sAnims[id].speed = 24;
    CircleCounterclockwise(sprite);
    sprite->callback = CircleCounterclockwise;
}

#define GlowColor(color, colorIncrement, speed)                         \
{                                                                       \
    if (sprite->data[2] == 0)                                           \
        sprite->data[7] = OBJ_PLTT_ID(sprite->oam.paletteNum);          \
                                                                        \
    if (sprite->data[2] > 128)                                          \
    {                                                                   \
        BlendPalette(sprite->data[7], 16, 0, (color));                  \
        sprite->callback = WaitAnimEnd;                                 \
    }                                                                   \
    else                                                                \
    {                                                                   \
        sprite->data[6] = Sin(sprite->data[2], (colorIncrement));       \
        BlendPalette(sprite->data[7], 16, sprite->data[6], (color));    \
    }                                                                   \
    sprite->data[2] += (speed);                                         \
}

static void Anim_GlowBlack(struct Sprite *sprite)
{
    GlowColor(RGB_BLACK, 16, 1);
}

static void Anim_HorizontalStretch(struct Sprite *sprite)
{
    s16 index1 = 0, index2 = 0;

    if (sprite->data[2] == 0)
        HandleStartAffineAnim(sprite);

    if (sprite->data[2] > 40)
    {
        HandleSetAffineData(sprite, 256, 256, 0);
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        index2 = (sprite->data[2] * 128) / 40;

        if (sprite->data[2] >= 10 && sprite->data[2] <= 29)
        {
            sprite->data[7] += 51;
            index1 = 0xFF & sprite->data[7];
        }

        if (!sprite->sDontFlip)
            sprite->data[4] = (Sin(index2, 40) - 256) + Sin(index1, 16);
        else
            sprite->data[4] = (256 - Sin(index2, 40)) - Sin(index1, 16);

        sprite->data[5] = Sin(index2, 16) + 256;
        SetAffineData(sprite, sprite->data[4], sprite->data[5], 0);
    }

    sprite->data[2]++;
}

static void Anim_VerticalStretch(struct Sprite *sprite)
{
    s16 posY = 0, index1 = 0, index2 = 0;

    if (sprite->data[2] == 0)
        HandleStartAffineAnim(sprite);

    if (sprite->data[2] > 40)
    {
        HandleSetAffineData(sprite, 256, 256, 0);
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
        sprite->y2 = posY;
    }
    else
    {
        index2 = (sprite->data[2] * 128) / 40;

        if (sprite->data[2] >= 10 && sprite->data[2] <= 29)
        {
            sprite->data[7] += 51;
            index1 = 0xFF & sprite->data[7];
        }

        if (!sprite->sDontFlip)
            sprite->data[4] = -(Sin(index2, 16)) - 256;
        else
            sprite->data[4] = Sin(index2, 16) + 256;

        sprite->data[5] = (256 - Sin(index2, 40)) - Sin(index1, 8);

        if (sprite->data[5] != 256)
            posY = (256 - sprite->data[5]) / 8;

        sprite->y2 = -(posY);
        SetAffineData(sprite, sprite->data[4], sprite->data[5], 0);
    }

    sprite->data[2]++;
}

static void VerticalShakeTwice(struct Sprite *sprite)
{
    u8 index = sprite->data[2];
    u8 var7 = sprite->data[6];
    u8 var5 = sVerticalShakeData[sprite->data[5]][0];
    u8 var6 = sVerticalShakeData[sprite->data[5]][1];
    u8 amplitude = 0;

    if (var5 != (u8)-2)
        amplitude = (var6 - var7) * var5 / var6;
    else
        amplitude = 0;

    if (var5 == (u8)-1)
    {
        sprite->callback = WaitAnimEnd;
        sprite->y2 = 0;
    }
    else
    {
        sprite->y2 = Sin(index, amplitude);

        if (var7 == var6)
        {
            sprite->data[5]++;
            sprite->data[6] = 0;
        }
        else
        {
            sprite->data[2] += sprite->data[0];
            sprite->data[6]++;
        }
    }
}

static void Anim_VerticalShakeTwice(struct Sprite *sprite)
{
    sprite->data[0] = 48;
    VerticalShakeTwice(sprite);
    sprite->callback = VerticalShakeTwice;
}

static void Anim_TipMoveForward(struct Sprite *sprite)
{
    u8 counter = 0;

    TryFlipX(sprite);
    counter = sprite->data[2];

    if (sprite->data[2] == 0)
        HandleStartAffineAnim(sprite);

    if (sprite->data[2] > 35)
    {
        HandleSetAffineData(sprite, 256, 256, 0);
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
        sprite->x2 = 0;
    }
    else
    {
        s16 index = ((counter - 10) * 128) / 20;

        if (counter < 10)
            HandleSetAffineData(sprite, 256, 256, counter / 2 * 512);
        else if (counter >= 10 && counter <= 29)
            sprite->x2 = -(Sin(index, 5));
        else
            HandleSetAffineData(sprite, 256, 256, (35 - counter) / 2 * 1024);
    }

    sprite->data[2]++;
    TryFlipX(sprite);
}

static void Anim_HorizontalPivot(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
        HandleStartAffineAnim(sprite);

    if (sprite->data[2] > 100)
    {
        HandleSetAffineData(sprite, 256, 256, 0);
        sprite->y2 = 0;
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        s16 index = (sprite->data[2] * 256) / 100;
        sprite->y2 = Sin(index, 10);
        HandleSetAffineData(sprite, 256, 256, Sin(index, 3276));
    }

    sprite->data[2]++;
}

static void VerticalSlideWobble(struct Sprite *sprite)
{
    s32 var = 0;
    s16 index = 0;

    if (sprite->data[2] == 0)
        HandleStartAffineAnim(sprite);

    if (sprite->data[2] > 100)
    {
        HandleSetAffineData(sprite, 256, 256, 0);
        sprite->y2 = 0;
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        index = (sprite->data[2] * 256) / 100;
        var = (sprite->data[2] * 512) / 100;
        var &= 0xFF;
        sprite->y2 = Sin(index, sprite->data[0]);
        HandleSetAffineData(sprite, 256, 256, Sin(var, 3276));
    }

    sprite->data[2]++;
}

static void Anim_VerticalSlideWobble(struct Sprite *sprite)
{
    sprite->data[0] = 10;
    VerticalSlideWobble(sprite);
    sprite->callback = VerticalSlideWobble;
}

static void RisingWobble(struct Sprite *sprite)
{
    s32 var = 0;
    s16 index = 0;

    if (sprite->data[2] == 0)
        HandleStartAffineAnim(sprite);

    if (sprite->data[2] > 100)
    {
        HandleSetAffineData(sprite, 256, 256, 0);
        sprite->y2 = 0;
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        index = (sprite->data[2] * 256) / 100;
        var = (sprite->data[2] * 512) / 100;
        var &= 0xFF;
        sprite->y2 = -(Sin(index / 2, sprite->data[0] * 2));
        HandleSetAffineData(sprite, 256, 256, Sin(var, 3276));
    }

    sprite->data[2]++;
}

static void Anim_RisingWobble(struct Sprite *sprite)
{
    sprite->data[0] = 5;
    RisingWobble(sprite);
    sprite->callback = RisingWobble;
}

static void Anim_HorizontalSlideWobble(struct Sprite *sprite)
{
    s32 var;
    s16 index = 0;

    TryFlipX(sprite);
    var = 0;

    if (sprite->data[2] == 0)
        HandleStartAffineAnim(sprite);

    if (sprite->data[2] > 100)
    {
        HandleSetAffineData(sprite, 256, 256, 0);
        sprite->x2 = 0;
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        index = (sprite->data[2] * 256) / 100;
        var = (sprite->data[2] * 512) / 100;
        var &= 0xFF;
        sprite->x2 = Sin(index, 8);
        HandleSetAffineData(sprite, 256, 256, Sin(var, 3276));
    }

    sprite->data[2]++;
    TryFlipX(sprite);
}

static void VerticalSquishBounce(struct Sprite *sprite)
{
    s16 posY = 0;

    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[3] = 0;
    }

    TryFlipX(sprite);

    if (sprite->data[2] > sprite->data[0] * 3)
    {
        HandleSetAffineData(sprite, 256, 256, 0);
        sprite->y2 = 0;
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        s16 yScale = Sin(sprite->data[4], 32) + 256;

        if (sprite->data[2] > sprite->data[0] && sprite->data[2] < sprite->data[0] * 2)
            sprite->data[3] += (128 / sprite->data[0]);
        if (yScale > 256)
            posY = (256 - yScale) / 8;

        sprite->y2 = -(Sin(sprite->data[3], 10)) - posY;
        HandleSetAffineData(sprite, 256 - Sin(sprite->data[4], 32), yScale, 0);
        sprite->data[2]++;
        sprite->data[4] = (sprite->data[4] + 128 / sprite->data[0]) & 0xFF;
    }

    TryFlipX(sprite);
}

static void Anim_VerticalSquishBounce(struct Sprite *sprite)
{
    sprite->data[0] = 16;
    VerticalSquishBounce(sprite);
    sprite->callback = VerticalSquishBounce;
}

static void ShrinkGrow(struct Sprite *sprite)
{
    s16 posY = 0;

    if (sprite->data[2] > (128 / sprite->data[6]) * sprite->data[7])
    {
        HandleSetAffineData(sprite, 256, 256, 0);
        sprite->y2 = 0;
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        s16 yScale = Sin(sprite->data[4], 32) + 256;

        if (yScale > 256)
            posY = (256 - yScale) / 8;

        sprite->y2 = -(posY);
        HandleSetAffineData(sprite, Sin(sprite->data[4], 48) + 256, yScale, 0);
        sprite->data[2]++;
        sprite->data[4] = (sprite->data[4] + sprite->data[6]) & 0xFF;
    }
}

static void Anim_ShrinkGrow(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[7] = 3;
        sprite->data[6] = 8;
    }

    ShrinkGrow(sprite);
}

static const s8 sBounceRotateToSidesData[][8][3] =
{
    {
        { 0,  8,  8},
        { 8, -8, 12},
        {-8,  8, 12},
        { 8, -8, 12},
        {-8,  8, 12},
        { 8, -8, 12},
        {-8,  0, 12},
        { 0,  0,  0}
    },
    {
        { 0,  8, 16},
        { 8, -8, 24},
        {-8,  8, 24},
        { 8, -8, 24},
        {-8,  8, 24},
        { 8, -8, 24},
        {-8,  0, 24},
        { 0,  0,  0}
    },
};

static void BounceRotateToSides(struct Sprite *sprite)
{
    s16 var;
    u8 structId;
    s8 r9;
    s16 r10;
    s16 r7;
    u32 arrId;

    TryFlipX(sprite);
    structId = sprite->data[0];
    var = sAnims[structId].rotation;
    r9 = sBounceRotateToSidesData[sAnims[structId].data][sprite->data[4]][0];
    r10 = sBounceRotateToSidesData[sAnims[structId].data][sprite->data[4]][1] - r9;
    arrId = sAnims[structId].data;
    r7 = sprite->data[3];

    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[2]++;
    }

    if (sBounceRotateToSidesData[arrId][sprite->data[4]][2] == 0)
    {
        HandleSetAffineData(sprite, 256, 256, 0);
        sprite->x2 = 0;
        sprite->y2 = 0;
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        u16 rotation;

        sprite->y2 = -(Sin(r7 * 128 / sBounceRotateToSidesData[arrId][sprite->data[4]][2], 10));
        sprite->x2 = (r10 * r7 / sBounceRotateToSidesData[arrId][sprite->data[4]][2]) + r9;

        rotation = -(var * sprite->x2) / 8;
        HandleSetAffineData(sprite, 256, 256, rotation);

        if (r7 == sBounceRotateToSidesData[arrId][sprite->data[4]][2])
        {
            sprite->data[4]++;
            sprite->data[3] = 0;
        }
        else
        {
            sprite->data[3]++;
        }
    }

    TryFlipX(sprite);
}

static void Anim_BounceRotateToSides(struct Sprite *sprite)
{
    u8 id = sprite->data[0] = AddNewAnim();
    sAnims[id].rotation = 4096;
    sAnims[id].data = sprite->data[6];
    BounceRotateToSides(sprite);
    sprite->callback = BounceRotateToSides;
}

static void Anim_GlowOrange(struct Sprite *sprite)
{
    GlowColor(RGB(31, 22, 0), 12, 2);
}

static void Anim_GlowRed(struct Sprite *sprite)
{
    GlowColor(RGB_RED, 12, 2);
}

static void Anim_GlowBlue(struct Sprite *sprite)
{
    GlowColor(RGB_BLUE, 12, 2);
}

static void Anim_GlowYellow(struct Sprite *sprite)
{
    GlowColor(RGB_YELLOW, 12, 2);
}

static void Anim_GlowPurple(struct Sprite *sprite)
{
    GlowColor(RGB(24, 0, 24), 12, 2);
}

static void BackAndLunge_0(struct Sprite *sprite);
static void BackAndLunge_1(struct Sprite *sprite);
static void BackAndLunge_2(struct Sprite *sprite);
static void BackAndLunge_3(struct Sprite *sprite);
static void BackAndLunge_4(struct Sprite *sprite);

static void Anim_BackAndLunge(struct Sprite *sprite)
{
    HandleStartAffineAnim(sprite);
    sprite->callback = BackAndLunge_0;
}

static void BackAndLunge_0(struct Sprite *sprite)
{
    TryFlipX(sprite);
    if (++sprite->x2 > 7)
    {
        sprite->x2 = 8;
        sprite->data[7] = 2;
        sprite->callback = BackAndLunge_1;
    }
    TryFlipX(sprite);
}

static void BackAndLunge_1(struct Sprite *sprite)
{
    TryFlipX(sprite);

    sprite->x2 -= sprite->data[7];
    sprite->data[7]++;
    if (sprite->x2 <= 0)
    {
        s16 subResult;
        u8 var = sprite->data[7];
        sprite->data[6] = 0;
        subResult = sprite->x2;

        do
        {
            subResult -= var;
            sprite->data[6]++;
            var++;
        }
        while (subResult > -8);

        sprite->data[5] = 1;
        sprite->callback = BackAndLunge_2;
    }

    TryFlipX(sprite);
}

static void BackAndLunge_2(struct Sprite *sprite)
{
    u8 rotation;

    TryFlipX(sprite);
    sprite->x2 -= sprite->data[7];
    sprite->data[7]++;
    rotation = (sprite->data[5] * 6) / sprite->data[6];

    if (++sprite->data[5] > sprite->data[6])
        sprite->data[5] = sprite->data[6];

    HandleSetAffineData(sprite, 256, 256, rotation * 256);

    if (sprite->x2 < -8)
    {
        sprite->x2 = -8;
        sprite->data[4] = 2;
        sprite->data[3] = 0;
        sprite->data[2] = rotation;
        sprite->callback = BackAndLunge_3;
    }

    TryFlipX(sprite);
}

static void BackAndLunge_3(struct Sprite *sprite)
{
    TryFlipX(sprite);

    if (sprite->data[3] > 11)
    {
        sprite->data[2] -= 2;
        if (sprite->data[2] < 0)
            sprite->data[2] = 0;

        HandleSetAffineData(sprite, 256, 256, sprite->data[2] << 8);
        if (sprite->data[2] == 0)
            sprite->callback = BackAndLunge_4;
    }
    else
    {
        sprite->x2 += sprite->data[4];
        sprite->data[4] *= -1;
        sprite->data[3]++;
    }

    TryFlipX(sprite);
}

static void BackAndLunge_4(struct Sprite *sprite)
{
    TryFlipX(sprite);

    sprite->x2 += 2;
    if (sprite->x2 > 0)
    {
        sprite->x2 = 0;
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
    }

    TryFlipX(sprite);
}

static void BackFlip_0(struct Sprite *sprite);
static void BackFlip_1(struct Sprite *sprite);
static void BackFlip_2(struct Sprite *sprite);

static void Anim_BackFlip(struct Sprite *sprite)
{
    HandleStartAffineAnim(sprite);
    sprite->data[3] = 0;
    sprite->callback = BackFlip_0;
}

static void BackFlip_0(struct Sprite *sprite)
{
    TryFlipX(sprite);
    sprite->x2++;
    sprite->y2--;

    if (sprite->x2 % 2 == 0 && sprite->data[3] <= 0)
        sprite->data[3] = 10;
    if (sprite->x2 > 7)
    {
        sprite->x2 = 8;
        sprite->y2 = -8;
        sprite->data[4] = 0;
        sprite->callback = BackFlip_1;
    }

    TryFlipX(sprite);
}

static void BackFlip_1(struct Sprite *sprite)
{
    TryFlipX(sprite);
    sprite->x2 = Cos(sprite->data[4], 16) - 8;
    sprite->y2 = Sin(sprite->data[4], 16) - 8;

    if (sprite->data[4] > 63)
    {
        sprite->data[2] = 160;
        sprite->data[3] = 10;
        sprite->callback = BackFlip_2;
    }
    sprite->data[4] += 8;
    if (sprite->data[4] > 64)
        sprite->data[4] = 64;

    TryFlipX(sprite);
}

static void BackFlip_2(struct Sprite *sprite)
{
    TryFlipX(sprite);

    if (sprite->data[3] > 0)
    {
        sprite->data[3]--;
    }
    else
    {
        u32 rotation;

        sprite->x2 = Cos(sprite->data[2], 5) - 4;
        sprite->y2 = -(Sin(sprite->data[2], 5)) + 4;
        sprite->data[2] -= 4;
        rotation = sprite->data[2] - 32;
        HandleSetAffineData(sprite, 256, 256, rotation * 512);

        if (sprite->data[2] <= 32)
        {
            sprite->x2 = 0;
            sprite->y2 = 0;
            ResetSpriteAfterAnim(sprite);
            sprite->callback = WaitAnimEnd;
        }
    }

    TryFlipX(sprite);
}

static void Anim_Flicker(struct Sprite *sprite)
{
    if (sprite->data[3] > 0)
    {
        sprite->data[3]--;
    }
    else
    {
        sprite->data[4] = (sprite->data[4] == 0) ? TRUE : FALSE;
        sprite->invisible = sprite->data[4];
        if (++sprite->data[2] > 19)
        {
            sprite->invisible = FALSE;
            sprite->callback = WaitAnimEnd;
        }
        sprite->data[3] = 2;
    }
}

static void BackFlipBig_0(struct Sprite *sprite);
static void BackFlipBig_1(struct Sprite *sprite);
static void BackFlipBig_2(struct Sprite *sprite);

static void Anim_BackFlipBig(struct Sprite *sprite)
{
    HandleStartAffineAnim(sprite);
    sprite->callback = BackFlipBig_0;
}

static void BackFlipBig_0(struct Sprite *sprite)
{
    TryFlipX(sprite);
    sprite->x2--;
    sprite->y2++;

    if (sprite->x2 <= -16)
    {
        sprite->x2 = -16;
        sprite->y2 = 16;
        sprite->callback = BackFlipBig_1;
        sprite->data[2] = 160;
    }

    TryFlipX(sprite);
}

static void BackFlipBig_1(struct Sprite *sprite)
{
    u32 rotation;

    TryFlipX(sprite);
    sprite->data[2] -= 4;
    sprite->x2 = Cos(sprite->data[2], 22);
    sprite->y2 = -(Sin(sprite->data[2], 22));
    rotation = sprite->data[2] - 32;
    HandleSetAffineData(sprite, 256, 256, rotation * 512);

    if (sprite->data[2] <= 32)
        sprite->callback = BackFlipBig_2;

    TryFlipX(sprite);
}

static void BackFlipBig_2(struct Sprite *sprite)
{
    TryFlipX(sprite);
    sprite->x2--;
    sprite->y2++;

    if (sprite->x2 <= 0)
    {
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
    }

    TryFlipX(sprite);
}

static void FrontFlip_0(struct Sprite *sprite);
static void FrontFlip_1(struct Sprite *sprite);
static void FrontFlip_2(struct Sprite *sprite);

static void Anim_FrontFlip(struct Sprite *sprite)
{
    HandleStartAffineAnim(sprite);
    sprite->callback = FrontFlip_0;
}

static void FrontFlip_0(struct Sprite *sprite)
{
    TryFlipX(sprite);
    sprite->x2++;
    sprite->y2--;

    if (sprite->x2 > 15)
    {
        sprite->data[2] = 0;
        sprite->callback = FrontFlip_1;
    }

    TryFlipX(sprite);
}

static void FrontFlip_1(struct Sprite *sprite)
{
    TryFlipX(sprite);
    sprite->data[2] += 16;

    if (sprite->x2 <= -16)
    {
        sprite->x2 = -16;
        sprite->y2 = 16;
        sprite->data[2] = 0;
        sprite->callback = FrontFlip_2;
    }
    else
    {
        sprite->x2 -= 2;
        sprite->y2 += 2;
    }

    HandleSetAffineData(sprite, 256, 256, sprite->data[2] << 8);
    TryFlipX(sprite);
}

static void FrontFlip_2(struct Sprite *sprite)
{
    TryFlipX(sprite);
    sprite->x2++;
    sprite->y2--;;

    if (sprite->x2 >= 0)
    {
        sprite->x2 = 0;
        sprite->y2 = 0;
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
    }

    TryFlipX(sprite);
}

static void TumblingFrontFlip(struct Sprite *sprite);

static void Anim_TumblingFrontFlip(struct Sprite *sprite)
{
    u8 id = sprite->data[0] = AddNewAnim();
    sAnims[id].speed = 2;
    TumblingFrontFlip(sprite);
    sprite->callback = TumblingFrontFlip;
}

static void TumblingFrontFlip(struct Sprite *sprite)
{
    if (sAnims[sprite->data[0]].delay != 0)
    {
        sAnims[sprite->data[0]].delay--;
    }
    else
    {
        TryFlipX(sprite);
        if (sprite->data[2] == 0)
        {
            sprite->data[2]++;
            HandleStartAffineAnim(sprite);
            sprite->data[7] = sAnims[sprite->data[0]].speed;
            sprite->data[3] = -1;
            sprite->data[4] = -1;
            sprite->data[5] = 0;
            sprite->data[6] = 0;
        }

        sprite->x2 += (sprite->data[7] * 2 * sprite->data[3]);
        sprite->y2 += (sprite->data[7] * sprite->data[4]);
        sprite->data[6] += 8;
        if (sprite->x2 <= -16 || sprite->x2 >= 16)
        {
            sprite->x2 = sprite->data[3] * 16;
            sprite->data[3] *= -1;
            sprite->data[5]++;
        }
        else if (sprite->y2 <= -16 || sprite->y2 >= 16)
        {
            sprite->y2 = sprite->data[4] * 16;
            sprite->data[4] *= -1;
            sprite->data[5]++;
        }

        if (sprite->data[5] > 5 && sprite->x2 <= 0)
        {
            sprite->x2 = 0;
            sprite->y2 = 0;
            if (sAnims[sprite->data[0]].runs > 1)
            {
                sAnims[sprite->data[0]].runs--;
                sprite->data[5] = 0;
                sprite->data[6] = 0;
                sAnims[sprite->data[0]].delay = 10;
            }
            else
            {
                ResetSpriteAfterAnim(sprite);
                sprite->callback = WaitAnimEnd;
            }
        }

        HandleSetAffineData(sprite, 256, 256, sprite->data[6] << 8);
        TryFlipX(sprite);
    }
}

static void Figure8(struct Sprite *sprite);

static void Anim_Figure8(struct Sprite *sprite)
{
    HandleStartAffineAnim(sprite);
    sprite->data[6] = 0;
    sprite->data[7] = 0;
    sprite->callback = Figure8;
}

static void Figure8(struct Sprite *sprite)
{
    TryFlipX(sprite);
    sprite->data[6] += 4;
    sprite->x2 = -(Sin(sprite->data[6], 16));
    sprite->y2 = -(Sin((sprite->data[6] * 2) & 0xFF, 8));
    if (sprite->data[6] > 192 && sprite->data[7] == 1)
    {
        HandleSetAffineData(sprite, 256, 256, 0);
        sprite->data[7]++;
    }
    else if (sprite->data[6] > 64 && sprite->data[7] == 0)
    {
        HandleSetAffineData(sprite, -256, 256, 0);
        sprite->data[7]++;
    }

    if (sprite->data[6] > 255)
    {
        sprite->x2 = 0;
        sprite->y2 = 0;
        HandleSetAffineData(sprite, 256, 256, 0);
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
    }
    TryFlipX(sprite);
}

static void Anim_FlashYellow(struct Sprite *sprite)
{
    if (++sprite->data[2] == 1)
    {
        sprite->data[7] = OBJ_PLTT_ID(sprite->oam.paletteNum);
        sprite->data[6] = 0;
        sprite->data[5] = 0;
        sprite->data[4] = 0;
    }

    if (sYellowFlashData[sprite->data[6]][1] == (u8)-1)
    {
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        if (sprite->data[4] == 1)
        {
            if (sYellowFlashData[sprite->data[6]][0])
                BlendPalette(sprite->data[7], 16, 16, RGB_YELLOW);
            else
                BlendPalette(sprite->data[7], 16, 0, RGB_YELLOW);

            sprite->data[4] = 0;
        }

        if (sYellowFlashData[sprite->data[6]][1] == sprite->data[5])
        {
            sprite->data[4] = 1;
            sprite->data[5] = 0;
            sprite->data[6]++;
        }
        else
        {
            sprite->data[5]++;
        }
    }
}

static void SwingConcave(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
        HandleStartAffineAnim(sprite);

    TryFlipX(sprite);
    if (sprite->data[2] > sAnims[sprite->data[0]].data)
    {
        HandleSetAffineData(sprite, 256, 256, 0);
        sprite->x2 = 0;
        if (sAnims[sprite->data[0]].runs > 1)
        {
            sAnims[sprite->data[0]].runs--;
            sprite->data[2] = 0;
        }
        else
        {
            ResetSpriteAfterAnim(sprite);
            sprite->callback = WaitAnimEnd;
        }
    }
    else
    {
        s16 index = (sprite->data[2] * 256) / sAnims[sprite->data[0]].data;
        sprite->x2 = -(Sin(index, 10));
        HandleSetAffineData(sprite, 256, 256, Sin(index, 3276));
    }

    sprite->data[2]++;
    TryFlipX(sprite);
}

static void Anim_SwingConcave_FastShort(struct Sprite *sprite)
{
    u8 id = sprite->data[0] = AddNewAnim();
    sAnims[id].data = 50;
    SwingConcave(sprite);
    sprite->callback = SwingConcave;
}

static void SwingConvex(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
        HandleStartAffineAnim(sprite);

    TryFlipX(sprite);
    if (sprite->data[2] > sAnims[sprite->data[0]].data)
    {
        HandleSetAffineData(sprite, 256, 256, 0);
        sprite->x2 = 0;
        if (sAnims[sprite->data[0]].runs > 1)
        {
            sAnims[sprite->data[0]].runs--;
            sprite->data[2] = 0;
        }
        else
        {
            ResetSpriteAfterAnim(sprite);
            sprite->callback = WaitAnimEnd;
        }
    }
    else
    {
        s16 index = (sprite->data[2] * 256) / sAnims[sprite->data[0]].data;
        sprite->x2 = -(Sin(index, 10));
        HandleSetAffineData(sprite, 256, 256, -(Sin(index, 3276)));
    }

    sprite->data[2]++;
    TryFlipX(sprite);
}

static void Anim_SwingConvex_FastShort(struct Sprite *sprite)
{
    u8 id = sprite->data[0] = AddNewAnim();
    sAnims[id].data = 50;
    SwingConvex(sprite);
    sprite->callback = SwingConvex;
}

static void RotateUpSlamDown_0(struct Sprite *sprite);
static void RotateUpSlamDown_1(struct Sprite *sprite);
static void RotateUpSlamDown_2(struct Sprite *sprite);

static void Anim_RotateUpSlamDown(struct Sprite *sprite)
{
    HandleStartAffineAnim(sprite);
    sprite->data[6] = -(14 * sprite->centerToCornerVecX / 10);
    sprite->data[7] = 128;
    sprite->callback = RotateUpSlamDown_0;
}

static void RotateUpSlamDown_0(struct Sprite *sprite)
{
    TryFlipX(sprite);
    sprite->data[7]--;
    sprite->x2 = sprite->data[6] + Cos(sprite->data[7], sprite->data[6]);

    sprite->y2 = -(Sin(sprite->data[7], sprite->data[6]));

    HandleSetAffineData(sprite, 256, 256, (sprite->data[7] - 128) << 8);
    if (sprite->data[7] <= 120)
    {
        sprite->data[7] = 120;
        sprite->data[3] = 0;
        sprite->callback = RotateUpSlamDown_1;
    }

    TryFlipX(sprite);
}

static void RotateUpSlamDown_1(struct Sprite *sprite)
{
    if (sprite->data[3] == 20)
    {
        sprite->callback = RotateUpSlamDown_2;
        sprite->data[3] = 0;
    }

    sprite->data[3]++;
}

static void RotateUpSlamDown_2(struct Sprite *sprite)
{
    TryFlipX(sprite);
    sprite->data[7] += 2;
    sprite->x2 = sprite->data[6] + Cos(sprite->data[7], sprite->data[6]);

    sprite->y2 = -(Sin(sprite->data[7], sprite->data[6]));

    HandleSetAffineData(sprite, 256, 256, (sprite->data[7] - 128) << 8);
    if (sprite->data[7] >= 128)
    {
        sprite->x2 = 0;
        sprite->y2 = 0;
        HandleSetAffineData(sprite, 256, 256, 0);
        sprite->data[2] = 0;
        ResetSpriteAfterAnim(sprite);
        sprite->callback = Anim_VerticalShake;
    }

    TryFlipX(sprite);
}

static void DeepVerticalSquishBounce(struct Sprite *sprite)
{
    if (sAnims[sprite->data[0]].delay != 0)
    {
        sAnims[sprite->data[0]].delay--;
    }
    else
    {
        if (sprite->data[2] == 0)
        {
            HandleStartAffineAnim(sprite);
            sprite->data[4] = 0;
            sprite->data[5] = 0;
            sprite->data[2] = 1;
        }

        if (sprite->data[5] == 0)
        {
            sprite->data[7] = Sin(sprite->data[4], 256);
            sprite->y2 = Sin(sprite->data[4], 16);
            sprite->data[6] = Sin(sprite->data[4], 32);
            HandleSetAffineData(sprite, 256 - sprite->data[6], 256 + sprite->data[7], 0);
            if (sprite->data[4] == 128)
            {
                sprite->data[4] = 0;
                sprite->data[5] = 1;
            }
        }
        else if (sprite->data[5] == 1)
        {
            sprite->data[7] = Sin(sprite->data[4], 32);
            sprite->y2 = -(Sin(sprite->data[4], 8));
            sprite->data[6] = Sin(sprite->data[4], 128);
            HandleSetAffineData(sprite, 256 + sprite->data[6], 256 - sprite->data[7], 0);
            if (sprite->data[4] == 128)
            {
                if (sAnims[sprite->data[0]].runs > 1)
                {
                    sAnims[sprite->data[0]].runs--;
                    sAnims[sprite->data[0]].delay = 10;
                    sprite->data[4] = 0;
                    sprite->data[5] = 0;
                }
                else
                {
                    HandleSetAffineData(sprite, 256, 256, 0);
                    ResetSpriteAfterAnim(sprite);
                    sprite->callback = WaitAnimEnd;
                }
            }
        }

        sprite->data[4] += sAnims[sprite->data[0]].rotation;
    }
}

static void Anim_DeepVerticalSquishBounce(struct Sprite *sprite)
{
    u8 id = sprite->data[0] = AddNewAnim();
    sAnims[id].rotation = 4;
    DeepVerticalSquishBounce(sprite);
    sprite->callback = DeepVerticalSquishBounce;
}

static void Anim_HorizontalJumps(struct Sprite *sprite)
{
    s32 counter = sprite->data[2];
    TryFlipX(sprite);
    if (counter > 512)
    {
        sprite->callback = WaitAnimEnd;
        sprite->x2 = 0;
        sprite->y2 = 0;
    }
    else
    {
        switch (sprite->data[2] / 128)
        {
        case 0:
            sprite->x2 = -(counter % 128 * 8) / 128;
            break;
        case 1:
            sprite->x2 = (counter % 128 / 16) - 8;
            break;
        case 2:
            sprite->x2 = (counter % 128 / 16);
            break;
        case 3:
            sprite->x2 = -(counter % 128 * 8) / 128 + 8;
            break;
        }

        sprite->y2 = -(Sin(counter % 128, 8));
    }

    sprite->data[2] += 12;
    TryFlipX(sprite);
}

static void HorizontalJumpsVerticalStretch_0(struct Sprite *sprite);
static void HorizontalJumpsVerticalStretch_1(struct Sprite *sprite);
static void HorizontalJumpsVerticalStretch_2(struct Sprite *sprite);

static void Anim_HorizontalJumpsVerticalStretch(struct Sprite *sprite)
{
    u8 id = sprite->data[0] = AddNewAnim();
    sAnims[id].data = -1;
    HandleStartAffineAnim(sprite);
    sprite->data[3] = 0;
    HorizontalJumpsVerticalStretch_0(sprite);
    sprite->callback = HorizontalJumpsVerticalStretch_0;
}

static void HorizontalJumpsVerticalStretch_0(struct Sprite *sprite)
{
    if (sAnims[sprite->data[0]].delay != 0)
    {
        sAnims[sprite->data[0]].delay--;
    }
    else
    {
        s32 counter;

        TryFlipX(sprite);
        counter = sprite->data[2];
        if (sprite->data[2] > 128)
        {
            sprite->data[2] = 0;
            sprite->callback = HorizontalJumpsVerticalStretch_1;
        }
        else
        {
            s32 var = 8 * sAnims[sprite->data[0]].data;
            sprite->x2 = var * (counter % 128) / 128;
            sprite->y2 = -(Sin(counter % 128, 8));
            sprite->data[2] += 12;
        }

        TryFlipX(sprite);
    }
}

static void HorizontalJumpsVerticalStretch_1(struct Sprite *sprite)
{
    TryFlipX(sprite);
    if (sprite->data[2] > 48)
    {
        HandleSetAffineData(sprite, 256, 256, 0);
        sprite->y2 = 0;
        sprite->data[2] = 0;
        sprite->callback = HorizontalJumpsVerticalStretch_2;
    }
    else
    {
        s16 yDelta;
        s16 yScale = Sin(sprite->data[4], 64) + 256;
        if (sprite->data[2] >= 16 && sprite->data[2] <= 31)
        {
            sprite->data[3] += 8;
            sprite->x2 -= sAnims[sprite->data[0]].data;
        }

        yDelta = 0;
        if (yScale > 256)
            yDelta = (256 - yScale) / 8;

        sprite->y2 = -(Sin(sprite->data[3], 20)) - yDelta;
        HandleSetAffineData(sprite, 256 - Sin(sprite->data[4], 32), yScale, 0);
        sprite->data[2]++;
        sprite->data[4] += 8;
        sprite->data[4] &= 0xFF;
    }

    TryFlipX(sprite);
}

static void HorizontalJumpsVerticalStretch_2(struct Sprite *sprite)
{
    s32 counter;

    TryFlipX(sprite);
    counter = sprite->data[2];
    if (counter > 128)
    {
        if (sAnims[sprite->data[0]].runs > 1)
        {
            sAnims[sprite->data[0]].runs--;
            sAnims[sprite->data[0]].delay = 10;
            sprite->data[3] = 0;
            sprite->data[2] = 0;
            sprite->data[4] = 0;
            sprite->callback = HorizontalJumpsVerticalStretch_0;
        }
        else
        {
            ResetSpriteAfterAnim(sprite);
            sprite->callback = WaitAnimEnd;
        }

        sprite->x2 = 0;
        sprite->y2 = 0;
    }
    else
    {
        s32 var = sAnims[sprite->data[0]].data;

        sprite->x2 = var * ((counter % 128) * 8) / 128 + 8 * -var;
        sprite->y2 = -(Sin(counter % 128, 8));
    }

    sprite->data[2] += 12;
    TryFlipX(sprite);
}

static void RotateToSides(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[2]++;
    }

    TryFlipX(sprite);
    if (sprite->data[7] > 254)
    {
        sprite->x2 = 0;
        sprite->y2 = 0;
        HandleSetAffineData(sprite, 256, 256, 0);
        if (sAnims[sprite->data[0]].runs > 1)
        {
            sAnims[sprite->data[0]].runs--;
            sprite->data[2] = 0;
            sprite->data[7] = 0;
        }
        else
        {
            ResetSpriteAfterAnim(sprite);
            sprite->callback = WaitAnimEnd;
        }

        TryFlipX(sprite);
    }
    else
    {
        u16 rotation;

        sprite->x2 = -(Sin(sprite->data[7], 16));
        rotation = Sin(sprite->data[7], 32);
        HandleSetAffineData(sprite, 256, 256, rotation << 8);
        sprite->data[7] += sAnims[sprite->data[0]].rotation;
        TryFlipX(sprite);
    }
}

static void Anim_RotateToSides_Fast(struct Sprite *sprite)
{
    u8 id = sprite->data[0] = AddNewAnim();
    sAnims[id].rotation = 4;
    RotateToSides(sprite);
    sprite->callback = RotateToSides;
}

static void Anim_RotateUpToSides(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[2]++;
    }

    TryFlipX(sprite);
    if (sprite->data[7] > 254)
    {
        sprite->x2 = 0;
        sprite->y2 = 0;
        HandleSetAffineData(sprite, 256, 256, 0);
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
        TryFlipX(sprite);
    }
    else
    {
        u16 rotation;

        sprite->x2 = -(Sin(sprite->data[7], 16));
        sprite->y2 = -(Sin(sprite->data[7] % 128, 16));
        rotation = Sin(sprite->data[7], 32);
        HandleSetAffineData(sprite, 256, 256, rotation << 8);
        sprite->data[7] += 8;
        TryFlipX(sprite);
    }
}

static void Anim_FlickerIncreasing(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
        sprite->data[7] = 0;

    if (sprite->data[2] == sprite->data[7])
    {
        sprite->data[7] = 0;
        sprite->data[2]++;
        sprite->invisible = FALSE;
    }
    else
    {
        sprite->data[7]++;
        sprite->invisible = TRUE;
    }

    if (sprite->data[2] > 10)
    {
        sprite->invisible = FALSE;
        sprite->callback = WaitAnimEnd;
    }
}

static void TipHopForward_0(struct Sprite *sprite);
static void TipHopForward_1(struct Sprite *sprite);
static void TipHopForward_2(struct Sprite *sprite);

static void Anim_TipHopForward(struct Sprite *sprite)
{
    HandleStartAffineAnim(sprite);
    sprite->data[7] = 0;
    sprite->callback = TipHopForward_0;
}

static void TipHopForward_0(struct Sprite *sprite)
{
    if (sprite->data[7] > 31)
    {
        sprite->data[7] = 32;
        sprite->data[2] = 0;
        sprite->callback = TipHopForward_1;
    }
    else
    {
        sprite->data[7] += 4;
    }

    HandleSetAffineData(sprite, 256, 256, sprite->data[7] << 8);
}

static void TipHopForward_1(struct Sprite *sprite)
{
    TryFlipX(sprite);
    if (sprite->data[2] > 512)
    {
        sprite->callback = TipHopForward_2;
        sprite->data[6] = 0;
    }
    else
    {
        sprite->x2 = -(sprite->data[2] * 16) / 512;
        sprite->y2 = -(Sin(sprite->data[2] % 128, 4));
        sprite->data[2] += 12;
    }

    TryFlipX(sprite);
}

static void TipHopForward_2(struct Sprite *sprite)
{
    TryFlipX(sprite);
    sprite->data[7] -= 2;
    if (sprite->data[7] < 0)
    {
        sprite->data[7] = 0;
        sprite->x2 = 0;
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        sprite->x2 = -(Sin(sprite->data[7] * 2, 16));
    }

    HandleSetAffineData(sprite, 256, 256, sprite->data[7] << 8);
    TryFlipX(sprite);
}

static void Anim_PivotShake(struct Sprite *sprite)
{
    u16 rotation;

    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[2]++;
        sprite->data[7] = 0;
    }

    TryFlipX(sprite);
    if (sprite->data[7] > 255)
    {
        sprite->x2 = 0;
        sprite->y2 = 0;
        sprite->data[7] = 0;
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        sprite->data[7] += 16;
        sprite->x2 = -(Sin(sprite->data[7] % 128, 8));
        sprite->y2 = -(Sin(sprite->data[7] % 128, 8));
    }

    rotation = Sin(sprite->data[7] % 128, 16);
    HandleSetAffineData(sprite, 256, 256, rotation << 8);
    TryFlipX(sprite);
}

static void TipAndShake_0(struct Sprite *sprite);
static void TipAndShake_1(struct Sprite *sprite);
static void TipAndShake_2(struct Sprite *sprite);
static void TipAndShake_3(struct Sprite *sprite);

static void Anim_TipAndShake(struct Sprite *sprite)
{
    HandleStartAffineAnim(sprite);
    sprite->data[7] = 0;
    sprite->data[4] = 0;
    sprite->callback = TipAndShake_0;
}

static void TipAndShake_0(struct Sprite *sprite)
{
    TryFlipX(sprite);
    if (sprite->data[7] > 24)
    {
        if (++sprite->data[4] > 4)
        {
            sprite->data[4] = 0;
            sprite->callback = TipAndShake_1;
        }
    }
    else
    {
        sprite->data[7] += 2;
        sprite->x2 = Sin(sprite->data[7], 8);
        sprite->y2 = -(Sin(sprite->data[7], 8));
    }

    HandleSetAffineData(sprite, 256, 256, -(sprite->data[7]) << 8);
    TryFlipX(sprite);
}

static void TipAndShake_1(struct Sprite *sprite)
{
    TryFlipX(sprite);
    if (sprite->data[7] > 32)
    {
        sprite->data[6] = 1;
        sprite->callback = TipAndShake_2;
    }
    else
    {
        sprite->data[7] += 2;
        sprite->x2 = Sin(sprite->data[7], 8);
        sprite->y2 = -(Sin(sprite->data[7], 8));
    }

    HandleSetAffineData(sprite, 256, 256, -(sprite->data[7]) << 8);
    TryFlipX(sprite);
}

static void TipAndShake_2(struct Sprite *sprite)
{
    TryFlipX(sprite);
    sprite->data[7] += (sprite->data[6] * 4);
    if (sprite->data[5] > 9)
    {
        sprite->data[7] = 32;
        sprite->callback = TipAndShake_3;
    }

    sprite->x2 = Sin(sprite->data[7], 8);
    sprite->y2 = -(Sin(sprite->data[7], 8));
    if (sprite->data[7] <= 28 || sprite->data[7] >= 36)
    {
        sprite->data[6] *= -1;
        sprite->data[5]++;
    }

    HandleSetAffineData(sprite, 256, 256, -(sprite->data[7]) << 8);
    TryFlipX(sprite);
}

static void TipAndShake_3(struct Sprite *sprite)
{
    TryFlipX(sprite);
    if (sprite->data[7] <= 0)
    {
        sprite->data[7] = 0;
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        sprite->data[7] -= 2;
        sprite->x2 = Sin(sprite->data[7], 8);
        sprite->y2 = -(Sin(sprite->data[7], 8));
    }

    HandleSetAffineData(sprite, 256, 256, -(sprite->data[7]) << 8);
    TryFlipX(sprite);
}

static void Anim_VibrateToCorners(struct Sprite *sprite)
{
    TryFlipX(sprite);
    if (sprite->data[2] > 40)
    {
        sprite->callback = WaitAnimEnd;
        sprite->x2 = 0;
    }
    else
    {
        s8 sign;
        if (!(sprite->data[2] & 1))
            sign = 1;
        else
            sign = -1;

        if ((sprite->data[2] % 4) / 2 == 0)
        {
            sprite->x2 = Sin((sprite->data[2] * 128 / 40) % 256, 16) * sign;
            sprite->y2 = -(sprite->x2);
        }
        else
        {
            sprite->x2 = -(Sin((sprite->data[2] * 128 / 40) % 256, 16)) * sign;
            sprite->y2 = sprite->x2;
        }
    }

    sprite->data[2]++;
    TryFlipX(sprite);
}

static void Anim_GrowInStages(struct Sprite *sprite)
{
    TryFlipX(sprite);
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[5] = 0;
        sprite->data[6] = 0;
        sprite->data[7] = 0;
        sprite->data[2]++;
    }

    if (sprite->data[6] > 0)
    {
        sprite->data[6]--;
        if (sprite->data[5] != 3)
        {
            s16 scale = (8 * sprite->data[6]) / 20;
            scale = Sin(sprite->data[7] - scale, 64);
            HandleSetAffineData(sprite, 256 - scale, 256 - scale, 0);
        }
    }
    else
    {
        s16 var;

        if (sprite->data[5] == 3)
        {
            if (sprite->data[7] > 63)
            {
                sprite->data[7] = 64;
                HandleSetAffineData(sprite, 256, 256, 0);
                ResetSpriteAfterAnim(sprite);
                sprite->callback = WaitAnimEnd;
            }
            var = Cos(sprite->data[7], 64);
        }
        else
        {
            var = Sin(sprite->data[7], 64);
            if (sprite->data[7] > 63)
            {
                sprite->data[5] = 3;
                sprite->data[6] = 10;
                sprite->data[7] = 0;
            }
            else
            {
                if (var > 48 && sprite->data[5] == 1)
                {
                    sprite->data[5] = 2;
                    sprite->data[6] = 20;
                }
                else if (var > 16 && sprite->data[5] == 0)
                {
                    sprite->data[5] = 1;
                    sprite->data[6] = 20;
                }
            }
        }

        sprite->data[7] += 2;
        HandleSetAffineData(sprite, 256 - var, 256 - var, 0);
    }

    TryFlipX(sprite);
}

static void Anim_VerticalSpring(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[2]++;
        sprite->data[7] = 0;
    }

    if (sprite->data[7] > 512)
    {
        sprite->y2 = 0;
        HandleSetAffineData(sprite, 256, 256, 0);
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        s16 yScale;

        sprite->y2 = Sin(sprite->data[7] % 256, 8);
        sprite->data[7] += 8;
        yScale = Sin(sprite->data[7] % 128, 96);
        HandleSetAffineData(sprite, 256, yScale + 256, 0);
    }
}

static void Anim_VerticalRepeatedSpring(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[2]++;
        sprite->data[7] = 0;
    }

    if (sprite->data[7] > 256)
    {
        sprite->y2 = 0;
        HandleSetAffineData(sprite, 256, 256, 0);
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        s16 yScale;

        sprite->y2 = Sin(sprite->data[7], 16);
        sprite->data[7] += 4;
        yScale = Sin((sprite->data[7] % 64) * 2, 128);
        HandleSetAffineData(sprite, 256, yScale + 256, 0);
    }
}

static void SpringRising_0(struct Sprite *sprite);
static void SpringRising_1(struct Sprite *sprite);
static void SpringRising_2(struct Sprite *sprite);

static void Anim_SpringRising(struct Sprite *sprite)
{
    HandleStartAffineAnim(sprite);
    sprite->callback = SpringRising_0;
    sprite->data[7] = 0;
}

static void SpringRising_0(struct Sprite *sprite)
{
    s16 yScale;

    sprite->data[7] += 8;
    if (sprite->data[7] > 63)
    {
        sprite->data[7] = 0;
        sprite->data[6] = 0;
        sprite->callback = SpringRising_1;
        yScale = Sin(64, 128); // 128 * 1 = 128
    }
    else
    {
        yScale = Sin(sprite->data[7], 128);
    }

    HandleSetAffineData(sprite, 256, 256 + yScale, 0);
}

static void SpringRising_1(struct Sprite *sprite)
{
    s16 yScale;

    sprite->data[7] += 4;
    if (sprite->data[7] > 95)
    {
        yScale = Cos(0, 128); // 128 * (-1) = -128
        sprite->data[7] = 0;
        sprite->data[6]++;
    }
    else
    {
        s16 sign, index;

        sprite->y2 = -(sprite->data[6] * 4) - Sin(sprite->data[7], 8);
        if (sprite->data[7] > 63)
        {
            sign = -1;
            index = sprite->data[7] - 64;
        }
        else
        {
            sign = 1;
            index = 0;
        }

        yScale = Cos((index * 2) + sprite->data[7], 128) * sign;
    }

    HandleSetAffineData(sprite, 256, 256 + yScale, 0);
    if (sprite->data[6] == 3)
    {
        sprite->data[7] = 0;
        sprite->callback = SpringRising_2;
    }
}

static void SpringRising_2(struct Sprite *sprite)
{
    s16 yScale;

    sprite->data[7] += 8;
    yScale = Cos(sprite->data[7], 128);
    sprite->y2 = -(Cos(sprite->data[7], 12));
    if (sprite->data[7] > 63)
    {
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
        sprite->y2 = 0;
        HandleSetAffineData(sprite, 256, 256, 0);
    }

    HandleSetAffineData(sprite, 256, 256 + yScale, 0);
}

static void HorizontalSpring(struct Sprite *sprite)
{
    if (sprite->data[7] > sprite->data[5])
    {
        sprite->x2 = 0;
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
        HandleSetAffineData(sprite, 256, 256, 0);
    }
    else
    {
        s16 xScale;

        sprite->x2 = Sin(sprite->data[7] % 256, sprite->data[4]);
        sprite->data[7] += sprite->data[6];
        xScale = Sin(sprite->data[7] % 128, 96);
        HandleSetAffineData(sprite, 256 + xScale, 256, 0);
    }
}

static void Anim_HorizontalSpring(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[2]++;
        sprite->data[7] = 0;
        sprite->data[6] = 8;
        sprite->data[5] = 512;
        sprite->data[4] = 8;
    }

    HorizontalSpring(sprite);
}

static void HorizontalRepeatedSpring(struct Sprite *sprite)
{
    if (sprite->data[7] > sprite->data[5])
    {
        sprite->x2 = 0;
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
        HandleSetAffineData(sprite, 256, 256, 0);
    }
    else
    {
        s16 xScale;

        sprite->x2 = Sin(sprite->data[7] % 256, sprite->data[4]);
        sprite->data[7] += sprite->data[6];
        xScale = Sin((sprite->data[7] % 64) * 2, 128);
        HandleSetAffineData(sprite, 256 + xScale, 256, 0);
    }
}

static void Anim_HorizontalRepeatedSpring_Slow(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[2]++;
        sprite->data[7] = 0;
        sprite->data[6] = 4;
        sprite->data[5] = 256;
        sprite->data[4] = 16;
    }

    HorizontalRepeatedSpring(sprite);
}

static void Anim_HorizontalSlideShrink(struct Sprite *sprite)
{
    TryFlipX(sprite);
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[2]++;
        sprite->data[7] = 0;
    }

    if (sprite->data[7] > 512)
    {
        sprite->x2 = 0;
        ResetSpriteAfterAnim(sprite);
        HandleSetAffineData(sprite, 256, 256, 0);
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        s16 scale;

        sprite->x2 = Sin(sprite->data[7] % 256, 8);
        sprite->data[7] += 8;
        scale = Sin(sprite->data[7] % 128, 96);
        HandleSetAffineData(sprite, 256 + scale, 256 + scale, 0);
    }

    TryFlipX(sprite);
}

static void Anim_LungeGrow(struct Sprite *sprite)
{
    TryFlipX(sprite);
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[2]++;
        sprite->data[7] = 0;
    }

    if (sprite->data[7] > 512)
    {
        sprite->x2 = 0;
        ResetSpriteAfterAnim(sprite);
        HandleSetAffineData(sprite, 256, 256, 0);
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        s16 scale;

        sprite->x2 = -(Sin((sprite->data[7] % 256) / 2, 16));
        sprite->data[7] += 8;
        scale = -(Sin((sprite->data[7] % 256) / 2, 64));
        HandleSetAffineData(sprite, 256 + scale, 256 + scale, 0);
    }

    TryFlipX(sprite);
}

static void Anim_CircleIntoBackground(struct Sprite *sprite)
{
    TryFlipX(sprite);
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[2]++;
        sprite->data[7] = 0;
    }

    if (sprite->data[7] > 512)
    {
        sprite->x2 = 0;
        ResetSpriteAfterAnim(sprite);
        HandleSetAffineData(sprite, 256, 256, 0);
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        s16 scale;

        sprite->x2 = -(Sin(sprite->data[7] % 256 , 8));
        sprite->data[7] += 8;
        scale = Sin((sprite->data[7] % 256) / 2, 96);
        HandleSetAffineData(sprite, 256 + scale, 256 + scale, 0);
    }

    TryFlipX(sprite);
}

static void Anim_RapidHorizontalHops(struct Sprite *sprite)
{
    TryFlipX(sprite);
    if (sprite->data[2] > 2048)
    {
        sprite->callback = WaitAnimEnd;
        sprite->data[6] = 0;
    }
    else
    {
        s16 caseVar = (sprite->data[2] / 512) % 4;
        switch (caseVar)
        {
        case 0:
            sprite->x2 = -(sprite->data[2] % 512 * 16) / 512;
            break;
        case 1:
            sprite->x2 = (sprite->data[2] % 512 / 32) - 16;
            break;
        case 2:
            sprite->x2 = (sprite->data[2] % 512) / 32;
            break;
        case 3:
            sprite->x2 = -(sprite->data[2] % 512 * 16) / 512 + 16;
            break;
        }

        sprite->y2 = -(Sin(sprite->data[2] % 128, 4));
        sprite->data[2] += 24;
    }

    TryFlipX(sprite);
}

static void Anim_FourPetal(struct Sprite *sprite)
{
    TryFlipX(sprite);
    if (sprite->data[2] == 0)
    {
        sprite->data[6] = 0;
        sprite->data[7] = 64;
        sprite->data[2]++;
    }

    sprite->data[7] += 8;
    if (sprite->data[6] == 4)
    {
        if (sprite->data[7] > 63)
        {
            sprite->data[7] = 0;
            sprite->data[6]++;
        }
    }
    else
    {
        if (sprite->data[7] > 127)
        {
            sprite->data[7] = 0;
            sprite->data[6]++;
        }
    }

    switch (sprite->data[6])
    {
    case 1:
        sprite->x2 = -(Cos(sprite->data[7], 8));
        sprite->y2 = Sin(sprite->data[7], 8) - 8;
        break;
    case 2:
        sprite->x2 = Sin(sprite->data[7] + 128, 8) + 8;
        sprite->y2 = -(Cos(sprite->data[7], 8));
        break;
    case 3:
        sprite->x2 = Cos(sprite->data[7], 8);
        sprite->y2 = Sin(sprite->data[7] + 128, 8) + 8;
        break;
    case 0:
    case 4:
        sprite->x2 = Sin(sprite->data[7], 8) - 8;
        sprite->y2 = Cos(sprite->data[7], 8);
        break;
    default:
        sprite->x2 = 0;
        sprite->y2 = 0;
        sprite->callback = WaitAnimEnd;
        break;
    }

    TryFlipX(sprite);
}

static void Anim_VerticalSquishBounce_Slow(struct Sprite *sprite)
{
    sprite->data[0] = 32;
    VerticalSquishBounce(sprite);
    sprite->callback = VerticalSquishBounce;
}

static void Anim_HorizontalSlide_Slow(struct Sprite *sprite)
{
    sprite->data[0] = 80;
    HorizontalSlide(sprite);
    sprite->callback = HorizontalSlide;
}

static void Anim_VerticalSlide_Slow(struct Sprite *sprite)
{
    sprite->data[0] = 80;
    VerticalSlide(sprite);
    sprite->callback = VerticalSlide;
}

static void Anim_BounceRotateToSides_Small(struct Sprite *sprite)
{
    u8 id = sprite->data[0] = AddNewAnim();

    sAnims[id].rotation = 2048;
    sAnims[id].data = sprite->data[6];
    BounceRotateToSides(sprite);
    sprite->callback = BounceRotateToSides;
}

static void Anim_BounceRotateToSides_Slow(struct Sprite *sprite)
{
    sprite->data[6] = 1;
    Anim_BounceRotateToSides(sprite);
}

static void Anim_BounceRotateToSides_SmallSlow(struct Sprite *sprite)
{
    sprite->data[6] = 1;
    Anim_BounceRotateToSides_Small(sprite);
}

static void Anim_ZigzagSlow(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
        sprite->data[0] = 0;

    if (sprite->data[0] <= 0)
    {
        Zigzag(sprite);
        sprite->data[0] = 1;
    }
    else
    {
        sprite->data[0]--;
    }
}

static void Anim_HorizontalShake_Slow(struct Sprite *sprite)
{
    sprite->data[0] = 30;
    sprite->data[7] = 3;
    HorizontalShake(sprite);
    sprite->callback = HorizontalShake;
}

static void Anim_VertialShake_Slow(struct Sprite *sprite)
{
    sprite->data[0] = 30;
    VerticalShake(sprite);
    sprite->callback = VerticalShake;
}

static void Anim_Twist_Twice(struct Sprite *sprite)
{
    u8 id = sprite->data[0] = AddNewAnim();

    sAnims[id].rotation = 1024;
    sAnims[id].delay = 0;
    sAnims[id].runs = 2;
    Twist(sprite);
    sprite->callback = Twist;
}

static void Anim_CircleCounterclockwise_Slow(struct Sprite *sprite)
{
    u8 id = sprite->data[0] = AddNewAnim();

    sAnims[id].rotation = 512;
    sAnims[id].data = 3;
    sAnims[id].speed = 12;
    CircleCounterclockwise(sprite);
    sprite->callback = CircleCounterclockwise;
}

static void Anim_VerticalShakeTwice_Slow(struct Sprite *sprite)
{
    sprite->data[0] = 24;
    VerticalShakeTwice(sprite);
    sprite->callback = VerticalShakeTwice;
}

static void Anim_VerticalSlideWobble_Small(struct Sprite *sprite)
{
    sprite->data[0] = 5;
    VerticalSlideWobble(sprite);
    sprite->callback = VerticalSlideWobble;
}

static void Anim_VerticalJumps_Small(struct Sprite *sprite)
{
    sprite->data[0] = 3;
    VerticalJumps(sprite);
    sprite->callback = VerticalJumps;
}

static void Anim_Spin(struct Sprite *sprite)
{
    u8 id = sprite->data[0] = AddNewAnim();

    sAnims[id].delay = 60;
    sAnims[id].data = 30;
    Spin(sprite);
    sprite->callback = Spin;
}

static void Anim_TumblingFrontFlip_Twice(struct Sprite *sprite)
{
    u8 id = sprite->data[0] = AddNewAnim();

    sAnims[id].speed = 1;
    sAnims[id].runs = 2;
    TumblingFrontFlip(sprite);
    sprite->callback = TumblingFrontFlip;
}

static void Anim_DeepVerticalSquishBounce_Twice(struct Sprite *sprite)
{
    u8 id = sprite->data[0] = AddNewAnim();

    sAnims[id].rotation = 4;
    sAnims[id].runs = 2;
    DeepVerticalSquishBounce(sprite);
    sprite->callback = DeepVerticalSquishBounce;
}

static void Anim_HorizontalJumpsVerticalStretch_Twice(struct Sprite *sprite)
{
    u8 id = sprite->data[0] = AddNewAnim();

    sAnims[id].data = 1;
    sAnims[id].runs = 2;
    HandleStartAffineAnim(sprite);
    sprite->data[3] = 0;
    HorizontalJumpsVerticalStretch_0(sprite);
    sprite->callback = HorizontalJumpsVerticalStretch_0;
}

static void Anim_RotateToSides(struct Sprite *sprite)
{
    u8 id = sprite->data[0] = AddNewAnim();

    sAnims[id].rotation = 2;
    RotateToSides(sprite);
    sprite->callback = RotateToSides;
}

static void Anim_RotateToSides_Twice(struct Sprite *sprite)
{
    u8 id = sprite->data[0] = AddNewAnim();

    sAnims[id].rotation = 4;
    sAnims[id].runs = 2;
    RotateToSides(sprite);
    sprite->callback = RotateToSides;
}

static void Anim_SwingConcave(struct Sprite *sprite)
{
    u8 id = sprite->data[0] = AddNewAnim();

    sAnims[id].data = 100;
    SwingConcave(sprite);
    sprite->callback = SwingConcave;
}

static void Anim_SwingConcave_Fast(struct Sprite *sprite)
{
    u8 id = sprite->data[0] = AddNewAnim();

    sAnims[id].data = 50;
    sAnims[id].runs = 2;
    SwingConcave(sprite);
    sprite->callback = SwingConcave;
}

static void Anim_SwingConvex(struct Sprite *sprite)
{
    u8 id = sprite->data[0] = AddNewAnim();

    sAnims[id].data = 100;
    SwingConvex(sprite);
    sprite->callback = SwingConvex;
}

static void Anim_SwingConvex_Fast(struct Sprite *sprite)
{
    u8 id = sprite->data[0] = AddNewAnim();

    sAnims[id].data = 50;
    sAnims[id].runs = 2;
    SwingConvex(sprite);
    sprite->callback = SwingConvex;
}

// Very similar to VerticalShake, used by back animations only
static void VerticalShakeBack(struct Sprite *sprite)
{
    s32 counter = sprite->data[2];
    if (counter > 2304)
    {
        sprite->callback = WaitAnimEnd;
        sprite->y2 = 0;
    }
    else
    {
        sprite->y2 = Sin((counter + 192) % 256, sprite->data[7]) + sprite->data[7];
    }

    sprite->data[2] += sprite->data[0];
}

static void Anim_VerticalShakeBack(struct Sprite *sprite)
{
    sprite->data[0] = 60;
    sprite->data[7] = 3;
    VerticalShakeBack(sprite);
    sprite->callback = VerticalShakeBack;
}

static void Anim_VerticalShakeBack_Slow(struct Sprite *sprite)
{
    sprite->data[0] = 30;
    sprite->data[7] = 3;
    VerticalShakeBack(sprite);
    sprite->callback = VerticalShakeBack;
}

static void Anim_VerticalShakeHorizontalSlide_Slow(struct Sprite *sprite)
{
    TryFlipX(sprite);
    if (sprite->data[2] > 2048)
    {
        sprite->callback = WaitAnimEnd;
        sprite->data[6] = 0;
    }
    else
    {
        s16 divCase = (sprite->data[2] / 512) % 4;
        switch (divCase)
        {
        case 0:
            sprite->x2 = (sprite->data[2] % 512) / 32;
            break;
        case 2:
            sprite->x2 = -(sprite->data[2] % 512 * 16) / 512;
            break;
        case 1:
            sprite->x2 = -(sprite->data[2] % 512 * 16) / 512 + 16;
            break;
        case 3:
            sprite->x2 = (sprite->data[2] % 512) / 32 - 16;
            break;
        }

        sprite->y2 = Sin(sprite->data[2] % 128, 4);
        sprite->data[2] += 24;
    }

    TryFlipX(sprite);
}

static void VerticalStretchBothEnds(struct Sprite *sprite)
{
    s16 index1 = 0, index2 = 0;

    if (sprite->data[5] > sprite->data[6])
    {
        sprite->y2 = 0;
        sprite->data[5] = 0;
        HandleSetAffineData(sprite, 256, 256, 0);
        if (sprite->data[4] <= 1)
        {
            ResetSpriteAfterAnim(sprite);
            sprite->callback = WaitAnimEnd;
        }
        else
        {
            sprite->data[4]--;
            sprite->data[7] = 0;
        }
    }
    else
    {
        u8 amplitude, cmpVal1, cmpVal2;
        s16 xScale, yScale;

        index2 = (sprite->data[5] * 128) / sprite->data[6];
        cmpVal1 = sprite->data[6] / 4;
        cmpVal2 = cmpVal1 * 3;
        if (sprite->data[5] >= cmpVal1 && sprite->data[5] < cmpVal2)
        {
            sprite->data[7] += 51;
            index1 = sprite->data[7] & 0xFF;
        }

        if (!sprite->sDontFlip)
            xScale = -256 - Sin(index2, 16);
        else
            xScale = 256 + Sin(index2, 16);

        amplitude = sprite->data[3];
        yScale = 256 - Sin(index2, amplitude) - Sin(index1, amplitude / 5);
        SetAffineData(sprite, xScale, yScale, 0);
        sprite->data[5]++;
    }
}

static void Anim_VerticalStretchBothEnds_Slow(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[2] = 1;
        HandleStartAffineAnim(sprite);
        sprite->data[4] = 1;
        sprite->data[6] = 40;
        sprite->data[3] = 40;
        sprite->data[5] = 0;
        sprite->data[7] = 0;
    }

    VerticalStretchBothEnds(sprite);
}

static void HorizontalStretchFar(struct Sprite *sprite)
{
    s16 index1 = 0, index2;

    if (sprite->data[5] > sprite->data[6])
    {
        sprite->data[5] = 0;
        HandleSetAffineData(sprite, 256, 256, 0);
        if (sprite->data[4] <= 1)
        {
            ResetSpriteAfterAnim(sprite);
            sprite->callback = WaitAnimEnd;
        }
        else
        {
            sprite->data[4]--;
            sprite->data[7] = 0;
        }
    }
    else
    {
        u8 amplitude, cmpVal1, cmpVal2;
        s16 xScale;

        index2 = (sprite->data[5] * 128) / sprite->data[6];
        cmpVal1 = sprite->data[6] / 4;
        cmpVal2 = cmpVal1 * 3;
        if (sprite->data[5] >= cmpVal1 && sprite->data[5] < cmpVal2)
        {
            sprite->data[7] += 51;
            index1 = sprite->data[7] & 0xFF;
        }

        amplitude = sprite->data[3];

        if (!sprite->sDontFlip)
            xScale = -256 + Sin(index2, amplitude) + Sin(index1, amplitude / 5 * 2);
        else
            xScale = 256 - Sin(index2, amplitude) - Sin(index1, amplitude / 5 * 2);

        SetAffineData(sprite, xScale, 256, 0);
        sprite->data[5]++;
    }
}

static void Anim_HorizontalStretchFar_Slow(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[2] = 1;
        HandleStartAffineAnim(sprite);
        sprite->data[4] = 1;
        sprite->data[6] = 40;
        sprite->data[3] = 40;
        sprite->data[5] = 0;
        sprite->data[7] = 0;
    }

    HorizontalStretchFar(sprite);
}

static void VerticalShakeLowTwice(struct Sprite *sprite)
{
    u8 var6, var7;
    u8 var8 = sprite->data[2];
    u8 var9 = sprite->data[6];
    u8 var5 = sVerticalShakeData[sprite->data[5]][0];
    if (var5 != (u8)-1)
        var5 = sprite->data[7];

    var6 = sVerticalShakeData[sprite->data[5]][1];
    var7 = 0;
    if (sVerticalShakeData[sprite->data[5]][0] != (u8)-2)
        var7 = (var6 - var9) * var5 / var6;
    else
        var7 = 0;

    if (var5 == (u8)-1)
    {
        sprite->callback = WaitAnimEnd;
        sprite->y2 = 0;
    }
    else
    {
        sprite->y2 = Sin((var8 + 192) % 256, var7) + var7;
        if (var9 == var6)
        {
            sprite->data[5]++;
            sprite->data[6] = 0;
        }
        else
        {
            sprite->data[2] += sprite->data[0];
            sprite->data[6]++;
        }
    }
}

// Very similar in appearance to Anim_VerticalShakeTwice (especially the fast variant), but deeper
static void Anim_VerticalShakeLowTwice(struct Sprite *sprite)
{
    sprite->data[0] = 40;
    sprite->data[7] = 6;
    VerticalShakeLowTwice(sprite);
    sprite->callback = VerticalShakeLowTwice;
}

static void Anim_HorizontalShake_Fast(struct Sprite *sprite)
{
    sprite->data[0] = 70;
    sprite->data[7] = 6;
    HorizontalShake(sprite);
    sprite->callback = HorizontalShake;
}

static void Anim_HorizontalSlide_Fast(struct Sprite *sprite)
{
    sprite->data[0] = 20;
    HorizontalSlide(sprite);
    sprite->callback = HorizontalSlide;
}

static void Anim_HorizontalVibrate_Fast(struct Sprite *sprite)
{
    if (sprite->data[2] > 40)
    {
        sprite->callback = WaitAnimEnd;
        sprite->x2 = 0;
    }
    else
    {
        s8 sign;
        if (!(sprite->data[2] & 1))
            sign = 1;
        else
            sign = -1;

        sprite->x2 = Sin((sprite->data[2] * 128 / 40) % 256, 9) * sign;
    }

    sprite->data[2]++;
}

static void Anim_HorizontalVibrate_Fastest(struct Sprite *sprite)
{
    if (sprite->data[2] > 40)
    {
        sprite->callback = WaitAnimEnd;
        sprite->x2 = 0;
    }
    else
    {
        s8 sign;
        if (!(sprite->data[2] & 1))
            sign = 1;
        else
            sign = -1;

        sprite->x2 = Sin((sprite->data[2] * 128 / 40) % 256, 12) * sign;
    }

    sprite->data[2]++;
}

static void Anim_VerticalShakeBack_Fast(struct Sprite *sprite)
{
    sprite->data[0] = 70;
    sprite->data[7] = 6;
    VerticalShakeBack(sprite);
    sprite->callback = VerticalShakeBack;
}

static void Anim_VerticalShakeLowTwice_Slow(struct Sprite *sprite)
{
    sprite->data[0] = 24;
    sprite->data[7] = 6;
    VerticalShakeLowTwice(sprite);
    sprite->callback = VerticalShakeLowTwice;
}

static void Anim_VerticalShakeLowTwice_Fast(struct Sprite *sprite)
{
    sprite->data[0] = 56;
    sprite->data[7] = 9;
    VerticalShakeLowTwice(sprite);
    sprite->callback = VerticalShakeLowTwice;
}

static void Anim_CircleCounterclockwise_Long(struct Sprite *sprite)
{
    u8 id = sprite->data[0] = AddNewAnim();

    sAnims[id].rotation = 1024;
    sAnims[id].data = 6;
    sAnims[id].speed = 24;
    CircleCounterclockwise(sprite);
    sprite->callback = CircleCounterclockwise;
}

static void GrowStutter(struct Sprite *sprite)
{
    s16 index1 = 0, index2 = 0;
    if (sprite->data[5] > sprite->data[6])
    {
        sprite->y2 = 0;
        sprite->data[5] = 0;
        HandleSetAffineData(sprite, 256, 256, 0);
        if (sprite->data[4] <= 1)
        {
            ResetSpriteAfterAnim(sprite);
            sprite->callback = WaitAnimEnd;
        }
        else
        {
            sprite->data[4]--;
            sprite->data[7] = 0;
        }
    }
    else
    {
        u8 amplitude, cmpVal1, cmpVal2;
        s16 xScale, yScale;

        index2 = (sprite->data[5] * 128) / sprite->data[6];
        cmpVal1 = sprite->data[6] / 4;
        cmpVal2 = cmpVal1 * 3;
        if (sprite->data[5] >= cmpVal1 && sprite->data[5] < cmpVal2)
        {
            sprite->data[7] += 51;
            index1 = sprite->data[7] & 0xFF;
        }

        amplitude = sprite->data[3];

        if (!sprite->sDontFlip)
            xScale = Sin(index2, amplitude) + (Sin(index1, amplitude / 5 * 2) - 256);
        else
            xScale = 256 - Sin(index1, amplitude / 5 * 2) - Sin(index2, amplitude);

        yScale = 256 - Sin(index1, amplitude / 5) - Sin(index2, amplitude);
        SetAffineData(sprite, xScale, yScale, 0);
        sprite->data[5]++;
    }
}

static void Anim_GrowStutter_Slow(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[2] = 1;
        HandleStartAffineAnim(sprite);
        sprite->data[4] = 1;
        sprite->data[6] = 40;
        sprite->data[3] = 40;
        sprite->data[5] = 0;
        sprite->data[7] = 0;
    }

    GrowStutter(sprite);
}

static void Anim_VerticalShakeHorizontalSlide(struct Sprite *sprite)
{
    TryFlipX(sprite);
    if (sprite->data[2] > 2048)
    {
        sprite->callback = WaitAnimEnd;
        sprite->data[6] = 0;
    }
    else
    {
        s16 divCase = (sprite->data[2] / 512) % 4;
        switch (divCase)
        {
        case 0:
            sprite->x2 = (sprite->data[2] % 512) / 32;
            break;
        case 2:
            sprite->x2 = -(sprite->data[2] % 512 * 16) / 512;
            break;
        case 1:
            sprite->x2 = -(sprite->data[2] % 512 * 16) / 512 + 16;
            break;
        case 3:
            sprite->x2 = (sprite->data[2] % 512) / 32 - 16;
            break;
        }

        sprite->y2 = Sin(sprite->data[2] % 128, 4);
        sprite->data[2] += 48;
    }

    TryFlipX(sprite);
}

static void Anim_VerticalShakeHorizontalSlide_Fast(struct Sprite *sprite)
{
    TryFlipX(sprite);
    if (sprite->data[2] > 2048)
    {
        sprite->callback = WaitAnimEnd;
        sprite->data[6] = 0;
    }
    else
    {
        s16 divCase = (sprite->data[2] / 512) % 4;
        switch (divCase)
        {
        case 0:
            sprite->x2 = (sprite->data[2] % 512) / 32;
            break;
        case 2:
            sprite->x2 = -(sprite->data[2] % 512 * 16) / 512;
            break;
        case 1:
            sprite->x2 = -(sprite->data[2] % 512 * 16) / 512 + 16;
            break;
        case 3:
            sprite->x2 = (sprite->data[2] % 512) / 32 - 16;
            break;
        }

        sprite->y2 = Sin(sprite->data[2] % 96, 4);
        sprite->data[2] += 64;
    }

    TryFlipX(sprite);
}

static const s8 sTriangleDownData[][3] =
{
//   x    y   timer
    {1,   1, 12},
    {-2,  0, 12},
    {1,  -1, 12},
    {0,  0,  0}
};

static void TriangleDown(struct Sprite *sprite)
{
    TryFlipX(sprite);
    if (sprite->data[2] == 0)
        sprite->data[3] = 0;

    if (sTriangleDownData[sprite->data[3]][2] / sprite->data[5] == sprite->data[2])
    {
        sprite->data[3]++;
        sprite->data[2] = 0;
    }

    if (sTriangleDownData[sprite->data[3]][2] / sprite->data[5] == 0)
    {
        if (--sprite->data[6] == 0)
            sprite->callback = WaitAnimEnd;
        else
            sprite->data[2] = 0;
    }
    else
    {
        s32 amplitude = sprite->data[5];
        sprite->x2 += (sTriangleDownData[sprite->data[3]][0] * amplitude);
        sprite->y2 += (sTriangleDownData[sprite->data[3]][1] * sprite->data[5]); // Not using amplitude here. No reason for this.
        sprite->data[2]++;
        TryFlipX(sprite);
    }
}

static void Anim_TriangleDown_Slow(struct Sprite *sprite)
{
    sprite->data[5] = 1;
    sprite->data[6] = 1;
    TriangleDown(sprite);
    sprite->callback = TriangleDown;
}

static void Anim_TriangleDown(struct Sprite *sprite)
{
    sprite->data[5] = 2;
    sprite->data[6] = 1;
    TriangleDown(sprite);
    sprite->callback = TriangleDown;
}

static void Anim_TriangleDown_Fast(struct Sprite *sprite)
{
    sprite->data[5] = 2;
    sprite->data[6] = 2;
    TriangleDown(sprite);
    sprite->callback = TriangleDown;
}

static void Grow(struct Sprite *sprite)
{
    if (sprite->data[7] > 255)
    {
        if (sprite->data[5] <= 1)
        {
            ResetSpriteAfterAnim(sprite);
            sprite->callback = WaitAnimEnd;
            HandleSetAffineData(sprite, 256, 256, 0);
        }
        else
        {
            sprite->data[5]--;
            sprite->data[7] = 0;
        }
    }
    else
    {
        s16 scale;

        sprite->data[7] += sprite->data[6];
        if (sprite->data[7] > 256)
            sprite->data[7] = 256;

        scale = Sin(sprite->data[7] / 2, 64);
        HandleSetAffineData(sprite, 256 - scale, 256 - scale, 0);
    }
}

static void Anim_Grow(struct Sprite *sprite)
{
    TryFlipX(sprite);
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[2]++;
        sprite->data[7] = 0;
        sprite->data[6] = 4;
        sprite->data[5] = 1;
    }

    Grow(sprite);
    TryFlipX(sprite);
}

static void Anim_Grow_Twice(struct Sprite *sprite)
{
    TryFlipX(sprite);
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[2]++;
        sprite->data[7] = 0;
        sprite->data[6] = 8;
        sprite->data[5] = 2;
    }

    Grow(sprite);
    TryFlipX(sprite);
}

static void Anim_HorizontalSpring_Fast(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[2]++;
        sprite->data[7] = 0;
        sprite->data[6] = 8;
        sprite->data[5] = 512;
        sprite->data[4] = 16;
    }

    HorizontalSpring(sprite);
}

static void Anim_HorizontalSpring_Slow(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[2]++;
        sprite->data[7] = 0;
        sprite->data[6] = 4;
        sprite->data[5] = 256;
        sprite->data[4] = 16;
    }

    HorizontalSpring(sprite);
}

static void Anim_HorizontalRepeatedSpring_Fast(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[2]++;
        sprite->data[7] = 0;
        sprite->data[6] = 8;
        sprite->data[5] = 512;
        sprite->data[4] = 16;
    }

    HorizontalRepeatedSpring(sprite);
}

static void Anim_HorizontalRepeatedSpring(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[2]++;
        sprite->data[7] = 0;
        sprite->data[6] = 8;
        sprite->data[5] = 512;
        sprite->data[4] = 8;
    }

    HorizontalRepeatedSpring(sprite);
}

static void Anim_ShrinkGrow_Fast(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[7] = 5;
        sprite->data[6] = 8;
    }

    ShrinkGrow(sprite);
}

static void Anim_ShrinkGrow_Slow(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[7] = 3;
        sprite->data[6] = 4;
    }

    ShrinkGrow(sprite);
}

static void Anim_VerticalStretchBothEnds(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[2] = 1;
        HandleStartAffineAnim(sprite);
        sprite->data[4] = 1;
        sprite->data[6] = 30;
        sprite->data[3] = 60;
        sprite->data[7] = 0;
    }

    VerticalStretchBothEnds(sprite);
}

static void Anim_VerticalStretchBothEnds_Twice(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[2] = 1;
        HandleStartAffineAnim(sprite);
        sprite->data[4] = 2;
        sprite->data[6] = 20;
        sprite->data[3] = 70;
        sprite->data[7] = 0;
    }

    VerticalStretchBothEnds(sprite);
}

static void Anim_HorizontalStretchFar_Twice(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[2] = 1;
        HandleStartAffineAnim(sprite);
        sprite->data[4] = 2;
        sprite->data[6] = 20;
        sprite->data[3] = 70;
        sprite->data[5] = 0;
        sprite->data[7] = 0;
    }

    HorizontalStretchFar(sprite);
}

static void Anim_HorizontalStretchFar(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[2] = 1;
        HandleStartAffineAnim(sprite);
        sprite->data[4] = 1;
        sprite->data[6] = 30;
        sprite->data[3] = 60;
        sprite->data[5] = 0;
        sprite->data[7] = 0;
    }

    HorizontalStretchFar(sprite);
}

static void Anim_GrowStutter_Twice(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[2] = 1;
        HandleStartAffineAnim(sprite);
        sprite->data[4] = 2;
        sprite->data[6] = 20;
        sprite->data[3] = 70;
        sprite->data[5] = 0;
        sprite->data[7] = 0;
    }

    GrowStutter(sprite);
}

static void Anim_GrowStutter(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[2] = 1;
        HandleStartAffineAnim(sprite);
        sprite->data[4] = 1;
        sprite->data[6] = 30;
        sprite->data[3] = 60;
        sprite->data[5] = 0;
        sprite->data[7] = 0;
    }

    GrowStutter(sprite);
}

static void ConcaveArc(struct Sprite *sprite)
{
    if (sprite->data[7] > 255)
    {
        if (sprite->data[6] <= 1)
        {
            sprite->callback = WaitAnimEnd;
            sprite->x2 = 0;
            sprite->y2 = 0;
        }
        else
        {
            sprite->data[7] %= 256;
            sprite->data[6]--;
        }
    }
    else
    {
        sprite->x2 = -(Sin(sprite->data[7], sprite->data[5]));
        sprite->y2 = Sin((sprite->data[7] + 192) % 256, sprite->data[4]);
        if (sprite->y2 > 0)
            sprite->y2 *= -1;

        sprite->y2 += sprite->data[4];
        sprite->data[7] += sprite->data[3];
    }
}

static void Anim_ConcaveArcLarge_Slow(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[2] = 1;
        sprite->data[6] = 1;
        sprite->data[7] = 0;
        sprite->data[5] = 12;
        sprite->data[4] = 12;
        sprite->data[3] = 4;
    }

    ConcaveArc(sprite);
}

static void Anim_ConcaveArcLarge(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[2] = 1;
        sprite->data[6] = 1;
        sprite->data[7] = 0;
        sprite->data[5] = 12;
        sprite->data[4] = 12;
        sprite->data[3] = 6;
    }

    ConcaveArc(sprite);
}

static void Anim_ConcaveArcLarge_Twice(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[2] = 1;
        sprite->data[6] = 2;
        sprite->data[7] = 0;
        sprite->data[5] = 12;
        sprite->data[4] = 12;
        sprite->data[3] = 8;
    }

    ConcaveArc(sprite);
}

static void ConvexDoubleArc(struct Sprite *sprite)
{
    if (sprite->data[7] > 256)
    {
        if (sprite->data[6] <= sprite->data[4])
        {
            sprite->callback = WaitAnimEnd;
        }
        else
        {
            sprite->data[4]++;
            sprite->data[7] = 0;
        }

        sprite->x2 = 0;
        sprite->y2 = 0;
    }
    else
    {
        s16 posX;

        if (sprite->data[7] > 159)
        {
            if (sprite->data[7] > 256)
                sprite->data[7] = 256;

            sprite->y2 = -(Sin(sprite->data[7] % 256, 8));
        }
        else if (sprite->data[7] > 95)
        {
            sprite->y2 = Sin(96, 6) - Sin((sprite->data[7] - 96) * 2, 4);
        }
        else
        {
            sprite->y2 = Sin(sprite->data[7], 6);
        }

        posX = -(Sin(sprite->data[7] / 2, sprite->data[5]));
        if (sprite->data[4] % 2 == 0)
            posX *= -1;

        sprite->x2 = posX;
        sprite->data[7] += sprite->data[3];
    }
}

static void Anim_ConvexDoubleArc_Slow(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[2] = 1;
        sprite->data[6] = 2;
        sprite->data[7] = 0;
        sprite->data[5] = 16;
        sprite->data[4] = 1;
        sprite->data[3] = 4;
    }

    ConvexDoubleArc(sprite);
}

static void Anim_ConvexDoubleArc(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[2] = 1;
        sprite->data[6] = 2;
        sprite->data[7] = 0;
        sprite->data[5] = 16;
        sprite->data[4] = 1;
        sprite->data[3] = 6;
    }

    ConvexDoubleArc(sprite);
}

static void Anim_ConvexDoubleArc_Twice(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[2] = 1;
        sprite->data[6] = 3;
        sprite->data[7] = 0;
        sprite->data[5] = 16;
        sprite->data[4] = 1;
        sprite->data[3] = 8;
    }

    ConvexDoubleArc(sprite);
}

static void Anim_ConcaveArcSmall_Slow(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[2] = 1;
        sprite->data[6] = 1;
        sprite->data[7] = 0;
        sprite->data[5] = 4;
        sprite->data[4] = 6;
        sprite->data[3] = 4;
    }

    ConcaveArc(sprite);
}

static void Anim_ConcaveArcSmall(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[2] = 1;
        sprite->data[6] = 1;
        sprite->data[7] = 0;
        sprite->data[5] = 4;
        sprite->data[4] = 6;
        sprite->data[3] = 6;
    }

    ConcaveArc(sprite);
}

static void Anim_ConcaveArcSmall_Twice(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[2] = 1;
        sprite->data[6] = 2;
        sprite->data[7] = 0;
        sprite->data[5] = 4;
        sprite->data[4] = 6;
        sprite->data[3] = 8;
    }

    ConcaveArc(sprite);
}

static void SetHorizontalDip(struct Sprite *sprite)
{
    u16 index = Sin((sprite->data[2] * 128) / sprite->data[7], sprite->data[5]);
    sprite->data[6] = -(index << 8);
    SetPosForRotation(sprite, index, sprite->data[4], 0);
    HandleSetAffineData(sprite, 256, 256, sprite->data[6]);
}

static void Anim_HorizontalDip(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[7] = 60;
        sprite->data[5] = 8;
        sprite->data[4] = -32;
        sprite->data[3] = 1;
        sprite->data[0] = 0;
    }

    if (sprite->data[2] > sprite->data[7])
    {
        HandleSetAffineData(sprite, 256, 256, 0);
        sprite->x2 = 0;
        sprite->y2 = 0;
        sprite->data[0]++;
        if (sprite->data[3] <= sprite->data[0])
        {
            ResetSpriteAfterAnim(sprite);
            sprite->callback = WaitAnimEnd;
            return;
        }
        else
        {
            sprite->data[2] = 0;
        }
    }
    else
    {
        SetHorizontalDip(sprite);
    }

    sprite->data[2]++;
}

static void Anim_HorizontalDip_Fast(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[7] = 90;
        sprite->data[5] = 8;
        sprite->data[4] = -32;
        sprite->data[3] = 1;
        sprite->data[0] = 0;
    }

    if (sprite->data[2] > sprite->data[7])
    {
        HandleSetAffineData(sprite, 256, 256, 0);
        sprite->x2 = 0;
        sprite->y2 = 0;
        sprite->data[0]++;
        if (sprite->data[3] <= sprite->data[0])
        {
            ResetSpriteAfterAnim(sprite);
            sprite->callback = WaitAnimEnd;
            return;
        }
        else
        {
            sprite->data[2] = 0;
        }
    }
    else
    {
        SetHorizontalDip(sprite);
    }

    sprite->data[2]++;
}

static void Anim_HorizontalDip_Twice(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->data[7] = 30;
        sprite->data[5] = 8;
        sprite->data[4] = -32;
        sprite->data[3] = 2;
        sprite->data[0] = 0;
    }

    if (sprite->data[2] > sprite->data[7])
    {
        HandleSetAffineData(sprite, 256, 256, 0);
        sprite->x2 = 0;
        sprite->y2 = 0;
        sprite->data[0]++;
        if (sprite->data[3] <= sprite->data[0])
        {
            ResetSpriteAfterAnim(sprite);
            sprite->callback = WaitAnimEnd;
            return;
        }
        else
        {
            sprite->data[2] = 0;
        }
    }
    else
    {
        SetHorizontalDip(sprite);
    }

    sprite->data[2]++;
}

static void ShrinkGrowVibrate(struct Sprite *sprite)
{
    if (sprite->data[2] > sprite->data[7])
    {
        sprite->y2 = 0;
        HandleSetAffineData(sprite, 256, 256, 0);
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        s8 sinY;
        u16 y;
        s16 index = ((u16)(sprite->data[2] % sprite->data[6] * 256) / sprite->data[6]) % 256;
        if (sprite->data[2] % 2 == 0)
        {
            sprite->data[4] = Sin(index, 32) + 256;
            sprite->data[5] = Sin(index, 32) + 256;
            sinY = Sin(index, 32);
        }
        else
        {
            sprite->data[4] = Sin(index, 8) + 256;
            sprite->data[5] = Sin(index, 8) + 256;
            sinY = Sin(index, 8);
        }

        y = sinY / 8;
        sprite->y2 = y;
        HandleSetAffineData(sprite, sprite->data[4], sprite->data[5], 0);
    }

    sprite->data[2]++;
}

static void Anim_ShrinkGrowVibrate_Fast(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->y2 += 2;
        sprite->data[6] = 40;
        sprite->data[7] = 80;
    }

    ShrinkGrowVibrate(sprite);
}

static void Anim_ShrinkGrowVibrate(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->y2 += 2;
        sprite->data[6] = 40;
        sprite->data[7] = 40;
    }

    ShrinkGrowVibrate(sprite);
}

static void Anim_ShrinkGrowVibrate_Slow(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        HandleStartAffineAnim(sprite);
        sprite->y2 += 2;
        sprite->data[6] = 80;
        sprite->data[7] = 80;
    }

    ShrinkGrowVibrate(sprite);
}

static void JoltRight_0(struct Sprite *sprite);
static void JoltRight_1(struct Sprite *sprite);
static void JoltRight_2(struct Sprite *sprite);
static void JoltRight_3(struct Sprite *sprite);

static void JoltRight(struct Sprite *sprite)
{
    TryFlipX(sprite);
    sprite->x2 -= sprite->data[2];
    if (sprite->x2 <= -sprite->data[6])
    {
        sprite->x2 = -sprite->data[6];
        sprite->data[7] = 2;
        sprite->callback = JoltRight_0;
    }

    TryFlipX(sprite);
}

static void JoltRight_0(struct Sprite *sprite)
{
    TryFlipX(sprite);
    sprite->x2 += sprite->data[7];
    sprite->data[7]++;
    if (sprite->x2 >= 0)
        sprite->callback = JoltRight_1;

    TryFlipX(sprite);
}

static void JoltRight_1(struct Sprite *sprite)
{
    TryFlipX(sprite);
    sprite->x2 += sprite->data[7];
    sprite->data[7]++;
    if (sprite->x2 > sprite->data[6])
    {
        sprite->x2 = sprite->data[6];
        sprite->callback = JoltRight_2;
    }

    TryFlipX(sprite);
}

static void JoltRight_2(struct Sprite *sprite)
{
    TryFlipX(sprite);
    if (sprite->data[3] >= sprite->data[5])
    {
        sprite->callback = JoltRight_3;
    }
    else
    {
        sprite->x2 += sprite->data[4];
        sprite->data[4] *= -1;
        sprite->data[3]++;
    }

    TryFlipX(sprite);
}

static void JoltRight_3(struct Sprite *sprite)
{
    TryFlipX(sprite);
    sprite->x2 -= 2;
    if (sprite->x2 <= 0)
    {
        sprite->x2 = 0;
        ResetSpriteAfterAnim(sprite);
        sprite->callback = WaitAnimEnd;
    }

    TryFlipX(sprite);
}

static void Anim_JoltRight_Fast(struct Sprite *sprite)
{
    HandleStartAffineAnim(sprite);
    sprite->data[7] = 4;
    sprite->data[6] = 12;
    sprite->data[5] = 16;
    sprite->data[4] = 4;
    sprite->data[3] = 0;
    sprite->data[2] = 2;
    sprite->callback = JoltRight;
}

static void Anim_JoltRight(struct Sprite *sprite)
{
    HandleStartAffineAnim(sprite);
    sprite->data[7] = 2;
    sprite->data[6] = 8;
    sprite->data[5] = 12;
    sprite->data[4] = 2;
    sprite->data[3] = 0;
    sprite->data[2] = 1;
    sprite->callback = JoltRight;
}

static void Anim_JoltRight_Slow(struct Sprite *sprite)
{
    HandleStartAffineAnim(sprite);
    sprite->data[7] = 0;
    sprite->data[6] = 6;
    sprite->data[5] = 6;
    sprite->data[4] = 2;
    sprite->data[3] = 0;
    sprite->data[2] = 1;
    sprite->callback = JoltRight;
}

static void SetShakeFlashYellowPos(struct Sprite *sprite)
{
    sprite->x2 = sprite->data[1];
    if (sprite->data[0] > 1)
    {
        sprite->data[1] *= -1;
        sprite->data[0] = 0;
    }
    else
    {
        sprite->data[0]++;
    }
}

static const struct YellowFlashData sShakeYellowFlashData_Fast[] =
{
    {FALSE,  1},
    { TRUE,  2},
    {FALSE, 15},
    { TRUE,  1},
    {FALSE, 15},
    { TRUE,  1},
    {FALSE, 15},
    { TRUE,  1},
    {FALSE,  1},
    { TRUE,  1},
    {FALSE,  1},
    { TRUE,  1},
    {FALSE,  1},
    { TRUE,  1},
    {FALSE,  1},
    { TRUE,  1},
    {FALSE,  1},
    { TRUE,  1},
    {FALSE,  1},
    {FALSE, -1}
};

static const struct YellowFlashData sShakeYellowFlashData_Normal[] =
{
    {FALSE,  5},
    { TRUE,  1},
    {FALSE, 15},
    { TRUE,  4},
    {FALSE,  2},
    { TRUE,  2},
    {FALSE,  2},
    { TRUE,  2},
    {FALSE,  2},
    { TRUE,  2},
    {FALSE,  2},
    { TRUE,  2},
    {FALSE,  2},
    {FALSE, -1}
};

static const struct YellowFlashData sShakeYellowFlashData_Slow[] =
{
    {FALSE,  1},
    { TRUE,  1},
    {FALSE, 20},
    { TRUE,  1},
    {FALSE, 20},
    { TRUE,  1},
    {FALSE, 20},
    { TRUE,  1},
    {FALSE,  1},
    {FALSE, -1}
};

static const struct YellowFlashData *const sShakeYellowFlashData[] =
{
    sShakeYellowFlashData_Fast,
    sShakeYellowFlashData_Normal,
    sShakeYellowFlashData_Slow
};

static void ShakeFlashYellow(struct Sprite *sprite)
{
    const struct YellowFlashData *array = sShakeYellowFlashData[sprite->data[3]];
    SetShakeFlashYellowPos(sprite);
    if (array[sprite->data[6]].time == (u8)-1)
    {
        sprite->x2 = 0;
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        if (sprite->data[4] == 1)
        {
            if (array[sprite->data[6]].isYellow)
                BlendPalette(sprite->data[7], 16, 16, RGB_YELLOW);
            else
                BlendPalette(sprite->data[7], 16, 0, RGB_YELLOW);

            sprite->data[4] = 0;
        }

        if (array[sprite->data[6]].time == sprite->data[5])
        {
            sprite->data[4] = 1;
            sprite->data[5] = 0;
            sprite->data[6]++;
        }
        else
        {
            sprite->data[5]++;
        }
    }
}

static void Anim_ShakeFlashYellow_Fast(struct Sprite *sprite)
{
    if (++sprite->data[2] == 1)
    {
        sprite->data[7] = OBJ_PLTT_ID(sprite->oam.paletteNum);
        sprite->data[6] = 0;
        sprite->data[5] = 0;
        sprite->data[4] = 0;
        sprite->data[3] = 0;
    }

    ShakeFlashYellow(sprite);
}

static void Anim_ShakeFlashYellow(struct Sprite *sprite)
{
    if (++sprite->data[2] == 1)
    {
        sprite->data[7] = OBJ_PLTT_ID(sprite->oam.paletteNum);
        sprite->data[6] = 0;
        sprite->data[5] = 0;
        sprite->data[4] = 0;
        sprite->data[3] = 1;
    }

    ShakeFlashYellow(sprite);
}

static void Anim_ShakeFlashYellow_Slow(struct Sprite *sprite)
{
    if (++sprite->data[2] == 1)
    {
        sprite->data[7] = OBJ_PLTT_ID(sprite->oam.paletteNum);
        sprite->data[6] = 0;
        sprite->data[5] = 0;
        sprite->data[4] = 0;
        sprite->data[3] = 2;
    }

    ShakeFlashYellow(sprite);
}

enum {
    SHAKEGLOW_RED,
    SHAKEGLOW_GREEN,
    SHAKEGLOW_BLUE,
    SHAKEGLOW_BLACK
};

static void ShakeGlow_Blend(struct Sprite *sprite)
{
    static const u16 sColors[] =
    {
        [SHAKEGLOW_RED]   = RGB_RED,
        [SHAKEGLOW_GREEN] = RGB_GREEN,
        [SHAKEGLOW_BLUE]  = RGB_BLUE,
        [SHAKEGLOW_BLACK] = RGB_BLACK
    };

    if (sprite->data[2] > 127)
    {
        BlendPalette(sprite->data[7], 16, 0, RGB_RED);
        sprite->callback = WaitAnimEnd;
    }
    else
    {
        sprite->data[6] = Sin(sprite->data[2], 12);
        BlendPalette(sprite->data[7], 16, sprite->data[6], sColors[sprite->data[1]]);
    }
}

static void ShakeGlow_Move(struct Sprite *sprite)
{
    if (sprite->data[3] < sprite->data[4])
    {
        TryFlipX(sprite);
        if (sprite->data[5] > sprite->data[0])
        {
            if (++sprite->data[3] < sprite->data[4])
                sprite->data[5] = 0;

            sprite->x2 = 0;
        }
        else
        {
            s8 sign = 1 - (sprite->data[3] % 2 * 2);
            sprite->x2 = sign * Sin((sprite->data[5] * 384 / sprite->data[0]) % 256, 6);
            sprite->data[5]++;
        }

        TryFlipX(sprite);
    }
}

static void Anim_ShakeGlowRed_Fast(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[7] = OBJ_PLTT_ID(sprite->oam.paletteNum);
        sprite->data[0] = 10;
        sprite->data[5] = 0;
        sprite->data[4] = 2;
        sprite->data[3] = 0;
        sprite->data[1] = SHAKEGLOW_RED;
    }

    if (sprite->data[2] % 2 == 0)
        ShakeGlow_Blend(sprite);

    if (sprite->data[2] >= (128 - sprite->data[0] * sprite->data[4]) / 2)
        ShakeGlow_Move(sprite);

    sprite->data[2]++;
}

static void Anim_ShakeGlowRed(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[7] = OBJ_PLTT_ID(sprite->oam.paletteNum);
        sprite->data[0] = 20;
        sprite->data[5] = 0;
        sprite->data[4] = 1;
        sprite->data[3] = 0;
        sprite->data[1] = SHAKEGLOW_RED;
    }

    if (sprite->data[2] % 2 == 0)
        ShakeGlow_Blend(sprite);

    if (sprite->data[2] >= (128 - sprite->data[0] * sprite->data[4]) / 2)
        ShakeGlow_Move(sprite);

    sprite->data[2]++;
}

static void Anim_ShakeGlowRed_Slow(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[7] = OBJ_PLTT_ID(sprite->oam.paletteNum);
        sprite->data[0] = 80;
        sprite->data[5] = 0;
        sprite->data[4] = 1;
        sprite->data[3] = 0;
        sprite->data[1] = SHAKEGLOW_RED;
    }

    if (sprite->data[2] % 2 == 0)
        ShakeGlow_Blend(sprite);

    if (sprite->data[2] >= (128 - sprite->data[0] * sprite->data[4]) / 2)
        ShakeGlow_Move(sprite);

    sprite->data[2]++;
}

static void Anim_ShakeGlowGreen_Fast(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[7] = OBJ_PLTT_ID(sprite->oam.paletteNum);
        sprite->data[0] = 10;
        sprite->data[5] = 0;
        sprite->data[4] = 2;
        sprite->data[3] = 0;
        sprite->data[1] = SHAKEGLOW_GREEN;
    }

    if (sprite->data[2] % 2 == 0)
        ShakeGlow_Blend(sprite);

    if (sprite->data[2] >= (128 - sprite->data[0] * sprite->data[4]) / 2)
        ShakeGlow_Move(sprite);

    sprite->data[2]++;
}

static void Anim_ShakeGlowGreen(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[7] = OBJ_PLTT_ID(sprite->oam.paletteNum);
        sprite->data[0] = 20;
        sprite->data[5] = 0;
        sprite->data[4] = 1;
        sprite->data[3] = 0;
        sprite->data[1] = SHAKEGLOW_GREEN;
    }

    if (sprite->data[2] % 2 == 0)
        ShakeGlow_Blend(sprite);

    if (sprite->data[2] >= (128 - sprite->data[0] * sprite->data[4]) / 2)
        ShakeGlow_Move(sprite);

    sprite->data[2]++;
}

static void Anim_ShakeGlowGreen_Slow(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[7] = OBJ_PLTT_ID(sprite->oam.paletteNum);
        sprite->data[0] = 80;
        sprite->data[5] = 0;
        sprite->data[4] = 1;
        sprite->data[3] = 0;
        sprite->data[1] = SHAKEGLOW_GREEN;
    }

    if (sprite->data[2] % 2 == 0)
        ShakeGlow_Blend(sprite);

    if (sprite->data[2] >= (128 - sprite->data[0] * sprite->data[4]) / 2)
        ShakeGlow_Move(sprite);

    sprite->data[2]++;
}

static void Anim_ShakeGlowBlue_Fast(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[7] = OBJ_PLTT_ID(sprite->oam.paletteNum);
        sprite->data[0] = 10;
        sprite->data[5] = 0;
        sprite->data[4] = 2;
        sprite->data[3] = 0;
        sprite->data[1] = SHAKEGLOW_BLUE;
    }

    if (sprite->data[2] % 2 == 0)
        ShakeGlow_Blend(sprite);

    if (sprite->data[2] >= (128 - sprite->data[0] * sprite->data[4]) / 2)
        ShakeGlow_Move(sprite);

    sprite->data[2]++;
}

static void Anim_ShakeGlowBlue(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[7] = OBJ_PLTT_ID(sprite->oam.paletteNum);
        sprite->data[0] = 20;
        sprite->data[5] = 0;
        sprite->data[4] = 1;
        sprite->data[3] = 0;
        sprite->data[1] = SHAKEGLOW_BLUE;
    }

    if (sprite->data[2] % 2 == 0)
        ShakeGlow_Blend(sprite);

    if (sprite->data[2] >= (128 - sprite->data[0] * sprite->data[4]) / 2)
        ShakeGlow_Move(sprite);

    sprite->data[2]++;
}

static void Anim_ShakeGlowBlue_Slow(struct Sprite *sprite)
{
    if (sprite->data[2] == 0)
    {
        sprite->data[7] = OBJ_PLTT_ID(sprite->oam.paletteNum);
        sprite->data[0] = 80;
        sprite->data[5] = 0;
        sprite->data[4] = 1;
        sprite->data[3] = 0;
        sprite->data[1] = SHAKEGLOW_BLUE;
    }

    if (sprite->data[2] % 2 == 0)
        ShakeGlow_Blend(sprite);

    if (sprite->data[2] >= (128 - sprite->data[0] * sprite->data[4]) / 2)
        ShakeGlow_Move(sprite);

    sprite->data[2]++;
}

static void WaitAnimEnd(struct Sprite *sprite)
{
    if (sprite->animEnded)
        sprite->callback = SpriteCallbackDummy;
}
