Merge pull request #1803 from abaresk/thunder

Add more documentation to thunder weather effect
This commit is contained in:
GriffinR 2022-10-20 11:36:10 -04:00 committed by GitHub
commit fad92ec906
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 86 additions and 76 deletions

View File

@ -77,12 +77,12 @@ struct Weather
u8 snowflakeSpriteCount; u8 snowflakeSpriteCount;
u8 targetSnowflakeSpriteCount; u8 targetSnowflakeSpriteCount;
// Thunderstorm // Thunderstorm
u16 thunderDelay; u16 thunderTimer; // general-purpose timer for state transitions
u16 thunderCounter; u16 thunderSETimer; // timer for thunder sound effect
bool8 thunderAllowEnd; bool8 thunderAllowEnd;
bool8 thunderSkipShort; bool8 thunderLongBolt; // true if this cycle will end in a long lightning bolt
u8 thunderShortRetries; u8 thunderShortBolts; // the number of short bolts this cycle
bool8 thunderTriggered; bool8 thunderEnqueued;
// Horizontal fog // Horizontal fog
u16 fogHScrollPosX; u16 fogHScrollPosX;
u16 fogHScrollCounter; u16 fogHScrollCounter;

View File

@ -1014,29 +1014,29 @@ static void UpdateSnowflakeSprite(struct Sprite *sprite)
enum { enum {
// This block of states is run only once // This block of states is run only once
// when first setting up the thunderstorm // when first setting up the thunderstorm
TSTORM_STATE_LOAD_RAIN, THUNDER_STATE_LOAD_RAIN,
TSTORM_STATE_CREATE_RAIN, THUNDER_STATE_CREATE_RAIN,
TSTORM_STATE_INIT_RAIN, THUNDER_STATE_INIT_RAIN,
TSTORM_STATE_WAIT_CHANGE, THUNDER_STATE_WAIT_CHANGE,
// The thunderstorm loops through these states, // The thunderstorm loops through these states,
// not necessarily in order. // not necessarily in order.
TSTORM_STATE_LOOP_START, THUNDER_STATE_NEW_CYCLE,
TSTORM_STATE_LOOP_WAIT, THUNDER_STATE_NEW_CYCLE_WAIT,
TSTORM_STATE_INIT_THUNDER_SHORT_1, THUNDER_STATE_INIT_CYCLE_1,
TSTORM_STATE_INIT_THUNDER_SHORT_2, THUNDER_STATE_INIT_CYCLE_2,
TSTORM_STATE_TRY_THUNDER_SHORT, THUNDER_STATE_SHORT_BOLT,
TSTORM_STATE_TRY_NEW_THUNDER, THUNDER_STATE_TRY_NEW_BOLT,
TSTORM_STATE_WAIT_THUNDER_SHORT, THUNDER_STATE_WAIT_BOLT_SHORT,
TSTORM_STATE_INIT_THUNDER_LONG, THUNDER_STATE_INIT_BOLT_LONG,
TSTORM_STATE_WAIT_THUNDER_LONG, THUNDER_STATE_WAIT_BOLT_LONG,
TSTORM_STATE_FADE_THUNDER_LONG, THUNDER_STATE_FADE_BOLT_LONG,
TSTORM_STATE_END_THUNDER_LONG, THUNDER_STATE_END_BOLT_LONG,
}; };
void Thunderstorm_InitVars(void) void Thunderstorm_InitVars(void)
{ {
gWeatherPtr->initStep = TSTORM_STATE_LOAD_RAIN; gWeatherPtr->initStep = THUNDER_STATE_LOAD_RAIN;
gWeatherPtr->weatherGfxLoaded = FALSE; gWeatherPtr->weatherGfxLoaded = FALSE;
gWeatherPtr->rainSpriteVisibleCounter = 0; gWeatherPtr->rainSpriteVisibleCounter = 0;
gWeatherPtr->rainSpriteVisibleDelay = 4; gWeatherPtr->rainSpriteVisibleDelay = 4;
@ -1045,7 +1045,7 @@ void Thunderstorm_InitVars(void)
gWeatherPtr->targetColorMapIndex = 3; gWeatherPtr->targetColorMapIndex = 3;
gWeatherPtr->colorMapStepDelay = 20; gWeatherPtr->colorMapStepDelay = 20;
gWeatherPtr->weatherGfxLoaded = FALSE; // duplicate assignment gWeatherPtr->weatherGfxLoaded = FALSE; // duplicate assignment
gWeatherPtr->thunderTriggered = FALSE; gWeatherPtr->thunderEnqueued = FALSE;
SetRainStrengthFromSoundEffect(SE_THUNDERSTORM); SetRainStrengthFromSoundEffect(SE_THUNDERSTORM);
} }
@ -1061,11 +1061,11 @@ void Thunderstorm_InitAll(void)
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
static void UpdateThunderSound(void); static void UpdateThunderSound(void);
static void SetThunderCounter(u16); static void EnqueueThunder(u16);
void Downpour_InitVars(void) void Downpour_InitVars(void)
{ {
gWeatherPtr->initStep = TSTORM_STATE_LOAD_RAIN; gWeatherPtr->initStep = THUNDER_STATE_LOAD_RAIN;
gWeatherPtr->weatherGfxLoaded = FALSE; gWeatherPtr->weatherGfxLoaded = FALSE;
gWeatherPtr->rainSpriteVisibleCounter = 0; gWeatherPtr->rainSpriteVisibleCounter = 0;
gWeatherPtr->rainSpriteVisibleDelay = 4; gWeatherPtr->rainSpriteVisibleDelay = 4;
@ -1084,110 +1084,119 @@ void Downpour_InitAll(void)
Thunderstorm_Main(); Thunderstorm_Main();
} }
// In a given cycle, there will be some shorter bolts of lightning, potentially
// followed by a longer bolt. As a "regex", the pattern is:
// (SHORT_BOLT){1,2}(LONG_BOLT)?
//
// Thunder only plays on the final bolt of the cycle.
void Thunderstorm_Main(void) void Thunderstorm_Main(void)
{ {
UpdateThunderSound(); UpdateThunderSound();
switch (gWeatherPtr->initStep) switch (gWeatherPtr->initStep)
{ {
case TSTORM_STATE_LOAD_RAIN: case THUNDER_STATE_LOAD_RAIN:
LoadRainSpriteSheet(); LoadRainSpriteSheet();
gWeatherPtr->initStep++; gWeatherPtr->initStep++;
break; break;
case TSTORM_STATE_CREATE_RAIN: case THUNDER_STATE_CREATE_RAIN:
if (!CreateRainSprite()) if (!CreateRainSprite())
gWeatherPtr->initStep++; gWeatherPtr->initStep++;
break; break;
case TSTORM_STATE_INIT_RAIN: case THUNDER_STATE_INIT_RAIN:
if (!UpdateVisibleRainSprites()) if (!UpdateVisibleRainSprites())
{ {
gWeatherPtr->weatherGfxLoaded = TRUE; gWeatherPtr->weatherGfxLoaded = TRUE;
gWeatherPtr->initStep++; gWeatherPtr->initStep++;
} }
break; break;
case TSTORM_STATE_WAIT_CHANGE: case THUNDER_STATE_WAIT_CHANGE:
if (gWeatherPtr->palProcessingState != WEATHER_PAL_STATE_CHANGING_WEATHER) if (gWeatherPtr->palProcessingState != WEATHER_PAL_STATE_CHANGING_WEATHER)
gWeatherPtr->initStep = TSTORM_STATE_INIT_THUNDER_SHORT_1; gWeatherPtr->initStep = THUNDER_STATE_INIT_CYCLE_1;
break; break;
case TSTORM_STATE_LOOP_START: case THUNDER_STATE_NEW_CYCLE:
gWeatherPtr->thunderAllowEnd = TRUE; gWeatherPtr->thunderAllowEnd = TRUE;
gWeatherPtr->thunderDelay = (Random() % 360) + 360; gWeatherPtr->thunderTimer = (Random() % 360) + 360;
gWeatherPtr->initStep++; gWeatherPtr->initStep++;
// fall through // fall through
case TSTORM_STATE_LOOP_WAIT: case THUNDER_STATE_NEW_CYCLE_WAIT:
// Wait between 360-720 frames before trying thunder again // Wait between 360-720 frames before starting a new cycle.
if (--gWeatherPtr->thunderDelay == 0) if (--gWeatherPtr->thunderTimer == 0)
gWeatherPtr->initStep++; gWeatherPtr->initStep++;
break; break;
case TSTORM_STATE_INIT_THUNDER_SHORT_1: case THUNDER_STATE_INIT_CYCLE_1:
gWeatherPtr->thunderAllowEnd = TRUE; gWeatherPtr->thunderAllowEnd = TRUE;
gWeatherPtr->thunderSkipShort = Random() % 2; gWeatherPtr->thunderLongBolt = Random() % 2;
gWeatherPtr->initStep++; gWeatherPtr->initStep++;
break; break;
case TSTORM_STATE_INIT_THUNDER_SHORT_2: case THUNDER_STATE_INIT_CYCLE_2:
gWeatherPtr->thunderShortRetries = (Random() & 1) + 1; gWeatherPtr->thunderShortBolts = (Random() & 1) + 1;
gWeatherPtr->initStep++; gWeatherPtr->initStep++;
// fall through // fall through
case TSTORM_STATE_TRY_THUNDER_SHORT: case THUNDER_STATE_SHORT_BOLT:
// Short bolt of lightning strikes.
ApplyWeatherColorMapIfIdle(19); ApplyWeatherColorMapIfIdle(19);
if (!gWeatherPtr->thunderSkipShort && gWeatherPtr->thunderShortRetries == 1) // If final lightning bolt, enqueue thunder.
SetThunderCounter(20); // Do short thunder if (!gWeatherPtr->thunderLongBolt && gWeatherPtr->thunderShortBolts == 1)
EnqueueThunder(20);
gWeatherPtr->thunderDelay = (Random() % 3) + 6; gWeatherPtr->thunderTimer = (Random() % 3) + 6;
gWeatherPtr->initStep++; gWeatherPtr->initStep++;
break; break;
case TSTORM_STATE_TRY_NEW_THUNDER: case THUNDER_STATE_TRY_NEW_BOLT:
if (--gWeatherPtr->thunderDelay == 0) if (--gWeatherPtr->thunderTimer == 0)
{ {
// Short bolt of lightning ends.
ApplyWeatherColorMapIfIdle(3); ApplyWeatherColorMapIfIdle(3);
gWeatherPtr->thunderAllowEnd = TRUE; gWeatherPtr->thunderAllowEnd = TRUE;
if (--gWeatherPtr->thunderShortRetries != 0) if (--gWeatherPtr->thunderShortBolts != 0)
{ {
// Try a short thunder again // Wait a little, then do another short bolt.
gWeatherPtr->thunderDelay = (Random() % 16) + 60; gWeatherPtr->thunderTimer = (Random() % 16) + 60;
gWeatherPtr->initStep = TSTORM_STATE_WAIT_THUNDER_SHORT; gWeatherPtr->initStep = THUNDER_STATE_WAIT_BOLT_SHORT;
} }
else if (!gWeatherPtr->thunderSkipShort) else if (!gWeatherPtr->thunderLongBolt)
{ {
// No more thunder, restart loop // No more bolts, restart loop.
gWeatherPtr->initStep = TSTORM_STATE_LOOP_START; gWeatherPtr->initStep = THUNDER_STATE_NEW_CYCLE;
} }
else else
{ {
// Set up long thunder // Set up long bolt.
gWeatherPtr->initStep = TSTORM_STATE_INIT_THUNDER_LONG; gWeatherPtr->initStep = THUNDER_STATE_INIT_BOLT_LONG;
} }
} }
break; break;
case TSTORM_STATE_WAIT_THUNDER_SHORT: case THUNDER_STATE_WAIT_BOLT_SHORT:
if (--gWeatherPtr->thunderDelay == 0) if (--gWeatherPtr->thunderTimer == 0)
gWeatherPtr->initStep = TSTORM_STATE_TRY_THUNDER_SHORT; gWeatherPtr->initStep = THUNDER_STATE_SHORT_BOLT;
break; break;
case TSTORM_STATE_INIT_THUNDER_LONG: case THUNDER_STATE_INIT_BOLT_LONG:
gWeatherPtr->thunderDelay = (Random() % 16) + 60; gWeatherPtr->thunderTimer = (Random() % 16) + 60;
gWeatherPtr->initStep++; gWeatherPtr->initStep++;
break; break;
case TSTORM_STATE_WAIT_THUNDER_LONG: case THUNDER_STATE_WAIT_BOLT_LONG:
if (--gWeatherPtr->thunderDelay == 0) if (--gWeatherPtr->thunderTimer == 0)
{ {
// Do long thunder // Do long bolt. Enqueue thunder with a potentially longer delay.
SetThunderCounter(100); EnqueueThunder(100);
ApplyWeatherColorMapIfIdle(19); ApplyWeatherColorMapIfIdle(19);
gWeatherPtr->thunderDelay = (Random() & 0xF) + 30; gWeatherPtr->thunderTimer = (Random() & 0xF) + 30;
gWeatherPtr->initStep++; gWeatherPtr->initStep++;
} }
break; break;
case TSTORM_STATE_FADE_THUNDER_LONG: case THUNDER_STATE_FADE_BOLT_LONG:
if (--gWeatherPtr->thunderDelay == 0) if (--gWeatherPtr->thunderTimer == 0)
{ {
// Fade long bolt out over time.
ApplyWeatherColorMapIfIdle_Gradual(19, 3, 5); ApplyWeatherColorMapIfIdle_Gradual(19, 3, 5);
gWeatherPtr->initStep++; gWeatherPtr->initStep++;
} }
break; break;
case TSTORM_STATE_END_THUNDER_LONG: case THUNDER_STATE_END_BOLT_LONG:
if (gWeatherPtr->palProcessingState == WEATHER_PAL_STATE_IDLE) if (gWeatherPtr->palProcessingState == WEATHER_PAL_STATE_IDLE)
{ {
gWeatherPtr->thunderAllowEnd = TRUE; gWeatherPtr->thunderAllowEnd = TRUE;
gWeatherPtr->initStep = TSTORM_STATE_LOOP_START; gWeatherPtr->initStep = THUNDER_STATE_NEW_CYCLE;
} }
break; break;
} }
@ -1218,7 +1227,7 @@ bool8 Thunderstorm_Finish(void)
if (!UpdateVisibleRainSprites()) if (!UpdateVisibleRainSprites())
{ {
DestroyRainSprites(); DestroyRainSprites();
gWeatherPtr->thunderTriggered = 0; gWeatherPtr->thunderEnqueued = FALSE;
gWeatherPtr->finishStep++; gWeatherPtr->finishStep++;
return FALSE; return FALSE;
} }
@ -1229,20 +1238,21 @@ bool8 Thunderstorm_Finish(void)
return TRUE; return TRUE;
} }
static void SetThunderCounter(u16 max) // Enqueue a thunder sound effect for at most `waitFrames` frames from now.
static void EnqueueThunder(u16 waitFrames)
{ {
if (!gWeatherPtr->thunderTriggered) if (!gWeatherPtr->thunderEnqueued)
{ {
gWeatherPtr->thunderCounter = Random() % max; gWeatherPtr->thunderSETimer = Random() % waitFrames;
gWeatherPtr->thunderTriggered = TRUE; gWeatherPtr->thunderEnqueued = TRUE;
} }
} }
static void UpdateThunderSound(void) static void UpdateThunderSound(void)
{ {
if (gWeatherPtr->thunderTriggered == TRUE) if (gWeatherPtr->thunderEnqueued == TRUE)
{ {
if (gWeatherPtr->thunderCounter == 0) if (gWeatherPtr->thunderSETimer == 0)
{ {
if (IsSEPlaying()) if (IsSEPlaying())
return; return;
@ -1252,11 +1262,11 @@ static void UpdateThunderSound(void)
else else
PlaySE(SE_THUNDER2); PlaySE(SE_THUNDER2);
gWeatherPtr->thunderTriggered = FALSE; gWeatherPtr->thunderEnqueued = FALSE;
} }
else else
{ {
gWeatherPtr->thunderCounter--; gWeatherPtr->thunderSETimer--;
} }
} }
} }