#include "global.h" #include "battle.h" #include "battle_anim.h" #include "gpu_regs.h" #include "palette.h" #include "constants/rgb.h" #include "scanline_effect.h" #include "constants/songs.h" #include "sound.h" #include "trig.h" #include "util.h" static void AnimConfuseRayBallBounce(struct Sprite *); static void AnimConfuseRayBallBounce_Step1(struct Sprite *); static void AnimConfuseRayBallBounce_Step2(struct Sprite *); static void UpdateConfuseRayBallBlend(struct Sprite *); static void AnimConfuseRayBallSpiral(struct Sprite *); static void AnimConfuseRayBallSpiral_Step(struct Sprite *); static void AnimTask_NightShadeClone_Step1(u8 taskId); static void AnimTask_NightShadeClone_Step2(u8 taskId); static void AnimShadowBall(struct Sprite *); static void AnimShadowBall_Step(struct Sprite *); static void AnimLick(struct Sprite *); static void AnimLick_Step(struct Sprite *); static void AnimTask_NightmareClone_Step(u8 taskId); static void AnimTask_SpiteTargetShadow_Step1(u8 taskId); static void AnimTask_SpiteTargetShadow_Step2(u8 taskId); static void AnimTask_SpiteTargetShadow_Step3(u8 taskId); static void AnimDestinyBondWhiteShadow(struct Sprite *); static void AnimDestinyBondWhiteShadow_Step(struct Sprite *); static void AnimTask_DestinyBondWhiteShadow_Step(u8 taskId); static void AnimTask_CurseStretchingBlackBg_Step1(u8 taskId); static void AnimTask_CurseStretchingBlackBg_Step2(u8 taskId); static void AnimCurseNail(struct Sprite *); static void AnimCurseNail_Step1(struct Sprite *); static void AnimCurseNail_Step2(struct Sprite *); static void AnimCurseNail_End(struct Sprite *); static void AnimGhostStatusSprite(struct Sprite *); static void AnimGhostStatusSprite_Step(struct Sprite *); static void AnimTask_GrudgeFlames_Step(u8 taskId); static void AnimGrudgeFlame(struct Sprite *); static void AnimMonMoveCircular(struct Sprite *); static void AnimMonMoveCircular_Step(struct Sprite *); static const union AffineAnimCmd sAffineAnim_ConfuseRayBallBounce[] = { AFFINEANIMCMD_FRAME(0x1E, 0x1E, 10, 5), AFFINEANIMCMD_FRAME(0xFFE2, 0xFFE2, 10, 5), AFFINEANIMCMD_JUMP(0), }; static const union AffineAnimCmd *const sAffineAnims_ConfuseRayBallBounce[] = { sAffineAnim_ConfuseRayBallBounce, }; const struct SpriteTemplate gConfuseRayBallBounceSpriteTemplate = { .tileTag = ANIM_TAG_YELLOW_BALL, .paletteTag = ANIM_TAG_YELLOW_BALL, .oam = &gOamData_AffineDouble_ObjNormal_16x16, .anims = gDummySpriteAnimTable, .images = NULL, .affineAnims = sAffineAnims_ConfuseRayBallBounce, .callback = AnimConfuseRayBallBounce, }; const struct SpriteTemplate gConfuseRayBallSpiralSpriteTemplate = { .tileTag = ANIM_TAG_YELLOW_BALL, .paletteTag = ANIM_TAG_YELLOW_BALL, .oam = &gOamData_AffineOff_ObjBlend_16x16, .anims = gDummySpriteAnimTable, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = AnimConfuseRayBallSpiral, }; static const union AffineAnimCmd sAffineAnim_ShadowBall[] = { AFFINEANIMCMD_FRAME(0x0, 0x0, 10, 1), AFFINEANIMCMD_JUMP(0), }; static const union AffineAnimCmd *const sAffineAnims_ShadowBall[] = { sAffineAnim_ShadowBall, }; const struct SpriteTemplate gShadowBallSpriteTemplate = { .tileTag = ANIM_TAG_SHADOW_BALL, .paletteTag = ANIM_TAG_SHADOW_BALL, .oam = &gOamData_AffineNormal_ObjNormal_32x32, .anims = gDummySpriteAnimTable, .images = NULL, .affineAnims = sAffineAnims_ShadowBall, .callback = AnimShadowBall, }; static const union AnimCmd sAnim_Lick[] = { ANIMCMD_FRAME(0, 2), ANIMCMD_FRAME(8, 2), ANIMCMD_FRAME(16, 2), ANIMCMD_FRAME(24, 2), ANIMCMD_FRAME(32, 2), ANIMCMD_END, }; static const union AnimCmd *const sAnims_Lick[] = { sAnim_Lick, }; const struct SpriteTemplate gLickSpriteTemplate = { .tileTag = ANIM_TAG_LICK, .paletteTag = ANIM_TAG_LICK, .oam = &gOamData_AffineOff_ObjNormal_16x32, .anims = sAnims_Lick, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = AnimLick, }; static const union AffineAnimCmd sAffineAnim_Unused[] = { AFFINEANIMCMD_FRAME(0x200, 0x200, 0, 0), AFFINEANIMCMD_END, }; // Unused static const union AffineAnimCmd *const sAffineAnims_Unused[] = { sAffineAnim_Unused, }; const struct SpriteTemplate gDestinyBondWhiteShadowSpriteTemplate = { .tileTag = ANIM_TAG_WHITE_SHADOW, .paletteTag = ANIM_TAG_WHITE_SHADOW, .oam = &gOamData_AffineOff_ObjBlend_64x32, .anims = gDummySpriteAnimTable, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = AnimDestinyBondWhiteShadow, }; const struct SpriteTemplate gCurseNailSpriteTemplate = { .tileTag = ANIM_TAG_NAIL, .paletteTag = ANIM_TAG_NAIL, .oam = &gOamData_AffineOff_ObjBlend_32x16, .anims = gDummySpriteAnimTable, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = AnimCurseNail, }; const struct SpriteTemplate gCurseGhostSpriteTemplate = { .tileTag = ANIM_TAG_GHOSTLY_SPIRIT, .paletteTag = ANIM_TAG_GHOSTLY_SPIRIT, .oam = &gOamData_AffineOff_ObjBlend_32x32, .anims = gDummySpriteAnimTable, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = AnimGhostStatusSprite, }; const struct SpriteTemplate gNightmareDevilSpriteTemplate = { .tileTag = ANIM_TAG_DEVIL, .paletteTag = ANIM_TAG_DEVIL, .oam = &gOamData_AffineOff_ObjBlend_32x32, .anims = gDummySpriteAnimTable, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = AnimGhostStatusSprite, }; static const union AnimCmd sAnim_GrudgeFlame[] = { ANIMCMD_FRAME(0, 4), ANIMCMD_FRAME(8, 4), ANIMCMD_FRAME(16, 4), ANIMCMD_FRAME(24, 4), ANIMCMD_JUMP(0), }; static const union AnimCmd *const sAnims_GrudgeFlame[] = { sAnim_GrudgeFlame, }; const struct SpriteTemplate gGrudgeFlameSpriteTemplate = { .tileTag = ANIM_TAG_PURPLE_FLAME, .paletteTag = ANIM_TAG_PURPLE_FLAME, .oam = &gOamData_AffineOff_ObjBlend_16x32, .anims = sAnims_GrudgeFlame, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = AnimGrudgeFlame, }; // Unused static const struct SpriteTemplate sMonMoveCircularSpriteTemplate = { .tileTag = 0, .paletteTag = 0, .oam = &gDummyOamData, .anims = gDummySpriteAnimTable, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = AnimMonMoveCircular, }; static void AnimConfuseRayBallBounce(struct Sprite *sprite) { InitSpritePosToAnimAttacker(sprite, TRUE); sprite->data[0] = gBattleAnimArgs[2]; sprite->data[1] = sprite->x; sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2); sprite->data[3] = sprite->y; sprite->data[4] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y_PIC_OFFSET); InitAnimLinearTranslationWithSpeed(sprite); sprite->callback = AnimConfuseRayBallBounce_Step1; sprite->data[6] = 16; SetGpuReg(REG_OFFSET_BLDCNT, (BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_ALL)); SetGpuReg(REG_OFFSET_BLDALPHA, sprite->data[6]); } static void AnimConfuseRayBallBounce_Step1(struct Sprite *sprite) { s16 r0; s16 r2; UpdateConfuseRayBallBlend(sprite); if (AnimTranslateLinear(sprite)) { sprite->callback = AnimConfuseRayBallBounce_Step2; return; } sprite->x2 += Sin(sprite->data[5], 10); sprite->y2 += Cos(sprite->data[5], 15); r2 = sprite->data[5]; sprite->data[5] = (sprite->data[5] + 5) & 0xFF; r0 = sprite->data[5]; if (r2 != 0 && r2 <= 196) return; if (r0 <= 0) return; PlaySE12WithPanning(SE_M_CONFUSE_RAY, gAnimCustomPanning); } static void AnimConfuseRayBallBounce_Step2(struct Sprite *sprite) { s16 r2; s16 r0; sprite->data[0] = 1; AnimTranslateLinear(sprite); sprite->x2 += Sin(sprite->data[5], 10); sprite->y2 += Cos(sprite->data[5], 15); r2 = sprite->data[5]; sprite->data[5] = (sprite->data[5] + 5) & 0xFF; r0 = sprite->data[5]; if (r2 == 0 || r2 > 196) { if (r0 > 0) PlaySE(SE_M_CONFUSE_RAY); } if (sprite->data[6] == 0) { sprite->invisible = TRUE; sprite->callback = DestroyAnimSpriteAndDisableBlend; } else UpdateConfuseRayBallBlend(sprite); } static void UpdateConfuseRayBallBlend(struct Sprite *sprite) { if (sprite->data[6] > 0xFF) { if (++sprite->data[6] == 0x10d) sprite->data[6] = 0; return; } if ((sprite->data[7]++ & 0xFF) == 0) { sprite->data[7] &= 0xff00; if ((sprite->data[7] & 0x100) != 0) sprite->data[6]++; else sprite->data[6]--; SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(sprite->data[6], 16 - sprite->data[6])); if (sprite->data[6] == 0 || sprite->data[6] == 16) sprite->data[7] ^= 0x100; if (sprite->data[6] == 0) sprite->data[6] = 0x100; } } static void AnimConfuseRayBallSpiral(struct Sprite *sprite) { InitSpritePosToAnimTarget(sprite, TRUE); sprite->callback = AnimConfuseRayBallSpiral_Step; sprite->callback(sprite); } static void AnimConfuseRayBallSpiral_Step(struct Sprite *sprite) { u16 temp1; sprite->x2 = Sin(sprite->data[0], 32); sprite->y2 = Cos(sprite->data[0], 8); temp1 = sprite->data[0] - 65; if (temp1 <= 130) sprite->oam.priority = 2; else sprite->oam.priority = 1; sprite->data[0] = (sprite->data[0] + 19) & 0xFF; sprite->data[2] += 80; sprite->y2 += sprite->data[2] >> 8; sprite->data[7] += 1; if (sprite->data[7] == 61) DestroyAnimSprite(sprite); } // Creates a large transparent clone of the attacker centered on their position which shrinks to original size void AnimTask_NightShadeClone(u8 taskId) { u8 spriteId; SetGpuReg(REG_OFFSET_BLDCNT, (BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_ALL)); SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(0, 0x10)); spriteId = GetAnimBattlerSpriteId(ANIM_ATTACKER); PrepareBattlerSpriteForRotScale(spriteId, ST_OAM_OBJ_BLEND); SetSpriteRotScale(spriteId, 128, 128, 0); gSprites[spriteId].invisible = FALSE; gTasks[taskId].data[0] = 128; gTasks[taskId].data[1] = *gBattleAnimArgs; gTasks[taskId].data[2] = 0; gTasks[taskId].data[3] = 16; gTasks[taskId].func = AnimTask_NightShadeClone_Step1; } static void AnimTask_NightShadeClone_Step1(u8 taskId) { gTasks[taskId].data[10] += 1; if (gTasks[taskId].data[10] == 3) { gTasks[taskId].data[10] = 0; gTasks[taskId].data[2] += 1; gTasks[taskId].data[3] -= 1; SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(gTasks[taskId].data[2], gTasks[taskId].data[3])); if (gTasks[taskId].data[2] != 9) return; gTasks[taskId].func = AnimTask_NightShadeClone_Step2; } } static void AnimTask_NightShadeClone_Step2(u8 taskId) { u8 spriteId; if (gTasks[taskId].data[1] > 0) { gTasks[taskId].data[1] -= 1; return; } spriteId = GetAnimBattlerSpriteId(ANIM_ATTACKER); gTasks[taskId].data[0] += 8; if (gTasks[taskId].data[0] <= 0xFF) { SetSpriteRotScale(spriteId, gTasks[taskId].data[0], gTasks[taskId].data[0], 0); } else { ResetSpriteRotScale(spriteId); DestroyAnimVisualTask(taskId); SetGpuReg(REG_OFFSET_BLDCNT, 0); SetGpuReg(REG_OFFSET_BLDALPHA, 0); } } // Spins a sprite towards the target, pausing in the middle. // Used in Shadow Ball. // arg 0: duration step 1 (attacker -> center) // arg 1: duration step 2 (spin center) // arg 2: duration step 3 (center -> target) static void AnimShadowBall(struct Sprite *sprite) { s16 oldPosX = sprite->x; s16 oldPosY = sprite->y; sprite->x = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_X_2); sprite->y = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_Y_PIC_OFFSET); sprite->data[0] = 0; sprite->data[1] = gBattleAnimArgs[0]; sprite->data[2] = gBattleAnimArgs[1]; sprite->data[3] = gBattleAnimArgs[2]; sprite->data[4] = sprite->x << 4; sprite->data[5] = sprite->y << 4; sprite->data[6] = ((oldPosX - sprite->x) << 4) / (gBattleAnimArgs[0] << 1); sprite->data[7] = ((oldPosY - sprite->y) << 4) / (gBattleAnimArgs[0] << 1); sprite->callback = AnimShadowBall_Step; } static void AnimShadowBall_Step(struct Sprite *sprite) { switch (sprite->data[0]) { case 0: sprite->data[4] += sprite->data[6]; sprite->data[5] += sprite->data[7]; sprite->x = sprite->data[4] >> 4; sprite->y = sprite->data[5] >> 4; sprite->data[1] -= 1; if (sprite->data[1] > 0) break; sprite->data[0] += 1; break; case 1: sprite->data[2] -= 1; if (sprite->data[2] > 0) break; sprite->data[1] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2); sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y_PIC_OFFSET); sprite->data[4] = sprite->x << 4; sprite->data[5] = sprite->y << 4; sprite->data[6] = ((sprite->data[1] - sprite->x) << 4) / sprite->data[3]; sprite->data[7] = ((sprite->data[2] - sprite->y) << 4) / sprite->data[3]; sprite->data[0] += 1; break; case 2: sprite->data[4] += sprite->data[6]; sprite->data[5] += sprite->data[7]; sprite->x = sprite->data[4] >> 4; sprite->y = sprite->data[5] >> 4; sprite->data[3] -= 1; if (sprite->data[3] > 0) break; sprite->x = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2); sprite->y = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y_PIC_OFFSET); sprite->data[0] += 1; break; case 3: DestroySpriteAndMatrix(sprite); break; } } static void AnimLick(struct Sprite *sprite) { InitSpritePosToAnimTarget(sprite, TRUE); sprite->callback = AnimLick_Step; } static void AnimLick_Step(struct Sprite *sprite) { bool8 r5 = FALSE; bool8 r6 = FALSE; if (sprite->animEnded) { if (!sprite->invisible) sprite->invisible = TRUE; switch (sprite->data[0]) { default: r6 = TRUE; break; case 0: if (sprite->data[1] == 2) r5 = TRUE; break; case 1: if (sprite->data[1] == 4) r5 = TRUE; break; } if (r5) { sprite->invisible ^= 1; sprite->data[2]++; sprite->data[1] = 0; if (sprite->data[2] == 5) { sprite->data[2] = 0; sprite->data[0]++; } } else if (r6) { DestroyAnimSprite(sprite); } else { sprite->data[1]++; } } } // Creates a transparent clone of the target which drifts up and away to the side void AnimTask_NightmareClone(u8 taskId) { struct Task *task; task = &gTasks[taskId]; task->data[0] = CloneBattlerSpriteWithBlend(ANIM_TARGET); if (task->data[0] < 0) { DestroyAnimVisualTask(taskId); return; } task->data[1] = 0; task->data[2] = 15; task->data[3] = 2; task->data[4] = 0; SetGpuReg(REG_OFFSET_BLDCNT, (BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_ALL)); SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(task->data[2], task->data[3])); gSprites[task->data[0]].data[0] = 80; if (GetBattlerSide(gBattleAnimTarget) == B_SIDE_PLAYER) { gSprites[task->data[0]].data[1] = -144; gSprites[task->data[0]].data[2] = 112; } else { gSprites[task->data[0]].data[1] = 144; gSprites[task->data[0]].data[2] = -112; } gSprites[task->data[0]].data[3] = 0; gSprites[task->data[0]].data[4] = 0; StoreSpriteCallbackInData6(&gSprites[task->data[0]], SpriteCallbackDummy); gSprites[task->data[0]].callback = TranslateSpriteLinearFixedPoint; task->func = AnimTask_NightmareClone_Step; } static void AnimTask_NightmareClone_Step(u8 taskId) { struct Task *task; task = &gTasks[taskId]; switch (task->data[4]) { case 0: task->data[1] += 1; task->data[5] = task->data[1] & 3; if (task->data[5] == 1) if (task->data[2] > 0) task->data[2] -= 1; if (task->data[5] == 3) if (task->data[3] <= 15) task->data[3] += 1; SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(task->data[2], task->data[3])); if (task->data[3] != 16 || task->data[2] != 0) break; if (task->data[1] <= 80) break; DestroySpriteWithActiveSheet(&gSprites[task->data[0]]); task->data[4] = 1; break; case 1: if (++task->data[6] <= 1) break; SetGpuReg(REG_OFFSET_BLDCNT, 0); SetGpuReg(REG_OFFSET_BLDALPHA, 0); task->data[4] += 1; break; case 2: DestroyAnimVisualTask(taskId); break; } } // Creates a blended copy of the target that wavers in front of them void AnimTask_SpiteTargetShadow(u8 taskId) { struct Task *task; task = &gTasks[taskId]; task->data[15] = 0; task->func = AnimTask_SpiteTargetShadow_Step1; task->func(taskId); } static void AnimTask_SpiteTargetShadow_Step1(u8 taskId) { s16 startLine; struct Task *task = &gTasks[taskId]; u8 position = GetBattlerSpriteBGPriorityRank(gBattleAnimTarget); switch (task->data[15]) { case 0: task->data[14] = AllocSpritePalette(ANIM_TAG_BENT_SPOON); if (task->data[14] == 0xFF || task->data[14] == 0xF) { DestroyAnimVisualTask(taskId); } else { task->data[0] = CloneBattlerSpriteWithBlend(ANIM_TARGET); if (task->data[0] < 0) { FreeSpritePaletteByTag(ANIM_TAG_BENT_SPOON); DestroyAnimVisualTask(taskId); } else { s16 mask2; gSprites[task->data[0]].oam.paletteNum = task->data[14]; gSprites[task->data[0]].oam.objMode = ST_OAM_OBJ_NORMAL; gSprites[task->data[0]].oam.priority = 3; gSprites[task->data[0]].invisible = (gBattleSpritesDataPtr->battlerData[gBattleAnimTarget].invisible); task->data[1] = 0; task->data[2] = 0; task->data[3] = 16; task->data[13] = GetAnimBattlerSpriteId(ANIM_TARGET); task->data[4] = (gSprites[task->data[13]].oam.paletteNum + 16) * 16; if (position == 1) { u16 mask = DISPCNT_BG1_ON; mask2 = mask; } else { u16 mask = DISPCNT_BG2_ON; mask2 = mask; } ClearGpuRegBits(REG_OFFSET_DISPCNT, mask2); task->data[15]++; } } break; case 1: task->data[14] = (task->data[14] + 16) * 16; CpuCopy32(&gPlttBufferUnfaded[task->data[4]], &gPlttBufferFaded[task->data[14]], 32); BlendPalette(task->data[4], 16, 10, RGB(13, 0, 15)); task->data[15]++; break; case 2: startLine = gSprites[task->data[13]].y + gSprites[task->data[13]].y2 - 32; if (startLine < 0) startLine = 0; if (position == 1) task->data[10] = ScanlineEffect_InitWave(startLine, startLine + 64, 2, 6, 0, SCANLINE_EFFECT_REG_BG1HOFS, 1); else task->data[10] = ScanlineEffect_InitWave(startLine, startLine + 64, 2, 6, 0, SCANLINE_EFFECT_REG_BG2HOFS, 1); task->data[15]++; break; case 3: if (position == 1) SetGpuReg(REG_OFFSET_BLDCNT, (BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_ALL | BLDCNT_TGT1_BG1)); else SetGpuReg(REG_OFFSET_BLDCNT, (BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_ALL | BLDCNT_TGT1_BG2)); SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(0, 0x10)); task->data[15]++; break; case 4: if (position == 1) SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_BG1_ON); else SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_BG2_ON); task->func = AnimTask_SpiteTargetShadow_Step2; task->data[15]++; break; default: task->data[15]++; break; } } static void AnimTask_SpiteTargetShadow_Step2(u8 taskId) { struct Task *task = &gTasks[taskId]; task->data[1]++; task->data[5] = task->data[1] & 1; if (task->data[5] == 0) task->data[2] = gSineTable[task->data[1]] / 18; if (task->data[5] == 1) task->data[3] = 16 - (gSineTable[task->data[1]] / 18); SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(task->data[2], task->data[3])); if (task->data[1] == 128) { task->data[15] = 0; task->func = AnimTask_SpiteTargetShadow_Step3; task->func(taskId); } } static void AnimTask_SpiteTargetShadow_Step3(u8 taskId) { struct Task *task = &gTasks[taskId]; u8 rank = GetBattlerSpriteBGPriorityRank(gBattleAnimTarget); switch (task->data[15]) { case 0: gScanlineEffect.state = 3; task->data[14] = GetAnimBattlerSpriteId(ANIM_TARGET); if (rank == 1) ClearGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_BG1_ON); else ClearGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_BG2_ON); break; case 1: BlendPalette(task->data[4], 16, 0, RGB(13, 0, 15)); break; case 2: gSprites[task->data[14]].invisible = TRUE; DestroySpriteWithActiveSheet(&gSprites[task->data[0]]); FreeSpritePaletteByTag(ANIM_TAG_BENT_SPOON); SetGpuReg(REG_OFFSET_BLDCNT, 0); SetGpuReg(REG_OFFSET_BLDALPHA, 0); if (rank == 1) SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_BG1_ON); else SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_BG2_ON); DestroyAnimVisualTask(taskId); break; } task->data[15]++; } static void AnimDestinyBondWhiteShadow(struct Sprite *sprite) { s16 battler1X, battler1Y; s16 battler2X, battler2Y; s16 yDiff; if (gBattleAnimArgs[0] == 0) { battler1X = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_X); battler1Y = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_Y) + 28; battler2X = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X); battler2Y = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y) + 28; } else { battler1X = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X); battler1Y = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y) + 28; battler2X = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_X); battler2Y = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_Y) + 28; } yDiff = battler2Y - battler1Y; sprite->data[0] = battler1X * 16; sprite->data[1] = battler1Y * 16; sprite->data[2] = ((battler2X - battler1X) * 16) / gBattleAnimArgs[1]; sprite->data[3] = (yDiff * 16) / gBattleAnimArgs[1]; sprite->data[4] = gBattleAnimArgs[1]; sprite->data[5] = battler2X; sprite->data[6] = battler2Y; sprite->data[7] = sprite->data[4] / 2; sprite->oam.priority = 2; sprite->x = battler1X; sprite->y = battler1Y; sprite->callback = AnimDestinyBondWhiteShadow_Step; sprite->invisible = TRUE; } static void AnimDestinyBondWhiteShadow_Step(struct Sprite *sprite) { if (sprite->data[4]) { sprite->data[0] += sprite->data[2]; sprite->data[1] += sprite->data[3]; sprite->x = sprite->data[0] >> 4; sprite->y = sprite->data[1] >> 4; if (--sprite->data[4] == 0) sprite->data[0] = 0; } } void AnimTask_DestinyBondWhiteShadow(u8 taskId) { struct Task *task; s16 battler; u8 spriteId; s16 baseX, baseY; s16 x, y; task = &gTasks[taskId]; SetGpuReg(REG_OFFSET_BLDCNT, (BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_ALL)); SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(0, 0x10)); task->data[5] = 0; task->data[6] = 0; task->data[7] = 0; task->data[8] = 0; task->data[9] = 16; task->data[10] = gBattleAnimArgs[0]; baseX = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_X_2); baseY = GetBattlerSpriteCoordAttr(gBattleAnimAttacker, BATTLER_COORD_ATTR_BOTTOM); if (!IsContest()) { for (battler = 0; battler < MAX_BATTLERS_COUNT; battler++) { if (battler != gBattleAnimAttacker && battler != (gBattleAnimAttacker ^ 2) && IsBattlerSpriteVisible(battler)) { spriteId = CreateSprite(&gDestinyBondWhiteShadowSpriteTemplate, baseX, baseY, 55); if (spriteId != MAX_SPRITES) { x = GetBattlerSpriteCoord(battler, BATTLER_COORD_X_2); y = GetBattlerSpriteCoordAttr(battler, BATTLER_COORD_ATTR_BOTTOM); gSprites[spriteId].data[0] = baseX << 4; gSprites[spriteId].data[1] = baseY << 4; gSprites[spriteId].data[2] = ((x - baseX) << 4) / gBattleAnimArgs[1]; gSprites[spriteId].data[3] = ((y - baseY) << 4) / gBattleAnimArgs[1]; gSprites[spriteId].data[4] = gBattleAnimArgs[1]; gSprites[spriteId].data[5] = x; gSprites[spriteId].data[6] = y; gSprites[spriteId].callback = AnimDestinyBondWhiteShadow_Step; task->data[task->data[12] + 13] = spriteId; task->data[12]++; } } } } else { spriteId = CreateSprite(&gDestinyBondWhiteShadowSpriteTemplate, baseX, baseY, 55); if (spriteId != MAX_SPRITES) { x = 48; y = 40; gSprites[spriteId].data[0] = baseX << 4; gSprites[spriteId].data[1] = baseY << 4; gSprites[spriteId].data[2] = ((x - baseX) << 4) / gBattleAnimArgs[1]; gSprites[spriteId].data[3] = ((y - baseY) << 4) / gBattleAnimArgs[1]; gSprites[spriteId].data[4] = gBattleAnimArgs[1]; gSprites[spriteId].data[5] = x; gSprites[spriteId].data[6] = y; gSprites[spriteId].callback = AnimDestinyBondWhiteShadow_Step; task->data[13] = spriteId; task->data[12] = 1; } } task->func = AnimTask_DestinyBondWhiteShadow_Step; } static void AnimTask_DestinyBondWhiteShadow_Step(u8 taskId) { u16 i; struct Task *task = &gTasks[taskId]; switch (task->data[0]) { case 0: if (task->data[6] == 0) { if (++task->data[5] > 1) { task->data[5] = 0; task->data[7]++; if (task->data[7] & 1) { if (task->data[8] < 16) task->data[8]++; } else { if (task->data[9]) task->data[9]--; } SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(task->data[8], task->data[9])); if (task->data[7] >= 24) { task->data[7] = 0; task->data[6] = 1; } } } if (task->data[10]) task->data[10]--; else if (task->data[6]) task->data[0]++; break; case 1: if (++task->data[5] > 1) { task->data[5] = 0; task->data[7]++; if (task->data[7] & 1) { if (task->data[8]) task->data[8]--; } else { if (task->data[9] < 16) task->data[9]++; } SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(task->data[8], task->data[9])); if (task->data[8] == 0 && task->data[9] == 16) { for (i = 0; i < task->data[12]; i++) DestroySprite(&gSprites[task->data[i + 13]]); task->data[0]++; } } break; case 2: if (++task->data[5] > 0) task->data[0]++; break; case 3: SetGpuReg(REG_OFFSET_BLDCNT, 0); SetGpuReg(REG_OFFSET_BLDALPHA, 0); DestroyAnimVisualTask(taskId); break; } } void AnimTask_CurseStretchingBlackBg(u8 taskId) { s16 startX, startY; s16 leftDistance, topDistance, bottomDistance, rightDistance; gBattle_WIN0H = 0; gBattle_WIN0V = 0; SetGpuReg(REG_OFFSET_WININ, ((WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR) | (WININ_WIN1_BG_ALL | WININ_WIN1_OBJ | WININ_WIN1_CLR))); SetGpuReg(REG_OFFSET_WINOUT, ((WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ) | (WINOUT_WINOBJ_BG_ALL | WINOUT_WINOBJ_OBJ | WINOUT_WINOBJ_CLR))); SetGpuReg(REG_OFFSET_BLDCNT, (BLDCNT_TGT1_BG3 | BLDCNT_EFFECT_DARKEN)); SetGpuReg(REG_OFFSET_BLDY, 16); if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER || IsContest()) startX = 40; else startX = 200; gBattle_WIN0H = WIN_RANGE(startX, startX); startY = 40; gBattle_WIN0V = WIN_RANGE(startY, startY); leftDistance = startX; rightDistance = DISPLAY_WIDTH - startX; topDistance = startY; bottomDistance = 72; gTasks[taskId].data[1] = leftDistance; gTasks[taskId].data[2] = rightDistance; gTasks[taskId].data[3] = topDistance; gTasks[taskId].data[4] = bottomDistance; gTasks[taskId].data[5] = startX; gTasks[taskId].data[6] = startY; gTasks[taskId].func = AnimTask_CurseStretchingBlackBg_Step1; } static void AnimTask_CurseStretchingBlackBg_Step1(u8 taskId) { s16 step; s16 leftDistance, rightDistance, topDistance, bottomDistance; s16 startX, startY; u16 left, right, top, bottom; u16 selectedPalettes; step = gTasks[taskId].data[0]; gTasks[taskId].data[0]++; leftDistance = gTasks[taskId].data[1]; rightDistance = gTasks[taskId].data[2]; topDistance = gTasks[taskId].data[3]; bottomDistance = gTasks[taskId].data[4]; startX = gTasks[taskId].data[5]; startY = gTasks[taskId].data[6]; if (step < 16) { left = startX - (leftDistance * 0.0625) * step; right = startX + (rightDistance * 0.0625) * step; top = startY - (topDistance * 0.0625) * step; bottom = startY + (bottomDistance * 0.0625) * step; } else { left = 0; right = DISPLAY_WIDTH; top = 0; bottom = 112; selectedPalettes = GetBattleBgPalettesMask(1, 0, 0, 0, 0, 0, 0); BeginNormalPaletteFade(selectedPalettes, 0, 16, 16, RGB(0, 0, 0)); gTasks[taskId].func = AnimTask_CurseStretchingBlackBg_Step2; } gBattle_WIN0H = WIN_RANGE(left, right); gBattle_WIN0V = WIN_RANGE(top, bottom); } static void AnimTask_CurseStretchingBlackBg_Step2(u8 taskId) { if (!gPaletteFade.active) { gBattle_WIN0H = 0; gBattle_WIN0V = 0; SetGpuReg(REG_OFFSET_WININ, ((WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR) | (WININ_WIN1_BG_ALL | WININ_WIN1_OBJ | WININ_WIN1_CLR))); SetGpuReg(REG_OFFSET_WINOUT, ((WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR) | (WINOUT_WINOBJ_BG_ALL | WINOUT_WINOBJ_OBJ | WINOUT_WINOBJ_CLR))); SetGpuReg(REG_OFFSET_BLDCNT, 0); SetGpuReg(REG_OFFSET_BLDY, 0); DestroyAnimVisualTask(taskId); } } static void AnimCurseNail(struct Sprite *sprite) { s16 xDelta; s16 xDelta2; InitSpritePosToAnimAttacker(sprite, 1); if (GetBattlerSide(gBattleAnimAttacker) == B_SIDE_PLAYER) { xDelta = 24; xDelta2 = -2; sprite->oam.matrixNum = ST_OAM_HFLIP; } else { xDelta = -24; xDelta2 = 2; } sprite->x += xDelta; sprite->data[1] = xDelta2; sprite->data[0] = 60; sprite->callback = AnimCurseNail_Step1; } static void AnimCurseNail_Step1(struct Sprite *sprite) { u16 var0; if (sprite->data[0] > 0) { sprite->data[0]--; } else { sprite->x2 += sprite->data[1]; var0 = sprite->x2 + 7; if (var0 > 14) { sprite->x += sprite->x2; sprite->x2 = 0; sprite->oam.tileNum += 8; if (++sprite->data[2] == 3) { sprite->data[0] = 30; sprite->callback = WaitAnimForDuration; StoreSpriteCallbackInData6(sprite, AnimCurseNail_Step2); } else { sprite->data[0] = 40; } } } } static void AnimCurseNail_Step2(struct Sprite *sprite) { if (sprite->data[0] == 0) { SetGpuReg(REG_OFFSET_BLDCNT, (BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_ALL)); SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(16, 0)); sprite->data[0]++; sprite->data[1] = 0; sprite->data[2] = 0; } else if (sprite->data[1] < 2) { sprite->data[1]++; } else { sprite->data[1] = 0; sprite->data[2]++; SetGpuReg(REG_OFFSET_BLDALPHA, (16 - sprite->data[2]) | (sprite->data[2] << 8)); if (sprite->data[2] == 16) { sprite->invisible = TRUE; sprite->callback = AnimCurseNail_End; } } } static void AnimCurseNail_End(struct Sprite *sprite) { SetGpuReg(REG_OFFSET_BLDCNT, 0); SetGpuReg(REG_OFFSET_BLDALPHA, 0); gBattle_WIN0H = 0; gBattle_WIN0V = 0; DestroyAnimSprite(sprite); } static void AnimGhostStatusSprite(struct Sprite *sprite) { u16 coeffB; u16 coeffA; sprite->x2 = Sin(sprite->data[0], 12); if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER) sprite->x2 = -sprite->x2; sprite->data[0] = (sprite->data[0] + 6) & 0xFF; sprite->data[1] += 0x100; sprite->y2 = -(sprite->data[1] >> 8); sprite->data[7]++; if (sprite->data[7] == 1) { sprite->data[6] = 0x050B; SetGpuReg(REG_OFFSET_BLDCNT, (BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_ALL)); SetGpuReg(REG_OFFSET_BLDALPHA, sprite->data[6]); } else if (sprite->data[7] > 30) { sprite->data[2]++; coeffB = sprite->data[6] >> 8; coeffA = sprite->data[6] & 0xFF; if (++coeffB > 16) coeffB = 16; --coeffA; if ((s16)coeffA < 0) coeffA = 0; SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(coeffA, coeffB)); sprite->data[6] = BLDALPHA_BLEND(coeffA, coeffB); if (coeffB == 16 && coeffA == 0) { sprite->invisible = TRUE; sprite->callback = AnimGhostStatusSprite_Step; } } } static void AnimGhostStatusSprite_Step(struct Sprite *sprite) { SetGpuReg(REG_OFFSET_BLDCNT, 0); SetGpuReg(REG_OFFSET_BLDALPHA, 0); DestroyAnimSprite(sprite); } void AnimTask_GrudgeFlames(u8 taskId) { struct Task *task = &gTasks[taskId]; task->data[0] = 0; task->data[1] = 16; task->data[9] = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_X_2); task->data[10] = GetBattlerYCoordWithElevation(gBattleAnimAttacker); task->data[11] = (GetBattlerSpriteCoordAttr(gBattleAnimAttacker, BATTLER_COORD_ATTR_WIDTH) / 2) + 8; task->data[7] = 0; task->data[5] = GetBattlerSpriteBGPriority(gBattleAnimAttacker); task->data[6] = GetBattlerSpriteSubpriority(gBattleAnimAttacker) - 2; task->data[3] = 0; task->data[4] = 16; SetGpuReg(REG_OFFSET_BLDCNT, (BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_ALL)); SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(0, 0x10)); task->data[8] = 0; task->func = AnimTask_GrudgeFlames_Step; } static void AnimTask_GrudgeFlames_Step(u8 taskId) { u16 i; u8 spriteId; struct Task *task = &gTasks[taskId]; switch (task->data[0]) { case 0: for (i = 0; i < 6; i++) { spriteId = CreateSprite(&gGrudgeFlameSpriteTemplate, task->data[9], task->data[10], task->data[6]); if (spriteId != MAX_SPRITES) { gSprites[spriteId].data[0] = taskId; gSprites[spriteId].data[1] = GetBattlerSide(gBattleAnimAttacker) == B_SIDE_PLAYER; gSprites[spriteId].data[2] = (i * 42) & 0xFF; gSprites[spriteId].data[3] = task->data[11]; gSprites[spriteId].data[5] = i * 6; task->data[7]++; } } task->data[0]++; break; case 1: if (++task->data[1] & 1) { if (task->data[3] < 14) task->data[3]++; } else { if (task->data[4] > 4) task->data[4]--; } if (task->data[3] == 14 && task->data[4] == 4) { task->data[1] = 0; task->data[0]++; } SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(task->data[3], task->data[4])); break; case 2: if (++task->data[1] > 30) { task->data[1] = 0; task->data[0]++; } break; case 3: if (++task->data[1] & 1) { if (task->data[3] > 0) task->data[3]--; } else { if (task->data[4] < 16) task->data[4]++; } if (task->data[3] == 0 && task->data[4] == 16) { task->data[8] = 1; task->data[0]++; } SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(task->data[3], task->data[4])); break; case 4: if (task->data[7] == 0) task->data[0]++; break; case 5: SetGpuReg(REG_OFFSET_BLDCNT, 0); SetGpuReg(REG_OFFSET_BLDALPHA, 0); DestroyAnimVisualTask(taskId); break; } } static void AnimGrudgeFlame(struct Sprite *sprite) { u16 index; if (sprite->data[1] == 0) sprite->data[2] += 2; else sprite->data[2] -= 2; sprite->data[2] &= 0xFF; sprite->x2 = Sin(sprite->data[2], sprite->data[3]); index = sprite->data[2] - 65; if (index < 127) sprite->oam.priority = gTasks[sprite->data[0]].data[5] + 1; else sprite->oam.priority = gTasks[sprite->data[0]].data[5]; sprite->data[5]++; sprite->data[6] = (sprite->data[5] * 8) & 0xFF; sprite->y2 = Sin(sprite->data[6], 7); if (gTasks[sprite->data[0]].data[8]) { gTasks[sprite->data[0]].data[7]--; DestroySprite(sprite); } } static void AnimMonMoveCircular(struct Sprite *sprite) { sprite->invisible = TRUE; sprite->data[5] = gBattlerSpriteIds[gBattleAnimAttacker]; sprite->data[0] = 128; sprite->data[1] = 10; sprite->data[2] = gBattleAnimArgs[0]; sprite->data[3] = gBattleAnimArgs[1]; sprite->callback = AnimMonMoveCircular_Step; gSprites[sprite->data[5]].y += 8; } static void AnimMonMoveCircular_Step(struct Sprite *sprite) { if (sprite->data[3]) { sprite->data[3]--; gSprites[sprite->data[5]].x2 = Sin(sprite->data[0], sprite->data[1]); gSprites[sprite->data[5]].y2 = Cos(sprite->data[0], sprite->data[1]); sprite->data[0] += sprite->data[2]; if (sprite->data[0] > 255) sprite->data[0] -= 256; } else { gSprites[sprite->data[5]].x2 = 0; gSprites[sprite->data[5]].y2 = 0; gSprites[sprite->data[5]].y -= 8; sprite->callback = DestroySpriteAndMatrix; } }