pokeemerald/src/field_weather.c

1102 lines
31 KiB
C
Raw Normal View History

2018-12-08 19:05:03 +01:00
#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 DROUGHT_COLOR_INDEX(color) ((((color) >> 1) & 0xF) | (((color) >> 2) & 0xF0) | (((color) >> 3) & 0xF00))
2018-12-08 19:05:03 +01:00
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.
2018-12-08 19:43:21 +01:00
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);
static void Task_WeatherInit(u8 taskId);
static void Task_WeatherMain(u8 taskId);
static void None_Init(void);
static void None_Main(void);
static u8 None_Finish(void);
EWRAM_DATA struct Weather gWeather = {0};
EWRAM_DATA static u8 sFieldEffectPaletteGammaTypes[32] = {0};
IWRAM_DATA static const u8 *sPaletteGammaTypes;
// The drought weather effect uses a precalculated color lookup table. Presumably this
// is because the underlying color shift calculation is slow.
const u16 sDroughtWeatherColors[][0x1000] = {
INCBIN_U16("graphics/weather/drought/0.gbapal"),
INCBIN_U16("graphics/weather/drought/1.gbapal"),
INCBIN_U16("graphics/weather/drought/2.gbapal"),
INCBIN_U16("graphics/weather/drought/3.gbapal"),
INCBIN_U16("graphics/weather/drought/4.gbapal"),
INCBIN_U16("graphics/weather/drought/5.gbapal"),
};
2018-12-08 19:43:21 +01:00
2018-12-09 12:16:01 +01:00
// This is a pointer to gWeather. All code in this file accesses gWeather directly,
2018-12-08 19:05:03 +01:00
// 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;
2018-12-08 19:43:21 +01:00
static const struct WeatherCallbacks sWeatherFuncs[] =
2018-12-08 19:05:03 +01:00
{
{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.
2018-12-08 19:43:21 +01:00
static const u8 sBasePaletteGammaTypes[32] =
2018-12-08 19:05:03 +01:00
{
// 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,
};
2018-12-08 19:43:21 +01:00
const u16 gUnknown_083970E8[] = INCBIN_U16("graphics/weather/0.gbapal");
2018-12-08 19:05:03 +01:00
// code
void StartWeather(void)
{
if (!FuncIsActiveTask(Task_WeatherMain))
{
u8 index = AllocSpritePalette(0x1200);
CpuCopy32(gUnknown_083970E8, &gPlttBufferUnfaded[0x100 + index * 16], 32);
BuildGammaShiftTables();
2018-12-08 19:43:21 +01:00
gWeatherPtr->altGammaSpritePalIndex = index;
gWeatherPtr->weatherPicSpritePalIndex = AllocSpritePalette(0x1201);
gWeatherPtr->rainSpriteCount = 0;
gWeatherPtr->unknown_6D8 = 0;
gWeatherPtr->cloudSpritesCreated = 0;
gWeatherPtr->snowflakeSpriteCount = 0;
gWeatherPtr->ashSpritesCreated = 0;
gWeatherPtr->fog1SpritesCreated = 0;
gWeatherPtr->fog2SpritesCreated = 0;
gWeatherPtr->sandstormSprites1Created = 0;
gWeatherPtr->sandstormSprites2Created = 0;
gWeatherPtr->unknown_72E = 0;
gWeatherPtr->lightenedFogSpritePalsCount = 0;
2018-12-08 19:05:03 +01:00
Weather_SetBlendCoeffs(16, 0);
2018-12-08 19:43:21 +01:00
gWeatherPtr->currWeather = 0;
gWeatherPtr->palProcessingState = WEATHER_PAL_STATE_IDLE;
gWeatherPtr->readyForInit = FALSE;
gWeatherPtr->weatherChangeComplete = TRUE;
gWeatherPtr->taskId = CreateTask(Task_WeatherInit, 80);
2018-12-08 19:05:03 +01:00
}
}
void ChangeWeather(u8 weather)
{
if (weather != WEATHER_RAIN_LIGHT && weather != WEATHER_RAIN_MED && weather != WEATHER_RAIN_HEAVY)
{
PlayRainSoundEffect();
}
2018-12-08 19:43:21 +01:00
if (gWeatherPtr->nextWeather != weather && gWeatherPtr->currWeather == weather)
2018-12-08 19:05:03 +01:00
{
sWeatherFuncs[weather].initVars();
}
2018-12-08 19:43:21 +01:00
gWeatherPtr->weatherChangeComplete = FALSE;
gWeatherPtr->nextWeather = weather;
gWeatherPtr->finishStep = 0;
2018-12-08 19:05:03 +01:00
}
void sub_80AB104(u8 weather)
{
PlayRainSoundEffect();
2018-12-08 19:43:21 +01:00
gWeatherPtr->currWeather = weather;
gWeatherPtr->nextWeather = weather;
2018-12-08 19:05:03 +01:00
}
void sub_80AB130(u8 weather)
{
PlayRainSoundEffect();
2018-12-08 19:43:21 +01:00
gWeatherPtr->currWeather = weather;
gWeatherPtr->nextWeather = weather;
gWeatherPtr->readyForInit = TRUE;
2018-12-08 19:05:03 +01:00
}
2018-12-08 19:43:21 +01:00
static void Task_WeatherInit(u8 taskId)
2018-12-08 19:05:03 +01:00
{
// Waits until it's ok to initialize weather.
// When the screen fades in, this is set to TRUE.
2018-12-08 19:43:21 +01:00
if (gWeatherPtr->readyForInit)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
sWeatherFuncs[gWeatherPtr->currWeather].initAll();
2018-12-08 19:05:03 +01:00
gTasks[taskId].func = Task_WeatherMain;
}
}
2018-12-08 19:43:21 +01:00
static void Task_WeatherMain(u8 taskId)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
if (gWeatherPtr->currWeather != gWeatherPtr->nextWeather)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
if (!sWeatherFuncs[gWeatherPtr->currWeather].finish() && gWeatherPtr->palProcessingState != WEATHER_PAL_STATE_SCREEN_FADING_OUT)
2018-12-08 19:05:03 +01:00
{
// Finished cleaning up previous weather. Now transition to next weather.
2018-12-08 19:43:21 +01:00
sWeatherFuncs[gWeatherPtr->nextWeather].initVars();
gWeatherPtr->gammaStepFrameCounter = 0;
gWeatherPtr->palProcessingState = WEATHER_PAL_STATE_CHANGING_WEATHER;
gWeatherPtr->currWeather = gWeatherPtr->nextWeather;
gWeatherPtr->weatherChangeComplete = TRUE;
2018-12-08 19:05:03 +01:00
}
}
else
{
2018-12-08 19:43:21 +01:00
sWeatherFuncs[gWeatherPtr->currWeather].main();
2018-12-08 19:05:03 +01:00
}
2018-12-08 19:43:21 +01:00
gWeatherPalStateFuncs[gWeatherPtr->palProcessingState]();
2018-12-08 19:05:03 +01:00
}
2018-12-08 19:43:21 +01:00
static void None_Init(void)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
gWeatherPtr->gammaTargetIndex = 0;
gWeatherPtr->gammaStepDelay = 0;
2018-12-08 19:05:03 +01:00
}
2018-12-08 19:43:21 +01:00
static void None_Main(void)
2018-12-08 19:05:03 +01:00
{
}
2018-12-08 19:43:21 +01:00
static u8 None_Finish(void)
2018-12-08 19:05:03 +01:00
{
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.
2018-12-08 19:43:21 +01:00
static void BuildGammaShiftTables(void)
2018-12-08 19:05:03 +01:00
{
u16 v0;
2018-12-09 12:16:01 +01:00
u8 (*gammaTable)[32];
2018-12-08 19:05:03 +01:00
u16 v2;
u16 v4;
u16 v5;
2018-12-09 12:16:01 +01:00
u16 gammaIndex;
2018-12-08 19:05:03 +01:00
u16 v9;
u32 v10;
u16 v11;
s16 dunno;
sPaletteGammaTypes = sBasePaletteGammaTypes;
for (v0 = 0; v0 <= 1; v0++)
{
if (v0 == 0)
2018-12-09 12:16:01 +01:00
gammaTable = gWeatherPtr->gammaShifts;
2018-12-08 19:05:03 +01:00
else
2018-12-09 12:16:01 +01:00
gammaTable = gWeatherPtr->altGammaShifts;
2018-12-08 19:05:03 +01:00
for (v2 = 0; v2 < 32; v2++)
{
v4 = v2 << 8;
if (v0 == 0)
v5 = (v2 << 8) / 16;
else
v5 = 0;
2018-12-09 12:16:01 +01:00
for (gammaIndex = 0; gammaIndex <= 2; gammaIndex++)
2018-12-08 19:05:03 +01:00
{
v4 = (v4 - v5);
2018-12-09 12:16:01 +01:00
gammaTable[gammaIndex][v2] = v4 >> 8;
2018-12-08 19:05:03 +01:00
}
v9 = v4;
v10 = 0x1f00 - v4;
if ((0x1f00 - v4) < 0)
{
v10 += 0xf;
}
v11 = v10 >> 4;
if (v2 < 12)
{
2018-12-09 12:16:01 +01:00
for (; gammaIndex < 19; gammaIndex++)
2018-12-08 19:05:03 +01:00
{
v4 += v11;
dunno = v4 - v9;
if (dunno > 0)
v4 -= (dunno + ((u16)dunno >> 15)) >> 1;
2018-12-09 12:16:01 +01:00
gammaTable[gammaIndex][v2] = v4 >> 8;
if (gammaTable[gammaIndex][v2] > 0x1f)
gammaTable[gammaIndex][v2] = 0x1f;
2018-12-08 19:05:03 +01:00
}
}
else
{
2018-12-09 12:16:01 +01:00
for (; gammaIndex < 19; gammaIndex++)
2018-12-08 19:05:03 +01:00
{
v4 += v11;
2018-12-09 12:16:01 +01:00
gammaTable[gammaIndex][v2] = v4 >> 8;
if (gammaTable[gammaIndex][v2] > 0x1f)
gammaTable[gammaIndex][v2] = 0x1f;
2018-12-08 19:05:03 +01:00
}
}
}
}
}
// When the weather is changing, it gradually updates the palettes
// towards the desired gamma shift.
2018-12-08 19:43:21 +01:00
static void UpdateWeatherGammaShift(void)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
if (gWeatherPtr->palProcessingState != WEATHER_PAL_STATE_SCREEN_FADING_OUT)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
if (gWeatherPtr->gammaIndex == gWeatherPtr->gammaTargetIndex)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
gWeatherPtr->palProcessingState = WEATHER_PAL_STATE_IDLE;
2018-12-08 19:05:03 +01:00
}
else
{
2018-12-08 19:43:21 +01:00
if (++gWeatherPtr->gammaStepFrameCounter >= gWeatherPtr->gammaStepDelay)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
gWeatherPtr->gammaStepFrameCounter = 0;
if (gWeatherPtr->gammaIndex < gWeatherPtr->gammaTargetIndex)
gWeatherPtr->gammaIndex++;
2018-12-08 19:05:03 +01:00
else
2018-12-08 19:43:21 +01:00
gWeatherPtr->gammaIndex--;
2018-12-08 19:05:03 +01:00
2018-12-08 19:43:21 +01:00
ApplyGammaShift(0, 32, gWeatherPtr->gammaIndex);
2018-12-08 19:05:03 +01:00
}
}
}
}
2018-12-08 19:43:21 +01:00
static void FadeInScreenWithWeather(void)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
if (++gWeatherPtr->unknown_6CB > 1)
gWeatherPtr->unknown_6CA = 0;
2018-12-08 19:05:03 +01:00
2018-12-08 19:43:21 +01:00
switch (gWeatherPtr->currWeather)
2018-12-08 19:05:03 +01:00
{
case WEATHER_RAIN_LIGHT:
case WEATHER_RAIN_MED:
case WEATHER_RAIN_HEAVY:
case WEATHER_SNOW:
case WEATHER_SHADE:
if (FadeInScreen_RainShowShade() == FALSE)
{
2018-12-08 19:43:21 +01:00
gWeatherPtr->gammaIndex = 3;
gWeatherPtr->palProcessingState = WEATHER_PAL_STATE_IDLE;
2018-12-08 19:05:03 +01:00
}
break;
case WEATHER_DROUGHT:
if (FadeInScreen_Drought() == FALSE)
{
2018-12-08 19:43:21 +01:00
gWeatherPtr->gammaIndex = -6;
gWeatherPtr->palProcessingState = WEATHER_PAL_STATE_IDLE;
2018-12-08 19:05:03 +01:00
}
break;
case WEATHER_FOG_1:
if (FadeInScreen_Fog1() == FALSE)
{
2018-12-08 19:43:21 +01:00
gWeatherPtr->gammaIndex = 0;
gWeatherPtr->palProcessingState = WEATHER_PAL_STATE_IDLE;
2018-12-08 19:05:03 +01:00
}
break;
case WEATHER_ASH:
case WEATHER_SANDSTORM:
case WEATHER_FOG_2:
case WEATHER_FOG_3:
default:
if (!gPaletteFade.active)
{
2018-12-08 19:43:21 +01:00
gWeatherPtr->gammaIndex = gWeatherPtr->gammaTargetIndex;
gWeatherPtr->palProcessingState = WEATHER_PAL_STATE_IDLE;
2018-12-08 19:05:03 +01:00
}
break;
}
}
2018-12-08 19:43:21 +01:00
static bool8 FadeInScreen_RainShowShade(void)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
if (gWeatherPtr->fadeScreenCounter == 16)
2018-12-08 19:05:03 +01:00
return FALSE;
2018-12-08 19:43:21 +01:00
if (++gWeatherPtr->fadeScreenCounter >= 16)
2018-12-08 19:05:03 +01:00
{
ApplyGammaShift(0, 32, 3);
2018-12-08 19:43:21 +01:00
gWeatherPtr->fadeScreenCounter = 16;
2018-12-08 19:05:03 +01:00
return FALSE;
}
2018-12-08 19:43:21 +01:00
ApplyGammaShiftWithBlend(0, 32, 3, 16 - gWeatherPtr->fadeScreenCounter, gWeatherPtr->fadeDestColor);
2018-12-08 19:05:03 +01:00
return TRUE;
}
2018-12-08 19:43:21 +01:00
static bool8 FadeInScreen_Drought(void)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
if (gWeatherPtr->fadeScreenCounter == 16)
2018-12-08 19:05:03 +01:00
return FALSE;
2018-12-08 19:43:21 +01:00
if (++gWeatherPtr->fadeScreenCounter >= 16)
2018-12-08 19:05:03 +01:00
{
ApplyGammaShift(0, 32, -6);
2018-12-08 19:43:21 +01:00
gWeatherPtr->fadeScreenCounter = 16;
2018-12-08 19:05:03 +01:00
return FALSE;
}
2018-12-08 19:43:21 +01:00
ApplyDroughtGammaShiftWithBlend(-6, 16 - gWeatherPtr->fadeScreenCounter, gWeatherPtr->fadeDestColor);
2018-12-08 19:05:03 +01:00
return TRUE;
}
2018-12-08 19:43:21 +01:00
static bool8 FadeInScreen_Fog1(void)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
if (gWeatherPtr->fadeScreenCounter == 16)
2018-12-08 19:05:03 +01:00
return FALSE;
2018-12-08 19:43:21 +01:00
gWeatherPtr->fadeScreenCounter++;
ApplyFogBlend(16 - gWeatherPtr->fadeScreenCounter, gWeatherPtr->fadeDestColor);
2018-12-08 19:05:03 +01:00
return TRUE;
}
2018-12-08 19:43:21 +01:00
static void DoNothing(void)
2018-12-08 19:05:03 +01:00
{ }
2018-12-08 19:43:21 +01:00
static void ApplyGammaShift(u8 startPalIndex, u8 numPalettes, s8 gammaIndex)
2018-12-08 19:05:03 +01:00
{
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;
2018-12-08 19:43:21 +01:00
if (sPaletteGammaTypes[curPalIndex] == GAMMA_ALT || curPalIndex - 16 == gWeatherPtr->altGammaSpritePalIndex)
gammaTable = gWeatherPtr->altGammaShifts[gammaIndex];
2018-12-08 19:05:03 +01:00
else
2018-12-08 19:43:21 +01:00
gammaTable = gWeatherPtr->gammaShifts[gammaIndex];
2018-12-08 19:05:03 +01:00
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] = sDroughtWeatherColors[gammaIndex][DROUGHT_COLOR_INDEX(gPlttBufferUnfaded[palOffset])];
2018-12-08 19:05:03 +01:00
palOffset++;
}
}
curPalIndex++;
}
}
else
{
// No palette blending.
CpuFastCopy(gPlttBufferUnfaded + startPalIndex * 16, gPlttBufferFaded + startPalIndex * 16, numPalettes * 16 * sizeof(u16));
}
}
2018-12-08 19:43:21 +01:00
static void ApplyGammaShiftWithBlend(u8 startPalIndex, u8 numPalettes, s8 gammaIndex, u8 blendCoeff, u16 blendColor)
2018-12-08 19:05:03 +01:00
{
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)
2018-12-08 19:43:21 +01:00
gammaTable = gWeatherPtr->gammaShifts[gammaIndex];
2018-12-08 19:05:03 +01:00
else
2018-12-08 19:43:21 +01:00
gammaTable = gWeatherPtr->altGammaShifts[gammaIndex];
2018-12-08 19:05:03 +01:00
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++;
}
}
2018-12-08 19:43:21 +01:00
static void ApplyDroughtGammaShiftWithBlend(s8 gammaIndex, u8 blendCoeff, u16 blendColor)
2018-12-08 19:05:03 +01:00
{
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 *)&sDroughtWeatherColors[gammaIndex][offset];
2018-12-08 19:05:03 +01:00
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;
}
}
}
}
2018-12-08 19:43:21 +01:00
static void ApplyFogBlend(u8 blendCoeff, u16 blendColor)
2018-12-08 19:05:03 +01:00
{
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);
}
}
}
2018-12-08 19:43:21 +01:00
static void MarkFogSpritePalToLighten(u8 paletteIndex)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
if (gWeatherPtr->lightenedFogSpritePalsCount < 6)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
gWeatherPtr->lightenedFogSpritePals[gWeatherPtr->lightenedFogSpritePalsCount] = paletteIndex;
gWeatherPtr->lightenedFogSpritePalsCount++;
2018-12-08 19:05:03 +01:00
}
}
2018-12-08 19:43:21 +01:00
static bool8 LightenSpritePaletteInFog(u8 paletteIndex)
2018-12-08 19:05:03 +01:00
{
u16 i;
2018-12-08 19:43:21 +01:00
for (i = 0; i < gWeatherPtr->lightenedFogSpritePalsCount; i++)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
if (gWeatherPtr->lightenedFogSpritePals[i] == paletteIndex)
2018-12-08 19:05:03 +01:00
return TRUE;
}
return FALSE;
}
void sub_80ABC48(s8 gammaIndex)
{
2018-12-08 19:43:21 +01:00
if (gWeatherPtr->palProcessingState == WEATHER_PAL_STATE_IDLE)
2018-12-08 19:05:03 +01:00
{
ApplyGammaShift(0, 32, gammaIndex);
2018-12-08 19:43:21 +01:00
gWeatherPtr->gammaIndex = gammaIndex;
2018-12-08 19:05:03 +01:00
}
}
void sub_80ABC7C(u8 gammaIndex, u8 gammaTargetIndex, u8 gammaStepDelay)
{
2018-12-08 19:43:21 +01:00
if (gWeatherPtr->palProcessingState == WEATHER_PAL_STATE_IDLE)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
gWeatherPtr->palProcessingState = WEATHER_PAL_STATE_CHANGING_WEATHER;
gWeatherPtr->gammaIndex = gammaIndex;
gWeatherPtr->gammaTargetIndex = gammaTargetIndex;
gWeatherPtr->gammaStepFrameCounter = 0;
gWeatherPtr->gammaStepDelay = gammaStepDelay;
2018-12-08 19:05:03 +01:00
sub_80ABC48(gammaIndex);
}
}
void FadeScreen(u8 mode, s8 delay)
{
u32 fadeColor;
bool8 fadeOut;
bool8 useWeatherPal;
switch (mode)
{
case FADE_FROM_BLACK:
2018-12-09 12:16:01 +01:00
fadeColor = RGB_BLACK;
2018-12-08 19:05:03 +01:00
fadeOut = FALSE;
break;
case FADE_FROM_WHITE:
2018-12-09 12:16:01 +01:00
fadeColor = RGB_WHITEALPHA;
2018-12-08 19:05:03 +01:00
fadeOut = FALSE;
break;
case FADE_TO_BLACK:
2018-12-09 12:16:01 +01:00
fadeColor = RGB_BLACK;
2018-12-08 19:05:03 +01:00
fadeOut = TRUE;
break;
case FADE_TO_WHITE:
2018-12-09 12:16:01 +01:00
fadeColor = RGB_WHITEALPHA;
2018-12-08 19:05:03 +01:00
fadeOut = TRUE;
break;
default:
return;
}
2018-12-08 19:43:21 +01:00
switch (gWeatherPtr->currWeather)
2018-12-08 19:05:03 +01:00
{
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);
2018-12-08 19:43:21 +01:00
gWeatherPtr->palProcessingState = WEATHER_PAL_STATE_SCREEN_FADING_OUT;
2018-12-08 19:05:03 +01:00
}
else
{
2018-12-08 19:43:21 +01:00
gWeatherPtr->fadeDestColor = fadeColor;
2018-12-08 19:05:03 +01:00
if (useWeatherPal)
2018-12-08 19:43:21 +01:00
gWeatherPtr->fadeScreenCounter = 0;
2018-12-08 19:05:03 +01:00
else
BeginNormalPaletteFade(0xFFFFFFFF, delay, 16, 0, fadeColor);
2018-12-08 19:43:21 +01:00
gWeatherPtr->palProcessingState = WEATHER_PAL_STATE_SCREEN_FADING_IN;
gWeatherPtr->unknown_6CA = 1;
gWeatherPtr->unknown_6CB = 0;
Weather_SetBlendCoeffs(gWeatherPtr->currBlendEVA, gWeatherPtr->currBlendEVB);
gWeatherPtr->readyForInit = TRUE;
2018-12-08 19:05:03 +01:00
}
}
bool8 IsWeatherNotFadingIn(void)
{
2018-12-08 19:43:21 +01:00
return (gWeatherPtr->palProcessingState != WEATHER_PAL_STATE_SCREEN_FADING_IN);
2018-12-08 19:05:03 +01:00
}
void UpdateSpritePaletteWithWeather(u8 spritePaletteIndex)
{
u16 paletteIndex = 16 + spritePaletteIndex;
u16 i;
2018-12-08 19:43:21 +01:00
switch (gWeatherPtr->palProcessingState)
2018-12-08 19:05:03 +01:00
{
case WEATHER_PAL_STATE_SCREEN_FADING_IN:
2018-12-08 19:43:21 +01:00
if (gWeatherPtr->unknown_6CA != 0)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
if (gWeatherPtr->currWeather == WEATHER_FOG_1)
2018-12-08 19:05:03 +01:00
MarkFogSpritePalToLighten(paletteIndex);
paletteIndex *= 16;
for (i = 0; i < 16; i++)
2018-12-08 19:43:21 +01:00
gPlttBufferFaded[paletteIndex + i] = gWeatherPtr->fadeDestColor;
2018-12-08 19:05:03 +01:00
}
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:
2018-12-08 19:43:21 +01:00
if (gWeatherPtr->currWeather != WEATHER_FOG_1)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
ApplyGammaShift(paletteIndex, 1, gWeatherPtr->gammaIndex);
2018-12-08 19:05:03 +01:00
}
else
{
paletteIndex *= 16;
BlendPalette(paletteIndex, 16, 12, RGB(28, 31, 28));
}
break;
}
}
void ApplyWeatherGammaShiftToPal(u8 paletteIndex)
{
2018-12-08 19:43:21 +01:00
ApplyGammaShift(paletteIndex, 1, gWeatherPtr->gammaIndex);
2018-12-08 19:05:03 +01:00
}
u8 sub_80ABF20(void)
{
2018-12-08 19:43:21 +01:00
if (gWeatherPtr->palProcessingState == WEATHER_PAL_STATE_SCREEN_FADING_IN)
return gWeatherPtr->unknown_6CA;
2018-12-08 19:05:03 +01:00
else
return 0;
}
void LoadCustomWeatherSpritePalette(const u16 *palette)
{
2018-12-08 19:43:21 +01:00
LoadPalette(palette, 0x100 + gWeatherPtr->weatherPicSpritePalIndex * 16, 32);
UpdateSpritePaletteWithWeather(gWeatherPtr->weatherPicSpritePalIndex);
2018-12-08 19:05:03 +01:00
}
2018-12-08 19:43:21 +01:00
static void LoadDroughtWeatherPalette(u8 *gammaIndexPtr, u8 *a1)
2018-12-08 19:05:03 +01:00
{
*gammaIndexPtr = 0x20;
*a1 = 0x20;
}
void ResetDroughtWeatherPaletteLoading(void)
{
2018-12-08 19:43:21 +01:00
gWeatherPtr->loadDroughtPalsIndex = 1;
gWeatherPtr->loadDroughtPalsOffset = 1;
2018-12-08 19:05:03 +01:00
}
bool8 LoadDroughtWeatherPalettes(void)
{
2018-12-08 19:43:21 +01:00
if (gWeatherPtr->loadDroughtPalsIndex < 32)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
LoadDroughtWeatherPalette(&gWeatherPtr->loadDroughtPalsIndex, &gWeatherPtr->loadDroughtPalsOffset);
if (gWeatherPtr->loadDroughtPalsIndex < 32)
2018-12-08 19:05:03 +01:00
return TRUE;
}
return FALSE;
}
void sub_80ABFE0(s8 gammaIndex)
{
sub_80ABC48(-gammaIndex - 1);
}
void sub_80ABFF0(void)
{
2018-12-08 19:43:21 +01:00
gWeatherPtr->unknown_73C = 0;
gWeatherPtr->unknown_740 = 0;
gWeatherPtr->unknown_742 = 0;
gWeatherPtr->unknown_73E = 0;
2018-12-08 19:05:03 +01:00
}
void sub_80AC01C(void)
{
2018-12-08 19:43:21 +01:00
switch (gWeatherPtr->unknown_742)
2018-12-08 19:05:03 +01:00
{
case 0:
2018-12-08 19:43:21 +01:00
if (++gWeatherPtr->unknown_740 > 5)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
gWeatherPtr->unknown_740 = 0;
sub_80ABFE0(gWeatherPtr->unknown_73C++);
if (gWeatherPtr->unknown_73C > 5)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
gWeatherPtr->unknown_73E = gWeatherPtr->unknown_73C;
gWeatherPtr->unknown_742 = 1;
gWeatherPtr->unknown_740 = 0x3C;
2018-12-08 19:05:03 +01:00
}
}
break;
case 1:
2018-12-08 19:43:21 +01:00
gWeatherPtr->unknown_740 = (gWeatherPtr->unknown_740 + 3) & 0x7F;
gWeatherPtr->unknown_73C = ((gSineTable[gWeatherPtr->unknown_740] - 1) >> 6) + 2;
if (gWeatherPtr->unknown_73C != gWeatherPtr->unknown_73E)
sub_80ABFE0(gWeatherPtr->unknown_73C);
gWeatherPtr->unknown_73E = gWeatherPtr->unknown_73C;
2018-12-08 19:05:03 +01:00
break;
case 2:
2018-12-08 19:43:21 +01:00
if (++gWeatherPtr->unknown_740 > 5)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
gWeatherPtr->unknown_740 = 0;
sub_80ABFE0(--gWeatherPtr->unknown_73C);
if (gWeatherPtr->unknown_73C == 3)
gWeatherPtr->unknown_742 = 0;
2018-12-08 19:05:03 +01:00
}
break;
}
}
void Weather_SetBlendCoeffs(u8 eva, u8 evb)
{
2018-12-08 19:43:21 +01:00
gWeatherPtr->currBlendEVA = eva;
gWeatherPtr->currBlendEVB = evb;
gWeatherPtr->targetBlendEVA = eva;
gWeatherPtr->targetBlendEVB = evb;
2018-12-08 19:05:03 +01:00
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(eva, evb));
}
void Weather_SetTargetBlendCoeffs(u8 eva, u8 evb, int delay)
{
2018-12-08 19:43:21 +01:00
gWeatherPtr->targetBlendEVA = eva;
gWeatherPtr->targetBlendEVB = evb;
gWeatherPtr->blendDelay = delay;
gWeatherPtr->blendFrameCounter = 0;
gWeatherPtr->blendUpdateCounter = 0;
2018-12-08 19:05:03 +01:00
}
bool8 Weather_UpdateBlend(void)
{
2018-12-08 19:43:21 +01:00
if (gWeatherPtr->currBlendEVA == gWeatherPtr->targetBlendEVA
&& gWeatherPtr->currBlendEVB == gWeatherPtr->targetBlendEVB)
2018-12-08 19:05:03 +01:00
return TRUE;
2018-12-08 19:43:21 +01:00
if (++gWeatherPtr->blendFrameCounter > gWeatherPtr->blendDelay)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
gWeatherPtr->blendFrameCounter = 0;
gWeatherPtr->blendUpdateCounter++;
2018-12-08 19:05:03 +01:00
// Update currBlendEVA and currBlendEVB on alternate frames
2018-12-08 19:43:21 +01:00
if (gWeatherPtr->blendUpdateCounter & 1)
2018-12-08 19:05:03 +01:00
{
2018-12-08 19:43:21 +01:00
if (gWeatherPtr->currBlendEVA < gWeatherPtr->targetBlendEVA)
gWeatherPtr->currBlendEVA++;
else if (gWeatherPtr->currBlendEVA > gWeatherPtr->targetBlendEVA)
gWeatherPtr->currBlendEVA--;
2018-12-08 19:05:03 +01:00
}
else
{
2018-12-08 19:43:21 +01:00
if (gWeatherPtr->currBlendEVB < gWeatherPtr->targetBlendEVB)
gWeatherPtr->currBlendEVB++;
else if (gWeatherPtr->currBlendEVB > gWeatherPtr->targetBlendEVB)
gWeatherPtr->currBlendEVB--;
2018-12-08 19:05:03 +01:00
}
}
2018-12-08 19:43:21 +01:00
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(gWeatherPtr->currBlendEVA, gWeatherPtr->currBlendEVB));
2018-12-08 19:05:03 +01:00
2018-12-08 19:43:21 +01:00
if (gWeatherPtr->currBlendEVA == gWeatherPtr->targetBlendEVA
&& gWeatherPtr->currBlendEVB == gWeatherPtr->targetBlendEVB)
2018-12-08 19:05:03 +01:00
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)
{
2018-12-08 19:43:21 +01:00
return gWeatherPtr->currWeather;
2018-12-08 19:05:03 +01:00
}
void SetRainStrengthFromSoundEffect(u16 soundEffect)
{
2018-12-08 19:43:21 +01:00
if (gWeatherPtr->palProcessingState != WEATHER_PAL_STATE_SCREEN_FADING_OUT)
2018-12-08 19:05:03 +01:00
{
switch (soundEffect)
{
case SE_T_KOAME:
2018-12-08 19:43:21 +01:00
gWeatherPtr->rainStrength = 0;
2018-12-08 19:05:03 +01:00
break;
case SE_T_OOAME:
2018-12-08 19:43:21 +01:00
gWeatherPtr->rainStrength = 1;
2018-12-08 19:05:03 +01:00
break;
case SE_T_AME:
2018-12-08 19:43:21 +01:00
gWeatherPtr->rainStrength = 2;
2018-12-08 19:05:03 +01:00
break;
default:
return;
}
PlaySE(soundEffect);
}
}
void PlayRainSoundEffect(void)
{
if (IsSpecialSEPlaying())
{
2018-12-08 19:43:21 +01:00
switch (gWeatherPtr->rainStrength)
2018-12-08 19:05:03 +01:00
{
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)
{
2018-12-08 19:43:21 +01:00
return gWeatherPtr->weatherChangeComplete;
2018-12-08 19:05:03 +01:00
}
void SetWeatherScreenFadeOut(void)
{
2018-12-08 19:43:21 +01:00
gWeatherPtr->palProcessingState = WEATHER_PAL_STATE_SCREEN_FADING_OUT;
2018-12-08 19:05:03 +01:00
}
void sub_80AC3E4(void)
{
2018-12-08 19:43:21 +01:00
gWeatherPtr->palProcessingState = WEATHER_PAL_STATE_IDLE;
2018-12-08 19:05:03 +01:00
}
void PreservePaletteInWeather(u8 preservedPalIndex)
{
2018-12-08 19:43:21 +01:00
CpuCopy16(sBasePaletteGammaTypes, sFieldEffectPaletteGammaTypes, 32);
sFieldEffectPaletteGammaTypes[preservedPalIndex] = GAMMA_NONE;
sPaletteGammaTypes = sFieldEffectPaletteGammaTypes;
2018-12-08 19:05:03 +01:00
}
void ResetPreservedPalettesInWeather(void)
{
sPaletteGammaTypes = sBasePaletteGammaTypes;
}