Merge branch 'lighting' into lighting-expanded-id

This commit is contained in:
Ariel A 2025-01-25 21:43:05 -05:00
commit c1d105c31c
15 changed files with 248 additions and 106 deletions

View File

@ -1674,13 +1674,14 @@
.4byte \text
.endm
@ Equivalent to fadescreen but copies gPlttBufferUnfaded to gPaletteDecompressionBuffer on the fade out
@ and the reverse on the fade in, in effect saving gPlttBufferUnfaded to restore it.
@ If nowait set, does not wait for the fade to complete
@ Equivalent to fadescreen but uses a hardware fade and darken/lighten blend modes,
@ to avoid modifying palettes at all.
@ Useful for fade-out/fade-in without leaving the overworld or entering a new scene.
@ If nowait set, doesn't wait for the fade to complete
.macro fadescreenswapbuffers mode:req, nowait=0
.byte 0xdc
.byte \mode
.byte \nowait
.byte \nowait
.endm
@ Buffers the specified trainer's class name to the given string var.

View File

@ -1,3 +1,4 @@
#include "constants/field_weather.h"
@ The first .byte argument of each macro below is an index into gFieldEffectScriptFuncs
.macro field_eff_loadtiles address:req
@ -5,9 +6,10 @@
.4byte \address
.endm
.macro field_eff_loadfadedpal address:req
.macro field_eff_loadfadedpal address:req, color_map_type=COLOR_MAP_DARK_CONTRAST
.byte 1
.4byte \address
.byte \color_map_type
.endm
.macro field_eff_loadpal address:req
@ -24,10 +26,11 @@
.byte 4
.endm
.macro field_eff_loadgfx_callnative tiles_address:req, palette_address:req, function_address:req
.macro field_eff_loadgfx_callnative tiles_address:req, palette_address:req, function_address:req, color_map_type=COLOR_MAP_DARK_CONTRAST
.byte 5
.4byte \tiles_address
.4byte \palette_address
.byte \color_map_type
.4byte \function_address
.endm
@ -37,8 +40,9 @@
.4byte \function_address
.endm
.macro field_eff_loadfadedpal_callnative palette_address:req, function_address:req
.macro field_eff_loadfadedpal_callnative palette_address:req, function_address:req, color_map_type=COLOR_MAP_DARK_CONTRAST
.byte 7
.4byte \palette_address
.byte \color_map_type
.4byte \function_address
.endm

View File

@ -1,6 +1,11 @@
#ifndef GUARD_CONSTANTS_FIELD_WEATHER_H
#define GUARD_CONSTANTS_FIELD_WEATHER_H
// sPaletteColorMapTypes & field_effect_scripts
#define COLOR_MAP_NONE 0
#define COLOR_MAP_DARK_CONTRAST 1
#define COLOR_MAP_CONTRAST 2
#define MAX_RAIN_SPRITES 24
#define NUM_CLOUD_SPRITES 3
#define NUM_FOG_HORIZONTAL_SPRITES 20

View File

@ -152,6 +152,7 @@ void SetCurrentAndNextWeatherNoDelay(u8 weather);
void ApplyWeatherColorMapIfIdle(s8 colorMapIndex);
void ApplyWeatherColorMapIfIdle_Gradual(u8 colorMapIndex, u8 targetColorMapIndex, u8 colorMapStepDelay);
void FadeScreen(u8 mode, s8 delay);
u16 FadeScreenHardware(u8 mode, s8 delay);
bool8 IsWeatherNotFadingIn(void);
void UpdateSpritePaletteWithWeather(u8 spritePaletteIndex, bool8 allowFog);
void ApplyWeatherColorMapToPal(u8 paletteIndex);
@ -170,7 +171,9 @@ void PlayRainStoppingSoundEffect(void);
u8 IsWeatherChangeComplete(void);
void SetWeatherScreenFadeOut(void);
void SetWeatherPalStateIdle(void);
const u8* SetPaletteColorMapType(u8 paletteIndex, u8 colorMapType);
void PreservePaletteInWeather(u8 preservedPalIndex);
void ResetPaletteColorMapType(u8 paletteIndex);
void ResetPreservedPalettesInWeather(void);
// field_weather_effect.c

View File

