pokeemerald/src/field_weather_effect.c

2587 lines
65 KiB
C
Raw Normal View History

2018-12-08 19:05:03 +01:00
#include "global.h"
#include "battle_anim.h"
2018-12-08 19:05:03 +01:00
#include "event_object_movement.h"
#include "field_weather.h"
#include "overworld.h"
#include "random.h"
#include "script.h"
#include "constants/weather.h"
#include "constants/songs.h"
#include "sound.h"
#include "sprite.h"
#include "task.h"
#include "trig.h"
#include "gpu_regs.h"
2018-12-08 19:43:21 +01:00
// EWRAM
EWRAM_DATA static u8 gCurrentAlternatingWeather = 0;
EWRAM_DATA static u16 gUnusedWeatherRelated = 0;
2018-12-08 19:43:21 +01:00
// CONST
const u16 gCloudsWeatherPalette[] = INCBIN_U16("graphics/weather/cloud.gbapal");
const u16 gSandstormWeatherPalette[] = INCBIN_U16("graphics/weather/sandstorm.gbapal");
2018-12-08 19:05:03 +01:00
const u8 gWeatherFog2Tiles[] = INCBIN_U8("graphics/weather/fog2.4bpp");
const u8 gWeatherFog1Tiles[] = INCBIN_U8("graphics/weather/fog1.4bpp");
const u8 gWeatherCloudTiles[] = INCBIN_U8("graphics/weather/cloud.4bpp");
const u8 gWeatherSnow1Tiles[] = INCBIN_U8("graphics/weather/snow0.4bpp");
const u8 gWeatherSnow2Tiles[] = INCBIN_U8("graphics/weather/snow1.4bpp");
const u8 gWeatherBubbleTiles[] = INCBIN_U8("graphics/weather/bubble.4bpp");
const u8 gWeatherAshTiles[] = INCBIN_U8("graphics/weather/ash.4bpp");
const u8 gWeatherRainTiles[] = INCBIN_U8("graphics/weather/rain.4bpp");
const u8 gWeatherSandstormTiles[] = INCBIN_U8("graphics/weather/sandstorm.4bpp");
2019-04-01 04:07:29 +02:00
//------------------------------------------------------------------------------
// Clouds
//------------------------------------------------------------------------------
2019-04-02 03:04:23 +02:00
static void CreateCloudSprites(void);
static void DestroyCloudSprites(void);
static void UpdateCloudSprite(struct Sprite *);
2019-04-01 04:07:29 +02:00
2019-04-02 03:04:23 +02:00
// The clouds are positioned on the map's grid.
// These coordinates are for the lower half of Route 120.
static const struct Coords16 sCloudSpriteMapCoords[] =
2018-12-08 19:05:03 +01:00
{
{ 0, 66},
{ 5, 73},
{10, 78},
};
2019-04-01 04:07:29 +02:00
static const struct SpriteSheet sCloudSpriteSheet =
{
.data = gWeatherCloudTiles,
.size = sizeof(gWeatherCloudTiles),
.tag = 0x1200
};
2018-12-08 19:05:03 +01:00
2019-04-02 03:04:23 +02:00
static const struct OamData sCloudSpriteOamData =
2018-12-08 19:05:03 +01:00
{
.y = 0,
.affineMode = 0,
2019-04-02 03:04:23 +02:00
.objMode = ST_OAM_OBJ_BLEND,
2018-12-08 19:05:03 +01:00
.mosaic = 0,
.bpp = 0,
.shape = SPRITE_SHAPE(64x64),
2018-12-08 19:05:03 +01:00
.x = 0,
.matrixNum = 0,
.size = SPRITE_SIZE(64x64),
2018-12-08 19:05:03 +01:00
.tileNum = 0,
.priority = 3,
.paletteNum = 0,
.affineParam = 0,
};
2019-04-02 03:04:23 +02:00
static const union AnimCmd sCloudSpriteAnimCmd[] =
2018-12-08 19:05:03 +01:00
{
ANIMCMD_FRAME(0, 16),
ANIMCMD_END,
};
2019-04-02 03:04:23 +02:00
static const union AnimCmd *const sCloudSpriteAnimCmds[] =
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
sCloudSpriteAnimCmd,
2018-12-08 19:05:03 +01:00
};
2018-12-08 19:43:21 +01:00
static const struct SpriteTemplate sCloudSpriteTemplate =
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
.tileTag = 0x1200,
.paletteTag = 0x1201,
.oam = &sCloudSpriteOamData,
.anims = sCloudSpriteAnimCmds,
2018-12-08 19:05:03 +01:00
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
2019-04-02 03:04:23 +02:00
.callback = UpdateCloudSprite,
2018-12-08 19:05:03 +01:00
};
void Clouds_InitVars(void)
{
gWeatherPtr->gammaTargetIndex = 0;
gWeatherPtr->gammaStepDelay = 20;
gWeatherPtr->weatherGfxLoaded = FALSE;
gWeatherPtr->initStep = 0;
if (gWeatherPtr->cloudSpritesCreated == FALSE)
Weather_SetBlendCoeffs(0, 16);
}
void Clouds_InitAll(void)
{
Clouds_InitVars();
while (gWeatherPtr->weatherGfxLoaded == FALSE)
Clouds_Main();
}
void Clouds_Main(void)
{
switch (gWeatherPtr->initStep)
{
case 0:
CreateCloudSprites();
gWeatherPtr->initStep++;
break;
case 1:
Weather_SetTargetBlendCoeffs(12, 8, 1);
gWeatherPtr->initStep++;
break;
case 2:
if (Weather_UpdateBlend())
{
gWeatherPtr->weatherGfxLoaded = TRUE;
gWeatherPtr->initStep++;
}
break;
}
}
bool8 Clouds_Finish(void)
{
switch (gWeatherPtr->finishStep)
{
case 0:
Weather_SetTargetBlendCoeffs(0, 16, 1);
gWeatherPtr->finishStep++;
return TRUE;
case 1:
if (Weather_UpdateBlend())
{
2019-04-02 03:04:23 +02:00
DestroyCloudSprites();
2018-12-08 19:05:03 +01:00
gWeatherPtr->finishStep++;
}
return TRUE;
}
return FALSE;
}
2019-04-02 03:04:23 +02:00
void Sunny_InitVars(void)
2018-12-08 19:05:03 +01:00
{
gWeatherPtr->gammaTargetIndex = 0;
gWeatherPtr->gammaStepDelay = 20;
}
2019-04-02 03:04:23 +02:00
void Sunny_InitAll(void)
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
Sunny_InitVars();
2018-12-08 19:05:03 +01:00
}
2019-04-02 03:04:23 +02:00
void Sunny_Main(void)
2018-12-08 19:05:03 +01:00
{
}
2019-04-02 03:04:23 +02:00
bool8 Sunny_Finish(void)
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
return FALSE;
2018-12-08 19:05:03 +01:00
}
2019-04-02 03:04:23 +02:00
static void CreateCloudSprites(void)
2018-12-08 19:05:03 +01:00
{
u16 i;
2019-04-02 03:04:23 +02:00
u8 spriteId;
struct Sprite *sprite;
2018-12-08 19:05:03 +01:00
if (gWeatherPtr->cloudSpritesCreated == TRUE)
return;
2019-04-02 03:04:23 +02:00
2018-12-08 19:05:03 +01:00
LoadSpriteSheet(&sCloudSpriteSheet);
LoadCustomWeatherSpritePalette(gCloudsWeatherPalette);
2019-04-02 03:04:23 +02:00
for (i = 0; i < NUM_CLOUD_SPRITES; i++)
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
spriteId = CreateSprite(&sCloudSpriteTemplate, 0, 0, 0xFF);
2018-12-09 12:16:01 +01:00
if (spriteId != MAX_SPRITES)
2018-12-08 19:05:03 +01:00
{
gWeatherPtr->sprites.s1.cloudSprites[i] = &gSprites[spriteId];
sprite = gWeatherPtr->sprites.s1.cloudSprites[i];
2019-04-02 03:04:23 +02:00
SetSpritePosToMapCoords(sCloudSpriteMapCoords[i].x + 7, sCloudSpriteMapCoords[i].y + 7, &sprite->pos1.x, &sprite->pos1.y);
2018-12-08 19:05:03 +01:00
sprite->coordOffsetEnabled = TRUE;
}
else
{
gWeatherPtr->sprites.s1.cloudSprites[i] = NULL;
}
}
2019-04-02 03:04:23 +02:00
2018-12-08 19:05:03 +01:00
gWeatherPtr->cloudSpritesCreated = TRUE;
}
2019-04-02 03:04:23 +02:00
static void DestroyCloudSprites(void)
2018-12-08 19:05:03 +01:00
{
u16 i;
2019-04-02 03:04:23 +02:00
if (!gWeatherPtr->cloudSpritesCreated)
2018-12-08 19:05:03 +01:00
return;
2019-04-02 03:04:23 +02:00
for (i = 0; i < NUM_CLOUD_SPRITES; i++)
2018-12-08 19:05:03 +01:00
{
if (gWeatherPtr->sprites.s1.cloudSprites[i] != NULL)
DestroySprite(gWeatherPtr->sprites.s1.cloudSprites[i]);
}
2019-04-02 03:04:23 +02:00
2018-12-08 19:05:03 +01:00
FreeSpriteTilesByTag(0x1200);
gWeatherPtr->cloudSpritesCreated = FALSE;
}
2019-04-02 03:04:23 +02:00
static void UpdateCloudSprite(struct Sprite *sprite)
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
// Move 1 pixel left every 2 frames.
2018-12-08 19:05:03 +01:00
sprite->data[0] = (sprite->data[0] + 1) & 1;
2019-04-02 03:04:23 +02:00
if (sprite->data[0])
2018-12-08 19:05:03 +01:00
sprite->pos1.x--;
}
//------------------------------------------------------------------------------
// Drought
//------------------------------------------------------------------------------
static void UpdateDroughtBlend(u8);
2018-12-08 19:05:03 +01:00
void Drought_InitVars(void)
{
gWeatherPtr->initStep = 0;
gWeatherPtr->weatherGfxLoaded = FALSE;
gWeatherPtr->gammaTargetIndex = 0;
gWeatherPtr->gammaStepDelay = 0;
}
void Drought_InitAll(void)
{
Drought_InitVars();
while (gWeatherPtr->weatherGfxLoaded == FALSE)
Drought_Main();
}
void Drought_Main(void)
{
switch (gWeatherPtr->initStep)
{
case 0:
if (gWeatherPtr->palProcessingState != WEATHER_PAL_STATE_CHANGING_WEATHER)
gWeatherPtr->initStep++;
break;
case 1:
ResetDroughtWeatherPaletteLoading();
gWeatherPtr->initStep++;
break;
case 2:
if (LoadDroughtWeatherPalettes() == FALSE)
gWeatherPtr->initStep++;
break;
case 3:
sub_80ABFF0();
gWeatherPtr->initStep++;
break;
case 4:
sub_80AC01C();
if (gWeatherPtr->unknown_73C == 6)
{
gWeatherPtr->weatherGfxLoaded = TRUE;
gWeatherPtr->initStep++;
}
break;
default:
sub_80AC01C();
break;
}
}
2018-12-08 19:43:21 +01:00
bool8 Drought_Finish(void)
2018-12-08 19:05:03 +01:00
{
return FALSE;
2018-12-08 19:05:03 +01:00
}
void StartDroughtWeatherBlend(void)
2018-12-08 19:05:03 +01:00
{
CreateTask(UpdateDroughtBlend, 0x50);
2018-12-08 19:05:03 +01:00
}
#define tState data[0]
#define tBlendY data[1]
#define tBlendDelay data[2]
#define tWinRange data[3]
static void UpdateDroughtBlend(u8 taskId)
2018-12-08 19:05:03 +01:00
{
struct Task *task = &gTasks[taskId];
switch (task->tState)
{
case 0:
task->tBlendY = 0;
task->tBlendDelay = 0;
task->tWinRange = REG_WININ;
SetGpuReg(REG_OFFSET_WININ, WIN_RANGE(63, 63));
SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG1 | BLDCNT_TGT1_BG2 | BLDCNT_TGT1_BG3 | BLDCNT_TGT1_OBJ | BLDCNT_EFFECT_LIGHTEN);
SetGpuReg(REG_OFFSET_BLDY, 0);
task->tState++;
// fall through
case 1:
task->tBlendY += 3;
if (task->tBlendY > 16)
task->tBlendY = 16;
SetGpuReg(REG_OFFSET_BLDY, task->tBlendY);
if (task->tBlendY >= 16)
task->tState++;
break;
case 2:
task->tBlendDelay++;
if (task->tBlendDelay > 9)
{
task->tBlendDelay = 0;
task->tBlendY--;
if (task->tBlendY <= 0)
{
task->tBlendY = 0;
task->tState++;
}
SetGpuReg(REG_OFFSET_BLDY, task->tBlendY);
}
break;
case 3:
SetGpuReg(REG_OFFSET_BLDCNT, 0);
SetGpuReg(REG_OFFSET_BLDY, 0);
SetGpuReg(REG_OFFSET_WININ, task->tWinRange);
task->tState++;
break;
case 4:
EnableBothScriptContexts();
DestroyTask(taskId);
break;
}
}
#undef tState
#undef tBlendY
#undef tBlendDelay
#undef tWinRange
//------------------------------------------------------------------------------
// Light Rain
//------------------------------------------------------------------------------
2019-04-01 04:07:29 +02:00
static void LoadRainSpriteSheet(void);
static bool8 CreateRainSprite(void);
static void UpdateRainSprite(struct Sprite *sprite);
static bool8 UpdateVisibleRainSprites(void);
static void DestroyRainSprites(void);
static const struct Coords16 sRainSpriteCoords[] =
{
{ 0, 0},
{ 0, 160},
{ 0, 64},
{144, 224},
{144, 128},
{ 32, 32},
{ 32, 192},
{ 32, 96},
{ 72, 128},
{ 72, 32},
{ 72, 192},
{216, 96},
{216, 0},
{104, 160},
{104, 64},
{104, 224},
{144, 0},
{144, 160},
{144, 64},
{ 32, 224},
{ 32, 128},
{ 72, 32},
{ 72, 192},
{ 48, 96},
};
static const struct OamData sRainSpriteOamData =
{
.y = 0,
.affineMode = 0,
.objMode = 0,
.mosaic = 0,
.bpp = 0,
.shape = SPRITE_SHAPE(16x32),
.x = 0,
.matrixNum = 0,
.size = SPRITE_SIZE(16x32),
.tileNum = 0,
.priority = 1,
.paletteNum = 2,
.affineParam = 0,
};
static const union AnimCmd sRainSpriteFallAnimCmd[] =
{
ANIMCMD_FRAME(0, 16),
ANIMCMD_JUMP(0),
};
static const union AnimCmd sRainSpriteSplashAnimCmd[] =
{
ANIMCMD_FRAME(8, 3),
ANIMCMD_FRAME(32, 2),
ANIMCMD_FRAME(40, 2),
ANIMCMD_END,
};
static const union AnimCmd sRainSpriteHeavySplashAnimCmd[] =
{
ANIMCMD_FRAME(8, 3),
ANIMCMD_FRAME(16, 3),
ANIMCMD_FRAME(24, 4),
ANIMCMD_END,
};
static const union AnimCmd *const sRainSpriteAnimCmds[] =
{
sRainSpriteFallAnimCmd,
sRainSpriteSplashAnimCmd,
sRainSpriteHeavySplashAnimCmd,
};
static const struct SpriteTemplate sRainSpriteTemplate =
{
.tileTag = 4614,
2019-04-02 03:04:23 +02:00
.paletteTag = 0x1200,
2019-04-01 04:07:29 +02:00
.oam = &sRainSpriteOamData,
.anims = sRainSpriteAnimCmds,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = UpdateRainSprite,
};
// Q28.4 fixed-point format values
static const s16 sRainSpriteMovement[][2] =
{
{-0x68, 0xD0},
{-0xA0, 0x140},
};
// First byte is the number of frames a raindrop falls before it splashes.
// Second byte is the maximum number of frames a raindrop can "wait" before
// it appears and starts falling. (This is only for the initial raindrop spawn.)
static const u16 sRainSpriteFallingDurations[][2] =
{
{18, 7},
{12, 10},
};
static const struct SpriteSheet sRainSpriteSheet =
{
.data = gWeatherRainTiles,
.size = sizeof(gWeatherRainTiles),
.tag = 0x1206,
};
2018-12-08 19:05:03 +01:00
void LightRain_InitVars(void)
{
gWeatherPtr->initStep = 0;
gWeatherPtr->weatherGfxLoaded = FALSE;
2019-04-01 04:07:29 +02:00
gWeatherPtr->rainSpriteVisibleCounter = 0;
gWeatherPtr->rainSpriteVisibleDelay = 8;
gWeatherPtr->isHeavyRain = 0;
2019-04-02 03:04:23 +02:00
gWeatherPtr->targetRainSpriteCount = 10;
2018-12-08 19:05:03 +01:00
gWeatherPtr->gammaTargetIndex = 3;
gWeatherPtr->gammaStepDelay = 20;
SetRainStrengthFromSoundEffect(SE_T_KOAME);
}
void LightRain_InitAll(void)
{
LightRain_InitVars();
2019-04-01 04:07:29 +02:00
while (!gWeatherPtr->weatherGfxLoaded)
2018-12-08 19:05:03 +01:00
LightRain_Main();
}
void LightRain_Main(void)
{
switch (gWeatherPtr->initStep)
{
case 0:
LoadRainSpriteSheet();
gWeatherPtr->initStep++;
break;
case 1:
2019-04-01 04:07:29 +02:00
if (!CreateRainSprite())
2018-12-08 19:05:03 +01:00
gWeatherPtr->initStep++;
break;
case 2:
2019-04-01 04:07:29 +02:00
if (!UpdateVisibleRainSprites())
2018-12-08 19:05:03 +01:00
{
gWeatherPtr->weatherGfxLoaded = TRUE;
gWeatherPtr->initStep++;
}
break;
}
}
bool8 LightRain_Finish(void)
{
switch (gWeatherPtr->finishStep)
{
case 0:
if (gWeatherPtr->nextWeather == WEATHER_RAIN_LIGHT
|| gWeatherPtr->nextWeather == WEATHER_RAIN_MED
|| gWeatherPtr->nextWeather == WEATHER_RAIN_HEAVY)
{
gWeatherPtr->finishStep = 0xFF;
return FALSE;
}
else
{
2019-04-02 03:04:23 +02:00
gWeatherPtr->targetRainSpriteCount = 0;
2018-12-08 19:05:03 +01:00
gWeatherPtr->finishStep++;
}
// fall through
case 1:
2019-04-01 04:07:29 +02:00
if (!UpdateVisibleRainSprites())
2018-12-08 19:05:03 +01:00
{
DestroyRainSprites();
gWeatherPtr->finishStep++;
return FALSE;
}
return TRUE;
}
return FALSE;
}
2019-04-01 04:07:29 +02:00
#define tCounter data[0]
#define tRandom data[1]
#define tPosX data[2]
#define tPosY data[3]
#define tState data[4]
#define tActive data[5]
#define tWaiting data[6]
2018-12-08 19:05:03 +01:00
2019-04-01 04:07:29 +02:00
static void StartRainSpriteFall(struct Sprite *sprite)
2018-12-08 19:05:03 +01:00
{
2019-04-01 04:07:29 +02:00
u32 rand;
u16 numFallingFrames;
int tileX;
int tileY;
2018-12-08 19:05:03 +01:00
2019-04-01 04:07:29 +02:00
if (sprite->tRandom == 0)
sprite->tRandom = 361;
2018-12-08 19:05:03 +01:00
2019-04-01 04:07:29 +02:00
// Standard RNG sequence.
rand = sprite->tRandom * 1103515245 + 12345;
sprite->tRandom = ((rand & 0x7FFF0000) >> 16) % 600;
2018-12-08 19:05:03 +01:00
2019-04-01 04:07:29 +02:00
numFallingFrames = sRainSpriteFallingDurations[gWeatherPtr->isHeavyRain][0];
2018-12-08 19:05:03 +01:00
2019-04-01 04:07:29 +02:00
tileX = sprite->tRandom % 30;
sprite->tPosX = tileX * 8; // Useless assignment, leftover from before fixed-point values were used
2018-12-08 19:05:03 +01:00
2019-04-01 04:07:29 +02:00
tileY = sprite->tRandom / 30;
sprite->tPosY = tileY * 8; // Useless assignment, leftover from before fixed-point values were used
2018-12-08 19:05:03 +01:00
2019-04-01 04:07:29 +02:00
sprite->tPosX = tileX;
sprite->tPosX <<= 7; // This is tileX * 8, using a fixed-point value with 4 decimal places
2018-12-08 19:05:03 +01:00
2019-04-01 04:07:29 +02:00
sprite->tPosY = tileY;
sprite->tPosY <<= 7; // This is tileX * 8, using a fixed-point value with 4 decimal places
// "Rewind" the rain sprites, from their ending position.
sprite->tPosX -= sRainSpriteMovement[gWeatherPtr->isHeavyRain][0] * numFallingFrames;
sprite->tPosY -= sRainSpriteMovement[gWeatherPtr->isHeavyRain][1] * numFallingFrames;
2018-12-08 19:05:03 +01:00
StartSpriteAnim(sprite, 0);
2019-04-01 04:07:29 +02:00
sprite->tState = 0;
2018-12-08 19:05:03 +01:00
sprite->coordOffsetEnabled = FALSE;
2019-04-01 04:07:29 +02:00
sprite->tCounter = numFallingFrames;
2018-12-08 19:05:03 +01:00
}
2019-04-01 04:07:29 +02:00
static void UpdateRainSprite(struct Sprite *sprite)
2018-12-08 19:05:03 +01:00
{
2019-04-01 04:07:29 +02:00
if (sprite->tState == 0)
2018-12-08 19:05:03 +01:00
{
2019-04-01 04:07:29 +02:00
// Raindrop is in its "falling" motion.
sprite->tPosX += sRainSpriteMovement[gWeatherPtr->isHeavyRain][0];
sprite->tPosY += sRainSpriteMovement[gWeatherPtr->isHeavyRain][1];
sprite->pos1.x = sprite->tPosX >> 4;
sprite->pos1.y = sprite->tPosY >> 4;
2018-12-08 19:05:03 +01:00
2019-04-01 04:07:29 +02:00
if (sprite->tActive
2018-12-08 19:05:03 +01:00
&& (sprite->pos1.x >= -8 && sprite->pos1.x <= 248)
&& sprite->pos1.y >= -16 && sprite->pos1.y <= 176)
sprite->invisible = FALSE;
else
sprite->invisible = TRUE;
2019-04-01 04:07:29 +02:00
if (--sprite->tCounter == 0)
2018-12-08 19:05:03 +01:00
{
2019-04-01 04:07:29 +02:00
// Make raindrop splash on the ground
StartSpriteAnim(sprite, gWeatherPtr->isHeavyRain + 1);
sprite->tState = 1;
2018-12-08 19:05:03 +01:00
sprite->pos1.x -= gSpriteCoordOffsetX;
sprite->pos1.y -= gSpriteCoordOffsetY;
sprite->coordOffsetEnabled = TRUE;
}
}
else if (sprite->animEnded)
{
2019-04-01 04:07:29 +02:00
// The splashing animation ended.
2018-12-08 19:05:03 +01:00
sprite->invisible = TRUE;
2019-04-01 04:07:29 +02:00
StartRainSpriteFall(sprite);
2018-12-08 19:05:03 +01:00
}
}
2019-04-01 04:07:29 +02:00
static void WaitRainSprite(struct Sprite *sprite)
2018-12-08 19:05:03 +01:00
{
2019-04-01 04:07:29 +02:00
if (sprite->tCounter == 0)
2018-12-08 19:05:03 +01:00
{
2019-04-01 04:07:29 +02:00
StartRainSpriteFall(sprite);
sprite->callback = UpdateRainSprite;
2018-12-08 19:05:03 +01:00
}
else
{
2019-04-01 04:07:29 +02:00
sprite->tCounter--;
2018-12-08 19:05:03 +01:00
}
}
2019-04-01 04:07:29 +02:00
static void InitRainSpriteMovement(struct Sprite *sprite, u16 val)
2018-12-08 19:05:03 +01:00
{
2019-04-01 04:07:29 +02:00
u16 numFallingFrames = sRainSpriteFallingDurations[gWeatherPtr->isHeavyRain][0];
u16 numAdvanceRng = val / (sRainSpriteFallingDurations[gWeatherPtr->isHeavyRain][1] + numFallingFrames);
u16 frameVal = val % (sRainSpriteFallingDurations[gWeatherPtr->isHeavyRain][1] + numFallingFrames);
while (--numAdvanceRng != 0xFFFF)
StartRainSpriteFall(sprite);
2018-12-08 19:05:03 +01:00
2019-04-01 04:07:29 +02:00
if (frameVal < numFallingFrames)
2018-12-08 19:05:03 +01:00
{
2019-04-01 04:07:29 +02:00
while (--frameVal != 0xFFFF)
UpdateRainSprite(sprite);
sprite->tWaiting = 0;
2018-12-08 19:05:03 +01:00
}
else
{
2019-04-01 04:07:29 +02:00
sprite->tCounter = frameVal - numFallingFrames;
2018-12-08 19:05:03 +01:00
sprite->invisible = TRUE;
2019-04-01 04:07:29 +02:00
sprite->tWaiting = 1;
2018-12-08 19:05:03 +01:00
}
}
2019-04-01 04:07:29 +02:00
static void LoadRainSpriteSheet(void)
2018-12-08 19:05:03 +01:00
{
LoadSpriteSheet(&sRainSpriteSheet);
}
2019-04-01 04:07:29 +02:00
static bool8 CreateRainSprite(void)
2018-12-08 19:05:03 +01:00
{
2019-04-01 04:07:29 +02:00
u8 spriteIndex;
u8 spriteId;
2018-12-08 19:05:03 +01:00
2019-04-01 04:07:29 +02:00
if (gWeatherPtr->rainSpriteCount == MAX_RAIN_SPRITES)
return FALSE;
spriteIndex = gWeatherPtr->rainSpriteCount;
spriteId = CreateSpriteAtEnd(&sRainSpriteTemplate,
sRainSpriteCoords[spriteIndex].x, sRainSpriteCoords[spriteIndex].y, 78);
if (spriteId != MAX_SPRITES)
{
gSprites[spriteId].tActive = 0;
gSprites[spriteId].tRandom = spriteIndex * 145;
while (gSprites[spriteId].tRandom >= 600)
gSprites[spriteId].tRandom -= 600;
StartRainSpriteFall(&gSprites[spriteId]);
InitRainSpriteMovement(&gSprites[spriteId], spriteIndex * 9);
gSprites[spriteId].invisible = TRUE;
gWeatherPtr->sprites.s1.rainSprites[spriteIndex] = &gSprites[spriteId];
}
else
{
gWeatherPtr->sprites.s1.rainSprites[spriteIndex] = NULL;
}
if (++gWeatherPtr->rainSpriteCount == MAX_RAIN_SPRITES)
{
u16 i;
for (i = 0; i < MAX_RAIN_SPRITES; i++)
{
if (gWeatherPtr->sprites.s1.rainSprites[i])
{
if (!gWeatherPtr->sprites.s1.rainSprites[i]->tWaiting)
gWeatherPtr->sprites.s1.rainSprites[i]->callback = UpdateRainSprite;
else
gWeatherPtr->sprites.s1.rainSprites[i]->callback = WaitRainSprite;
}
}
return FALSE;
}
2018-12-08 19:05:03 +01:00
2019-04-01 04:07:29 +02:00
return TRUE;
}
static bool8 UpdateVisibleRainSprites(void)
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
if (gWeatherPtr->curRainSpriteIndex == gWeatherPtr->targetRainSpriteCount)
2019-04-01 04:07:29 +02:00
return FALSE;
2018-12-08 19:05:03 +01:00
2019-04-01 04:07:29 +02:00
if (++gWeatherPtr->rainSpriteVisibleCounter > gWeatherPtr->rainSpriteVisibleDelay)
{
gWeatherPtr->rainSpriteVisibleCounter = 0;
2019-04-02 03:04:23 +02:00
if (gWeatherPtr->curRainSpriteIndex < gWeatherPtr->targetRainSpriteCount)
2019-04-01 04:07:29 +02:00
{
gWeatherPtr->sprites.s1.rainSprites[gWeatherPtr->curRainSpriteIndex++]->tActive = 1;
}
else
{
gWeatherPtr->curRainSpriteIndex--;
gWeatherPtr->sprites.s1.rainSprites[gWeatherPtr->curRainSpriteIndex]->tActive = 0;
gWeatherPtr->sprites.s1.rainSprites[gWeatherPtr->curRainSpriteIndex]->invisible = TRUE;
}
}
return TRUE;
}
static void DestroyRainSprites(void)
2018-12-08 19:05:03 +01:00
{
2019-04-01 04:07:29 +02:00
u16 i;
for (i = 0; i < gWeatherPtr->rainSpriteCount; i++)
{
if (gWeatherPtr->sprites.s1.rainSprites[i] != NULL)
DestroySprite(gWeatherPtr->sprites.s1.rainSprites[i]);
}
gWeatherPtr->rainSpriteCount = 0;
FreeSpriteTilesByTag(0x1206);
}
2018-12-08 19:05:03 +01:00
2019-04-01 04:07:29 +02:00
#undef tCounter
#undef tRandom
#undef tPosX
#undef tPosY
#undef tState
#undef tActive
#undef tWaiting
//------------------------------------------------------------------------------
// Snow
//------------------------------------------------------------------------------
2019-04-02 03:04:23 +02:00
static void UpdateSnowflakeSprite(struct Sprite *);
static bool8 UpdateVisibleSnowflakeSprites(void);
static bool8 CreateSnowflakeSprite(void);
static bool8 DestroySnowflakeSprite(void);
static void InitSnowflakeSpriteMovement(struct Sprite *);
2019-04-01 04:07:29 +02:00
void Snow_InitVars(void)
2018-12-08 19:05:03 +01:00
{
2019-04-01 04:07:29 +02:00
gWeatherPtr->initStep = 0;
gWeatherPtr->weatherGfxLoaded = FALSE;
gWeatherPtr->gammaTargetIndex = 3;
gWeatherPtr->gammaStepDelay = 20;
2019-04-02 03:04:23 +02:00
gWeatherPtr->targetSnowflakeSpriteCount = 16;
gWeatherPtr->snowflakeVisibleCounter = 0;
2019-04-01 04:07:29 +02:00
}
void Snow_InitAll(void)
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
u16 i;
2019-04-01 04:07:29 +02:00
Snow_InitVars();
while (gWeatherPtr->weatherGfxLoaded == FALSE)
{
Snow_Main();
for (i = 0; i < gWeatherPtr->snowflakeSpriteCount; i++)
2019-04-02 03:04:23 +02:00
UpdateSnowflakeSprite(gWeatherPtr->sprites.s1.snowflakeSprites[i]);
2019-04-01 04:07:29 +02:00
}
}
void Snow_Main(void)
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
if (gWeatherPtr->initStep == 0 && !UpdateVisibleSnowflakeSprites())
2019-04-01 04:07:29 +02:00
{
gWeatherPtr->weatherGfxLoaded = TRUE;
gWeatherPtr->initStep++;
}
}
2018-12-08 19:05:03 +01:00
2019-04-01 04:07:29 +02:00
bool8 Snow_Finish(void)
2018-12-08 19:05:03 +01:00
{
2019-04-01 04:07:29 +02:00
switch (gWeatherPtr->finishStep)
{
case 0:
2019-04-02 03:04:23 +02:00
gWeatherPtr->targetSnowflakeSpriteCount = 0;
gWeatherPtr->snowflakeVisibleCounter = 0;
2019-04-01 04:07:29 +02:00
gWeatherPtr->finishStep++;
// fall through
case 1:
2019-04-02 03:04:23 +02:00
if (!UpdateVisibleSnowflakeSprites())
2019-04-01 04:07:29 +02:00
{
gWeatherPtr->finishStep++;
return FALSE;
}
return TRUE;
}
2019-04-02 03:04:23 +02:00
2019-04-01 04:07:29 +02:00
return FALSE;
}
2018-12-08 19:05:03 +01:00
2019-04-02 03:04:23 +02:00
static bool8 UpdateVisibleSnowflakeSprites(void)
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
if (gWeatherPtr->snowflakeSpriteCount == gWeatherPtr->targetSnowflakeSpriteCount)
2019-04-01 04:07:29 +02:00
return FALSE;
2018-12-08 19:05:03 +01:00
2019-04-02 03:04:23 +02:00
if (++gWeatherPtr->snowflakeVisibleCounter > 36)
2019-04-01 04:07:29 +02:00
{
2019-04-02 03:04:23 +02:00
gWeatherPtr->snowflakeVisibleCounter = 0;
if (gWeatherPtr->snowflakeSpriteCount < gWeatherPtr->targetSnowflakeSpriteCount)
2019-04-01 04:07:29 +02:00
CreateSnowflakeSprite();
else
2019-04-02 03:04:23 +02:00
DestroySnowflakeSprite();
2019-04-01 04:07:29 +02:00
}
2019-04-02 03:04:23 +02:00
return gWeatherPtr->snowflakeSpriteCount != gWeatherPtr->targetSnowflakeSpriteCount;
}
2018-12-08 19:05:03 +01:00
2019-04-02 03:04:23 +02:00
static const struct OamData sSnowflakeSpriteOamData =
2018-12-08 19:05:03 +01:00
{
.y = 0,
.affineMode = 0,
.objMode = 0,
.mosaic = 0,
.bpp = 0,
.shape = SPRITE_SHAPE(8x8),
2018-12-08 19:05:03 +01:00
.x = 0,
.matrixNum = 0,
.size = SPRITE_SIZE(8x8),
2018-12-08 19:05:03 +01:00
.tileNum = 0,
.priority = 1,
.paletteNum = 0,
.affineParam = 0,
};
2019-04-02 03:04:23 +02:00
static const struct SpriteFrameImage sSnowflakeSpriteImages[] =
2018-12-08 19:05:03 +01:00
{
{gWeatherSnow1Tiles, sizeof(gWeatherSnow1Tiles)},
{gWeatherSnow2Tiles, sizeof(gWeatherSnow2Tiles)},
};
2019-04-02 03:04:23 +02:00
static const union AnimCmd sSnowflakeAnimCmd0[] =
2018-12-08 19:05:03 +01:00
{
ANIMCMD_FRAME(0, 16),
ANIMCMD_END,
};
2019-04-02 03:04:23 +02:00
static const union AnimCmd sSnowflakeAnimCmd1[] =
2018-12-08 19:05:03 +01:00
{
ANIMCMD_FRAME(1, 16),
ANIMCMD_END,
};
2019-04-02 03:04:23 +02:00
static const union AnimCmd *const sSnowflakeAnimCmds[] =
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
sSnowflakeAnimCmd0,
sSnowflakeAnimCmd1,
2018-12-08 19:05:03 +01:00
};
2018-12-08 19:43:21 +01:00
static const struct SpriteTemplate sSnowflakeSpriteTemplate =
2018-12-08 19:05:03 +01:00
{
.tileTag = 0xFFFF,
2019-04-02 03:04:23 +02:00
.paletteTag = 0x1200,
.oam = &sSnowflakeSpriteOamData,
.anims = sSnowflakeAnimCmds,
.images = sSnowflakeSpriteImages,
2018-12-08 19:05:03 +01:00
.affineAnims = gDummySpriteAffineAnimTable,
2019-04-02 03:04:23 +02:00
.callback = UpdateSnowflakeSprite,
2018-12-08 19:05:03 +01:00
};
2019-04-02 03:04:23 +02:00
#define tPosY data[0]
#define tDeltaY data[1]
#define tWaveDelta data[2]
#define tWaveIndex data[3]
#define tSnowflakeId data[4]
#define tFallCounter data[5]
#define tFallDuration data[6]
#define tDeltaY2 data[7]
2018-12-08 19:05:03 +01:00
2019-04-02 03:04:23 +02:00
static bool8 CreateSnowflakeSprite(void)
2018-12-08 19:05:03 +01:00
{
u8 spriteId = CreateSpriteAtEnd(&sSnowflakeSpriteTemplate, 0, 0, 78);
2018-12-09 12:16:01 +01:00
if (spriteId == MAX_SPRITES)
2018-12-08 19:05:03 +01:00
return FALSE;
2019-04-02 03:04:23 +02:00
gSprites[spriteId].tSnowflakeId = gWeatherPtr->snowflakeSpriteCount;
InitSnowflakeSpriteMovement(&gSprites[spriteId]);
2018-12-08 19:05:03 +01:00
gSprites[spriteId].coordOffsetEnabled = TRUE;
gWeatherPtr->sprites.s1.snowflakeSprites[gWeatherPtr->snowflakeSpriteCount++] = &gSprites[spriteId];
return TRUE;
}
2019-04-02 03:04:23 +02:00
static bool8 DestroySnowflakeSprite(void)
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
if (gWeatherPtr->snowflakeSpriteCount)
2018-12-08 19:05:03 +01:00
{
DestroySprite(gWeatherPtr->sprites.s1.snowflakeSprites[--gWeatherPtr->snowflakeSpriteCount]);
return TRUE;
}
2019-04-02 03:04:23 +02:00
2018-12-08 19:05:03 +01:00
return FALSE;
}
2019-04-02 03:04:23 +02:00
static void InitSnowflakeSpriteMovement(struct Sprite *sprite)
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
u16 rand;
u16 x = ((sprite->tSnowflakeId * 5) & 7) * 30 + (Random() % 30);
2018-12-08 19:05:03 +01:00
sprite->pos1.y = -3 - (gSpriteCoordOffsetY + sprite->centerToCornerVecY);
2019-04-02 03:04:23 +02:00
sprite->pos1.x = x - (gSpriteCoordOffsetX + sprite->centerToCornerVecX);
sprite->tPosY = sprite->pos1.y * 128;
2018-12-08 19:05:03 +01:00
sprite->pos2.x = 0;
2019-04-02 03:04:23 +02:00
rand = Random();
sprite->tDeltaY = (rand & 3) * 5 + 64;
sprite->tDeltaY2 = sprite->tDeltaY;
StartSpriteAnim(sprite, (rand & 1) ? 0 : 1);
sprite->tWaveIndex = 0;
sprite->tWaveDelta = ((rand & 3) == 0) ? 2 : 1;
sprite->tFallDuration = (rand & 0x1F) + 210;
sprite->tFallCounter = 0;
2018-12-08 19:05:03 +01:00
}
2019-04-02 03:04:23 +02:00
static void WaitSnowflakeSprite(struct Sprite *sprite)
2018-12-08 19:05:03 +01:00
{
if (gWeatherPtr->unknown_6E2 > 18)
{
sprite->invisible = FALSE;
2019-04-02 03:04:23 +02:00
sprite->callback = UpdateSnowflakeSprite;
sprite->pos1.y = 250 - (gSpriteCoordOffsetY + sprite->centerToCornerVecY);
sprite->tPosY = sprite->pos1.y * 128;
2018-12-08 19:05:03 +01:00
gWeatherPtr->unknown_6E2 = 0;
}
}
2019-04-02 03:04:23 +02:00
static void UpdateSnowflakeSprite(struct Sprite *sprite)
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
s16 x;
s16 y;
2018-12-08 19:05:03 +01:00
2019-04-02 03:04:23 +02:00
sprite->tPosY += sprite->tDeltaY;
sprite->pos1.y = sprite->tPosY >> 7;
sprite->tWaveIndex += sprite->tWaveDelta;
sprite->tWaveIndex &= 0xFF;
sprite->pos2.x = gSineTable[sprite->tWaveIndex] / 64;
2018-12-08 19:05:03 +01:00
2019-04-02 03:04:23 +02:00
x = (sprite->pos1.x + sprite->centerToCornerVecX + gSpriteCoordOffsetX) & 0x1FF;
if (x & 0x100)
x |= -0x100;
if (x < -3)
2018-12-08 19:05:03 +01:00
sprite->pos1.x = 242 - (gSpriteCoordOffsetX + sprite->centerToCornerVecX);
2019-04-02 03:04:23 +02:00
else if (x > 242)
2018-12-08 19:05:03 +01:00
sprite->pos1.x = -3 - (gSpriteCoordOffsetX + sprite->centerToCornerVecX);
2019-04-02 03:04:23 +02:00
y = (sprite->pos1.y + sprite->centerToCornerVecY + gSpriteCoordOffsetY) & 0xFF;
if (y > 163 && y < 171)
2018-12-08 19:05:03 +01:00
{
sprite->pos1.y = 250 - (gSpriteCoordOffsetY + sprite->centerToCornerVecY);
2019-04-02 03:04:23 +02:00
sprite->tPosY = sprite->pos1.y * 128;
sprite->tFallCounter = 0;
sprite->tFallDuration = 220;
2018-12-08 19:05:03 +01:00
}
2019-04-02 03:04:23 +02:00
else if (y > 242 && y < 250)
2018-12-08 19:05:03 +01:00
{
sprite->pos1.y = 163;
2019-04-02 03:04:23 +02:00
sprite->tPosY = sprite->pos1.y * 128;
sprite->tFallCounter = 0;
sprite->tFallDuration = 220;
2018-12-08 19:05:03 +01:00
sprite->invisible = TRUE;
2019-04-02 03:04:23 +02:00
sprite->callback = WaitSnowflakeSprite;
2018-12-08 19:05:03 +01:00
}
2019-04-02 03:04:23 +02:00
if (++sprite->tFallCounter == sprite->tFallDuration)
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
InitSnowflakeSpriteMovement(sprite);
2018-12-08 19:05:03 +01:00
sprite->pos1.y = 250;
sprite->invisible = TRUE;
2019-04-02 03:04:23 +02:00
sprite->callback = WaitSnowflakeSprite;
2018-12-08 19:05:03 +01:00
}
}
2019-04-02 03:04:23 +02:00
#undef tPosY
#undef tDeltaY
#undef tWaveDelta
#undef tWaveIndex
#undef tSnowflakeId
#undef tFallCounter
#undef tFallDuration
#undef tDeltaY2
2018-12-08 19:05:03 +01:00
//------------------------------------------------------------------------------
// Medium Rain
//------------------------------------------------------------------------------
void MedRain_InitVars(void)
{
gWeatherPtr->initStep = 0;
gWeatherPtr->weatherGfxLoaded = FALSE;
2019-04-01 04:07:29 +02:00
gWeatherPtr->rainSpriteVisibleCounter = 0;
gWeatherPtr->rainSpriteVisibleDelay = 4;
gWeatherPtr->isHeavyRain = 0;
2019-04-02 03:04:23 +02:00
gWeatherPtr->targetRainSpriteCount = 16;
2018-12-08 19:05:03 +01:00
gWeatherPtr->gammaTargetIndex = 3;
gWeatherPtr->gammaStepDelay = 20;
gWeatherPtr->weatherGfxLoaded = FALSE; // duplicate assignment
2019-04-02 03:04:23 +02:00
gWeatherPtr->thunderTriggered = 0;
2018-12-08 19:05:03 +01:00
SetRainStrengthFromSoundEffect(SE_T_AME);
}
void MedRain_InitAll(void)
{
MedRain_InitVars();
while (gWeatherPtr->weatherGfxLoaded == FALSE)
Rain_Main();
}
//------------------------------------------------------------------------------
// Heavy Rain
//------------------------------------------------------------------------------
2019-04-02 03:04:23 +02:00
static void UpdateThunderSound(void);
static void SetThunderCounter(u16);
2018-12-08 19:05:03 +01:00
void HeavyRain_InitVars(void)
{
gWeatherPtr->initStep = 0;
gWeatherPtr->weatherGfxLoaded = FALSE;
2019-04-01 04:07:29 +02:00
gWeatherPtr->rainSpriteVisibleCounter = 0;
gWeatherPtr->rainSpriteVisibleDelay = 4;
gWeatherPtr->isHeavyRain = 1;
2019-04-02 03:04:23 +02:00
gWeatherPtr->targetRainSpriteCount = 24;
2018-12-08 19:05:03 +01:00
gWeatherPtr->gammaTargetIndex = 3;
gWeatherPtr->gammaStepDelay = 20;
gWeatherPtr->weatherGfxLoaded = FALSE; // duplicate assignment
SetRainStrengthFromSoundEffect(SE_T_OOAME);
}
void HeavyRain_InitAll(void)
{
HeavyRain_InitVars();
while (gWeatherPtr->weatherGfxLoaded == FALSE)
Rain_Main();
}
void Rain_Main(void)
{
UpdateThunderSound();
switch (gWeatherPtr->initStep)
{
case 0:
LoadRainSpriteSheet();
gWeatherPtr->initStep++;
break;
case 1:
2019-04-02 03:04:23 +02:00
if (!CreateRainSprite())
gWeatherPtr->initStep++;
2018-12-08 19:05:03 +01:00
break;
case 2:
2019-04-02 03:04:23 +02:00
if (!UpdateVisibleRainSprites())
{
gWeatherPtr->weatherGfxLoaded = TRUE;
gWeatherPtr->initStep++;
}
2018-12-08 19:05:03 +01:00
break;
case 3:
2019-04-02 03:04:23 +02:00
if (gWeatherPtr->palProcessingState != WEATHER_PAL_STATE_CHANGING_WEATHER)
gWeatherPtr->initStep = 6;
2018-12-08 19:05:03 +01:00
break;
case 4:
gWeatherPtr->unknown_6EA = 1;
gWeatherPtr->unknown_6E6 = (Random() % 360) + 360;
gWeatherPtr->initStep++;
// fall through
case 5:
2019-04-02 03:04:23 +02:00
if (--gWeatherPtr->unknown_6E6 == 0)
gWeatherPtr->initStep++;
2018-12-08 19:05:03 +01:00
break;
case 6:
gWeatherPtr->unknown_6EA = 1;
gWeatherPtr->unknown_6EB = Random() % 2;
gWeatherPtr->initStep++;
break;
case 7:
gWeatherPtr->unknown_6EC = (Random() & 1) + 1;
gWeatherPtr->initStep++;
// fall through
case 8:
sub_80ABC48(19);
if (gWeatherPtr->unknown_6EB == 0 && gWeatherPtr->unknown_6EC == 1)
SetThunderCounter(20);
2019-04-02 03:04:23 +02:00
2018-12-08 19:05:03 +01:00
gWeatherPtr->unknown_6E6 = (Random() % 3) + 6;
gWeatherPtr->initStep++;
break;
case 9:
2019-04-02 03:04:23 +02:00
if (--gWeatherPtr->unknown_6E6 == 0)
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
sub_80ABC48(3);
gWeatherPtr->unknown_6EA = 1;
if (--gWeatherPtr->unknown_6EC != 0)
{
gWeatherPtr->unknown_6E6 = (Random() % 16) + 60;
gWeatherPtr->initStep = 10;
}
else if (gWeatherPtr->unknown_6EB == 0)
{
gWeatherPtr->initStep = 4;
}
else
{
gWeatherPtr->initStep = 11;
}
2018-12-08 19:05:03 +01:00
}
break;
case 10:
2019-04-02 03:04:23 +02:00
if (--gWeatherPtr->unknown_6E6 == 0)
gWeatherPtr->initStep = 8;
2018-12-08 19:05:03 +01:00
break;
case 11:
gWeatherPtr->unknown_6E6 = (Random() % 16) + 60;
gWeatherPtr->initStep++;
break;
case 12:
2019-04-02 03:04:23 +02:00
if (--gWeatherPtr->unknown_6E6 == 0)
{
SetThunderCounter(100);
sub_80ABC48(19);
gWeatherPtr->unknown_6E6 = (Random() & 0xF) + 30;
gWeatherPtr->initStep++;
}
2018-12-08 19:05:03 +01:00
break;
case 13:
2019-04-02 03:04:23 +02:00
if (--gWeatherPtr->unknown_6E6 == 0)
{
sub_80ABC7C(19, 3, 5);
gWeatherPtr->initStep++;
}
2018-12-08 19:05:03 +01:00
break;
case 14:
2019-04-02 03:04:23 +02:00
if (gWeatherPtr->palProcessingState == WEATHER_PAL_STATE_IDLE)
{
gWeatherPtr->unknown_6EA = 1;
gWeatherPtr->initStep = 4;
}
2018-12-08 19:05:03 +01:00
break;
}
}
bool8 Rain_Finish(void)
{
switch (gWeatherPtr->finishStep)
{
case 0:
gWeatherPtr->unknown_6EA = 0;
gWeatherPtr->finishStep++;
// fall through
case 1:
Rain_Main();
2019-04-02 03:04:23 +02:00
if (gWeatherPtr->unknown_6EA)
2018-12-08 19:05:03 +01:00
{
if (gWeatherPtr->nextWeather == WEATHER_RAIN_LIGHT
|| gWeatherPtr->nextWeather == WEATHER_RAIN_MED
|| gWeatherPtr->nextWeather == WEATHER_RAIN_HEAVY)
return FALSE;
2019-04-02 03:04:23 +02:00
gWeatherPtr->targetRainSpriteCount = 0;
2018-12-08 19:05:03 +01:00
gWeatherPtr->finishStep++;
}
break;
case 2:
2019-04-02 03:04:23 +02:00
if (!UpdateVisibleRainSprites())
{
DestroyRainSprites();
gWeatherPtr->thunderTriggered = 0;
gWeatherPtr->finishStep++;
return FALSE;
}
break;
2018-12-08 19:05:03 +01:00
default:
return FALSE;
}
return TRUE;
}
2019-04-01 04:07:29 +02:00
static void SetThunderCounter(u16 max)
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
if (gWeatherPtr->thunderTriggered == 0)
2018-12-08 19:05:03 +01:00
{
gWeatherPtr->thunderCounter = Random() % max;
2019-04-02 03:04:23 +02:00
gWeatherPtr->thunderTriggered = 1;
2018-12-08 19:05:03 +01:00
}
}
2019-04-01 04:07:29 +02:00
static void UpdateThunderSound(void)
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
if (gWeatherPtr->thunderTriggered == 1)
2018-12-08 19:05:03 +01:00
{
if (gWeatherPtr->thunderCounter == 0)
{
if (IsSEPlaying())
return;
2019-04-02 03:04:23 +02:00
2018-12-08 19:05:03 +01:00
if (Random() & 1)
PlaySE(SE_T_KAMI);
else
PlaySE(SE_T_KAMI2);
2019-04-02 03:04:23 +02:00
gWeatherPtr->thunderTriggered = 0;
2018-12-08 19:05:03 +01:00
}
else
{
gWeatherPtr->thunderCounter--;
}
}
}
//------------------------------------------------------------------------------
// Fog 1
//------------------------------------------------------------------------------
2019-04-02 03:04:23 +02:00
// unused data
static const u16 unusedData_839AB1C[] = {0, 6, 6, 12, 18, 42, 300, 300};
static const struct OamData gOamData_839AB2C =
{
.y = 0,
.affineMode = 0,
.objMode = 1,
.mosaic = 0,
.bpp = 0,
.shape = SPRITE_SHAPE(64x64),
.x = 0,
.matrixNum = 0,
.size = SPRITE_SIZE(64x64),
.tileNum = 0,
.priority = 2,
.paletteNum = 0,
.affineParam = 0,
};
static const union AnimCmd gSpriteAnim_839AB34[] =
{
ANIMCMD_FRAME(0, 16),
ANIMCMD_END,
};
static const union AnimCmd gSpriteAnim_839AB3C[] =
{
ANIMCMD_FRAME(32, 16),
ANIMCMD_END,
};
static const union AnimCmd gSpriteAnim_839AB44[] =
{
ANIMCMD_FRAME(64, 16),
ANIMCMD_END,
};
static const union AnimCmd gSpriteAnim_839AB4C[] =
{
ANIMCMD_FRAME(96, 16),
ANIMCMD_END,
};
static const union AnimCmd gSpriteAnim_839AB54[] =
{
ANIMCMD_FRAME(128, 16),
ANIMCMD_END,
};
static const union AnimCmd gSpriteAnim_839AB5C[] =
{
ANIMCMD_FRAME(160, 16),
ANIMCMD_END,
};
static const union AnimCmd *const gSpriteAnimTable_839AB64[] =
{
gSpriteAnim_839AB34,
gSpriteAnim_839AB3C,
gSpriteAnim_839AB44,
gSpriteAnim_839AB4C,
gSpriteAnim_839AB54,
gSpriteAnim_839AB5C,
};
static const union AffineAnimCmd gSpriteAffineAnim_839AB7C[] =
{
AFFINEANIMCMD_FRAME(0x200, 0x200, 0, 0),
AFFINEANIMCMD_END,
};
static const union AffineAnimCmd *const gSpriteAffineAnimTable_839AB8C[] =
{
gSpriteAffineAnim_839AB7C,
};
static void Fog1SpriteCallback(struct Sprite *);
static const struct SpriteTemplate sFog1SpriteTemplate =
{
.tileTag = 0x1201,
.paletteTag = 0x1200,
.oam = &gOamData_839AB2C,
.anims = gSpriteAnimTable_839AB64,
.images = NULL,
.affineAnims = gSpriteAffineAnimTable_839AB8C,
.callback = Fog1SpriteCallback,
};
2018-12-08 19:05:03 +01:00
void Fog1_Main(void);
2018-12-08 19:43:21 +01:00
static void CreateFog1Sprites(void);
static void DestroyFog1Sprites(void);
2018-12-08 19:05:03 +01:00
void Fog1_InitVars(void)
{
gWeatherPtr->initStep = 0;
gWeatherPtr->weatherGfxLoaded = FALSE;
gWeatherPtr->gammaTargetIndex = 0;
gWeatherPtr->gammaStepDelay = 20;
if (gWeatherPtr->fog1SpritesCreated == 0)
{
2019-04-02 03:04:23 +02:00
gWeatherPtr->fog1ScrollCounter = 0;
gWeatherPtr->fog1ScrollOffset = 0;
2018-12-08 19:05:03 +01:00
gWeatherPtr->fog1ScrollPosX = 0;
Weather_SetBlendCoeffs(0, 16);
}
}
void Fog1_InitAll(void)
{
Fog1_InitVars();
while (gWeatherPtr->weatherGfxLoaded == FALSE)
Fog1_Main();
}
void Fog1_Main(void)
{
2019-04-02 03:04:23 +02:00
gWeatherPtr->fog1ScrollPosX = (gSpriteCoordOffsetX - gWeatherPtr->fog1ScrollOffset) & 0xFF;
if (++gWeatherPtr->fog1ScrollCounter > 3)
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
gWeatherPtr->fog1ScrollCounter = 0;
gWeatherPtr->fog1ScrollOffset++;
2018-12-08 19:05:03 +01:00
}
switch (gWeatherPtr->initStep)
{
case 0:
CreateFog1Sprites();
if (gWeatherPtr->currWeather == WEATHER_FOG_1)
Weather_SetTargetBlendCoeffs(12, 8, 3);
else
Weather_SetTargetBlendCoeffs(4, 16, 0);
gWeatherPtr->initStep++;
break;
case 1:
if (Weather_UpdateBlend())
{
gWeatherPtr->weatherGfxLoaded = TRUE;
gWeatherPtr->initStep++;
}
break;
}
}
bool8 Fog1_Finish(void)
{
2019-04-02 03:04:23 +02:00
gWeatherPtr->fog1ScrollPosX = (gSpriteCoordOffsetX - gWeatherPtr->fog1ScrollOffset) & 0xFF;
if (++gWeatherPtr->fog1ScrollCounter > 3)
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
gWeatherPtr->fog1ScrollCounter = 0;
gWeatherPtr->fog1ScrollOffset++;
2018-12-08 19:05:03 +01:00
}
2019-04-02 03:04:23 +02:00
2018-12-08 19:05:03 +01:00
switch (gWeatherPtr->finishStep)
{
case 0:
Weather_SetTargetBlendCoeffs(0, 16, 3);
gWeatherPtr->finishStep++;
break;
case 1:
2019-04-02 03:04:23 +02:00
if (Weather_UpdateBlend())
gWeatherPtr->finishStep++;
2018-12-08 19:05:03 +01:00
break;
case 2:
DestroyFog1Sprites();
gWeatherPtr->finishStep++;
break;
default:
return FALSE;
}
return TRUE;
}
2019-04-02 03:04:23 +02:00
#define tSpriteColumn data[0]
2018-12-08 19:05:03 +01:00
2018-12-08 19:43:21 +01:00
static void Fog1SpriteCallback(struct Sprite *sprite)
2018-12-08 19:05:03 +01:00
{
sprite->pos2.y = (u8)gSpriteCoordOffsetY;
2019-04-02 03:04:23 +02:00
sprite->pos1.x = gWeatherPtr->fog1ScrollPosX + 32 + sprite->tSpriteColumn * 64;
if (sprite->pos1.x > 271)
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
sprite->pos1.x = 480 + gWeatherPtr->fog1ScrollPosX - (4 - sprite->tSpriteColumn) * 64;
2018-12-08 19:05:03 +01:00
sprite->pos1.x &= 0x1FF;
}
}
2018-12-08 19:43:21 +01:00
static void CreateFog1Sprites(void)
2018-12-08 19:05:03 +01:00
{
u16 i;
2019-04-02 03:04:23 +02:00
u8 spriteId;
struct Sprite *sprite;
2018-12-08 19:05:03 +01:00
if (!gWeatherPtr->fog1SpritesCreated)
{
2019-04-02 03:04:23 +02:00
struct SpriteSheet fog1SpriteSheet = {
.data = gWeatherFog1Tiles,
.size = sizeof(gWeatherFog1Tiles),
.tag = 0x1201,
};
2018-12-08 19:05:03 +01:00
LoadSpriteSheet(&fog1SpriteSheet);
for (i = 0; i < NUM_FOG1_SPRITES; i++)
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
spriteId = CreateSpriteAtEnd(&sFog1SpriteTemplate, 0, 0, 0xFF);
2018-12-08 19:05:03 +01:00
if (spriteId != MAX_SPRITES)
{
2019-04-02 03:04:23 +02:00
sprite = &gSprites[spriteId];
sprite->tSpriteColumn = i % 5;
2018-12-08 19:05:03 +01:00
sprite->pos1.x = (i % 5) * 64 + 32;
sprite->pos1.y = (i / 5) * 64 + 32;
gWeatherPtr->sprites.s2.fog1Sprites[i] = sprite;
}
else
{
gWeatherPtr->sprites.s2.fog1Sprites[i] = NULL;
}
}
2019-04-02 03:04:23 +02:00
2018-12-08 19:05:03 +01:00
gWeatherPtr->fog1SpritesCreated = TRUE;
}
}
2018-12-08 19:43:21 +01:00
static void DestroyFog1Sprites(void)
2018-12-08 19:05:03 +01:00
{
u16 i;
if (gWeatherPtr->fog1SpritesCreated)
{
for (i = 0; i < NUM_FOG1_SPRITES; i++)
2018-12-08 19:05:03 +01:00
{
if (gWeatherPtr->sprites.s2.fog1Sprites[i] != NULL)
DestroySprite(gWeatherPtr->sprites.s2.fog1Sprites[i]);
}
2019-04-02 03:04:23 +02:00
2018-12-08 19:05:03 +01:00
FreeSpriteTilesByTag(0x1201);
gWeatherPtr->fog1SpritesCreated = 0;
}
}
2019-04-02 03:04:23 +02:00
#undef tSpriteColumn
2018-12-08 19:05:03 +01:00
//------------------------------------------------------------------------------
// Volcanic ash
//------------------------------------------------------------------------------
2019-04-02 03:04:23 +02:00
static void LoadAshSpriteSheet(void);
static void CreateAshSprites(void);
static void DestroyAshSprites(void);
static void UpdateAshSprite(struct Sprite *);
2018-12-08 19:05:03 +01:00
void Ash_InitVars(void)
{
gWeatherPtr->initStep = 0;
gWeatherPtr->weatherGfxLoaded = FALSE;
gWeatherPtr->gammaTargetIndex = 0;
gWeatherPtr->gammaStepDelay = 20;
gWeatherPtr->unknown_6FE = 20;
if (!gWeatherPtr->ashSpritesCreated)
{
Weather_SetBlendCoeffs(0, 16);
2019-04-02 03:04:23 +02:00
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(64, 63)); // These aren't valid blend coefficients!
2018-12-08 19:05:03 +01:00
}
}
void Ash_InitAll(void)
{
Ash_InitVars();
while (gWeatherPtr->weatherGfxLoaded == FALSE)
Ash_Main();
}
void Ash_Main(void)
{
gWeatherPtr->ashBaseSpritesX = gSpriteCoordOffsetX & 0x1FF;
while (gWeatherPtr->ashBaseSpritesX >= 240)
gWeatherPtr->ashBaseSpritesX -= 240;
2019-04-02 03:04:23 +02:00
2018-12-08 19:05:03 +01:00
switch (gWeatherPtr->initStep)
{
case 0:
LoadAshSpriteSheet();
gWeatherPtr->initStep++;
break;
case 1:
if (!gWeatherPtr->ashSpritesCreated)
CreateAshSprites();
2019-04-02 03:04:23 +02:00
2018-12-08 19:05:03 +01:00
Weather_SetTargetBlendCoeffs(16, 0, 1);
gWeatherPtr->initStep++;
break;
case 2:
2019-04-02 03:04:23 +02:00
if (Weather_UpdateBlend())
{
gWeatherPtr->weatherGfxLoaded = TRUE;
gWeatherPtr->initStep++;
}
2018-12-08 19:05:03 +01:00
break;
default:
Weather_UpdateBlend();
break;
}
}
bool8 Ash_Finish(void)
{
switch (gWeatherPtr->finishStep)
{
case 0:
Weather_SetTargetBlendCoeffs(0, 16, 1);
gWeatherPtr->finishStep++;
break;
case 1:
2019-04-02 03:04:23 +02:00
if (Weather_UpdateBlend())
{
DestroyAshSprites();
gWeatherPtr->finishStep++;
}
2018-12-08 19:05:03 +01:00
break;
case 2:
SetGpuReg(REG_OFFSET_BLDALPHA, 0);
gWeatherPtr->finishStep++;
return FALSE;
default:
return FALSE;
}
return TRUE;
}
2019-04-02 03:04:23 +02:00
static const struct SpriteSheet sAshSpriteSheet =
{
.data = gWeatherAshTiles,
.size = sizeof(gWeatherAshTiles),
.tag = 0x1202,
};
2018-12-08 19:05:03 +01:00
2019-04-02 03:04:23 +02:00
static void LoadAshSpriteSheet(void)
2018-12-08 19:05:03 +01:00
{
LoadSpriteSheet(&sAshSpriteSheet);
}
2019-04-02 03:04:23 +02:00
static const struct OamData sAshSpriteOamData =
2018-12-08 19:05:03 +01:00
{
.y = 0,
2019-04-02 00:31:10 +02:00
.affineMode = ST_OAM_AFFINE_OFF,
2019-04-02 03:04:23 +02:00
.objMode = ST_OAM_OBJ_BLEND,
2019-04-02 00:31:10 +02:00
.bpp = ST_OAM_4BPP,
.shape = SPRITE_SHAPE(64x64),
2018-12-08 19:05:03 +01:00
.x = 0,
.size = SPRITE_SIZE(64x64),
2018-12-08 19:05:03 +01:00
.tileNum = 0,
.priority = 1,
.paletteNum = 15,
};
2019-04-02 03:04:23 +02:00
static const union AnimCmd sAshSpriteAnimCmd0[] =
2018-12-08 19:05:03 +01:00
{
ANIMCMD_FRAME(0, 60),
ANIMCMD_FRAME(64, 60),
ANIMCMD_JUMP(0),
};
2019-04-02 03:04:23 +02:00
static const union AnimCmd *const sAshSpriteAnimCmds[] =
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
sAshSpriteAnimCmd0,
2018-12-08 19:05:03 +01:00
};
2018-12-08 19:43:21 +01:00
static const struct SpriteTemplate sAshSpriteTemplate =
2018-12-08 19:05:03 +01:00
{
.tileTag = 4610,
2019-04-02 03:04:23 +02:00
.paletteTag = 0x1200,
.oam = &sAshSpriteOamData,
.anims = sAshSpriteAnimCmds,
2018-12-08 19:05:03 +01:00
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
2019-04-02 03:04:23 +02:00
.callback = UpdateAshSprite,
2018-12-08 19:05:03 +01:00
};
2019-04-02 03:04:23 +02:00
#define tOffsetY data[0]
#define tCounterY data[1]
#define tSpriteColumn data[2]
#define tSpriteRow data[3]
static void CreateAshSprites(void)
2018-12-08 19:05:03 +01:00
{
u8 i;
2019-04-02 03:04:23 +02:00
u8 spriteId;
struct Sprite *sprite;
2018-12-08 19:05:03 +01:00
if (!gWeatherPtr->ashSpritesCreated)
{
2019-04-02 03:04:23 +02:00
for (i = 0; i < NUM_ASH_SPRITES; i++)
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
spriteId = CreateSpriteAtEnd(&sAshSpriteTemplate, 0, 0, 0x4E);
2018-12-08 19:05:03 +01:00
if (spriteId != MAX_SPRITES)
{
2019-04-02 03:04:23 +02:00
sprite = &gSprites[spriteId];
sprite->tCounterY = 0;
sprite->tSpriteColumn = (u8)(i % 5);
sprite->tSpriteRow = (u8)(i / 5);
sprite->tOffsetY = sprite->tSpriteRow * 64 + 32;
2018-12-08 19:05:03 +01:00
gWeatherPtr->sprites.s2.ashSprites[i] = sprite;
}
else
{
gWeatherPtr->sprites.s2.ashSprites[i] = NULL;
}
}
2019-04-02 03:04:23 +02:00
2018-12-08 19:05:03 +01:00
gWeatherPtr->ashSpritesCreated = TRUE;
}
}
2019-04-02 03:04:23 +02:00
static void DestroyAshSprites(void)
2018-12-08 19:05:03 +01:00
{
u16 i;
if (gWeatherPtr->ashSpritesCreated)
{
2019-04-02 03:04:23 +02:00
for (i = 0; i < NUM_ASH_SPRITES; i++)
2018-12-08 19:05:03 +01:00
{
if (gWeatherPtr->sprites.s2.ashSprites[i] != NULL)
DestroySprite(gWeatherPtr->sprites.s2.ashSprites[i]);
}
2019-04-02 03:04:23 +02:00
2018-12-08 19:05:03 +01:00
FreeSpriteTilesByTag(0x1202);
gWeatherPtr->ashSpritesCreated = FALSE;
}
}
2019-04-02 03:04:23 +02:00
static void UpdateAshSprite(struct Sprite *sprite)
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
if (++sprite->tCounterY > 5)
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
sprite->tCounterY = 0;
sprite->tOffsetY++;
2018-12-08 19:05:03 +01:00
}
2019-04-02 03:04:23 +02:00
sprite->pos1.y = gSpriteCoordOffsetY + sprite->tOffsetY;
sprite->pos1.x = gWeatherPtr->ashBaseSpritesX + 32 + sprite->tSpriteColumn * 64;
2018-12-08 19:05:03 +01:00
if (sprite->pos1.x > 271)
{
sprite->pos1.x = gWeatherPtr->ashBaseSpritesX + 480 - (4 - sprite->tSpriteColumn) * 64;
2018-12-08 19:05:03 +01:00
sprite->pos1.x &= 0x1FF;
}
}
2019-04-02 03:04:23 +02:00
#undef tOffsetY
#undef tCounterY
#undef tSpriteColumn
#undef tSpriteRow
2018-12-08 19:05:03 +01:00
//------------------------------------------------------------------------------
// Fog 2
//------------------------------------------------------------------------------
static void UpdateFog2Movement(void);
static void CreateFog2Sprites(void);
static void DestroyFog2Sprites(void);
static void UpdateFog2Sprite(struct Sprite *);
2018-12-08 19:05:03 +01:00
void Fog2_InitVars(void)
{
gWeatherPtr->initStep = 0;
gWeatherPtr->weatherGfxLoaded = 0;
gWeatherPtr->gammaTargetIndex = 0;
gWeatherPtr->gammaStepDelay = 20;
2019-04-02 03:04:23 +02:00
gWeatherPtr->fog1ScrollCounter = 0;
gWeatherPtr->fog1ScrollOffset = 1;
if (!gWeatherPtr->fog2SpritesCreated)
{
gWeatherPtr->fog2ScrollXCounter = 0;
gWeatherPtr->fog2ScrollYCounter = 0;
gWeatherPtr->fog2XOffset = 0;
gWeatherPtr->fog2YOffset = 0;
gWeatherPtr->fog2BaseSpritesX = 0;
gWeatherPtr->fog2PosY = 0;
2018-12-08 19:05:03 +01:00
Weather_SetBlendCoeffs(0, 16);
}
}
void Fog2_InitAll(void)
{
Fog2_InitVars();
while (gWeatherPtr->weatherGfxLoaded == FALSE)
Fog2_Main();
}
void Fog2_Main(void)
{
UpdateFog2Movement();
2018-12-08 19:05:03 +01:00
switch (gWeatherPtr->initStep)
{
case 0:
CreateFog2Sprites();
gWeatherPtr->initStep++;
break;
case 1:
Weather_SetTargetBlendCoeffs(12, 8, 8);
gWeatherPtr->initStep++;
break;
case 2:
if (!Weather_UpdateBlend())
break;
gWeatherPtr->weatherGfxLoaded = TRUE;
gWeatherPtr->initStep++;
break;
}
}
bool8 Fog2_Finish(void)
{
UpdateFog2Movement();
2018-12-08 19:05:03 +01:00
switch (gWeatherPtr->finishStep)
{
case 0:
Weather_SetTargetBlendCoeffs(0, 16, 1);
gWeatherPtr->finishStep++;
break;
case 1:
if (!Weather_UpdateBlend())
break;
gWeatherPtr->finishStep++;
break;
case 2:
DestroyFog2Sprites();
gWeatherPtr->finishStep++;
break;
default:
return FALSE;
}
return TRUE;
}
static void UpdateFog2Movement(void)
2018-12-08 19:05:03 +01:00
{
if (++gWeatherPtr->fog2ScrollXCounter > 2)
2018-12-08 19:05:03 +01:00
{
gWeatherPtr->fog2XOffset++;
gWeatherPtr->fog2ScrollXCounter = 0;
2018-12-08 19:05:03 +01:00
}
if (++gWeatherPtr->fog2ScrollYCounter > 4)
2018-12-08 19:05:03 +01:00
{
gWeatherPtr->fog2YOffset++;
gWeatherPtr->fog2ScrollYCounter = 0;
2018-12-08 19:05:03 +01:00
}
gWeatherPtr->fog2BaseSpritesX = (gSpriteCoordOffsetX - gWeatherPtr->fog2XOffset) & 0xFF;
gWeatherPtr->fog2PosY = gSpriteCoordOffsetY + gWeatherPtr->fog2YOffset;
2018-12-08 19:05:03 +01:00
}
static const struct SpriteSheet gFog2SpriteSheet =
2018-12-08 19:05:03 +01:00
{
.data = gWeatherFog2Tiles,
.size = sizeof(gWeatherFog2Tiles),
.tag = 0x1203,
};
2018-12-08 19:05:03 +01:00
static const struct OamData sFog2SpriteOamData =
2018-12-08 19:05:03 +01:00
{
.y = 0,
2019-04-02 00:31:10 +02:00
.affineMode = ST_OAM_AFFINE_OFF,
.objMode = ST_OAM_OBJ_BLEND,
.bpp = ST_OAM_4BPP,
.shape = SPRITE_SHAPE(64x64),
2018-12-08 19:05:03 +01:00
.x = 0,
.size = SPRITE_SIZE(64x64),
2018-12-08 19:05:03 +01:00
.tileNum = 0,
.priority = 2,
.paletteNum = 0,
};
static const union AnimCmd sFog2SpriteAnimCmd0[] =
2018-12-08 19:05:03 +01:00
{
ANIMCMD_FRAME(0, 16),
ANIMCMD_END,
};
static const union AnimCmd *const sFog2SpriteAnimCmds[] =
2018-12-08 19:05:03 +01:00
{
sFog2SpriteAnimCmd0,
2018-12-08 19:05:03 +01:00
};
static const struct SpriteTemplate sFog2SpriteTemplate =
2018-12-08 19:05:03 +01:00
{
.tileTag = 0x1203,
2019-04-02 03:04:23 +02:00
.paletteTag = 0x1200,
.oam = &sFog2SpriteOamData,
.anims = sFog2SpriteAnimCmds,
2018-12-08 19:05:03 +01:00
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = UpdateFog2Sprite,
2018-12-08 19:05:03 +01:00
};
#define tSpriteColumn data[0]
#define tSpriteRow data[1]
static void CreateFog2Sprites(void)
{
u16 i;
struct SpriteSheet fog2SpriteSheet;
u8 spriteId;
struct Sprite *sprite;
if (!gWeatherPtr->fog2SpritesCreated)
{
fog2SpriteSheet = gFog2SpriteSheet;
LoadSpriteSheet(&fog2SpriteSheet);
for (i = 0; i < NUM_FOG2_SPRITES; i++)
{
spriteId = CreateSpriteAtEnd(&sFog2SpriteTemplate, 0, (i / 5) * 64, 0xFF);
if (spriteId != MAX_SPRITES)
{
sprite = &gSprites[spriteId];
sprite->tSpriteColumn = i % 5;
sprite->tSpriteRow = i / 5;
gWeatherPtr->sprites.s2.fog2Sprites[i] = sprite;
}
else
{
gWeatherPtr->sprites.s2.fog2Sprites[i] = NULL;
}
}
gWeatherPtr->fog2SpritesCreated = TRUE;
}
}
static void DestroyFog2Sprites(void)
2018-12-08 19:05:03 +01:00
{
u16 i;
if (gWeatherPtr->fog2SpritesCreated)
{
for (i = 0; i < NUM_FOG2_SPRITES; i++)
2018-12-08 19:05:03 +01:00
{
if (gWeatherPtr->sprites.s2.fog2Sprites[i])
2018-12-08 19:05:03 +01:00
DestroySprite(gWeatherPtr->sprites.s2.fog2Sprites[i]);
}
2018-12-08 19:05:03 +01:00
FreeSpriteTilesByTag(0x1203);
gWeatherPtr->fog2SpritesCreated = FALSE;
}
}
static void UpdateFog2Sprite(struct Sprite *sprite)
2018-12-08 19:05:03 +01:00
{
sprite->pos2.y = gWeatherPtr->fog2PosY;
sprite->pos1.x = gWeatherPtr->fog2BaseSpritesX + 32 + sprite->tSpriteColumn * 64;
2018-12-08 19:05:03 +01:00
if (sprite->pos1.x > 271)
{
sprite->pos1.x = gWeatherPtr->fog2BaseSpritesX + 480 - (4 - sprite->tSpriteColumn) * 64;
2018-12-08 19:05:03 +01:00
sprite->pos1.x &= 0x1FF;
}
}
#undef tSpriteColumn
#undef tSpriteRow
2018-12-08 19:05:03 +01:00
//------------------------------------------------------------------------------
// Sandstorm
//------------------------------------------------------------------------------
static void UpdateSandstormWaveIndex(void);
static void UpdateSandstormMovement(void);
static void CreateSandstormSprites(void);
static void CreateSwirlSandstormSprites(void);
static void DestroySandstormSprites(void);
static void UpdateSandstormSprite(struct Sprite *);
static void WaitSandSwirlSpriteEntrance(struct Sprite *);
static void UpdateSandstormSwirlSprite(struct Sprite *);
#define MIN_SANDSTORM_WAVE_INDEX 0x20
2018-12-08 19:05:03 +01:00
void Sandstorm_InitVars(void)
{
gWeatherPtr->initStep = 0;
gWeatherPtr->weatherGfxLoaded = 0;
gWeatherPtr->gammaTargetIndex = 0;
gWeatherPtr->gammaStepDelay = 20;
if (!gWeatherPtr->sandstormSpritesCreated)
2018-12-08 19:05:03 +01:00
{
gWeatherPtr->sandstormXOffset = gWeatherPtr->sandstormYOffset = 0;
gWeatherPtr->sandstormWaveIndex = 8;
gWeatherPtr->sandstormWaveCounter = 0;
2018-12-08 19:05:03 +01:00
// Dead code. How does the compiler not optimize this out?
if (gWeatherPtr->sandstormWaveIndex >= 0x80 - MIN_SANDSTORM_WAVE_INDEX)
gWeatherPtr->sandstormWaveIndex = 0x80 - gWeatherPtr->sandstormWaveIndex;
2018-12-08 19:05:03 +01:00
Weather_SetBlendCoeffs(0, 16);
}
}
void Sandstorm_InitAll(void)
{
Sandstorm_InitVars();
while (!gWeatherPtr->weatherGfxLoaded)
2018-12-08 19:05:03 +01:00
Sandstorm_Main();
}
void Sandstorm_Main(void)
{
UpdateSandstormMovement();
UpdateSandstormWaveIndex();
if (gWeatherPtr->sandstormWaveIndex >= 0x80 - MIN_SANDSTORM_WAVE_INDEX)
gWeatherPtr->sandstormWaveIndex = MIN_SANDSTORM_WAVE_INDEX;
2018-12-08 19:05:03 +01:00
switch (gWeatherPtr->initStep)
{
case 0:
CreateSandstormSprites();
CreateSwirlSandstormSprites();
2018-12-08 19:05:03 +01:00
gWeatherPtr->initStep++;
break;
case 1:
Weather_SetTargetBlendCoeffs(16, 0, 0);
gWeatherPtr->initStep++;
break;
case 2:
if (Weather_UpdateBlend())
{
gWeatherPtr->weatherGfxLoaded = TRUE;
gWeatherPtr->initStep++;
}
2018-12-08 19:05:03 +01:00
break;
}
}
bool8 Sandstorm_Finish(void)
{
UpdateSandstormMovement();
UpdateSandstormWaveIndex();
2018-12-08 19:05:03 +01:00
switch (gWeatherPtr->finishStep)
{
case 0:
Weather_SetTargetBlendCoeffs(0, 16, 0);
gWeatherPtr->finishStep++;
break;
case 1:
if (Weather_UpdateBlend())
gWeatherPtr->finishStep++;
2018-12-08 19:05:03 +01:00
break;
case 2:
DestroySandstormSprites();
2018-12-08 19:05:03 +01:00
gWeatherPtr->finishStep++;
break;
default:
return FALSE;
}
2018-12-08 19:05:03 +01:00
return TRUE;
}
static void UpdateSandstormWaveIndex(void)
2018-12-08 19:05:03 +01:00
{
if (gWeatherPtr->sandstormWaveCounter++ > 4)
2018-12-08 19:05:03 +01:00
{
gWeatherPtr->sandstormWaveIndex++;
gWeatherPtr->sandstormWaveCounter = 0;
2018-12-08 19:05:03 +01:00
}
}
static void UpdateSandstormMovement(void)
2018-12-08 19:05:03 +01:00
{
gWeatherPtr->sandstormXOffset -= gSineTable[gWeatherPtr->sandstormWaveIndex] * 4;
gWeatherPtr->sandstormYOffset -= gSineTable[gWeatherPtr->sandstormWaveIndex];
gWeatherPtr->sandstormBaseSpritesX = (gSpriteCoordOffsetX + (gWeatherPtr->sandstormXOffset >> 8)) & 0xFF;
gWeatherPtr->sandstormPosY = gSpriteCoordOffsetY + (gWeatherPtr->sandstormYOffset >> 8);
2018-12-08 19:05:03 +01:00
}
static void DestroySandstormSprites(void)
2018-12-08 19:05:03 +01:00
{
u16 i;
if (gWeatherPtr->sandstormSpritesCreated)
2018-12-08 19:05:03 +01:00
{
for (i = 0; i < NUM_SANDSTORM_SPRITES; i++)
2018-12-08 19:05:03 +01:00
{
if (gWeatherPtr->sprites.s2.sandstormSprites1[i])
2018-12-08 19:05:03 +01:00
DestroySprite(gWeatherPtr->sprites.s2.sandstormSprites1[i]);
}
gWeatherPtr->sandstormSpritesCreated = FALSE;
2018-12-08 19:05:03 +01:00
FreeSpriteTilesByTag(0x1204);
}
if (gWeatherPtr->sandstormSwirlSpritesCreated)
2018-12-08 19:05:03 +01:00
{
for (i = 0; i < NUM_SWIRL_SANDSTORM_SPRITES; i++)
2018-12-08 19:05:03 +01:00
{
if (gWeatherPtr->sprites.s2.sandstormSprites2[i] != NULL)
DestroySprite(gWeatherPtr->sprites.s2.sandstormSprites2[i]);
}
gWeatherPtr->sandstormSwirlSpritesCreated = FALSE;
2018-12-08 19:05:03 +01:00
}
}
static const struct OamData sSandstormSpriteOamData =
2018-12-08 19:05:03 +01:00
{
.y = 0,
2019-04-02 00:31:10 +02:00
.affineMode = ST_OAM_AFFINE_OFF,
.objMode = ST_OAM_OBJ_BLEND,
.bpp = ST_OAM_4BPP,
.shape = SPRITE_SHAPE(64x64),
2018-12-08 19:05:03 +01:00
.x = 0,
.size = SPRITE_SIZE(64x64),
2018-12-08 19:05:03 +01:00
.tileNum = 0,
.priority = 1,
.paletteNum = 0,
};
static const union AnimCmd sSandstormSpriteAnimCmd0[] =
2018-12-08 19:05:03 +01:00
{
ANIMCMD_FRAME(0, 3),
ANIMCMD_END,
};
static const union AnimCmd sSandstormSpriteAnimCmd1[] =
2018-12-08 19:05:03 +01:00
{
ANIMCMD_FRAME(64, 3),
ANIMCMD_END,
};
static const union AnimCmd *const sSandstormSpriteAnimCmds[] =
2018-12-08 19:05:03 +01:00
{
sSandstormSpriteAnimCmd0,
sSandstormSpriteAnimCmd1,
2018-12-08 19:05:03 +01:00
};
static const struct SpriteTemplate sSandstormSpriteTemplate =
2018-12-08 19:05:03 +01:00
{
2019-04-02 03:04:23 +02:00
.tileTag = 0x1204,
.paletteTag = 0x1201,
.oam = &sSandstormSpriteOamData,
.anims = sSandstormSpriteAnimCmds,
2018-12-08 19:05:03 +01:00
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = UpdateSandstormSprite,
2018-12-08 19:05:03 +01:00
};
static const struct SpriteSheet sSandstormSpriteSheet =
{
.data = gWeatherSandstormTiles,
.size = sizeof(gWeatherSandstormTiles),
.tag = 0x1204,
};
// Regular sandstorm sprites
#define tSpriteColumn data[0]
#define tSpriteRow data[1]
// Swirly sandstorm sprites
#define tRadius data[0]
#define tWaveIndex data[1]
#define tRadiusCounter data[2]
#define tEntranceDelay data[3]
2018-12-08 19:05:03 +01:00
static void CreateSandstormSprites(void)
2018-12-08 19:05:03 +01:00
{
u16 i;
u8 spriteId;
2018-12-08 19:05:03 +01:00
if (!gWeatherPtr->sandstormSpritesCreated)
2018-12-08 19:05:03 +01:00
{
LoadSpriteSheet(&sSandstormSpriteSheet);
LoadCustomWeatherSpritePalette(gSandstormWeatherPalette);
for (i = 0; i < NUM_SANDSTORM_SPRITES; i++)
2018-12-08 19:05:03 +01:00
{
spriteId = CreateSpriteAtEnd(&sSandstormSpriteTemplate, 0, (i / 5) * 64, 1);
2018-12-08 19:05:03 +01:00
if (spriteId != MAX_SPRITES)
{
gWeatherPtr->sprites.s2.sandstormSprites1[i] = &gSprites[spriteId];
gWeatherPtr->sprites.s2.sandstormSprites1[i]->tSpriteColumn = i % 5;
gWeatherPtr->sprites.s2.sandstormSprites1[i]->tSpriteRow = i / 5;
2018-12-08 19:05:03 +01:00
}
else
{
gWeatherPtr->sprites.s2.sandstormSprites1[i] = NULL;
}
}
gWeatherPtr->sandstormSpritesCreated = TRUE;
2018-12-08 19:05:03 +01:00
}
}
static const u16 sSwirlEntranceDelays[] = {0, 120, 80, 160, 40, 0};
2018-12-08 19:05:03 +01:00
static void CreateSwirlSandstormSprites(void)
2018-12-08 19:05:03 +01:00
{
u16 i;
u8 spriteId;
2018-12-08 19:05:03 +01:00
if (!gWeatherPtr->sandstormSwirlSpritesCreated)
2018-12-08 19:05:03 +01:00
{
for (i = 0; i < NUM_SWIRL_SANDSTORM_SPRITES; i++)
2018-12-08 19:05:03 +01:00
{
spriteId = CreateSpriteAtEnd(&sSandstormSpriteTemplate, i * 48 + 24, 208, 1);
2018-12-08 19:05:03 +01:00
if (spriteId != MAX_SPRITES)
{
gWeatherPtr->sprites.s2.sandstormSprites2[i] = &gSprites[spriteId];
gWeatherPtr->sprites.s2.sandstormSprites2[i]->oam.size = 2;
gWeatherPtr->sprites.s2.sandstormSprites2[i]->tSpriteRow = i * 51;
gWeatherPtr->sprites.s2.sandstormSprites2[i]->tRadius = 8;
gWeatherPtr->sprites.s2.sandstormSprites2[i]->tRadiusCounter = 0;
gWeatherPtr->sprites.s2.sandstormSprites2[i]->data[4] = 0x6730; // unused value
gWeatherPtr->sprites.s2.sandstormSprites2[i]->tEntranceDelay = sSwirlEntranceDelays[i];
2018-12-08 19:05:03 +01:00
StartSpriteAnim(gWeatherPtr->sprites.s2.sandstormSprites2[i], 1);
CalcCenterToCornerVec(gWeatherPtr->sprites.s2.sandstormSprites2[i], 0, 2, 0);
gWeatherPtr->sprites.s2.sandstormSprites2[i]->callback = WaitSandSwirlSpriteEntrance;
2018-12-08 19:05:03 +01:00
}
else
{
gWeatherPtr->sprites.s2.sandstormSprites2[i] = NULL;
}
gWeatherPtr->sandstormSwirlSpritesCreated = TRUE;
2018-12-08 19:05:03 +01:00
}
}
}
static void UpdateSandstormSprite(struct Sprite *sprite)
2018-12-08 19:05:03 +01:00
{
sprite->pos2.y = gWeatherPtr->sandstormPosY;
sprite->pos1.x = gWeatherPtr->sandstormBaseSpritesX + 32 + sprite->tSpriteColumn * 64;
2018-12-08 19:05:03 +01:00
if (sprite->pos1.x > 271)
{
sprite->pos1.x = gWeatherPtr->sandstormBaseSpritesX + 480 - (4 - sprite->tSpriteColumn) * 64;
2018-12-08 19:05:03 +01:00
sprite->pos1.x &= 0x1FF;
}
}
static void WaitSandSwirlSpriteEntrance(struct Sprite *sprite)
2018-12-08 19:05:03 +01:00
{
if (--sprite->tEntranceDelay == -1)
sprite->callback = UpdateSandstormSwirlSprite;
2018-12-08 19:05:03 +01:00
}
static void UpdateSandstormSwirlSprite(struct Sprite *sprite)
2018-12-08 19:05:03 +01:00
{
u32 x, y;
2018-12-08 19:05:03 +01:00
if (--sprite->pos1.y < -48)
{
sprite->pos1.y = 208;
sprite->tRadius = 4;
2018-12-08 19:05:03 +01:00
}
x = sprite->tRadius * gSineTable[sprite->tWaveIndex];
y = sprite->tRadius * gSineTable[sprite->tWaveIndex + 0x40];
2018-12-08 19:05:03 +01:00
sprite->pos2.x = x >> 8;
sprite->pos2.y = y >> 8;
sprite->tWaveIndex = (sprite->tWaveIndex + 10) & 0xFF;
if (++sprite->tRadiusCounter > 8)
2018-12-08 19:05:03 +01:00
{
sprite->tRadiusCounter = 0;
sprite->tRadius++;
2018-12-08 19:05:03 +01:00
}
}
#undef tSpriteColumn
#undef tSpriteRow
#undef tRadius
#undef tWaveIndex
#undef tRadiusCounter
#undef tEntranceDelay
2018-12-08 19:05:03 +01:00
//------------------------------------------------------------------------------
// Shade
//------------------------------------------------------------------------------
void Shade_InitVars(void)
{
gWeatherPtr->initStep = 0;
gWeatherPtr->gammaTargetIndex = 3;
gWeatherPtr->gammaStepDelay = 20;
}
void Shade_InitAll(void)
{
Shade_InitVars();
}
void Shade_Main(void)
{
}
bool8 Shade_Finish(void)
{
return FALSE;
}
//------------------------------------------------------------------------------
2019-04-01 04:07:29 +02:00
// Bubbles
2018-12-08 19:05:03 +01:00
//------------------------------------------------------------------------------
static void CreateBubbleSprite(u16);
static void DestroyBubbleSprites(void);
static void UpdateBubbleSprite(struct Sprite *);
static const u8 sBubbleStartDelays[] = {40, 90, 60, 90, 2, 60, 40, 30};
2018-12-08 19:05:03 +01:00
static const struct SpriteSheet sWeatherBubbleSpriteSheet =
{
.data = gWeatherBubbleTiles,
.size = sizeof(gWeatherBubbleTiles),
.tag = 0x1205,
};
static const s16 sBubbleStartCoords[][2] =
{
{120, 160},
{376, 160},
{ 40, 140},
{296, 140},
{180, 130},
{436, 130},
{ 60, 160},
{436, 160},
{220, 180},
{476, 180},
{ 10, 90},
{266, 90},
{256, 160},
};
2018-12-08 19:05:03 +01:00
void Bubbles_InitVars(void)
{
Fog1_InitVars();
if (!gWeatherPtr->bubblesSpritesCreated)
2018-12-08 19:05:03 +01:00
{
LoadSpriteSheet(&sWeatherBubbleSpriteSheet);
gWeatherPtr->bubblesDelayIndex = 0;
gWeatherPtr->bubblesDelayCounter = sBubbleStartDelays[0];
gWeatherPtr->bubblesCoordsIndex = 0;
gWeatherPtr->bubblesSpriteCount = 0;
2018-12-08 19:05:03 +01:00
}
}
void Bubbles_InitAll(void)
{
Bubbles_InitVars();
while (!gWeatherPtr->weatherGfxLoaded)
2018-12-08 19:05:03 +01:00
Bubbles_Main();
}
void Bubbles_Main(void)
{
Fog1_Main();
if (++gWeatherPtr->bubblesDelayCounter > sBubbleStartDelays[gWeatherPtr->bubblesDelayIndex])
2018-12-08 19:05:03 +01:00
{
gWeatherPtr->bubblesDelayCounter = 0;
if (++gWeatherPtr->bubblesDelayIndex > ARRAY_COUNT(sBubbleStartDelays) - 1)
gWeatherPtr->bubblesDelayIndex = 0;
CreateBubbleSprite(gWeatherPtr->bubblesCoordsIndex);
if (++gWeatherPtr->bubblesCoordsIndex > ARRAY_COUNT(sBubbleStartCoords) - 1)
gWeatherPtr->bubblesCoordsIndex = 0;
2018-12-08 19:05:03 +01:00
}
}
bool8 Bubbles_Finish(void)
{
if (!Fog1_Finish())
{
DestroyBubbleSprites();
2018-12-08 19:05:03 +01:00
return FALSE;
}
2018-12-08 19:05:03 +01:00
return TRUE;
}
static const union AnimCmd sBubbleSpriteAnimCmd0[] =
2018-12-08 19:05:03 +01:00
{
ANIMCMD_FRAME(0, 16),
ANIMCMD_FRAME(1, 16),
ANIMCMD_END,
};
static const union AnimCmd *const sBubbleSpriteAnimCmds[] =
2018-12-08 19:05:03 +01:00
{
sBubbleSpriteAnimCmd0,
2018-12-08 19:05:03 +01:00
};
static const struct SpriteTemplate sBubbleSpriteTemplate =
2018-12-08 19:05:03 +01:00
{
.tileTag = 0x1205,
2019-04-02 03:04:23 +02:00
.paletteTag = 0x1200,
2018-12-08 19:05:03 +01:00
.oam = &gUnknown_08524904,
.anims = sBubbleSpriteAnimCmds,
2018-12-08 19:05:03 +01:00
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = UpdateBubbleSprite,
2018-12-08 19:05:03 +01:00
};
#define tScrollXCounter data[0]
#define tScrollXDir data[1]
#define tCounter data[2]
2018-12-08 19:05:03 +01:00
static void CreateBubbleSprite(u16 coordsIndex)
{
s16 x = sBubbleStartCoords[coordsIndex][0];
s16 y = sBubbleStartCoords[coordsIndex][1] - gSpriteCoordOffsetY;
u8 spriteId = CreateSpriteAtEnd(&sBubbleSpriteTemplate, x, y, 0);
2018-12-08 19:05:03 +01:00
if (spriteId != MAX_SPRITES)
{
gSprites[spriteId].oam.priority = 1;
gSprites[spriteId].coordOffsetEnabled = TRUE;
gSprites[spriteId].tScrollXCounter = 0;
gSprites[spriteId].tScrollXDir = 0;
gSprites[spriteId].tCounter = 0;
gWeatherPtr->bubblesSpriteCount++;
2018-12-08 19:05:03 +01:00
}
}
static void DestroyBubbleSprites(void)
2018-12-08 19:05:03 +01:00
{
u16 i;
if (gWeatherPtr->bubblesSpriteCount)
2018-12-08 19:05:03 +01:00
{
for (i = 0; i < MAX_SPRITES; i++)
2018-12-08 19:05:03 +01:00
{
if (gSprites[i].template == &sBubbleSpriteTemplate)
2018-12-08 19:05:03 +01:00
DestroySprite(&gSprites[i]);
}
2018-12-08 19:05:03 +01:00
FreeSpriteTilesByTag(0x1205);
gWeatherPtr->bubblesSpriteCount = 0;
2018-12-08 19:05:03 +01:00
}
}
static void UpdateBubbleSprite(struct Sprite *sprite)
2018-12-08 19:05:03 +01:00
{
++sprite->tScrollXCounter;
if (++sprite->tScrollXCounter > 8) // double increment
2018-12-08 19:05:03 +01:00
{
sprite->tScrollXCounter = 0;
if (sprite->tScrollXDir == 0)
2018-12-08 19:05:03 +01:00
{
if (++sprite->pos2.x > 4)
sprite->tScrollXDir = 1;
2018-12-08 19:05:03 +01:00
}
else
{
if (--sprite->pos2.x <= 0)
sprite->tScrollXDir = 0;
2018-12-08 19:05:03 +01:00
}
}
2018-12-08 19:05:03 +01:00
sprite->pos1.y -= 3;
if (++sprite->tCounter >= 120)
2018-12-08 19:05:03 +01:00
DestroySprite(sprite);
}
#undef tScrollXCounter
#undef tScrollXDir
#undef tCounter
2018-12-08 19:43:21 +01:00
//------------------------------------------------------------------------------
// Unused function.
static void UnusedSetCurrentAlternatingWeather(u32 a0, u32 a1)
2018-12-08 19:05:03 +01:00
{
gCurrentAlternatingWeather = a0;
gUnusedWeatherRelated = a1;
2018-12-08 19:05:03 +01:00
}
static void Task_DoAlternatingWeather(u8 taskId)
2018-12-08 19:05:03 +01:00
{
s16 *data = gTasks[taskId].data;
switch (data[0])
{
case 0:
if (data[15]-- <= 0)
{
SetNextWeather(data[1]);
gCurrentAlternatingWeather = data[1];
2018-12-08 19:05:03 +01:00
data[15] = 600;
data[0]++;
}
break;
case 1:
if (data[15]-- <= 0)
{
SetNextWeather(data[2]);
gCurrentAlternatingWeather = data[2];
2018-12-08 19:05:03 +01:00
data[15] = 600;
data[0] = 0;
}
break;
}
}
static void CreateAlternatingWeatherTask(void)
2018-12-08 19:05:03 +01:00
{
u8 taskId = CreateTask(Task_DoAlternatingWeather, 0);
2018-12-08 19:05:03 +01:00
s16 *data = gTasks[taskId].data;
data[15] = 600;
if (gCurrentAlternatingWeather == WEATHER_RAIN_HEAVY)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
data[1] = WEATHER_DROUGHT;
data[2] = WEATHER_RAIN_HEAVY;
2018-12-08 19:05:03 +01:00
}
else if (gCurrentAlternatingWeather == WEATHER_DROUGHT)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
data[1] = WEATHER_RAIN_HEAVY;
data[2] = WEATHER_DROUGHT;
2018-12-08 19:05:03 +01:00
}
else
{
gCurrentAlternatingWeather = WEATHER_RAIN_HEAVY;
2018-12-08 19:43:21 +01:00
data[1] = WEATHER_DROUGHT;
data[2] = WEATHER_RAIN_HEAVY;
2018-12-08 19:05:03 +01:00
}
}
2018-12-08 19:43:21 +01:00
static u8 TranslateWeatherNum(u8);
static void UpdateRainCounter(u8, u8);
2018-12-08 19:05:03 +01:00
void SetSav1Weather(u32 weather)
{
u8 oldWeather = gSaveBlock1Ptr->weather;
gSaveBlock1Ptr->weather = TranslateWeatherNum(weather);
UpdateRainCounter(gSaveBlock1Ptr->weather, oldWeather);
}
u8 GetSav1Weather(void)
{
return gSaveBlock1Ptr->weather;
}
void SetSav1WeatherFromCurrMapHeader(void)
{
u8 oldWeather = gSaveBlock1Ptr->weather;
gSaveBlock1Ptr->weather = TranslateWeatherNum(gMapHeader.weather);
UpdateRainCounter(gSaveBlock1Ptr->weather, oldWeather);
}
void SetWeather(u32 weather)
{
SetSav1Weather(weather);
SetNextWeather(GetSav1Weather());
2018-12-08 19:05:03 +01:00
}
void SetWeather_Unused(u32 weather)
{
SetSav1Weather(weather);
SetCurrentAndNextWeather(GetSav1Weather());
2018-12-08 19:05:03 +01:00
}
void DoCurrentWeather(void)
{
u8 weather = GetSav1Weather();
if (weather == WEATHER_ALTERNATING)
2018-12-08 19:05:03 +01:00
{
if (!FuncIsActiveTask(Task_DoAlternatingWeather))
CreateAlternatingWeatherTask();
weather = gCurrentAlternatingWeather;
2018-12-08 19:05:03 +01:00
}
else
{
if (FuncIsActiveTask(Task_DoAlternatingWeather))
DestroyTask(FindTaskIdByFunc(Task_DoAlternatingWeather));
gCurrentAlternatingWeather = WEATHER_RAIN_HEAVY;
2018-12-08 19:05:03 +01:00
}
SetNextWeather(weather);
2018-12-08 19:05:03 +01:00
}
2019-02-25 08:28:41 +01:00
void ResumePausedWeather(void)
2018-12-08 19:05:03 +01:00
{
u8 weather = GetSav1Weather();
if (weather == WEATHER_ALTERNATING)
2018-12-08 19:05:03 +01:00
{
if (!FuncIsActiveTask(Task_DoAlternatingWeather))
CreateAlternatingWeatherTask();
weather = gCurrentAlternatingWeather;
2018-12-08 19:05:03 +01:00
}
else
{
if (FuncIsActiveTask(Task_DoAlternatingWeather))
DestroyTask(FindTaskIdByFunc(Task_DoAlternatingWeather));
gCurrentAlternatingWeather = WEATHER_RAIN_HEAVY;
2018-12-08 19:05:03 +01:00
}
SetCurrentAndNextWeather(weather);
2018-12-08 19:05:03 +01:00
}
2018-12-08 19:43:21 +01:00
static const u8 sWeatherCycleRoute119[] =
2018-12-08 19:05:03 +01:00
{
WEATHER_SUNNY,
WEATHER_RAIN_LIGHT,
WEATHER_RAIN_MED,
WEATHER_RAIN_LIGHT,
};
2018-12-08 19:43:21 +01:00
static const u8 sWeatherCycleRoute123[] =
2018-12-08 19:05:03 +01:00
{
WEATHER_SUNNY,
WEATHER_SUNNY,
WEATHER_RAIN_LIGHT,
WEATHER_SUNNY,
};
2018-12-08 19:43:21 +01:00
static u8 TranslateWeatherNum(u8 weather)
2018-12-08 19:05:03 +01:00
{
switch (weather)
{
2019-02-25 08:28:41 +01:00
case WEATHER_NONE: return WEATHER_NONE;
case WEATHER_CLOUDS: return WEATHER_CLOUDS;
case WEATHER_SUNNY: return WEATHER_SUNNY;
case WEATHER_RAIN_LIGHT: return WEATHER_RAIN_LIGHT;
case WEATHER_SNOW: return WEATHER_SNOW;
case WEATHER_RAIN_MED: return WEATHER_RAIN_MED;
case WEATHER_FOG_1: return WEATHER_FOG_1;
case WEATHER_ASH: return WEATHER_ASH;
case WEATHER_SANDSTORM: return WEATHER_SANDSTORM;
case WEATHER_FOG_2: return WEATHER_FOG_2;
case WEATHER_FOG_3: return WEATHER_FOG_3;
case WEATHER_SHADE: return WEATHER_SHADE;
case WEATHER_DROUGHT: return WEATHER_DROUGHT;
case WEATHER_RAIN_HEAVY: return WEATHER_RAIN_HEAVY;
case WEATHER_BUBBLES: return WEATHER_BUBBLES;
case WEATHER_ALTERNATING: return WEATHER_ALTERNATING;
2018-12-08 19:05:03 +01:00
case WEATHER_ROUTE119_CYCLE: return sWeatherCycleRoute119[gSaveBlock1Ptr->weatherCycleStage];
case WEATHER_ROUTE123_CYCLE: return sWeatherCycleRoute123[gSaveBlock1Ptr->weatherCycleStage];
2019-02-25 08:28:41 +01:00
default: return WEATHER_NONE;
2018-12-08 19:05:03 +01:00
}
}
void UpdateWeatherPerDay(u16 increment)
{
u16 weatherStage = gSaveBlock1Ptr->weatherCycleStage + increment;
weatherStage %= 4;
gSaveBlock1Ptr->weatherCycleStage = weatherStage;
}
2018-12-08 19:43:21 +01:00
static void UpdateRainCounter(u8 newWeather, u8 oldWeather)
2018-12-08 19:05:03 +01:00
{
if (newWeather != oldWeather
&& (newWeather == WEATHER_RAIN_LIGHT || newWeather == WEATHER_RAIN_MED))
IncrementGameStat(GAME_STAT_GOT_RAINED_ON);
}
2019-04-02 00:31:10 +02:00