#include "global.h" #include "battle_anim.h" #include "scanline_effect.h" #include "task.h" #include "trig.h" #include "constants/rgb.h" static void AnimOutrageFlame(struct Sprite *); static void AnimDragonDanceOrb_Step(struct Sprite *); static void AnimOverheatFlame_Step(struct Sprite *); static void AnimTask_DragonDanceWaver_Step(u8); static void UpdateDragonDanceScanlineEffect(struct Task *); static void AnimDragonRushStep(struct Sprite *sprite); static void AnimSpinningDracoMeteor(struct Sprite *sprite); static void AnimSpinningDracoMeteorFinish(struct Sprite *sprite); EWRAM_DATA static u16 gUnusedOverheatData[7] = {0}; static const union AnimCmd sAnim_OutrageOverheatFire_0[] = { ANIMCMD_FRAME(0, 4), ANIMCMD_FRAME(16, 4), ANIMCMD_FRAME(32, 4), ANIMCMD_FRAME(48, 4), ANIMCMD_FRAME(64, 4), ANIMCMD_JUMP(0), }; static const union AnimCmd *const sAnims_OutrageOverheatFire[] = { sAnim_OutrageOverheatFire_0, }; const struct SpriteTemplate gOutrageFlameSpriteTemplate = { .tileTag = ANIM_TAG_SMALL_EMBER, .paletteTag = ANIM_TAG_SMALL_EMBER, .oam = &gOamData_AffineOff_ObjNormal_32x32, .anims = sAnims_OutrageOverheatFire, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = AnimOutrageFlame, }; static const union AnimCmd sAnim_DragonBreathFire_0[] = { ANIMCMD_FRAME(16, 3), ANIMCMD_FRAME(32, 3), ANIMCMD_FRAME(48, 3), ANIMCMD_JUMP(0), }; static const union AnimCmd sAnim_DragonBreathFire_1[] = { ANIMCMD_FRAME(16, 3, .vFlip = TRUE, .hFlip = TRUE), ANIMCMD_FRAME(32, 3, .vFlip = TRUE, .hFlip = TRUE), ANIMCMD_FRAME(48, 3, .vFlip = TRUE, .hFlip = TRUE), ANIMCMD_JUMP(0), }; const union AnimCmd *const gAnims_DragonBreathFire[] = { sAnim_DragonBreathFire_0, sAnim_DragonBreathFire_1, }; static const union AffineAnimCmd sAffineAnim_DragonBreathFire_0[] = { AFFINEANIMCMD_FRAME(0x50, 0x50, 127, 0), AFFINEANIMCMD_FRAME(0xD, 0xD, 0, 100), AFFINEANIMCMD_END, }; static const union AffineAnimCmd sAffineAnim_DragonBreathFire_1[] = { AFFINEANIMCMD_FRAME(0x50, 0x50, 0, 0), AFFINEANIMCMD_FRAME(0xD, 0xD, 0, 100), AFFINEANIMCMD_END, }; const union AffineAnimCmd *const gAffineAnims_DragonBreathFire[] = { sAffineAnim_DragonBreathFire_0, sAffineAnim_DragonBreathFire_1, }; const struct SpriteTemplate gDragonBreathFireSpriteTemplate = { .tileTag = ANIM_TAG_SMALL_EMBER, .paletteTag = ANIM_TAG_SMALL_EMBER, .oam = &gOamData_AffineDouble_ObjNormal_32x32, .anims = gAnims_DragonBreathFire, .images = NULL, .affineAnims = gAffineAnims_DragonBreathFire, .callback = AnimDragonFireToTarget, }; static const union AnimCmd sAnim_DragonRageFirePlume[] = { ANIMCMD_FRAME(0, 5), ANIMCMD_FRAME(16, 5), ANIMCMD_FRAME(32, 5), ANIMCMD_FRAME(48, 5), ANIMCMD_FRAME(64, 5), ANIMCMD_END, }; const union AnimCmd *const gAnims_DragonRageFirePlume[] = { sAnim_DragonRageFirePlume, }; const struct SpriteTemplate gDragonRageFirePlumeSpriteTemplate = { .tileTag = ANIM_TAG_FIRE_PLUME, .paletteTag = ANIM_TAG_FIRE_PLUME, .oam = &gOamData_AffineOff_ObjNormal_32x32, .anims = gAnims_DragonRageFirePlume, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = AnimDragonRageFirePlume, }; static const union AnimCmd sAnim_DragonRageFire[] = { ANIMCMD_FRAME(16, 3), ANIMCMD_FRAME(32, 3), ANIMCMD_FRAME(48, 3), ANIMCMD_JUMP(0), }; const union AnimCmd *const gAnims_DragonRageFire[] = { sAnim_DragonRageFire, sAnim_DragonRageFire, }; static const union AffineAnimCmd sAffineAnim_DragonRageFire_0[] = { AFFINEANIMCMD_FRAME(0x64, 0x64, 127, 1), AFFINEANIMCMD_END, }; static const union AffineAnimCmd sAffineAnim_DragonRageFire_1[] = { AFFINEANIMCMD_FRAME(0x64, 0x64, 0, 1), AFFINEANIMCMD_END, }; const union AffineAnimCmd *const gAffineAnims_DragonRageFire[] = { sAffineAnim_DragonRageFire_0, sAffineAnim_DragonRageFire_1, }; const struct SpriteTemplate gDragonRageFireSpitSpriteTemplate = { .tileTag = ANIM_TAG_SMALL_EMBER, .paletteTag = ANIM_TAG_SMALL_EMBER, .oam = &gOamData_AffineDouble_ObjNormal_32x32, .anims = gAnims_DragonRageFire, .images = NULL, .affineAnims = gAffineAnims_DragonRageFire, .callback = AnimDragonFireToTarget, }; const struct SpriteTemplate gDragonDanceOrbSpriteTemplate = { .tileTag = ANIM_TAG_HOLLOW_ORB, .paletteTag = ANIM_TAG_HOLLOW_ORB, .oam = &gOamData_AffineOff_ObjNormal_16x16, .anims = gDummySpriteAnimTable, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = AnimDragonDanceOrb, }; const struct SpriteTemplate gOverheatFlameSpriteTemplate = { .tileTag = ANIM_TAG_SMALL_EMBER, .paletteTag = ANIM_TAG_SMALL_EMBER, .oam = &gOamData_AffineOff_ObjNormal_32x32, .anims = sAnims_OutrageOverheatFire, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = AnimOverheatFlame, }; const union AnimCmd gDragonRushAnimCmds[] = { ANIMCMD_FRAME(0, 4), ANIMCMD_FRAME(64, 4), ANIMCMD_END, }; const union AnimCmd *const gDragonRushAnimTable[] = { gDragonRushAnimCmds, }; const union AffineAnimCmd gDragonRushAffineanimCmds1[] = { AFFINEANIMCMD_FRAME(0x100, 0x100, 0, 0), AFFINEANIMCMD_FRAME(0, 0, -4, 8), AFFINEANIMCMD_END, }; const union AffineAnimCmd gDragonRushAffineanimCmds2[] = { AFFINEANIMCMD_FRAME(-0x100, 0x100, 0, 0), AFFINEANIMCMD_FRAME(0, 0, 4, 8), AFFINEANIMCMD_END, }; const union AffineAnimCmd *const gDragonRushAffineAnimTable[] = { gDragonRushAffineanimCmds1, gDragonRushAffineanimCmds2, }; const union AnimCmd gDracoMeteorAnimTable[] = { ANIMCMD_FRAME(0, 1), ANIMCMD_END, }; const union AnimCmd *const gDracoMeteorAnimCmd[] = { gDracoMeteorAnimTable, }; const union AffineAnimCmd gDracoMeteorAffineAnimCmd[] = { AFFINEANIMCMD_FRAME(0x100, 0x100, 0, 0), AFFINEANIMCMD_FRAME(0xFFF8, 0xFFF8, 20, 1), AFFINEANIMCMD_JUMP(1), }; const union AffineAnimCmd *const gDracoMeteorAffineAnims[] = { gDracoMeteorAffineAnimCmd, }; const struct SpriteTemplate gDragonRushSpriteTemplate = { .tileTag = ANIM_TAG_SLAM_HIT_2, .paletteTag = ANIM_TAG_RED_HEART, .oam = &gOamData_AffineNormal_ObjNormal_64x64, .anims = gDragonRushAnimTable, .images = NULL, .affineAnims = gDragonRushAffineAnimTable, .callback = AnimDragonRushStep, }; const struct SpriteTemplate gDracoMetorSpriteTemplate = { .tileTag = ANIM_TAG_IMPACT, .paletteTag = ANIM_TAG_IMPACT, .oam = &gOamData_AffineDouble_ObjNormal_32x32, .anims = gDracoMeteorAnimCmd, .images = NULL, .affineAnims = gDracoMeteorAffineAnims, .callback = AnimSpinningDracoMeteor, }; const struct SpriteTemplate gDragonPulseSpriteTemplate = { .tileTag = ANIM_TAG_DRAGON_PULSE, .paletteTag = ANIM_TAG_DRAGON_PULSE, .oam = &gOamData_AffineOff_ObjNormal_16x32, .anims = gDummySpriteAnimTable, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = TranslateAnimSpriteToTargetMonLocation, }; static void AnimDragonRushStep(struct Sprite *sprite) { // These two cases are identical. if (GetBattlerSide(gBattleAnimTarget) == B_SIDE_PLAYER) { sprite->data[1] += sprite->data[0]; sprite->data[1] &= 0xFF; } else { sprite->data[1] += sprite->data[0]; sprite->data[1] &= 0xFF; } sprite->pos2.x = Cos(sprite->data[1], 20); sprite->pos2.y = Sin(sprite->data[1], 20); if (sprite->animEnded) DestroyAnimSprite(sprite); sprite->data[2]++; } static void AnimSpinningDracoMeteorFinish(struct Sprite *sprite) { StartSpriteAffineAnim(sprite, 0); sprite->affineAnimPaused = 1; sprite->data[0] = 20; sprite->callback = WaitAnimForDuration; StoreSpriteCallbackInData6(sprite, DestroyAnimSprite); } static void AnimSpinningDracoMeteor(struct Sprite *sprite) { InitSpritePosToAnimTarget(sprite, TRUE); StartSpriteAnim(sprite, gBattleAnimArgs[2]); sprite->data[0] = gBattleAnimArgs[3]; sprite->callback = WaitAnimForDuration; StoreSpriteCallbackInData6(sprite, AnimSpinningDracoMeteorFinish); } static void AnimOutrageFlame(struct Sprite *sprite) { sprite->pos1.x = GetBattlerSpriteCoord(gBattleAnimAttacker, 2); sprite->pos1.y = GetBattlerSpriteCoord(gBattleAnimAttacker, 3); if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER) { sprite->pos1.x -= gBattleAnimArgs[0]; gBattleAnimArgs[3] = -gBattleAnimArgs[3]; gBattleAnimArgs[4] = -gBattleAnimArgs[4]; } else { sprite->pos1.x += gBattleAnimArgs[0]; } sprite->pos1.y += gBattleAnimArgs[1]; sprite->data[0] = gBattleAnimArgs[2]; sprite->data[1] = gBattleAnimArgs[3]; sprite->data[3] = gBattleAnimArgs[4]; sprite->data[5] = gBattleAnimArgs[5]; sprite->invisible = TRUE; StoreSpriteCallbackInData6(sprite, DestroySpriteAndMatrix); sprite->callback = TranslateSpriteLinearAndFlicker; } static void StartDragonFireTranslation(struct Sprite *sprite) { SetSpriteCoordsToAnimAttackerCoords(sprite); sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimTarget, 2); sprite->data[4] = GetBattlerSpriteCoord(gBattleAnimTarget, 3); if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER) { sprite->pos1.x -= gBattleAnimArgs[1]; sprite->pos1.y += gBattleAnimArgs[1]; sprite->data[2] -= gBattleAnimArgs[2]; sprite->data[4] += gBattleAnimArgs[3]; } else { sprite->pos1.x += gBattleAnimArgs[0]; sprite->pos1.y += gBattleAnimArgs[1]; sprite->data[2] += gBattleAnimArgs[2]; sprite->data[4] += gBattleAnimArgs[3]; StartSpriteAnim(sprite, 1); } sprite->data[0] = gBattleAnimArgs[4]; sprite->callback = StartAnimLinearTranslation; StoreSpriteCallbackInData6(sprite, DestroySpriteAndMatrix); } void AnimDragonRageFirePlume(struct Sprite *sprite) { if (gBattleAnimArgs[0] == 0) { sprite->pos1.x = GetBattlerSpriteCoord(gBattleAnimAttacker, 0); sprite->pos1.y = GetBattlerSpriteCoord(gBattleAnimAttacker, 1); } else { sprite->pos1.x = GetBattlerSpriteCoord(gBattleAnimTarget, 0); sprite->pos1.y = GetBattlerSpriteCoord(gBattleAnimTarget, 1); } SetAnimSpriteInitialXOffset(sprite, gBattleAnimArgs[1]); sprite->pos1.y += gBattleAnimArgs[2]; sprite->callback = RunStoredCallbackWhenAnimEnds; StoreSpriteCallbackInData6(sprite, DestroySpriteAndMatrix); } // For Dragon Breath and Dragon Rage void AnimDragonFireToTarget(struct Sprite *sprite) { if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER) StartSpriteAffineAnim(sprite, 1); StartDragonFireTranslation(sprite); } void AnimDragonDanceOrb(struct Sprite *sprite) { u16 r5; u16 r0; sprite->pos1.x = GetBattlerSpriteCoord(gBattleAnimAttacker, 2); sprite->pos1.y = GetBattlerSpriteCoord(gBattleAnimAttacker, 3); sprite->data[4] = 0; sprite->data[5] = 1; sprite->data[6] = gBattleAnimArgs[0]; r5 = GetBattlerSpriteCoordAttr(gBattlerAttacker, BATTLER_COORD_ATTR_HEIGHT); r0 = GetBattlerSpriteCoordAttr(gBattlerAttacker, BATTLER_COORD_ATTR_WIDTH); if (r5 > r0) sprite->data[7] = r5 / 2; else sprite->data[7] = r0 / 2; sprite->pos2.x = Cos(sprite->data[6], sprite->data[7]); sprite->pos2.y = Sin(sprite->data[6], sprite->data[7]); sprite->callback = AnimDragonDanceOrb_Step; } static void AnimDragonDanceOrb_Step(struct Sprite *sprite) { switch (sprite->data[0]) { case 0: sprite->data[6] = (sprite->data[6] - sprite->data[5]) & 0xFF; sprite->pos2.x = Cos(sprite->data[6], sprite->data[7]); sprite->pos2.y = Sin(sprite->data[6], sprite->data[7]); if (++sprite->data[4] > 5) { sprite->data[4] = 0; if (sprite->data[5] <= 15 && ++sprite->data[5] > 15) sprite->data[5] = 16; } if (++sprite->data[3] > 0x3C) { sprite->data[3] = 0; sprite->data[0]++; } break; case 1: sprite->data[6] = (sprite->data[6] - sprite->data[5]) & 0xFF; if (sprite->data[7] <= 0x95 && (sprite->data[7] += 8) > 0x95) sprite->data[7] = 0x96; sprite->pos2.x = Cos(sprite->data[6], sprite->data[7]); sprite->pos2.y = Sin(sprite->data[6], sprite->data[7]); if (++sprite->data[4] > 5) { sprite->data[4] = 0; if (sprite->data[5] <= 15 && ++sprite->data[5] > 15) sprite->data[5] = 16; } if (++sprite->data[3] > 20) DestroyAnimSprite(sprite); break; } } // Wavers the attacker back and forth. Progressing vertical wave of scanline shifts // Used by Dragon Dance void AnimTask_DragonDanceWaver(u8 taskId) { struct ScanlineEffectParams scanlineParams; struct Task *task = &gTasks[taskId]; u16 i; u8 y; if (GetBattlerSpriteBGPriorityRank(gBattleAnimAttacker) == 1) { scanlineParams.dmaDest = ®_BG1HOFS; task->data[2] = gBattle_BG1_X; } else { scanlineParams.dmaDest = ®_BG2HOFS; task->data[2] = gBattle_BG2_X; } scanlineParams.dmaControl = SCANLINE_EFFECT_DMACNT_16BIT; scanlineParams.initState = 1; scanlineParams.unused9 = 0; y = GetBattlerYCoordWithElevation(gBattleAnimAttacker); task->data[3] = y - 32; task->data[4] = y + 32; if (task->data[3] < 0) task->data[3] = 0; for (i = task->data[3]; i <= task->data[4]; i++) { gScanlineEffectRegBuffers[0][i] = task->data[2]; gScanlineEffectRegBuffers[1][i] = task->data[2]; } ScanlineEffect_SetParams(scanlineParams); task->func = AnimTask_DragonDanceWaver_Step; } static void AnimTask_DragonDanceWaver_Step(u8 taskId) { struct Task *task = &gTasks[taskId]; switch (task->data[0]) { case 0: if (++task->data[7] > 1) { task->data[7] = 0; if (++task->data[6] == 3) task->data[0]++; } UpdateDragonDanceScanlineEffect(task); break; case 1: if (++task->data[1] > 0x3C) task->data[0]++; UpdateDragonDanceScanlineEffect(task); break; case 2: if (++task->data[7] > 1) { task->data[7] = 0; if (--task->data[6] == 0) task->data[0]++; } UpdateDragonDanceScanlineEffect(task); break; case 3: gScanlineEffect.state = 3; task->data[0]++; break; case 4: DestroyAnimVisualTask(taskId); break; } } static void UpdateDragonDanceScanlineEffect(struct Task *task) { u16 sineIndex = task->data[5]; u16 i; for (i = task->data[3]; i <= task->data[4]; i++) { gScanlineEffectRegBuffers[gScanlineEffect.srcBuffer][i] = ((gSineTable[sineIndex] * task->data[6]) >> 7) + task->data[2]; sineIndex = (sineIndex + 8) & 0xFF; } task->data[5] = (task->data[5] + 9) & 0xFF; } void AnimOverheatFlame(struct Sprite *sprite) { int i; int yAmplitude = (gBattleAnimArgs[2] * 3) / 5; sprite->pos1.x = GetBattlerSpriteCoord(gBattleAnimAttacker, 2); sprite->pos1.y = GetBattlerSpriteCoord(gBattleAnimAttacker, 3) + gBattleAnimArgs[4]; sprite->data[1] = Cos(gBattleAnimArgs[1], gBattleAnimArgs[2]); sprite->data[2] = Sin(gBattleAnimArgs[1], yAmplitude); sprite->pos1.x += sprite->data[1] * gBattleAnimArgs[0]; sprite->pos1.y += sprite->data[2] * gBattleAnimArgs[0]; sprite->data[3] = gBattleAnimArgs[3]; sprite->callback = AnimOverheatFlame_Step; for (i = 0; i < 7; i++) gUnusedOverheatData[i] = sprite->data[i]; } static void AnimOverheatFlame_Step(struct Sprite *sprite) { sprite->data[4] += sprite->data[1]; sprite->data[5] += sprite->data[2]; sprite->pos2.x = sprite->data[4] / 10; sprite->pos2.y = sprite->data[5] / 10; if (++sprite->data[0] > sprite->data[3]) DestroyAnimSprite(sprite); }