@ -599,6 +599,7 @@
#define BLDCNT_EFFECT_BLEND (1 << 6) // 1st+2nd targets mixed (controlled by BLDALPHA)
#define BLDCNT_EFFECT_LIGHTEN (2 << 6) // 1st target becomes whiter (controlled by BLDY)
#define BLDCNT_EFFECT_DARKEN (3 << 6) // 1st target becomes blacker (controlled by BLDY)
#define BLDCNT_EFFECT_EFF_MASK (3 << 6) // mask to check effect
// Bits 8-13 select layers for the 2nd target
#define BLDCNT_TGT2_BG0 (1 << 8)
#define BLDCNT_TGT2_BG1 (1 << 9)
@ -611,6 +612,8 @@
// BLDALPHA
#define BLDALPHA_BLEND(target1, target2) (((target2) << 8) | (target1))
#define BLDALPHA_TGT1(bld) ((bld) & 0x1F)
#define BLDALPHA_TGT2(bld) (((bld) >> 8) & 0x1F)
// SOUNDCNT_H
#define SOUND_CGB_MIX_QUARTER 0x0000

View File

@ -30,6 +30,11 @@
#define TIME_OF_DAY_DAY 2
#define TIME_OF_DAY_MAX TIME_OF_DAY_DAY
// trigger a time-of-day blend once
#define HOURS_BLEND_ONCE 25
// don't update currentTimeBlend
#define HOURS_FREEZE_BLEND 26
struct InitialPlayerAvatarState
{
u8 transitionFlags;
@ -44,14 +49,6 @@ struct LinkPlayerObjectEvent
u8 movementMode;
};
struct __attribute__((packed)) TimeBlendSettings {
u16 weight:9;
u16 time1:3;
u16 time0:3;
u16 unused:1;
u16 altWeight;
};
// Exported RAM declarations
extern struct WarpData gLastUsedWarp;
extern struct LinkPlayerObjectEvent gLinkPlayerObjectEvents[4];
@ -65,7 +62,7 @@ extern bool8 (*gFieldCallback2)(void);
extern u8 gLocalLinkPlayerId;
extern u8 gFieldLinkPlayerCount;
extern u8 gTimeOfDay;
extern u16 gTimeUpdateCounter;
extern s16 gTimeUpdateCounter;
extern struct TimeBlendSettings currentTimeBlend;
@ -175,5 +172,6 @@ bool32 Overworld_RecvKeysFromLinkIsRunning(void);
bool32 Overworld_SendKeysToLinkIsRunning(void);
bool32 IsSendingKeysOverCable(void);
void ClearLinkPlayerObjectEvents(void);
bool16 SetTimeOfDay(u16 hours);
#endif // GUARD_OVERWORLD_H

View File

