diff --git a/src/battle_anim_ice.c b/src/battle_anim_ice.c index 273721e162..6b48215a7a 100644 --- a/src/battle_anim_ice.c +++ b/src/battle_anim_ice.c @@ -13,11 +13,16 @@ #include "constants/battle_anim.h" #include "constants/rgb.h" +enum { + HAILSTRUCTTYPE_NEGATIVE_POS_MOD = 0, + HAILSTRUCTTYPE_POSITIVE_POS_MOD = 1, + HAILSTRUCTTYPE_FIXED_POSITION = 2, +}; struct HailStruct { s32 x:10; s32 y:10; s32 bPosition:8; - s32 unk3:4; + s32 type:4; }; static void AnimUnusedIceCrystalThrow(struct Sprite *); @@ -371,16 +376,16 @@ const struct SpriteTemplate gPoisonGasCloudSpriteTemplate = static const struct HailStruct sHailCoordData[] = { - {.x = 100, .y = 120, .bPosition = B_POSITION_PLAYER_LEFT, .unk3 = 2}, - {.x = 85, .y = 120, .bPosition = B_POSITION_PLAYER_LEFT, .unk3 = 0}, - {.x = 242, .y = 120, .bPosition = B_POSITION_OPPONENT_LEFT, .unk3 = 1}, - {.x = 66, .y = 120, .bPosition = B_POSITION_PLAYER_RIGHT, .unk3 = 1}, - {.x = 182, .y = 120, .bPosition = B_POSITION_OPPONENT_RIGHT, .unk3 = 0}, - {.x = 60, .y = 120, .bPosition = B_POSITION_PLAYER_LEFT, .unk3 = 2}, - {.x = 214, .y = 120, .bPosition = B_POSITION_OPPONENT_LEFT, .unk3 = 0}, - {.x = 113, .y = 120, .bPosition = B_POSITION_PLAYER_LEFT, .unk3 = 1}, - {.x = 210, .y = 120, .bPosition = B_POSITION_OPPONENT_RIGHT, .unk3 = 1}, - {.x = 38, .y = 120, .bPosition = B_POSITION_PLAYER_RIGHT, .unk3 = 0}, + {.x = 100, .y = 120, .bPosition = B_POSITION_PLAYER_LEFT, .type = HAILSTRUCTTYPE_FIXED_POSITION}, + {.x = 85, .y = 120, .bPosition = B_POSITION_PLAYER_LEFT, .type = HAILSTRUCTTYPE_NEGATIVE_POS_MOD}, + {.x = 242, .y = 120, .bPosition = B_POSITION_OPPONENT_LEFT, .type = HAILSTRUCTTYPE_POSITIVE_POS_MOD}, + {.x = 66, .y = 120, .bPosition = B_POSITION_PLAYER_RIGHT, .type = HAILSTRUCTTYPE_POSITIVE_POS_MOD}, + {.x = 182, .y = 120, .bPosition = B_POSITION_OPPONENT_RIGHT, .type = HAILSTRUCTTYPE_NEGATIVE_POS_MOD}, + {.x = 60, .y = 120, .bPosition = B_POSITION_PLAYER_LEFT, .type = HAILSTRUCTTYPE_FIXED_POSITION}, + {.x = 214, .y = 120, .bPosition = B_POSITION_OPPONENT_LEFT, .type = HAILSTRUCTTYPE_NEGATIVE_POS_MOD}, + {.x = 113, .y = 120, .bPosition = B_POSITION_PLAYER_LEFT, .type = HAILSTRUCTTYPE_POSITIVE_POS_MOD}, + {.x = 210, .y = 120, .bPosition = B_POSITION_OPPONENT_RIGHT, .type = HAILSTRUCTTYPE_POSITIVE_POS_MOD}, + {.x = 38, .y = 120, .bPosition = B_POSITION_PLAYER_RIGHT, .type = HAILSTRUCTTYPE_NEGATIVE_POS_MOD}, }; static const union AffineAnimCmd sAffineAnim_HailParticle_0[] = @@ -1332,6 +1337,13 @@ static void MovePoisonGasCloud(struct Sprite *sprite) } } +#define tState data[0] +#define tSpriteCount data[1] +#define tHailAffineAnimNum data[2] +#define tHailStructId data[3] +#define tInitialDelayTimer data[4] +#define tHailSpawnTimer data[5] + void AnimTask_Hail(u8 taskId) { struct Task *task = &gTasks[taskId]; @@ -1342,71 +1354,86 @@ void AnimTask_Hail(u8 taskId) static void AnimTask_Hail2(u8 taskId) { struct Task *task = &gTasks[taskId]; - switch (task->data[0]) + switch (task->tState) { case 0: - if (++task->data[4] > 2) + if (++task->tInitialDelayTimer > 2) { - task->data[4] = 0; - task->data[5] = 0; - task->data[2] = 0; - task->data[0]++; + task->tInitialDelayTimer = 0; + task->tHailSpawnTimer = 0; + task->tHailAffineAnimNum = 0; + task->tState++; } break; case 1: - if (task->data[5] == 0) + if (task->tHailSpawnTimer == 0) { - if (GenerateHailParticle(task->data[3], task->data[2], taskId, 1)) - task->data[1]++; + if (GenerateHailParticle(task->tHailStructId, task->tHailAffineAnimNum, taskId, 1)) + task->tSpriteCount++; - if (++task->data[2] == 3) + if (++task->tHailAffineAnimNum == (int)ARRAY_COUNT(sAffineAnims_HailParticle)) { - if (++task->data[3] == 10) - task->data[0]++; + if (++task->tHailStructId == (int)ARRAY_COUNT(sHailCoordData)) + task->tState++; else - task->data[0]--; + task->tState--; } else { - task->data[5] = 1; + task->tHailSpawnTimer = 1; } } else { - task->data[5]--; + task->tHailSpawnTimer--; } break; case 2: - if (task->data[1] == 0) + if (task->tSpriteCount == 0) DestroyAnimVisualTask(taskId); break; } } +#undef tState +#undef tSpriteCount +#undef tHailAffineAnimNum +#undef tHailStructId +#undef tInitialDelayTimer +#undef tHailSpawnTimer + +// Hail falling particle sprite vars +#define sSpawnImpactEffect data[0] +#define sTargetX data[3] +#define sTargetY data[4] +#define sAffineAnimNum data[5] +#define sOwnerTaskId data[6] +#define sOwnerTaskSpriteCountField data[7] + static bool8 GenerateHailParticle(u8 hailStructId, u8 affineAnimNum, u8 taskId, u8 c) { u8 id; s16 battlerX, battlerY; s16 spriteX; - bool8 possibleBool = FALSE; - s8 unk = sHailCoordData[hailStructId].unk3; + bool8 shouldSpawnImpactEffect = FALSE; + s8 type = sHailCoordData[hailStructId].type; - if (unk != 2) + if (type != HAILSTRUCTTYPE_FIXED_POSITION) { id = GetBattlerAtPosition(sHailCoordData[hailStructId].bPosition); if (IsBattlerSpriteVisible(id)) { - possibleBool = TRUE; + shouldSpawnImpactEffect = TRUE; battlerX = GetBattlerSpriteCoord(id, BATTLER_COORD_X_2); battlerY = GetBattlerSpriteCoord(id, BATTLER_COORD_Y_PIC_OFFSET); - switch (unk) + switch (type) { - case 0: + case HAILSTRUCTTYPE_NEGATIVE_POS_MOD: battlerX -= GetBattlerSpriteCoordAttr(id, BATTLER_COORD_ATTR_WIDTH) / 6; battlerY -= GetBattlerSpriteCoordAttr(id, BATTLER_COORD_ATTR_HEIGHT) / 6; break; - case 1: + case HAILSTRUCTTYPE_POSITIVE_POS_MOD: battlerX += GetBattlerSpriteCoordAttr(id, BATTLER_COORD_ATTR_WIDTH) / 6; battlerY += GetBattlerSpriteCoordAttr(id, BATTLER_COORD_ATTR_HEIGHT) / 6; break; @@ -1432,12 +1459,12 @@ static bool8 GenerateHailParticle(u8 hailStructId, u8 affineAnimNum, u8 taskId, else { StartSpriteAffineAnim(&gSprites[id], affineAnimNum); - gSprites[id].data[0] = possibleBool; - gSprites[id].data[3] = battlerX; - gSprites[id].data[4] = battlerY; - gSprites[id].data[5] = affineAnimNum; - gSprites[id].data[6] = taskId; - gSprites[id].data[7] = c; + gSprites[id].sSpawnImpactEffect = shouldSpawnImpactEffect; + gSprites[id].sTargetX = battlerX; + gSprites[id].sTargetY = battlerY; + gSprites[id].sAffineAnimNum = affineAnimNum; + gSprites[id].sOwnerTaskId = taskId; + gSprites[id].sOwnerTaskSpriteCountField = c; return TRUE; } } @@ -1449,20 +1476,23 @@ static void AnimHailBegin(struct Sprite *sprite) sprite->x += 4; sprite->y += 8; - if (sprite->x < sprite->data[3] && sprite->y < sprite->data[4]) + if (sprite->x < sprite->sTargetX && sprite->y < sprite->sTargetY) return; - if (sprite->data[0] == 1 && sprite->data[5] == 0) + if (sprite->sSpawnImpactEffect == 1 && sprite->sAffineAnimNum == 0) { spriteId = CreateSprite(&gIceCrystalHitLargeSpriteTemplate, - sprite->data[3], sprite->data[4], sprite->subpriority); + sprite->sTargetX, sprite->sTargetY, sprite->subpriority); sprite->data[0] = spriteId; if (spriteId != MAX_SPRITES) { + // The sprite template we're using is shared amongst a few other + // places, which make the sprite flicker. That's not what we want + // here, though. Override the callback. gSprites[sprite->data[0]].callback = AnimHailContinue; - gSprites[sprite->data[0]].data[6] = sprite->data[6]; - gSprites[sprite->data[0]].data[7] = sprite->data[7]; + gSprites[sprite->data[0]].sOwnerTaskId = sprite->sOwnerTaskId; + gSprites[sprite->data[0]].sOwnerTaskSpriteCountField = sprite->sOwnerTaskSpriteCountField; } FreeOamMatrix(sprite->oam.matrixNum); @@ -1470,22 +1500,34 @@ static void AnimHailBegin(struct Sprite *sprite) } else { - gTasks[sprite->data[6]].data[sprite->data[7]]--; + gTasks[sprite->sOwnerTaskId].data[sprite->sOwnerTaskSpriteCountField]--; FreeOamMatrix(sprite->oam.matrixNum); DestroySprite(sprite); } } +#undef sSpawnImpactEffect +#undef sTargetX +#undef sTargetY +#undef sAffineAnimNum + +// Hail impact VFX sprite vars +#define sTimer data[0] + static void AnimHailContinue(struct Sprite *sprite) { - if (++sprite->data[0] == 20) + if (++sprite->sTimer == 20) { - gTasks[sprite->data[6]].data[sprite->data[7]]--; + gTasks[sprite->sOwnerTaskId].data[sprite->sOwnerTaskSpriteCountField]--; FreeOamMatrix(sprite->oam.matrixNum); DestroySprite(sprite); } } +#undef sTimer +#undef sOwnerTaskId +#undef sOwnerTaskSpriteCountField + // Initializes the animation for Ice Ball. // arg 0: initial x pixel offset // arg 1: initial y pixel offset diff --git a/src/battle_anim_rock.c b/src/battle_anim_rock.c index bb8c3aa2f6..376edfc0eb 100644 --- a/src/battle_anim_rock.c +++ b/src/battle_anim_rock.c @@ -388,6 +388,11 @@ static void AnimParticleInVortex_Step(struct Sprite *sprite) } } +#define tBlendTimer data[10] +#define tBlend data[11] +#define tFullAlphaTimer data[11] // not a typo; this data field is used for multiple purposes +#define tState data[12] + void AnimTask_LoadSandstormBackground(u8 taskId) { int var0; @@ -430,45 +435,45 @@ static void AnimTask_LoadSandstormBackground_Step(u8 taskId) gBattle_BG1_Y += -1; - switch (gTasks[taskId].data[12]) + switch (gTasks[taskId].tState) { case 0: - if (++gTasks[taskId].data[10] == 4) + if (++gTasks[taskId].tBlendTimer == 4) { - gTasks[taskId].data[10] = 0; - gTasks[taskId].data[11]++; - SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(gTasks[taskId].data[11], 16 - gTasks[taskId].data[11])); - if (gTasks[taskId].data[11] == 7) + gTasks[taskId].tBlendTimer = 0; + gTasks[taskId].tBlend++; + SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(gTasks[taskId].tBlend, 16 - gTasks[taskId].tBlend)); + if (gTasks[taskId].tBlend == 7) { - gTasks[taskId].data[12]++; - gTasks[taskId].data[11] = 0; + gTasks[taskId].tState++; + gTasks[taskId].tFullAlphaTimer = 0; } } break; case 1: - if (++gTasks[taskId].data[11] == 101) + if (++gTasks[taskId].tFullAlphaTimer == 101) { - gTasks[taskId].data[11] = 7; - gTasks[taskId].data[12]++; + gTasks[taskId].tBlend = 7; + gTasks[taskId].tState++; } break; case 2: - if (++gTasks[taskId].data[10] == 4) + if (++gTasks[taskId].tBlendTimer == 4) { - gTasks[taskId].data[10] = 0; - gTasks[taskId].data[11]--; - SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(gTasks[taskId].data[11], 16 - gTasks[taskId].data[11])); - if (gTasks[taskId].data[11] == 0) + gTasks[taskId].tBlendTimer = 0; + gTasks[taskId].tBlend--; + SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(gTasks[taskId].tBlend, 16 - gTasks[taskId].tBlend)); + if (gTasks[taskId].tBlend == 0) { - gTasks[taskId].data[12]++; - gTasks[taskId].data[11] = 0; + gTasks[taskId].tState++; + gTasks[taskId].tFullAlphaTimer = 0; } } break; case 3: GetBattleAnimBg1Data(&animBg); ClearBattleAnimBg(animBg.bgId); - gTasks[taskId].data[12]++; + gTasks[taskId].tState++; break; case 4: if (!IsContest()) @@ -484,21 +489,36 @@ static void AnimTask_LoadSandstormBackground_Step(u8 taskId) } } +#undef tBlendTimer +#undef tBlend +#undef tFullAlphaTimer +#undef tState + // Animates the sprites that fly diagonally across the screen // in Sandstorm and Heat Wave. -// arg 0: initial y pixel offset -// arg 1: projectile speed -// arg 2: y pixel drop -// arg 3: ??? unknown (possibly a color bit) + +#define sState data[0] +#define sVelocityX data[1] // 256ths of a pixel // init'd from gBattleAnimArgs[1] +#define sVelocityY data[2] // 256ths of a pixel // init'd from gBattleAnimArgs[2] +#define sFractionalX data[3] // 256ths of a pixel +#define sFractionalY data[4] // 256ths of a pixel +#define sMirroredX data[5] // init'd from gBattleAnimArgs[3] + +// The fields named "velocity" are arguably more like "acceleration," +// and the fields named "fractional" are arguably more like "velocity." +// +// ...is what I WOULD say if the "fractional" fields weren't AND'd with +// 0xFF after every frame. + static void AnimFlyingSandCrescent(struct Sprite *sprite) { - if (sprite->data[0] == 0) + if (sprite->sState == 0) { if (gBattleAnimArgs[3] != 0 && GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER) { sprite->x = DISPLAY_WIDTH + 64; gBattleAnimArgs[1] = -gBattleAnimArgs[1]; - sprite->data[5] = 1; + sprite->sMirroredX = 1; sprite->oam.matrixNum = ST_OAM_HFLIP; } else @@ -508,18 +528,18 @@ static void AnimFlyingSandCrescent(struct Sprite *sprite) sprite->y = gBattleAnimArgs[0]; SetSubspriteTables(sprite, sFlyingSandSubspriteTable); - sprite->data[1] = gBattleAnimArgs[1]; - sprite->data[2] = gBattleAnimArgs[2]; - sprite->data[0]++; + sprite->sVelocityX = gBattleAnimArgs[1]; + sprite->sVelocityY = gBattleAnimArgs[2]; + sprite->sState++; } else { - sprite->data[3] += sprite->data[1]; - sprite->data[4] += sprite->data[2]; - sprite->x2 += (sprite->data[3] >> 8); - sprite->y2 += (sprite->data[4] >> 8); - sprite->data[3] &= 0xFF; - sprite->data[4] &= 0xFF; + sprite->sFractionalX += sprite->sVelocityX; + sprite->sFractionalY += sprite->sVelocityY; + sprite->x2 += (sprite->sFractionalX >> 8); + sprite->y2 += (sprite->sFractionalY >> 8); + sprite->sFractionalX &= 0xFF; + sprite->sFractionalY &= 0xFF; if (sprite->data[5] == 0) { @@ -535,6 +555,13 @@ static void AnimFlyingSandCrescent(struct Sprite *sprite) } } +#undef sState +#undef sVelocityX +#undef sVelocityY +#undef sFractionalX +#undef sFractionalY +#undef sMirroredX + // Animates the rising rocks in Ancient Power. // arg 0: initial x pixel offset // arg 1: initial y pixel offset diff --git a/src/battle_anim_water.c b/src/battle_anim_water.c index dc793f70a5..fda3558e4d 100644 --- a/src/battle_anim_water.c +++ b/src/battle_anim_water.c @@ -473,27 +473,37 @@ const struct SpriteTemplate gWeatherBallWaterDownSpriteTemplate = .callback = AnimWeatherBallDown, }; +#define tRaindropSpawnTimer data[0] +#define tRaindropUnused data[1] +#define tRaindropSpawnInterval data[2] +#define tRaindropSpawnDuration data[3] // number of frames over which we spawn raindrops + void AnimTask_CreateRaindrops(u8 taskId) { u8 x, y; - if (gTasks[taskId].data[0] == 0) + if (gTasks[taskId].tRaindropSpawnTimer == 0) { - gTasks[taskId].data[1] = gBattleAnimArgs[0]; - gTasks[taskId].data[2] = gBattleAnimArgs[1]; - gTasks[taskId].data[3] = gBattleAnimArgs[2]; + gTasks[taskId].tRaindropUnused = gBattleAnimArgs[0]; + gTasks[taskId].tRaindropSpawnInterval = gBattleAnimArgs[1]; + gTasks[taskId].tRaindropSpawnDuration = gBattleAnimArgs[2]; } - gTasks[taskId].data[0]++; - if (gTasks[taskId].data[0] % gTasks[taskId].data[2] == 1) + gTasks[taskId].tRaindropSpawnTimer++; + if (gTasks[taskId].tRaindropSpawnTimer % gTasks[taskId].tRaindropSpawnInterval == 1) { x = Random2() % DISPLAY_WIDTH; y = Random2() % (DISPLAY_HEIGHT / 2); CreateSprite(&gRainDropSpriteTemplate, x, y, 4); } - if (gTasks[taskId].data[0] == gTasks[taskId].data[3]) + if (gTasks[taskId].tRaindropSpawnTimer == gTasks[taskId].tRaindropSpawnDuration) DestroyAnimVisualTask(taskId); } +#undef tRaindropSpawnTimer +#undef tRaindropUnused +#undef tRaindropSpawnInterval +#undef tRaindropSpawnDuration + static void AnimRainDrop(struct Sprite *sprite) { sprite->callback = AnimRainDrop_Step; @@ -503,6 +513,10 @@ static void AnimRainDrop_Step(struct Sprite *sprite) { if (++sprite->data[0] <= 13) { + // + // Make the raindrop fall, but only until it reaches the + // impact/splash frames of its animation. + // sprite->x2++; sprite->y2 += 4; }