summaryrefslogtreecommitdiff
path: root/src/field_weather.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/field_weather.c')
-rw-r--r--src/field_weather.c1152
1 files changed, 1152 insertions, 0 deletions
diff --git a/src/field_weather.c b/src/field_weather.c
new file mode 100644
index 000000000..0be584d51
--- /dev/null
+++ b/src/field_weather.c
@@ -0,0 +1,1152 @@
+#include "global.h"
+#include "constants/songs.h"
+#include "constants/weather.h"
+#include "constants/rgb.h"
+#include "util.h"
+#include "event_object_movement.h"
+#include "field_weather.h"
+#include "main.h"
+#include "menu.h"
+#include "palette.h"
+#include "random.h"
+#include "script.h"
+#include "start_menu.h"
+#include "sound.h"
+#include "sprite.h"
+#include "task.h"
+#include "trig.h"
+#include "gpu_regs.h"
+
+#define MACRO1(color) ((((color) >> 1) & 0xF) | (((color) >> 2) & 0xF0) | (((color) >> 3) & 0xF00))
+
+enum
+{
+ GAMMA_NONE,
+ GAMMA_NORMAL,
+ GAMMA_ALT,
+};
+
+struct RGBColor
+{
+ u16 r:5;
+ u16 g:5;
+ u16 b:5;
+};
+
+struct WeatherPaletteData
+{
+ u16 gammaShiftColors[8][0x1000]; // 0x1000 is the number of bytes that make up all palettes.
+};
+
+struct WeatherCallbacks
+{
+ void (*initVars)(void);
+ void (*main)(void);
+ void (*initAll)(void);
+ bool8 (*finish)(void);
+};
+
+// This file's functions.
+/*static*/ bool8 LightenSpritePaletteInFog(u8);
+/*static*/ void BuildGammaShiftTables(void);
+/*static*/ void UpdateWeatherGammaShift(void);
+/*static*/ void ApplyGammaShift(u8 startPalIndex, u8 numPalettes, s8 gammaIndex);
+/*static*/ void ApplyGammaShiftWithBlend(u8 startPalIndex, u8 numPalettes, s8 gammaIndex, u8 blendCoeff, u16 blendColor);
+/*static*/ void ApplyDroughtGammaShiftWithBlend(s8 gammaIndex, u8 blendCoeff, u16 blendColor);
+/*static*/ void ApplyFogBlend(u8 blendCoeff, u16 blendColor);
+/*static*/ bool8 FadeInScreen_RainShowShade(void);
+/*static*/ bool8 FadeInScreen_Drought(void);
+/*static*/ bool8 FadeInScreen_Fog1(void);
+/*static*/ void FadeInScreenWithWeather(void);
+/*static*/ void DoNothing(void);
+void None_Init(void);
+void None_Main(void);
+bool8 None_Finish(void);
+void Clouds_InitVars(void);
+void Clouds_Main(void);
+void Clouds_InitAll(void);
+bool8 Clouds_Finish(void);
+void Weather2_InitVars(void);
+void Weather2_Main(void);
+void Weather2_InitAll(void);
+bool8 Weather2_Finish(void);
+void LightRain_InitVars(void);
+void LightRain_Main(void);
+void LightRain_InitAll(void);
+bool8 LightRain_Finish(void);
+void Snow_InitVars(void);
+void Snow_Main(void);
+void Snow_InitAll(void);
+bool8 Snow_Finish(void);
+void MedRain_InitVars(void);
+void Rain_Main(void);
+void MedRain_InitAll(void);
+bool8 Rain_Finish(void);
+void Fog1_InitVars(void);
+void Fog1_Main(void);
+void Fog1_InitAll(void);
+bool8 Fog1_Finish(void);
+void Ash_InitVars(void);
+void Ash_Main(void);
+void Ash_InitAll(void);
+bool8 Ash_Finish(void);
+void Sandstorm_InitVars(void);
+void Sandstorm_Main(void);
+void Sandstorm_InitAll(void);
+bool8 Sandstorm_Finish(void);
+void Fog2_InitVars(void);
+void Fog2_Main(void);
+void Fog2_InitAll(void);
+bool8 Fog2_Finish(void);
+void Fog1_InitVars(void);
+void Fog1_Main(void);
+void Fog1_InitAll(void);
+bool8 Fog1_Finish(void);
+void Shade_InitVars(void);
+void Shade_Main(void);
+void Shade_InitAll(void);
+bool8 Shade_Finish(void);
+void Drought_InitVars(void);
+void Drought_Main(void);
+void Drought_InitAll(void);
+bool8 Drought_Finish(void);
+void HeavyRain_InitVars(void);
+void Rain_Main(void);
+void HeavyRain_InitAll(void);
+bool8 Rain_Finish(void);
+void Bubbles_InitVars(void);
+void Bubbles_Main(void);
+void Bubbles_InitAll(void);
+bool8 Bubbles_Finish(void);
+
+// Const rom data
+
+// This is a pointer to gWeather. All code in this file accesses gWeather directly,
+// while code in other field weather files accesses gWeather through this pointer.
+// This is likely the result of compiler optimization, since using the pointer in
+// this file produces the same result as accessing gWeather directly.
+struct Weather *const gWeatherPtr = &gWeather;
+
+/*static*/ const struct WeatherCallbacks sWeatherFuncs[] =
+{
+ {None_Init, None_Main, None_Init, None_Finish},
+ {Clouds_InitVars, Clouds_Main, Clouds_InitAll, Clouds_Finish},
+ {Weather2_InitVars, Weather2_Main, Weather2_InitAll, Weather2_Finish},
+ {LightRain_InitVars, LightRain_Main, LightRain_InitAll, LightRain_Finish},
+ {Snow_InitVars, Snow_Main, Snow_InitAll, Snow_Finish},
+ {MedRain_InitVars, Rain_Main, MedRain_InitAll, Rain_Finish},
+ {Fog1_InitVars, Fog1_Main, Fog1_InitAll, Fog1_Finish},
+ {Ash_InitVars, Ash_Main, Ash_InitAll, Ash_Finish},
+ {Sandstorm_InitVars, Sandstorm_Main, Sandstorm_InitAll, Sandstorm_Finish},
+ {Fog2_InitVars, Fog2_Main, Fog2_InitAll, Fog2_Finish},
+ {Fog1_InitVars, Fog1_Main, Fog1_InitAll, Fog1_Finish},
+ {Shade_InitVars, Shade_Main, Shade_InitAll, Shade_Finish},
+ {Drought_InitVars, Drought_Main, Drought_InitAll, Drought_Finish},
+ {HeavyRain_InitVars, Rain_Main, HeavyRain_InitAll, Rain_Finish},
+ {Bubbles_InitVars, Bubbles_Main, Bubbles_InitAll, Bubbles_Finish},
+};
+
+void (*const gWeatherPalStateFuncs[])(void) =
+{
+ UpdateWeatherGammaShift, // WEATHER_PAL_STATE_CHANGING_WEATHER
+ FadeInScreenWithWeather, // WEATHER_PAL_STATE_SCREEN_FADING_IN
+ DoNothing, // WEATHER_PAL_STATE_SCREEN_FADING_OUT
+ DoNothing, // WEATHER_PAL_STATE_IDLE
+};
+
+// This table specifies which of the gamma shift tables should be
+// applied to each of the background and sprite palettes.
+/*static*/ const u8 sBasePaletteGammaTypes[32] =
+{
+ // background palettes
+ GAMMA_NORMAL,
+ GAMMA_NORMAL,
+ GAMMA_NORMAL,
+ GAMMA_NORMAL,
+ GAMMA_NORMAL,
+ GAMMA_NORMAL,
+ GAMMA_NORMAL,
+ GAMMA_NORMAL,
+ GAMMA_NORMAL,
+ GAMMA_NORMAL,
+ GAMMA_NORMAL,
+ GAMMA_NORMAL,
+ GAMMA_NORMAL,
+ GAMMA_NORMAL,
+ GAMMA_NONE,
+ GAMMA_NONE,
+ // sprite palettes
+ GAMMA_ALT,
+ GAMMA_NORMAL,
+ GAMMA_ALT,
+ GAMMA_ALT,
+ GAMMA_ALT,
+ GAMMA_ALT,
+ GAMMA_NORMAL,
+ GAMMA_NORMAL,
+ GAMMA_NORMAL,
+ GAMMA_NORMAL,
+ GAMMA_ALT,
+ GAMMA_NORMAL,
+ GAMMA_NORMAL,
+ GAMMA_NORMAL,
+ GAMMA_NORMAL,
+ GAMMA_NORMAL,
+};
+
+
+// EWRAM
+EWRAM_DATA struct Weather gWeather = {0};
+EWRAM_DATA u8 gFieldEffectPaletteGammaTypes[32] = {0};
+
+// IWRAM bss
+IWRAM_DATA const u8 *sPaletteGammaTypes;
+IWRAM_DATA u32 filler_03000f54;
+
+// const
+extern const u16 gUnknown_083970E8[];
+extern const u16 gUnknown_0854014C[][4096];
+
+// code
+void StartWeather(void)
+{
+ if (!FuncIsActiveTask(Task_WeatherMain))
+ {
+ u8 index = AllocSpritePalette(0x1200);
+ CpuCopy32(gUnknown_083970E8, &gPlttBufferUnfaded[0x100 + index * 16], 32);
+ BuildGammaShiftTables();
+ gWeather.altGammaSpritePalIndex = index;
+ gWeather.weatherPicSpritePalIndex = AllocSpritePalette(0x1201);
+ gWeather.rainSpriteCount = 0;
+ gWeather.unknown_6D8 = 0;
+ gWeather.cloudSpritesCreated = 0;
+ gWeather.snowflakeSpriteCount = 0;
+ gWeather.ashSpritesCreated = 0;
+ gWeather.fog1SpritesCreated = 0;
+ gWeather.fog2SpritesCreated = 0;
+ gWeather.sandstormSprites1Created = 0;
+ gWeather.sandstormSprites2Created = 0;
+ gWeather.unknown_72E = 0;
+ gWeather.lightenedFogSpritePalsCount = 0;
+ Weather_SetBlendCoeffs(16, 0);
+ gWeather.currWeather = 0;
+ gWeather.palProcessingState = WEATHER_PAL_STATE_IDLE;
+ gWeather.readyForInit = FALSE;
+ gWeather.weatherChangeComplete = TRUE;
+ gWeather.taskId = CreateTask(Task_WeatherInit, 80);
+ }
+}
+
+void ChangeWeather(u8 weather)
+{
+ if (weather != WEATHER_RAIN_LIGHT && weather != WEATHER_RAIN_MED && weather != WEATHER_RAIN_HEAVY)
+ {
+ PlayRainSoundEffect();
+ }
+
+ if (gWeather.nextWeather != weather && gWeather.currWeather == weather)
+ {
+ sWeatherFuncs[weather].initVars();
+ }
+
+ gWeather.weatherChangeComplete = FALSE;
+ gWeather.nextWeather = weather;
+ gWeather.finishStep = 0;
+}
+
+void sub_80AB104(u8 weather)
+{
+ PlayRainSoundEffect();
+ gWeather.currWeather = weather;
+ gWeather.nextWeather = weather;
+}
+
+void sub_80AB130(u8 weather)
+{
+ PlayRainSoundEffect();
+ gWeather.currWeather = weather;
+ gWeather.nextWeather = weather;
+ gWeather.readyForInit = TRUE;
+}
+
+void Task_WeatherInit(u8 taskId)
+{
+ // Waits until it's ok to initialize weather.
+ // When the screen fades in, this is set to TRUE.
+ if (gWeather.readyForInit)
+ {
+ sWeatherFuncs[gWeather.currWeather].initAll();
+ gTasks[taskId].func = Task_WeatherMain;
+ }
+}
+
+void Task_WeatherMain(u8 taskId)
+{
+ if (gWeather.currWeather != gWeather.nextWeather)
+ {
+ if (!sWeatherFuncs[gWeather.currWeather].finish() && gWeather.palProcessingState != WEATHER_PAL_STATE_SCREEN_FADING_OUT)
+ {
+ // Finished cleaning up previous weather. Now transition to next weather.
+ sWeatherFuncs[gWeather.nextWeather].initVars();
+ gWeather.gammaStepFrameCounter = 0;
+ gWeather.palProcessingState = WEATHER_PAL_STATE_CHANGING_WEATHER;
+ gWeather.currWeather = gWeather.nextWeather;
+ gWeather.weatherChangeComplete = TRUE;
+ }
+ }
+ else
+ {
+ sWeatherFuncs[gWeather.currWeather].main();
+ }
+
+ gWeatherPalStateFuncs[gWeather.palProcessingState]();
+}
+
+void None_Init(void)
+{
+ gWeather.gammaTargetIndex = 0;
+ gWeather.gammaStepDelay = 0;
+}
+
+void None_Main(void)
+{
+}
+
+u8 None_Finish(void)
+{
+ return 0;
+}
+
+// Builds two tables that contain gamma shifts for palette colors.
+// It's unclear why the two tables aren't declared as const arrays, since
+// this function always builds the same two tables.
+/*static*/ void BuildGammaShiftTables(void)
+{
+ u16 v0;
+ u8 (*v1)[32];
+ u16 v2;
+ u16 v4;
+ u16 v5;
+ u16 v6;
+ u16 v9;
+ u32 v10;
+ u16 v11;
+ s16 dunno;
+
+ sPaletteGammaTypes = sBasePaletteGammaTypes;
+ for (v0 = 0; v0 <= 1; v0++)
+ {
+ if (v0 == 0)
+ v1 = gWeather.gammaShifts;
+ else
+ v1 = gWeather.altGammaShifts;
+
+ for (v2 = 0; v2 < 32; v2++)
+ {
+ v4 = v2 << 8;
+ if (v0 == 0)
+ v5 = (v2 << 8) / 16;
+ else
+ v5 = 0;
+ for (v6 = 0; v6 <= 2; v6++)
+ {
+ v4 = (v4 - v5);
+ v1[v6][v2] = v4 >> 8;
+ }
+ v9 = v4;
+ v10 = 0x1f00 - v4;
+ if ((0x1f00 - v4) < 0)
+ {
+ v10 += 0xf;
+ }
+ v11 = v10 >> 4;
+ if (v2 < 12)
+ {
+ for (; v6 < 19; v6++)
+ {
+ v4 += v11;
+ dunno = v4 - v9;
+ if (dunno > 0)
+ v4 -= (dunno + ((u16)dunno >> 15)) >> 1;
+ v1[v6][v2] = v4 >> 8;
+ if (v1[v6][v2] > 0x1f)
+ v1[v6][v2] = 0x1f;
+ }
+ }
+ else
+ {
+ for (; v6 < 19; v6++)
+ {
+ v4 += v11;
+ v1[v6][v2] = v4 >> 8;
+ if (v1[v6][v2] > 0x1f)
+ v1[v6][v2] = 0x1f;
+ }
+ }
+ }
+ }
+}
+
+// When the weather is changing, it gradually updates the palettes
+// towards the desired gamma shift.
+/*static*/ void UpdateWeatherGammaShift(void)
+{
+ if (gWeather.palProcessingState != WEATHER_PAL_STATE_SCREEN_FADING_OUT)
+ {
+ if (gWeather.gammaIndex == gWeather.gammaTargetIndex)
+ {
+ gWeather.palProcessingState = WEATHER_PAL_STATE_IDLE;
+ }
+ else
+ {
+ if (++gWeather.gammaStepFrameCounter >= gWeather.gammaStepDelay)
+ {
+ gWeather.gammaStepFrameCounter = 0;
+ if (gWeather.gammaIndex < gWeather.gammaTargetIndex)
+ gWeather.gammaIndex++;
+ else
+ gWeather.gammaIndex--;
+
+ ApplyGammaShift(0, 32, gWeather.gammaIndex);
+ }
+ }
+ }
+}
+
+/*static*/ void FadeInScreenWithWeather(void)
+{
+ if (++gWeather.unknown_6CB > 1)
+ gWeather.unknown_6CA = 0;
+
+ switch (gWeather.currWeather)
+ {
+ case WEATHER_RAIN_LIGHT:
+ case WEATHER_RAIN_MED:
+ case WEATHER_RAIN_HEAVY:
+ case WEATHER_SNOW:
+ case WEATHER_SHADE:
+ if (FadeInScreen_RainShowShade() == FALSE)
+ {
+ gWeather.gammaIndex = 3;
+ gWeather.palProcessingState = WEATHER_PAL_STATE_IDLE;
+ }
+ break;
+ case WEATHER_DROUGHT:
+ if (FadeInScreen_Drought() == FALSE)
+ {
+ gWeather.gammaIndex = -6;
+ gWeather.palProcessingState = WEATHER_PAL_STATE_IDLE;
+ }
+ break;
+ case WEATHER_FOG_1:
+ if (FadeInScreen_Fog1() == FALSE)
+ {
+ gWeather.gammaIndex = 0;
+ gWeather.palProcessingState = WEATHER_PAL_STATE_IDLE;
+ }
+ break;
+ case WEATHER_ASH:
+ case WEATHER_SANDSTORM:
+ case WEATHER_FOG_2:
+ case WEATHER_FOG_3:
+ default:
+ if (!gPaletteFade.active)
+ {
+ gWeather.gammaIndex = gWeather.gammaTargetIndex;
+ gWeather.palProcessingState = WEATHER_PAL_STATE_IDLE;
+ }
+ break;
+ }
+}
+
+bool8 FadeInScreen_RainShowShade(void)
+{
+ if (gWeather.fadeScreenCounter == 16)
+ return FALSE;
+
+ if (++gWeather.fadeScreenCounter >= 16)
+ {
+ ApplyGammaShift(0, 32, 3);
+ gWeather.fadeScreenCounter = 16;
+ return FALSE;
+ }
+
+ ApplyGammaShiftWithBlend(0, 32, 3, 16 - gWeather.fadeScreenCounter, gWeather.fadeDestColor);
+ return TRUE;
+}
+
+bool8 FadeInScreen_Drought(void)
+{
+ if (gWeather.fadeScreenCounter == 16)
+ return FALSE;
+
+ if (++gWeather.fadeScreenCounter >= 16)
+ {
+ ApplyGammaShift(0, 32, -6);
+ gWeather.fadeScreenCounter = 16;
+ return FALSE;
+ }
+
+ ApplyDroughtGammaShiftWithBlend(-6, 16 - gWeather.fadeScreenCounter, gWeather.fadeDestColor);
+ return TRUE;
+}
+
+bool8 FadeInScreen_Fog1(void)
+{
+ if (gWeather.fadeScreenCounter == 16)
+ return FALSE;
+
+ gWeather.fadeScreenCounter++;
+ ApplyFogBlend(16 - gWeather.fadeScreenCounter, gWeather.fadeDestColor);
+ return TRUE;
+}
+
+/*static*/ void DoNothing(void)
+{ }
+
+/*static*/ void ApplyGammaShift(u8 startPalIndex, u8 numPalettes, s8 gammaIndex)
+{
+ u16 curPalIndex;
+ u16 palOffset;
+ u8 *gammaTable;
+ u16 i;
+
+ if (gammaIndex > 0)
+ {
+ gammaIndex--;
+ palOffset = startPalIndex * 16;
+ numPalettes += startPalIndex;
+ curPalIndex = startPalIndex;
+
+ // Loop through the speficied palette range and apply necessary gamma shifts to the colors.
+ while (curPalIndex < numPalettes)
+ {
+ if (sPaletteGammaTypes[curPalIndex] == GAMMA_NONE)
+ {
+ // No palette change.
+ CpuFastCopy(gPlttBufferUnfaded + palOffset, gPlttBufferFaded + palOffset, 16 * sizeof(u16));
+ palOffset += 16;
+ }
+ else
+ {
+ u8 r, g, b;
+
+ if (sPaletteGammaTypes[curPalIndex] == GAMMA_ALT || curPalIndex - 16 == gWeather.altGammaSpritePalIndex)
+ gammaTable = gWeather.altGammaShifts[gammaIndex];
+ else
+ gammaTable = gWeather.gammaShifts[gammaIndex];
+
+ for (i = 0; i < 16; i++)
+ {
+ // Apply gamma shift to the original color.
+ struct RGBColor baseColor = *(struct RGBColor *)&gPlttBufferUnfaded[palOffset];
+ r = gammaTable[baseColor.r];
+ g = gammaTable[baseColor.g];
+ b = gammaTable[baseColor.b];
+ gPlttBufferFaded[palOffset++] = (b << 10) | (g << 5) | r;
+ }
+ }
+
+ curPalIndex++;
+ }
+ }
+ else if (gammaIndex < 0)
+ {
+ // A negative gammIndex value means that the blending will come from the special Drought weather's palette tables.
+ gammaIndex = -gammaIndex - 1;
+ palOffset = startPalIndex * 16;
+ numPalettes += startPalIndex;
+ curPalIndex = startPalIndex;
+
+ while (curPalIndex < numPalettes)
+ {
+ if (sPaletteGammaTypes[curPalIndex] == GAMMA_NONE)
+ {
+ // No palette change.
+ CpuFastCopy(gPlttBufferUnfaded + palOffset, gPlttBufferFaded + palOffset, 16 * sizeof(u16));
+ palOffset += 16;
+ }
+ else
+ {
+ for (i = 0; i < 16; i++)
+ {
+ gPlttBufferFaded[palOffset] = gUnknown_0854014C[gammaIndex][MACRO1(gPlttBufferUnfaded[palOffset])];
+ palOffset++;
+ }
+ }
+
+ curPalIndex++;
+ }
+ }
+ else
+ {
+ // No palette blending.
+ CpuFastCopy(gPlttBufferUnfaded + startPalIndex * 16, gPlttBufferFaded + startPalIndex * 16, numPalettes * 16 * sizeof(u16));
+ }
+}
+
+/*static*/ void ApplyGammaShiftWithBlend(u8 startPalIndex, u8 numPalettes, s8 gammaIndex, u8 blendCoeff, u16 blendColor)
+{
+ u16 palOffset;
+ u16 curPalIndex;
+ u16 i;
+ struct RGBColor color = *(struct RGBColor *)&blendColor;
+ u8 rBlend = color.r;
+ u8 gBlend = color.g;
+ u8 bBlend = color.b;
+
+ palOffset = startPalIndex * 16;
+ numPalettes += startPalIndex;
+ gammaIndex--;
+ curPalIndex = startPalIndex;
+
+ while (curPalIndex < numPalettes)
+ {
+ if (sPaletteGammaTypes[curPalIndex] == GAMMA_NONE)
+ {
+ // No gamma shift. Simply blend the colors.
+ BlendPalette(palOffset, 16, blendCoeff, blendColor);
+ palOffset += 16;
+ }
+ else
+ {
+ u8 *gammaTable;
+
+ if (sPaletteGammaTypes[curPalIndex] == GAMMA_NORMAL)
+ gammaTable = gWeather.gammaShifts[gammaIndex];
+ else
+ gammaTable = gWeather.altGammaShifts[gammaIndex];
+
+ for (i = 0; i < 16; i++)
+ {
+ struct RGBColor baseColor = *(struct RGBColor *)&gPlttBufferUnfaded[palOffset];
+ u8 r = gammaTable[baseColor.r];
+ u8 g = gammaTable[baseColor.g];
+ u8 b = gammaTable[baseColor.b];
+
+ // Apply gamma shift and target blend color to the original color.
+ r += ((rBlend - r) * blendCoeff) >> 4;
+ g += ((gBlend - g) * blendCoeff) >> 4;
+ b += ((bBlend - b) * blendCoeff) >> 4;
+ gPlttBufferFaded[palOffset++] = (b << 10) | (g << 5) | r;
+ }
+ }
+
+ curPalIndex++;
+ }
+}
+
+void ApplyDroughtGammaShiftWithBlend(s8 gammaIndex, u8 blendCoeff, u16 blendColor)
+{
+ struct RGBColor color;
+ u8 rBlend;
+ u8 gBlend;
+ u8 bBlend;
+ u16 curPalIndex;
+ u16 palOffset;
+ u16 i;
+
+ gammaIndex = -gammaIndex - 1;
+ color = *(struct RGBColor *)&blendColor;
+ rBlend = color.r;
+ gBlend = color.g;
+ bBlend = color.b;
+ palOffset = 0;
+ for (curPalIndex = 0; curPalIndex < 32; curPalIndex++)
+ {
+ if (sPaletteGammaTypes[curPalIndex] == GAMMA_NONE)
+ {
+ // No gamma shift. Simply blend the colors.
+ BlendPalette(palOffset, 16, blendCoeff, blendColor);
+ palOffset += 16;
+ }
+ else
+ {
+ for (i = 0; i < 16; i++)
+ {
+ u32 offset;
+ struct RGBColor color1;
+ struct RGBColor color2;
+ u8 r1, g1, b1;
+ u8 r2, g2, b2;
+
+ color1 = *(struct RGBColor *)&gPlttBufferUnfaded[palOffset];
+ r1 = color1.r;
+ g1 = color1.g;
+ b1 = color1.b;
+
+ offset = ((b1 & 0x1E) << 7) | ((g1 & 0x1E) << 3) | ((r1 & 0x1E) >> 1);
+ color2 = *(struct RGBColor *)&gUnknown_0854014C[gammaIndex][offset];
+ r2 = color2.r;
+ g2 = color2.g;
+ b2 = color2.b;
+
+ r2 += ((rBlend - r2) * blendCoeff) >> 4;
+ g2 += ((gBlend - g2) * blendCoeff) >> 4;
+ b2 += ((bBlend - b2) * blendCoeff) >> 4;
+
+ gPlttBufferFaded[palOffset++] = (b2 << 10) | (g2 << 5) | r2;
+ }
+ }
+ }
+}
+
+void ApplyFogBlend(u8 blendCoeff, u16 blendColor)
+{
+ struct RGBColor color;
+ u8 rBlend;
+ u8 gBlend;
+ u8 bBlend;
+ u16 curPalIndex;
+
+ BlendPalette(0, 256, blendCoeff, blendColor);
+ color = *(struct RGBColor *)&blendColor;
+ rBlend = color.r;
+ gBlend = color.g;
+ bBlend = color.b;
+
+ for (curPalIndex = 16; curPalIndex < 32; curPalIndex++)
+ {
+ if (LightenSpritePaletteInFog(curPalIndex))
+ {
+ u16 palEnd = (curPalIndex + 1) * 16;
+ u16 palOffset = curPalIndex * 16;
+
+ while (palOffset < palEnd)
+ {
+ struct RGBColor color = *(struct RGBColor *)&gPlttBufferUnfaded[palOffset];
+ u8 r = color.r;
+ u8 g = color.g;
+ u8 b = color.b;
+
+ r += ((28 - r) * 3) >> 2;
+ g += ((31 - g) * 3) >> 2;
+ b += ((28 - b) * 3) >> 2;
+
+ r += ((rBlend - r) * blendCoeff) >> 4;
+ g += ((gBlend - g) * blendCoeff) >> 4;
+ b += ((bBlend - b) * blendCoeff) >> 4;
+
+ gPlttBufferFaded[palOffset] = (b << 10) | (g << 5) | r;
+ palOffset++;
+ }
+ }
+ else
+ {
+ BlendPalette(curPalIndex * 16, 16, blendCoeff, blendColor);
+ }
+ }
+}
+
+/*static*/ void MarkFogSpritePalToLighten(u8 paletteIndex)
+{
+ if (gWeather.lightenedFogSpritePalsCount < 6)
+ {
+ gWeather.lightenedFogSpritePals[gWeather.lightenedFogSpritePalsCount] = paletteIndex;
+ gWeather.lightenedFogSpritePalsCount++;
+ }
+}
+
+/*static*/ bool8 LightenSpritePaletteInFog(u8 paletteIndex)
+{
+ u16 i;
+
+ for (i = 0; i < gWeather.lightenedFogSpritePalsCount; i++)
+ {
+ if (gWeather.lightenedFogSpritePals[i] == paletteIndex)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void sub_80ABC48(s8 gammaIndex)
+{
+ if (gWeather.palProcessingState == WEATHER_PAL_STATE_IDLE)
+ {
+ ApplyGammaShift(0, 32, gammaIndex);
+ gWeather.gammaIndex = gammaIndex;
+ }
+}
+
+void sub_80ABC7C(u8 gammaIndex, u8 gammaTargetIndex, u8 gammaStepDelay)
+{
+ if (gWeather.palProcessingState == WEATHER_PAL_STATE_IDLE)
+ {
+ gWeather.palProcessingState = WEATHER_PAL_STATE_CHANGING_WEATHER;
+ gWeather.gammaIndex = gammaIndex;
+ gWeather.gammaTargetIndex = gammaTargetIndex;
+ gWeather.gammaStepFrameCounter = 0;
+ gWeather.gammaStepDelay = gammaStepDelay;
+ sub_80ABC48(gammaIndex);
+ }
+}
+
+void FadeScreen(u8 mode, s8 delay)
+{
+ u32 fadeColor;
+ bool8 fadeOut;
+ bool8 useWeatherPal;
+
+ switch (mode)
+ {
+ case FADE_FROM_BLACK:
+ fadeColor = 0;
+ fadeOut = FALSE;
+ break;
+ case FADE_FROM_WHITE:
+ fadeColor = 0xFFFF;
+ fadeOut = FALSE;
+ break;
+ case FADE_TO_BLACK:
+ fadeColor = 0;
+ fadeOut = TRUE;
+ break;
+ case FADE_TO_WHITE:
+ fadeColor = 0xFFFF;
+ fadeOut = TRUE;
+ break;
+ default:
+ return;
+ }
+
+ switch (gWeather.currWeather)
+ {
+ case WEATHER_RAIN_LIGHT:
+ case WEATHER_RAIN_MED:
+ case WEATHER_RAIN_HEAVY:
+ case WEATHER_SNOW:
+ case WEATHER_FOG_1:
+ case WEATHER_SHADE:
+ case WEATHER_DROUGHT:
+ useWeatherPal = TRUE;
+ break;
+ default:
+ useWeatherPal = FALSE;
+ break;
+ }
+
+ if (fadeOut)
+ {
+ if (useWeatherPal)
+ CpuFastCopy(gPlttBufferFaded, gPlttBufferUnfaded, 0x400);
+
+ BeginNormalPaletteFade(0xFFFFFFFF, delay, 0, 16, fadeColor);
+ gWeather.palProcessingState = WEATHER_PAL_STATE_SCREEN_FADING_OUT;
+ }
+ else
+ {
+ gWeather.fadeDestColor = fadeColor;
+ if (useWeatherPal)
+ gWeather.fadeScreenCounter = 0;
+ else
+ BeginNormalPaletteFade(0xFFFFFFFF, delay, 16, 0, fadeColor);
+
+ gWeather.palProcessingState = WEATHER_PAL_STATE_SCREEN_FADING_IN;
+ gWeather.unknown_6CA = 1;
+ gWeather.unknown_6CB = 0;
+ Weather_SetBlendCoeffs(gWeather.currBlendEVA, gWeather.currBlendEVB);
+ gWeather.readyForInit = TRUE;
+ }
+}
+
+bool8 IsWeatherNotFadingIn(void)
+{
+ return (gWeather.palProcessingState != WEATHER_PAL_STATE_SCREEN_FADING_IN);
+}
+
+void UpdateSpritePaletteWithWeather(u8 spritePaletteIndex)
+{
+ u16 paletteIndex = 16 + spritePaletteIndex;
+ u16 i;
+
+ switch (gWeather.palProcessingState)
+ {
+ case WEATHER_PAL_STATE_SCREEN_FADING_IN:
+ if (gWeather.unknown_6CA != 0)
+ {
+ if (gWeather.currWeather == WEATHER_FOG_1)
+ MarkFogSpritePalToLighten(paletteIndex);
+ paletteIndex *= 16;
+ for (i = 0; i < 16; i++)
+ gPlttBufferFaded[paletteIndex + i] = gWeather.fadeDestColor;
+ }
+ break;
+ case WEATHER_PAL_STATE_SCREEN_FADING_OUT:
+ paletteIndex *= 16;
+ CpuFastCopy(gPlttBufferFaded + paletteIndex, gPlttBufferUnfaded + paletteIndex, 32);
+ BlendPalette(paletteIndex, 16, gPaletteFade.y, gPaletteFade.blendColor);
+ break;
+ // WEATHER_PAL_STATE_CHANGING_WEATHER
+ // WEATHER_PAL_STATE_CHANGING_IDLE
+ default:
+ if (gWeather.currWeather != WEATHER_FOG_1)
+ {
+ ApplyGammaShift(paletteIndex, 1, gWeather.gammaIndex);
+ }
+ else
+ {
+ paletteIndex *= 16;
+ BlendPalette(paletteIndex, 16, 12, RGB(28, 31, 28));
+ }
+ break;
+ }
+}
+
+void ApplyWeatherGammaShiftToPal(u8 paletteIndex)
+{
+ ApplyGammaShift(paletteIndex, 1, gWeather.gammaIndex);
+}
+
+u8 sub_80ABF20(void)
+{
+ if (gWeather.palProcessingState == WEATHER_PAL_STATE_SCREEN_FADING_IN)
+ return gWeather.unknown_6CA;
+ else
+ return 0;
+}
+
+void LoadCustomWeatherSpritePalette(const u16 *palette)
+{
+ LoadPalette(palette, 0x100 + gWeather.weatherPicSpritePalIndex * 16, 32);
+ UpdateSpritePaletteWithWeather(gWeather.weatherPicSpritePalIndex);
+}
+
+void LoadDroughtWeatherPalette(u8 *gammaIndexPtr, u8 *a1)
+{
+ *gammaIndexPtr = 0x20;
+ *a1 = 0x20;
+}
+
+void ResetDroughtWeatherPaletteLoading(void)
+{
+ gWeather.loadDroughtPalsIndex = 1;
+ gWeather.loadDroughtPalsOffset = 1;
+}
+
+bool8 LoadDroughtWeatherPalettes(void)
+{
+ if (gWeather.loadDroughtPalsIndex < 32)
+ {
+ LoadDroughtWeatherPalette(&gWeather.loadDroughtPalsIndex, &gWeather.loadDroughtPalsOffset);
+ if (gWeather.loadDroughtPalsIndex < 32)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void sub_80ABFE0(s8 gammaIndex)
+{
+ sub_80ABC48(-gammaIndex - 1);
+}
+
+void sub_80ABFF0(void)
+{
+ gWeather.unknown_73C = 0;
+ gWeather.unknown_740 = 0;
+ gWeather.unknown_742 = 0;
+ gWeather.unknown_73E = 0;
+}
+
+void sub_80AC01C(void)
+{
+ switch (gWeather.unknown_742)
+ {
+ case 0:
+ if (++gWeather.unknown_740 > 5)
+ {
+ gWeather.unknown_740 = 0;
+ sub_80ABFE0(gWeather.unknown_73C++);
+ if (gWeather.unknown_73C > 5)
+ {
+ gWeather.unknown_73E = gWeather.unknown_73C;
+ gWeather.unknown_742 = 1;
+ gWeather.unknown_740 = 0x3C;
+ }
+ }
+ break;
+ case 1:
+ gWeather.unknown_740 = (gWeather.unknown_740 + 3) & 0x7F;
+ gWeather.unknown_73C = ((gSineTable[gWeather.unknown_740] - 1) >> 6) + 2;
+ if (gWeather.unknown_73C != gWeather.unknown_73E)
+ sub_80ABFE0(gWeather.unknown_73C);
+ gWeather.unknown_73E = gWeather.unknown_73C;
+ break;
+ case 2:
+ if (++gWeather.unknown_740 > 5)
+ {
+ gWeather.unknown_740 = 0;
+ sub_80ABFE0(--gWeather.unknown_73C);
+ if (gWeather.unknown_73C == 3)
+ gWeather.unknown_742 = 0;
+ }
+ break;
+ }
+}
+
+void Weather_SetBlendCoeffs(u8 eva, u8 evb)
+{
+ gWeather.currBlendEVA = eva;
+ gWeather.currBlendEVB = evb;
+ gWeather.targetBlendEVA = eva;
+ gWeather.targetBlendEVB = evb;
+ SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(eva, evb));
+}
+
+void Weather_SetTargetBlendCoeffs(u8 eva, u8 evb, int delay)
+{
+ gWeather.targetBlendEVA = eva;
+ gWeather.targetBlendEVB = evb;
+ gWeather.blendDelay = delay;
+ gWeather.blendFrameCounter = 0;
+ gWeather.blendUpdateCounter = 0;
+}
+
+bool8 Weather_UpdateBlend(void)
+{
+ if (gWeather.currBlendEVA == gWeather.targetBlendEVA
+ && gWeather.currBlendEVB == gWeather.targetBlendEVB)
+ return TRUE;
+
+ if (++gWeather.blendFrameCounter > gWeather.blendDelay)
+ {
+ gWeather.blendFrameCounter = 0;
+ gWeather.blendUpdateCounter++;
+
+ // Update currBlendEVA and currBlendEVB on alternate frames
+ if (gWeather.blendUpdateCounter & 1)
+ {
+ if (gWeather.currBlendEVA < gWeather.targetBlendEVA)
+ gWeather.currBlendEVA++;
+ else if (gWeather.currBlendEVA > gWeather.targetBlendEVA)
+ gWeather.currBlendEVA--;
+ }
+ else
+ {
+ if (gWeather.currBlendEVB < gWeather.targetBlendEVB)
+ gWeather.currBlendEVB++;
+ else if (gWeather.currBlendEVB > gWeather.targetBlendEVB)
+ gWeather.currBlendEVB--;
+ }
+ }
+
+ SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(gWeather.currBlendEVA, gWeather.currBlendEVB));
+
+ if (gWeather.currBlendEVA == gWeather.targetBlendEVA
+ && gWeather.currBlendEVB == gWeather.targetBlendEVB)
+ return TRUE;
+
+ return FALSE;
+}
+
+void sub_80AC274(u8 a)
+{
+ switch (a)
+ {
+ case 1:
+ SetWeather(WEATHER_CLOUDS);
+ break;
+ case 2:
+ SetWeather(WEATHER_SUNNY);
+ break;
+ case 3:
+ SetWeather(WEATHER_RAIN_LIGHT);
+ break;
+ case 4:
+ SetWeather(WEATHER_SNOW);
+ break;
+ case 5:
+ SetWeather(WEATHER_RAIN_MED);
+ break;
+ case 6:
+ SetWeather(WEATHER_FOG_1);
+ break;
+ case 7:
+ SetWeather(WEATHER_FOG_2);
+ break;
+ case 8:
+ SetWeather(WEATHER_ASH);
+ break;
+ case 9:
+ SetWeather(WEATHER_SANDSTORM);
+ break;
+ case 10:
+ SetWeather(WEATHER_SHADE);
+ break;
+ }
+}
+
+u8 GetCurrentWeather(void)
+{
+ return gWeather.currWeather;
+}
+
+void SetRainStrengthFromSoundEffect(u16 soundEffect)
+{
+ if (gWeather.palProcessingState != WEATHER_PAL_STATE_SCREEN_FADING_OUT)
+ {
+ switch (soundEffect)
+ {
+ case SE_T_KOAME:
+ gWeather.rainStrength = 0;
+ break;
+ case SE_T_OOAME:
+ gWeather.rainStrength = 1;
+ break;
+ case SE_T_AME:
+ gWeather.rainStrength = 2;
+ break;
+ default:
+ return;
+ }
+
+ PlaySE(soundEffect);
+ }
+}
+
+void PlayRainSoundEffect(void)
+{
+ if (IsSpecialSEPlaying())
+ {
+ switch (gWeather.rainStrength)
+ {
+ case 0:
+ PlaySE(SE_T_KOAME_E);
+ break;
+ case 1:
+ PlaySE(SE_T_OOAME_E);
+ break;
+ case 2:
+ default:
+ PlaySE(SE_T_AME_E);
+ break;
+ }
+ }
+}
+
+u8 IsWeatherChangeComplete(void)
+{
+ return gWeather.weatherChangeComplete;
+}
+
+void SetWeatherScreenFadeOut(void)
+{
+ gWeather.palProcessingState = WEATHER_PAL_STATE_SCREEN_FADING_OUT;
+}
+
+void sub_80AC3E4(void)
+{
+ gWeather.palProcessingState = WEATHER_PAL_STATE_IDLE;
+}
+
+void PreservePaletteInWeather(u8 preservedPalIndex)
+{
+ CpuCopy16(sBasePaletteGammaTypes, gFieldEffectPaletteGammaTypes, 32);
+ gFieldEffectPaletteGammaTypes[preservedPalIndex] = GAMMA_NONE;
+ sPaletteGammaTypes = gFieldEffectPaletteGammaTypes;
+}
+
+void ResetPreservedPalettesInWeather(void)
+{
+ sPaletteGammaTypes = sBasePaletteGammaTypes;
+}