diff options
Diffstat (limited to 'src/battle_transition.c')
-rw-r--r-- | src/battle_transition.c | 3728 |
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], ®_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], ®_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], ®_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], ®_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], ®_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], ®_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], ®_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], ®_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], ®_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], ®_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 |