pokeplatinum/src/battle_anim/script_funcs_0.c
2025-08-17 12:13:47 +02:00

2797 lines
99 KiB
C

#include "battle_anim/script_funcs_0.h"
#include "nitro/pad/common/pad.h"
#include <nitro.h>
#include <string.h>
#include "constants/battle.h"
#include "constants/battle/battle_anim.h"
#include "constants/graphics.h"
#include "battle_anim/battle_anim_system.h"
#include "battle_anim/battle_anim_helpers.h"
#include "battle_anim/battle_anim_util.h"
#include "battle_script_battlers.h"
#include "bg_window.h"
#include "heap.h"
#include "math_util.h"
#include "palette.h"
#include "pltt_transfer.h"
#include "pokemon_sprite.h"
#include "sprite.h"
#include "sprite_system.h"
#include "sys_task_manager.h"
typedef struct {
u8 unk_00;
u8 unk_01[3];
u8 unk_04;
u8 unk_05;
u8 unk_06;
BattleAnimSystem *unk_08;
SpriteSystem *unk_0C;
SpriteManager *unk_10;
ManagedSprite *unk_14[3];
XYTransformContext unk_20;
} UnkStruct_ov12_0222AC70;
// -------------------------------------------------------------------
// Strength
// -------------------------------------------------------------------
typedef struct StrengthContext {
u8 state;
s16 baseY;
int spriteHeight;
u8 blinkCounter;
BattleAnimSystem *battleAnimSys;
PokemonSprite *sprite;
XYTransformContext scale;
XYTransformContext shake;
} StrengthContext;
enum StrengthState {
STRENGTH_STATE_SHRINK = 0,
STRENGTH_STATE_FADE_TO_RED,
STRENGTH_STATE_FADE_TO_NORMAL,
STRENGTH_STATE_WAIT_FOR_FADE,
STRENGTH_STATE_GROW,
STRENGTH_STATE_CLEANUP,
};
#define STRENGTH_SHAKE_X 2
#define STRENGTH_SHAKE_Y 0
#define STRENGTH_SHAKE_INTERVAL 0
#define STRENGTH_SHAKE_AMOUNT 10
#define STRENGTH_BLINK_COLOR COLOR_RED
#define STRENGTH_BLINK_ALPHA 10
#define STRENGTH_BLINK_COUNT 3
#define STRENGTH_VAR_SHRINK_SCALE 0
#define STRENGTH_VAR_GROW_SCALE 1
#define STRENGTH_VAR_SHRINK_FRAMES 2
#define STRENGTH_VAR_GROW_FRAMES 3
// -------------------------------------------------------------------
// Bulk Up
// -------------------------------------------------------------------
typedef struct BulkUpContext {
u8 state;
s16 baseY;
int spriteHeight;
BattleAnimSystem *battleAnimSys;
PokemonSprite *sprite;
XYTransformContext scale;
XYTransformContext unused;
} BulkUpContext;
enum BulkUpState {
BULK_UP_STATE_SQUISH_Y = 0,
BULK_UP_STATE_SQUISH_X,
BULK_UP_STATE_RETURN_TO_NORMAL,
BULK_UP_STATE_GROW,
BULK_UP_STATE_SHRINK,
};
#define BULK_UP_STRETCH_X 150
#define BULK_UP_SQUISH_X 50
#define BULK_UP_STRETCH_Y 150
#define BULK_UP_SQUISH_Y 50
#define BULK_UP_SQUISH_STRETCH_FRAMES 10
#define BULK_UP_RETURN_TO_NORMAL_FRAMES 5
#define BULK_UP_GROW_FRAMES 5
#define BULK_UP_SHRINK_FRAMES 5
// -------------------------------------------------------------------
// Double Team
// -------------------------------------------------------------------
#define DOUBLE_TEAM_SPRITE_COUNT 4
typedef struct DoubleTeamContext {
u8 iteration;
u8 state;
u16 unk_02;
u8 blendA;
u8 blendB;
u16 unk_06;
s16 attackerX;
s16 attackerY;
BattleAnimSystem *battleAnimSys;
PokemonSprite *attackerSprite;
SpriteManager *pokemonSpriteManager;
ManagedSprite *monSprites[DOUBLE_TEAM_SPRITE_COUNT];
XYTransformContext pos[DOUBLE_TEAM_SPRITE_COUNT];
} DoubleTeamContext;
enum DoubleTeamState {
DOUBLE_TEAM_STATE_INIT = 0,
DOUBLE_TEAM_STATE_UPDATE_SPRITES,
DOUBLE_TEAM_STATE_FADE_OUT_SPRITES,
};
// If X is the attacker sprite, double team performs the following transformations simultaneously:
// (Longer arrow means takes more frames)
// L1 <- X -> R1
// L2 <-- X --> R2
#define DOUBLE_TEAM_SPRITE_R1 0
#define DOUBLE_TEAM_SPRITE_L1 1
#define DOUBLE_TEAM_SPRITE_R2 2
#define DOUBLE_TEAM_SPRITE_L2 3
#define DOUBLE_TEAM_BLEND_A 8
#define DOUBLE_TEAM_BLEND_B 6
#define DOUBLE_TEAM_MON_1_PRIORITY 10
#define DOUBLE_TEAM_MON_2_PRIORITY 20
#define DOUBLE_TEAM_MON_1_TINT_R 128
#define DOUBLE_TEAM_MON_1_TINT_G 128
#define DOUBLE_TEAM_MON_1_TINT_B 128
#define DOUBLE_TEAM_MON_2_TINT_R 196
#define DOUBLE_TEAM_MON_2_TINT_G 196
#define DOUBLE_TEAM_MON_2_TINT_B 196
#define DOUBLE_TEAM_BASEPOS 0
#define DOUBLE_TEAM_RANGE_X 32
#define DOUBLE_TEAM_ITERATION_FRAMES_1 7
#define DOUBLE_TEAM_ITERATION_FRAMES_2 10
// One iteration is either a single outwards or inwards movement of all sprites
#define DOUBLE_TEAM_MAX_MOVE_ITERATIONS 8
// -------------------------------------------------------------------
// Growth
// -------------------------------------------------------------------
typedef struct GrowthContext {
u8 state;
u8 iterations;
u8 scaleState;
BattleAnimSystem *battleAnimSys;
PokemonSprite *sprite;
XYTransformContext scale;
} GrowthContext;
enum GrowthState {
GROWTH_STATE_SCALE_FADE = 0,
GROWTH_STATE_WAIT,
};
#define GROWTH_SCALE 115
#define GROWTH_SCALE_FRAMES 6
#define GROWTH_SCALE_CYCLES 2
#define GROWTH_BLINK_COLOR COLOR_WHITE
#define GROWTH_BLINK_ALPHA 6
// -------------------------------------------------------------------
// Meditate
// -------------------------------------------------------------------
typedef struct MeditateContext {
u8 state;
u8 iterations;
s16 attackerY;
s16 attackerHeight;
BattleAnimSystem *battleAnimSys;
PokemonSprite *attackerSprite;
XYTransformContext scale;
} MeditateContext;
enum MeditateState {
MEDITATE_STATE_SCALE,
MEDITATE_STATE_WAIT_FOR_SCALE,
};
#define MEDITATE_STRETCH_SCALE_X 150
#define MEDITATE_STRETCH_SCALE_Y 50
#define MEDITATE_SQUISH_SCALE_X 50
#define MEDITATE_SQUISH_SCALE_Y 150
#define MEDITATE_STRETCH_FRAMES 8
#define MEDITATE_SQUISH_FRAMES 8
#define MEDITATE_REVERT_FRAMES 8
// -------------------------------------------------------------------
// Teleport
// -------------------------------------------------------------------
typedef struct TeleportContext {
u8 state;
u8 scaleType;
s16 attackerY;
s16 baseY;
s16 attackerHeight;
BattleAnimSystem *battleAnimSys;
PokemonSprite *attackerSprite;
XYTransformContext scale;
} TeleportContext;
enum TeleportState {
TELEPORT_STATE_SETUP_SQUISH = 0,
TELEPORT_STATE_SQUISH,
TELEPORT_STATE_SETUP_MOVE,
TELEPORT_STATE_MOVE,
TELEPORT_STATE_SETUP_SHRINK,
TELEPORT_STATE_SHRINK,
};
#define TELEPORT_SQUISH_SCALE_X 10
#define TELEPORT_SQUISH_SCALE_Y 180
#define TELEPORT_SHRINK_SCALE_X 10
#define TELEPORT_SHRINK_SCALE_Y 0
#define TELEPORT_SQUISH_FRAMES 10
#define TELEPORT_SHRINK_FRAMES 5
#define TELEPORT_REVERT_POS_X 0
#define TELEPORT_REVERT_POS_Y 0
#define TELEPORT_REVERT_POS_FRAMES 5
// -------------------------------------------------------------------
// Flash
// -------------------------------------------------------------------
typedef struct FlashContext {
u8 state;
u8 delay;
PaletteData *paletteData;
BattleAnimSystem *battleAnimSys;
PaletteFadeContext *unk_0C;
PokemonSprite *attackerSprite;
} FlashContext;
enum FlashState {
FLASH_STATE_SETUP_FADE_OUT = 0,
FLASH_STATE_FADE_OUT,
FLASH_STATE_HOLD,
FLASH_STATE_SETUP_FADE_IN,
FLASH_STATE_FADE_IN,
};
#define FLASH_PALETTE_FADE_BUFFERS PLTTBUF_MAIN_BG_F
#define FLASH_FADE_START_ALPHA 0
#define FLASH_FADE_END_ALPHA 16
#define FLASH_PALETTE_FADE_DELAY -2
#define FLASH_POKEMON_FADE_DELAY 0
#define FLASH_PALETTE_FADE_COLOR COLOR_WHITE
#define FLASH_POKEMON_FADE_COLOR COLOR_BLACK
#define FLASH_HOLD_FRAMES 5
// -------------------------------------------------------------------
// Splash
// -------------------------------------------------------------------
typedef struct SplashContext {
u8 state;
u8 iteration;
u8 cycles;
s16 attackerY;
s16 attackerHeight;
BattleAnimSystem *battleAnimSys;
PokemonSprite *attackerSprite;
XYTransformContext scale;
XYTransformContext pos;
} SplashContext;
enum SplashState {
SPLASH_STATE_SETUP_ANIMS = 0,
SPLASH_STATE_WAIT_FOR_ANIMS,
};
#define SPLASH_CYCLES 3
#define SPLASH_BASE_SCALE BASE_SCALE_XY
#define SPLASH_STRETCH_SCALE 120
#define SPLASH_SQUISH_SCALE 80
#define SPLASH_ANIM_FRAMES 5
#define SPLASH_BASE_POS_Y 0
#define SPLASH_OFFSET_POS_Y 16
// -------------------------------------------------------------------
// Harden
// -------------------------------------------------------------------
typedef struct HardenContext {
u8 state;
u8 timer;
BattleAnimSystem *battleAnimSys;
SpriteManager *pokemonSpriteManager;
ManagedSprite *attackerSprite1;
ManagedSprite *attackerSprite2;
} HardenContext;
enum HardenState {
HARDEN_STATE_WAIT = 0,
HARDEN_STATE_ENABLE_SPRITES,
HARDEN_STATE_WAIT_DRAW,
};
#define HARDEN_TINT_R 256
#define HARDEN_TINT_G 256
#define HARDEN_TINT_B 256
#define HARDEN_START_DELAY 10
// -------------------------------------------------------------------
// Minimize
// -------------------------------------------------------------------
#define MINIMIZE_SPRITE_COUNT 3
typedef struct MinimizeSprite {
u8 state;
u8 frameCounter;
ManagedSprite *sprite;
XYTransformContext scale;
} MinimizeSprite;
typedef struct MinimizeContext {
u8 state;
u8 cycles;
s16 attackerY;
int attackerSpriteHeight;
s8 spriteDir;
PokemonSprite *attackerSprite;
BattleAnimSystem *battleAnimSys;
SpriteManager *pokemonSpriteManager;
MinimizeSprite sprites[MINIMIZE_SPRITE_COUNT];
} MinimizeContext;
enum MiminizeSpriteState {
MINIMIZE_SPRITE_STATE_INIT = 0,
MINIMIZE_SPRITE_STATE_SHRINK,
};
enum MinimizeState {
MINIMIZE_STATE_INIT = 0,
MINIMIZE_STATE_SHRINK,
MINIMIZE_STATE_SETUP_GROW,
MINIMIZE_STATE_GROW,
};
#define MINIMIZE_SPRITE_ALPHA 12
#define MINIMIZE_BG_ALPHA 6
#define MINIMIZE_SHRINK_SCALE_X 5
#define MINIMIZE_SHRINK_SCALE_Y 5
#define MINIMIZE_SHRINK_FRAMES 5
#define MINIMIZE_SHRINK_CYCLES 3
// -------------------------------------------------------------------
// Earthquake
// -------------------------------------------------------------------
typedef struct EarthquakeContext {
u8 state;
u8 shakeCount;
u8 flashFlag;
u8 flashDuration;
int spriteCount;
BgConfig *bgConfig;
BattleAnimSystem *battleAnimSys;
SpriteManager *pokemonSpriteManager;
BattleAnimSpriteInfo sprites[MAX_BATTLERS];
BattleAnimSpriteInfo unused[MAX_BATTLERS];
XYTransformContext shake;
} EarthquakeContext;
enum EarthquakeState {
EARTHQUAKE_STATE_INIT = 0,
EARTHQUAKE_STATE_FADE_BG,
EARTHQUAKE_STATE_FLASH,
EARTHQUAKE_STATE_SHAKE,
};
#define EARTHQUAKE_BG_FADE_DELAY 1
#define EARTHQUAKE_BG_FADE_ALPHA 10
#define EARTHQUAKE_BG_FADE_COLOR COLOR_BLACK
#define EARTHQUAKE_BG_FLASH_FRAMES 3
#define EARTHQUAKE_BG_FLASH_PALETTES 0xFF
#define EARTHQUAKE_BG_FLASH_ALPHA 10
#define EARTHQUAKE_BG_FLASH_OFF_ALPHA 0
#define EARTHQUAKE_BG_FLASH_OFF_COLOR COLOR_BLACK
#define EARTHQUAKE_BG_FLASH_0_COLOR COLOR_BLACK
#define EARTHQUAKE_BG_FLASH_1_COLOR COLOR_WHITE
#define EARTHQUAKE_SPRITE_SHAKE_EXTENT_Y 0
#define EARTHQUAKE_SPRITE_SHAKE_INTERVAL 0
#define EARTHQUAKE_SPRITE_SHAKE_AMOUNT 5
// -------------------------------------------------------------------
// Nightmare
// -------------------------------------------------------------------
typedef struct NightmareContext {
u8 state;
u8 unused;
u8 unk_02;
u8 unk_03;
Point2D monPos;
BgConfig *bgConfig;
BattleAnimSystem *system;
SpriteManager *pokemonSpriteManager;
PokemonSprite *monSprite;
ManagedSprite *xluSprite;
XYTransformContext shake; // Never initialized so it doesn't do anything
XYTransformContext pos;
AlphaFadeContext alpha;
} NightmareContext;
#define NIGHTMARE_SPRITE_START_ALPHA 31
#define NIGHTMARE_SPRITE_END_ALPHA 0
#define NIGHTMARE_BG_START_ALPHA 0
#define NIGHTMARE_BG_END_ALPHA 31
#define NIGHTMARE_SPRITE_OFFSET_X (-20)
#define NIGHTMARE_SPRITE_OFFSET_Y (20)
#define NIGHTMARE_SPRITE_OFFSET_FRAMES 20
#define NIGHTMARE_SPRITE_ALPHA_FRAMES (NIGHTMARE_SPRITE_OFFSET_FRAMES - 5)
#define NIGHTMARE_VAR_MOVE_ATTACKER 0
// -------------------------------------------------------------------
// Flail (animation), used by Struggle, Flail, Frustration, etc.
// -------------------------------------------------------------------
typedef struct FlailContext {
BattleAnimScriptFuncCommon common;
SpriteShakeInfo shakeInfo;
PokemonSprite *battlerSprites[2];
s16 unk_30;
s16 unk_32;
s16 unk_34;
s16 unk_36;
XYTransformContext shake;
ValueLerpContext angle;
} FlailContext;
enum FlailState {
FLAIL_MODE_ATTACKER_STATE_SETUP_ROTATION = 0,
FLAIL_MODE_ATTACKER_STATE_ROTATE,
FLAIL_MODE_DEFENDER_STATE_SETUP_SHAKE = 0,
FLAIL_MODE_DEFENDER_STATE_SHAKE,
};
#define FLAIL_WIGGLES 5
#define FLAIL_WIGGLE_PIVOT_Y 100
#define FLAIL_VAR_MODE 0
#define FLAIL_VAR_SHAKE_EXTENT_X 1
#define FLAIL_VAR_SHAKE_EXTENT_Y 2
#define FLAIL_VAR_SHAKE_INTERVAL 3
#define FLAIL_VAR_SHAKE_AMOUNT 4
// -------------------------------------------------------------------
// Magnitude
// -------------------------------------------------------------------
typedef struct MagnitudeContext {
BattleAnimScriptFuncCommon common;
SpriteShakeInfo unk_1C;
Point2D battlerPositions[MAX_BATTLERS];
PokemonSprite *battlerSprites[MAX_BATTLERS];
int power;
XYTransformContext shake;
} MagnitudeContext;
enum MagnitudeState {
MAGNITUDE_STATE_INIT = 0,
MAGNITUDE_STATE_SHAKE,
};
#define MAGNITUDE_POWER150_SHAKE_EXTENT 6
#define MAGNITUDE_POWER110_SHAKE_EXTENT 5
#define MAGNITUDE_POWER90_SHAKE_EXTENT 4
#define MAGNITUDE_POWER70_SHAKE_EXTENT 3
#define MAGNITUDE_POWER50_SHAKE_EXTENT 2
#define MAGNITUDE_POWER30_SHAKE_EXTENT 1
#define MAGNITUDE_DEFAULT_SHAKE_EXTENT 0
#define MAGNITUDE_SHAKE_BASE_EXTENT 2
#define MAGNITUDE_SHAKE_INTERVAL 0
#define MAGNITUDE_SHAKE_AMOUNT 10
// -------------------------------------------------------------------
// Odor Sleuth
// -------------------------------------------------------------------
typedef struct OdorSleuthContext {
BattleAnimScriptFuncCommon common;
SpriteShakeInfo unused;
Point2D spritePositions[NUM_BATTLE_SIDES];
PokemonSprite *battlerSprites[NUM_BATTLE_SIDES];
ManagedSprite *monSprites[NUM_BATTLE_SIDES];
XYTransformContext shake[NUM_BATTLE_SIDES];
} OdorSleuthContext;
enum OdorSleuthState {
ODOR_SLEUTH_STATE_INIT = 0,
ODOR_SLEUTH_STATE_SHAKE,
};
#define ODOR_SLEUTH_ATTACKER_SHAKE_EXTENT_X 20
#define ODOR_SLEUTH_ATTACKER_SHAKE_EXTENT_Y 0
#define ODOR_SLEUTH_ATTACKER_SHAKE_INTERVAL 0
#define ODOR_SLEUTH_ATTACKER_SHAKE_AMOUNT 10
#define ODOR_SLEUTH_DEFENDER_SHAKE_EXTENT_X 2 // Note: These "defender" values aren't actually used/applied.
#define ODOR_SLEUTH_DEFENDER_SHAKE_EXTENT_Y 0
#define ODOR_SLEUTH_DEFENDER_SHAKE_INTERVAL 0
#define ODOR_SLEUTH_DEFENDER_SHAKE_AMOUNT 10
typedef struct {
int unk_00;
int unk_04;
int unk_08;
Point2D unk_0C;
BattleAnimScriptFuncCommon unk_10;
SpriteShakeInfo unk_2C;
ManagedSprite *unk_38;
BattleAnimSpriteInfo unk_3C[4];
XYTransformContext unk_8C[2];
ValueLerpContext unk_D4;
} UnkStruct_ov12_0222CBFC;
// -------------------------------------------------------------------
// Surf
// -------------------------------------------------------------------
typedef struct SurfContext {
int state;
int holdTimer;
int unused0;
u8 alphaStart;
u8 alphaBg;
u8 alphaEnd;
u8 alphaReset;
u8 alphaTargetStart;
u8 alphaTargetBg;
s16 dir;
Point2D spritePos;
BattleAnimScriptFuncCommon common;
SpriteShakeInfo unused1;
ManagedSprite *currentSprite;
ManagedSprite *sprites[2];
BattleAnimSpriteInfo unused2[4];
XYTransformContext scale;
ValueLerpContext unused3;
} SurfContext;
enum SurfState {
SURF_STATE_COMPRESS = 0,
SURF_STATE_STRETCH,
SURF_STATE_HOLD,
SURF_STATE_RESTORE,
};
#define SURF_CONTEST_X (255 - 76)
#define SURF_CONTEST_Y 120
#define SURF_PLAYER_SIDE_X 76
#define SURF_PLAYER_SIDE_Y 120
#define SURF_ENEMY_SIDE_X 144
#define SURF_ENEMY_SIDE_Y 64
#define SURF_SCALE_INITIAL 100
#define SURF_SCALE_COMPRESSED 60
#define SURF_SCALE_STRETCHED 150
#define SURF_SCALE_FRAMES_INITIAL 5
#define SURF_SCALE_FRAMES_STRETCH 150
#define SURF_SCALE_FRAMES_COMPRESS 10
#define SURF_SCALE_FRAMES_GROW 12
#define SURF_HOLD_FRAMES 4
#define SURF_ALPHA_TRANSPARENT 0
#define SURF_ALPHA_OPAQUE 31
#define SURF_ALPHA_TARGET 4
#define SURF_SPRITE_HEIGHT 16
typedef struct {
ManagedSprite *unk_00;
XYTransformContext unk_04[2];
} UnkStruct_ov12_0222D128_sub1;
typedef struct {
u8 unk_00;
u8 unk_01;
int unk_04;
int unk_08;
u8 unk_0C;
BattleAnimSystem *unk_10;
SpriteSystem *unk_14;
SpriteManager *unk_18;
PokemonSprite *unk_1C;
s16 unk_20;
int unk_24;
u16 unk_28;
fx32 unk_2C;
UnkStruct_ov12_0222D128_sub1 unk_30[2];
s16 unk_C8;
s16 unk_CA;
XYTransformContext unk_CC;
} UnkStruct_ov12_0222D128;
static const u8 Unk_ov12_0223A09E[][2] = {
{ 0x8, 0x2 },
{ 0xD, 0x1 },
{ 0x12, 0x3 }
};
static void ov12_0222AC70(SysTask *param0, void *param1)
{
int v0;
UnkStruct_ov12_0222AC70 *v1 = (UnkStruct_ov12_0222AC70 *)param1;
switch (v1->unk_00) {
case 0:
v1->unk_04++;
for (v0 = 0; v0 < BattleAnimSystem_GetScriptVar(v1->unk_08, 0); v0++) {
{
s16 v2, v3;
ManagedSprite_GetPositionXY(v1->unk_14[v0], &v2, &v3);
}
if (v1->unk_04 >= Unk_ov12_0223A09E[v0][0]) {
v1->unk_01[v0]++;
if (v1->unk_01[v0] >= Unk_ov12_0223A09E[v0][1]) {
v1->unk_01[v0] = 0;
if (ManagedSprite_GetDrawFlag(v1->unk_14[v0]) == 1) {
ManagedSprite_SetDrawFlag(v1->unk_14[v0], 0);
} else {
ManagedSprite_SetDrawFlag(v1->unk_14[v0], 1);
}
}
} else {
ManagedSprite_SetDrawFlag(v1->unk_14[v0], 0);
}
}
if (v1->unk_04 >= 45) {
for (v0 = 0; v0 < BattleAnimSystem_GetScriptVar(v1->unk_08, 0); v0++) {
ManagedSprite_SetDrawFlag(v1->unk_14[v0], 1);
}
v1->unk_04 = 0;
v1->unk_00++;
}
break;
case 1:
ScaleLerpContext_InitXY(&v1->unk_20, 100, 60, 100, 100, 100, 10);
v1->unk_00++;
break;
case 2:
if (ScaleLerpContext_UpdateXY(&v1->unk_20) == 1) {
for (v0 = 0; v0 < BattleAnimSystem_GetScriptVar(v1->unk_08, 0); v0++) {
f32 v4, v5;
ScaleLerpContext_GetAffineScale(&v1->unk_20, &v4, &v5);
ManagedSprite_SetAffineScale(v1->unk_14[v0], v4, v5);
}
} else {
if (++v1->unk_04 >= 45) {
v1->unk_00++;
}
}
break;
case 3:
if (v1->unk_05 > 0) {
v1->unk_05--;
}
if (v1->unk_06 < 15) {
v1->unk_06++;
}
if ((v1->unk_05 == 0) && (v1->unk_06 == 15)) {
v1->unk_00++;
}
G2_ChangeBlendAlpha(v1->unk_05, v1->unk_06);
break;
default:
for (v0 = 0; v0 < BattleAnimSystem_GetScriptVar(v1->unk_08, 0); v0++) {
Sprite_DeleteAndFreeResources(v1->unk_14[v0]);
}
BattleAnimSystem_EndAnimTask(v1->unk_08, param0);
Heap_Free(v1);
return;
}
for (v0 = 0; v0 < BattleAnimSystem_GetScriptVar(v1->unk_08, 0); v0++) {
Sprite_TickFrame(v1->unk_14[v0]->sprite);
}
SpriteSystem_DrawSprites(v1->unk_10);
}
void ov12_0222AE68(BattleAnimSystem *param0, SpriteSystem *param1, SpriteManager *param2, ManagedSprite *param3)
{
int v0;
UnkStruct_ov12_0222AC70 *v1;
SpriteTemplate v2;
v1 = Heap_AllocFromHeap(BattleAnimSystem_GetHeapID(param0), sizeof(UnkStruct_ov12_0222AC70));
GF_ASSERT(v1 != NULL);
v1->unk_04 = 0;
v1->unk_00 = 0;
v1->unk_0C = param1;
v1->unk_10 = param2;
v1->unk_08 = param0;
v2 = BattleAnimSystem_GetLastSpriteTemplate(param0);
BattleAnimUtil_SetSpriteBgBlending(v1->unk_08, 0xffffffff, 0xffffffff);
v1->unk_05 = 15;
v1->unk_06 = 0;
G2_ChangeBlendAlpha(v1->unk_05, v1->unk_06);
v1->unk_14[0] = param3;
{
Point2D v3;
int v4 = BattleAnimUtil_GetBattlerSide(param0, BattleAnimSystem_GetDefender(param0));
if (v4 == 0x3) {
BattleAnimUtil_GetBattlerTypeDefaultPos(0, BattleAnimSystem_IsContest(param0), &v3);
} else {
BattleAnimUtil_GetBattlerTypeDefaultPos(1, BattleAnimSystem_IsContest(param0), &v3);
}
for (v0 = 1; v0 < BattleAnimSystem_GetScriptVar(v1->unk_08, 0); v0++) {
v1->unk_14[v0] = SpriteSystem_NewSprite(v1->unk_0C, v1->unk_10, &v2);
ManagedSprite_SetPositionXY(v1->unk_14[v0], v3.x, v3.y);
}
ManagedSprite_SetPositionXY(v1->unk_14[0], v3.x, v3.y);
}
for (v0 = 0; v0 < BattleAnimSystem_GetScriptVar(v1->unk_08, 0); v0++) {
v1->unk_01[v0] = 0;
ManagedSprite_SetAffineOverwriteMode(v1->unk_14[v0], AFFINE_OVERWRITE_MODE_DOUBLE);
ManagedSprite_OffsetPositionXY(v1->unk_14[v0], 0, 32 - (v0 * 4));
ManagedSprite_SetExplicitOamMode(v1->unk_14[v0], GX_OAM_MODE_XLU);
}
BattleAnimSystem_StartAnimTaskEx(param0, ov12_0222AC70, v1, 0x1000);
}
static void BattleAnimTask_Strength(SysTask *task, void *param)
{
StrengthContext *ctx = param;
switch (ctx->state) {
case STRENGTH_STATE_SHRINK:
if (ScaleLerpContext_Update(&ctx->scale) == TRUE) {
ShakeContext_Update(&ctx->shake);
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_SCALE_X, ctx->scale.x);
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_SCALE_Y, ctx->scale.y);
PokemonSprite_AddAttribute(ctx->sprite, MON_SPRITE_X_CENTER, ctx->shake.x);
s16 offset = BattleAnimUtil_GetGroundAnchoredScaleOffset(ctx->baseY, ctx->spriteHeight, ctx->scale.data[XY_PARAM_CUR_Y]);
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_Y_CENTER, ctx->baseY + offset);
} else {
ctx->state++;
}
break;
case STRENGTH_STATE_FADE_TO_RED:
PokemonSprite_StartFade(ctx->sprite, 0, STRENGTH_BLINK_ALPHA, 0, STRENGTH_BLINK_COLOR);
ctx->state++;
break;
case STRENGTH_STATE_FADE_TO_NORMAL:
if (PokemonSprite_IsFadeActive(ctx->sprite) == FALSE) {
PokemonSprite_StartFade(ctx->sprite, STRENGTH_BLINK_ALPHA, 0, 0, STRENGTH_BLINK_COLOR);
ctx->state++;
}
break;
case STRENGTH_STATE_WAIT_FOR_FADE:
if (PokemonSprite_IsFadeActive(ctx->sprite) == FALSE) {
ctx->blinkCounter++;
if (ctx->blinkCounter >= STRENGTH_BLINK_COUNT) {
ScaleLerpContext_Init(
&ctx->scale,
BattleAnimSystem_GetScriptVar(ctx->battleAnimSys, STRENGTH_VAR_SHRINK_SCALE),
100,
BattleAnimSystem_GetScriptVar(ctx->battleAnimSys, STRENGTH_VAR_GROW_SCALE),
BattleAnimSystem_GetScriptVar(ctx->battleAnimSys, STRENGTH_VAR_GROW_FRAMES));
ctx->state++;
} else {
ctx->state = STRENGTH_STATE_FADE_TO_RED;
}
}
break;
case STRENGTH_STATE_GROW:
if (ScaleLerpContext_Update(&ctx->scale) == TRUE) {
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_SCALE_X, ctx->scale.x);
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_SCALE_Y, ctx->scale.y);
s16 offset = BattleAnimUtil_GetGroundAnchoredScaleOffset(ctx->baseY, ctx->spriteHeight, ctx->scale.data[XY_PARAM_CUR_Y]);
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_Y_CENTER, ctx->baseY + offset);
} else {
ctx->state++;
}
break;
case STRENGTH_STATE_CLEANUP:
if (ScaleLerpContext_Update(&ctx->scale) == TRUE) {
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_SCALE_X, ctx->scale.x);
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_SCALE_Y, ctx->scale.y);
s16 offset = BattleAnimUtil_GetGroundAnchoredScaleOffset(ctx->baseY, ctx->spriteHeight, ctx->scale.data[XY_PARAM_CUR_Y]);
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_Y_CENTER, ctx->baseY + offset);
} else {
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_SCALE_X, MON_AFFINE_SCALE(1));
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_SCALE_Y, MON_AFFINE_SCALE(1));
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_Y_CENTER, ctx->baseY);
ctx->state++;
}
break;
default:
BattleAnimSystem_EndAnimTask(ctx->battleAnimSys, task);
Heap_Free(ctx);
break;
}
}
void BattleAnimScriptFunc_Strength(BattleAnimSystem *system)
{
StrengthContext *ctx = Heap_AllocFromHeap(BattleAnimSystem_GetHeapID(system), sizeof(StrengthContext));
ctx->blinkCounter = 0;
ctx->state = STRENGTH_STATE_SHRINK;
ctx->battleAnimSys = system;
ctx->sprite = BattleAnimSystem_GetBattlerSprite(ctx->battleAnimSys, BattleAnimSystem_GetAttacker(ctx->battleAnimSys));
ctx->baseY = PokemonSprite_GetAttribute(ctx->sprite, MON_SPRITE_Y_CENTER);
ctx->spriteHeight = BattleAnimSystem_GetBattlerSpriteOffset(ctx->battleAnimSys, BattleAnimSystem_GetAttacker(ctx->battleAnimSys));
ScaleLerpContext_Init(
&ctx->scale,
BASE_SCALE_XY,
BASE_SCALE_XY,
BattleAnimSystem_GetScriptVar(system, STRENGTH_VAR_SHRINK_SCALE),
BattleAnimSystem_GetScriptVar(system, STRENGTH_VAR_SHRINK_FRAMES));
ShakeContext_Init(&ctx->shake, STRENGTH_SHAKE_X, STRENGTH_SHAKE_Y, STRENGTH_SHAKE_INTERVAL, STRENGTH_SHAKE_AMOUNT);
BattleAnimSystem_StartAnimTask(ctx->battleAnimSys, BattleAnimTask_Strength, ctx);
}
static void BattleAnimTask_BulkUp(SysTask *task, void *param)
{
BulkUpContext *ctx = param;
switch (ctx->state) {
case BULK_UP_STATE_SQUISH_Y:
if (ScaleLerpContext_UpdateXY(&ctx->scale) == TRUE) {
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_SCALE_X, ctx->scale.x);
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_SCALE_Y, ctx->scale.y);
s16 offset = BattleAnimUtil_GetGroundAnchoredScaleOffset(ctx->baseY, ctx->spriteHeight, ctx->scale.data[XY_PARAM_CUR_Y]);
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_Y_CENTER, ctx->baseY + offset);
} else {
ScaleLerpContext_InitXY(
&ctx->scale,
BULK_UP_STRETCH_X,
BULK_UP_SQUISH_X,
BULK_UP_SQUISH_Y,
BULK_UP_STRETCH_Y,
BASE_SCALE_XY,
BULK_UP_SQUISH_STRETCH_FRAMES);
ctx->state++;
}
break;
case BULK_UP_STATE_SQUISH_X:
if (ScaleLerpContext_UpdateXY(&ctx->scale) == TRUE) {
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_SCALE_X, ctx->scale.x);
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_SCALE_Y, ctx->scale.y);
s16 offset = BattleAnimUtil_GetGroundAnchoredScaleOffset(ctx->baseY, ctx->spriteHeight, ctx->scale.data[XY_PARAM_CUR_Y]);
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_Y_CENTER, ctx->baseY + offset);
} else {
ScaleLerpContext_InitXY(
&ctx->scale,
BULK_UP_SQUISH_X,
BASE_SCALE_XY,
BULK_UP_STRETCH_Y,
BASE_SCALE_XY,
BASE_SCALE_XY,
BULK_UP_RETURN_TO_NORMAL_FRAMES);
ctx->state++;
}
break;
case BULK_UP_STATE_RETURN_TO_NORMAL:
if (ScaleLerpContext_UpdateXY(&ctx->scale) == TRUE) {
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_SCALE_X, ctx->scale.x);
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_SCALE_Y, ctx->scale.y);
s16 offset = BattleAnimUtil_GetGroundAnchoredScaleOffset(ctx->baseY, ctx->spriteHeight, ctx->scale.data[XY_PARAM_CUR_Y]);
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_Y_CENTER, ctx->baseY + offset);
} else {
ScaleLerpContext_InitXY(
&ctx->scale,
BASE_SCALE_XY,
BULK_UP_STRETCH_X,
BASE_SCALE_XY,
BULK_UP_STRETCH_Y,
BASE_SCALE_XY,
BULK_UP_GROW_FRAMES);
ctx->state++;
}
break;
case BULK_UP_STATE_GROW:
if (ScaleLerpContext_UpdateXY(&ctx->scale) == TRUE) {
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_SCALE_X, ctx->scale.x);
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_SCALE_Y, ctx->scale.y);
s16 offset = BattleAnimUtil_GetGroundAnchoredScaleOffset(ctx->baseY, ctx->spriteHeight, ctx->scale.data[XY_PARAM_CUR_Y]);
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_Y_CENTER, ctx->baseY + offset);
} else {
ScaleLerpContext_InitXY(
&ctx->scale,
BULK_UP_STRETCH_X,
BASE_SCALE_XY,
BULK_UP_STRETCH_Y,
BASE_SCALE_XY,
BASE_SCALE_XY,
BULK_UP_SHRINK_FRAMES);
ctx->state++;
}
break;
case BULK_UP_STATE_SHRINK:
if (ScaleLerpContext_UpdateXY(&ctx->scale) == TRUE) {
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_SCALE_X, ctx->scale.x);
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_SCALE_Y, ctx->scale.y);
s16 offset = BattleAnimUtil_GetGroundAnchoredScaleOffset(ctx->baseY, ctx->spriteHeight, ctx->scale.data[XY_PARAM_CUR_Y]);
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_Y_CENTER, ctx->baseY + offset);
} else {
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_SCALE_X, MON_AFFINE_SCALE(1));
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_SCALE_Y, MON_AFFINE_SCALE(1));
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_Y_CENTER, ctx->baseY);
ctx->state++;
}
break;
default:
BattleAnimSystem_EndAnimTask(ctx->battleAnimSys, task);
Heap_Free(ctx);
break;
}
}
void BattleAnimScriptFunc_BulkUp(BattleAnimSystem *system)
{
BulkUpContext *ctx = Heap_AllocFromHeap(BattleAnimSystem_GetHeapID(system), sizeof(BulkUpContext));
ctx->state = BULK_UP_STATE_SQUISH_Y;
ctx->battleAnimSys = system;
ctx->sprite = BattleAnimSystem_GetBattlerSprite(ctx->battleAnimSys, BattleAnimSystem_GetAttacker(ctx->battleAnimSys));
ctx->baseY = PokemonSprite_GetAttribute(ctx->sprite, MON_SPRITE_Y_CENTER);
ctx->spriteHeight = BattleAnimSystem_GetBattlerSpriteOffset(ctx->battleAnimSys, BattleAnimSystem_GetAttacker(ctx->battleAnimSys));
ScaleLerpContext_InitXY(
&ctx->scale,
BASE_SCALE_XY,
BULK_UP_STRETCH_X,
BASE_SCALE_XY,
BULK_UP_SQUISH_Y,
BASE_SCALE_XY,
BULK_UP_SQUISH_STRETCH_FRAMES);
BattleAnimSystem_StartAnimTask(ctx->battleAnimSys, BattleAnimTask_BulkUp, ctx);
}
enum DoubleTeamTableIndex {
DOUBLE_TEAM_TABLE_BASEPOS = 0,
DOUBLE_TEAM_TABLE_RANGE_X,
DOUBLE_TEAM_TABLE_ITERATION_FRAMES,
DOUBLE_TEAM_TABLE_COUNT
};
static const s16 sDoubleTeamPositions[][DOUBLE_TEAM_TABLE_COUNT] = {
{ DOUBLE_TEAM_BASEPOS, DOUBLE_TEAM_RANGE_X, DOUBLE_TEAM_ITERATION_FRAMES_1 },
{ DOUBLE_TEAM_BASEPOS, DOUBLE_TEAM_RANGE_X, DOUBLE_TEAM_ITERATION_FRAMES_2 },
{ DOUBLE_TEAM_RANGE_X, DOUBLE_TEAM_BASEPOS, DOUBLE_TEAM_ITERATION_FRAMES_1 },
{ DOUBLE_TEAM_RANGE_X, DOUBLE_TEAM_BASEPOS, DOUBLE_TEAM_ITERATION_FRAMES_2 }
};
static void BattleAnimTask_DoubleTeam(SysTask *task, void *param)
{
int i;
u8 numComplete;
DoubleTeamContext *ctx = param;
switch (ctx->state) {
case DOUBLE_TEAM_STATE_INIT: {
int posIndex = (ctx->iteration % 2) * 2;
int frameReduction = (ctx->iteration + 1) / 2;
PosLerpContext_Init(
&ctx->pos[DOUBLE_TEAM_SPRITE_R1],
ctx->attackerX + sDoubleTeamPositions[posIndex][DOUBLE_TEAM_TABLE_BASEPOS],
ctx->attackerX + sDoubleTeamPositions[posIndex][DOUBLE_TEAM_TABLE_RANGE_X],
ctx->attackerY,
ctx->attackerY,
sDoubleTeamPositions[posIndex][DOUBLE_TEAM_TABLE_ITERATION_FRAMES] - frameReduction);
PosLerpContext_Init(
&ctx->pos[DOUBLE_TEAM_SPRITE_L1],
ctx->attackerX - sDoubleTeamPositions[posIndex][DOUBLE_TEAM_TABLE_BASEPOS],
ctx->attackerX - sDoubleTeamPositions[posIndex][DOUBLE_TEAM_TABLE_RANGE_X],
ctx->attackerY,
ctx->attackerY,
sDoubleTeamPositions[posIndex][DOUBLE_TEAM_TABLE_ITERATION_FRAMES] - frameReduction);
PosLerpContext_Init(
&ctx->pos[DOUBLE_TEAM_SPRITE_R2],
ctx->attackerX + sDoubleTeamPositions[posIndex + 1][DOUBLE_TEAM_TABLE_BASEPOS],
ctx->attackerX + sDoubleTeamPositions[posIndex + 1][DOUBLE_TEAM_TABLE_RANGE_X],
ctx->attackerY,
ctx->attackerY,
sDoubleTeamPositions[posIndex + 1][DOUBLE_TEAM_TABLE_ITERATION_FRAMES] - frameReduction);
PosLerpContext_Init(
&ctx->pos[DOUBLE_TEAM_SPRITE_L2],
ctx->attackerX - sDoubleTeamPositions[posIndex + 1][DOUBLE_TEAM_TABLE_BASEPOS],
ctx->attackerX - sDoubleTeamPositions[posIndex + 1][DOUBLE_TEAM_TABLE_RANGE_X],
ctx->attackerY,
ctx->attackerY,
sDoubleTeamPositions[posIndex + 1][DOUBLE_TEAM_TABLE_ITERATION_FRAMES] - frameReduction);
}
ctx->iteration++;
ctx->state++;
case DOUBLE_TEAM_STATE_UPDATE_SPRITES:
numComplete = 0;
for (i = 0; i < DOUBLE_TEAM_SPRITE_COUNT; i++) {
if (PosLerpContext_Update(&ctx->pos[i]) == FALSE) {
numComplete++;
} else {
ManagedSprite_SetPositionXY(ctx->monSprites[i], ctx->pos[i].x, ctx->pos[i].y);
}
ManagedSprite_TickFrame(ctx->monSprites[i]);
}
if (numComplete == DOUBLE_TEAM_SPRITE_COUNT) {
if (ctx->iteration == DOUBLE_TEAM_MAX_MOVE_ITERATIONS + 1) {
ctx->state++;
} else {
ctx->state = DOUBLE_TEAM_STATE_INIT;
}
}
break;
case DOUBLE_TEAM_STATE_FADE_OUT_SPRITES:
if (ctx->blendA > 0) {
ctx->blendA--;
}
if (ctx->blendB < 15) {
ctx->blendB++;
}
if (ctx->blendA == 0 && ctx->blendB == 15) {
ctx->state++;
}
G2_ChangeBlendAlpha(ctx->blendA, ctx->blendB);
break;
default:
BattleAnimSystem_EndAnimTask(ctx->battleAnimSys, task);
Heap_Free(ctx);
return;
}
SpriteSystem_DrawSprites(ctx->pokemonSpriteManager);
}
void BattleAnimScriptFunc_DoubleTeam(BattleAnimSystem *system)
{
DoubleTeamContext *ctx = Heap_AllocFromHeap(BattleAnimSystem_GetHeapID(system), sizeof(DoubleTeamContext));
ctx->state = 0;
ctx->iteration = 0;
ctx->battleAnimSys = system;
ctx->attackerSprite = BattleAnimSystem_GetBattlerSprite(ctx->battleAnimSys, BattleAnimSystem_GetAttacker(ctx->battleAnimSys));
ctx->attackerX = PokemonSprite_GetAttribute(ctx->attackerSprite, MON_SPRITE_X_CENTER);
ctx->attackerY = PokemonSprite_GetAttribute(ctx->attackerSprite, MON_SPRITE_Y_CENTER);
ctx->attackerY -= PokemonSprite_GetAttribute(ctx->attackerSprite, MON_SPRITE_SHADOW_HEIGHT);
ctx->pokemonSpriteManager = BattleAnimSystem_GetPokemonSpriteManager(ctx->battleAnimSys);
ctx->blendA = DOUBLE_TEAM_BLEND_A;
ctx->blendB = DOUBLE_TEAM_BLEND_B;
BattleAnimUtil_SetSpriteBgBlending(ctx->battleAnimSys, -1, -1);
G2_ChangeBlendAlpha(ctx->blendA, ctx->blendB);
int monPlttIndex = BattleAnimSystem_GetBattlerSpritePaletteIndex(ctx->battleAnimSys, BattleAnimSystem_GetAttacker(ctx->battleAnimSys));
int monSpritePriority = BattleAnimSystem_GetPokemonSpritePriority(ctx->battleAnimSys);
enum NarcID monSpriteNarcIndex = BattleAnimSystem_GetBattlerSpriteNarcID(ctx->battleAnimSys, BattleAnimSystem_GetAttacker(ctx->battleAnimSys));
for (int i = 0; i < DOUBLE_TEAM_SPRITE_COUNT; i++) {
ctx->monSprites[i] = BattleAnimSystem_GetPokemonSprite(ctx->battleAnimSys, i);
ManagedSprite_SetExplicitOamMode(ctx->monSprites[i], GX_OAM_MODE_XLU);
}
if (BattleAnimUtil_GetBattlerSide(ctx->battleAnimSys, BattleAnimSystem_GetAttacker(ctx->battleAnimSys)) == BTLSCR_PLAYER) {
// Player side
ManagedSprite_SetPriority(ctx->monSprites[DOUBLE_TEAM_SPRITE_R1], DOUBLE_TEAM_MON_1_PRIORITY);
ManagedSprite_SetPriority(ctx->monSprites[DOUBLE_TEAM_SPRITE_L1], DOUBLE_TEAM_MON_1_PRIORITY);
ManagedSprite_SetPriority(ctx->monSprites[DOUBLE_TEAM_SPRITE_R2], DOUBLE_TEAM_MON_2_PRIORITY);
ManagedSprite_SetPriority(ctx->monSprites[DOUBLE_TEAM_SPRITE_L2], DOUBLE_TEAM_MON_2_PRIORITY);
ManagedSprite_SetExplicitPriority(ctx->monSprites[DOUBLE_TEAM_SPRITE_R1], monSpritePriority);
ManagedSprite_SetExplicitPriority(ctx->monSprites[DOUBLE_TEAM_SPRITE_L1], monSpritePriority);
ManagedSprite_SetExplicitPriority(ctx->monSprites[DOUBLE_TEAM_SPRITE_R2], monSpritePriority);
ManagedSprite_SetExplicitPriority(ctx->monSprites[DOUBLE_TEAM_SPRITE_L2], monSpritePriority);
u16 offset = PlttTransfer_GetPlttOffset(
Sprite_GetPaletteProxy(ctx->monSprites[DOUBLE_TEAM_SPRITE_R1]->sprite),
NNS_G2D_VRAM_TYPE_2DMAIN);
PaletteData_LoadBufferFromFileStartWithTint(
BattleAnimSystem_GetPaletteData(ctx->battleAnimSys),
monSpriteNarcIndex,
monPlttIndex,
BattleAnimSystem_GetHeapID(system),
PLTTBUF_MAIN_OBJ,
PALETTE_SIZE_BYTES,
PLTT_DEST(offset),
DOUBLE_TEAM_MON_1_TINT_R,
DOUBLE_TEAM_MON_1_TINT_G,
DOUBLE_TEAM_MON_1_TINT_B);
offset = PlttTransfer_GetPlttOffset(
Sprite_GetPaletteProxy(ctx->monSprites[DOUBLE_TEAM_SPRITE_R2]->sprite),
NNS_G2D_VRAM_TYPE_2DMAIN);
PaletteData_LoadBufferFromFileStartWithTint(
BattleAnimSystem_GetPaletteData(ctx->battleAnimSys),
monSpriteNarcIndex,
monPlttIndex,
BattleAnimSystem_GetHeapID(system),
PLTTBUF_MAIN_OBJ,
PALETTE_SIZE_BYTES,
PLTT_DEST(offset),
DOUBLE_TEAM_MON_2_TINT_R,
DOUBLE_TEAM_MON_2_TINT_G,
DOUBLE_TEAM_MON_2_TINT_B);
} else {
// Enemy side; flip mon 1 and 2 priorities
ManagedSprite_SetPriority(ctx->monSprites[DOUBLE_TEAM_SPRITE_R1], DOUBLE_TEAM_MON_2_PRIORITY);
ManagedSprite_SetPriority(ctx->monSprites[DOUBLE_TEAM_SPRITE_L1], DOUBLE_TEAM_MON_2_PRIORITY);
ManagedSprite_SetPriority(ctx->monSprites[DOUBLE_TEAM_SPRITE_R2], DOUBLE_TEAM_MON_1_PRIORITY);
ManagedSprite_SetPriority(ctx->monSprites[DOUBLE_TEAM_SPRITE_L2], DOUBLE_TEAM_MON_1_PRIORITY);
ManagedSprite_SetExplicitPriority(ctx->monSprites[DOUBLE_TEAM_SPRITE_R1], monSpritePriority + 1);
ManagedSprite_SetExplicitPriority(ctx->monSprites[DOUBLE_TEAM_SPRITE_L1], monSpritePriority + 1);
ManagedSprite_SetExplicitPriority(ctx->monSprites[DOUBLE_TEAM_SPRITE_R2], monSpritePriority + 1);
ManagedSprite_SetExplicitPriority(ctx->monSprites[DOUBLE_TEAM_SPRITE_L2], monSpritePriority + 1);
ManagedSprite_SetExplicitPriority(ctx->monSprites[DOUBLE_TEAM_SPRITE_R1], monSpritePriority);
ManagedSprite_SetExplicitPriority(ctx->monSprites[DOUBLE_TEAM_SPRITE_L1], monSpritePriority);
ManagedSprite_SetExplicitPriority(ctx->monSprites[DOUBLE_TEAM_SPRITE_R2], monSpritePriority);
ManagedSprite_SetExplicitPriority(ctx->monSprites[DOUBLE_TEAM_SPRITE_L2], monSpritePriority);
u16 offset = PlttTransfer_GetPlttOffset(
Sprite_GetPaletteProxy(ctx->monSprites[DOUBLE_TEAM_SPRITE_R1]->sprite),
NNS_G2D_VRAM_TYPE_2DMAIN);
PaletteData_LoadBufferFromFileStartWithTint(
BattleAnimSystem_GetPaletteData(ctx->battleAnimSys),
monSpriteNarcIndex,
monPlttIndex,
BattleAnimSystem_GetHeapID(system),
PLTTBUF_MAIN_OBJ,
PALETTE_SIZE_BYTES,
PLTT_DEST(offset),
DOUBLE_TEAM_MON_2_TINT_R,
DOUBLE_TEAM_MON_2_TINT_G,
DOUBLE_TEAM_MON_2_TINT_B);
offset = PlttTransfer_GetPlttOffset(
Sprite_GetPaletteProxy(ctx->monSprites[DOUBLE_TEAM_SPRITE_R2]->sprite),
NNS_G2D_VRAM_TYPE_2DMAIN);
PaletteData_LoadBufferFromFileStartWithTint(
BattleAnimSystem_GetPaletteData(ctx->battleAnimSys),
monSpriteNarcIndex,
monPlttIndex,
BattleAnimSystem_GetHeapID(system),
PLTTBUF_MAIN_OBJ,
PALETTE_SIZE_BYTES,
PLTT_DEST(offset),
DOUBLE_TEAM_MON_1_TINT_R,
DOUBLE_TEAM_MON_1_TINT_G,
DOUBLE_TEAM_MON_1_TINT_B);
}
BattleAnimSystem_StartAnimTask(ctx->battleAnimSys, BattleAnimTask_DoubleTeam, ctx);
}
enum {
GROWTH_TABLE_SCALE_START = 0,
GROWTH_TABLE_SCALE_END,
GROWTH_TABLE_FRAMES,
GROWTH_TABLE_COUNT
};
static const u8 sGrowthScaleTable[][GROWTH_TABLE_COUNT] = {
{ BASE_SCALE_XY, GROWTH_SCALE, GROWTH_SCALE_FRAMES },
{ GROWTH_SCALE, BASE_SCALE_XY, GROWTH_SCALE_FRAMES }
};
static void BattleAnimTask_Growth(SysTask *task, void *param)
{
GrowthContext *ctx = param;
switch (ctx->state) {
case GROWTH_STATE_SCALE_FADE:
ScaleLerpContext_Init(
&ctx->scale,
sGrowthScaleTable[ctx->scaleState][GROWTH_TABLE_SCALE_START],
BASE_SCALE_XY,
sGrowthScaleTable[ctx->scaleState][GROWTH_TABLE_SCALE_END],
sGrowthScaleTable[ctx->scaleState][GROWTH_TABLE_FRAMES]);
if (ctx->scaleState == 0) {
PokemonSprite_StartFade(ctx->sprite, 0, GROWTH_BLINK_ALPHA, 0, GROWTH_BLINK_COLOR);
} else {
PokemonSprite_StartFade(ctx->sprite, GROWTH_BLINK_ALPHA, 0, 0, GROWTH_BLINK_COLOR);
}
ctx->scaleState ^= 1;
ctx->iterations++;
ctx->state++;
break;
case GROWTH_STATE_WAIT:
if (ScaleLerpContext_Update(&ctx->scale) == FALSE && PokemonSprite_IsFadeActive(ctx->sprite) == FALSE) {
if (ctx->iterations < (GROWTH_SCALE_CYCLES * 2)) {
ctx->state--;
} else {
ctx->state++;
}
}
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_SCALE_X, ctx->scale.x);
PokemonSprite_SetAttribute(ctx->sprite, MON_SPRITE_SCALE_Y, ctx->scale.y);
break;
default:
BattleAnimSystem_EndAnimTask(ctx->battleAnimSys, task);
Heap_Free(ctx);
break;
}
}
void BattleAnimScriptFunc_Growth(BattleAnimSystem *system)
{
GrowthContext *ctx = BattleAnimUtil_Alloc(system, sizeof(GrowthContext));
ctx->state = GROWTH_STATE_SCALE_FADE;
ctx->scaleState = 0;
ctx->iterations = 0;
ctx->battleAnimSys = system;
ctx->sprite = BattleAnimSystem_GetBattlerSprite(ctx->battleAnimSys, BattleAnimSystem_GetAttacker(ctx->battleAnimSys));
BattleAnimSystem_StartAnimTask(ctx->battleAnimSys, BattleAnimTask_Growth, ctx);
}
enum {
MEDITATE_TABLE_SCALE_SX = 0,
MEDITATE_TABLE_SCALE_EX,
MEDITATE_TABLE_SCALE_SY,
MEDITATE_TABLE_SCALE_EY,
MEDITATE_TABLE_SCALE_FRAMES,
MEDITATE_TABLE_COUNT
};
static const u8 sMeditateScaleTable[][MEDITATE_TABLE_COUNT] = {
{ BASE_SCALE_XY, MEDITATE_STRETCH_SCALE_X, BASE_SCALE_XY, MEDITATE_STRETCH_SCALE_Y, MEDITATE_STRETCH_FRAMES },
{ MEDITATE_STRETCH_SCALE_X, MEDITATE_SQUISH_SCALE_X, MEDITATE_STRETCH_SCALE_Y, MEDITATE_SQUISH_SCALE_Y, MEDITATE_SQUISH_FRAMES },
{ MEDITATE_SQUISH_SCALE_X, BASE_SCALE_XY, MEDITATE_SQUISH_SCALE_Y, BASE_SCALE_XY, MEDITATE_REVERT_FRAMES }
};
static void BattleAnimTask_Meditate(SysTask *task, void *param)
{
MeditateContext *ctx = param;
switch (ctx->state) {
case MEDITATE_STATE_SCALE:
ScaleLerpContext_InitXY(
&ctx->scale,
sMeditateScaleTable[ctx->iterations][MEDITATE_TABLE_SCALE_SX],
sMeditateScaleTable[ctx->iterations][MEDITATE_TABLE_SCALE_EX],
sMeditateScaleTable[ctx->iterations][MEDITATE_TABLE_SCALE_SY],
sMeditateScaleTable[ctx->iterations][MEDITATE_TABLE_SCALE_EY],
BASE_SCALE_XY,
sMeditateScaleTable[ctx->iterations][MEDITATE_TABLE_SCALE_FRAMES]);
ctx->iterations++;
ctx->state++;
break;
case MEDITATE_STATE_WAIT_FOR_SCALE: {
if (ScaleLerpContext_UpdateXY(&ctx->scale) == FALSE) {
if (ctx->iterations < NELEMS(sMeditateScaleTable)) {
ctx->state--;
} else {
ctx->state++;
}
}
PokemonSprite_SetAttribute(ctx->attackerSprite, MON_SPRITE_SCALE_X, ctx->scale.x);
PokemonSprite_SetAttribute(ctx->attackerSprite, MON_SPRITE_SCALE_Y, ctx->scale.y);
s16 offset = BattleAnimUtil_GetGroundAnchoredScaleOffset(ctx->attackerY, ctx->attackerHeight, ctx->scale.data[XY_PARAM_CUR_Y]);
PokemonSprite_SetAttribute(ctx->attackerSprite, MON_SPRITE_Y_CENTER, ctx->attackerY + offset);
} break;
default:
BattleAnimSystem_EndAnimTask(ctx->battleAnimSys, task);
Heap_Free(ctx);
break;
}
}
void BattleAnimScriptFunc_Meditate(BattleAnimSystem *system)
{
MeditateContext *ctx = BattleAnimUtil_Alloc(system, sizeof(MeditateContext));
ctx->state = MEDITATE_STATE_SCALE;
ctx->iterations = 0;
ctx->battleAnimSys = system;
ctx->attackerSprite = BattleAnimSystem_GetBattlerSprite(ctx->battleAnimSys, BattleAnimSystem_GetAttacker(ctx->battleAnimSys));
ctx->attackerY = PokemonSprite_GetAttribute(ctx->attackerSprite, MON_SPRITE_Y_CENTER);
ctx->attackerHeight = BattleAnimSystem_GetBattlerSpriteOffset(ctx->battleAnimSys, BattleAnimSystem_GetAttacker(ctx->battleAnimSys));
BattleAnimSystem_StartAnimTask(ctx->battleAnimSys, BattleAnimTask_Meditate, ctx);
}
enum {
TELEPORT_TABLE_SCALE_SX = 0,
TELEPORT_TABLE_SCALE_EX,
TELEPORT_TABLE_SCALE_SY,
TELEPORT_TABLE_SCALE_EY,
TELEPORT_TABLE_SCALE_FRAMES,
TELEPORT_TABLE_COUNT
};
static const u8 sTeleportScaleTable[][TELEPORT_TABLE_COUNT] = {
{ BASE_SCALE_XY, TELEPORT_SQUISH_SCALE_X, BASE_SCALE_XY, TELEPORT_SQUISH_SCALE_Y, TELEPORT_SQUISH_FRAMES },
{ TELEPORT_SQUISH_SCALE_X, TELEPORT_SHRINK_SCALE_X, TELEPORT_SQUISH_SCALE_Y, TELEPORT_SHRINK_SCALE_Y, TELEPORT_SHRINK_FRAMES }
};
static void BattleAnimTask_Teleport(SysTask *task, void *param)
{
TeleportContext *ctx = param;
switch (ctx->state) {
case TELEPORT_STATE_SETUP_SQUISH:
ScaleLerpContext_InitXY(
&ctx->scale,
sTeleportScaleTable[ctx->scaleType][TELEPORT_TABLE_SCALE_SX],
sTeleportScaleTable[ctx->scaleType][TELEPORT_TABLE_SCALE_EX],
sTeleportScaleTable[ctx->scaleType][TELEPORT_TABLE_SCALE_SY],
sTeleportScaleTable[ctx->scaleType][TELEPORT_TABLE_SCALE_EY],
BASE_SCALE_XY,
sTeleportScaleTable[ctx->scaleType][TELEPORT_TABLE_SCALE_FRAMES]);
ctx->scaleType++;
ctx->state++;
break;
case TELEPORT_STATE_SQUISH:
if (ScaleLerpContext_UpdateXY(&ctx->scale) == FALSE) {
ctx->state++;
}
PokemonSprite_SetAttribute(ctx->attackerSprite, MON_SPRITE_SCALE_X, ctx->scale.x);
PokemonSprite_SetAttribute(ctx->attackerSprite, MON_SPRITE_SCALE_Y, ctx->scale.y);
BattleAnimUtil_SetPokemonSpriteAnchoredPosition(
ctx->attackerSprite,
ctx->attackerY,
ctx->attackerHeight,
ctx->scale.data[XY_PARAM_CUR_Y],
BATTLE_ANIM_ANCHOR_BOTTOM);
break;
case TELEPORT_STATE_SETUP_MOVE:
PosLerpContext_Init(
&ctx->scale,
0,
TELEPORT_REVERT_POS_X,
PokemonSprite_GetAttribute(ctx->attackerSprite, MON_SPRITE_Y_CENTER),
TELEPORT_REVERT_POS_Y,
TELEPORT_REVERT_POS_FRAMES);
ctx->state++;
break;
case TELEPORT_STATE_MOVE:
if (PosLerpContext_Update(&ctx->scale) == FALSE) {
ctx->state++;
}
PokemonSprite_SetAttribute(ctx->attackerSprite, MON_SPRITE_Y_CENTER, ctx->scale.y);
break;
case TELEPORT_STATE_SETUP_SHRINK:
ScaleLerpContext_InitXY(
&ctx->scale,
sTeleportScaleTable[ctx->scaleType][TELEPORT_TABLE_SCALE_SX],
sTeleportScaleTable[ctx->scaleType][TELEPORT_TABLE_SCALE_EX],
sTeleportScaleTable[ctx->scaleType][TELEPORT_TABLE_SCALE_SY],
sTeleportScaleTable[ctx->scaleType][TELEPORT_TABLE_SCALE_EY],
BASE_SCALE_XY,
sTeleportScaleTable[ctx->scaleType][TELEPORT_TABLE_SCALE_FRAMES]);
ctx->attackerY = PokemonSprite_GetAttribute(ctx->attackerSprite, MON_SPRITE_Y_CENTER);
ctx->state++;
break;
case TELEPORT_STATE_SHRINK:
if (ScaleLerpContext_UpdateXY(&ctx->scale) == FALSE) {
ctx->state++;
}
PokemonSprite_SetAttribute(ctx->attackerSprite, MON_SPRITE_SCALE_X, ctx->scale.x);
PokemonSprite_SetAttribute(ctx->attackerSprite, MON_SPRITE_SCALE_Y, ctx->scale.y);
BattleAnimUtil_SetPokemonSpriteAnchoredPosition(
ctx->attackerSprite,
ctx->attackerY,
ctx->attackerHeight,
ctx->scale.data[XY_PARAM_CUR_Y],
BATTLE_ANIM_ANCHOR_TOP);
break;
default:
PokemonSprite_SetAttribute(ctx->attackerSprite, MON_SPRITE_Y_CENTER, ctx->baseY);
PokemonSprite_SetAttribute(ctx->attackerSprite, MON_SPRITE_HIDE, TRUE);
PokemonSprite_SetAttribute(ctx->attackerSprite, MON_SPRITE_SCALE_X, MON_AFFINE_SCALE(1));
PokemonSprite_SetAttribute(ctx->attackerSprite, MON_SPRITE_SCALE_Y, MON_AFFINE_SCALE(1));
BattleAnimSystem_EndAnimTask(ctx->battleAnimSys, task);
Heap_Free(ctx);
break;
}
}
void BattleAnimScriptFunc_Teleport(BattleAnimSystem *system)
{
TeleportContext *ctx = BattleAnimUtil_Alloc(system, sizeof(TeleportContext));
ctx->state = TELEPORT_STATE_SETUP_SQUISH;
ctx->scaleType = 0;
ctx->battleAnimSys = system;
ctx->attackerSprite = BattleAnimSystem_GetBattlerSprite(ctx->battleAnimSys, BattleAnimSystem_GetAttacker(ctx->battleAnimSys));
ctx->attackerY = PokemonSprite_GetAttribute(ctx->attackerSprite, MON_SPRITE_Y_CENTER);
ctx->baseY = ctx->attackerY;
ctx->attackerHeight = BattleAnimSystem_GetBattlerSpriteOffset(ctx->battleAnimSys, BattleAnimSystem_GetAttacker(ctx->battleAnimSys));
BattleAnimSystem_StartAnimTask(ctx->battleAnimSys, BattleAnimTask_Teleport, ctx);
}
static void BattleAnimTask_Flash(SysTask *task, void *param)
{
FlashContext *ctx = param;
switch (ctx->state) {
case FLASH_STATE_SETUP_FADE_OUT:
PaletteData_StartFade(
ctx->paletteData,
FLASH_PALETTE_FADE_BUFFERS,
BattleAnimSystem_GetBaseBgPalettes(ctx->battleAnimSys),
FLASH_PALETTE_FADE_DELAY,
FLASH_FADE_START_ALPHA,
FLASH_FADE_END_ALPHA,
FLASH_PALETTE_FADE_COLOR);
PokemonSprite_StartFade(
ctx->attackerSprite,
FLASH_FADE_START_ALPHA,
FLASH_FADE_END_ALPHA,
FLASH_POKEMON_FADE_DELAY,
FLASH_POKEMON_FADE_COLOR);
ctx->state++;
break;
case FLASH_STATE_FADE_OUT:
if (PaletteData_GetSelectedBuffersMask(ctx->paletteData) == FALSE && PokemonSprite_IsFadeActive(ctx->attackerSprite) == FALSE) {
ctx->state++;
}
break;
case FLASH_STATE_HOLD:
if (++ctx->delay > FLASH_HOLD_FRAMES) {
ctx->state++;
}
break;
case FLASH_STATE_SETUP_FADE_IN:
PaletteData_StartFade(
ctx->paletteData,
FLASH_PALETTE_FADE_BUFFERS,
BattleAnimSystem_GetBaseBgPalettes(ctx->battleAnimSys),
FLASH_PALETTE_FADE_DELAY,
FLASH_FADE_END_ALPHA,
FLASH_FADE_START_ALPHA,
FLASH_PALETTE_FADE_COLOR);
PokemonSprite_StartFade(
ctx->attackerSprite,
FLASH_FADE_END_ALPHA,
FLASH_FADE_START_ALPHA,
FLASH_POKEMON_FADE_DELAY,
FLASH_POKEMON_FADE_COLOR);
ctx->state++;
break;
case FLASH_STATE_FADE_IN:
if (PaletteData_GetSelectedBuffersMask(ctx->paletteData) == FALSE && PokemonSprite_IsFadeActive(ctx->attackerSprite) == FALSE) {
ctx->state++;
}
break;
default:
BattleAnimSystem_EndAnimTask(ctx->battleAnimSys, task);
Heap_Free(ctx);
break;
}
}
void BattleAnimScriptFunc_Flash(BattleAnimSystem *system)
{
FlashContext *ctx = BattleAnimUtil_Alloc(system, sizeof(FlashContext));
ctx->battleAnimSys = system;
ctx->paletteData = BattleAnimSystem_GetPaletteData(ctx->battleAnimSys);
ctx->attackerSprite = BattleAnimSystem_GetBattlerSprite(ctx->battleAnimSys, BattleAnimSystem_GetAttacker(ctx->battleAnimSys));
BattleAnimSystem_StartAnimTask(ctx->battleAnimSys, BattleAnimTask_Flash, ctx);
}
enum {
SPLASH_TABLE_SCALE_SX = 0,
SPLASH_TABLE_SCALE_EX,
SPLASH_TABLE_SCALE_SY,
SPLASH_TABLE_SCALE_EY,
SPLASH_TABLE_SCALE_FRAMES,
SPLASH_TABLE_SCALE_COUNT,
SPLASH_TABLE_POS_SY = 0,
SPLASH_TABLE_POS_EY,
SPLASH_TABLE_POS_FRAMES,
SPLASH_TABLE_POS_COUNT
};
static const u8 sSplashScaleTable[][SPLASH_TABLE_SCALE_COUNT] = {
{ SPLASH_BASE_SCALE, SPLASH_STRETCH_SCALE, SPLASH_BASE_SCALE, SPLASH_SQUISH_SCALE, SPLASH_ANIM_FRAMES },
{ SPLASH_STRETCH_SCALE, SPLASH_BASE_SCALE, SPLASH_SQUISH_SCALE, SPLASH_STRETCH_SCALE, SPLASH_ANIM_FRAMES },
{ SPLASH_BASE_SCALE, SPLASH_BASE_SCALE, SPLASH_STRETCH_SCALE, SPLASH_BASE_SCALE, SPLASH_ANIM_FRAMES }
};
static const u8 sSplashPosTable[][SPLASH_TABLE_POS_COUNT] = {
{ SPLASH_BASE_POS_Y, SPLASH_OFFSET_POS_Y, SPLASH_ANIM_FRAMES },
{ SPLASH_OFFSET_POS_Y, SPLASH_BASE_POS_Y, SPLASH_ANIM_FRAMES },
{ SPLASH_BASE_POS_Y, SPLASH_BASE_POS_Y, SPLASH_ANIM_FRAMES }
};
static void BattleAnimTask_Splash(SysTask *task, void *param)
{
SplashContext *ctx = param;
switch (ctx->state) {
case SPLASH_STATE_SETUP_ANIMS:
ScaleLerpContext_InitXY(
&ctx->scale,
sSplashScaleTable[ctx->iteration][SPLASH_TABLE_SCALE_SX],
sSplashScaleTable[ctx->iteration][SPLASH_TABLE_SCALE_EX],
sSplashScaleTable[ctx->iteration][SPLASH_TABLE_SCALE_SY],
sSplashScaleTable[ctx->iteration][SPLASH_TABLE_SCALE_EY],
100,
sSplashScaleTable[ctx->iteration][SPLASH_TABLE_SCALE_FRAMES]);
PosLerpContext_Init(
&ctx->pos,
0,
0,
ctx->attackerY + sSplashPosTable[ctx->iteration][SPLASH_TABLE_POS_SY],
ctx->attackerY + sSplashPosTable[ctx->iteration][SPLASH_TABLE_POS_EY],
sSplashPosTable[ctx->iteration][SPLASH_TABLE_POS_FRAMES]);
ctx->iteration++;
ctx->state++;
break;
case SPLASH_STATE_WAIT_FOR_ANIMS: {
int done = 0;
if (ScaleLerpContext_UpdateXY(&ctx->scale) == FALSE) {
done++;
}
if (PosLerpContext_Update(&ctx->pos) == FALSE) {
done++;
}
if (done >= 2) {
if (ctx->iteration >= NELEMS(sSplashScaleTable)) {
ctx->cycles++;
ctx->iteration = 0;
if (ctx->cycles >= SPLASH_CYCLES) {
ctx->state++;
}
} else {
ctx->state = SPLASH_STATE_SETUP_ANIMS;
}
}
PokemonSprite_SetAttribute(ctx->attackerSprite, MON_SPRITE_SCALE_X, ctx->scale.x);
PokemonSprite_SetAttribute(ctx->attackerSprite, MON_SPRITE_SCALE_Y, ctx->scale.y);
BattleAnimUtil_SetPokemonSpriteAnchoredPosition(
ctx->attackerSprite,
ctx->pos.y,
ctx->attackerHeight,
ctx->scale.data[XY_PARAM_CUR_Y],
BATTLE_ANIM_ANCHOR_BOTTOM);
} break;
default:
BattleAnimSystem_EndAnimTask(ctx->battleAnimSys, task);
Heap_Free(ctx);
break;
}
}
void BattleAnimScriptFunc_Splash(BattleAnimSystem *system)
{
SplashContext *ctx = BattleAnimUtil_Alloc(system, sizeof(SplashContext));
ctx->state = SPLASH_STATE_SETUP_ANIMS;
ctx->iteration = 0;
ctx->battleAnimSys = system;
ctx->attackerSprite = BattleAnimSystem_GetBattlerSprite(ctx->battleAnimSys, BattleAnimSystem_GetAttacker(ctx->battleAnimSys));
ctx->attackerY = PokemonSprite_GetAttribute(ctx->attackerSprite, MON_SPRITE_Y_CENTER);
ctx->attackerHeight = BattleAnimSystem_GetBattlerSpriteOffset(ctx->battleAnimSys, BattleAnimSystem_GetAttacker(ctx->battleAnimSys));
BattleAnimSystem_StartAnimTask(ctx->battleAnimSys, BattleAnimTask_Splash, ctx);
}
static void BattleAnimTask_Harden(SysTask *task, void *param)
{
HardenContext *ctx = param;
switch (ctx->state) {
case HARDEN_STATE_WAIT:
if (++ctx->timer >= HARDEN_START_DELAY) {
ctx->timer = 0;
ctx->state++;
}
break;
case HARDEN_STATE_ENABLE_SPRITES:
ManagedSprite_SetDrawFlag(ctx->attackerSprite1, TRUE);
ManagedSprite_SetDrawFlag(ctx->attackerSprite2, TRUE);
ManagedSprite_SetExplicitOamMode(ctx->attackerSprite2, GX_OAM_MODE_OBJWND);
ctx->state++;
break;
case HARDEN_STATE_WAIT_DRAW:
if (++ctx->timer >= HARDEN_START_DELAY) {
G2_SetWndOutsidePlane(BATTLE_BG_WNDMASK_ALL | GX_WND_PLANEMASK_OBJ, FALSE);
G2_SetWndOBJInsidePlane(BATTLE_BG_WNDMASK_ALL | GX_WND_PLANEMASK_OBJ, FALSE);
ManagedSprite_SetDrawFlag(ctx->attackerSprite1, FALSE);
ManagedSprite_SetDrawFlag(ctx->attackerSprite2, FALSE);
ctx->timer = 0;
ctx->state++;
}
break;
default:
GX_SetVisibleWnd(GX_WNDMASK_NONE);
BattleAnimSystem_EndAnimTask(ctx->battleAnimSys, task);
Heap_Free(ctx);
return;
}
ManagedSprite_TickFrame(ctx->attackerSprite1);
ManagedSprite_TickFrame(ctx->attackerSprite2);
SpriteSystem_DrawSprites(ctx->pokemonSpriteManager);
}
void BattleAnimScriptFunc_Harden(BattleAnimSystem *system)
{
HardenContext *ctx = BattleAnimUtil_Alloc(system, sizeof(HardenContext));
ctx->battleAnimSys = system;
ctx->pokemonSpriteManager = BattleAnimSystem_GetPokemonSpriteManager(ctx->battleAnimSys);
ctx->attackerSprite1 = BattleAnimSystem_GetPokemonSprite(ctx->battleAnimSys, BATTLE_ANIM_MON_SPRITE_0);
ctx->attackerSprite2 = BattleAnimSystem_GetPokemonSprite(ctx->battleAnimSys, BATTLE_ANIM_MON_SPRITE_1);
GX_SetVisibleWnd(GX_WNDMASK_OW);
G2_SetWndOutsidePlane(BATTLE_BG_WNDMASK_ALL | GX_WND_PLANEMASK_OBJ, FALSE);
G2_SetWndOBJInsidePlane(BATTLE_BG_WNDMASK_WINDOW | GX_WND_PLANEMASK_OBJ, FALSE);
int paletteIndex = BattleAnimSystem_GetBattlerSpritePaletteIndex(ctx->battleAnimSys, BattleAnimSystem_GetAttacker(ctx->battleAnimSys));
int narcID = BattleAnimSystem_GetBattlerSpriteNarcID(ctx->battleAnimSys, BattleAnimSystem_GetAttacker(ctx->battleAnimSys));
int palOffset = PlttTransfer_GetPlttOffset(Sprite_GetPaletteProxy(ctx->attackerSprite1->sprite), NNS_G2D_VRAM_TYPE_2DMAIN);
PaletteData_LoadBufferFromFileStartWithTint(
BattleAnimSystem_GetPaletteData(ctx->battleAnimSys),
narcID,
paletteIndex,
BattleAnimSystem_GetHeapID(system),
PLTTBUF_MAIN_OBJ,
PALETTE_SIZE_BYTES,
PLTT_DEST(palOffset),
HARDEN_TINT_R,
HARDEN_TINT_G,
HARDEN_TINT_B);
ManagedSprite_SetDrawFlag(ctx->attackerSprite1, FALSE);
ManagedSprite_SetDrawFlag(ctx->attackerSprite2, FALSE);
BattleAnimSystem_StartAnimTask(ctx->battleAnimSys, BattleAnimTask_Harden, ctx);
}
static const u8 sMinimizeSpriteDelays[] = {
2, 7, 13, 18
};
static void BattleAnimTask_Minimize(SysTask *task, void *param)
{
int i;
int done;
MinimizeContext *ctx = param;
switch (ctx->state) {
case MINIMIZE_STATE_INIT:
PokemonSprite_SetAttribute(ctx->attackerSprite, MON_SPRITE_PARTIAL_DRAW, TRUE);
ctx->state++;
break;
case MINIMIZE_STATE_SHRINK:
done = 0;
for (i = 0; i < MINIMIZE_SPRITE_COUNT; i++) {
switch (ctx->sprites[i].state) {
case MINIMIZE_SPRITE_STATE_INIT:
if (++ctx->sprites[i].frameCounter >= sMinimizeSpriteDelays[i]) {
ScaleLerpContext_InitXY(
&ctx->sprites[i].scale,
BASE_SCALE_XY,
MINIMIZE_SHRINK_SCALE_X,
BASE_SCALE_XY,
MINIMIZE_SHRINK_SCALE_Y,
BASE_SCALE_XY,
MINIMIZE_SHRINK_FRAMES);
ctx->sprites[i].state++;
}
break;
case MINIMIZE_SPRITE_STATE_SHRINK:
if (ScaleLerpContext_UpdateXY(&ctx->sprites[i].scale) == FALSE) {
ctx->sprites[i].state++;
} else {
f32 scaleX, scaleY;
ScaleLerpContext_GetAffineScale(&ctx->sprites[i].scale, &scaleX, &scaleY);
ManagedSprite_SetAffineScale(ctx->sprites[i].sprite, scaleX * ctx->spriteDir, scaleY);
BattleAnimUtil_SetSpriteAnchoredPosition(
ctx->sprites[i].sprite,
ctx->attackerY,
ctx->attackerSpriteHeight,
ctx->sprites[i].scale.data[XY_PARAM_CUR_Y],
BATTLE_ANIM_ANCHOR_BOTTOM);
}
break;
default:
done++;
break;
}
ManagedSprite_TickFrame(ctx->sprites[i].sprite);
}
if (done >= MINIMIZE_SPRITE_COUNT) {
ctx->cycles++;
if (ctx->cycles < MINIMIZE_SHRINK_CYCLES) {
for (i = 0; i < MINIMIZE_SPRITE_COUNT; i++) {
s16 x, y;
ManagedSprite_GetPositionXY(ctx->sprites[i].sprite, &x, &y);
ManagedSprite_SetPositionXY(ctx->sprites[i].sprite, x, ctx->attackerY);
ManagedSprite_SetAffineScale(ctx->sprites[i].sprite, 1.0f * ctx->spriteDir, 1.0f);
ctx->sprites[i].state = MINIMIZE_SPRITE_STATE_INIT;
ctx->sprites[i].frameCounter = 0;
}
ctx->state--;
} else {
ctx->state++;
}
}
break;
case MINIMIZE_STATE_SETUP_GROW:
for (i = 0; i < MINIMIZE_SPRITE_COUNT; i++) {
ManagedSprite_SetExplicitOamMode(ctx->sprites[i].sprite, GX_OAM_MODE_NORMAL);
ScaleLerpContext_InitXY(
&ctx->sprites[i].scale,
MINIMIZE_SHRINK_SCALE_X,
BASE_SCALE_XY,
MINIMIZE_SHRINK_SCALE_Y,
BASE_SCALE_XY,
BASE_SCALE_XY,
MINIMIZE_SHRINK_FRAMES);
}
ctx->state++;
break;
case MINIMIZE_STATE_GROW:
done = 0;
for (i = 0; i < MINIMIZE_SPRITE_COUNT; i++) {
if (ScaleLerpContext_UpdateXY(&ctx->sprites[i].scale) == FALSE) {
done++;
} else {
f32 scaleX, scaleY;
ScaleLerpContext_GetAffineScale(&ctx->sprites[i].scale, &scaleX, &scaleY);
ManagedSprite_SetAffineScale(ctx->sprites[i].sprite, scaleX * ctx->spriteDir, scaleY);
BattleAnimUtil_SetSpriteAnchoredPosition(
ctx->sprites[i].sprite,
ctx->attackerY,
ctx->attackerSpriteHeight,
ctx->sprites[i].scale.data[XY_PARAM_CUR_Y],
BATTLE_ANIM_ANCHOR_BOTTOM);
}
}
if (done >= MINIMIZE_SPRITE_COUNT) {
ctx->state++;
}
break;
default:
PokemonSprite_SetAttribute(ctx->attackerSprite, MON_SPRITE_PARTIAL_DRAW, 0);
BattleAnimSystem_EndAnimTask(ctx->battleAnimSys, task);
Heap_Free(ctx);
return;
}
SpriteSystem_DrawSprites(ctx->pokemonSpriteManager);
}
void BattleAnimScriptFunc_Minimize(BattleAnimSystem *system)
{
MinimizeContext *ctx = BattleAnimUtil_Alloc(system, sizeof(MinimizeContext));
ctx->state = MINIMIZE_STATE_INIT;
ctx->cycles = 0;
ctx->battleAnimSys = system;
ctx->pokemonSpriteManager = BattleAnimSystem_GetPokemonSpriteManager(ctx->battleAnimSys);
ctx->attackerSprite = BattleAnimSystem_GetBattlerSprite(ctx->battleAnimSys, BattleAnimSystem_GetAttacker(ctx->battleAnimSys));
ctx->attackerY = PokemonSprite_GetAttribute(ctx->attackerSprite, MON_SPRITE_Y_CENTER);
ctx->attackerY -= PokemonSprite_GetAttribute(ctx->attackerSprite, MON_SPRITE_SHADOW_HEIGHT);
ctx->attackerSpriteHeight = BattleAnimSystem_GetBattlerSpriteOffset(ctx->battleAnimSys, BattleAnimSystem_GetAttacker(ctx->battleAnimSys));
BattleAnimUtil_SetSpriteBgBlending(ctx->battleAnimSys, BATTLE_ANIM_DEFAULT_ALPHA, BATTLE_ANIM_DEFAULT_ALPHA);
G2_ChangeBlendAlpha(MINIMIZE_SPRITE_ALPHA, MINIMIZE_BG_ALPHA);
for (int i = 0; i < MINIMIZE_SPRITE_COUNT; i++) {
ctx->sprites[i].state = MINIMIZE_SPRITE_STATE_INIT;
ctx->sprites[i].frameCounter = 0;
ctx->sprites[i].sprite = BattleAnimSystem_GetPokemonSprite(ctx->battleAnimSys, i);
ManagedSprite_SetAffineOverwriteMode(ctx->sprites[i].sprite, AFFINE_OVERWRITE_MODE_DOUBLE);
ManagedSprite_SetExplicitOamMode(ctx->sprites[i].sprite, GX_OAM_MODE_XLU);
ManagedSprite_SetPriority(ctx->sprites[i].sprite, i + 1);
}
if (BattleAnimSystem_ShouldBattlerSpriteBeFlipped(system, BATTLER_TYPE_ATTACKER) == TRUE) {
ctx->spriteDir = -1;
} else {
ctx->spriteDir = +1;
}
for (int i = 0; i < MINIMIZE_SPRITE_COUNT; i++) {
ManagedSprite_SetAffineScale(ctx->sprites[i].sprite, 1.0f * ctx->spriteDir, 1.0f);
}
BattleAnimSystem_StartAnimTask(ctx->battleAnimSys, BattleAnimTask_Minimize, ctx);
}
static const s16 sEarthquakeShakeExtents[] = {
12, 10, 8, 6, 4, 2, 1, 0
};
static void BattleAnimTask_Earthquake(SysTask *task, void *param)
{
EarthquakeContext *ctx = param;
switch (ctx->state) {
case EARTHQUAKE_STATE_INIT:
PaletteData_StartFade(
BattleAnimSystem_GetPaletteData(ctx->battleAnimSys),
PLTTBUF_MAIN_BG_F,
BattleAnimSystem_GetBaseBgPalettes(ctx->battleAnimSys),
EARTHQUAKE_BG_FADE_DELAY,
0,
EARTHQUAKE_BG_FADE_ALPHA,
EARTHQUAKE_BG_FADE_COLOR);
ctx->state++;
break;
case EARTHQUAKE_STATE_FADE_BG:
if (PaletteData_GetSelectedBuffersMask(BattleAnimSystem_GetPaletteData(ctx->battleAnimSys)) != 0) {
break;
}
ctx->state++;
case EARTHQUAKE_STATE_FLASH:
ShakeContext_Init(
&ctx->shake,
sEarthquakeShakeExtents[ctx->shakeCount],
EARTHQUAKE_SPRITE_SHAKE_EXTENT_Y,
EARTHQUAKE_SPRITE_SHAKE_INTERVAL,
EARTHQUAKE_SPRITE_SHAKE_AMOUNT);
if (ctx->flashFlag == 0) {
PaletteData_BlendMulti(
BattleAnimSystem_GetPaletteData(ctx->battleAnimSys),
PLTTBUF_MAIN_BG,
EARTHQUAKE_BG_FLASH_PALETTES,
EARTHQUAKE_BG_FLASH_ALPHA,
EARTHQUAKE_BG_FLASH_0_COLOR);
} else {
PaletteData_BlendMulti(
BattleAnimSystem_GetPaletteData(ctx->battleAnimSys),
PLTTBUF_MAIN_BG,
EARTHQUAKE_BG_FLASH_PALETTES,
EARTHQUAKE_BG_FLASH_ALPHA,
EARTHQUAKE_BG_FLASH_1_COLOR);
}
ctx->flashDuration = EARTHQUAKE_BG_FLASH_FRAMES;
ctx->flashFlag ^= 1;
ctx->shakeCount++;
ctx->state++;
case EARTHQUAKE_STATE_SHAKE:
if (ShakeContext_Update(&ctx->shake) == FALSE) {
if (ctx->shakeCount >= NELEMS(sEarthquakeShakeExtents)) {
ctx->state++;
} else {
ctx->state--;
}
}
if (ctx->flashDuration > 0) {
ctx->flashDuration--;
if (ctx->flashDuration == 0) {
PaletteData_BlendMulti(
BattleAnimSystem_GetPaletteData(ctx->battleAnimSys),
PLTTBUF_MAIN_BG,
EARTHQUAKE_BG_FLASH_PALETTES,
EARTHQUAKE_BG_FLASH_OFF_ALPHA,
EARTHQUAKE_BG_FLASH_OFF_COLOR);
}
}
for (int i = 0; i < MAX_BATTLERS; i++) {
if (ctx->sprites[i].monSprite == NULL) {
continue;
}
PokemonSprite_SetAttribute(ctx->sprites[i].monSprite, MON_SPRITE_X_CENTER, ctx->sprites[i].basePos.x + ctx->shake.x);
}
Bg_SetOffset(ctx->bgConfig, BATTLE_BG_EFFECT, 0, ctx->shake.x);
break;
default:
BattleAnimSystem_EndAnimTask(ctx->battleAnimSys, task);
Heap_Free(ctx);
break;
}
}
void BattleAnimScriptFunc_Earthquake(BattleAnimSystem *system)
{
EarthquakeContext *ctx = BattleAnimUtil_Alloc(system, sizeof(EarthquakeContext));
ctx->state = EARTHQUAKE_STATE_INIT;
ctx->shakeCount = 0;
ctx->battleAnimSys = system;
ctx->pokemonSpriteManager = BattleAnimSystem_GetPokemonSpriteManager(ctx->battleAnimSys);
ctx->bgConfig = BattleAnimSystem_GetBgConfig(ctx->battleAnimSys);
int sprites = BattleAnimSystem_IsDoubleBattle(ctx->battleAnimSys) == TRUE
? BATTLE_ANIM_ALL_BATTLERS
: (BATTLE_ANIM_ATTACKER | BATTLE_ANIM_DEFENDER);
BattleAnimUtil_GetBattlerSprites(system, sprites, &ctx->sprites[0], &ctx->spriteCount);
for (int i = 0; i < ctx->spriteCount; i++) {
ctx->sprites[i].basePos.x = PokemonSprite_GetAttribute(ctx->sprites[i].monSprite, MON_SPRITE_X_CENTER);
ctx->sprites[i].basePos.y = PokemonSprite_GetAttribute(ctx->sprites[i].monSprite, MON_SPRITE_Y_CENTER);
}
BattleAnimSystem_StartAnimTask(ctx->battleAnimSys, BattleAnimTask_Earthquake, ctx);
}
static void BattleAnimTask_Nightmare(SysTask *task, void *param)
{
NightmareContext *ctx = param;
switch (ctx->state) {
case 0:
if (PosLerpContext_Update(&ctx->pos) == FALSE) {
ctx->state++;
}
// Doesn't do anything
ShakeContext_Update(&ctx->shake);
AlphaFadeContext_IsDone(&ctx->alpha);
ManagedSprite_SetPositionXY(ctx->xluSprite, ctx->pos.x, ctx->pos.y);
ManagedSprite_TickFrame(ctx->xluSprite);
SpriteSystem_DrawSprites(ctx->pokemonSpriteManager);
break;
default:
BattleAnimSystem_EndAnimTask(ctx->system, task);
Heap_Free(ctx);
break;
}
}
void BattleAnimScriptFunc_Nightmare(BattleAnimSystem *system)
{
NightmareContext *ctx = BattleAnimUtil_Alloc(system, sizeof(NightmareContext));
ctx->state = 0;
ctx->unused = 0;
ctx->system = system;
ctx->pokemonSpriteManager = BattleAnimSystem_GetPokemonSpriteManager(ctx->system);
ctx->bgConfig = BattleAnimSystem_GetBgConfig(ctx->system);
ctx->xluSprite = BattleAnimSystem_GetPokemonSprite(ctx->system, BATTLE_ANIM_MON_SPRITE_0);
int battler;
if (BattleAnimSystem_GetScriptVar(system, NIGHTMARE_VAR_MOVE_ATTACKER) == FALSE) {
battler = BattleAnimSystem_GetDefender(ctx->system);
} else {
battler = BattleAnimSystem_GetAttacker(ctx->system);
}
ctx->monSprite = BattleAnimSystem_GetBattlerSprite(ctx->system, battler);
BattleAnimUtil_GetMonSpritePos(ctx->monSprite, &ctx->monPos);
ctx->monPos.y -= PokemonSprite_GetAttribute(ctx->monSprite, MON_SPRITE_SHADOW_HEIGHT);
int dirX = BattleAnimUtil_GetTransformDirectionX(ctx->system, battler);
int dirY = BattleAnimUtil_GetTransformDirectionY(ctx->system, battler);
PosLerpContext_Init(
&ctx->pos,
ctx->monPos.x,
ctx->monPos.x + NIGHTMARE_SPRITE_OFFSET_X * dirX,
ctx->monPos.y,
ctx->monPos.y + NIGHTMARE_SPRITE_OFFSET_Y * dirY,
NIGHTMARE_SPRITE_OFFSET_FRAMES);
BattleAnimUtil_SetSpriteBlending(
ctx->system,
(1 << BattleAnimSystem_GetBgID(system, BATTLE_ANIM_BG_EFFECT)) | GX_BLEND_PLANEMASK_BD | (1 << BattleAnimSystem_GetBgID(system, BATTLE_ANIM_BG_BASE)) | GX_WND_PLANEMASK_BG0,
BATTLE_ANIM_DEFAULT_ALPHA,
BATTLE_ANIM_DEFAULT_ALPHA);
AlphaFadeContext_Init(
&ctx->alpha,
NIGHTMARE_SPRITE_START_ALPHA,
NIGHTMARE_SPRITE_END_ALPHA,
NIGHTMARE_BG_START_ALPHA,
NIGHTMARE_BG_END_ALPHA,
NIGHTMARE_SPRITE_ALPHA_FRAMES);
ManagedSprite_SetExplicitOamMode(ctx->xluSprite, GX_OAM_MODE_XLU);
BattleAnimSystem_StartAnimTask(ctx->system, BattleAnimTask_Nightmare, ctx);
}
enum {
FLAIL_ANGLE_TABLE_ANGLE = 0,
FLAIL_ANGLE_TABLE_FRAMES,
};
static const int sFlailAngles[][2] = {
{ DEG_TO_IDX(20), 3 },
{ DEG_TO_IDX(15), 3 },
{ DEG_TO_IDX(10), 2 },
{ DEG_TO_IDX(5), 2 },
{ DEG_TO_IDX(0), 1 }
};
static void BattleAnimTask_FlailAttackerMode(SysTask *task, void *param)
{
FlailContext *ctx = param;
switch (ctx->common.state) {
case FLAIL_MODE_ATTACKER_STATE_SETUP_ROTATION: {
int startAngle;
int endAngle;
if (ctx->common.counter1 == 0) {
startAngle = -sFlailAngles[ctx->common.counter2][FLAIL_ANGLE_TABLE_ANGLE];
endAngle = +sFlailAngles[ctx->common.counter2][FLAIL_ANGLE_TABLE_ANGLE];
} else {
startAngle = +sFlailAngles[ctx->common.counter2][FLAIL_ANGLE_TABLE_ANGLE];
endAngle = -sFlailAngles[ctx->common.counter2][FLAIL_ANGLE_TABLE_ANGLE];
}
ValueLerpContext_Init(
&ctx->angle,
startAngle,
endAngle,
sFlailAngles[ctx->common.counter2][FLAIL_ANGLE_TABLE_FRAMES]);
if (ctx->common.counter1 == 1) {
ctx->common.counter2++;
}
ctx->common.counter1 ^= 1;
ctx->common.state++;
}
case FLAIL_MODE_ATTACKER_STATE_ROTATE:
if (ValueLerpContext_Update(&ctx->angle) == TRUE) {
PokemonSprite_SetAttribute(
ctx->battlerSprites[BATTLER_TYPE_ATTACKER],
MON_SPRITE_ROTATION_Z,
(u16)ctx->angle.value);
} else {
if (ctx->common.counter2 >= FLAIL_WIGGLES) {
ctx->common.state++;
} else {
ctx->common.state--;
}
}
break;
default:
PokemonSprite_SetAttribute(ctx->battlerSprites[BATTLER_TYPE_ATTACKER], MON_SPRITE_ROTATION_Z, 0);
BattleAnimSystem_EndAnimTask(ctx->common.battleAnimSys, task);
Heap_Free(ctx);
break;
}
}
static void BattleAnimTask_FlailDefenderMode(SysTask *task, void *param)
{
FlailContext *ctx = param;
switch (ctx->common.state) {
case FLAIL_MODE_DEFENDER_STATE_SETUP_SHAKE:
ShakeContext_Init(
&ctx->shake,
ctx->shakeInfo.extentX,
ctx->shakeInfo.extentY,
ctx->shakeInfo.interval,
ctx->shakeInfo.amount);
ctx->common.state++;
break;
case FLAIL_MODE_DEFENDER_STATE_SHAKE: {
Point2D pos;
BattleAnimUtil_GetMonSpritePos(ctx->battlerSprites[BATTLER_TYPE_DEFENDER], &pos);
if (ShakeContext_UpdateAndApplyToMon(&ctx->shake, pos.x, pos.y, ctx->battlerSprites[BATTLER_TYPE_DEFENDER]) == FALSE) {
ctx->common.state++;
}
} break;
default:
BattleAnimSystem_EndAnimTask(ctx->common.battleAnimSys, task);
Heap_Free(ctx);
break;
}
}
void BattleAnimScriptFunc_Flail(BattleAnimSystem *system)
{
FlailContext *ctx = BattleAnimUtil_Alloc(system, sizeof(FlailContext));
BattleAnimSystem_GetCommonData(system, &ctx->common);
ctx->battlerSprites[BATTLER_TYPE_ATTACKER] = BattleAnimSystem_GetBattlerSprite(
ctx->common.battleAnimSys,
BattleAnimSystem_GetAttacker(ctx->common.battleAnimSys));
ctx->battlerSprites[BATTLER_TYPE_DEFENDER] = BattleAnimSystem_GetBattlerSprite(
ctx->common.battleAnimSys,
BattleAnimSystem_GetDefender(ctx->common.battleAnimSys));
PokemonSprite_SetAttribute(ctx->battlerSprites[BATTLER_TYPE_ATTACKER], MON_SPRITE_Y_PIVOT, FLAIL_WIGGLE_PIVOT_Y);
int mode = BattleAnimSystem_GetScriptVar(system, FLAIL_VAR_MODE);
ctx->shakeInfo.extentX = BattleAnimSystem_GetScriptVar(system, FLAIL_VAR_SHAKE_EXTENT_X);
ctx->shakeInfo.extentY = BattleAnimSystem_GetScriptVar(system, FLAIL_VAR_SHAKE_EXTENT_Y);
ctx->shakeInfo.interval = BattleAnimSystem_GetScriptVar(system, FLAIL_VAR_SHAKE_INTERVAL);
ctx->shakeInfo.amount = BattleAnimSystem_GetScriptVar(system, FLAIL_VAR_SHAKE_AMOUNT);
ctx->shakeInfo.targets = BattleAnimSystem_GetScriptVar(system, 5);
if (mode == FLAIL_MODE_ATTACKER) {
BattleAnimSystem_StartAnimTask(ctx->common.battleAnimSys, BattleAnimTask_FlailAttackerMode, ctx);
} else {
BattleAnimSystem_StartAnimTask(ctx->common.battleAnimSys, BattleAnimTask_FlailDefenderMode, ctx);
}
}
static void BattleAnimTask_Magnitude(SysTask *task, void *param1)
{
MagnitudeContext *ctx = param1;
switch (ctx->common.state) {
case MAGNITUDE_STATE_INIT:
ShakeContext_Init(
&ctx->shake,
MAGNITUDE_SHAKE_BASE_EXTENT + ctx->power,
ctx->power,
MAGNITUDE_SHAKE_INTERVAL,
MAGNITUDE_SHAKE_AMOUNT);
ctx->common.state++;
break;
case MAGNITUDE_STATE_SHAKE:
if (ShakeContext_Update(&ctx->shake) == FALSE) {
ctx->common.state++;
} else {
for (int battler = 0; battler < MAX_BATTLERS; battler++) {
if (ctx->battlerSprites[battler] == NULL) {
continue;
}
PokemonSprite_SetAttribute(
ctx->battlerSprites[battler],
MON_SPRITE_X_CENTER,
ctx->battlerPositions[battler].x + ctx->shake.x);
}
Bg_SetOffset(ctx->common.bgConfig, BATTLE_BG_EFFECT, BG_OFFSET_UPDATE_SET_X, ctx->shake.x);
Bg_SetOffset(ctx->common.bgConfig, BATTLE_BG_EFFECT, BG_OFFSET_UPDATE_SET_Y, ctx->shake.y);
}
break;
default:
BattleAnimSystem_EndAnimTask(ctx->common.battleAnimSys, task);
Heap_Free(ctx);
break;
}
}
void BattleAnimScriptFunc_Magnitude(BattleAnimSystem *system)
{
MagnitudeContext *ctx = BattleAnimUtil_Alloc(system, sizeof(MagnitudeContext));
BattleAnimSystem_GetCommonData(system, &ctx->common);
int power = BattleAnimSystem_GetMoveInfo(ctx->common.battleAnimSys, BATTLE_ANIM_MOVE_INFO_POWER);
switch (power) {
case 150:
ctx->power = MAGNITUDE_POWER150_SHAKE_EXTENT;
break;
case 110:
ctx->power = MAGNITUDE_POWER110_SHAKE_EXTENT;
break;
case 90:
ctx->power = MAGNITUDE_POWER90_SHAKE_EXTENT;
break;
case 70:
ctx->power = MAGNITUDE_POWER70_SHAKE_EXTENT;
break;
case 50:
ctx->power = MAGNITUDE_POWER50_SHAKE_EXTENT;
break;
case 30:
ctx->power = MAGNITUDE_POWER30_SHAKE_EXTENT;
break;
default:
ctx->power = MAGNITUDE_DEFAULT_SHAKE_EXTENT;
break;
}
for (int battler = 0; battler < MAX_BATTLERS; battler++) {
ctx->battlerSprites[battler] = BattleAnimSystem_GetBattlerSprite(ctx->common.battleAnimSys, battler);
if (ctx->battlerSprites[battler] == NULL) {
continue;
}
BattleAnimUtil_GetMonSpritePos(ctx->battlerSprites[battler], &ctx->battlerPositions[battler]);
}
BattleAnimSystem_StartAnimTask(ctx->common.battleAnimSys, BattleAnimTask_Magnitude, ctx);
}
static void BattleAnimTask_OdorSleuth(SysTask *task, void *param)
{
OdorSleuthContext *ctx = param;
switch (ctx->common.state) {
case 0:
ShakeContext_Init(
&ctx->shake[BATTLER_TYPE_ATTACKER],
ODOR_SLEUTH_ATTACKER_SHAKE_EXTENT_X,
ODOR_SLEUTH_ATTACKER_SHAKE_EXTENT_Y,
ODOR_SLEUTH_ATTACKER_SHAKE_INTERVAL,
ODOR_SLEUTH_ATTACKER_SHAKE_AMOUNT);
ShakeContext_Init(
&ctx->shake[BATTLER_TYPE_DEFENDER],
ODOR_SLEUTH_DEFENDER_SHAKE_EXTENT_X,
ODOR_SLEUTH_DEFENDER_SHAKE_EXTENT_Y,
ODOR_SLEUTH_DEFENDER_SHAKE_INTERVAL,
ODOR_SLEUTH_DEFENDER_SHAKE_AMOUNT);
ctx->common.state++;
break;
case 1:
if (ShakeContext_Update(&ctx->shake[BATTLER_TYPE_ATTACKER]) == FALSE) {
ctx->common.state++;
} else {
ManagedSprite_SetPositionXY(
ctx->monSprites[BATTLER_TYPE_ATTACKER],
+ctx->spritePositions[BATTLER_TYPE_DEFENDER].x + ctx->shake[BATTLER_TYPE_ATTACKER].x,
ctx->spritePositions[BATTLER_TYPE_DEFENDER].y + ctx->shake[BATTLER_TYPE_ATTACKER].y);
ManagedSprite_SetPositionXY(
ctx->monSprites[BATTLER_TYPE_DEFENDER],
-ctx->spritePositions[BATTLER_TYPE_DEFENDER].x + ctx->shake[BATTLER_TYPE_ATTACKER].x,
ctx->spritePositions[BATTLER_TYPE_DEFENDER].y + ctx->shake[BATTLER_TYPE_ATTACKER].y);
ManagedSprite_TickFrame(ctx->monSprites[BATTLER_TYPE_ATTACKER]);
ManagedSprite_TickFrame(ctx->monSprites[BATTLER_TYPE_DEFENDER]);
}
SpriteSystem_DrawSprites(ctx->common.pokemonSpriteManager);
break;
default:
BattleAnimSystem_EndAnimTask(ctx->common.battleAnimSys, task);
Heap_Free(ctx);
break;
}
}
void BattleAnimScriptFunc_OdorSleuth(BattleAnimSystem *system)
{
OdorSleuthContext *ctx = BattleAnimUtil_Alloc(system, sizeof(OdorSleuthContext));
BattleAnimSystem_GetCommonData(system, &ctx->common);
ctx->monSprites[BATTLER_TYPE_ATTACKER] = BattleAnimSystem_GetPokemonSprite(ctx->common.battleAnimSys, BATTLE_ANIM_MON_SPRITE_0);
ctx->monSprites[BATTLER_TYPE_DEFENDER] = BattleAnimSystem_GetPokemonSprite(ctx->common.battleAnimSys, BATTLE_ANIM_MON_SPRITE_1);
ctx->battlerSprites[BATTLER_TYPE_ATTACKER] = BattleAnimSystem_GetBattlerSprite(ctx->common.battleAnimSys, BattleAnimSystem_GetAttacker(ctx->common.battleAnimSys));
ctx->battlerSprites[BATTLER_TYPE_DEFENDER] = BattleAnimSystem_GetBattlerSprite(ctx->common.battleAnimSys, BattleAnimSystem_GetDefender(ctx->common.battleAnimSys));
BattleAnimUtil_GetMonSpritePos(ctx->battlerSprites[BATTLER_TYPE_ATTACKER], &ctx->spritePositions[BATTLER_TYPE_ATTACKER]);
BattleAnimUtil_GetMonSpritePos(ctx->battlerSprites[BATTLER_TYPE_DEFENDER], &ctx->spritePositions[BATTLER_TYPE_DEFENDER]);
BattleAnimSystem_StartAnimTask(ctx->common.battleAnimSys, BattleAnimTask_OdorSleuth, ctx);
}
static void ov12_0222CBFC(SysTask *param0, void *param1)
{
int v0;
UnkStruct_ov12_0222CBFC *v1 = (UnkStruct_ov12_0222CBFC *)param1;
if (ov12_02225D2C(&v1->unk_8C[0], &v1->unk_8C[1], v1->unk_38) == 0) {
Sprite_DeleteAndFreeResources(v1->unk_38);
BattleAnimSystem_EndAnimTask(v1->unk_10.battleAnimSys, param0);
BattleAnimUtil_Free(v1);
(v1) = NULL;
return;
}
if (ValueLerpContext_Update(&v1->unk_D4) == 1) {
ManagedSprite_SetAffineZRotation(v1->unk_38, v1->unk_D4.value);
}
ManagedSprite_TickFrame(v1->unk_38);
SpriteSystem_DrawSprites(v1->unk_10.primarySpriteManager);
}
void ov12_0222CC54(BattleAnimSystem *param0, SpriteSystem *param1, SpriteManager *param2, ManagedSprite *param3)
{
int v0;
int v1;
UnkStruct_ov12_0222CBFC *v2 = BattleAnimUtil_Alloc(param0, sizeof(UnkStruct_ov12_0222CBFC));
BattleAnimSystem_GetCommonData(param0, &v2->unk_10);
v2->unk_0C.x = BattleAnimSystem_GetScriptVar(param0, 0);
v2->unk_0C.y = BattleAnimSystem_GetScriptVar(param0, 1);
v2->unk_04 = BattleAnimSystem_GetScriptVar(param0, 2);
v2->unk_08 = BattleAnimSystem_GetScriptVar(param0, 3);
v1 = BattleAnimUtil_GetTransformDirectionX(param0, BattleAnimSystem_GetAttacker(param0));
v2->unk_38 = param3;
ManagedSprite_SetAffineOverwriteMode(v2->unk_38, AFFINE_OVERWRITE_MODE_DOUBLE);
v2->unk_3C[0].monSprite = BattleAnimSystem_GetBattlerSprite(param0, BattleAnimSystem_GetAttacker(param0));
v2->unk_3C[1].monSprite = BattleAnimSystem_GetBattlerSprite(param0, BattleAnimSystem_GetDefender(param0));
BattleAnimUtil_GetMonSpritePos(v2->unk_3C[0].monSprite, &v2->unk_3C[0].pos);
BattleAnimUtil_GetMonSpritePos(v2->unk_3C[1].monSprite, &v2->unk_3C[1].pos);
XYTransformContext_InitParabolic(&v2->unk_8C[0], &v2->unk_8C[1], v2->unk_3C[0].pos.x, v2->unk_3C[1].pos.x + (v2->unk_0C.x * v1), v2->unk_3C[0].pos.y, v2->unk_3C[1].pos.y + (v2->unk_0C.y * v1), v2->unk_04, v2->unk_08 * FX32_ONE);
if ((BattleAnimSystem_GetBattlerType(param0, BattleAnimSystem_GetAttacker(param0)) == 4) && (BattleAnimSystem_GetBattlerType(param0, BattleAnimSystem_GetDefender(param0)) == 2)) {
v1 *= -1;
}
if ((BattleAnimSystem_GetBattlerType(param0, BattleAnimSystem_GetAttacker(param0)) == 5) && (BattleAnimSystem_GetBattlerType(param0, BattleAnimSystem_GetDefender(param0)) == 3)) {
v1 *= -1;
}
if (v1 > 0) {
ValueLerpContext_Init(&v2->unk_D4, ((20 * 0xffff) / 360) * v1, ((130 * 0xffff) / 360) * v1, 10);
} else {
ValueLerpContext_Init(&v2->unk_D4, ((90 * 0xffff) / 360) * v1, ((130 * 0xffff) / 360) * v1, 10);
}
ManagedSprite_SetAffineZRotation(v2->unk_38, v2->unk_D4.value);
ov12_02225D2C(&v2->unk_8C[0], &v2->unk_8C[1], v2->unk_38);
ManagedSprite_TickFrame(v2->unk_38);
BattleAnimSystem_StartAnimTask(v2->unk_10.battleAnimSys, ov12_0222CBFC, v2);
}
static void BattleAnimTask_Surf(SysTask *task, void *param)
{
SurfContext *ctx = param;
switch (ctx->common.state) {
case SURF_STATE_COMPRESS:
ScaleLerpContext_InitXY(
&ctx->scale,
SURF_SCALE_INITIAL * ctx->dir,
SURF_SCALE_COMPRESSED * ctx->dir,
SURF_SCALE_FRAMES_INITIAL,
SURF_SCALE_STRETCHED,
SURF_SCALE_INITIAL,
SURF_SCALE_FRAMES_GROW);
ctx->common.state++;
break;
case SURF_STATE_STRETCH:
if (ScaleLerpContext_UpdateXY(&ctx->scale) == FALSE) {
ScaleLerpContext_InitXY(&ctx->scale, SURF_SCALE_COMPRESSED * ctx->dir, SURF_SCALE_STRETCHED * ctx->dir, SURF_SCALE_FRAMES_STRETCH, SURF_SCALE_FRAMES_COMPRESS, SURF_SCALE_INITIAL, SURF_SCALE_FRAMES_GROW);
ctx->common.state++;
} else {
f32 scaleX, scaleY;
ScaleLerpContext_GetAffineScale(&ctx->scale, &scaleX, &scaleY);
ManagedSprite_SetAffineScale(ctx->currentSprite, scaleX, scaleY);
s16 offsetY = BattleAnimUtil_GetGroundAnchoredScaleOffset(ctx->spritePos.y, SURF_SPRITE_HEIGHT, ctx->scale.data[4]);
ManagedSprite_SetPositionXY(ctx->currentSprite, ctx->spritePos.x, ctx->spritePos.y + offsetY);
if (ctx->alphaStart < ctx->alphaTargetStart) {
ctx->alphaStart++;
}
if (ctx->alphaBg > ctx->alphaTargetBg) {
ctx->alphaBg--;
}
G2_ChangeBlendAlpha(ctx->alphaStart, ctx->alphaBg);
}
break;
case SURF_STATE_HOLD:
if (++ctx->holdTimer >= SURF_HOLD_FRAMES) {
ctx->common.state++;
}
break;
case SURF_STATE_RESTORE:
if (ScaleLerpContext_UpdateXY(&ctx->scale) == FALSE) {
ctx->common.state++;
} else {
f32 scaleX, scaleY;
ScaleLerpContext_GetAffineScale(&ctx->scale, &scaleX, &scaleY);
ManagedSprite_SetAffineScale(ctx->currentSprite, scaleX, scaleY);
s16 offsetY = BattleAnimUtil_GetGroundAnchoredScaleOffset(ctx->spritePos.y, SURF_SPRITE_HEIGHT, ctx->scale.data[4]);
ManagedSprite_SetPositionXY(ctx->currentSprite, ctx->spritePos.x, ctx->spritePos.y + offsetY);
if (ctx->alphaStart > ctx->alphaEnd) {
ctx->alphaStart--;
}
if (ctx->alphaBg < ctx->alphaReset) {
ctx->alphaBg++;
}
G2_ChangeBlendAlpha(ctx->alphaStart, ctx->alphaBg);
}
break;
default:
Sprite_DeleteAndFreeResources(ctx->sprites[0]);
Sprite_DeleteAndFreeResources(ctx->sprites[1]);
BattleAnimSystem_EndAnimTask(ctx->common.battleAnimSys, task);
BattleAnimUtil_Free(ctx);
(ctx) = NULL;
return;
}
ManagedSprite_TickFrame(ctx->currentSprite);
SpriteSystem_DrawSprites(ctx->common.primarySpriteManager);
}
void BattleAnimScriptFunc_Surf(BattleAnimSystem *system)
{
SurfContext *ctx = BattleAnimUtil_Alloc(system, sizeof(SurfContext));
BattleAnimSystem_GetCommonData(system, &ctx->common);
ctx->sprites[0] = BattleAnimSystem_GetSprite(system, 0);
ctx->sprites[1] = BattleAnimSystem_GetSprite(system, 1);
BattleAnimUtil_SetSpriteBgBlending(ctx->common.battleAnimSys, BATTLE_ANIM_DEFAULT_ALPHA, BATTLE_ANIM_DEFAULT_ALPHA);
if (BattleAnimSystem_GetScriptVar(system, 0) == 0) {
ctx->alphaStart = SURF_ALPHA_TRANSPARENT;
ctx->alphaBg = SURF_ALPHA_OPAQUE;
ctx->alphaEnd = SURF_ALPHA_TRANSPARENT;
ctx->alphaReset = SURF_ALPHA_OPAQUE;
ctx->alphaTargetStart = SURF_ALPHA_OPAQUE;
ctx->alphaTargetBg = SURF_ALPHA_TARGET;
} else {
ctx->alphaStart = SURF_ALPHA_TRANSPARENT;
ctx->alphaBg = SURF_ALPHA_OPAQUE;
ctx->alphaEnd = SURF_ALPHA_TRANSPARENT;
ctx->alphaReset = SURF_ALPHA_OPAQUE;
ctx->alphaTargetStart = SURF_ALPHA_OPAQUE;
ctx->alphaTargetBg = SURF_ALPHA_TARGET;
}
if (BattleAnimSystem_IsContest(system) == TRUE) {
ctx->currentSprite = ctx->sprites[0];
ManagedSprite_SetDrawFlag(ctx->sprites[1], FALSE);
ManagedSprite_SetAnim(ctx->currentSprite, 0);
ctx->spritePos.x = SURF_CONTEST_X;
ctx->spritePos.y = SURF_CONTEST_Y;
ManagedSprite_SetExplicitPriority(
ctx->currentSprite,
BattleAnimSystem_GetPokemonSpritePriority(system) + 1);
ctx->dir = -1;
} else {
if (BattleAnimUtil_GetBattlerSide(system, BattleAnimSystem_GetAttacker(system))
== BTLSCR_ENEMY) {
ctx->currentSprite = ctx->sprites[1];
ManagedSprite_SetDrawFlag(ctx->sprites[0], FALSE);
ManagedSprite_SetAnim(ctx->currentSprite, 1);
ctx->spritePos.x = SURF_ENEMY_SIDE_X;
ctx->spritePos.y = SURF_ENEMY_SIDE_Y;
} else {
ctx->currentSprite = ctx->sprites[0];
ManagedSprite_SetDrawFlag(ctx->sprites[1], FALSE);
ManagedSprite_SetAnim(ctx->currentSprite, 0);
ctx->spritePos.x = SURF_PLAYER_SIDE_X;
ctx->spritePos.y = SURF_PLAYER_SIDE_Y;
ManagedSprite_SetExplicitPriority(
ctx->currentSprite,
BattleAnimSystem_GetPokemonSpritePriority(system) + 1);
}
ctx->dir = 1;
}
ManagedSprite_SetPositionXY(ctx->currentSprite, ctx->spritePos.x, ctx->spritePos.y);
ManagedSprite_SetAffineOverwriteMode(ctx->currentSprite, AFFINE_OVERWRITE_MODE_DOUBLE);
ManagedSprite_SetExplicitOamMode(ctx->currentSprite, GX_OAM_MODE_XLU);
ScaleLerpContext_InitXY(
&ctx->scale,
SURF_SCALE_INITIAL * ctx->dir,
SURF_SCALE_INITIAL * ctx->dir,
SURF_SCALE_INITIAL,
SURF_SCALE_FRAMES_INITIAL,
SURF_SCALE_INITIAL,
1);
ScaleLerpContext_UpdateXY(&ctx->scale);
f32 scaleX, scaleY;
ScaleLerpContext_GetAffineScale(&ctx->scale, &scaleX, &scaleY);
ManagedSprite_SetAffineScale(ctx->currentSprite, scaleX, scaleY);
s16 offsetY = BattleAnimUtil_GetGroundAnchoredScaleOffset(
ctx->spritePos.y,
SURF_SPRITE_HEIGHT,
ctx->scale.data[XY_PARAM_CUR_Y]);
ManagedSprite_SetPositionXY(ctx->currentSprite, ctx->spritePos.x, ctx->spritePos.y + offsetY);
BattleAnimSystem_StartAnimTask(ctx->common.battleAnimSys, BattleAnimTask_Surf, ctx);
}
static const u8 Unk_ov12_0223A0D0[][5] = {
{ 0x64, 0x64, 0x64, 0x46, 0x8 },
{ 0x64, 0x64, 0x46, 0x78, 0x3 },
{ 0x64, 0x64, 0x78, 0x64, 0x3 }
};
static void ov12_0222D128(SysTask *param0, void *param1)
{
int v0;
UnkStruct_ov12_0222D128 *v1 = (UnkStruct_ov12_0222D128 *)param1;
switch (v1->unk_00) {
case 0:
ScaleLerpContext_InitXY(&v1->unk_CC, Unk_ov12_0223A0D0[v1->unk_0C][0], Unk_ov12_0223A0D0[v1->unk_0C][1], Unk_ov12_0223A0D0[v1->unk_0C][2], Unk_ov12_0223A0D0[v1->unk_0C][3], 100, Unk_ov12_0223A0D0[v1->unk_0C][4]);
v1->unk_0C++;
v1->unk_00++;
break;
case 1:
if (ScaleLerpContext_UpdateXY(&v1->unk_CC) == 1) {
PokemonSprite_SetAttribute(v1->unk_1C, MON_SPRITE_SCALE_X, v1->unk_CC.x);
PokemonSprite_SetAttribute(v1->unk_1C, MON_SPRITE_SCALE_Y, v1->unk_CC.y);
{
s16 v2 = BattleAnimUtil_GetGroundAnchoredScaleOffset(v1->unk_20, v1->unk_24, v1->unk_CC.data[4]);
PokemonSprite_SetAttribute(v1->unk_1C, MON_SPRITE_Y_CENTER, v1->unk_20 + v2);
}
} else {
if (v1->unk_0C >= 3) {
v1->unk_00++;
} else {
v1->unk_00--;
}
}
break;
case 2:
if ((++v1->unk_01) >= 1) {
v1->unk_01 = 0;
v1->unk_0C = 0;
v1->unk_00++;
}
break;
case 3: {
s16 v3, v4;
ManagedSprite_GetPositionXY(v1->unk_30[0].unk_00, &v3, &v4);
if (v4 <= ((40 - 16 + 20 + 10) + 50)) {
ManagedSprite_OffsetPositionXY(v1->unk_30[0].unk_00, 0, 2);
ManagedSprite_OffsetPositionXY(v1->unk_30[1].unk_00, 0, 2);
} else {
v1->unk_00++;
}
} break;
case 4: {
s16 v5, v6;
ManagedSprite_GetPositionXY(v1->unk_30[0].unk_00, &v5, &v6);
if (v6 <= ((40 - 16 + 20 + 10) + 50)) {
ManagedSprite_OffsetPositionXY(v1->unk_30[0].unk_00, 0, 2);
ManagedSprite_OffsetPositionXY(v1->unk_30[1].unk_00, 0, 2);
} else {
G2_ChangeBlendAlpha(16, 0);
v1->unk_00++;
}
}
v1->unk_01++;
ov12_022267A8(&v1->unk_04, 16, +16);
ov12_022267A8(&v1->unk_08, 0, -16);
G2_ChangeBlendAlpha(v1->unk_04, v1->unk_08);
if (v1->unk_01 == 10) {
ManagedSprite_OffsetPositionXY(v1->unk_30[0].unk_00, 0, 16);
}
if (v1->unk_01 == 12) {
ManagedSprite_OffsetPositionXY(v1->unk_30[1].unk_00, 0, 16);
}
break;
case 5:
if ((++v1->unk_01) < 1) {
break;
}
v1->unk_01 = 0;
{
s16 v7, v8, v9, v10;
ManagedSprite_GetPositionXY(v1->unk_30[0].unk_00, &v7, &v8);
ManagedSprite_GetPositionXY(v1->unk_30[1].unk_00, &v9, &v10);
ov12_02226728(v7, v8, v9, v10, &v1->unk_C8, &v1->unk_CA);
ov12_02226744(v7, v8, v1->unk_C8, v1->unk_CA, &v1->unk_2C);
ov12_0222676C(v7, v8, v1->unk_C8, v1->unk_CA, &v1->unk_28);
v1->unk_2C = (40 * FX32_ONE);
}
v1->unk_00++;
break;
case 6: {
s16 v11, v12, v13, v14;
s8 v15[][2] = {
{ +1, -1 },
{ -1, +1 },
{ +1, -1 },
{ +1, -1 },
{ +1, -1 },
};
ManagedSprite_GetPositionXY(v1->unk_30[0].unk_00, &v11, &v12);
ManagedSprite_GetPositionXY(v1->unk_30[1].unk_00, &v13, &v14);
XYTransformContext_InitParabolic(&v1->unk_30[0].unk_04[0], &v1->unk_30[0].unk_04[1], v11, v13, v12, v14, 10, v1->unk_2C * v15[v1->unk_0C][0]);
XYTransformContext_InitParabolic(&v1->unk_30[1].unk_04[0], &v1->unk_30[1].unk_04[1], v13, v11, v14, v12, 10, v1->unk_2C * v15[v1->unk_0C][1]);
}
v1->unk_0C++;
v1->unk_00++;
break;
case 7: {
u8 v16 = 0;
if (ov12_02225D2C(&v1->unk_30[0].unk_04[0], &v1->unk_30[0].unk_04[1], v1->unk_30[0].unk_00) == 0) {
v16++;
}
if (ov12_02225D2C(&v1->unk_30[1].unk_04[0], &v1->unk_30[1].unk_04[1], v1->unk_30[1].unk_00) == 0) {
v16++;
}
if (v16 == 2) {
if (v1->unk_0C == 5) {
v1->unk_00++;
} else {
v1->unk_00--;
}
}
} break;
case 8: {
int v17 = 0;
if (ov12_022267A8(&v1->unk_04, 0, -2) == 1) {
v17++;
}
if (ov12_022267A8(&v1->unk_08, 16, +2) == 1) {
v17++;
}
G2_ChangeBlendAlpha(v1->unk_04, v1->unk_08);
if (v17 == 2) {
v1->unk_00++;
}
} break;
default:
for (v0 = 0; v0 < BattleAnimSystem_GetScriptVar(v1->unk_10, 0); v0++) {
Sprite_DeleteAndFreeResources(v1->unk_30[v0].unk_00);
}
BattleAnimSystem_EndAnimTask(v1->unk_10, param0);
Heap_Free(v1);
return;
}
{
s16 v18, v19;
for (v0 = 0; v0 < BattleAnimSystem_GetScriptVar(v1->unk_10, 0); v0++) {
ManagedSprite_GetPositionXY(v1->unk_30[v0].unk_00, &v18, &v19);
if (v19 < 80) {
ManagedSprite_SetExplicitPriority(v1->unk_30[v0].unk_00, BattleAnimSystem_GetPokemonSpritePriority(v1->unk_10));
} else {
if (v18 > 128) {
ManagedSprite_SetExplicitPriority(v1->unk_30[v0].unk_00, BattleAnimSystem_GetPokemonSpritePriority(v1->unk_10));
} else {
ManagedSprite_SetExplicitPriority(v1->unk_30[v0].unk_00, BattleAnimSystem_GetPokemonSpritePriority(v1->unk_10) + 1);
}
}
}
}
if (v1->unk_00 < 4) {
return;
}
for (v0 = 0; v0 < BattleAnimSystem_GetScriptVar(v1->unk_10, 0); v0++) {
ManagedSprite_TickFrame(v1->unk_30[v0].unk_00);
}
SpriteSystem_DrawSprites(v1->unk_18);
}
void ov12_0222D56C(BattleAnimSystem *param0, SpriteSystem *param1, SpriteManager *param2, ManagedSprite *param3)
{
int v0;
UnkStruct_ov12_0222D128 *v1;
SpriteTemplate v2;
v1 = BattleAnimUtil_Alloc(param0, sizeof(UnkStruct_ov12_0222D128));
v1->unk_00 = 0;
v1->unk_01 = 0;
v1->unk_10 = param0;
v1->unk_18 = param2;
v1->unk_14 = param1;
v1->unk_04 = 0;
v1->unk_08 = 16;
v1->unk_1C = BattleAnimSystem_GetBattlerSprite(v1->unk_10, BattleAnimSystem_GetAttacker(v1->unk_10));
v1->unk_20 = PokemonSprite_GetAttribute(v1->unk_1C, MON_SPRITE_Y_CENTER);
v1->unk_24 = BattleAnimSystem_GetBattlerSpriteOffset(v1->unk_10, BattleAnimSystem_GetAttacker(v1->unk_10));
BattleAnimUtil_SetSpriteBlending(v1->unk_10, (1 << BattleAnimSystem_GetBgID(param0, 2)) | (1 << BattleAnimSystem_GetBgID(param0, 1)) | GX_WND_PLANEMASK_BG0, 0xffffffff, 0xffffffff);
G2_ChangeBlendAlpha(v1->unk_04, v1->unk_08);
v2 = BattleAnimSystem_GetLastSpriteTemplate(param0);
v1->unk_30[0].unk_00 = param3;
{
for (v0 = 1; v0 < BattleAnimSystem_GetScriptVar(v1->unk_10, 0); v0++) {
v1->unk_30[v0].unk_00 = SpriteSystem_NewSprite(v1->unk_14, v1->unk_18, &v2);
}
}
for (v0 = 0; v0 < BattleAnimSystem_GetScriptVar(v1->unk_10, 0); v0++) {
ManagedSprite_SetExplicitOamMode(v1->unk_30[v0].unk_00, GX_OAM_MODE_XLU);
ManagedSprite_SetExplicitPriority(v1->unk_30[v0].unk_00, BattleAnimSystem_GetPokemonSpritePriority(v1->unk_10) + 1);
}
if (BattleAnimSystem_IsContest(param0) == 1) {
ManagedSprite_SetPositionXY(v1->unk_30[0].unk_00, 180 - 20, 40 - 16 + 20 + 10);
ManagedSprite_SetPositionXY(v1->unk_30[1].unk_00, 100 - 20, 25 - 16 + 20 + 10);
} else {
ManagedSprite_SetPositionXY(v1->unk_30[0].unk_00, 100, 40 - 16 + 20 + 10);
ManagedSprite_SetPositionXY(v1->unk_30[1].unk_00, 180, 25 - 16 + 20 + 10);
}
BattleAnimSystem_StartAnimTask(v1->unk_10, ov12_0222D128, v1);
}