summaryrefslogtreecommitdiff
path: root/src/battle_transition.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/battle_transition.c')
-rw-r--r--src/battle_transition.c3728
1 files changed, 3728 insertions, 0 deletions
diff --git a/src/battle_transition.c b/src/battle_transition.c
new file mode 100644
index 000000000..0fd92d631
--- /dev/null
+++ b/src/battle_transition.c
@@ -0,0 +1,3728 @@
+#include "global.h"
+#include "sprite.h"
+#include "task.h"
+#include "overworld.h"
+#include "malloc.h"
+#include "palette.h"
+#include "trig.h"
+#include "random.h"
+#include "sound.h"
+#include "decompress.h"
+#include "gpu_regs.h"
+#include "battle_transition.h"
+#include "field_effect.h"
+#include "field_weather.h"
+#include "field_camera.h"
+#include "trainer_pokemon_sprites.h"
+#include "scanline_effect.h"
+#include "constants/songs.h"
+
+typedef bool8 (*TransitionStateFunc)(struct Task *task);
+typedef bool8 (*TransitionSpriteCallback)(struct Sprite *sprite);
+
+struct TransitionData
+{
+ vu8 vblankDma;
+ u16 winIn;
+ u16 winOut;
+ u16 win0H;
+ u16 win0V;
+ u16 unused_A;
+ u16 win1V;
+ u16 bldCnt;
+ u16 bldAlpha;
+ u16 bldY;
+ s16 bg123HOfs;
+ s16 bg123VOfs;
+ s16 bg0HOfsOpponent;
+ s16 bg0HOfsPlayer;
+ s16 bg0VOfs;
+ s16 unused_1E;
+ s16 counter;
+ s16 unused_22;
+ s16 data[11]; // for multiple purposes
+};
+
+static EWRAM_DATA struct TransitionData *sTransitionStructPtr = NULL;
+
+// TODO: Move this declaration to include/event_object_movement.h
+extern const struct OamData gEventObjectBaseOam_32x32;
+
+static bool8 BT_Phase1_FadeOut(struct Task *task);
+static bool8 BT_Phase1_FadeIn(struct Task *task);
+static bool8 BT_Phase2BlackDoodles_Init(struct Task *task);
+static bool8 BT_Phase2BlackDoodles_InitSingleBrush(struct Task *task);
+static bool8 BT_Phase2BlackDoodles_DrawSingleBrush(struct Task *task);
+static bool8 BT_Phase2BlackDoodles_IsDone(struct Task *task);
+static bool8 BT_Phase2BlackDoodles_NextBrush(struct Task *task);
+static bool8 BT_Phase2GridSquares_LoadGfx(struct Task *task);
+static bool8 BT_Phase2GridSquares_UpdateTileset(struct Task *task);
+static bool8 BT_Phase2GridSquares_IsDone(struct Task *task);
+static bool8 BT_Phase2WhiteFadeInStripes_Init(struct Task *task);
+static bool8 BT_Phase2WhiteFadeInStripes_SetupSprites(struct Task *task);
+static bool8 BT_Phase2WhiteFadeInStripes_IsWhiteFadeDone(struct Task *task);
+static bool8 BT_Phase2WhiteFadeInStripes_Stop(struct Task *task);
+static bool8 BT_Phase2WhiteFadeInStripes_IsDone(struct Task *task);
+static bool8 BT_Phase2SlicedScreen_Init(struct Task *task);
+static bool8 BT_Phase2SlicedScreen_UpdateOffsets(struct Task *task);
+static bool8 BT_Phase2SlicedScreen_End(struct Task *task);
+static bool8 BT_Phase2Mugshot_Init(struct Task *task);
+static bool8 BT_Phase2Mugshot_LoadGfx(struct Task *task);
+static bool8 BT_Phase2Mugshot_VsBarsSlideIn(struct Task *task);
+static bool8 BT_Phase2Mugshot_StartSpriteSlide(struct Task *task);
+static bool8 BT_Phase2Mugshot_WaitForOpponentInPlace(struct Task *task);
+static bool8 BT_Phase2Mugshot_WaitForPlayerInPlace(struct Task *task);
+static bool8 BT_Phase2Mugshot_ExpandWhiteBand(struct Task *task);
+static bool8 BT_Phase2Mugshot_StartBlackFade(struct Task *task);
+static bool8 BT_Phase2Mugshot_WaitForBlackFade(struct Task *task);
+static bool8 BT_Phase2Mugshot_End(struct Task *task);
+static bool8 BT_Phase2AntiClockwiseSpiral_Init(struct Task *task);
+static bool8 BT_Phase2AntiClockwiseSpiral_Update(struct Task *task);
+static bool8 BT_Phase2BlackWaveToRight_Init(struct Task *task);
+static bool8 BT_Phase2BlackWaveToRight_UpdateWave(struct Task *task);
+static bool8 BT_Phase2BlackWaveToRight_End(struct Task *task);
+static bool8 BT_Phase2FullScreenWave_Init(struct Task *task);
+static bool8 BT_Phase2FullScreenWave_UpdateWave(struct Task *task);
+static bool8 BT_Phase2ClockwiseBlackFade_Init(struct Task *task);
+static bool8 BT_Phase2ClockwiseBlackFade_Step1(struct Task *task);
+static bool8 BT_Phase2ClockwiseBlackFade_Step2(struct Task *task);
+static bool8 BT_Phase2ClockwiseBlackFade_Step3(struct Task *task);
+static bool8 BT_Phase2ClockwiseBlackFade_Step4(struct Task *task);
+static bool8 BT_Phase2ClockwiseBlackFade_Step5(struct Task *task);
+static bool8 BT_Phase2ClockwiseBlackFade_End(struct Task *task);
+static bool8 BT_Phase2SlidingPokeballs_LoadBgGfx(struct Task *task);
+static bool8 BT_Phase2SlidingPokeballs_SetupFldeffArgs(struct Task *task);
+static bool8 BT_Phase2SlidingPokeballs_IsDone(struct Task *task);
+static bool8 BT_Phase2BigPokeball_Init(struct Task *task);
+static bool8 BT_Phase2BigPokeball_LoadTilemapAndWave(struct Task *task);
+static bool8 BT_Phase2BigPokeball_UpdateWave1IncEva(struct Task *task);
+static bool8 BT_Phase2BigPokeball_UpdateWave2DecEvb(struct Task *task);
+static bool8 BT_Phase2BigPokeball_UpdateWave3(struct Task *task);
+static bool8 BT_Phase2BigPokeball_CircleEffect(struct Task *task);
+static bool8 BT_Phase2HorizontalCorrugate_Init(struct Task *task);
+static bool8 BT_Phase2HorizontalCorrugate_UpdateWave(struct Task *task);
+static bool8 BT_Phase2DistortedWave_InitWave(struct Task *task);
+static bool8 BT_Phase2DistortedWave_UpdateWave(struct Task *task);
+static bool8 BT_Phase2Blur_InitBgMosaic(struct Task *task);
+static bool8 BT_Phase2Blur_Anim(struct Task *task);
+static bool8 BT_Phase2Blur_IsDone(struct Task *task);
+static bool8 BT_Phase1Blink(struct Task *task);
+static bool8 BT_WaitForPhase1(struct Task *task);
+static bool8 BT_Phase2LaunchAnimTask(struct Task *task);
+static bool8 BT_WaitForPhase2(struct Task *task);
+
+static void BT_Phase2Blur(u8 taskId);
+static void BT_Phase2DistortedWave(u8 taskId);
+static void BT_Phase2HorizontalCorrugate(u8 taskId);
+static void BT_Phase2BigPokeball(u8 taskId);
+static void BT_Phase2SlidingPokeballs(u8 taskId);
+static void BT_Phase2ClockwiseBlackFade(u8 taskId);
+static void BT_Phase2FullScreenWave(u8 taskId);
+static void BT_Phase2BlackWaveToRight(u8 taskId);
+static void BT_Phase2SlicedScreen(u8 taskId);
+static void BT_Phase2WhiteFadeInStripes(u8 taskId);
+static void BT_Phase2GridSquares(u8 taskId);
+static void BT_Phase2BlackDoodles(u8 taskId);
+static void BT_Phase2StartLoreleiMugshot(u8 taskId);
+static void BT_Phase2StartBrunoMugshot(u8 taskId);
+static void BT_Phase2StartAgathaMugshot(u8 taskId);
+static void BT_Phase2StartLanceMugshot(u8 taskId);
+static void BT_Phase2StartBlueMugshot(u8 taskId);
+static void BT_Phase2AntiClockwiseSpiral(u8 taskId);
+static void BT_Phase1Task(u8 taskId);
+static void BT_Phase2Mugshot(u8 taskId);
+static void BT_Phase1SubTask(u8 taskId);
+
+static void SpriteCB_BT_Phase2Mugshots(struct Sprite *sprite);
+static void SpriteCB_BT_Phase2SlidingPokeballs(struct Sprite *sprite);
+static void SpriteCB_BT_Phase2WhiteFadeInStripes(struct Sprite *sprite);
+
+static bool8 BT_Phase2MugshotsSpriteFuncs_Wait(struct Sprite *sprite);
+static bool8 BT_Phase2MugshotsSpriteFuncs_InitParams(struct Sprite *sprite);
+static bool8 BT_Phase2MugshotsSpriteFuncs_SlideSpriteIn(struct Sprite *sprite);
+static bool8 BT_Phase2MugshotsSpriteFuncs_DecelerateSprite(struct Sprite *sprite);
+static bool8 BT_Phase2MugshotsSpriteFuncs_DecelerateSprite2(struct Sprite *sprite);
+
+static void VBCB_BT_Phase2DistortedWave(void);
+static void HBCB_BT_Phase2DistortedWave(void);
+static void VBCB_BT_Phase2HorizontalCorrugate(void);
+static void HBCB_BT_Phase2HorizontalCorrugate(void);
+static void VBCB_BT_Phase2BigPokeball1(void);
+static void VBCB_BT_Phase2BigPokeball2(void);
+static void HBCB_BT_Phase2BigPokeball(void);
+static void VBCB_BT_Phase2ClockwiseBlackFade(void);
+static void VBCB_BT_Phase2FullScreenWave(void);
+static void HBCB_BT_Phase2FullScreenWave(void);
+static void VBCB_BT_Phase2BlackWaveToRight(void);
+static void VBCB_BT_Phase2AntiClockwiseBlackFade(void);
+static void VBCB_BT_Phase2Mugshot1_Slide(void);
+static void VBCB_BT_Phase2Mugshot2_WhiteFade(void);
+static void HBCB_BT_Phase2Mugshot(void);
+static void VBCB_BT_Phase2SlicedScreen(void);
+static void HBCB_BT_Phase2SlicedScreen(void);
+static void VBCB_BT_Phase2WhiteFadeInStripes1(void);
+static void VBCB_BT_Phase2WhiteFadeInStripes2(void);
+static void HBCB_BT_Phase2WhiteFadeInStripes(void);
+static void VBCB_BT_Phase2BlackDoodles(void);
+
+static void BT_LaunchTask(u8 transitionId);
+static void BT_TaskMain(u8 taskId);
+static void BT_InitCtrlBlk(void);
+static void BT_CreatePhase1SubTask(s16 fadeOutDelay, s16 fadeInDelay, s16 blinkTimes, s16 fadeOutSpeed, s16 fadeInSpeed);
+static bool8 BT_IsPhase1Done(void);
+static void BT_VBSyncOamAndPltt(void);
+static void BT_GetBg0TilesetBase(u16 **tilesetPtr);
+static void BT_GetBg0TilemapAndTilesetBase(u16 **tilemapPtr, u16 **tilesetPtr);
+static void BT_LoadWaveIntoBuffer(s16 *buffer, s16 offset, s16 theta, s16 frequency, s16 amplitude, s16 bufSize);
+static void BT_GenerateCircle(s16 *buffer, s16 x, s16 y, s16 radius);
+static void BT_BlendPalettesToBlack(void);
+static void BT_DiagonalSegment_InitParams(s16 *data, s16 startPtX, s16 startPtY, s16 endPtX, s16 endPtY, s16 stepX, s16 stepY);
+static bool8 BT_DiagonalSegment_ComputePointOnSegment(s16 *data, bool8 checkBoundary1, bool8 checkBoundary2);
+static void BT_SetSpriteAsOpponentOrPlayer(s16 spriteId, bool16 value);
+static void BT_StartSpriteSlide(s16 spriteId);
+static s16 BT_IsSpriteSlideFinished(s16 spriteId);
+static void BT_Phase2Mugshots_CreateSprites(struct Task *task);
+
+static const u32 sBigPokeballTileset[] = INCBIN_U32("graphics/battle_transitions/big_pokeball_tileset.4bpp");
+static const u32 sSlidingPokeballTilemap[] = INCBIN_U32("graphics/battle_transitions/sliding_pokeball_tilemap.bin");
+static const u8 sSpriteImage_SlidingPokeball[] = INCBIN_U8("graphics/battle_transitions/sliding_pokeball.4bpp");
+static const u32 sVsBarTileset[] = INCBIN_U32("graphics/battle_transitions/vsbar_tileset.4bpp");
+static const u8 sSpriteImage_UnusedBrendan[] = INCBIN_U8("graphics/battle_transitions/unused_brendan.4bpp");
+static const u8 sSpriteImage_UnusedLass[] = INCBIN_U8("graphics/battle_transitions/unused_lass.4bpp");
+static const u32 sGridSquareTileset[] = INCBIN_U32("graphics/battle_transitions/grid_square_tileset.4bpp");
+
+static const TaskFunc sBT_Phase1Tasks[] =
+{
+ BT_Phase1Task,
+ BT_Phase1Task,
+ BT_Phase1Task,
+ BT_Phase1Task,
+ BT_Phase1Task,
+ BT_Phase1Task,
+ BT_Phase1Task,
+ BT_Phase1Task,
+ BT_Phase1Task,
+ BT_Phase1Task,
+ BT_Phase1Task,
+ BT_Phase1Task,
+ BT_Phase1Task,
+ BT_Phase1Task,
+ BT_Phase1Task,
+ BT_Phase1Task,
+ BT_Phase1Task,
+ BT_Phase1Task,
+};
+
+static const TaskFunc sBT_Phase2Tasks[] =
+{
+ BT_Phase2Blur,
+ BT_Phase2DistortedWave,
+ BT_Phase2HorizontalCorrugate,
+ BT_Phase2BigPokeball,
+ BT_Phase2SlidingPokeballs,
+ BT_Phase2ClockwiseBlackFade,
+ BT_Phase2FullScreenWave,
+ BT_Phase2BlackWaveToRight,
+ BT_Phase2SlicedScreen,
+ BT_Phase2WhiteFadeInStripes,
+ BT_Phase2GridSquares,
+ BT_Phase2BlackDoodles,
+ BT_Phase2StartLoreleiMugshot,
+ BT_Phase2StartBrunoMugshot,
+ BT_Phase2StartAgathaMugshot,
+ BT_Phase2StartLanceMugshot,
+ BT_Phase2StartBlueMugshot,
+ BT_Phase2AntiClockwiseSpiral,
+};
+
+static const TransitionStateFunc sBT_MainPhases[] =
+{
+ BT_Phase1Blink,
+ BT_WaitForPhase1,
+ BT_Phase2LaunchAnimTask,
+ BT_WaitForPhase2,
+};
+
+static const TransitionStateFunc sBT_Phase2BlurFuncs[] =
+{
+ BT_Phase2Blur_InitBgMosaic,
+ BT_Phase2Blur_Anim,
+ BT_Phase2Blur_IsDone,
+};
+
+static const TransitionStateFunc sBT_Phase2DistortedWaveFuncs[] =
+{
+ BT_Phase2DistortedWave_InitWave,
+ BT_Phase2DistortedWave_UpdateWave,
+};
+
+static const TransitionStateFunc sBT_Phase2HorizontalCorrugateFuncs[] =
+{
+ BT_Phase2HorizontalCorrugate_Init,
+ BT_Phase2HorizontalCorrugate_UpdateWave,
+};
+
+static const TransitionStateFunc sBT_Phase2BigPokeballFuncs[] =
+{
+ BT_Phase2BigPokeball_Init,
+ BT_Phase2BigPokeball_LoadTilemapAndWave,
+ BT_Phase2BigPokeball_UpdateWave1IncEva,
+ BT_Phase2BigPokeball_UpdateWave2DecEvb,
+ BT_Phase2BigPokeball_UpdateWave3,
+ BT_Phase2BigPokeball_CircleEffect,
+};
+
+static const TransitionStateFunc sBT_Phase2SlidingPokeballsFuncs[] =
+{
+ BT_Phase2SlidingPokeballs_LoadBgGfx,
+ BT_Phase2SlidingPokeballs_SetupFldeffArgs,
+ BT_Phase2SlidingPokeballs_IsDone,
+};
+
+static const s16 gUnknown_83FA400[] = { -16, 256 };
+
+static const s16 gUnknown_83FA404[] = { 0, 16, 32, 8, 24 };
+
+static const s16 gUnknown_83FA40E[] = { 8, -8 };
+
+static const TransitionStateFunc sBT_Phase2ClockwiseBlackFadeFuncs[] =
+{
+ BT_Phase2ClockwiseBlackFade_Init,
+ BT_Phase2ClockwiseBlackFade_Step1,
+ BT_Phase2ClockwiseBlackFade_Step2,
+ BT_Phase2ClockwiseBlackFade_Step3,
+ BT_Phase2ClockwiseBlackFade_Step4,
+ BT_Phase2ClockwiseBlackFade_Step5,
+ BT_Phase2ClockwiseBlackFade_End,
+};
+
+static const TransitionStateFunc sBT_Phase2FullScreenWaveFuncs[] =
+{
+ BT_Phase2FullScreenWave_Init,
+ BT_Phase2FullScreenWave_UpdateWave,
+};
+
+static const TransitionStateFunc sBT_Phase2BlackWaveToRightFuncs[] =
+{
+ BT_Phase2BlackWaveToRight_Init,
+ BT_Phase2BlackWaveToRight_UpdateWave,
+ BT_Phase2BlackWaveToRight_End,
+};
+static const s16 gUnknown_83FA444[] =
+{
+ 0x0, 0x26E,
+ 0x100, 0x69,
+ 0x0, -0x69,
+ -0x100, -0x266E,
+ 0x0, 0x26E,
+ 0x100, 0x69,
+ 0x0, -0x69,
+ -0x100, -0x266E,
+};
+
+static const TransitionStateFunc sBT_Phase2AntiClockwiseSpiralFuncs[] =
+{
+ BT_Phase2AntiClockwiseSpiral_Init,
+ BT_Phase2AntiClockwiseSpiral_Update,
+};
+
+static const TransitionStateFunc sBT_Phase2MugshotFuncs[] =
+{
+ BT_Phase2Mugshot_Init,
+ BT_Phase2Mugshot_LoadGfx,
+ BT_Phase2Mugshot_VsBarsSlideIn,
+ BT_Phase2Mugshot_StartSpriteSlide,
+ BT_Phase2Mugshot_WaitForOpponentInPlace,
+ BT_Phase2Mugshot_WaitForPlayerInPlace,
+ BT_Phase2Mugshot_ExpandWhiteBand,
+ BT_Phase2Mugshot_StartBlackFade,
+ BT_Phase2Mugshot_WaitForBlackFade,
+ BT_Phase2Mugshot_End,
+};
+
+static const u8 sMugshotsTrainerPicIDsTable[MUGSHOTS_COUNT] =
+{
+ // TODO: document these with macro
+ 0x70, 0x71, 0x72, 0x73, 0x7D
+};
+
+static const s16 sMugshotsOpponentRotationScales[MUGSHOTS_COUNT][2] =
+{
+ {0x200, 0x200},
+ {0x200, 0x200},
+ {0x200, 0x200},
+ {0x200, 0x200},
+ {0x200, 0x200},
+};
+
+static const s16 sMugshotsOpponentCoords[MUGSHOTS_COUNT][2] =
+{
+ { -8, 0 },
+ { -10, 0 },
+ { 0, 0 },
+ { -32, 0 },
+ { 0, 0 },
+};
+
+static const TransitionSpriteCallback sBT_Phase2MugshotSpriteFuncs[] =
+{
+ BT_Phase2MugshotsSpriteFuncs_Wait,
+ BT_Phase2MugshotsSpriteFuncs_InitParams,
+ BT_Phase2MugshotsSpriteFuncs_SlideSpriteIn,
+ BT_Phase2MugshotsSpriteFuncs_DecelerateSprite,
+ BT_Phase2MugshotsSpriteFuncs_Wait,
+ BT_Phase2MugshotsSpriteFuncs_DecelerateSprite2, // not used
+ BT_Phase2MugshotsSpriteFuncs_Wait,
+};
+
+static const s16 sMugShotSlideVelocity[] = { 12, -12 };
+
+static const s16 sMugShotSlideDeceleration[] = { -1, 1 };
+
+static const TransitionStateFunc sBT_Phase2SlicedScreenFuncs[] =
+{
+ BT_Phase2SlicedScreen_Init,
+ BT_Phase2SlicedScreen_UpdateOffsets,
+ BT_Phase2SlicedScreen_End,
+};
+
+static const TransitionStateFunc sBT_Phase2WhiteFadeInStripesFuncs[] =
+{
+ BT_Phase2WhiteFadeInStripes_Init,
+ BT_Phase2WhiteFadeInStripes_SetupSprites,
+ BT_Phase2WhiteFadeInStripes_IsWhiteFadeDone,
+ BT_Phase2WhiteFadeInStripes_Stop,
+ BT_Phase2WhiteFadeInStripes_IsDone,
+};
+
+static const u16 sWhiteStripeDelay[] = { 0, 9, 15, 6, 12, 3 };
+
+static const TransitionStateFunc sBT_Phase2GridSquaresFuncs[] =
+{
+ BT_Phase2GridSquares_LoadGfx,
+ BT_Phase2GridSquares_UpdateTileset,
+ BT_Phase2GridSquares_IsDone,
+};
+
+static const TransitionStateFunc sBT_Phase2BlackDoodlesFuncs[] =
+{
+ BT_Phase2BlackDoodles_Init,
+ BT_Phase2BlackDoodles_InitSingleBrush,
+ BT_Phase2BlackDoodles_DrawSingleBrush,
+ BT_Phase2BlackDoodles_IsDone,
+ BT_Phase2BlackDoodles_NextBrush,
+};
+
+static const s16 sBlackDoodlesSegments[][5] =
+{
+ { 0x38, 0x00, 0x00, 0xA0, 0 },
+ { 0x68, 0xA0, 0xF0, 0x58, 1 },
+ { 0xF0, 0x48, 0x38, 0x00, 1 },
+ { 0x00, 0x20, 0x90, 0xA0, 0 },
+ { 0x90, 0xA0, 0xB8, 0x00, 1 },
+ { 0x38, 0x00, 0xA8, 0xA0, 0 },
+ { 0xA8, 0xA0, 0x30, 0x00, 1 },
+};
+
+static const s16 sBlackDoodlesDelay[] = { 1, 1, 1, 1, 1, 1, 0 };
+
+static const TransitionStateFunc sBT_Phase1FadeFuncs[] =
+{
+ BT_Phase1_FadeOut,
+ BT_Phase1_FadeIn,
+};
+
+static const struct SpriteFrameImage sSpriteImageTable_SlidingPokeball[] =
+{
+ {
+ .data = sSpriteImage_SlidingPokeball,
+ .size = 0x200,
+ },
+};
+
+static const union AnimCmd sSpriteAnim_SlidingPokeball[] =
+{
+ ANIMCMD_FRAME(0, 1),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd *const sSpriteAnimTable_SlidingPokeball[] = { sSpriteAnim_SlidingPokeball };
+
+static const union AffineAnimCmd sSpriteAffineAnim_SlidingPokeball1[] =
+{
+ AFFINEANIMCMD_FRAME(0, 0, -4, 1),
+ AFFINEANIMCMD_JUMP(0),
+};
+
+static const union AffineAnimCmd sSpriteAffineAnim_SlidingPokeball2[] =
+{
+ AFFINEANIMCMD_FRAME(0, 0, 4, 1),
+ AFFINEANIMCMD_JUMP(0),
+};
+
+static const union AffineAnimCmd *const sSpriteAffineAnimTable_SlidingPokeball[] =
+{
+ sSpriteAffineAnim_SlidingPokeball1,
+ sSpriteAffineAnim_SlidingPokeball2,
+};
+
+static const struct SpriteTemplate sSpriteTemplate_SlidingPokeball =
+{
+ .tileTag = SPRITE_INVALID_TAG,
+ .paletteTag = 0x1009,
+ .oam = &gEventObjectBaseOam_32x32,
+ .anims = sSpriteAnimTable_SlidingPokeball,
+ .images = sSpriteImageTable_SlidingPokeball,
+ .affineAnims = sSpriteAffineAnimTable_SlidingPokeball,
+ .callback = SpriteCB_BT_Phase2SlidingPokeballs,
+};
+
+static const struct OamData sOamData_Unused =
+{
+ .y = 0,
+ .affineMode = 0,
+ .objMode = 0,
+ .mosaic = 0,
+ .bpp = 0,
+ .shape = SPRITE_SHAPE(64x64),
+ .x = 0,
+ .matrixNum = 0,
+ .size = SPRITE_SIZE(64x64),
+ .tileNum = 0,
+ .priority = 0,
+ .paletteNum = 0,
+ .affineParam = 0,
+};
+
+static const struct SpriteFrameImage sSpriteImageTable_UnusedBrendan[] =
+{
+ {
+ .data = sSpriteImage_UnusedBrendan,
+ .size = 0x800,
+ },
+};
+
+static const struct SpriteFrameImage sSpriteImageTable_UnusedLass[] =
+{
+ {
+ .data = sSpriteImage_UnusedLass,
+ .size = 0x800,
+ },
+};
+
+static const union AnimCmd sSpriteAnim_Unused[] =
+{
+ ANIMCMD_FRAME(0, 1),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd *const sSpriteAnimTable_Unused[] = { sSpriteAnim_Unused };
+
+static const struct SpriteTemplate sSpriteTemplateTable_Unused[] =
+{
+ {
+ .tileTag = SPRITE_INVALID_TAG,
+ .paletteTag = 0x100A,
+ .oam = &sOamData_Unused,
+ .anims = sSpriteAnimTable_Unused,
+ .images = sSpriteImageTable_UnusedBrendan,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCB_BT_Phase2Mugshots,
+ },
+ {
+ .tileTag = SPRITE_INVALID_TAG,
+ .paletteTag = 0x100A,
+ .oam = &sOamData_Unused,
+ .anims = sSpriteAnimTable_Unused,
+ .images = sSpriteImageTable_UnusedLass,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCB_BT_Phase2Mugshots,
+ },
+};
+
+// this palette is shared by big pokeball and sliding pokeball
+static const u16 sSlidingPokeballBigPokeballPalette[] = INCBIN_U16("graphics/battle_transitions/sliding_pokeball.gbapal");
+
+static const struct SpritePalette sSpritePalette_SlidingPokeball =
+{
+ .data = sSlidingPokeballBigPokeballPalette,
+ .tag = 0x1009,
+};
+
+static const u16 sVsBarLoreleiPalette[] = INCBIN_U16("graphics/battle_transitions/lorelei_bg.gbapal");
+static const u16 sVsBarBrunoPalette[] = INCBIN_U16("graphics/battle_transitions/bruno_bg.gbapal");
+static const u16 sVsBarAgathaPalette[] = INCBIN_U16("graphics/battle_transitions/agatha_bg.gbapal");
+static const u16 sVsBarLancePalette[] = INCBIN_U16("graphics/battle_transitions/lance_bg.gbapal");
+static const u16 sVsBarBluePalette[] = INCBIN_U16("graphics/battle_transitions/blue_bg.gbapal");
+static const u16 sVsBarMalePlayerPalette[] = INCBIN_U16("graphics/battle_transitions/red_bg.gbapal");
+static const u16 sVsBarFemalePlayerPalette[] = INCBIN_U16("graphics/battle_transitions/green_bg.gbapal");
+
+static const u16 *const sVsBarOpponentPalettes[MUGSHOTS_COUNT] =
+{
+ sVsBarLoreleiPalette,
+ sVsBarBrunoPalette,
+ sVsBarAgathaPalette,
+ sVsBarLancePalette,
+ sVsBarBluePalette,
+};
+
+static const u16 *const sVsBarPlayerPalettes[] =
+{
+ sVsBarMalePlayerPalette,
+ sVsBarFemalePlayerPalette,
+};
+
+static const u16 sUnusedTrainerPalette[] = INCBIN_U16("graphics/battle_transitions/unused_trainer.gbapal");
+
+static const struct SpritePalette sSpritePalette_UnusedTrainer =
+{
+ .data = sUnusedTrainerPalette,
+ .tag = 0x100A,
+};
+
+static const u16 sBigPokeballTilemap[] = INCBIN_U16("graphics/battle_transitions/big_pokeball_tilemap.bin");
+static const u16 sVsBarTilemap[] = INCBIN_U16("graphics/battle_transitions/vsbar_tilemap.bin");
+
+void BT_StartOnField(u8 transitionId)
+{
+ sTransitionStructPtr = AllocZeroed(sizeof(struct TransitionData));
+ gMain.callback2 = CB2_OverworldBasic;
+ BT_LaunchTask(transitionId);
+}
+
+// not used
+static void BT_StartWithoutAlloc(u8 transitionId)
+{
+ BT_LaunchTask(transitionId);
+}
+
+#define tState data[0]
+#define tTransitionId data[1]
+#define tTransitionDone data[15]
+
+bool8 BT_IsDone(void)
+{
+ u8 taskId = FindTaskIdByFunc(BT_TaskMain);
+ if (gTasks[taskId].tTransitionDone)
+ {
+ BT_InitCtrlBlk();
+ FREE_AND_SET_NULL(sTransitionStructPtr);
+ DestroyTask(taskId);
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+static void BT_LaunchTask(u8 transitionId)
+{
+ u8 taskId = CreateTask(BT_TaskMain, 2);
+ gTasks[taskId].tTransitionId = transitionId;
+}
+
+static void BT_TaskMain(u8 taskId)
+{
+ while (sBT_MainPhases[gTasks[taskId].tState](&gTasks[taskId]));
+}
+
+static bool8 BT_Phase1Blink(struct Task *task)
+{
+ SetWeatherScreenFadeOut();
+ CpuCopy32(gPlttBufferFaded, gPlttBufferUnfaded, 0x400);
+ if (sBT_Phase1Tasks[task->tTransitionId] != NULL)
+ {
+ CreateTask(sBT_Phase1Tasks[task->tTransitionId], 4);
+ ++task->tState;
+ return FALSE;
+ }
+ else
+ {
+ task->tState = 2;
+ return TRUE;
+ }
+}
+
+static bool8 BT_WaitForPhase1(struct Task *task)
+{
+ if (FindTaskIdByFunc(sBT_Phase1Tasks[task->tTransitionId]) == TASK_NONE)
+ {
+ ++task->tState;
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+static bool8 BT_Phase2LaunchAnimTask(struct Task *task)
+{
+ CreateTask(sBT_Phase2Tasks[task->tTransitionId], 0);
+ ++task->tState;
+ return FALSE;
+}
+
+static bool8 BT_WaitForPhase2(struct Task *task)
+{
+ task->tTransitionDone = FALSE;
+ if (FindTaskIdByFunc(sBT_Phase2Tasks[task->tTransitionId]) == TASK_NONE)
+ task->tTransitionDone = TRUE;
+ return FALSE;
+}
+
+static void BT_Phase1Task(u8 taskId)
+{
+ if (!gTasks[taskId].tState)
+ {
+ ++gTasks[taskId].tState;
+ BT_CreatePhase1SubTask(0, 0, 2, 2, 2);
+ }
+ else if (BT_IsPhase1Done())
+ {
+ DestroyTask(taskId);
+ }
+}
+
+#define tInterval data[1]
+#define tMosaicSize data[2]
+
+static void BT_Phase2Blur(u8 taskId)
+{
+ while (sBT_Phase2BlurFuncs[gTasks[taskId].tState](&gTasks[taskId]));
+}
+
+static bool8 BT_Phase2Blur_InitBgMosaic(struct Task *task)
+{
+ SetGpuReg(REG_OFFSET_MOSAIC, 0);
+ SetGpuRegBits(REG_OFFSET_BG1CNT, BGCNT_MOSAIC);
+ SetGpuRegBits(REG_OFFSET_BG2CNT, BGCNT_MOSAIC);
+ SetGpuRegBits(REG_OFFSET_BG3CNT, BGCNT_MOSAIC);
+ ++task->tState;
+ return TRUE;
+}
+
+static bool8 BT_Phase2Blur_Anim(struct Task *task)
+{
+ if (task->tInterval)
+ {
+ --task->tInterval;
+ }
+ else
+ {
+ task->tInterval = 2;
+ if (++task->tMosaicSize == 10)
+ BeginNormalPaletteFade(0xFFFFFFFF, -1, 0, 0x10, RGB_BLACK);
+ // The mosaic size argument is shared by HSIZE and VSIZE
+ SetGpuReg(REG_OFFSET_MOSAIC, (task->tMosaicSize & 0xF) + ((task->tMosaicSize & 0xF) << 4));
+ if (task->tMosaicSize > 14)
+ ++task->tState;
+ }
+ return FALSE;
+}
+
+static bool8 BT_Phase2Blur_IsDone(struct Task *task)
+{
+ if (!gPaletteFade.active)
+ DestroyTask(FindTaskIdByFunc(BT_Phase2Blur));
+ return FALSE;
+}
+
+#undef tInterval
+#undef tMosaicSize
+
+#define tTheta data[1]
+#define tAmplitude data[2]
+
+static void BT_Phase2DistortedWave(u8 taskId)
+{
+ while (sBT_Phase2DistortedWaveFuncs[gTasks[taskId].tState](&gTasks[taskId]));
+}
+
+static bool8 BT_Phase2DistortedWave_InitWave(struct Task *task)
+{
+ BT_InitCtrlBlk();
+ ScanlineEffect_Clear();
+ BeginNormalPaletteFade(0xFFFFFFFF, 4, 0, 0x10, RGB_BLACK);
+ BT_LoadWaveIntoBuffer(gScanlineEffectRegBuffers[1], sTransitionStructPtr->bg123HOfs, 0, 2, 0, 160);
+ SetVBlankCallback(VBCB_BT_Phase2DistortedWave);
+ SetHBlankCallback(HBCB_BT_Phase2DistortedWave);
+ EnableInterrupts(INTR_FLAG_VBLANK | INTR_FLAG_HBLANK);
+ ++task->tState;
+ return FALSE;
+}
+
+static bool8 BT_Phase2DistortedWave_UpdateWave(struct Task *task)
+{
+ sTransitionStructPtr->vblankDma = FALSE;
+ task->tTheta += 4;
+ task->tAmplitude += 8;
+ BT_LoadWaveIntoBuffer(gScanlineEffectRegBuffers[0], sTransitionStructPtr->bg123HOfs, task->tTheta, 2, task->tAmplitude, 160);
+ if (!gPaletteFade.active)
+ DestroyTask(FindTaskIdByFunc(BT_Phase2DistortedWave));
+ ++sTransitionStructPtr->vblankDma;
+ return FALSE;
+}
+
+static void VBCB_BT_Phase2DistortedWave(void)
+{
+ BT_VBSyncOamAndPltt();
+ if (sTransitionStructPtr->vblankDma)
+ DmaCopy16(3, gScanlineEffectRegBuffers[0], gScanlineEffectRegBuffers[1], 320);
+}
+
+static void HBCB_BT_Phase2DistortedWave(void)
+{
+ s16 offset = gScanlineEffectRegBuffers[1][REG_VCOUNT];
+
+ REG_BG1HOFS = offset;
+ REG_BG2HOFS = offset;
+ REG_BG3HOFS = offset;
+}
+
+static void BT_Phase2HorizontalCorrugate(u8 taskId)
+{
+ while (sBT_Phase2HorizontalCorrugateFuncs[gTasks[taskId].tState](&gTasks[taskId]));
+}
+
+static bool8 BT_Phase2HorizontalCorrugate_Init(struct Task *task)
+{
+ BT_InitCtrlBlk();
+ ScanlineEffect_Clear();
+ BeginNormalPaletteFade(0xFFFFFFFF, 4, 0, 0x10, RGB_BLACK);
+ memset(gScanlineEffectRegBuffers[1], sTransitionStructPtr->bg123VOfs, 320);
+ SetVBlankCallback(VBCB_BT_Phase2HorizontalCorrugate);
+ SetHBlankCallback(HBCB_BT_Phase2HorizontalCorrugate);
+ EnableInterrupts(INTR_FLAG_VBLANK | INTR_FLAG_HBLANK);
+ ++task->tState;
+ return FALSE;
+}
+
+static bool8 BT_Phase2HorizontalCorrugate_UpdateWave(struct Task *task)
+{
+ u8 i;
+ u16 theta, amplitude;
+
+ sTransitionStructPtr->vblankDma = FALSE;
+ theta = task->tTheta;
+ amplitude = task->tAmplitude >> 8;
+ task->tTheta += 4224;
+ task->tAmplitude += 384;
+ for (i = 0; i < 160; ++i, theta += 4224)
+ gScanlineEffectRegBuffers[0][i] = sTransitionStructPtr->bg123VOfs + Sin(theta / 256, amplitude);
+ if (!gPaletteFade.active)
+ DestroyTask(FindTaskIdByFunc(BT_Phase2HorizontalCorrugate));
+ ++sTransitionStructPtr->vblankDma;
+ return FALSE;
+}
+
+static void VBCB_BT_Phase2HorizontalCorrugate(void)
+{
+ BT_VBSyncOamAndPltt();
+ if (sTransitionStructPtr->vblankDma)
+ DmaCopy16(3, gScanlineEffectRegBuffers[0], gScanlineEffectRegBuffers[1], 320);
+}
+
+static void HBCB_BT_Phase2HorizontalCorrugate(void)
+{
+ s16 offset = gScanlineEffectRegBuffers[1][REG_VCOUNT];
+
+ REG_BG1VOFS = offset;
+ REG_BG2VOFS = offset;
+ REG_BG3VOFS = offset;
+}
+
+#undef tTheta
+#undef tAmplitude
+
+#define tEvb data[1]
+#define tEva data[2]
+#define tInterval data[3]
+#define tTheta data[4]
+#define tAmplitude data[5]
+
+static void BT_Phase2BigPokeball(u8 taskId)
+{
+ while (sBT_Phase2BigPokeballFuncs[gTasks[taskId].tState](&gTasks[taskId]));
+}
+
+static bool8 BT_Phase2BigPokeball_Init(struct Task *task)
+{
+ u16 i, *tilemapAddr, *tilesetAddr;
+
+ BT_InitCtrlBlk();
+ ScanlineEffect_Clear();
+ task->tEvb = 16;
+ task->tEva = 0;
+ task-> tTheta = 0;
+ task-> tAmplitude = 0x4000;
+ sTransitionStructPtr->winIn = 0x3F;
+ sTransitionStructPtr->winOut = 0;
+ sTransitionStructPtr->win0H = 240;
+ sTransitionStructPtr->win0V = 160;
+ sTransitionStructPtr->bldCnt = BLDCNT_TGT1_BG0 | BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_BG0 | BLDCNT_TGT2_BG1 | BLDCNT_TGT2_BG2 | BLDCNT_TGT2_BG3 | BLDCNT_TGT2_OBJ | BLDCNT_TGT2_BD;
+ sTransitionStructPtr->bldAlpha = (task->tEvb << 8) | task->tEva;
+ for (i = 0; i < 160; ++i)
+ gScanlineEffectRegBuffers[1][i] = 240;
+ SetVBlankCallback(VBCB_BT_Phase2BigPokeball1);
+ BT_GetBg0TilemapAndTilesetBase(&tilemapAddr, &tilesetAddr);
+ CpuFill16(0, tilemapAddr, 0x800);
+ CpuCopy16(sBigPokeballTileset, tilesetAddr, 0x580);
+ LoadPalette(sSlidingPokeballBigPokeballPalette, 0xF0, 0x20);
+ ++task->tState;
+ return FALSE;
+}
+
+static bool8 BT_Phase2BigPokeball_LoadTilemapAndWave(struct Task *task)
+{
+ s16 i, j;
+ u16 *tilemapAddr, *tilesetAddr;
+ const u16 *BigPokeballMap = sBigPokeballTilemap;
+
+ BT_GetBg0TilemapAndTilesetBase(&tilemapAddr, &tilesetAddr);
+ for (i = 0; i < 20; ++i)
+ for (j = 0; j < 30; ++j, ++BigPokeballMap)
+ tilemapAddr[i * 32 + j] = *BigPokeballMap | 0xF000; // use palette #15
+ BT_LoadWaveIntoBuffer(gScanlineEffectRegBuffers[0], 0, task->tTheta, 132, task->tAmplitude, 160);
+ ++task->tState;
+ return TRUE;
+}
+
+static bool8 BT_Phase2BigPokeball_UpdateWave1IncEva(struct Task *task)
+{
+ sTransitionStructPtr->vblankDma = FALSE;
+ if (task->tInterval == 0 || --task->tInterval == 0)
+ {
+ ++task->tEva;
+ task->tInterval = 1; // Broken logic. This makes the condition always TRUE.
+ }
+ sTransitionStructPtr->bldAlpha = (task->tEvb << 8) | task->tEva;
+ // Increment eva until it reaches 50% coeff
+ if (task->tEva > 15)
+ ++task->tState;
+ task->tTheta += 12;
+ task->tAmplitude -= 384;
+ // Assign a very high frequency value so that 2 adjacent values in gScanlineEffectRegBuffers[0] will have different sign.
+ BT_LoadWaveIntoBuffer(gScanlineEffectRegBuffers[0], 0, task->tTheta, 132, task->tAmplitude >> 8, 160);
+ ++sTransitionStructPtr->vblankDma;
+ return FALSE;
+}
+
+static bool8 BT_Phase2BigPokeball_UpdateWave2DecEvb(struct Task *task)
+{
+ sTransitionStructPtr->vblankDma = FALSE;
+ if (task->tInterval == 0 || --task->tInterval == 0)
+ {
+ --task->tEvb;
+ task->tInterval = 2;
+ }
+ sTransitionStructPtr->bldAlpha = (task->tEvb << 8) | task->tEva;
+ if (!task->tEvb)
+ ++task->tState;
+ if (task->tAmplitude > 0)
+ {
+ task->tTheta += 12;
+ task->tAmplitude -= 384;
+ }
+ else
+ {
+ task->tAmplitude = 0;
+ }
+ BT_LoadWaveIntoBuffer(gScanlineEffectRegBuffers[0], 0, task->tTheta, 132, task->tAmplitude >> 8, 160);
+ ++sTransitionStructPtr->vblankDma;
+ return FALSE;
+}
+
+#undef tEvb
+#undef tEva
+#undef tInterval
+
+#define tRadius data[1]
+#define tDeltaRadius data[2]
+#define tKeepVBCB data[3]
+
+static bool8 BT_Phase2BigPokeball_UpdateWave3(struct Task *task)
+{
+ sTransitionStructPtr->vblankDma = FALSE;
+ if (task->tAmplitude > 0)
+ {
+ task->tTheta += 12;
+ task->tAmplitude -= 384;
+ }
+ else
+ {
+ task->tAmplitude = 0;
+ }
+ BT_LoadWaveIntoBuffer(gScanlineEffectRegBuffers[0], 0, task->tTheta, 132, task->tAmplitude >> 8, 160);
+ if (task->tAmplitude <= 0)
+ {
+ ++task->tState;
+ task->tRadius = 160;
+ task->tDeltaRadius = 256;
+ task->tKeepVBCB = 0;
+ }
+ ++sTransitionStructPtr->vblankDma;
+ return FALSE;
+}
+
+static bool8 BT_Phase2BigPokeball_CircleEffect(struct Task *task)
+{
+ sTransitionStructPtr->vblankDma = FALSE;
+ if (task->tDeltaRadius < 2048)
+ task->tDeltaRadius += 256;
+ if (task->tRadius)
+ {
+ task->tRadius -= (task->tDeltaRadius >> 8);
+ if (task->tRadius < 0)
+ task->tRadius = 0;
+ }
+ BT_GenerateCircle(gScanlineEffectRegBuffers[0], 120, 80, task->tRadius);
+ if (task->tRadius == 0)
+ {
+ DmaStop(0);
+ BT_BlendPalettesToBlack();
+ DestroyTask(FindTaskIdByFunc(BT_Phase2BigPokeball));
+ }
+ if (task->tKeepVBCB == 0)
+ {
+ ++task->tKeepVBCB;
+ SetVBlankCallback(VBCB_BT_Phase2BigPokeball2);
+ }
+ ++sTransitionStructPtr->vblankDma;
+ return FALSE;
+}
+
+static void BT_VBStopDma0SyncSrcBufferSetLcdRegs(void)
+{
+ DmaStop(0);
+ BT_VBSyncOamAndPltt();
+ if (sTransitionStructPtr->vblankDma)
+ DmaCopy16(3, gScanlineEffectRegBuffers[0], gScanlineEffectRegBuffers[1], 320);
+ SetGpuReg(REG_OFFSET_WININ, sTransitionStructPtr->winIn);
+ SetGpuReg(REG_OFFSET_WINOUT, sTransitionStructPtr->winOut);
+ SetGpuReg(REG_OFFSET_WIN0V, sTransitionStructPtr->win0V);
+ SetGpuReg(REG_OFFSET_BLDCNT, sTransitionStructPtr->bldCnt);
+ SetGpuReg(REG_OFFSET_BLDALPHA, sTransitionStructPtr->bldAlpha);
+}
+
+static void VBCB_BT_Phase2BigPokeball1(void)
+{
+ BT_VBStopDma0SyncSrcBufferSetLcdRegs();
+ DmaSet(0, gScanlineEffectRegBuffers[1], &REG_BG0HOFS, ((DMA_ENABLE | DMA_START_HBLANK | DMA_REPEAT | DMA_16BIT | DMA_SRC_INC | DMA_DEST_FIXED) << 16) | 1);
+}
+
+static void VBCB_BT_Phase2BigPokeball2(void)
+{
+ BT_VBStopDma0SyncSrcBufferSetLcdRegs();
+ DmaSet(0, gScanlineEffectRegBuffers[1], &REG_WIN0H, ((DMA_ENABLE | DMA_START_HBLANK | DMA_REPEAT | DMA_16BIT | DMA_SRC_INC | DMA_DEST_FIXED) << 16) | 1);
+}
+
+#undef tRadius
+#undef tDeltaRadius
+#undef tKeepVBCB
+#undef tTheta
+#undef tAmplitude
+
+// TODO: Document this effect after knowing more about field effects.
+static void BT_Phase2SlidingPokeballs(u8 taskId)
+{
+ while (sBT_Phase2SlidingPokeballsFuncs[gTasks[taskId].tState](&gTasks[taskId]));
+}
+
+static bool8 BT_Phase2SlidingPokeballs_LoadBgGfx(struct Task *task)
+{
+ u16 *tilemapAddr, *tilesetAddr;
+
+ BT_GetBg0TilemapAndTilesetBase(&tilemapAddr, &tilesetAddr);
+ CpuSet(sSlidingPokeballTilemap, tilesetAddr, 0x20);
+ CpuFill32(0, tilemapAddr, 0x800);
+ LoadPalette(sSlidingPokeballBigPokeballPalette, 0xF0, 0x20);
+ ++task->tState;
+ return FALSE;
+}
+
+static bool8 BT_Phase2SlidingPokeballs_SetupFldeffArgs(struct Task *task)
+{
+ s16 i, rand;
+ s16 arr0[NELEMS(gUnknown_83FA400)];
+ s16 arr1[NELEMS(gUnknown_83FA404)];
+
+ memcpy(arr0, gUnknown_83FA400, sizeof(gUnknown_83FA400));
+ memcpy(arr1, gUnknown_83FA404, sizeof(gUnknown_83FA404));
+ rand = Random() & 1;
+ for (i = 0; i <= 4; ++i, rand ^= 1)
+ {
+ gFieldEffectArguments[0] = arr0[rand]; // x
+ gFieldEffectArguments[1] = (i * 32) + 16; // y
+ gFieldEffectArguments[2] = rand;
+ gFieldEffectArguments[3] = arr1[i];
+ FieldEffectStart(FLDEFF_POKEBALL);
+ }
+ ++task->tState;
+ return FALSE;
+}
+
+static bool8 BT_Phase2SlidingPokeballs_IsDone(struct Task *task)
+{
+ if (!FieldEffectActiveListContains(FLDEFF_POKEBALL))
+ {
+ BT_BlendPalettesToBlack();
+ DestroyTask(FindTaskIdByFunc(BT_Phase2SlidingPokeballs));
+ }
+ return FALSE;
+}
+
+bool8 FldEff_Pokeball(void)
+{
+ u8 spriteId = CreateSpriteAtEnd(&sSpriteTemplate_SlidingPokeball, gFieldEffectArguments[0], gFieldEffectArguments[1], 0);
+
+ gSprites[spriteId].oam.priority = 0;
+ gSprites[spriteId].oam.affineMode = 1;
+ gSprites[spriteId].data[0] = gFieldEffectArguments[2];
+ gSprites[spriteId].data[1] = gFieldEffectArguments[3];
+ gSprites[spriteId].data[2] = -1;
+ InitSpriteAffineAnim(&gSprites[spriteId]);
+ StartSpriteAffineAnim(&gSprites[spriteId], gFieldEffectArguments[2]);
+ return FALSE;
+}
+
+#define SOME_VRAM_STORE(ptr, posY, posX, toStore) \
+{ \
+ u32 index = (posY) * 32 + posX; \
+ ptr[index] = toStore; \
+}
+
+static void SpriteCB_BT_Phase2SlidingPokeballs(struct Sprite *sprite)
+{
+ s16 arr0[NELEMS(gUnknown_83FA40E)];
+
+ memcpy(arr0, gUnknown_83FA40E, sizeof(gUnknown_83FA40E));
+ if (sprite->data[1])
+ {
+ --sprite->data[1];
+ }
+ else
+ {
+ if ((u16)sprite->pos1.x <= 240)
+ {
+ s16 posX = sprite->pos1.x >> 3;
+ s16 posY = sprite->pos1.y >> 3;
+
+ if (posX != sprite->data[2])
+ {
+ u32 var;
+ u16 *ptr;
+
+ sprite->data[2] = posX;
+ var = (((GetGpuReg(REG_OFFSET_BG0CNT) >> 8) & 0x1F) << 11);
+ ptr = (u16 *)(VRAM + var);
+ SOME_VRAM_STORE(ptr, posY - 2, posX, 0xF001);
+ SOME_VRAM_STORE(ptr, posY - 1, posX, 0xF001);
+ SOME_VRAM_STORE(ptr, posY - 0, posX, 0xF001);
+ SOME_VRAM_STORE(ptr, posY + 1, posX, 0xF001);
+ }
+ }
+ sprite->pos1.x += arr0[sprite->data[0]];
+ if (sprite->pos1.x < -15 || sprite->pos1.x > 255)
+ FieldEffectStop(sprite, FLDEFF_POKEBALL);
+ }
+}
+
+#define trStartPtX data[0]
+#define trStartPtY data[1]
+#define trCurrentPtX data[2]
+#define trCurrentPtY data[3]
+#define trEndPtX data[4]
+#define trEndPtY data[5]
+
+static void BT_Phase2ClockwiseBlackFade(u8 taskId)
+{
+ while (sBT_Phase2ClockwiseBlackFadeFuncs[gTasks[taskId].tState](&gTasks[taskId]));
+}
+
+static bool8 BT_Phase2ClockwiseBlackFade_Init(struct Task *task)
+{
+ u16 i;
+
+ BT_InitCtrlBlk();
+ ScanlineEffect_Clear();
+ sTransitionStructPtr->winIn = 0;
+ sTransitionStructPtr->winOut = 0x3F;
+ sTransitionStructPtr->win0H = 0xF0F1;
+ sTransitionStructPtr->win0V = 0x00A0;
+ for (i = 0; i < 160; ++i)
+ {
+ gScanlineEffectRegBuffers[1][i] = 0xF3F4;
+ }
+ SetVBlankCallback(VBCB_BT_Phase2ClockwiseBlackFade);
+ sTransitionStructPtr->trEndPtX = 120;
+ ++task->tState;
+ return TRUE;
+}
+
+static bool8 BT_Phase2ClockwiseBlackFade_Step1(struct Task *task)
+{
+ sTransitionStructPtr->vblankDma = FALSE;
+ BT_DiagonalSegment_InitParams(sTransitionStructPtr->data, 120, 80, sTransitionStructPtr->trEndPtX, -1, 1, 1);
+ do
+ {
+ gScanlineEffectRegBuffers[0][sTransitionStructPtr->trCurrentPtY] = (sTransitionStructPtr->trCurrentPtX + 1) | 0x7800;
+ }
+ while (!BT_DiagonalSegment_ComputePointOnSegment(sTransitionStructPtr->data, TRUE, TRUE));
+
+ sTransitionStructPtr->trEndPtX += 32;
+ if (sTransitionStructPtr->trEndPtX >= 240)
+ {
+ sTransitionStructPtr->trEndPtY = 0;
+ ++task->tState;
+ }
+ ++sTransitionStructPtr->vblankDma;
+ return FALSE;
+}
+
+static bool8 BT_Phase2ClockwiseBlackFade_Step2(struct Task *task)
+{
+ s16 left, right;
+ vu8 finished = FALSE;
+
+ sTransitionStructPtr->vblankDma = FALSE;
+ BT_DiagonalSegment_InitParams(sTransitionStructPtr->data, 120, 80, 240, sTransitionStructPtr->trEndPtY, 1, 1);
+ while (TRUE)
+ {
+ left = 120;
+ right = sTransitionStructPtr->trCurrentPtX + 1;
+ if (sTransitionStructPtr->trEndPtY >= 80)
+ {
+ left = sTransitionStructPtr->trCurrentPtX;
+ right = 240;
+ }
+ gScanlineEffectRegBuffers[0][sTransitionStructPtr->trCurrentPtY] = right | (left << 8);
+ if (finished)
+ break;
+ finished = BT_DiagonalSegment_ComputePointOnSegment(sTransitionStructPtr->data, TRUE, TRUE);
+ }
+ sTransitionStructPtr->trEndPtY += 16;
+ if (sTransitionStructPtr->trEndPtY >= 160)
+ {
+ sTransitionStructPtr->trEndPtX = 240;
+ ++task->tState;
+ }
+ else
+ {
+ while (sTransitionStructPtr->trCurrentPtY < sTransitionStructPtr->trEndPtY)
+ gScanlineEffectRegBuffers[0][++sTransitionStructPtr->trCurrentPtY] = right | (left << 8);
+ }
+ ++sTransitionStructPtr->vblankDma;
+ return FALSE;
+}
+
+static bool8 BT_Phase2ClockwiseBlackFade_Step3(struct Task *task)
+{
+ sTransitionStructPtr->vblankDma = FALSE;
+ BT_DiagonalSegment_InitParams(sTransitionStructPtr->data, 120, 80, sTransitionStructPtr->trEndPtX, 160, 1, 1);
+ do
+ {
+ gScanlineEffectRegBuffers[0][sTransitionStructPtr->trCurrentPtY] = (sTransitionStructPtr->trCurrentPtX << 8) | 0xF0;
+ }
+ while (!BT_DiagonalSegment_ComputePointOnSegment(sTransitionStructPtr->data, TRUE, TRUE));
+ sTransitionStructPtr->trEndPtX -= 32;
+ if (sTransitionStructPtr->trEndPtX <= 0)
+ {
+ sTransitionStructPtr->trEndPtY = 160;
+ ++task->tState;
+ }
+ ++sTransitionStructPtr->vblankDma;
+ return FALSE;
+}
+
+/*
+ * BUG: The following 2 functions are incorrect. The animation after
+ * the rotation angle reaches 1.5π will not be displayed.
+ *
+ * There're 2 problems which need to be solved in order to correct the logic.
+ * 1. With current setup, nothing is displayed inside WIN0 and everything
+ * is displayed outside WIN0. Thus, if the rotation angle is > 1.5π, it
+ * won't be able to handle the situation.
+ * 2. The programmer sometimes swapped the place of left and right boundary
+ * of WIN0 (see variables left and right), which will sometimes cause right
+ * to be smaller than left. In this way, garbage data will be written to WIN0H.
+ */
+static bool8 BT_Phase2ClockwiseBlackFade_Step4(struct Task *task)
+{
+ s16 right, left;
+ u16 win0H;
+ vu8 finished = FALSE;
+
+ sTransitionStructPtr->vblankDma = FALSE;
+ BT_DiagonalSegment_InitParams(sTransitionStructPtr->data, 120, 80, 0, sTransitionStructPtr->trEndPtY, 1, 1);
+ while (TRUE)
+ {
+ right = (gScanlineEffectRegBuffers[0][sTransitionStructPtr->trCurrentPtY]) & 0xFF;
+ left = sTransitionStructPtr->trCurrentPtX;
+ if (sTransitionStructPtr->trEndPtY <= 80)
+ {
+ left = 120;
+ right = sTransitionStructPtr->trCurrentPtX;
+ }
+ win0H = right | (left << 8);
+ gScanlineEffectRegBuffers[0][sTransitionStructPtr->trCurrentPtY] = win0H;
+ if (finished)
+ break;
+ finished = BT_DiagonalSegment_ComputePointOnSegment(sTransitionStructPtr->data, TRUE, TRUE);
+ }
+ sTransitionStructPtr->trEndPtY -= 16;
+ if (sTransitionStructPtr->trEndPtY <= 0)
+ {
+ sTransitionStructPtr->trEndPtX = 0;
+ ++task->tState;
+ }
+ else
+ {
+ while (sTransitionStructPtr->trCurrentPtY > sTransitionStructPtr->trEndPtY)
+ gScanlineEffectRegBuffers[0][--sTransitionStructPtr->trCurrentPtY] = right | (left << 8);
+ }
+ ++sTransitionStructPtr->vblankDma;
+ return FALSE;
+}
+
+static bool8 BT_Phase2ClockwiseBlackFade_Step5(struct Task *task)
+{
+ s16 left, right;
+
+ sTransitionStructPtr->vblankDma = FALSE;
+ BT_DiagonalSegment_InitParams(sTransitionStructPtr->data, 120, 80, sTransitionStructPtr->trEndPtX, 0, 1, 1);
+ do
+ {
+ left = 120;
+ right = sTransitionStructPtr->trCurrentPtX;
+ if (sTransitionStructPtr->trCurrentPtX >= 120)
+ {
+ left = 0;
+ right = 240;
+ }
+ gScanlineEffectRegBuffers[0][sTransitionStructPtr->trCurrentPtY] = right | (left << 8);
+ }
+ while (!BT_DiagonalSegment_ComputePointOnSegment(sTransitionStructPtr->data, TRUE, TRUE));
+ sTransitionStructPtr->trEndPtX += 32;
+ if (sTransitionStructPtr->trCurrentPtX > 120)
+ ++task->tState;
+ ++sTransitionStructPtr->vblankDma;
+ return FALSE;
+}
+
+static bool8 BT_Phase2ClockwiseBlackFade_End(struct Task *task)
+{
+ DmaStop(0);
+ BT_BlendPalettesToBlack();
+ DestroyTask(FindTaskIdByFunc(BT_Phase2ClockwiseBlackFade));
+ return FALSE;
+}
+
+static void VBCB_BT_Phase2ClockwiseBlackFade(void)
+{
+ DmaStop(0);
+ BT_VBSyncOamAndPltt();
+ if (sTransitionStructPtr->vblankDma)
+ DmaCopy16(3, gScanlineEffectRegBuffers[0], gScanlineEffectRegBuffers[1], 320);
+ SetGpuReg(REG_OFFSET_WININ, sTransitionStructPtr->winIn);
+ SetGpuReg(REG_OFFSET_WINOUT, sTransitionStructPtr->winOut);
+ SetGpuReg(REG_OFFSET_WIN0V, sTransitionStructPtr->win0V);
+ SetGpuReg(REG_OFFSET_WIN0H, gScanlineEffectRegBuffers[1][0]);
+ DmaSet(0, gScanlineEffectRegBuffers[1], &REG_WIN0H, ((DMA_ENABLE | DMA_START_HBLANK | DMA_REPEAT | DMA_16BIT | DMA_SRC_INC | DMA_DEST_FIXED) << 16) | 1);
+}
+
+#undef trStartPtX
+#undef trStartPtY
+#undef trCurrentPtX
+#undef trCurrentPtY
+#undef trEndPtX
+#undef trEndPtY
+
+#define tTheta data[1]
+#define tAmplitude data[2]
+#define tDelayForFade data[3]
+#define tStartFade data[4]
+
+static void BT_Phase2FullScreenWave(u8 taskId)
+{
+ while (sBT_Phase2FullScreenWaveFuncs[gTasks[taskId].tState](&gTasks[taskId]));
+}
+
+static bool8 BT_Phase2FullScreenWave_Init(struct Task *task)
+{
+ u8 i;
+
+ BT_InitCtrlBlk();
+ ScanlineEffect_Clear();
+ for (i = 0; i < 160; ++i)
+ gScanlineEffectRegBuffers[1][i] = sTransitionStructPtr->bg123VOfs;
+ SetVBlankCallback(VBCB_BT_Phase2FullScreenWave);
+ SetHBlankCallback(HBCB_BT_Phase2FullScreenWave);
+ EnableInterrupts(INTR_FLAG_HBLANK);
+ ++task->tState;
+ return TRUE;
+}
+
+static bool8 BT_Phase2FullScreenWave_UpdateWave(struct Task *task)
+{
+ u8 i;
+ s16 amplitude;
+ u16 theta, frequency;
+
+ sTransitionStructPtr->vblankDma = FALSE;
+ amplitude = task->tAmplitude >> 8;
+ theta = task->tTheta;
+ frequency = 384;
+ task->tTheta += 0x400;
+ if (task->tAmplitude <= 0x1FFF)
+ task->tAmplitude += 384;
+ for (i = 0; i < 160; ++i, theta += frequency)
+ {
+ s16 var = theta >> 8;
+
+ #ifndef NONMATCHING
+ asm("");
+ #endif
+ gScanlineEffectRegBuffers[0][i] = sTransitionStructPtr->bg123VOfs + Sin(var, amplitude);
+ }
+ if (++task->tDelayForFade == 41)
+ {
+ ++task->tStartFade;
+ BeginNormalPaletteFade(0xFFFFFFFF, -8, 0, 0x10, RGB_BLACK);
+ }
+ if (task->tStartFade && !gPaletteFade.active)
+ DestroyTask(FindTaskIdByFunc(BT_Phase2FullScreenWave));
+ ++sTransitionStructPtr->vblankDma;
+ return FALSE;
+}
+
+static void VBCB_BT_Phase2FullScreenWave(void)
+{
+ BT_VBSyncOamAndPltt();
+ if (sTransitionStructPtr->vblankDma)
+ DmaCopy16(3, gScanlineEffectRegBuffers[0], gScanlineEffectRegBuffers[1], 320);
+}
+
+static void HBCB_BT_Phase2FullScreenWave(void)
+{
+ s16 offset = gScanlineEffectRegBuffers[1][REG_VCOUNT];
+
+ REG_BG1VOFS = offset;
+ REG_BG2VOFS = offset;
+ REG_BG3VOFS = offset;
+}
+
+#undef tTheta
+#undef tAmplitude
+#undef tDelayForFade
+#undef tStartFade
+
+#define tOffset data[1]
+#define tTheta data[2]
+
+static void BT_Phase2BlackWaveToRight(u8 taskId)
+{
+ while (sBT_Phase2BlackWaveToRightFuncs[gTasks[taskId].tState](&gTasks[taskId]));
+}
+
+static bool8 BT_Phase2BlackWaveToRight_Init(struct Task *task)
+{
+ u8 i;
+
+ BT_InitCtrlBlk();
+ ScanlineEffect_Clear();
+ sTransitionStructPtr->winIn = 0x3F;
+ sTransitionStructPtr->winOut = 0;
+ sTransitionStructPtr->win0H = 240;
+ sTransitionStructPtr->win0V = 160;
+ for (i = 0; i < 160; ++i)
+ gScanlineEffectRegBuffers[1][i] = 242;
+ SetVBlankCallback(VBCB_BT_Phase2BlackWaveToRight);
+ ++task->tState;
+ return TRUE;
+}
+
+static bool8 BT_Phase2BlackWaveToRight_UpdateWave(struct Task *task)
+{
+ u8 i, theta;
+ u16 *winVal;
+ bool8 nextFunc;
+
+ sTransitionStructPtr->vblankDma = FALSE;
+ winVal = gScanlineEffectRegBuffers[0];
+ theta = task->tTheta;
+ task->tTheta += 16;
+ task->tOffset += 8;
+ for (i = 0, nextFunc = TRUE; i < 160; ++i, theta += 4, ++winVal)
+ {
+ s16 left = task->tOffset + Sin(theta, 40);
+ if (left < 0)
+ left = 0;
+ if (left > 240)
+ left = 240;
+ *winVal = (left << 8) | (0xF1);
+ if (left < 240)
+ nextFunc = FALSE;
+ }
+ if (nextFunc)
+ ++task->tState;
+ ++sTransitionStructPtr->vblankDma;
+ return FALSE;
+}
+
+static bool8 BT_Phase2BlackWaveToRight_End(struct Task *task)
+{
+ DmaStop(0);
+ BT_BlendPalettesToBlack();
+ DestroyTask(FindTaskIdByFunc(BT_Phase2BlackWaveToRight));
+ return FALSE;
+}
+
+static void VBCB_BT_Phase2BlackWaveToRight(void)
+{
+ DmaStop(0);
+ BT_VBSyncOamAndPltt();
+ if (sTransitionStructPtr->vblankDma)
+ DmaCopy16(3, gScanlineEffectRegBuffers[0], gScanlineEffectRegBuffers[1], 320);
+ SetGpuReg(REG_OFFSET_WININ, sTransitionStructPtr->winIn);
+ SetGpuReg(REG_OFFSET_WINOUT, sTransitionStructPtr->winOut);
+ SetGpuReg(REG_OFFSET_WIN0V, sTransitionStructPtr->win0V);
+ DmaSet(0, gScanlineEffectRegBuffers[1], &REG_WIN0H, ((DMA_ENABLE | DMA_START_HBLANK | DMA_REPEAT | DMA_SRC_INC | DMA_DEST_FIXED) << 16) | 1);
+}
+
+#undef tOffset
+#undef tTheta
+
+static void BT_Phase2AntiClockwiseSpiral(u8 taskId)
+{
+ while (sBT_Phase2AntiClockwiseSpiralFuncs[gTasks[taskId].tState](&gTasks[taskId]));
+}
+
+#ifdef NONMATCHING
+static void sub_80D1F64(s16 a1, s16 a2, u8 a3)
+{
+ s16 i, j;
+
+ u8 theta = 0;
+ for (i = 320; i < 960; ++i)
+ gScanlineEffectRegBuffers[1][i] = 120;
+ for (i = 0; i < (a2 << 4); ++i, ++theta)
+ {
+ s16 res1, res2, res3, res4, diff, r8, r0;
+
+ // PROBLEM #1:
+ // (around line 50 in ASM)
+ // This part completely doesn't match.
+ // It's also not tail merge.
+ if ((theta >> 3) != ((theta + 1) >> 3))
+ {
+ r8 = (theta >> 3) + a1;
+ ++r8;
+ r0 = (theta >> 3) + a1;
+ }
+ else
+ {
+ r0 = (theta >> 3) + a1;
+ r8 = (theta >> 3) + a1;
+ }
+ res1 = 80 - Sin(theta, r0);
+ res2 = Cos(theta, r0) + 120;
+ res3 = 80 - Sin(theta + 1, r8);
+ res4 = Cos(theta + 1, r8) + 120;
+ if ((res1 >= 0 || res3 >= 0) && (res1 <= 159 || res3 <= 159))
+ {
+ if (res1 < 0)
+ res1 = 0;
+ if (res1 > 159)
+ res1 = 159;
+ if (res2 < 0)
+ res2 = 0;
+ if (res2 > 255)
+ res2 = 255;
+ if (res3 < 0)
+ res3 = 0;
+ if (res3 > 159)
+ res3 = 159;
+ if (res4 < 0)
+ res4 = 0;
+ if (res4 > 255)
+ res4 = 255;
+ diff = res3 - res1;
+ if (theta - 64 >= 0)
+ {
+ gScanlineEffectRegBuffers[1][res1 + 320] = res2;
+ if (diff)
+ {
+ s16 diff2 = res4 - res2;
+
+ if (diff2 < -1 && res2 > 1)
+ --res2;
+ else if (diff2 > 1 && res2 <= 254)
+ ++res2;
+ // PROBLEM #2:
+ // (around line 300 in ASM)
+ // The current version matched the control flow,
+ // but it looks too weird and some shift doesn't match
+
+ // functional equivalent:
+ // for (j = diff; j < 0; ++j)
+ // gScanlineEffectRegBuffers[1][res1 + j + 480] = res2;
+ // for (j = diff; j > 0; --j)
+ // gScanlineEffectRegBuffers[1][res1 + j + 480] = res2;
+ if ((j = diff) < 0)
+ do
+ gScanlineEffectRegBuffers[1][res1 + j + 320] = res2;
+ while (++j < 0);
+ else
+ while (j > 0)
+ {
+ gScanlineEffectRegBuffers[1][res1 + j + 320] = res2;
+ ++j;
+ }
+ }
+ }
+ else
+ {
+ gScanlineEffectRegBuffers[1][res1 + 480] = res2;
+ if (diff)
+ {
+ s16 diff2 = res4 - res2;
+
+ if (diff2 < -1 && res2 > 1)
+ --res2;
+ else if (diff2 > 1 && res2 <= 254)
+ ++res2;
+ // same as PROBLEM #2
+ for (j = diff; j < 0; ++j)
+ gScanlineEffectRegBuffers[1][res1 + j + 480] = res2;
+ for (j = diff; j > 0; --j)
+ gScanlineEffectRegBuffers[1][res1 + j + 480] = res2;
+ }
+ }
+ }
+ }
+ // PROBLEM #3: We need (a2 << 16) & 0x30000 here.
+ // Is it because the programmer declared a s32 var to
+ // hold the value of a2 and then cast the result to s16?
+ // Currently I have to write it explicitly.
+ // (around line 460 in ASM)
+ if (!a3 || !((a2 << 16) & 0x30000))
+ {
+ for (i = 0; i < 160; ++i)
+ gScanlineEffectRegBuffers[1][i * 2 + a3] = (gScanlineEffectRegBuffers[1][i + 320] << 8) | gScanlineEffectRegBuffers[1][i + 480];
+ }
+ else
+ {
+ s16 res = Sin(a2 * 16, a1 + a2 * 2);
+
+ switch (a2 / 4)
+ {
+ case 0:
+ if (res > 80)
+ res = 80;
+ // PROBLEM #4:
+ // (around line 550 in ASM)
+ // Case 0-3 are very similar, so it's very likely
+ // that they have the same problem.
+ // The code is definitely functional equivalent,
+ // but the vanilla game used some extra shifts and
+ // used unsigned comparison. Another difference is
+ // that I can't figure out a way to make gUnknown_83FA444[a2]
+ // happen outside the loop body.
+ // It seems that sTransitionStructPtr->data[2] need
+ // to be used in the first statement so that the
+ // struct pointer sTransitionStructPtr will be loaded
+ // early enough.
+ //
+ // Logically the generated code is following if + do-while structure.
+ // But it seems that it can only make the situation even worse.
+ /*
+ i = res;
+ if (i > 0)
+ {
+ // This happens before loop body.
+ s16 unk = gUnknown_83FA444[a2];
+
+ do
+ {
+ sTransitionStructPtr->data[2] = ((i * unk) >> 8) + 120;
+ if (sTransitionStructPtr->data[2] <= 255)
+ {
+ sTransitionStructPtr->bg123HOfs = 400 - i;
+ sTransitionStructPtr->data[10] = gScanlineEffectRegBuffers[1][400 - i];
+ if (gScanlineEffectRegBuffers[1][560 - i] < sTransitionStructPtr->data[2])
+ gScanlineEffectRegBuffers[1][560 - i] = 120;
+ else if (gScanlineEffectRegBuffers[1][400 - i] < sTransitionStructPtr->data[2])
+ gScanlineEffectRegBuffers[1][400 - i] = sTransitionStructPtr->data[2];
+ }
+ }
+ while (--i > 0);
+ }
+ */
+ for (i = res; i > 0; --i)
+ {
+ sTransitionStructPtr->data[2] = ((i * gUnknown_83FA444[a2]) >> 8) + 120;
+ if (sTransitionStructPtr->data[2] <= 255)
+ {
+ sTransitionStructPtr->bg123HOfs = 400 - i;
+ sTransitionStructPtr->data[10] = gScanlineEffectRegBuffers[1][400 - i];
+ if (gScanlineEffectRegBuffers[1][560 - i] < sTransitionStructPtr->data[2])
+ gScanlineEffectRegBuffers[1][560 - i] = 120;
+ else if (gScanlineEffectRegBuffers[1][400 - i] < sTransitionStructPtr->data[2])
+ gScanlineEffectRegBuffers[1][400 - i] = sTransitionStructPtr->data[2];
+ }
+ }
+ break;
+ case 1:
+ if (res > 80)
+ res = 80;
+ // same as PROBLEM #4
+ for (i = res; i > 0; --i)
+ {
+ s16 unkVal;
+
+ sTransitionStructPtr->data[2] = ((i * gUnknown_83FA444[a2]) >> 8) + 120;
+ if (sTransitionStructPtr->data[2] <= 255)
+ {
+ sTransitionStructPtr->bg123HOfs = 400 - i;
+ sTransitionStructPtr->data[10] = gScanlineEffectRegBuffers[1][400 - i];
+ if (gScanlineEffectRegBuffers[1][400 - i] < sTransitionStructPtr->data[2])
+ gScanlineEffectRegBuffers[1][400 - i] = sTransitionStructPtr->data[2];
+ }
+ }
+ break;
+ case 2:
+ if (res < -79)
+ res = -79;
+ // same as PROBLEM #4
+ for (i = res; i <= 0; ++i)
+ {
+ sTransitionStructPtr->data[2] = ((i * gUnknown_83FA444[a2]) >> 8) + 120;
+ if (sTransitionStructPtr->data[2] <= 255)
+ {
+ sTransitionStructPtr->bg123HOfs = 560 - i;
+ sTransitionStructPtr->data[10] = gScanlineEffectRegBuffers[1][560 - i];
+ if (gScanlineEffectRegBuffers[1][400 - i] >= sTransitionStructPtr->data[2])
+ gScanlineEffectRegBuffers[1][400 - i] = 120;
+ else if (gScanlineEffectRegBuffers[1][560 - i] > sTransitionStructPtr->data[2])
+ gScanlineEffectRegBuffers[1][560 - i] = sTransitionStructPtr->data[2];
+ }
+ }
+ break;
+ case 3:
+ if (res < -79)
+ res = -79;
+ // same as PROBLEM #4
+ for (i = res; i <= 0; ++i)
+ {
+ sTransitionStructPtr->data[2] = ((i * gUnknown_83FA444[a2]) >> 8) + 120;
+ if (sTransitionStructPtr->data[2] <= 255)
+ {
+ sTransitionStructPtr->bg123HOfs = 560 - i;
+ sTransitionStructPtr->data[10] = gScanlineEffectRegBuffers[1][560 - i];
+ if (gScanlineEffectRegBuffers[1][560 - i] > sTransitionStructPtr->data[2])
+ gScanlineEffectRegBuffers[1][560 - i] = sTransitionStructPtr->data[2];
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ for (i = 0; i < 160; ++i)
+ gScanlineEffectRegBuffers[1][2 * i + a3] = (gScanlineEffectRegBuffers[1][i + 320] << 8) | gScanlineEffectRegBuffers[1][i + 480];
+ }
+}
+#else
+NAKED
+static void sub_80D1F64(s16 a1, s16 a2, u8 a3)
+{
+ asm_unified("\n\
+ push {r4-r7,lr}\n\
+ mov r7, r10\n\
+ mov r6, r9\n\
+ mov r5, r8\n\
+ push {r5-r7}\n\
+ sub sp, 0x14\n\
+ lsls r0, 16\n\
+ lsrs r0, 16\n\
+ str r0, [sp]\n\
+ lsls r1, 16\n\
+ lsrs r5, r1, 16\n\
+ lsls r2, 24\n\
+ lsrs r2, 24\n\
+ str r2, [sp, 0x4]\n\
+ movs r0, 0\n\
+ mov r10, r0\n\
+ movs r1, 0xA0\n\
+ lsls r1, 17\n\
+ ldr r4, _080D1FD8 @ =gScanlineEffectRegBuffers + 0x780\n\
+ ldr r3, _080D1FDC @ =0x000003bf\n\
+ movs r2, 0x78\n\
+ _080D1F8E:\n\
+ asrs r0, r1, 16\n\
+ lsls r1, r0, 1\n\
+ adds r1, r4\n\
+ strh r2, [r1]\n\
+ adds r0, 0x1\n\
+ lsls r1, r0, 16\n\
+ asrs r0, r1, 16\n\
+ cmp r0, r3\n\
+ ble _080D1F8E\n\
+ lsls r0, r5, 16\n\
+ movs r1, 0\n\
+ mov r9, r1\n\
+ str r0, [sp, 0xC]\n\
+ cmp r0, 0\n\
+ bgt _080D1FAE\n\
+ b _080D221A\n\
+ _080D1FAE:\n\
+ mov r3, r10\n\
+ lsrs r2, r3, 3\n\
+ ldr r4, [sp]\n\
+ adds r0, r2, r4\n\
+ lsls r0, 16\n\
+ lsrs r3, r0, 16\n\
+ mov r0, r10\n\
+ adds r0, 0x1\n\
+ asrs r1, r0, 3\n\
+ str r0, [sp, 0x8]\n\
+ cmp r2, r1\n\
+ beq _080D1FE0\n\
+ lsls r1, r3, 16\n\
+ movs r6, 0x80\n\
+ lsls r6, 9\n\
+ adds r0, r1, r6\n\
+ lsrs r0, 16\n\
+ mov r8, r0\n\
+ adds r0, r1, 0\n\
+ b _080D1FE6\n\
+ .align 2, 0\n\
+ _080D1FD8: .4byte gScanlineEffectRegBuffers + 0x780\n\
+ _080D1FDC: .4byte 0x000003bf\n\
+ _080D1FE0:\n\
+ lsls r0, r3, 16\n\
+ lsrs r1, r0, 16\n\
+ mov r8, r1\n\
+ _080D1FE6:\n\
+ asrs r4, r0, 16\n\
+ mov r0, r10\n\
+ adds r1, r4, 0\n\
+ bl Sin\n\
+ movs r5, 0x50\n\
+ subs r0, r5, r0\n\
+ lsls r0, 16\n\
+ lsrs r2, r0, 16\n\
+ mov r0, r10\n\
+ adds r1, r4, 0\n\
+ str r2, [sp, 0x10]\n\
+ bl Cos\n\
+ adds r0, 0x78\n\
+ lsls r0, 16\n\
+ lsrs r7, r0, 16\n\
+ ldr r6, [sp, 0x8]\n\
+ mov r3, r8\n\
+ lsls r4, r3, 16\n\
+ asrs r4, 16\n\
+ adds r0, r6, 0\n\
+ adds r1, r4, 0\n\
+ bl Sin\n\
+ subs r5, r0\n\
+ lsls r5, 16\n\
+ lsrs r5, 16\n\
+ adds r0, r6, 0\n\
+ adds r1, r4, 0\n\
+ bl Cos\n\
+ adds r0, 0x78\n\
+ lsls r0, 16\n\
+ lsrs r3, r0, 16\n\
+ ldr r2, [sp, 0x10]\n\
+ lsls r0, r2, 16\n\
+ asrs r1, r0, 16\n\
+ cmp r1, 0\n\
+ bge _080D203E\n\
+ lsls r0, r5, 16\n\
+ cmp r0, 0\n\
+ bge _080D203E\n\
+ b _080D21F8\n\
+ _080D203E:\n\
+ cmp r1, 0x9F\n\
+ ble _080D204C\n\
+ lsls r0, r5, 16\n\
+ asrs r0, 16\n\
+ cmp r0, 0x9F\n\
+ ble _080D204C\n\
+ b _080D21F8\n\
+ _080D204C:\n\
+ cmp r1, 0\n\
+ bge _080D2052\n\
+ movs r2, 0\n\
+ _080D2052:\n\
+ lsls r0, r2, 16\n\
+ asrs r0, 16\n\
+ cmp r0, 0x9F\n\
+ ble _080D205C\n\
+ movs r2, 0x9F\n\
+ _080D205C:\n\
+ lsls r0, r7, 16\n\
+ cmp r0, 0\n\
+ bge _080D2064\n\
+ movs r7, 0\n\
+ _080D2064:\n\
+ lsls r0, r7, 16\n\
+ asrs r0, 16\n\
+ cmp r0, 0xFF\n\
+ ble _080D206E\n\
+ movs r7, 0xFF\n\
+ _080D206E:\n\
+ lsls r0, r5, 16\n\
+ cmp r0, 0\n\
+ bge _080D2076\n\
+ movs r5, 0\n\
+ _080D2076:\n\
+ lsls r0, r5, 16\n\
+ asrs r0, 16\n\
+ cmp r0, 0x9F\n\
+ ble _080D2080\n\
+ movs r5, 0x9F\n\
+ _080D2080:\n\
+ lsls r0, r3, 16\n\
+ cmp r0, 0\n\
+ bge _080D2088\n\
+ movs r3, 0\n\
+ _080D2088:\n\
+ lsls r0, r3, 16\n\
+ asrs r0, 16\n\
+ cmp r0, 0xFF\n\
+ ble _080D2092\n\
+ movs r3, 0xFF\n\
+ _080D2092:\n\
+ lsls r0, r5, 16\n\
+ asrs r0, 16\n\
+ lsls r1, r2, 16\n\
+ asrs r2, r1, 16\n\
+ subs r0, r2\n\
+ lsls r0, 16\n\
+ lsrs r5, r0, 16\n\
+ mov r0, r10\n\
+ subs r0, 0x40\n\
+ lsls r0, 24\n\
+ adds r6, r1, 0\n\
+ cmp r0, 0\n\
+ blt _080D2158\n\
+ movs r4, 0xA0\n\
+ lsls r4, 1\n\
+ adds r0, r2, r4\n\
+ lsls r0, 1\n\
+ ldr r1, _080D20E8 @ =gScanlineEffectRegBuffers + 0x780\n\
+ adds r0, r1\n\
+ strh r7, [r0]\n\
+ lsls r0, r5, 16\n\
+ adds r4, r0, 0\n\
+ cmp r4, 0\n\
+ bne _080D20C4\n\
+ b _080D21F8\n\
+ _080D20C4:\n\
+ lsls r0, r3, 16\n\
+ asrs r0, 16\n\
+ lsls r1, r7, 16\n\
+ asrs r2, r1, 16\n\
+ subs r0, r2\n\
+ lsls r0, 16\n\
+ lsrs r3, r0, 16\n\
+ asrs r0, 16\n\
+ mov r8, r0\n\
+ movs r0, 0x1\n\
+ negs r0, r0\n\
+ cmp r8, r0\n\
+ bge _080D20EC\n\
+ cmp r2, 0x1\n\
+ ble _080D20EC\n\
+ subs r0, r2, 0x1\n\
+ b _080D20FC\n\
+ .align 2, 0\n\
+ _080D20E8: .4byte gScanlineEffectRegBuffers + 0x780\n\
+ _080D20EC:\n\
+ lsls r0, r3, 16\n\
+ asrs r0, 16\n\
+ cmp r0, 0x1\n\
+ ble _080D2100\n\
+ asrs r0, r1, 16\n\
+ cmp r0, 0xFE\n\
+ bgt _080D2100\n\
+ adds r0, 0x1\n\
+ _080D20FC:\n\
+ lsls r0, 16\n\
+ lsrs r7, r0, 16\n\
+ _080D2100:\n\
+ adds r0, r4, 0\n\
+ asrs r1, r0, 16\n\
+ cmp r1, 0\n\
+ bge _080D212C\n\
+ asrs r2, r6, 16\n\
+ ldr r3, _080D2128 @ =gScanlineEffectRegBuffers + 0x780\n\
+ _080D210C:\n\
+ asrs r1, r0, 16\n\
+ adds r0, r2, r1\n\
+ movs r4, 0xA0\n\
+ lsls r4, 1\n\
+ adds r0, r4\n\
+ lsls r0, 1\n\
+ adds r0, r3\n\
+ strh r7, [r0]\n\
+ adds r1, 0x1\n\
+ lsls r0, r1, 16\n\
+ cmp r0, 0\n\
+ blt _080D210C\n\
+ b _080D21F8\n\
+ .align 2, 0\n\
+ _080D2128: .4byte gScanlineEffectRegBuffers + 0x780\n\
+ _080D212C:\n\
+ cmp r1, 0\n\
+ ble _080D21F8\n\
+ asrs r2, r6, 16\n\
+ ldr r3, _080D2154 @ =gScanlineEffectRegBuffers + 0x780\n\
+ _080D2134:\n\
+ lsls r1, r5, 16\n\
+ asrs r1, 16\n\
+ adds r0, r2, r1\n\
+ movs r6, 0xA0\n\
+ lsls r6, 1\n\
+ adds r0, r6\n\
+ lsls r0, 1\n\
+ adds r0, r3\n\
+ strh r7, [r0]\n\
+ subs r1, 0x1\n\
+ lsls r1, 16\n\
+ lsrs r5, r1, 16\n\
+ cmp r1, 0\n\
+ bgt _080D2134\n\
+ b _080D21F8\n\
+ .align 2, 0\n\
+ _080D2154: .4byte gScanlineEffectRegBuffers + 0x780\n\
+ _080D2158:\n\
+ movs r1, 0xF0\n\
+ lsls r1, 1\n\
+ adds r0, r2, r1\n\
+ lsls r0, 1\n\
+ ldr r2, _080D2190 @ =gScanlineEffectRegBuffers + 0x780\n\
+ adds r0, r2\n\
+ strh r7, [r0]\n\
+ lsls r0, r5, 16\n\
+ adds r4, r0, 0\n\
+ cmp r4, 0\n\
+ beq _080D21F8\n\
+ lsls r0, r3, 16\n\
+ asrs r0, 16\n\
+ lsls r1, r7, 16\n\
+ asrs r2, r1, 16\n\
+ subs r0, r2\n\
+ lsls r0, 16\n\
+ lsrs r3, r0, 16\n\
+ asrs r0, 16\n\
+ mov r8, r0\n\
+ movs r0, 0x1\n\
+ negs r0, r0\n\
+ cmp r8, r0\n\
+ bge _080D2194\n\
+ cmp r2, 0x1\n\
+ ble _080D2194\n\
+ subs r0, r2, 0x1\n\
+ b _080D21A4\n\
+ .align 2, 0\n\
+ _080D2190: .4byte gScanlineEffectRegBuffers + 0x780\n\
+ _080D2194:\n\
+ lsls r0, r3, 16\n\
+ asrs r0, 16\n\
+ cmp r0, 0x1\n\
+ ble _080D21A8\n\
+ asrs r0, r1, 16\n\
+ cmp r0, 0xFE\n\
+ bgt _080D21A8\n\
+ adds r0, 0x1\n\
+ _080D21A4:\n\
+ lsls r0, 16\n\
+ lsrs r7, r0, 16\n\
+ _080D21A8:\n\
+ adds r0, r4, 0\n\
+ asrs r1, r0, 16\n\
+ cmp r1, 0\n\
+ bge _080D21D4\n\
+ asrs r2, r6, 16\n\
+ ldr r3, _080D21D0 @ =gScanlineEffectRegBuffers + 0x780\n\
+ _080D21B4:\n\
+ asrs r1, r0, 16\n\
+ adds r0, r2, r1\n\
+ movs r4, 0xF0\n\
+ lsls r4, 1\n\
+ adds r0, r4\n\
+ lsls r0, 1\n\
+ adds r0, r3\n\
+ strh r7, [r0]\n\
+ adds r1, 0x1\n\
+ lsls r0, r1, 16\n\
+ cmp r0, 0\n\
+ blt _080D21B4\n\
+ b _080D21F8\n\
+ .align 2, 0\n\
+ _080D21D0: .4byte gScanlineEffectRegBuffers + 0x780\n\
+ _080D21D4:\n\
+ cmp r1, 0\n\
+ ble _080D21F8\n\
+ asrs r2, r6, 16\n\
+ ldr r3, _080D2270 @ =gScanlineEffectRegBuffers + 0x780\n\
+ _080D21DC:\n\
+ lsls r1, r5, 16\n\
+ asrs r1, 16\n\
+ adds r0, r2, r1\n\
+ movs r6, 0xF0\n\
+ lsls r6, 1\n\
+ adds r0, r6\n\
+ lsls r0, 1\n\
+ adds r0, r3\n\
+ strh r7, [r0]\n\
+ subs r1, 0x1\n\
+ lsls r1, 16\n\
+ lsrs r5, r1, 16\n\
+ cmp r1, 0\n\
+ bgt _080D21DC\n\
+ _080D21F8:\n\
+ mov r1, r9\n\
+ lsls r0, r1, 16\n\
+ movs r2, 0x80\n\
+ lsls r2, 9\n\
+ adds r0, r2\n\
+ ldr r3, [sp, 0x8]\n\
+ lsls r1, r3, 24\n\
+ lsrs r1, 24\n\
+ mov r10, r1\n\
+ lsrs r4, r0, 16\n\
+ mov r9, r4\n\
+ asrs r0, 16\n\
+ ldr r6, [sp, 0xC]\n\
+ asrs r1, r6, 12\n\
+ cmp r0, r1\n\
+ bge _080D221A\n\
+ b _080D1FAE\n\
+ _080D221A:\n\
+ ldr r0, [sp, 0x4]\n\
+ cmp r0, 0\n\
+ beq _080D222C\n\
+ movs r0, 0xC0\n\
+ lsls r0, 10\n\
+ ldr r1, [sp, 0xC]\n\
+ ands r0, r1\n\
+ cmp r0, 0\n\
+ bne _080D2274\n\
+ _080D222C:\n\
+ movs r2, 0\n\
+ mov r9, r2\n\
+ ldr r4, _080D2270 @ =gScanlineEffectRegBuffers + 0x780\n\
+ movs r5, 0xA0\n\
+ lsls r5, 1\n\
+ _080D2236:\n\
+ mov r3, r9\n\
+ lsls r1, r3, 16\n\
+ asrs r1, 16\n\
+ lsls r3, r1, 1\n\
+ ldr r6, [sp, 0x4]\n\
+ adds r3, r6\n\
+ lsls r3, 1\n\
+ adds r3, r4\n\
+ adds r0, r1, r5\n\
+ lsls r0, 1\n\
+ adds r0, r4\n\
+ ldrh r2, [r0]\n\
+ lsls r2, 8\n\
+ movs r6, 0xF0\n\
+ lsls r6, 1\n\
+ adds r0, r1, r6\n\
+ lsls r0, 1\n\
+ adds r0, r4\n\
+ ldrh r0, [r0]\n\
+ orrs r2, r0\n\
+ strh r2, [r3]\n\
+ adds r1, 0x1\n\
+ lsls r1, 16\n\
+ lsrs r0, r1, 16\n\
+ mov r9, r0\n\
+ asrs r1, 16\n\
+ cmp r1, 0x9F\n\
+ ble _080D2236\n\
+ b _080D251C\n\
+ .align 2, 0\n\
+ _080D2270: .4byte gScanlineEffectRegBuffers + 0x780\n\
+ _080D2274:\n\
+ ldr r1, [sp, 0xC]\n\
+ asrs r4, r1, 16\n\
+ lsls r0, r4, 20\n\
+ asrs r0, 16\n\
+ lsls r5, r4, 1\n\
+ ldr r2, [sp]\n\
+ lsls r1, r2, 16\n\
+ asrs r1, 16\n\
+ adds r1, r5\n\
+ lsls r1, 16\n\
+ asrs r1, 16\n\
+ bl Sin\n\
+ lsls r0, 16\n\
+ lsrs r2, r0, 16\n\
+ cmp r4, 0\n\
+ bge _080D2298\n\
+ adds r4, 0x3\n\
+ _080D2298:\n\
+ asrs r0, r4, 2\n\
+ cmp r0, 0x1\n\
+ beq _080D234C\n\
+ cmp r0, 0x1\n\
+ bgt _080D22A8\n\
+ cmp r0, 0\n\
+ beq _080D22B6\n\
+ b _080D24DA\n\
+ _080D22A8:\n\
+ cmp r0, 0x2\n\
+ bne _080D22AE\n\
+ b _080D23CC\n\
+ _080D22AE:\n\
+ cmp r0, 0x3\n\
+ bne _080D22B4\n\
+ b _080D2466\n\
+ _080D22B4:\n\
+ b _080D24DA\n\
+ _080D22B6:\n\
+ lsls r0, r2, 16\n\
+ asrs r0, 16\n\
+ cmp r0, 0x50\n\
+ ble _080D22C0\n\
+ movs r2, 0x50\n\
+ _080D22C0:\n\
+ mov r9, r2\n\
+ lsls r1, r2, 16\n\
+ cmp r1, 0\n\
+ bgt _080D22CA\n\
+ b _080D24DA\n\
+ _080D22CA:\n\
+ ldr r0, _080D2320 @ =gUnknown_83FA444\n\
+ adds r0, r5, r0\n\
+ movs r3, 0\n\
+ ldrsh r4, [r0, r3]\n\
+ ldr r6, _080D2324 @ =gScanlineEffectRegBuffers + 0x780\n\
+ _080D22D4:\n\
+ ldr r0, _080D2328 @ =sTransitionStructPtr\n\
+ ldr r5, [r0]\n\
+ asrs r2, r1, 16\n\
+ adds r0, r2, 0\n\
+ muls r0, r4\n\
+ asrs r0, 8\n\
+ adds r0, 0x78\n\
+ lsls r1, r0, 16\n\
+ lsrs r7, r1, 16\n\
+ strh r0, [r5, 0x28]\n\
+ lsls r1, r7, 16\n\
+ lsrs r0, r1, 16\n\
+ cmp r0, 0xFF\n\
+ bhi _080D2334\n\
+ movs r3, 0xC8\n\
+ lsls r3, 1\n\
+ adds r0, r3, 0\n\
+ subs r0, r2\n\
+ strh r0, [r5, 0x14]\n\
+ adds r0, r3, 0\n\
+ subs r0, r2\n\
+ lsls r0, 1\n\
+ adds r3, r0, r6\n\
+ ldrh r0, [r3]\n\
+ strh r0, [r5, 0x38]\n\
+ movs r0, 0x8C\n\
+ lsls r0, 2\n\
+ subs r0, r2\n\
+ lsls r0, 1\n\
+ adds r2, r0, r6\n\
+ ldrh r0, [r2]\n\
+ asrs r1, 16\n\
+ cmp r0, r1\n\
+ bge _080D232C\n\
+ movs r0, 0x78\n\
+ strh r0, [r2]\n\
+ b _080D2334\n\
+ .align 2, 0\n\
+ _080D2320: .4byte gUnknown_83FA444\n\
+ _080D2324: .4byte gScanlineEffectRegBuffers + 0x780\n\
+ _080D2328: .4byte sTransitionStructPtr\n\
+ _080D232C:\n\
+ ldrh r0, [r3]\n\
+ cmp r0, r1\n\
+ bge _080D2334\n\
+ strh r7, [r3]\n\
+ _080D2334:\n\
+ mov r1, r9\n\
+ lsls r0, r1, 16\n\
+ ldr r2, _080D2348 @ =0xffff0000\n\
+ adds r0, r2\n\
+ lsrs r0, 16\n\
+ mov r9, r0\n\
+ lsls r1, r0, 16\n\
+ cmp r1, 0\n\
+ bgt _080D22D4\n\
+ b _080D24DA\n\
+ .align 2, 0\n\
+ _080D2348: .4byte 0xffff0000\n\
+ _080D234C:\n\
+ lsls r0, r2, 16\n\
+ asrs r0, 16\n\
+ cmp r0, 0x50\n\
+ ble _080D2356\n\
+ movs r2, 0x50\n\
+ _080D2356:\n\
+ mov r9, r2\n\
+ lsls r1, r2, 16\n\
+ cmp r1, 0\n\
+ bgt _080D2360\n\
+ b _080D24DA\n\
+ _080D2360:\n\
+ ldr r0, _080D23BC @ =gUnknown_83FA444\n\
+ adds r0, r5, r0\n\
+ movs r3, 0\n\
+ ldrsh r4, [r0, r3]\n\
+ ldr r6, _080D23C0 @ =gScanlineEffectRegBuffers + 0x780\n\
+ _080D236A:\n\
+ ldr r0, _080D23C4 @ =sTransitionStructPtr\n\
+ ldr r3, [r0]\n\
+ asrs r2, r1, 16\n\
+ adds r0, r2, 0\n\
+ muls r0, r4\n\
+ asrs r0, 8\n\
+ adds r0, 0x78\n\
+ lsls r1, r0, 16\n\
+ lsrs r7, r1, 16\n\
+ strh r0, [r3, 0x28]\n\
+ lsls r5, r7, 16\n\
+ lsrs r0, r5, 16\n\
+ cmp r0, 0xFF\n\
+ bhi _080D23A6\n\
+ movs r1, 0xC8\n\
+ lsls r1, 1\n\
+ adds r0, r1, 0\n\
+ subs r0, r2\n\
+ strh r0, [r3, 0x14]\n\
+ adds r0, r1, 0\n\
+ subs r0, r2\n\
+ lsls r0, 1\n\
+ adds r2, r0, r6\n\
+ ldrh r0, [r2]\n\
+ strh r0, [r3, 0x38]\n\
+ ldrh r1, [r2]\n\
+ asrs r0, r5, 16\n\
+ cmp r1, r0\n\
+ bge _080D23A6\n\
+ strh r7, [r2]\n\
+ _080D23A6:\n\
+ mov r2, r9\n\
+ lsls r0, r2, 16\n\
+ ldr r3, _080D23C8 @ =0xffff0000\n\
+ adds r0, r3\n\
+ lsrs r0, 16\n\
+ mov r9, r0\n\
+ lsls r1, r0, 16\n\
+ cmp r1, 0\n\
+ bgt _080D236A\n\
+ b _080D24DA\n\
+ .align 2, 0\n\
+ _080D23BC: .4byte gUnknown_83FA444\n\
+ _080D23C0: .4byte gScanlineEffectRegBuffers + 0x780\n\
+ _080D23C4: .4byte sTransitionStructPtr\n\
+ _080D23C8: .4byte 0xffff0000\n\
+ _080D23CC:\n\
+ lsls r0, r2, 16\n\
+ asrs r0, 16\n\
+ movs r1, 0x4F\n\
+ negs r1, r1\n\
+ cmp r0, r1\n\
+ bge _080D23DA\n\
+ ldr r2, _080D2438 @ =0x0000ffb1\n\
+ _080D23DA:\n\
+ mov r9, r2\n\
+ lsls r1, r2, 16\n\
+ cmp r1, 0\n\
+ bgt _080D24DA\n\
+ ldr r0, _080D243C @ =gUnknown_83FA444\n\
+ adds r0, r5, r0\n\
+ movs r6, 0\n\
+ ldrsh r4, [r0, r6]\n\
+ ldr r6, _080D2440 @ =gScanlineEffectRegBuffers + 0x780\n\
+ _080D23EC:\n\
+ ldr r0, _080D2444 @ =sTransitionStructPtr\n\
+ ldr r5, [r0]\n\
+ asrs r2, r1, 16\n\
+ adds r0, r2, 0\n\
+ muls r0, r4\n\
+ asrs r0, 8\n\
+ adds r0, 0x78\n\
+ lsls r1, r0, 16\n\
+ lsrs r7, r1, 16\n\
+ strh r0, [r5, 0x28]\n\
+ lsls r1, r7, 16\n\
+ lsrs r0, r1, 16\n\
+ cmp r0, 0xFF\n\
+ bhi _080D2450\n\
+ movs r3, 0x8C\n\
+ lsls r3, 2\n\
+ adds r0, r3, 0\n\
+ subs r0, r2\n\
+ strh r0, [r5, 0x14]\n\
+ adds r0, r3, 0\n\
+ subs r0, r2\n\
+ lsls r0, 1\n\
+ adds r3, r0, r6\n\
+ ldrh r0, [r3]\n\
+ strh r0, [r5, 0x38]\n\
+ movs r0, 0xC8\n\
+ lsls r0, 1\n\
+ subs r0, r2\n\
+ lsls r0, 1\n\
+ adds r2, r0, r6\n\
+ ldrh r0, [r2]\n\
+ asrs r1, 16\n\
+ cmp r0, r1\n\
+ blt _080D2448\n\
+ movs r0, 0x78\n\
+ strh r0, [r2]\n\
+ b _080D2450\n\
+ .align 2, 0\n\
+ _080D2438: .4byte 0x0000ffb1\n\
+ _080D243C: .4byte gUnknown_83FA444\n\
+ _080D2440: .4byte gScanlineEffectRegBuffers + 0x780\n\
+ _080D2444: .4byte sTransitionStructPtr\n\
+ _080D2448:\n\
+ ldrh r0, [r3]\n\
+ cmp r0, r1\n\
+ ble _080D2450\n\
+ strh r7, [r3]\n\
+ _080D2450:\n\
+ mov r1, r9\n\
+ lsls r0, r1, 16\n\
+ movs r2, 0x80\n\
+ lsls r2, 9\n\
+ adds r0, r2\n\
+ lsrs r0, 16\n\
+ mov r9, r0\n\
+ lsls r1, r0, 16\n\
+ cmp r1, 0\n\
+ ble _080D23EC\n\
+ b _080D24DA\n\
+ _080D2466:\n\
+ lsls r0, r2, 16\n\
+ asrs r0, 16\n\
+ movs r1, 0x4F\n\
+ negs r1, r1\n\
+ cmp r0, r1\n\
+ bge _080D2474\n\
+ ldr r2, _080D252C @ =0x0000ffb1\n\
+ _080D2474:\n\
+ mov r9, r2\n\
+ lsls r1, r2, 16\n\
+ cmp r1, 0\n\
+ bgt _080D24DA\n\
+ ldr r0, _080D2530 @ =gUnknown_83FA444\n\
+ adds r0, r5, r0\n\
+ movs r3, 0\n\
+ ldrsh r4, [r0, r3]\n\
+ ldr r6, _080D2534 @ =sTransitionStructPtr\n\
+ mov r8, r6\n\
+ ldr r6, _080D2538 @ =gScanlineEffectRegBuffers + 0x780\n\
+ _080D248A:\n\
+ mov r0, r8\n\
+ ldr r3, [r0]\n\
+ asrs r2, r1, 16\n\
+ adds r0, r2, 0\n\
+ muls r0, r4\n\
+ asrs r0, 8\n\
+ adds r0, 0x78\n\
+ lsls r1, r0, 16\n\
+ lsrs r7, r1, 16\n\
+ strh r0, [r3, 0x28]\n\
+ lsls r5, r7, 16\n\
+ lsrs r0, r5, 16\n\
+ cmp r0, 0xFF\n\
+ bhi _080D24C6\n\
+ movs r1, 0x8C\n\
+ lsls r1, 2\n\
+ adds r0, r1, 0\n\
+ subs r0, r2\n\
+ strh r0, [r3, 0x14]\n\
+ adds r0, r1, 0\n\
+ subs r0, r2\n\
+ lsls r0, 1\n\
+ adds r2, r0, r6\n\
+ ldrh r0, [r2]\n\
+ strh r0, [r3, 0x38]\n\
+ ldrh r1, [r2]\n\
+ asrs r0, r5, 16\n\
+ cmp r1, r0\n\
+ ble _080D24C6\n\
+ strh r7, [r2]\n\
+ _080D24C6:\n\
+ mov r2, r9\n\
+ lsls r0, r2, 16\n\
+ movs r3, 0x80\n\
+ lsls r3, 9\n\
+ adds r0, r3\n\
+ lsrs r0, 16\n\
+ mov r9, r0\n\
+ lsls r1, r0, 16\n\
+ cmp r1, 0\n\
+ ble _080D248A\n\
+ _080D24DA:\n\
+ movs r4, 0\n\
+ mov r9, r4\n\
+ ldr r4, _080D2538 @ =gScanlineEffectRegBuffers + 0x780\n\
+ movs r5, 0xA0\n\
+ lsls r5, 1\n\
+ _080D24E4:\n\
+ mov r6, r9\n\
+ lsls r1, r6, 16\n\
+ asrs r1, 16\n\
+ lsls r3, r1, 1\n\
+ ldr r0, [sp, 0x4]\n\
+ adds r3, r0\n\
+ lsls r3, 1\n\
+ adds r3, r4\n\
+ adds r0, r1, r5\n\
+ lsls r0, 1\n\
+ adds r0, r4\n\
+ ldrh r2, [r0]\n\
+ lsls r2, 8\n\
+ movs r6, 0xF0\n\
+ lsls r6, 1\n\
+ adds r0, r1, r6\n\
+ lsls r0, 1\n\
+ adds r0, r4\n\
+ ldrh r0, [r0]\n\
+ orrs r2, r0\n\
+ strh r2, [r3]\n\
+ adds r1, 0x1\n\
+ lsls r1, 16\n\
+ lsrs r0, r1, 16\n\
+ mov r9, r0\n\
+ asrs r1, 16\n\
+ cmp r1, 0x9F\n\
+ ble _080D24E4\n\
+ _080D251C:\n\
+ add sp, 0x14\n\
+ pop {r3-r5}\n\
+ mov r8, r3\n\
+ mov r9, r4\n\
+ mov r10, r5\n\
+ pop {r4-r7}\n\
+ pop {r0}\n\
+ bx r0\n\
+ .align 2, 0\n\
+ _080D252C: .4byte 0x0000ffb1\n\
+ _080D2530: .4byte gUnknown_83FA444\n\
+ _080D2534: .4byte sTransitionStructPtr\n\
+ _080D2538: .4byte gScanlineEffectRegBuffers + 0x780\n\
+ ");
+}
+#endif
+
+static bool8 BT_Phase2AntiClockwiseSpiral_Init(struct Task *task)
+{
+ BT_InitCtrlBlk();
+ ScanlineEffect_Clear();
+ sTransitionStructPtr->winIn = 0;
+ sTransitionStructPtr->winOut = 0x3F;
+ sTransitionStructPtr->win0H = 0x7878;
+ sTransitionStructPtr->win0V = 0x3070;
+ sTransitionStructPtr->win1V = 0x1090;
+ sTransitionStructPtr->counter = 0;
+ sub_80D1F64(0, 0, FALSE);
+ sub_80D1F64(0, 0, TRUE);
+ DmaCopy16(3, gScanlineEffectRegBuffers[1], gScanlineEffectRegBuffers[0], 640);
+ SetVBlankCallback(VBCB_BT_Phase2AntiClockwiseBlackFade);
+ ++task->tState;
+ task->data[1] = 0;
+ task->data[2] = 0;
+ return FALSE;
+}
+
+static bool8 BT_Phase2AntiClockwiseSpiral_Update(struct Task *task)
+{
+ s16 v0, v1;
+
+ sub_80D1F64(task->data[2], task->data[1], TRUE);
+ sTransitionStructPtr->vblankDma |= TRUE;
+ if (++task->data[1] == 17)
+ {
+ sub_80D1F64(task->data[2], 16, FALSE);
+ v0 = 48 - task->data[2];
+ if (v0 < 0)
+ v0 = 0;
+ v1 = task->data[2] + 112;
+ if (v1 > 255)
+ v1 = 255;
+ sTransitionStructPtr->win0V = v0 | v1;
+ task->data[2] += 32;
+ task->data[1] = 0;
+ sub_80D1F64(task->data[2], 0, TRUE);
+ v0 = 48 - task->data[2];
+ if (v0 < 0)
+ v0 = 0;
+ v1 = task->data[2] + 112;
+ if (v1 > 255)
+ v1 = 255;
+ sTransitionStructPtr->win1V = v0 | v1;
+ sTransitionStructPtr->vblankDma |= TRUE;
+ if (task->data[2] > 159)
+ {
+ sTransitionStructPtr->counter = 1;
+ BT_BlendPalettesToBlack();
+ }
+ }
+ return FALSE;
+}
+
+static void VBCB_BT_Phase2AntiClockwiseBlackFade(void)
+{
+ DmaStop(0);
+ BT_VBSyncOamAndPltt();
+ if (sTransitionStructPtr->counter)
+ {
+ DestroyTask(FindTaskIdByFunc(BT_Phase2AntiClockwiseSpiral));
+ }
+ else
+ {
+ if (sTransitionStructPtr->vblankDma)
+ {
+ DmaCopy16(3, gScanlineEffectRegBuffers[1], gScanlineEffectRegBuffers[0], 640);
+ sTransitionStructPtr->vblankDma = FALSE;
+ }
+ SetGpuReg(REG_OFFSET_WININ, sTransitionStructPtr->winIn);
+ SetGpuReg(REG_OFFSET_WINOUT, sTransitionStructPtr->winOut);
+ SetGpuReg(REG_OFFSET_WIN0V, sTransitionStructPtr->win0V);
+ SetGpuReg(REG_OFFSET_WIN1V, sTransitionStructPtr->win1V);
+ SetGpuReg(REG_OFFSET_WIN0H, gScanlineEffectRegBuffers[0][0]);
+ SetGpuReg(REG_OFFSET_WIN1H, gScanlineEffectRegBuffers[0][1]);
+ DmaSet(0, gScanlineEffectRegBuffers[0], &REG_WIN0H, ((DMA_ENABLE | DMA_START_HBLANK | DMA_REPEAT | DMA_32BIT | DMA_SRC_INC | DMA_DEST_FIXED) << 16) | 1);
+ }
+}
+
+#define tTheta data[1]
+#define tbg0HOfsOpponent data[2]
+#define tbg0HOfsPlayer data[3]
+#define tCounter data[3]
+#define tHalfBandwidth data[4]
+#define tOpponentSpriteId data[13]
+#define tPlayerSpriteId data[14]
+#define tWhichMugshot data[15]
+
+#define spState data[0]
+#define spSpeed data[1]
+#define spAbsAcc data[2]
+#define sphasSlideFinished data[6]
+#define spOpponentOrPlayer data[7]
+
+static void BT_Phase2StartLoreleiMugshot(u8 taskId)
+{
+ gTasks[taskId].tWhichMugshot = MUGSHOT_LORELEI;
+ BT_Phase2Mugshot(taskId);
+}
+
+static void BT_Phase2StartBrunoMugshot(u8 taskId)
+{
+ gTasks[taskId].tWhichMugshot = MUGSHOT_BRUNO;
+ BT_Phase2Mugshot(taskId);
+}
+
+static void BT_Phase2StartAgathaMugshot(u8 taskId)
+{
+ gTasks[taskId].tWhichMugshot = MUGSHOT_AGATHA;
+ BT_Phase2Mugshot(taskId);
+}
+
+static void BT_Phase2StartLanceMugshot(u8 taskId)
+{
+ gTasks[taskId].tWhichMugshot = MUGSHOT_LANCE;
+ BT_Phase2Mugshot(taskId);
+}
+
+static void BT_Phase2StartBlueMugshot(u8 taskId)
+{
+ gTasks[taskId].tWhichMugshot = MUGSHOT_BLUE;
+ BT_Phase2Mugshot(taskId);
+}
+
+static void BT_Phase2Mugshot(u8 taskId)
+{
+ while (sBT_Phase2MugshotFuncs[gTasks[taskId].tState](&gTasks[taskId]));
+}
+
+static bool8 BT_Phase2Mugshot_Init(struct Task *task)
+{
+ u8 i;
+
+ BT_InitCtrlBlk();
+ ScanlineEffect_Clear();
+ BT_Phase2Mugshots_CreateSprites(task);
+ task->tTheta = 0;
+ task->tbg0HOfsOpponent = 1;
+ task->tbg0HOfsPlayer = 239;
+ sTransitionStructPtr->winIn = 0x3F;
+ sTransitionStructPtr->winOut = 0x3E;
+ sTransitionStructPtr->win0V = 160;
+ for (i = 0; i < 160; ++i)
+ gScanlineEffectRegBuffers[1][i] = 0xF0F1;
+ SetVBlankCallback(VBCB_BT_Phase2Mugshot1_Slide);
+ ++task->tState;
+ return FALSE;
+}
+
+static bool8 BT_Phase2Mugshot_LoadGfx(struct Task *task)
+{
+ s16 i, j;
+ u16 *tilemapAddr, *tilesetAddr;
+ const u16 *mugshotsMap = sVsBarTilemap;
+
+ BT_GetBg0TilemapAndTilesetBase(&tilemapAddr, &tilesetAddr);
+ CpuSet(sVsBarTileset, tilesetAddr, 0xF0);
+ LoadPalette(sVsBarOpponentPalettes[task->tWhichMugshot], 0xF0, 0x20);
+ LoadPalette(sVsBarPlayerPalettes[gSaveBlock2Ptr->playerGender], 0xFA, 0xC);
+ for (i = 0; i < 20; ++i)
+ for (j = 0; j < 32; ++j, ++mugshotsMap)
+ tilemapAddr[i * 32 + j] = *mugshotsMap | 0xF000; // use palette #15
+ EnableInterrupts(INTR_FLAG_HBLANK);
+ SetHBlankCallback(HBCB_BT_Phase2Mugshot);
+ ++task->tState;
+ return FALSE;
+}
+
+static bool8 BT_Phase2Mugshot_VsBarsSlideIn(struct Task *task)
+{
+ u8 i, theta;
+ u16 *winVal;
+ s16 value;
+ s32 mergedBg0hOfs;
+
+ sTransitionStructPtr->vblankDma = FALSE;
+
+ winVal = gScanlineEffectRegBuffers[0];
+ theta = task->tTheta;
+ task->tTheta += 0x10;
+ for (i = 0; i < 80; ++i, ++winVal, theta += 0x10)
+ {
+ value = task->tbg0HOfsOpponent + Sin(theta, 0x10);
+ if (value < 0)
+ value = 1;
+ if (value > 0xF0)
+ value = 0xF0;
+ *winVal = value;
+ }
+ for (; i < 160; ++i, ++winVal, theta += 0x10)
+ {
+ value = task->tCounter - Sin(theta, 0x10);
+ if (value < 0)
+ value = 0;
+ if (value > 0xEF)
+ value = 0xEF;
+ *winVal = (value << 8) | (0xF0);
+ }
+ task->tbg0HOfsOpponent += 8;
+ task->tCounter -= 8;
+ if (task->tbg0HOfsOpponent > 0xF0)
+ task->tbg0HOfsOpponent = 0xF0;
+ if (task->tCounter < 0)
+ task->tCounter = 0;
+ mergedBg0hOfs = *(s32 *)(&task->tbg0HOfsOpponent);
+ if (mergedBg0hOfs == 0x00F0)
+ ++task->tState;
+ sTransitionStructPtr->bg0HOfsOpponent -= 8;
+ sTransitionStructPtr->bg0HOfsPlayer += 8;
+ ++sTransitionStructPtr->vblankDma;
+ return FALSE;
+}
+
+static bool8 BT_Phase2Mugshot_StartSpriteSlide(struct Task *task)
+{
+ u8 i;
+ u16 *winVal;
+
+ sTransitionStructPtr->vblankDma = FALSE;
+ for (i = 0, winVal = gScanlineEffectRegBuffers[0]; i < 160; ++i, ++winVal)
+ *winVal = 0xF0;
+ ++task->tState;
+ task->tTheta = 0;
+ task->tbg0HOfsOpponent = 0;
+ task->tbg0HOfsPlayer = 0;
+ sTransitionStructPtr->bg0HOfsOpponent -= 8;
+ sTransitionStructPtr->bg0HOfsPlayer += 8;
+ BT_SetSpriteAsOpponentOrPlayer(task->tOpponentSpriteId, FALSE);
+ BT_SetSpriteAsOpponentOrPlayer(task->tPlayerSpriteId, TRUE);
+ BT_StartSpriteSlide(task->tOpponentSpriteId);
+ PlaySE(SE_C_MAKU_U);
+ ++sTransitionStructPtr->vblankDma;
+ return FALSE;
+}
+
+static bool8 BT_Phase2Mugshot_WaitForOpponentInPlace(struct Task *task)
+{
+ sTransitionStructPtr->bg0HOfsOpponent -= 8;
+ sTransitionStructPtr->bg0HOfsPlayer += 8;
+ if (BT_IsSpriteSlideFinished(task->tOpponentSpriteId))
+ {
+ ++task->tState;
+ BT_StartSpriteSlide(task->tPlayerSpriteId);
+ }
+ return FALSE;
+}
+
+static bool8 BT_Phase2Mugshot_WaitForPlayerInPlace(struct Task *task)
+{
+ sTransitionStructPtr->bg0HOfsOpponent -= 8;
+ sTransitionStructPtr->bg0HOfsPlayer += 8;
+ if (BT_IsSpriteSlideFinished(task->tPlayerSpriteId))
+ {
+ sTransitionStructPtr->vblankDma = FALSE;
+ SetVBlankCallback(NULL);
+ DmaStop(0);
+ memset(gScanlineEffectRegBuffers[0], 0, 320);
+ memset(gScanlineEffectRegBuffers[1], 0, 320);
+ SetGpuReg(REG_OFFSET_WIN0H, 0xF0);
+ SetGpuReg(REG_OFFSET_BLDY, 0);
+ ++task->tState;
+ task->tCounter = 0;
+ task->tHalfBandwidth = 0;
+ sTransitionStructPtr->bldCnt = BLDCNT_TGT1_BG0 | BLDCNT_TGT1_BG1 | BLDCNT_TGT1_BG2 | BLDCNT_TGT1_BG3 | BLDCNT_TGT1_OBJ | BLDCNT_TGT1_BD | BLDCNT_EFFECT_LIGHTEN;
+ SetVBlankCallback(VBCB_BT_Phase2Mugshot2_WhiteFade);
+ }
+ return FALSE;
+}
+
+static bool8 BT_Phase2Mugshot_ExpandWhiteBand(struct Task *task)
+{
+ bool32 nextFunc;
+
+ sTransitionStructPtr->vblankDma = FALSE;
+ nextFunc = TRUE;
+ sTransitionStructPtr->bg0HOfsOpponent -= 8;
+ sTransitionStructPtr->bg0HOfsPlayer += 8;
+ if (task->tHalfBandwidth < 80)
+ task->tHalfBandwidth += 2;
+ if (task->tHalfBandwidth > 80)
+ task->tHalfBandwidth = 80;
+ if (++task->tCounter & 1)
+ {
+ s16 i;
+
+ for (i = 0, nextFunc = FALSE; i <= task->tHalfBandwidth; ++i)
+ {
+ s16 y1 = 80 - i;
+ s16 y2 = 80 + i;
+
+ if (gScanlineEffectRegBuffers[0][y1] <= 15)
+ {
+ nextFunc = TRUE;
+ ++gScanlineEffectRegBuffers[0][y1];
+ }
+ if (gScanlineEffectRegBuffers[0][y2] <= 15)
+ {
+ nextFunc = TRUE;
+ ++gScanlineEffectRegBuffers[0][y2];
+ }
+ }
+ }
+ if (task->tHalfBandwidth == 80 && !nextFunc)
+ ++task->tState;
+ ++sTransitionStructPtr->vblankDma;
+ return FALSE;
+}
+
+static bool8 BT_Phase2Mugshot_StartBlackFade(struct Task *task)
+{
+ sTransitionStructPtr->vblankDma = FALSE;
+ BlendPalettes(0xFFFFFFFF, 0x10, RGB_WHITE);
+ sTransitionStructPtr->bldCnt = BLDCNT_TGT1_BG0 | BLDCNT_TGT1_BG1 | BLDCNT_TGT1_BG2 | BLDCNT_TGT1_BG3 | BLDCNT_TGT1_OBJ | BLDCNT_TGT1_BD | BLDCNT_EFFECT_DARKEN;
+ task->tCounter = 0;
+ ++task->tState;
+ return TRUE;
+}
+
+static bool8 BT_Phase2Mugshot_WaitForBlackFade(struct Task *task)
+{
+ sTransitionStructPtr->vblankDma = FALSE;
+ ++task->tCounter;
+ memset(gScanlineEffectRegBuffers[0], task->tCounter, 320);
+ if (task->tCounter > 15)
+ ++task->tState;
+ ++sTransitionStructPtr->vblankDma;
+ return FALSE;
+}
+
+static bool8 BT_Phase2Mugshot_End(struct Task *task)
+{
+ DmaStop(0);
+ BT_BlendPalettesToBlack();
+ DestroyTask(FindTaskIdByFunc(task->func));
+ return FALSE;
+}
+
+static void VBCB_BT_Phase2Mugshot1_Slide(void)
+{
+ DmaStop(0);
+ BT_VBSyncOamAndPltt();
+ if (sTransitionStructPtr->vblankDma)
+ DmaCopy16(3, gScanlineEffectRegBuffers[0], gScanlineEffectRegBuffers[1], 320);
+ SetGpuReg(REG_OFFSET_BG0VOFS, sTransitionStructPtr->bg0VOfs);
+ SetGpuReg(REG_OFFSET_WININ, sTransitionStructPtr->winIn);
+ SetGpuReg(REG_OFFSET_WINOUT, sTransitionStructPtr->winOut);
+ SetGpuReg(REG_OFFSET_WIN0V, sTransitionStructPtr->win0V);
+ DmaSet(0, gScanlineEffectRegBuffers[1], &REG_WIN0H, ((DMA_ENABLE | DMA_START_HBLANK | DMA_REPEAT | DMA_SRC_INC | DMA_DEST_FIXED) << 16) | 1);
+}
+
+static void VBCB_BT_Phase2Mugshot2_WhiteFade(void)
+{
+ DmaStop(0);
+ BT_VBSyncOamAndPltt();
+ if (sTransitionStructPtr->vblankDma)
+ DmaCopy16(3, gScanlineEffectRegBuffers[0], gScanlineEffectRegBuffers[1], 320);
+ SetGpuReg(REG_OFFSET_BLDCNT, sTransitionStructPtr->bldCnt);
+ DmaSet(0, gScanlineEffectRegBuffers[1], &REG_BLDY, ((DMA_ENABLE | DMA_START_HBLANK | DMA_REPEAT | DMA_SRC_INC | DMA_DEST_FIXED) << 16) | 1);
+}
+
+static void HBCB_BT_Phase2Mugshot(void)
+{
+ if (REG_VCOUNT < 80)
+ REG_BG0HOFS = sTransitionStructPtr->bg0HOfsOpponent;
+ else
+ REG_BG0HOFS = sTransitionStructPtr->bg0HOfsPlayer;
+}
+
+
+static void BT_Phase2Mugshots_CreateSprites(struct Task *task)
+{
+ struct Sprite *opponentSprite, *playerSprite;
+ s16 mugshotId;
+
+ gReservedSpritePaletteCount = 10;
+ mugshotId = task->tWhichMugshot;
+ task->tOpponentSpriteId = CreateTrainerSprite(sMugshotsTrainerPicIDsTable[mugshotId], sMugshotsOpponentCoords[mugshotId][0] - 32, sMugshotsOpponentCoords[mugshotId][1] + 42, 0, gDecompressionBuffer);
+ task->tPlayerSpriteId = CreateTrainerSprite(PlayerGenderToFrontTrainerPicId_Debug(gSaveBlock2Ptr->playerGender, TRUE), 272, 106, 0, gDecompressionBuffer);
+ gReservedSpritePaletteCount = 12;
+ opponentSprite = &gSprites[task->tOpponentSpriteId];
+ playerSprite = &gSprites[task->tPlayerSpriteId];
+ opponentSprite->callback = SpriteCB_BT_Phase2Mugshots;
+ playerSprite->callback = SpriteCB_BT_Phase2Mugshots;
+ opponentSprite->oam.affineMode = 3;
+ playerSprite->oam.affineMode = 3;
+ opponentSprite->oam.matrixNum = AllocOamMatrix();
+ playerSprite->oam.matrixNum = AllocOamMatrix();
+ opponentSprite->oam.shape = 1;
+ playerSprite->oam.shape = 1;
+ opponentSprite->oam.size = 3;
+ playerSprite->oam.size = 3;
+ CalcCenterToCornerVec(opponentSprite, 1, 3, 3);
+ CalcCenterToCornerVec(playerSprite, 1, 3, 3);
+ SetOamMatrixRotationScaling(opponentSprite->oam.matrixNum, sMugshotsOpponentRotationScales[mugshotId][0], sMugshotsOpponentRotationScales[mugshotId][1], 0);
+ SetOamMatrixRotationScaling(playerSprite->oam.matrixNum, -512, 512, 0);
+}
+
+static void SpriteCB_BT_Phase2Mugshots(struct Sprite *sprite)
+{
+ while (sBT_Phase2MugshotSpriteFuncs[sprite->spState](sprite));
+}
+
+static bool8 BT_Phase2MugshotsSpriteFuncs_Wait(struct Sprite *sprite)
+{
+ return FALSE;
+}
+
+static bool8 BT_Phase2MugshotsSpriteFuncs_InitParams(struct Sprite *sprite)
+{
+ s16 arr0[2];
+ s16 arr1[2];
+
+ memcpy(arr0, sMugShotSlideVelocity, sizeof(sMugShotSlideVelocity));
+ memcpy(arr1, sMugShotSlideDeceleration, sizeof(sMugShotSlideDeceleration));
+ ++sprite->spState;
+ sprite->spSpeed = arr0[sprite->spOpponentOrPlayer];
+ sprite->spAbsAcc = arr1[sprite->spOpponentOrPlayer];
+ return TRUE;
+}
+
+static bool8 BT_Phase2MugshotsSpriteFuncs_SlideSpriteIn(struct Sprite *sprite)
+{
+ sprite->pos1.x += sprite->spSpeed;
+ if (sprite->spOpponentOrPlayer && sprite->pos1.x < 133)
+ ++sprite->spState;
+ else if (!sprite->spOpponentOrPlayer && sprite->pos1.x > 103)
+ ++sprite->spState;
+ return FALSE;
+}
+
+static bool8 BT_Phase2MugshotsSpriteFuncs_DecelerateSprite(struct Sprite *sprite)
+{
+ sprite->spSpeed += sprite->spAbsAcc;
+ sprite->pos1.x += sprite->spSpeed;
+ if (sprite->spSpeed == 0)
+ {
+ ++sprite->spState;
+ sprite->spAbsAcc = -sprite->spAbsAcc;
+ sprite->sphasSlideFinished = 1;
+ }
+ return FALSE;
+}
+
+// not used
+static bool8 BT_Phase2MugshotsSpriteFuncs_DecelerateSprite2(struct Sprite *sprite)
+{
+ sprite->spSpeed += sprite->spAbsAcc;
+ sprite->pos1.x += sprite->spSpeed;
+ if (sprite->pos1.x < -31 || sprite->pos1.x > 271)
+ ++sprite->spState;
+ return FALSE;
+}
+
+static void BT_SetSpriteAsOpponentOrPlayer(s16 spriteId, bool16 value)
+{
+ gSprites[spriteId].spOpponentOrPlayer = value;
+}
+
+static void BT_StartSpriteSlide(s16 spriteId)
+{
+ ++gSprites[spriteId].spState;
+}
+
+static s16 BT_IsSpriteSlideFinished(s16 spriteId)
+{
+ return gSprites[spriteId].sphasSlideFinished;
+}
+
+#undef tTheta
+#undef tbg0HOfsOpponent
+#undef tbg0HOfsPlayer
+#undef tCounter
+#undef tHalfBandwidth
+#undef tOpponentSpriteId
+#undef tPlayerSpriteId
+#undef tWhichMugshot
+
+#undef spState
+#undef spSpeed
+#undef spAbsAcc
+#undef sphasSlideFinished
+#undef spOpponentOrPlayer
+
+#define tSpeed data[1]
+#define tAcc data[2]
+#define tJerk data[3]
+
+static void BT_Phase2SlicedScreen(u8 taskId)
+{
+ while (sBT_Phase2SlicedScreenFuncs[gTasks[taskId].tState](&gTasks[taskId]));
+}
+
+static bool8 BT_Phase2SlicedScreen_Init(struct Task *task)
+{
+ u16 i;
+
+ BT_InitCtrlBlk();
+ ScanlineEffect_Clear();
+ task->tAcc = 256;
+ task->tJerk = 1;
+ sTransitionStructPtr->winIn = 0x3F;
+ sTransitionStructPtr->winOut = 0;
+ sTransitionStructPtr->win0V = 160;
+ for (i = 0; i < 160; ++i)
+ {
+ gScanlineEffectRegBuffers[1][i] = sTransitionStructPtr->bg123HOfs;
+ gScanlineEffectRegBuffers[1][160 + i] = 0xF0;
+ }
+ EnableInterrupts(INTR_FLAG_HBLANK);
+ SetVBlankCallback(VBCB_BT_Phase2SlicedScreen);
+ SetHBlankCallback(HBCB_BT_Phase2SlicedScreen);
+ ++task->tState;
+ return TRUE;
+}
+
+static bool8 BT_Phase2SlicedScreen_UpdateOffsets(struct Task *task)
+{
+ u16 i;
+
+ sTransitionStructPtr->vblankDma = FALSE;
+ task->tSpeed += (task->tAcc >> 8);
+ if (task->tSpeed > 0xF0)
+ task->tSpeed = 0xF0;
+ if (task->tAcc <= 0xFFF)
+ task->tAcc += task->tJerk;
+ if (task->tJerk < 128)
+ task->tJerk <<= 1;
+ for (i = 0; i < 160; ++i)
+ {
+ u16 *ofsBuffer = &gScanlineEffectRegBuffers[0][i];
+ u16 *win0HBuffer = &gScanlineEffectRegBuffers[0][i + 160];
+ if (i & 1)
+ {
+ *ofsBuffer = sTransitionStructPtr->bg123HOfs + task->tSpeed;
+ *win0HBuffer = 0xF0 - task->tSpeed;
+ }
+ else
+ {
+ *ofsBuffer = sTransitionStructPtr->bg123HOfs - task->tSpeed;
+ *win0HBuffer = (task->tSpeed << 8) | 0xF1;
+ }
+ }
+ if (task->tSpeed > 0xEF)
+ ++task->tState;
+ ++sTransitionStructPtr->vblankDma;
+ return FALSE;
+}
+
+static bool8 BT_Phase2SlicedScreen_End(struct Task *task)
+{
+ DmaStop(0);
+ BT_BlendPalettesToBlack();
+ DestroyTask(FindTaskIdByFunc(BT_Phase2SlicedScreen));
+ return FALSE;
+}
+
+static void VBCB_BT_Phase2SlicedScreen(void)
+{
+ DmaStop(0);
+ BT_VBSyncOamAndPltt();
+ SetGpuReg(REG_OFFSET_WININ, sTransitionStructPtr->winIn);
+ SetGpuReg(REG_OFFSET_WINOUT, sTransitionStructPtr->winOut);
+ SetGpuReg(REG_OFFSET_WIN0V, sTransitionStructPtr->win0V);
+ if (sTransitionStructPtr->vblankDma)
+ DmaCopy16(3, gScanlineEffectRegBuffers[0], gScanlineEffectRegBuffers[1], 640);
+ DmaSet(0, &gScanlineEffectRegBuffers[1][160], &REG_WIN0H, ((DMA_ENABLE | DMA_START_HBLANK | DMA_REPEAT | DMA_16BIT | DMA_SRC_INC | DMA_DEST_FIXED) << 16) | 1);
+}
+
+static void HBCB_BT_Phase2SlicedScreen(void)
+{
+ s16 offset = gScanlineEffectRegBuffers[1][REG_VCOUNT];
+
+ REG_BG1HOFS = offset;
+ REG_BG2HOFS = offset;
+ REG_BG3HOFS = offset;
+}
+
+#undef tSpeed
+#undef tAcc
+#undef tJerk
+
+#define spBldyCounter data[0]
+#define spFinished data[1]
+#define spAltDelay data[2]
+#define spDelay data[5]
+#define spLastSprite data[6]
+
+static void BT_Phase2WhiteFadeInStripes(u8 taskId)
+{
+ while (sBT_Phase2WhiteFadeInStripesFuncs[gTasks[taskId].tState](&gTasks[taskId]));
+}
+
+static bool8 BT_Phase2WhiteFadeInStripes_Init(struct Task *task)
+{
+ u16 i;
+
+ BT_InitCtrlBlk();
+ ScanlineEffect_Clear();
+ sTransitionStructPtr->bldCnt = BLDCNT_TGT1_BG0 | BLDCNT_TGT1_BG1 | BLDCNT_TGT1_BG2 | BLDCNT_TGT1_BG3 | BLDCNT_TGT1_OBJ | BLDCNT_TGT1_BD | BLDCNT_EFFECT_LIGHTEN;
+ sTransitionStructPtr->bldY = 0;
+ sTransitionStructPtr->winIn = 0x1E;
+ sTransitionStructPtr->winOut = 0x3F;
+ sTransitionStructPtr->win0V = 160;
+ for (i = 0; i < 160; ++i)
+ {
+ gScanlineEffectRegBuffers[1][i] = 0;
+ gScanlineEffectRegBuffers[1][i + 160] = 0xF0;
+ }
+ EnableInterrupts(INTR_FLAG_HBLANK);
+ SetHBlankCallback(HBCB_BT_Phase2WhiteFadeInStripes);
+ SetVBlankCallback(VBCB_BT_Phase2WhiteFadeInStripes1);
+ ++task->tState;
+ return FALSE;
+}
+
+static bool8 BT_Phase2WhiteFadeInStripes_SetupSprites(struct Task *task)
+{
+ s16 i, posY;
+ s16 buffer[NELEMS(sWhiteStripeDelay)];
+ struct Sprite *sprite;
+
+ memcpy(buffer, sWhiteStripeDelay, sizeof(sWhiteStripeDelay));
+ for (i = 0, posY = 0; i < 6; ++i, posY += 0x1B)
+ {
+ sprite = &gSprites[CreateInvisibleSprite(SpriteCB_BT_Phase2WhiteFadeInStripes)];
+ sprite->pos1.x = 0xF0;
+ sprite->pos1.y = posY;
+ sprite->spDelay = buffer[i];
+ }
+ ++sprite->spLastSprite;
+ ++task->tState;
+ return FALSE;
+}
+
+static bool8 BT_Phase2WhiteFadeInStripes_IsWhiteFadeDone(struct Task *task)
+{
+ sTransitionStructPtr->vblankDma = FALSE;
+ if (sTransitionStructPtr->counter > 5)
+ {
+ BlendPalettes(0xFFFFFFFF, 0x10, RGB_WHITE);
+ ++task->tState;
+ }
+ return FALSE;
+}
+
+static bool8 BT_Phase2WhiteFadeInStripes_Stop(struct Task *task)
+{
+ sTransitionStructPtr->vblankDma = FALSE;
+ DmaStop(0);
+ SetVBlankCallback(NULL);
+ SetHBlankCallback(NULL);
+ sTransitionStructPtr->win0H = 240;
+ sTransitionStructPtr->bldY = 0;
+ sTransitionStructPtr->bldCnt = BLDCNT_TGT1_BG0 | BLDCNT_TGT1_BG1 | BLDCNT_TGT1_BG2 | BLDCNT_TGT1_BG3 | BLDCNT_TGT1_OBJ | BLDCNT_TGT1_BD | BLDCNT_EFFECT_DARKEN;
+ sTransitionStructPtr->winIn = 0x3F;
+ sTransitionStructPtr->counter = 0;
+ SetVBlankCallback(VBCB_BT_Phase2WhiteFadeInStripes2);
+ ++task->tState;
+ return FALSE;
+}
+
+static bool8 BT_Phase2WhiteFadeInStripes_IsDone(struct Task *task)
+{
+ sTransitionStructPtr->counter += 480;
+ sTransitionStructPtr->bldY = sTransitionStructPtr->counter >> 8;
+ if (sTransitionStructPtr->bldY > 16)
+ {
+ BT_BlendPalettesToBlack();
+ DestroyTask(FindTaskIdByFunc(BT_Phase2WhiteFadeInStripes));
+ }
+ return FALSE;
+}
+
+static void VBCB_BT_Phase2WhiteFadeInStripes1(void)
+{
+ DmaStop(0);
+ BT_VBSyncOamAndPltt();
+ SetGpuReg(REG_OFFSET_BLDCNT, sTransitionStructPtr->bldCnt);
+ SetGpuReg(REG_OFFSET_WININ, sTransitionStructPtr->winIn);
+ SetGpuReg(REG_OFFSET_WINOUT, sTransitionStructPtr->winOut);
+ SetGpuReg(REG_OFFSET_WIN0V, sTransitionStructPtr->win0H); // BUG: This should obviously be sTransitionStructPtr->win0V
+ if (sTransitionStructPtr->vblankDma)
+ DmaCopy16(3, gScanlineEffectRegBuffers[0], gScanlineEffectRegBuffers[1], 640);
+ DmaSet(0, &gScanlineEffectRegBuffers[1][160], &REG_WIN0H, ((DMA_ENABLE | DMA_START_HBLANK | DMA_REPEAT | DMA_16BIT | DMA_SRC_INC | DMA_DEST_FIXED) << 16) | 1);
+}
+
+static void VBCB_BT_Phase2WhiteFadeInStripes2(void)
+{
+ BT_VBSyncOamAndPltt();
+ SetGpuReg(REG_OFFSET_BLDY, sTransitionStructPtr->bldY);
+ SetGpuReg(REG_OFFSET_BLDCNT, sTransitionStructPtr->bldCnt);
+ SetGpuReg(REG_OFFSET_WININ, sTransitionStructPtr->winIn);
+ SetGpuReg(REG_OFFSET_WINOUT, sTransitionStructPtr->winOut);
+ SetGpuReg(REG_OFFSET_WIN0H, sTransitionStructPtr->win0H);
+ SetGpuReg(REG_OFFSET_WIN0V, sTransitionStructPtr->win0V);
+}
+
+
+static void HBCB_BT_Phase2WhiteFadeInStripes(void)
+{
+ vu16 index = REG_VCOUNT;
+
+ if (index == 227)
+ index = 0;
+ REG_BLDY = gScanlineEffectRegBuffers[1][index];
+}
+
+static void SpriteCB_BT_Phase2WhiteFadeInStripes(struct Sprite *sprite)
+{
+ if (sprite->spDelay)
+ {
+ --sprite->spDelay;
+ if (sprite->spLastSprite)
+ sTransitionStructPtr->vblankDma = TRUE;
+ }
+ else
+ {
+ u16 i;
+ u16 *bldY = &gScanlineEffectRegBuffers[0][sprite->pos1.y];
+ u16 *win0H = &gScanlineEffectRegBuffers[0][sprite->pos1.y + 160];
+ u32 stripeWidth = sprite->spLastSprite ? 0x19 : 0x1B;
+
+ for (i = 0; i < stripeWidth; ++i)
+ {
+ bldY[i] = sprite->spBldyCounter >> 8;
+ win0H[i] = (u8)(sprite->pos1.x);
+ }
+ if (sprite->pos1.x == 0 && sprite->spBldyCounter == 0x1000)
+ sprite->spFinished = 1;
+ sprite->pos1.x -= 24;
+ sprite->spBldyCounter += 192;
+ if (sprite->pos1.x < 0)
+ sprite->pos1.x = 0;
+ if (sprite->spBldyCounter > 0x1000)
+ sprite->spBldyCounter = 0x1000;
+ if (sprite->spLastSprite)
+ sTransitionStructPtr->vblankDma = TRUE;
+ if (sprite->spFinished)
+ {
+ if (sprite->spLastSprite == FALSE || (sTransitionStructPtr->counter > 4))
+ {
+ ++sTransitionStructPtr->counter;
+ DestroySprite(sprite);
+ }
+ }
+ }
+}
+
+#undef spBldyCounter
+#undef spFinished
+#undef spAltDelay
+#undef spDelay
+#undef spLastSprite
+
+#define tDelay data[1]
+#define tWhichGrid data[2]
+
+static void BT_Phase2GridSquares(u8 taskId)
+{
+ while (sBT_Phase2GridSquaresFuncs[gTasks[taskId].tState](&gTasks[taskId]));
+}
+
+static bool8 BT_Phase2GridSquares_LoadGfx(struct Task *task)
+{
+ u16 *tilemapAddr, *tilesetAddr;
+
+ BT_GetBg0TilemapAndTilesetBase(&tilemapAddr, &tilesetAddr);
+ CpuSet(sGridSquareTileset, tilesetAddr, 0x10);
+ CpuFill16(0xF000, tilemapAddr, 0x800);
+ LoadPalette(sSlidingPokeballBigPokeballPalette, 0xF0, 0x20);
+ ++task->tState;
+ return FALSE;
+}
+
+static bool8 BT_Phase2GridSquares_UpdateTileset(struct Task *task)
+{
+ u16 *tilesetAddr;
+
+ if (task->tDelay == 0)
+ {
+ BT_GetBg0TilesetBase(&tilesetAddr);
+ task->tDelay = 3;
+ ++task->tWhichGrid;
+ CpuSet(sGridSquareTileset + (task->tWhichGrid * 8), tilesetAddr, 0x10);
+ if (task->tWhichGrid > 0xD)
+ {
+ ++task->tState;
+ task->tDelay = 16;
+ }
+ }
+ --task->tDelay;
+ return FALSE;
+}
+
+static bool8 BT_Phase2GridSquares_IsDone(struct Task *task)
+{
+ if (--task->tDelay == 0)
+ {
+ BT_BlendPalettesToBlack();
+ DestroyTask(FindTaskIdByFunc(BT_Phase2GridSquares));
+ }
+ return FALSE;
+}
+
+#undef tDelay
+#undef tWhichGrid
+
+#define tWhichBrush data[1]
+#define tWhichSide data[2]
+#define tDelay data[3]
+
+#define trCurrentPtX data[2]
+#define trCurrentPtY data[3]
+
+static void BT_Phase2BlackDoodles(u8 taskId)
+{
+ while (sBT_Phase2BlackDoodlesFuncs[gTasks[taskId].tState](&gTasks[taskId]));
+}
+
+static bool8 BT_Phase2BlackDoodles_Init(struct Task *task)
+{
+ u16 i;
+
+ BT_InitCtrlBlk();
+ ScanlineEffect_Clear();
+ sTransitionStructPtr->winIn = 0x3F;
+ sTransitionStructPtr->winOut = 0;
+ sTransitionStructPtr->win0V = 0xA0;
+ for (i = 0; i < 160; ++i)
+ gScanlineEffectRegBuffers[0][i] = 0x00F0;
+ CpuSet(gScanlineEffectRegBuffers[0], gScanlineEffectRegBuffers[1], 160);
+ SetVBlankCallback(VBCB_BT_Phase2BlackDoodles);
+ ++task->tState;
+ return TRUE;
+}
+
+static bool8 BT_Phase2BlackDoodles_InitSingleBrush(struct Task *task)
+{
+ BT_DiagonalSegment_InitParams(sTransitionStructPtr->data, sBlackDoodlesSegments[task->tWhichBrush][0], sBlackDoodlesSegments[task->tWhichBrush][1], sBlackDoodlesSegments[task->tWhichBrush][2], sBlackDoodlesSegments[task->tWhichBrush][3], 1, 1);
+ task->tWhichSide = sBlackDoodlesSegments[task->tWhichBrush][4];
+ ++task->tState;
+ return TRUE;
+}
+
+static bool8 BT_Phase2BlackDoodles_DrawSingleBrush(struct Task *task)
+{
+ s16 i;
+ bool8 nextFunc;
+
+ sTransitionStructPtr->vblankDma = FALSE;
+ for (i = 0, nextFunc = FALSE; i < 16; ++i)
+ {
+ s16 left = gScanlineEffectRegBuffers[0][sTransitionStructPtr->trCurrentPtY] >> 8;
+ s16 right = gScanlineEffectRegBuffers[0][sTransitionStructPtr->trCurrentPtY] & 0xFF;
+ if (task->tWhichSide == 0)
+ {
+ if (left < sTransitionStructPtr->trCurrentPtX)
+ left = sTransitionStructPtr->trCurrentPtX;
+ if (left > right)
+ left = right;
+ }
+ else
+ {
+ if (right > sTransitionStructPtr->trCurrentPtX)
+ right = sTransitionStructPtr->trCurrentPtX;
+ if (right <= left)
+ right = left;
+ }
+ gScanlineEffectRegBuffers[0][sTransitionStructPtr->trCurrentPtY] = right | (left << 8);
+ if (nextFunc)
+ {
+ ++task->tState;
+ break;
+ }
+ else
+ nextFunc = BT_DiagonalSegment_ComputePointOnSegment(sTransitionStructPtr->data, TRUE, TRUE);
+ }
+ ++sTransitionStructPtr->vblankDma;
+ return FALSE;
+}
+
+static bool8 BT_Phase2BlackDoodles_IsDone(struct Task *task)
+{
+ if (++task->tWhichBrush < 7)
+ {
+ ++task->tState;
+ task->tDelay = sBlackDoodlesDelay[task->tWhichBrush - 1];
+ return TRUE;
+ }
+ else
+ {
+ DmaStop(0);
+ BT_BlendPalettesToBlack();
+ DestroyTask(FindTaskIdByFunc(BT_Phase2BlackDoodles));
+ return FALSE;
+ }
+}
+
+static bool8 BT_Phase2BlackDoodles_NextBrush(struct Task *task)
+{
+ if (--task->tDelay == 0)
+ {
+ task->tState = 1;
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+static void VBCB_BT_Phase2BlackDoodles(void)
+{
+ DmaStop(0);
+ BT_VBSyncOamAndPltt();
+ if (sTransitionStructPtr->vblankDma)
+ DmaCopy16(3, gScanlineEffectRegBuffers[0], gScanlineEffectRegBuffers[1], 320);
+ SetGpuReg(REG_OFFSET_WININ, sTransitionStructPtr->winIn);
+ SetGpuReg(REG_OFFSET_WINOUT, sTransitionStructPtr->winOut);
+ SetGpuReg(REG_OFFSET_WIN0V, sTransitionStructPtr->win0V);
+ SetGpuReg(REG_OFFSET_WIN0H, gScanlineEffectRegBuffers[1][0]);
+ DmaSet(0, gScanlineEffectRegBuffers[1], &REG_WIN0H, ((DMA_ENABLE | DMA_START_HBLANK | DMA_REPEAT | DMA_16BIT | DMA_SRC_INC | DMA_DEST_FIXED) << 16) | 1);
+}
+
+#undef tWhichBrush
+#undef tWhichSide
+#undef tDelay
+
+#undef trCurrentPtX
+#undef trCurrentPtY
+
+#define tFadeOutDelay data[1]
+#define tFadeInDelay data[2]
+#define tBlinkTimes data[3]
+#define tFadeOutSpeed data[4]
+#define tFadeInSpeed data[5]
+#define tDelayCounter data[6]
+#define tCoeff data[7]
+
+static void BT_CreatePhase1SubTask(s16 fadeOutDelay, s16 fadeInDelay, s16 blinkTimes, s16 fadeOutSpeed, s16 fadeInSpeed)
+{
+ u8 taskId = CreateTask(BT_Phase1SubTask, 3);
+ gTasks[taskId].tFadeOutDelay = fadeOutDelay;
+ gTasks[taskId].tFadeInDelay = fadeInDelay;
+ gTasks[taskId].tBlinkTimes = blinkTimes;
+ gTasks[taskId].tFadeOutSpeed = fadeOutSpeed;
+ gTasks[taskId].tFadeInSpeed = fadeInSpeed;
+ gTasks[taskId].tDelayCounter = fadeOutDelay;
+}
+
+static bool8 BT_IsPhase1Done(void)
+{
+ if (FindTaskIdByFunc(BT_Phase1SubTask) == TASK_NONE)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static void BT_Phase1SubTask(u8 taskId)
+{
+ while (sBT_Phase1FadeFuncs[gTasks[taskId].tState](&gTasks[taskId]));
+}
+
+static bool8 BT_Phase1_FadeOut(struct Task *task)
+{
+ if (task->tDelayCounter == 0 || --task->tDelayCounter == 0)
+ {
+ task->tDelayCounter = task->tFadeOutDelay;
+ task->tCoeff += task->tFadeOutSpeed;
+ if (task->tCoeff > 16)
+ task->tCoeff = 16;
+ BlendPalettes(-1, task->tCoeff, RGB(11, 11, 11));
+ }
+ if (task->tCoeff > 15)
+ {
+ ++task->tState;
+ task->tDelayCounter = task->tFadeInDelay;
+ }
+ return FALSE;
+}
+
+static bool8 BT_Phase1_FadeIn(struct Task *task)
+{
+ if (task->tDelayCounter == 0 || --task->tDelayCounter == 0)
+ {
+ task->tDelayCounter = task->tFadeInDelay;
+ task->tCoeff -= task->tFadeInSpeed;
+ if (task->tCoeff < 0)
+ task->tCoeff = 0;
+ BlendPalettes(0xFFFFFFFF, task->tCoeff, RGB(11, 11, 11));
+ }
+ if (task->tCoeff == 0)
+ {
+ if (--task->tBlinkTimes == 0)
+ {
+ DestroyTask(FindTaskIdByFunc(BT_Phase1SubTask));
+ }
+ else
+ {
+ task->tDelayCounter = task->tFadeOutDelay;
+ task->tState = 0;
+ }
+ }
+ return FALSE;
+}
+
+#undef tFadeOutDelay
+#undef tFadeInDelay
+#undef tBlinkTimes
+#undef tFadeOutSpeed
+#undef tFadeInSpeed
+#undef tDelayCounter
+#undef tCoeff
+
+static void BT_InitCtrlBlk(void)
+{
+ memset(sTransitionStructPtr, 0, sizeof(*sTransitionStructPtr));
+ sub_805A658(&sTransitionStructPtr->bg123HOfs, &sTransitionStructPtr->bg123VOfs);
+}
+
+static void BT_VBSyncOamAndPltt(void)
+{
+ LoadOam();
+ ProcessSpriteCopyRequests();
+ TransferPlttBuffer();
+}
+
+static void BT_GetBg0TilesetBase(u16 **tilesetPtr)
+{
+ u16 charBase;
+
+ charBase = GetGpuReg(REG_OFFSET_BG0CNT) >> 2;
+ charBase <<= 0xE;
+ *tilesetPtr = (u16 *)(VRAM + charBase);
+}
+
+static void BT_GetBg0TilemapAndTilesetBase(u16 **tilemapPtr, u16 **tilesetPtr)
+{
+ u16 screenBase, charBase;
+
+ screenBase = (GetGpuReg(REG_OFFSET_BG0CNT) >> 8) & 0x1F;
+ charBase = GetGpuReg(REG_OFFSET_BG0CNT) >> 2;
+ screenBase <<= 0xB;
+ charBase <<= 0xE;
+ *tilemapPtr = (u16 *)(VRAM + screenBase);
+ *tilesetPtr = (u16 *)(VRAM + charBase);
+}
+
+static void BT_BlendPalettesToBlack(void)
+{
+ BlendPalettes(0xFFFFFFFF, 0x10, RGB_BLACK);
+}
+
+static void BT_LoadWaveIntoBuffer(s16 *buffer, s16 offset, s16 theta, s16 frequency, s16 amplitude, s16 bufSize)
+{
+ u8 i;
+
+ for (i = 0; bufSize > 0; --bufSize, ++i, theta += frequency)
+ buffer[i] = offset + Sin(0xFF & theta, amplitude);
+}
+
+static void BT_GenerateCircle(s16 *buffer, s16 x, s16 y, s16 radius)
+{
+ s16 i;
+
+ memset(buffer, 0xA, 320);
+ // 64 iterations because we only want to cover [0, π/2) discretely.
+ for (i = 0; i < 64; ++i)
+ {
+ s16 sinResult, cosResult, leftX, topY, bottomY, nextTopY, nextBottomY, winVal;
+
+ // The loop variable i here does not stand for rotation angle,
+ // but is the angle between segment (center, pointOnCircle)
+ // and vertical line.
+ sinResult = Sin(i, radius);
+ cosResult = Cos(i, radius);
+ leftX = x - sinResult;
+ winVal = x + sinResult;
+ topY = y - cosResult;
+ bottomY = y + cosResult;
+ if (leftX < 0)
+ leftX = 0;
+ if (winVal > 240)
+ winVal = 240;
+ if (topY < 0)
+ topY = 0;
+ if (bottomY > 159)
+ bottomY = 159;
+ winVal |= (leftX << 8);
+ buffer[topY] = winVal;
+ buffer[bottomY] = winVal;
+ cosResult = Cos(i + 1, radius);
+ nextTopY = y - cosResult;
+ nextBottomY = y + cosResult;
+ if (nextTopY < 0)
+ nextTopY = 0;
+ if (nextBottomY > 159)
+ nextBottomY = 159;
+ // fill everything in between with the same WIN0H value
+ while (topY > nextTopY)
+ buffer[--topY] = winVal;
+ while (topY < nextTopY)
+ buffer[++topY] = winVal;
+ while (bottomY > nextBottomY)
+ buffer[--bottomY] = winVal;
+ while (bottomY < nextBottomY)
+ buffer[++bottomY] = winVal;
+ }
+}
+
+#define trStartPtX data[0]
+#define trStartPtY data[1]
+#define trCurrentPtX data[2]
+#define trCurrentPtY data[3]
+#define trEndPtX data[4]
+#define trEndPtY data[5]
+#define trStepX data[6]
+#define trStepY data[7]
+#define trAbsDeltaX data[8]
+#define trAbsDeltaY data[9]
+#define trAccum data[10] // track one dimension based on slope
+
+static void BT_DiagonalSegment_InitParams(s16 *data, s16 startPtX, s16 startPtY, s16 endPtX, s16 endPtY, s16 stepX, s16 stepY)
+{
+ trStartPtX = startPtX;
+ trStartPtY = startPtY;
+ trCurrentPtX = startPtX;
+ trCurrentPtY = startPtY;
+ trEndPtX = endPtX;
+ trEndPtY = endPtY;
+ trStepX = stepX;
+ trStepY = stepY;
+ trAbsDeltaX = endPtX - startPtX;
+ if (trAbsDeltaX < 0)
+ {
+ trAbsDeltaX = -trAbsDeltaX;
+ trStepX = -stepX;
+ }
+ trAbsDeltaY = endPtY - startPtY;
+ if (trAbsDeltaY < 0)
+ {
+ trAbsDeltaY = -trAbsDeltaY;
+ trStepY = -stepY;
+ }
+ trAccum = 0;
+}
+
+static bool8 BT_DiagonalSegment_ComputePointOnSegment(s16 *data, bool8 checkBoundary1, bool8 checkBoundary2)
+{
+ u8 finish;
+
+ if (trAbsDeltaX > trAbsDeltaY)
+ {
+ trCurrentPtX += trStepX;
+ trAccum += trAbsDeltaY;
+ if (trAccum > trAbsDeltaX)
+ {
+ trCurrentPtY += trStepY;
+ trAccum -= trAbsDeltaX;
+ }
+ }
+ else
+ {
+ trCurrentPtY += trStepY;
+ trAccum += trAbsDeltaX;
+ if (trAccum > trAbsDeltaY)
+ {
+ trCurrentPtX += trStepX;
+ trAccum -= trAbsDeltaY;
+ }
+ }
+ finish = 0;
+ if ((trStepX > 0 && trCurrentPtX >= trEndPtX) || (trStepX < 0 && trCurrentPtX <= trEndPtX))
+ {
+ ++finish;
+ if (checkBoundary1)
+ trCurrentPtX = trEndPtX;
+ }
+ if ((trStepY > 0 && trCurrentPtY >= trEndPtY) || (trStepY < 0 && trCurrentPtY <= trEndPtY))
+ {
+ ++finish;
+ if (checkBoundary2)
+ trCurrentPtY = trEndPtY;
+ }
+ if (finish == 2)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+#undef trStartPtX
+#undef trStartPtY
+#undef trCurrentPtX
+#undef trCurrentPtY
+#undef trEndPtX
+#undef trEndPtY
+#undef trStepX
+#undef trStepY
+#undef trAbsDeltaX
+#undef trAbsDeltaY
+#undef trAccum