From 42d5fe07fad481e79b779848d8abba2d93736b99 Mon Sep 17 00:00:00 2001 From: Ariel Antonitis Date: Sun, 21 Jun 2020 22:26:41 -0400 Subject: [PATCH] Start of implementation for time of day filter. --- common_syms/overworld.txt | 1 + .../rustboro/metatile_attributes.bin | Bin 700 -> 700 bytes graphics/object_events/palettes/light.pal | 19 +++ graphics/object_events/pics/misc/light.png | Bin 0 -> 3064 bytes include/event_object_movement.h | 1 + include/global.h | 2 + include/overworld.h | 8 +- include/palette.h | 1 + .../field_effect_object_template_pointers.h | 1 + src/data/field_effects/field_effect_objects.h | 6 + .../object_events/object_event_graphics.h | 9 +- src/event_object_movement.c | 100 ++++++++++++- src/field_effect_helpers.c | 6 +- src/field_weather.c | 2 + src/field_weather_effect.c | 8 +- src/overworld.c | 71 ++++++++- src/palette.c | 141 +++++++++++++++++- 17 files changed, 354 insertions(+), 22 deletions(-) create mode 100644 graphics/object_events/palettes/light.pal create mode 100644 graphics/object_events/pics/misc/light.png diff --git a/common_syms/overworld.txt b/common_syms/overworld.txt index e136f54449..4833362098 100644 --- a/common_syms/overworld.txt +++ b/common_syms/overworld.txt @@ -6,3 +6,4 @@ gFieldCallback gFieldCallback2 gLocalLinkPlayerId gFieldLinkPlayerCount +gTimeOfDay diff --git a/data/tilesets/secondary/rustboro/metatile_attributes.bin b/data/tilesets/secondary/rustboro/metatile_attributes.bin index e2b728c657ac47e17dd2881b8dc1b3408baeb5db..56b728b08c8aa8566c69bc7c04bf414980f3c773 100644 GIT binary patch delta 14 VcmdnPx`%aw3Ns4>%SQF7OaLD*1F--A delta 13 UcmdnPx`%aw%ES*M8!cLx04BTzI{*Lx diff --git a/graphics/object_events/palettes/light.pal b/graphics/object_events/palettes/light.pal new file mode 100644 index 0000000000..3beca89bdf --- /dev/null +++ b/graphics/object_events/palettes/light.pal @@ -0,0 +1,19 @@ +JASC-PAL +0100 +16 +110 198 165 +255 213 18 +255 214 38 +254 217 39 +254 218 53 +255 220 65 +255 221 76 +255 223 86 +254 225 95 +254 228 104 +254 229 112 +254 230 120 +255 232 132 +255 235 148 +255 237 162 +255 240 176 diff --git a/graphics/object_events/pics/misc/light.png b/graphics/object_events/pics/misc/light.png new file mode 100644 index 0000000000000000000000000000000000000000..d1a0402d102cf52e47a584f2feb56230d5b7debf GIT binary patch literal 3064 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 e8c5f3ad6 (Added all 386 follower sprites.) const u32 gObjectEventPic_AnimatedBall[] = INCBIN_U32("graphics/object_events/pics/misc/animated_ball.4bpp"); const u16 gObjectEventPalette31[] = INCBIN_U16("graphics/object_events/palettes/31.gbapal"); const u32 gObjectEventPic_Bulbasaur[] = INCBIN_U32("graphics/object_events/pics/pokemon/bulbasaur.4bpp"); @@ -784,3 +778,4 @@ const u32 gObjectEventPic_LugiaOld[] = INCBIN_U32("graphics/object_events/pics/p const u32 gObjectEventPic_HoOhOld[] = INCBIN_U32("graphics/object_events/pics/pokemon/ho_oh_old.4bpp"); const u32 gObjectEventPic_GroudonOld[] = INCBIN_U32("graphics/object_events/pics/pokemon/groudon_old.4bpp"); const u32 gObjectEventPic_KyogreOld[] = INCBIN_U32("graphics/object_events/pics/pokemon/kyogre_old.4bpp"); +const u16 gObjectEventPaletteLight[] = INCBIN_U16("graphics/object_events/palettes/light.gbapal"); diff --git a/src/event_object_movement.c b/src/event_object_movement.c index 5a22b3f59d..348d65fdc8 100644 --- a/src/event_object_movement.c +++ b/src/event_object_movement.c @@ -451,6 +451,7 @@ const u8 gInitialMovementTypeFacingDirections[] = { #define OBJ_EVENT_PAL_TAG_RS_BRENDAN 0x1122 #define OBJ_EVENT_PAL_TAG_RS_MAY 0x1123 #define OBJ_EVENT_PAL_TAG_DYNAMIC 0x1124 +#define OBJ_EVENT_PAL_TAG_LIGHT 0x8001 #define OBJ_EVENT_PAL_TAG_NONE 0x11FF #include "data/object_events/object_event_graphics_info_pointers.h" @@ -498,6 +499,7 @@ static const struct SpritePalette sObjectEventSpritePalettes[] = { {gObjectEventPal_RubySapphireBrendan, OBJ_EVENT_PAL_TAG_RS_BRENDAN}, {gObjectEventPal_RubySapphireMay, OBJ_EVENT_PAL_TAG_RS_MAY}, {gObjectEventPalette0, OBJ_EVENT_PAL_TAG_DYNAMIC}, + {gObjectEventPaletteLight, OBJ_EVENT_PAL_TAG_LIGHT}, {NULL, 0x0000}, }; @@ -1753,6 +1755,87 @@ bool8 ScrFunc_followerfly(struct ScriptContext *ctx) { return FALSE; } +// Callback for light sprites +void UpdateLightSprite(struct Sprite *sprite) { + s16 left = gSaveBlock1Ptr->pos.x - 2; + s16 right = gSaveBlock1Ptr->pos.x + 17; + s16 top = gSaveBlock1Ptr->pos.y; + s16 bottom = gSaveBlock1Ptr->pos.y + 15; + s16 x = sprite->data[6]; + s16 y = sprite->data[7]; + u16 sheetTileStart; + u32 paletteNum; + bool8 finished = TRUE; + // Ripped from RemoveObjectEventIfOutsideView + if (x >= left && x <= right + && y >= top && y <= bottom) + finished = FALSE; + if (x >= left && x <= right + && y >= top && y <= bottom) + finished = FALSE; + finished = finished ? finished : gTimeOfDay != TIME_OF_DAY_NIGHT; + if (finished) { + sheetTileStart = sprite->sheetTileStart; + paletteNum = sprite->oam.paletteNum; + DestroySprite(sprite); + FieldEffectFreeTilesIfUnused(sheetTileStart); + FieldEffectFreePaletteIfUnused(paletteNum); + return; + } + + if (gPlayerAvatar.tileTransitionState) { + Weather_SetBlendCoeffs(7, 12); + sprite->invisible = FALSE; + } else { + Weather_SetBlendCoeffs(12, 12); + sprite->invisible = gSaveBlock2Ptr->playTimeVBlanks & 1; + } +} + +// Spawn a light at a map coordinate based on metatile behavior +static void SpawnLightSprite(s16 x, s16 y, s16 camX, s16 camY, u32 behavior) { + struct Sprite *sprite; + u8 i; + for (i = 0; i < MAX_SPRITES; i++) { + sprite = &gSprites[i]; + if (sprite->inUse && sprite->callback == UpdateLightSprite && sprite->data[6] == x && sprite->data[7] == y) + return; + } + sprite = &gSprites[CreateSprite(&gFieldEffectObjectTemplate_BallLight, 0, 0, 0)]; + UpdateSpritePaletteByTemplate(&gFieldEffectObjectTemplate_BallLight, sprite); + sub_8092FF0(x + camX, y + camY, &sprite->pos1.x, &sprite->pos1.y); + sprite->data[6] = x; + sprite->data[7] = y; + sprite->affineAnims = gDummySpriteAffineAnimTable; + sprite->affineAnimBeginning = TRUE; + sprite->centerToCornerVecX = -(32 >> 1); + sprite->centerToCornerVecY = -(32 >> 1); + sprite->oam.priority = 1; + sprite->oam.objMode = 1; // BLEND + sprite->oam.affineMode = ST_OAM_AFFINE_NORMAL; + sprite->coordOffsetEnabled = TRUE; + sprite->pos1.x += 8; + sprite->pos1.y += 22 + sprite->centerToCornerVecY; +} + +void TrySpawnLightSprites(s16 camX, s16 camY) { + s16 left = gSaveBlock1Ptr->pos.x - 2; + s16 right = gSaveBlock1Ptr->pos.x + 17; + s16 top = gSaveBlock1Ptr->pos.y; + s16 bottom = gSaveBlock1Ptr->pos.y + 16; + s16 x, y; + u32 behavior; + if (gTimeOfDay != TIME_OF_DAY_NIGHT) + return; + for (x = left; x <= right; x++) { + for (y = top; y <= bottom; y++) { + behavior = MapGridGetMetatileBehaviorAt(x, y); + if (behavior == 0x04) // TODO: Use an actual constant + SpawnLightSprite(x, y, camX, camY, behavior); + } + } +} + void TrySpawnObjectEvents(s16 cameraX, s16 cameraY) { u8 i; @@ -1789,6 +1872,7 @@ void TrySpawnObjectEvents(s16 cameraX, s16 cameraY) TrySpawnObjectEventTemplate(template, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, cameraX, cameraY); } } + TrySpawnLightSprites(cameraX, cameraY); } void RemoveObjectEventsOutsideView(void) @@ -1829,7 +1913,7 @@ static void RemoveObjectEventIfOutsideView(struct ObjectEvent *objectEvent) RemoveObjectEvent(objectEvent); } -void sub_808E16C(s16 x, s16 y) +void sub_808E16C(s16 x, s16 y) // Called when returning to field { u8 i; @@ -1842,6 +1926,7 @@ void sub_808E16C(s16 x, s16 y) } } CreateReflectionEffectSprites(); + TrySpawnLightSprites(x, y); } static void sub_808E1B8(u8 objectEventId, s16 x, s16 y) @@ -1934,7 +2019,13 @@ static u8 UpdateSpritePalette(const struct SpritePalette * spritePalette, struct sprite->inUse = FALSE; FieldEffectFreePaletteIfUnused(sprite->oam.paletteNum); sprite->inUse = TRUE; - sprite->oam.paletteNum = LoadSpritePalette(spritePalette); + if (IndexOfSpritePaletteTag(spritePalette->tag) == 0xFF) { + sprite->oam.paletteNum = LoadSpritePalette(spritePalette); + UpdateSpritePaletteWithTime(sprite->oam.paletteNum); + } else { + sprite->oam.paletteNum = LoadSpritePalette(spritePalette); + } + return sprite->oam.paletteNum; } @@ -2186,11 +2277,14 @@ void Unused_LoadObjectEventPaletteSet(u16 *paletteTags) static u8 sub_808E8F4(const struct SpritePalette *spritePalette) { + u8 paletteNum; if (IndexOfSpritePaletteTag(spritePalette->tag) != 0xFF) { return 0xFF; } - return LoadSpritePalette(spritePalette); + paletteNum = LoadSpritePalette(spritePalette); + UpdateSpritePaletteWithTime(paletteNum); + return paletteNum; } void PatchObjectPalette(u16 paletteTag, u8 paletteSlot) diff --git a/src/field_effect_helpers.c b/src/field_effect_helpers.c index 994a8ada23..05ade09d9e 100755 --- a/src/field_effect_helpers.c +++ b/src/field_effect_helpers.c @@ -146,11 +146,10 @@ static void LoadObjectRegularReflectionPalette(struct ObjectEvent *objectEvent, } paletteNum = LoadSpritePalette(&filteredPalette); UpdateSpritePaletteWithWeather(paletteNum); + UpdateSpritePaletteWithTime(paletteNum); } sprite->oam.paletteNum = paletteNum; - // Apply alpha blending - // SetGpuReg(REG_OFFSET_BLDALPHA, sprite->data[7] == FALSE ? BLDALPHA_BLEND(8, 12) : BLDALPHA_BLEND(8, 8)); - sprite->oam.objMode = 1; // BLEND + sprite->oam.objMode = 1; // Alpha blending } #define HIGH_BRIDGE_PAL_TAG 0x4010 @@ -200,6 +199,7 @@ static void UpdateObjectReflectionSprite(struct Sprite *reflectionSprite) } paletteNum = LoadSpritePalette(&filteredPalette); UpdateSpritePaletteWithWeather(paletteNum); + UpdateSpritePaletteWithTime(paletteNum); } reflectionSprite->oam.paletteNum = paletteNum; } diff --git a/src/field_weather.c b/src/field_weather.c index 655e24590e..73f22d56c8 100644 --- a/src/field_weather.c +++ b/src/field_weather.c @@ -254,6 +254,7 @@ static void Task_WeatherMain(u8 taskId) static void None_Init(void) { + Weather_SetBlendCoeffs(8, 12); // Indoor shadows gWeatherPtr->gammaTargetIndex = 0; gWeatherPtr->gammaStepDelay = 0; } @@ -860,6 +861,7 @@ void LoadCustomWeatherSpritePalette(const u16 *palette) { LoadPalette(palette, 0x100 + gWeatherPtr->weatherPicSpritePalIndex * 16, 32); UpdateSpritePaletteWithWeather(gWeatherPtr->weatherPicSpritePalIndex); + UpdateSpritePaletteWithTime(gWeatherPtr->weatherPicSpritePalIndex); } static void LoadDroughtWeatherPalette(u8 *gammaIndexPtr, u8 *a1) diff --git a/src/field_weather_effect.c b/src/field_weather_effect.c index 4281117d1f..0d0b71fe27 100644 --- a/src/field_weather_effect.c +++ b/src/field_weather_effect.c @@ -478,7 +478,7 @@ void Rain_InitVars(void) gWeatherPtr->rainSpriteVisibleDelay = 8; gWeatherPtr->isDownpour = FALSE; gWeatherPtr->targetRainSpriteCount = 10; - gWeatherPtr->gammaTargetIndex = 3; + gWeatherPtr->gammaTargetIndex = gTimeOfDay == TIME_OF_DAY_DAY ? 3 : 0; gWeatherPtr->gammaStepDelay = 20; SetRainStrengthFromSoundEffect(SE_RAIN); } @@ -1020,7 +1020,7 @@ void Thunderstorm_InitVars(void) gWeatherPtr->rainSpriteVisibleDelay = 4; gWeatherPtr->isDownpour = FALSE; gWeatherPtr->targetRainSpriteCount = 16; - gWeatherPtr->gammaTargetIndex = 3; + gWeatherPtr->gammaTargetIndex = gTimeOfDay == TIME_OF_DAY_DAY ? 3 : 0; gWeatherPtr->gammaStepDelay = 20; gWeatherPtr->weatherGfxLoaded = FALSE; // duplicate assignment gWeatherPtr->thunderTriggered = 0; @@ -1116,6 +1116,8 @@ void Thunderstorm_Main(void) if (--gWeatherPtr->unknown_6E6 == 0) { sub_80ABC48(3); + if (gTimeOfDay != TIME_OF_DAY_DAY) + BlendPalettesWithTime(0xFFFFFFFF); gWeatherPtr->unknown_6EA = 1; if (--gWeatherPtr->unknown_6EC != 0) { @@ -1152,7 +1154,7 @@ void Thunderstorm_Main(void) case 13: if (--gWeatherPtr->unknown_6E6 == 0) { - sub_80ABC7C(19, 3, 5); + gTimeOfDay == TIME_OF_DAY_DAY ? sub_80ABC7C(19, 3, 5) : BlendPalettesWithTime(0xFFFFFFFF); gWeatherPtr->initStep++; } break; diff --git a/src/overworld.c b/src/overworld.c index 369db2173d..32bd469cf8 100644 --- a/src/overworld.c +++ b/src/overworld.c @@ -42,6 +42,7 @@ #include "random.h" #include "roamer.h" #include "rotating_gate.h" +#include "rtc.h" #include "safari_zone.h" #include "save.h" #include "save_location.h" @@ -175,6 +176,8 @@ static u16 (*sPlayerKeyInterceptCallback)(u32); static bool8 sUnknown_03000E18; static u8 sRfuKeepAliveTimer; +u8 static gTimeOfDayState; + // IWRAM common u16 *gBGTilemapBuffers1; u16 *gBGTilemapBuffers2; @@ -185,6 +188,8 @@ bool8 (*gFieldCallback2)(void); u8 gLocalLinkPlayerId; // This is our player id in a multiplayer mode. u8 gFieldLinkPlayerCount; +u8 gTimeOfDay; + // EWRAM vars EWRAM_DATA static u8 sObjectEventLoadFlag = 0; EWRAM_DATA struct WarpData gLastUsedWarp = {0}; @@ -197,6 +202,7 @@ EWRAM_DATA static u16 sAmbientCrySpecies = 0; EWRAM_DATA static bool8 sIsAmbientCryWaterMon = FALSE; EWRAM_DATA struct LinkPlayerObjectEvent gLinkPlayerObjectEvents[4] = {0}; + // const rom data static const struct WarpData sDummyWarpData = { @@ -811,6 +817,7 @@ void LoadMapFromCameraTransition(u8 mapGroup, u8 mapNum) RoamerMove(); DoCurrentWeather(); ResetFieldTasksArgs(); + BlendPalettesWithTime(0xFFFFFFFF); RunOnResumeMapScript(); if (gMapHeader.regionMapSectionId != MAPSEC_BATTLE_FRONTIER @@ -1442,6 +1449,59 @@ void CB1_Overworld(void) DoCB1_Overworld(gMain.newKeys, gMain.heldKeys); } +struct TimeOfDayBlend { + u8 coeff:4; + u16 blendColor; +}; + +static const struct TimeOfDayBlend sTimeOfDayBlendVars[] = +{ + [TIME_OF_DAY_NIGHT] = {.coeff = 10, .blendColor = 0x1400}, + [TIME_OF_DAY_TWILIGHT] = {.coeff = 4, .blendColor = 0x155D}, + [TIME_OF_DAY_DAY] = {.coeff = 0, .blendColor = 0}, +}; + +u8 UpdateTimeOfDay(void) { + RtcCalcLocalTime(); + if (gLocalTime.hours >= 20 || gLocalTime.hours < 4) + return gTimeOfDay = TIME_OF_DAY_NIGHT; + else if (gLocalTime.hours >= 10 && gLocalTime.hours < 20) + return gTimeOfDay = TIME_OF_DAY_DAY; + return gTimeOfDay = TIME_OF_DAY_TWILIGHT; +} + +static bool8 MapHasNaturalLight(u8 mapType) { // Weather a map type is naturally lit/outside + return mapType == MAP_TYPE_TOWN || mapType == MAP_TYPE_CITY || mapType == MAP_TYPE_ROUTE; +} + +static bool8 FadePalettesWithTime(void) { + gTimeOfDayState = 0; + gTimeOfDay = UpdateTimeOfDay(); + if (MapHasNaturalLight(gMapHeader.mapType)) { + ResetPaletteFade(); + BeginTimeOfDayPaletteFade(0xFFFFFFFF, 0, 16, sTimeOfDayBlendVars[gTimeOfDay].coeff, sTimeOfDayBlendVars[gTimeOfDay].blendColor); + } +} + +void BlendPalettesWithTime(u32 palettes) { + // Only blend if not transitioning between times and the map type allows + if (gTimeOfDayState == 0 && MapHasNaturalLight(gMapHeader.mapType)) { + u8 i; + for (i = 0; i < 16; i++) { + if (GetSpritePaletteTagByPaletteNum(i) & 0x8000) // Don't blend special sprite palette tags + palettes &= ~(1 << (i + 16)); + } + palettes &= ~0xE000; // Don't blend tile palettes [13,15] + gTimeOfDay = gTimeOfDay > TIME_OF_DAY_MAX ? TIME_OF_DAY_MAX : gTimeOfDay; + BlendPalettes(palettes, sTimeOfDayBlendVars[gTimeOfDay].coeff, sTimeOfDayBlendVars[gTimeOfDay].blendColor); + } +} + +u8 UpdateSpritePaletteWithTime(u8 paletteNum) { + BlendPalettesWithTime(1 << (paletteNum + 16)); + return paletteNum; +} + static void OverworldBasic(void) { ScriptContext2_RunScript(); @@ -1463,12 +1523,16 @@ void CB2_OverworldBasic(void) void CB2_Overworld(void) { + u32 *debugPtr = (u32*) 0x0203de00; bool32 fading = (gPaletteFade.active != 0); + *debugPtr = (u32) &gTimeOfDay; if (fading) SetVBlankCallback(NULL); OverworldBasic(); - if (fading) - SetFieldVBlankCallback(); + if (fading) { + SetFieldVBlankCallback(); + return; + } } void SetMainCallback1(MainCallback cb) @@ -1564,6 +1628,7 @@ static void CB2_LoadMap2(void) DoMapLoadLoop(&gMain.state); SetFieldVBlankCallback(); SetMainCallback1(CB1_Overworld); + FadePalettesWithTime(); SetMainCallback2(CB2_Overworld); } @@ -1620,6 +1685,7 @@ static void CB2_ReturnToFieldLocal(void) if (ReturnToFieldLocal(&gMain.state)) { SetFieldVBlankCallback(); + FadePalettesWithTime(); SetMainCallback2(CB2_Overworld); } } @@ -1966,7 +2032,6 @@ static bool32 ReturnToFieldLocal(u8 *state) case 3: return TRUE; } - return FALSE; } diff --git a/src/palette.c b/src/palette.c index cbaae8da28..a367a5ed43 100644 --- a/src/palette.c +++ b/src/palette.c @@ -11,6 +11,7 @@ enum NORMAL_FADE, FAST_FADE, HARDWARE_FADE, + TIME_OF_DAY_FADE, }; // These are structs for some unused palette system. @@ -50,6 +51,7 @@ static u8 UpdateNormalPaletteFade(void); static void BeginFastPaletteFadeInternal(u8); static u8 UpdateFastPaletteFade(void); static u8 UpdateHardwarePaletteFade(void); +static u8 UpdateTimeOfDayPaletteFade(void); static void UpdateBlendRegisters(void); static bool8 IsSoftwarePaletteFadeFinishing(void); static void Task_BlendPalettesGradually(u8 taskId); @@ -123,6 +125,8 @@ u8 UpdatePaletteFade(void) result = UpdateNormalPaletteFade(); else if (gPaletteFade.mode == FAST_FADE) result = UpdateFastPaletteFade(); + else if (gPaletteFade.mode == TIME_OF_DAY_FADE) + result = UpdateTimeOfDayPaletteFade(); else result = UpdateHardwarePaletteFade(); @@ -199,6 +203,53 @@ bool8 BeginNormalPaletteFade(u32 selectedPalettes, s8 delay, u8 startY, u8 targe } } +// Like normal palette fade but respects sprite/tile palettes immune to time of day fading +bool8 BeginTimeOfDayPaletteFade(u32 selectedPalettes, s8 delay, u8 startY, u8 targetY, u16 blendColor) +{ + u8 temp; + u16 color = blendColor; + + if (gPaletteFade.active) + { + return FALSE; + } + else + { + gPaletteFade.deltaY = 2; + + if (delay < 0) + { + gPaletteFade.deltaY += (delay * -1); + delay = 0; + } + + gPaletteFade_selectedPalettes = selectedPalettes; + gPaletteFade.delayCounter = delay; + gPaletteFade_delay = delay; + gPaletteFade.y = startY; + gPaletteFade.targetY = targetY; + gPaletteFade.blendColor = color; + gPaletteFade.active = 1; + gPaletteFade.mode = TIME_OF_DAY_FADE; + + if (startY < targetY) + gPaletteFade.yDec = 0; + else + gPaletteFade.yDec = 1; + + UpdatePaletteFade(); + + temp = gPaletteFade.bufferTransferDisabled; + gPaletteFade.bufferTransferDisabled = 0; + CpuCopy32(gPlttBufferFaded, (void *)PLTT, PLTT_SIZE); + sPlttBufferTransferPending = 0; + if (gPaletteFade.mode == HARDWARE_FADE && gPaletteFade.active) + UpdateBlendRegisters(); + gPaletteFade.bufferTransferDisabled = temp; + return TRUE; + } +} + bool8 unref_sub_80A1C1C(u32 a1, u8 a2, u8 a3, u8 a4, u16 a5) { ReadPlttIntoBuffers(); @@ -405,6 +456,94 @@ static u8 GetPaletteNumByUid(u16 uid) return 16; } +// Like normal palette fade, but respects sprite/tile palettes immune to time of day fading +static u8 UpdateTimeOfDayPaletteFade(void) // Like normal, but respects sprite palettes immune to fading +{ + u8 paletteNum; + u16 paletteOffset; + u16 selectedPalettes; + + if (!gPaletteFade.active) + return PALETTE_FADE_STATUS_DONE; + + if (IsSoftwarePaletteFadeFinishing()) + return gPaletteFade.active ? PALETTE_FADE_STATUS_ACTIVE : PALETTE_FADE_STATUS_DONE; + + if (!gPaletteFade.objPaletteToggle) + { + if (gPaletteFade.delayCounter < gPaletteFade_delay) + { + gPaletteFade.delayCounter++; + return 2; + } + gPaletteFade.delayCounter = 0; + } + + paletteOffset = 0; + + if (!gPaletteFade.objPaletteToggle) + { + selectedPalettes = gPaletteFade_selectedPalettes; + } + else + { + selectedPalettes = gPaletteFade_selectedPalettes >> 16; + paletteOffset = 256; + } + + for (paletteNum = 0; paletteNum < 16; paletteNum++, selectedPalettes >>= 1, paletteOffset += 16) { + if (selectedPalettes & 1) { + if (gPaletteFade.yDec) { + if (gPaletteFade.objPaletteToggle) { // sprite palettes + if (gPaletteFade.y >= gPaletteFade.targetY || GetSpritePaletteTagByPaletteNum(paletteNum) & 0x8000) + BlendPalette(paletteOffset, 16, gPaletteFade.y, gPaletteFade.blendColor); + // tile palettes + } else if (gPaletteFade.y >= gPaletteFade.targetY || (paletteNum >= 13 && paletteNum <= 15)) { + BlendPalette(paletteOffset, 16, gPaletteFade.y, gPaletteFade.blendColor); + } + } else { + BlendPalette(paletteOffset, 16, gPaletteFade.y, gPaletteFade.blendColor); + } + } + } + + gPaletteFade.objPaletteToggle ^= 1; + + if (!gPaletteFade.objPaletteToggle) + { + if ((gPaletteFade.yDec && gPaletteFade.y == 0) || (!gPaletteFade.yDec && gPaletteFade.y == gPaletteFade.targetY)) + { + gPaletteFade_selectedPalettes = 0; + gPaletteFade.softwareFadeFinishing = 1; + } + else + { + s8 val; + + if (!gPaletteFade.yDec) + { + val = gPaletteFade.y; + val += gPaletteFade.deltaY; + if (val > gPaletteFade.targetY) + val = gPaletteFade.targetY; + gPaletteFade.y = val; + } + else + { + val = gPaletteFade.y; + val -= gPaletteFade.deltaY; + if (val < 0) + val = 0; + gPaletteFade.y = val; + } + } + } + + // gPaletteFade.active cannot change since the last time it was checked. So this + // is equivalent to `return PALETTE_FADE_STATUS_ACTIVE;` + return PALETTE_FADE_STATUS_ACTIVE; +} + static u8 UpdateNormalPaletteFade(void) { u16 paletteOffset; @@ -586,7 +725,6 @@ static u8 UpdateFastPaletteFade(void) if (IsSoftwarePaletteFadeFinishing()) return gPaletteFade.active ? PALETTE_FADE_STATUS_ACTIVE : PALETTE_FADE_STATUS_DONE; - if (gPaletteFade.objPaletteToggle) { @@ -721,7 +859,6 @@ static u8 UpdateFastPaletteFade(void) gPaletteFade.mode = NORMAL_FADE; gPaletteFade.softwareFadeFinishing = 1; } - // gPaletteFade.active cannot change since the last time it was checked. So this // is equivalent to `return PALETTE_FADE_STATUS_ACTIVE;` return gPaletteFade.active ? PALETTE_FADE_STATUS_ACTIVE : PALETTE_FADE_STATUS_DONE;