@ -45,6 +45,13 @@ struct BlendSettings {
u32 coeff:5;
};
struct __attribute__((packed)) TimeBlendSettings {
struct BlendSettings bld0;
struct BlendSettings bld1;
u16 weight;
u16 altWeight;
};
struct PaletteFadeControl
{
u32 multipurpose1; // This field needs to exist or errors will occur
@ -92,7 +99,7 @@ void InvertPlttBuffer(u32 selectedPalettes);
void TintPlttBuffer(u32 selectedPalettes, s8 r, s8 g, s8 b);
void UnfadePlttBuffer(u32 selectedPalettes);
void BeginFastPaletteFade(u8 submode);
void BeginHardwarePaletteFade(u8 blendCnt, u8 delay, u8 y, u8 targetY, u8 shouldResetBlendRegisters);
void BeginHardwarePaletteFade(u16 blendCnt, u8 delay, u8 y, u8 targetY, u8 shouldResetBlendRegisters);
void BlendPalettes(u32 selectedPalettes, u8 coeff, u16 color);
void BlendPalettesFine(u32 palettes, u16 *src, u16 *dst, u32 coeff, u32 color);
void BlendPalettesUnfaded(u32 selectedPalettes, u8 coeff, u16 color);

View File

@ -2513,6 +2513,8 @@ void UpdateLightSprite(struct Sprite *sprite) {
return;
}
// Note to self: Don't set window registers during hardware fade!
switch (sprite->data[5]) { // lightType
case 0:
if (gPaletteFade.active) { // if palette fade is active, don't flicker since the timer won't be updated
@ -2566,7 +2568,7 @@ static void SpawnLightSprite(s16 x, s16 y, s16 camX, s16 camY, u32 lightType) {
sprite->centerToCornerVecX = -(32 >> 1);
sprite->centerToCornerVecY = -(32 >> 1);
sprite->oam.priority = 1;
sprite->oam.objMode = 1; // BLEND
sprite->oam.objMode = ST_OAM_OBJ_BLEND;
sprite->oam.affineMode = ST_OAM_AFFINE_NORMAL;
sprite->x += 8;
sprite->y += 22 + sprite->centerToCornerVecY;
@ -2576,7 +2578,7 @@ static void SpawnLightSprite(s16 x, s16 y, s16 camX, s16 camY, u32 lightType) {
sprite->centerToCornerVecY = -(16 >> 1);
sprite->oam.priority = 2;
sprite->subpriority = 0xFF;
sprite->oam.objMode = 1; // BLEND
sprite->oam.objMode = ST_OAM_OBJ_BLEND;
}
}

View File

@ -781,9 +781,11 @@ void FieldEffectScript_LoadTiles(u8 **script)
void FieldEffectScript_LoadFadedPalette(u8 **script)
{
struct SpritePalette *palette = (struct SpritePalette *)FieldEffectScript_ReadWord(script);
LoadSpritePalette(palette);
UpdateSpritePaletteWithWeather(IndexOfSpritePaletteTag(palette->tag), TRUE);
u32 paletteSlot = LoadSpritePalette(palette);
(*script) += 4;
SetPaletteColorMapType(paletteSlot + 16, T1_READ_8(*script));
UpdateSpritePaletteWithWeather(paletteSlot, TRUE);
(*script)++;
}
void FieldEffectScript_LoadPalette(u8 **script)
@ -839,6 +841,7 @@ void FieldEffectFreePaletteIfUnused(u8 paletteNum)
for (i = 0; i < MAX_SPRITES; i++)
if (gSprites[i].inUse && gSprites[i].oam.paletteNum == paletteNum)
return;
ResetPaletteColorMapType(paletteNum + 16);
FreeSpritePaletteByTag(tag);
}
}

View File

@ -56,8 +56,8 @@ u32 FldEff_Shadow(void);
void SetUpShadow(struct ObjectEvent *objectEvent, struct Sprite *sprite) {
gFieldEffectArguments[0] = objectEvent->localId;
gFieldEffectArguments[1] = gSaveBlock1Ptr->location.mapNum;
gFieldEffectArguments[2] = gSaveBlock1Ptr->location.mapGroup;
gFieldEffectArguments[1] = objectEvent->mapNum;
gFieldEffectArguments[2] = objectEvent->mapGroup;
FldEff_Shadow();
}
@ -328,7 +328,11 @@ u32 FldEff_Shadow(void)
s32 i;
for (i = MAX_SPRITES - 1; i > -1; i--) { // Search backwards, because of CreateSpriteAtEnd
// Return early if a shadow sprite already exists
if (gSprites[i].data[0] == gFieldEffectArguments[0] && gSprites[i].callback == UpdateShadowFieldEffect)
if (gSprites[i].callback == UpdateShadowFieldEffect &&
gSprites[i].sLocalId == gFieldEffectArguments[0] &&
gSprites[i].sMapNum == gFieldEffectArguments[1] &&
gSprites[i].sMapGroup == gFieldEffectArguments[2]
)
return 0;
}
objectEventId = GetObjectEventIdByLocalIdAndMap(gFieldEffectArguments[0], gFieldEffectArguments[1], gFieldEffectArguments[2]);
@ -340,7 +344,7 @@ u32 FldEff_Shadow(void)
if (spriteId != MAX_SPRITES)
{
// SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(8, 12));
gSprites[spriteId].oam.objMode = 1; // BLEND
gSprites[spriteId].oam.objMode = ST_OAM_OBJ_BLEND;
gSprites[spriteId].coordOffsetEnabled = TRUE;
gSprites[spriteId].sLocalId = gFieldEffectArguments[0];
gSprites[spriteId].sMapNum = gFieldEffectArguments[1];

View File

@ -20,13 +20,6 @@
#define DROUGHT_COLOR_INDEX(color) ((((color) >> 1) & 0xF) | (((color) >> 2) & 0xF0) | (((color) >> 3) & 0xF00))
enum
{
COLOR_MAP_NONE,
COLOR_MAP_DARK_CONTRAST,
COLOR_MAP_CONTRAST,
};
struct RGBColor
{
u16 r:5;
@ -806,8 +799,8 @@ void FadeScreen(u8 mode, s8 delay)
if (MapHasNaturalLight(gMapHeader.mapType)) {
UpdateAltBgPalettes(PALETTES_BG);
BeginTimeOfDayPaletteFade(PALETTES_ALL, delay, 16, 0,
(struct BlendSettings *)&gTimeOfDayBlend[currentTimeBlend.time0],
(struct BlendSettings *)&gTimeOfDayBlend[currentTimeBlend.time1],
&currentTimeBlend.bld0,
&currentTimeBlend.bld1,
currentTimeBlend.weight, fadeColor);
} else {
BeginNormalPaletteFade(PALETTES_ALL, delay, 16, 0, fadeColor);
@ -822,6 +815,36 @@ void FadeScreen(u8 mode, s8 delay)
}
}
// fades screen using BLDY
// Note: This enables blending in all windows;
// These bits may need to be disabled later
// (i.e if blending lighting effects using WINOBJ)
u16 FadeScreenHardware(u8 mode, s8 delay) {
u16 bldCnt = GetGpuReg(REG_OFFSET_BLDCNT) & BLDCNT_TGT2_ALL;
bldCnt |= BLDCNT_TGT1_ALL;
// enable blend in all windows
SetGpuRegBits(REG_OFFSET_WININ, WININ_WIN0_CLR | WININ_WIN1_CLR);
SetGpuRegBits(REG_OFFSET_WINOUT, WINOUT_WIN01_CLR);
switch (mode)
{
case FADE_FROM_BLACK:
BeginHardwarePaletteFade(bldCnt | BLDCNT_EFFECT_DARKEN, delay, 16, 0, TRUE);
break;
case FADE_TO_BLACK:
BeginHardwarePaletteFade(bldCnt | BLDCNT_EFFECT_DARKEN, delay, 0, 16, FALSE);
break;
case FADE_FROM_WHITE:
BeginHardwarePaletteFade(bldCnt | BLDCNT_EFFECT_LIGHTEN, delay, 16, 0, TRUE);
break;
case FADE_TO_WHITE:
BeginHardwarePaletteFade(bldCnt | BLDCNT_EFFECT_LIGHTEN, delay, 0, 16, FALSE);
break;
}
return 0;
}
bool8 IsWeatherNotFadingIn(void)
{
return (gWeatherPtr->palProcessingState != WEATHER_PAL_STATE_SCREEN_FADING_IN);
@ -986,7 +1009,10 @@ void Weather_SetBlendCoeffs(u8 eva, u8 evb)
gWeatherPtr->currBlendEVB = evb;
gWeatherPtr->targetBlendEVA = eva;
gWeatherPtr->targetBlendEVB = evb;
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(eva, evb));
// don't update BLDALPHA if a hardware fade is on-screen
if ((GetGpuReg(REG_OFFSET_BLDCNT) & BLDCNT_EFFECT_EFF_MASK) < BLDCNT_EFFECT_LIGHTEN)
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(eva, evb));
}
void Weather_SetTargetBlendCoeffs(u8 eva, u8 evb, int delay)
@ -1136,11 +1162,27 @@ void SetWeatherPalStateIdle(void)
gWeatherPtr->palProcessingState = WEATHER_PAL_STATE_IDLE;
}
const u8* SetPaletteColorMapType(u8 paletteIndex, u8 colorMapType) {
if (sPaletteColorMapTypes[paletteIndex] == colorMapType)
return sPaletteColorMapTypes;
// setup field effect color map
if (sPaletteColorMapTypes != sFieldEffectPaletteColorMapTypes) {
CpuFastCopy(sBasePaletteColorMapTypes, sFieldEffectPaletteColorMapTypes, 32);
sPaletteColorMapTypes = sFieldEffectPaletteColorMapTypes;
}
sFieldEffectPaletteColorMapTypes[paletteIndex] = colorMapType;
return sPaletteColorMapTypes;
}
void PreservePaletteInWeather(u8 preservedPalIndex)
{
CpuCopy16(sBasePaletteColorMapTypes, sFieldEffectPaletteColorMapTypes, 32);
sFieldEffectPaletteColorMapTypes[preservedPalIndex] = COLOR_MAP_NONE;
sPaletteColorMapTypes = sFieldEffectPaletteColorMapTypes;
SetPaletteColorMapType(preservedPalIndex, COLOR_MAP_NONE);
}
void ResetPaletteColorMapType(u8 paletteIndex) {
if (sPaletteColorMapTypes == sBasePaletteColorMapTypes)
return;
sFieldEffectPaletteColorMapTypes[paletteIndex] = sBasePaletteColorMapTypes[paletteIndex];
}
void ResetPreservedPalettesInWeather(void)

View File

@ -881,7 +881,7 @@ static void LoadTilesetPalette(struct Tileset const *tileset, u16 destOffset, u1
{
// LoadPalette(&black, destOffset, 2);
if (skipFaded)
CpuFastCopy(tileset->palettes, &gPlttBufferUnfaded[destOffset], size);
CpuFastCopy(tileset->palettes, &gPlttBufferUnfaded[destOffset], size); // always word-aligned
else
LoadPaletteFast(tileset->palettes, destOffset, size);
gPlttBufferFaded[destOffset] = gPlttBufferUnfaded[destOffset] = RGB_BLACK; // why does it have to be black?
@ -891,11 +891,11 @@ static void LoadTilesetPalette(struct Tileset const *tileset, u16 destOffset, u1
}
else if (tileset->isSecondary == TRUE)
{
// (void*) is to silence 'source potentially unaligned' error
// All 'gTilesetPalettes_' arrays should have ALIGNED(4) in them
if (skipFaded)
CpuFastCopy((void*)tileset->palettes[NUM_PALS_IN_PRIMARY], &gPlttBufferUnfaded[destOffset], size);
else
// All 'gTilesetPalettes_' arrays should have ALIGNED(4) in them,
// but we use SmartCopy here just in case they don't
if (skipFaded) {
CpuSmartCopy16(tileset->palettes[NUM_PALS_IN_PRIMARY], &gPlttBufferUnfaded[destOffset], size);
} else
LoadPaletteFast(tileset->palettes[NUM_PALS_IN_PRIMARY], destOffset, size);
low = NUM_PALS_IN_PRIMARY;
high = NUM_PALS_TOTAL;

View File

@ -194,7 +194,7 @@ u8 gFieldLinkPlayerCount;
u8 gTimeOfDay;
struct TimeBlendSettings currentTimeBlend;
u16 gTimeUpdateCounter; // playTimeVBlanks will eventually overflow, so this is used to update TOD
s16 gTimeUpdateCounter; // playTimeVBlanks will eventually overflow, so this is used to update TOD
// EWRAM vars
EWRAM_DATA static u8 sObjectEventLoadFlag = 0;
@ -206,6 +206,7 @@ EWRAM_DATA static u16 sLastMapSectionId = 0;
EWRAM_DATA static struct InitialPlayerAvatarState sInitialPlayerAvatarState = {0};
EWRAM_DATA static u16 sAmbientCrySpecies = 0;
EWRAM_DATA static bool8 sIsAmbientCryWaterMon = FALSE;
EWRAM_DATA static u8 sHoursOverride = 0; // used to override apparent time of day hours
EWRAM_DATA struct LinkPlayerObjectEvent gLinkPlayerObjectEvents[4] = {0};
static const struct WarpData sDummyWarpData =
@ -853,6 +854,8 @@ static void LoadMapFromWarp(bool32 a1)
CheckLeftFriendsSecretBase();
TrySetMapSaveWarpStatus();
ClearTempFieldEventData();
// reset hours override on every warp
sHoursOverride = 0;
ResetCyclingRoadChallengeData();
RestartWildEncounterImmunitySteps();
TryUpdateRandomTrainerRematches(gSaveBlock1Ptr->location.mapGroup, gSaveBlock1Ptr->location.mapNum);
@ -1481,44 +1484,65 @@ const struct BlendSettings gTimeOfDayBlend[] =
u8 UpdateTimeOfDay(void) {
s32 hours, minutes;
RtcCalcLocalTime();
hours = gLocalTime.hours;
minutes = gLocalTime.minutes;
if (hours < 4) { // night
hours = sHoursOverride ? sHoursOverride : gLocalTime.hours;
minutes = sHoursOverride ? 0 : gLocalTime.minutes;
switch (hours)
{
case 0 ... 3: // night
gTimeOfDay = TIME_OF_DAY_NIGHT;
currentTimeBlend.bld0 = currentTimeBlend.bld1 = gTimeOfDayBlend[gTimeOfDay];
currentTimeBlend.weight = 256;
currentTimeBlend.altWeight = 0;
gTimeOfDay = currentTimeBlend.time0 = currentTimeBlend.time1 = TIME_OF_DAY_NIGHT;
} else if (hours < 7) { // night->twilight
currentTimeBlend.time0 = TIME_OF_DAY_NIGHT;
currentTimeBlend.time1 = TIME_OF_DAY_TWILIGHT;
break;
case 4 ... 6: // night -> twilight
currentTimeBlend.bld0 = gTimeOfDayBlend[TIME_OF_DAY_NIGHT];
currentTimeBlend.bld1 = gTimeOfDayBlend[TIME_OF_DAY_TWILIGHT];
currentTimeBlend.weight = 256 - 256 * ((hours - 4) * 60 + minutes) / ((7-4)*60);
currentTimeBlend.altWeight = (256 - currentTimeBlend.weight) / 2;
gTimeOfDay = TIME_OF_DAY_DAY;
} else if (hours < 10) { // twilight->day
currentTimeBlend.time0 = TIME_OF_DAY_TWILIGHT;
currentTimeBlend.time1 = TIME_OF_DAY_DAY;
break;
case 7 ... 9: // twilight -> day
currentTimeBlend.bld0 = gTimeOfDayBlend[TIME_OF_DAY_TWILIGHT];
currentTimeBlend.bld1 = gTimeOfDayBlend[TIME_OF_DAY_DAY];
currentTimeBlend.weight = 256 - 256 * ((hours - 7) * 60 + minutes) / ((10-7)*60);
currentTimeBlend.altWeight = (256 - currentTimeBlend.weight) / 2 + 128;
gTimeOfDay = TIME_OF_DAY_DAY;
} else if (hours < 18) { // day
break;
case 10 ... 17: // day
gTimeOfDay = TIME_OF_DAY_DAY;
currentTimeBlend.bld0 = currentTimeBlend.bld1 = gTimeOfDayBlend[gTimeOfDay];
currentTimeBlend.weight = currentTimeBlend.altWeight = 256;
gTimeOfDay = currentTimeBlend.time0 = currentTimeBlend.time1 = TIME_OF_DAY_DAY;
} else if (hours < 20) { // day->twilight
currentTimeBlend.time0 = TIME_OF_DAY_DAY;
currentTimeBlend.time1 = TIME_OF_DAY_TWILIGHT;
break;
case 18 ... 19: // day -> twilight
currentTimeBlend.bld0 = gTimeOfDayBlend[TIME_OF_DAY_DAY];
currentTimeBlend.bld1 = gTimeOfDayBlend[TIME_OF_DAY_TWILIGHT];
currentTimeBlend.weight = 256 - 256 * ((hours - 18) * 60 + minutes) / ((20-18)*60);
currentTimeBlend.altWeight = currentTimeBlend.weight / 2 + 128;
gTimeOfDay = TIME_OF_DAY_TWILIGHT;
} else if (hours < 22) { // twilight->night
currentTimeBlend.time0 = TIME_OF_DAY_TWILIGHT;
currentTimeBlend.time1 = TIME_OF_DAY_NIGHT;
break;
case 20 ... 21: // twilight -> night
currentTimeBlend.bld0 = gTimeOfDayBlend[TIME_OF_DAY_TWILIGHT];
currentTimeBlend.bld1 = gTimeOfDayBlend[TIME_OF_DAY_NIGHT];
currentTimeBlend.weight = 256 - 256 * ((hours - 20) * 60 + minutes) / ((22-20)*60);
currentTimeBlend.altWeight = currentTimeBlend.weight / 2;
gTimeOfDay = TIME_OF_DAY_NIGHT;
} else { // 22-24, night
break;
case 22 ... 24:
gTimeOfDay = TIME_OF_DAY_NIGHT;
currentTimeBlend.bld0 = currentTimeBlend.bld1 = gTimeOfDayBlend[gTimeOfDay];
currentTimeBlend.weight = 256;
currentTimeBlend.altWeight = 0;
gTimeOfDay = currentTimeBlend.time0 = currentTimeBlend.time1 = TIME_OF_DAY_NIGHT;
break;
// special value; always causes a blend update,
// and increments sHoursOverride
case HOURS_BLEND_ONCE:
currentTimeBlend.weight ^= 1;
sHoursOverride++;
break;
case HOURS_FREEZE_BLEND:
break;
}
return gTimeOfDay;
}
@ -1565,32 +1589,32 @@ void UpdatePalettesWithTime(u32 palettes) {
if (IS_BLEND_IMMUNE_TAG(GetSpritePaletteTagByPaletteNum(i)))
palettes &= ~(mask);
palettes &= PALETTES_MAP | PALETTES_OBJECTS; // Don't blend UI pals
if (!palettes)
return;
TimeMixPalettes(
palettes,
gPlttBufferUnfaded,
gPlttBufferFaded,
(struct BlendSettings *)&gTimeOfDayBlend[currentTimeBlend.time0],
(struct BlendSettings *)&gTimeOfDayBlend[currentTimeBlend.time1],
currentTimeBlend.weight
);
palettes &= PALETTES_MAP | PALETTES_OBJECTS; // Don't blend UI pals
if (!palettes)
return;
TimeMixPalettes(
palettes,
gPlttBufferUnfaded,
gPlttBufferFaded,
&currentTimeBlend.bld0,
&currentTimeBlend.bld1,
currentTimeBlend.weight
);
}
}
u8 UpdateSpritePaletteWithTime(u8 paletteNum) {
if (MapHasNaturalLight(gMapHeader.mapType)) {
if (IS_BLEND_IMMUNE_TAG(GetSpritePaletteTagByPaletteNum(paletteNum)))
return paletteNum;
TimeMixPalettes(
1,
&gPlttBufferUnfaded[OBJ_PLTT_ID(paletteNum)],
&gPlttBufferFaded[OBJ_PLTT_ID(paletteNum)],
(struct BlendSettings *)&gTimeOfDayBlend[currentTimeBlend.time0],
(struct BlendSettings *)&gTimeOfDayBlend[currentTimeBlend.time1],
currentTimeBlend.weight
);
return paletteNum;
TimeMixPalettes(
1,
&gPlttBufferUnfaded[OBJ_PLTT_ID(paletteNum)],
&gPlttBufferFaded[OBJ_PLTT_ID(paletteNum)],
&currentTimeBlend.bld0,
&currentTimeBlend.bld1,
currentTimeBlend.weight
);
}
return paletteNum;
}
@ -1607,18 +1631,16 @@ static void OverworldBasic(void)
UpdateTilesetAnimations();
DoScheduledBgTilemapCopiesToVram();
// Every minute if no palette fade is active, update TOD blending as needed
if (!gPaletteFade.active && ++gTimeUpdateCounter >= 3600) {
struct TimeBlendSettings cachedBlend = {
.time0 = currentTimeBlend.time0,
.time1 = currentTimeBlend.time1,
.weight = currentTimeBlend.weight,
};
gTimeUpdateCounter = 0;
if (!gPaletteFade.active && --gTimeUpdateCounter <= 0) {
struct TimeBlendSettings cachedBlend = currentTimeBlend;
u32 *bld0 = (u32*)&cachedBlend;
u32 *bld1 = (u32*)&currentTimeBlend;
gTimeUpdateCounter = 3600;
UpdateTimeOfDay();
if (cachedBlend.time0 != currentTimeBlend.time0
|| cachedBlend.time1 != currentTimeBlend.time1
|| cachedBlend.weight != currentTimeBlend.weight)
{
if (bld0[0] != bld1[0]
|| bld0[1] != bld1[1]
|| bld0[2] != bld1[2]
) {
UpdateAltBgPalettes(PALETTES_BG);
UpdatePalettesWithTime(PALETTES_ALL);
}
@ -3380,3 +3402,16 @@ static void SpriteCB_LinkPlayer(struct Sprite *sprite)
sprite->data[7]++;
}
}
// returns old sHoursOverride
u16 SetTimeOfDay(u16 hours) {
u16 oldHours = sHoursOverride;
sHoursOverride = hours;
gTimeUpdateCounter = 0;
return oldHours;
}
bool8 ScrFunc_settimeofday(struct ScriptContext *ctx) {
SetTimeOfDay(ScriptReadByte(ctx));
return FALSE;
}

View File

@ -896,7 +896,7 @@ static u8 UpdateFastPaletteFade(void)
return gPaletteFade.active ? PALETTE_FADE_STATUS_ACTIVE : PALETTE_FADE_STATUS_DONE;
}
void BeginHardwarePaletteFade(u8 blendCnt, u8 delay, u8 y, u8 targetY, u8 shouldResetBlendRegisters)
void BeginHardwarePaletteFade(u16 blendCnt, u8 delay, u8 y, u8 targetY, u8 shouldResetBlendRegisters)
{
gPaletteFade_blendCnt = blendCnt;
gPaletteFade.delayCounter = delay;
@ -950,7 +950,8 @@ static u8 UpdateHardwarePaletteFade(void)
{
if (gPaletteFade.shouldResetBlendRegisters)
{
gPaletteFade_blendCnt = 0;
// clear TGT1
gPaletteFade_blendCnt &= ~0xFF;
gPaletteFade.y = 0;
}
gPaletteFade.shouldResetBlendRegisters = FALSE;
@ -961,10 +962,43 @@ static u8 UpdateHardwarePaletteFade(void)
return gPaletteFade.active ? PALETTE_FADE_STATUS_ACTIVE : PALETTE_FADE_STATUS_DONE;
}
// Only called for hardware fades
static void UpdateBlendRegisters(void)
{
SetGpuReg(REG_OFFSET_BLDCNT, (u16)gPaletteFade_blendCnt);
SetGpuReg(REG_OFFSET_BLDY, gPaletteFade.y);
// If fade-out, also adjust BLDALPHA and DISPCNT
if (!gPaletteFade.yDec /*&& gPaletteFade.mode == HARDWARE_FADE*/) {
u16 bldAlpha = GetGpuReg(REG_OFFSET_BLDALPHA);
u8 tgt1 = BLDALPHA_TGT1(bldAlpha);
u8 tgt2 = BLDALPHA_TGT2(bldAlpha);
u8 bldFade;
switch (gPaletteFade_blendCnt & BLDCNT_EFFECT_EFF_MASK)
{
// FADE_TO_BLACK
case BLDCNT_EFFECT_DARKEN:
bldFade = BLDALPHA_TGT1(max(0, 16 - gPaletteFade.y));
SetGpuReg(
REG_OFFSET_BLDALPHA,
BLDALPHA_BLEND(min(tgt1, bldFade), min(tgt2, bldFade))
);
break;
// FADE_TO_WHITE
case BLDCNT_EFFECT_LIGHTEN:
SetGpuReg(
REG_OFFSET_BLDALPHA,
BLDALPHA_BLEND(min(++tgt1, 31), min(++tgt2, 31))
);
// cause display to show white when finished
// (otherwise blend-mode sprites will still be visible)
if (gPaletteFade.hardwareFadeFinishing && gPaletteFade.y >= 16)
SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_FORCED_BLANK);
break;
}
} else
ClearGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_FORCED_BLANK);
if (gPaletteFade.hardwareFadeFinishing)
{
gPaletteFade.hardwareFadeFinishing = FALSE;

View File

@ -23,6 +23,7 @@
#include "field_tasks.h"
#include "field_weather.h"
#include "fieldmap.h"
#include "gpu_regs.h"
#include "item.h"
#include "lilycove_lady.h"
#include "main.h"
@ -661,19 +662,19 @@ bool8 ScrCmd_fadescreenswapbuffers(struct ScriptContext *ctx)
switch (mode)
{
case FADE_TO_BLACK:
case FADE_TO_WHITE:
default:
CpuCopy32(gPlttBufferUnfaded, gPaletteDecompressionBuffer, PLTT_SIZE);
FadeScreen(mode, 0);
break;
case FADE_FROM_BLACK:
case FADE_FROM_WHITE:
CpuCopy32(gPaletteDecompressionBuffer, gPlttBufferUnfaded, PLTT_SIZE);
FadeScreen(mode, 0);
// Restore last weather blend before fading in,
// since BLDALPHA was modified by fade-out
SetGpuReg(
REG_OFFSET_BLDALPHA,
BLDALPHA_BLEND(gWeatherPtr->currBlendEVA, gWeatherPtr->currBlendEVB)
);
break;
}
FadeScreenHardware(mode, 0);
if (nowait)
return FALSE;
SetupNativeScript(ctx, IsPaletteNotActive);