This commit is contained in:
cawtds
2024-09-17 18:00:38 +02:00
parent 773fe36d37
commit 2ff6311c44
21 changed files with 851 additions and 65 deletions

View File

@@ -1764,6 +1764,15 @@
.byte 0xd6
.endm
@ Equivalent to fadescreen but copies gPlttBufferUnfaded to gDecompressionBuffer 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
.macro fadescreenswapbuffers mode:req, nowait=0
.byte 0xdc
.byte \mode
.byte \nowait
.endm
.macro _dynmultichoice left:req, top:req, ignoreBPress:req, maxBeforeScroll:req, shouldSort:req, initialSelected:req, callbacks:req argv:vararg
.byte 0xe3
.2byte \left

View File

@@ -1087,12 +1087,12 @@ EventScript_GymBadgeFanfare::
return
EventScript_OutOfCenterPartyHeal::
fadescreen FADE_TO_BLACK
fadescreenswapbuffers FADE_TO_BLACK
playfanfare MUS_HEAL
waitfanfare
special HealPlayerParty
callnative UpdateFollowingPokemon
fadescreen FADE_FROM_BLACK
fadescreenswapbuffers FADE_FROM_BLACK
return
EventScript_WallTownMap::

View File

@@ -51,10 +51,10 @@ MtEmber_Exterior_EventScript_BattleGrunt1::
MtEmber_Exterior_EventScript_DefeatedBothGrunts::
msgbox MtEmber_Exterior_Text_WellRegroupDontStepInsideThere
closemessage
fadescreen FADE_TO_BLACK
fadescreenswapbuffers FADE_TO_BLACK
removeobject LOCALID_GRUNT1
removeobject LOCALID_GRUNT2
fadescreen FADE_FROM_BLACK
fadescreenswapbuffers FADE_FROM_BLACK
release
end

View File

@@ -216,6 +216,12 @@ gScriptCmdTable::
.4byte ScrCmd_bufferitemnameplural @ 0xd4
.4byte ScrCmd_selectapproachingtrainer @ 0xd5
.4byte ScrCmd_lockfortrainer @ 0xd6
.4byte ScrCmd_nop1 @ 0xd7
.4byte ScrCmd_nop1 @ 0xd8
.4byte ScrCmd_nop1 @ 0xd9
.4byte ScrCmd_nop1 @ 0xda
.4byte ScrCmd_nop1 @ 0xdb
.4byte ScrCmd_fadescreenswapbuffers @ 0xdc
gScriptCmdTableEnd::
.4byte ScrCmd_nop

View File

@@ -1,14 +1,14 @@
EventScript_RemoveStaticMon::
fadescreen FADE_TO_BLACK
fadescreenswapbuffers FADE_TO_BLACK
removeobject VAR_LAST_TALKED
fadescreen FADE_FROM_BLACK
fadescreenswapbuffers FADE_FROM_BLACK
release
end
EventScript_MonFlewAway::
fadescreen FADE_TO_BLACK
fadescreenswapbuffers FADE_TO_BLACK
removeobject VAR_LAST_TALKED
fadescreen FADE_FROM_BLACK
fadescreenswapbuffers FADE_FROM_BLACK
bufferspeciesname STR_VAR_1, VAR_0x8004
msgbox Text_MonFlewAway
release

View File

@@ -62,7 +62,7 @@
#define GEN_8_PLA GEN_LATEST + 2
//Time
#define OW_TIMES_OF_DAY GEN_LATEST // Different generations have the times of day change at different times.
#define OW_TIMES_OF_DAY GEN_5 // Different generations have the times of day change at different times.
#define OW_USE_FAKE_RTC FALSE // When TRUE, seconds on the in-game clock will only advance once every 60 playTimeVBlanks (every 60 frames).
#define OW_ALTERED_TIME_RATIO GEN_LATEST // In GEN_8_PLA, the time in game moves forward 60 seconds for every second in the RTC. In GEN_9, it is 20 seconds. This has no effect if OW_USE_FAKE_RTC is FALSE.

View File

@@ -139,7 +139,7 @@ void SetWeatherScreenFadeOut(void);
void WeatherProcessingIdle(void);
u8 GetCurrentWeather(void);
void delay(u8, u8, u32);
void UpdateSpritePaletteWithWeather(u8 palIdx);
void UpdateSpritePaletteWithWeather(u8 palIdx, bool32 allowFog);
void ResetPreservedPalettesInWeather(void);
void PreservePaletteInWeather(u8 palIdx);
bool32 IsWeatherAlphaBlend(void);

View File

@@ -79,7 +79,8 @@ typedef void (*TilesetCB)(void);
struct Tileset
{
/*0x00*/ bool8 isCompressed;
/*0x00*/ bool8 isCompressed:1;
/*0x00*/ u8 swapPalettes:7; // bitmask determining whether palette has an alternate, night-time palette
/*0x01*/ bool8 isSecondary;
/*0x04*/ const u32 *tiles;
/*0x08*/ const u16 (*palettes)[16];

View File

@@ -27,6 +27,11 @@
#define MOVEMENT_MODE_FROZEN 1
#define MOVEMENT_MODE_SCRIPTED 2
#define TIME_OF_DAY_NIGHT 0
#define TIME_OF_DAY_TWILIGHT 1
#define TIME_OF_DAY_DAY 2
#define TIME_OF_DAY_MAX TIME_OF_DAY_DAY
struct LinkPlayerObjectEvent
{
u8 active;
@@ -49,6 +54,14 @@ enum {
MUSIC_DISABLE_KEEP,
};
struct __attribute__((packed)) TimeBlendSettings {
u16 weight:9;
u16 time1:3;
u16 time0:3;
u16 unused:1;
u16 altWeight;
};
extern struct WarpData gLastUsedWarp;
extern struct LinkPlayerObjectEvent gLinkPlayerObjectEvents[4];
@@ -65,6 +78,10 @@ extern u8 gExitStairsMovementDisabled;
extern u8 gDisableMapMusicChangeOnMapLoad;
extern u8 gGlobalFieldTintMode;
extern u8 gTimeOfDay;
extern u16 gTimeUpdateCounter;
extern struct TimeBlendSettings currentTimeBlend;
extern const struct Coords32 gDirectionToVectors[];
@@ -178,10 +195,15 @@ u16 SetLinkWaitingForScript(void);
void SetMainCallback1(MainCallback cb);
void CB1_Overworld(void);
void CB2_ReturnToFieldContinueScript(void);
u8 UpdateTimeOfDay(void);
bool8 MapHasNaturalLight(u8 mapType);
void UpdateAltBgPalettes(u16 palettes);
void UpdatePalettesWithTime(u32);
u8 GetLastUsedWarpMapSectionId(void);
void StoreInitialPlayerAvatarState(void);
void UpdateEscapeWarp(s16 x, s16 y);
bool8 SetDiveWarpEmerge(u16 x, u16 y);
bool8 SetDiveWarpDive(u16 x, u16 y);
u8 UpdateSpritePaletteWithTime(u8 paletteNum);
#endif //GUARD_OVERWORLD_H

View File

@@ -16,6 +16,8 @@
#define PALETTE_FADE_STATUS_LOADING 0xFF
#define PALETTES_BG 0x0000FFFF
// like PALETTES_BG but excludes UI pals [13, 15]
#define PALETTES_MAP 0x00001FFF
#define PALETTES_OBJECTS 0xFFFF0000
#define PALETTES_ALL (PALETTES_BG | PALETTES_OBJECTS)
@@ -26,6 +28,11 @@
#define OBJ_PLTT_ID(n) (OBJ_PLTT_OFFSET + PLTT_ID(n))
#define OBJ_PLTT_ID2(n) (PLTT_ID((n) + 16))
// Used to determine whether a sprite palette tag
// should be excluded from time (and weather) blending
#define BLEND_IMMUNE_FLAG (1 << 15)
#define IS_BLEND_IMMUNE_TAG(tag) ((tag) & BLEND_IMMUNE_FLAG)
enum
{
FAST_FADE_IN_FROM_WHITE,
@@ -34,9 +41,19 @@ enum
FAST_FADE_OUT_TO_BLACK,
};
struct BlendSettings {
u32 blendColor:24;
u32 isTint:1;
u32 coeff:5;
};
struct PaletteFadeControl
{
u32 multipurpose1;
// These three are only used for TOD blending
struct BlendSettings *bld0;
struct BlendSettings *bld1;
u16 weight:9; // [0, 256], so must be 9 bits
u8 delayCounter:6;
u16 y:5; // blend coefficient
u16 targetY:5; // target blend coefficient
@@ -55,6 +72,8 @@ struct PaletteFadeControl
u32 unused;
};
extern const struct BlendSettings gTimeOfDayBlend[];
extern struct PaletteFadeControl gPaletteFade;
extern u32 gPlttBufferTransferPending;
extern u16 gPlttBufferUnfaded[PLTT_BUFFER_SIZE];
@@ -67,11 +86,13 @@ void TransferPlttBuffer(void);
u32 UpdatePaletteFade(void);
void ResetPaletteFade(void);
bool32 BeginNormalPaletteFade(u32 selectedPalettes, s8 delay, u8 startY, u8 targetY, u32 blendColor);
bool32 BeginTimeOfDayPaletteFade(u32, s8, u8, u8, struct BlendSettings *, struct BlendSettings *, u32, u32);
void ResetPaletteFadeControl(void);
void InvertPlttBuffer(u32 selectedPalettes);
void BeginFastPaletteFade(u32 submode);
void BeginHardwarePaletteFade(u32 blendCnt, u32 delay, u32 y, u32 targetY, u32 shouldResetBlendRegisters);
void BlendPalettes(u32 selectedPalettes, u8 coeff, u32 color);
void BlendPalettesFine(u32 palettes, u16 *src, u16 *dst, u32 coeff, u32 color);
void BlendPalettesUnfaded(u32 selectedPalettes, u8 coeff, u32 color);
void TintPalette_GrayScale(u16 *palette, u32 count);
void TintPalette_GrayScale2(u16 *palette, u32 count);
@@ -81,6 +102,9 @@ void CopyPaletteInvertedTint(const u16 *src, u16 *dst, u32 count, u8 tone);
void BlendPalettesGradually(u32 selectedPalettes, s8 delay, u8 coeff, u8 coeffTarget, u16 color, u8 priority, u8 id);
bool32 IsBlendPalettesGraduallyTaskActive(u8 var);
void DestroyBlendPalettesGraduallyTask(void);
void TimeBlendPalette(u16 palOffset, u32 coeff, u32 blendColor);
void TimeMixPalettes(u32, u16 *, u16 *, struct BlendSettings *, struct BlendSettings *, u16);
void AvgPaletteWeighted(u16 *src0, u16 *src1, u16 *dst, u16 weight0);
static inline void SetBackdropFromColor(u32 color)
{

View File

@@ -398,12 +398,18 @@ static u8 GetBattleTerrainByMapScene(u8 mapBattleScene)
static void LoadBattleTerrainGfx(u16 terrain)
{
u32 palettes = 0;
if (terrain >= NELEMS(gBattleTerrainInfo))
terrain = BATTLE_TERRAIN_PLAIN;
// Copy to bg3
LZDecompressVram(gBattleTerrainInfo[terrain].background.tileset, (void *)BG_CHAR_ADDR(2));
LZDecompressVram(gBattleTerrainInfo[terrain].background.tilemap, (void *)BG_SCREEN_ADDR(26));
LoadCompressedPalette(gBattleTerrainInfo[terrain].background.palette, BG_PLTT_ID(2), 3 * PLTT_SIZE_4BPP);
palettes ^= (1 << 2);
palettes ^= (1 << 3);
palettes ^= (1 << 4);
UpdatePalettesWithTime(palettes);
}
static void LoadBattleTerrainEntryGfx(u16 terrain)

View File

@@ -2093,7 +2093,7 @@ static u8 LoadDynamicFollowerPalette(u16 species, u8 form, bool32 shiny)
}
if (gWeatherPtr->currWeather != WEATHER_FOG_HORIZONTAL) // don't want to weather blend in fog
UpdateSpritePaletteWithWeather(paletteNum);
UpdateSpritePaletteWithWeather(paletteNum, FALSE);
return paletteNum;
}
@@ -2116,7 +2116,7 @@ static void FollowerSetGraphics(struct ObjectEvent *objEvent, u16 species, u8 fo
}
else if (gWeatherPtr->currWeather != WEATHER_FOG_HORIZONTAL) // don't want to weather blend in fog
{
UpdateSpritePaletteWithWeather(gSprites[objEvent->spriteId].oam.paletteNum);
UpdateSpritePaletteWithWeather(gSprites[objEvent->spriteId].oam.paletteNum, FALSE);
}
}
@@ -2162,7 +2162,7 @@ static void RefreshFollowerGraphics(struct ObjectEvent *objEvent)
{
UpdateSpritePalette(&sObjectEventSpritePalettes[i], sprite);
if (gWeatherPtr->currWeather != WEATHER_FOG_HORIZONTAL) // don't want to weather blend in fog
UpdateSpritePaletteWithWeather(sprite->oam.paletteNum);
UpdateSpritePaletteWithWeather(sprite->oam.paletteNum, FALSE);
}
}
@@ -2795,7 +2795,17 @@ static u8 UpdateSpritePalette(const struct SpritePalette *spritePalette, struct
sprite->inUse = FALSE;
FieldEffectFreePaletteIfUnused(sprite->oam.paletteNum);
sprite->inUse = TRUE;
if (IndexOfSpritePaletteTag(spritePalette->tag) == 0xFF)
{
sprite->oam.paletteNum = LoadSpritePalette(spritePalette);
UpdateSpritePaletteWithWeather(sprite->oam.paletteNum, FALSE);
}
else
{
sprite->oam.paletteNum = LoadSpritePalette(spritePalette);
}
sprite->oam.paletteNum = LoadSpritePalette(spritePalette);
return sprite->oam.paletteNum;
}
@@ -3011,6 +3021,8 @@ static u8 LoadSpritePaletteIfTagExists(const struct SpritePalette *spritePalette
if (paletteNum != 0xFF) // don't load twice; return
return paletteNum;
paletteNum = LoadSpritePalette(spritePalette);
if (paletteNum != 0xFF)
UpdateSpritePaletteWithWeather(paletteNum, FALSE);
ApplyGlobalFieldPaletteTint(paletteNum);
return paletteNum;
}

View File

@@ -460,7 +460,7 @@ static void FieldEffectScript_LoadFadedPal(const u8 **script)
LoadSpritePalette(spritePalette);
if (idx == 0xFF)
ApplyGlobalFieldPaletteTint(IndexOfSpritePaletteTag(spritePalette->tag));
UpdateSpritePaletteWithWeather(IndexOfSpritePaletteTag(spritePalette->tag));
UpdateSpritePaletteWithWeather(IndexOfSpritePaletteTag(spritePalette->tag), TRUE);
*script += sizeof(u32);
}

View File

@@ -157,7 +157,7 @@ static void LoadObjectRegularReflectionPalette(struct ObjectEvent *objectEvent,
ApplyIceFilter(mainSprite->oam.paletteNum, filteredData);
paletteNum = LoadSpritePalette(&filteredPal);
ApplyGlobalFieldPaletteTint(paletteNum);
UpdateSpritePaletteWithWeather(paletteNum);
UpdateSpritePaletteWithWeather(paletteNum, TRUE);
}
sprite->oam.paletteNum = paletteNum;
sprite->oam.objMode = ST_OAM_OBJ_BLEND;
@@ -172,7 +172,7 @@ static void LoadObjectHighBridgeReflectionPalette(struct ObjectEvent *objectEven
CpuFill16(0x55C9, blueData, PLTT_SIZE_4BPP);
sprite->oam.paletteNum = LoadSpritePalette(&bluePalette);
ApplyGlobalFieldPaletteTint(sprite->oam.paletteNum);
UpdateSpritePaletteWithWeather(sprite->oam.paletteNum);
UpdateSpritePaletteWithWeather(sprite->oam.paletteNum, TRUE);
}
static void UpdateObjectReflectionSprite(struct Sprite *reflectionSprite)
@@ -209,7 +209,7 @@ static void UpdateObjectReflectionSprite(struct Sprite *reflectionSprite)
ApplyIceFilter(mainSprite->oam.paletteNum, filteredData);
paletteNum = LoadSpritePalette(&filteredPal);
ApplyGlobalFieldPaletteTint(paletteNum);
UpdateSpritePaletteWithWeather(paletteNum);
UpdateSpritePaletteWithWeather(paletteNum, TRUE);
}
reflectionSprite->oam.paletteNum = paletteNum;
}

View File

@@ -20,6 +20,7 @@
#include "battle_tower.h"
#include "field_camera.h"
#include "field_effect.h"
#include "field_weather.h"
#include "event_object_movement.h"
#include "item.h"
#include "menu_indicators.h"
@@ -2476,6 +2477,7 @@ static void MoveDeoxysObject(u8 num)
{
u8 mapObjId;
LoadPalette(sDeoxysObjectPals[num], OBJ_PLTT_ID(10), PLTT_SIZEOF(4));
UpdateSpritePaletteWithWeather(10, FALSE);
ApplyGlobalFieldPaletteTint(10);
TryGetObjectEventIdByLocalIdAndMap(1, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &mapObjId);
if (num == 0)

View File

@@ -5,12 +5,16 @@
#include "field_weather.h"
#include "field_weather_util.h"
#include "field_weather_effects.h"
#include "overworld.h"
#include "task.h"
#include "trig.h"
#include "constants/field_weather.h"
#include "constants/weather.h"
#include "constants/songs.h"
#include "quest_log.h"
#include "constants/quest_log.h"
#define DROUGHT_COLOR_INDEX(color) ((((color) >> 1) & 0xF) | (((color) >> 2) & 0xF0) | (((color) >> 3) & 0xF00))
enum
@@ -449,15 +453,30 @@ static void ApplyGammaShift(u8 startPalIndex, u8 numPalettes, s8 gammaIndex)
if (gammaIndex > 0)
{
// Create the palette mask
u32 palettes = PALETTES_ALL;
numPalettes += startPalIndex;
palettes = (palettes >> startPalIndex) << startPalIndex;
palettes = (palettes << (32-numPalettes)) >> (32-numPalettes);
numPalettes -= startPalIndex;
gammaIndex--;
palOffset = PLTT_ID(startPalIndex);
UpdateAltBgPalettes(palettes & PALETTES_BG);
// Thunder gamma-shift looks bad on night-blended palettes, so ignore time blending in some situations
if (!(gammaIndex > 3) && MapHasNaturalLight(gMapHeader.mapType))
UpdatePalettesWithTime(palettes);
else
CpuFastCopy(gPlttBufferUnfaded + palOffset, gPlttBufferFaded + palOffset, PLTT_SIZE_4BPP * numPalettes);
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)
if (sPaletteGammaTypes[curPalIndex] == GAMMA_NONE ||
(curPalIndex >= 16 && IS_BLEND_IMMUNE_TAG(GetSpritePaletteTagByPaletteNum(curPalIndex - 16))))
{
// No palette change.
CpuFastCopy(&gPlttBufferUnfaded[palOffset], &gPlttBufferFaded[palOffset], PLTT_SIZE_4BPP);
@@ -493,8 +512,18 @@ static void ApplyGammaShift(u8 startPalIndex, u8 numPalettes, s8 gammaIndex)
}
else
{
// No palette blending.
CpuFastCopy(&gPlttBufferUnfaded[PLTT_ID(startPalIndex)], &gPlttBufferFaded[PLTT_ID(startPalIndex)], numPalettes * PLTT_SIZE_4BPP);
if (MapHasNaturalLight(gMapHeader.mapType))
{
// Time-blend
u32 palettes = ((1 << numPalettes) - 1) << startPalIndex;
UpdateAltBgPalettes(palettes & PALETTES_BG);
UpdatePalettesWithTime(palettes);
}
else
{
// No palette blending.
CpuFastCopy(&gPlttBufferUnfaded[PLTT_ID(startPalIndex)], &gPlttBufferFaded[PLTT_ID(startPalIndex)], numPalettes * PLTT_SIZE_4BPP);
}
}
}
@@ -515,6 +544,9 @@ static void ApplyGammaShiftWithBlend(u8 startPalIndex, u8 numPalettes, s8 gammaI
while (curPalIndex < numPalettes)
{
UpdateAltBgPalettes((1 << (palOffset >> 4)) & PALETTES_BG);
CpuFastCopy(gPlttBufferUnfaded + palOffset, gPlttBufferFaded + palOffset, 16 * sizeof(u16));
UpdatePalettesWithTime(1 << (palOffset >> 4)); // Apply TOD blend
if (sPaletteGammaTypes[curPalIndex] == GAMMA_NONE)
{
// No gamma shift. Simply blend the colors.
@@ -597,49 +629,24 @@ static void ApplyDroughtGammaShiftWithBlend(s8 gammaIndex, u8 blendCoeff, u32 bl
static void ApplyFogBlend(u8 blendCoeff, u32 blendColor)
{
struct RGBColor color;
u8 rBlend;
u8 gBlend;
u8 bBlend;
u16 curPalIndex;
u32 curPalIndex;
u16 fogCoeff = min((gTimeOfDay + 1) * 4, 12);
BlendPalette(0, 256, blendCoeff, blendColor);
color = *(struct RGBColor *)&blendColor;
rBlend = color.r;
gBlend = color.g;
bBlend = color.b;
// First blend all palettes with time
UpdateAltBgPalettes(PALETTES_BG);
CpuFastCopy(gPlttBufferUnfaded, gPlttBufferFaded, PLTT_BUFFER_SIZE * 2);
UpdatePalettesWithTime(PALETTES_ALL);
// Then blend tile palettes [0, 12] faded->faded with fadeIn color
BlendPalettesFine(PALETTES_MAP, gPlttBufferFaded, gPlttBufferFaded, blendCoeff, blendColor);
// Do fog blending on marked sprite palettes
for (curPalIndex = 16; curPalIndex < 32; curPalIndex++)
{
if (LightenSpritePaletteInFog(curPalIndex))
{
u16 palEnd = PLTT_ID(curPalIndex + 1);
u16 palOffset = PLTT_ID(curPalIndex);
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(PLTT_ID(curPalIndex), 16, blendCoeff, blendColor);
}
BlendPalettesFine(1, gPlttBufferFaded + PLTT_ID(curPalIndex), gPlttBufferFaded + PLTT_ID(curPalIndex), fogCoeff, RGB(28, 31, 28));
}
// Finally blend all sprite palettes faded->faded with fadeIn color
BlendPalettesFine(PALETTES_OBJECTS, gPlttBufferFaded, gPlttBufferFaded, blendCoeff, blendColor);
}
static void MarkFogSpritePalToLighten(u8 paletteIndex)
@@ -732,8 +739,10 @@ void FadeScreen(u8 mode, s8 delay)
if (fadeOut)
{
if (useWeatherPal)
CpuFastCopy(gPlttBufferFaded, gPlttBufferUnfaded, PLTT_SIZE);
// Note: Copying faded -> unfaded like this works fine, except if the screen is faded back in
// without transitioning to a different screen
// For cases like that, use fadescreenswapbuffers
CpuFastCopy(gPlttBufferFaded, gPlttBufferUnfaded, PLTT_SIZE);
BeginNormalPaletteFade(PALETTES_ALL, delay, 0, 16, fadeColor);
gWeatherPtr->palProcessingState = WEATHER_PAL_STATE_SCREEN_FADING_OUT;
@@ -741,8 +750,17 @@ void FadeScreen(u8 mode, s8 delay)
else
{
gWeatherPtr->fadeDestColor = fadeColor;
UpdateTimeOfDay();
if (useWeatherPal)
gWeatherPtr->fadeScreenCounter = 0;
else if (!QL_IS_PLAYBACK_STATE && MapHasNaturalLight(gMapHeader.mapType))
{
UpdateAltBgPalettes(PALETTES_BG);
BeginTimeOfDayPaletteFade(PALETTES_ALL, delay, 16, 0,
(struct BlendSettings *)&gTimeOfDayBlend[currentTimeBlend.time0],
(struct BlendSettings *)&gTimeOfDayBlend[currentTimeBlend.time1],
currentTimeBlend.weight, fadeColor);
}
else
BeginNormalPaletteFade(PALETTES_ALL, delay, 16, 0, fadeColor);
@@ -828,7 +846,7 @@ bool8 IsWeatherNotFadingIn(void)
return (gWeatherPtr->palProcessingState != WEATHER_PAL_STATE_SCREEN_FADING_IN);
}
void UpdateSpritePaletteWithWeather(u8 spritePaletteIndex)
void UpdateSpritePaletteWithWeather(u8 spritePaletteIndex, bool32 allowFog)
{
u16 paletteIndex = 16 + spritePaletteIndex;
u16 i;
@@ -855,12 +873,29 @@ void UpdateSpritePaletteWithWeather(u8 spritePaletteIndex)
default:
if (gWeatherPtr->currWeather != WEATHER_FOG_HORIZONTAL)
{
ApplyGammaShift(paletteIndex, 1, gWeatherPtr->gammaIndex);
if (gWeatherPtr->gammaIndex)
ApplyGammaShift(paletteIndex, 1, gWeatherPtr->gammaIndex);
else
UpdateSpritePaletteWithTime(spritePaletteIndex);
}
else
{
paletteIndex = PLTT_ID(paletteIndex);
BlendPalette(paletteIndex, 16, 12, RGB(28, 31, 28));
// In horizontal fog, only specific palettes should be fog-blended
if (allowFog)
{
i = min((gTimeOfDay + 1) * 4, 12); // fog coeff, highest in day and lowest at night
paletteIndex = PLTT_ID(paletteIndex);
// First blend with time
CpuFastCopy(gPlttBufferUnfaded + paletteIndex, gPlttBufferFaded + paletteIndex, PLTT_SIZE_4BPP);
UpdateSpritePaletteWithTime(spritePaletteIndex);
// Then blend faded->faded with fog coeff
BlendPalettesFine(1, gPlttBufferFaded + paletteIndex, gPlttBufferFaded + paletteIndex, i, RGB(28, 31, 28));
}
else
{
// Otherwise, just time-blend the palette
UpdateSpritePaletteWithTime(spritePaletteIndex);
}
}
break;
}
@@ -874,7 +909,7 @@ void ApplyWeatherGammaShiftToPal(u8 paletteIndex)
void LoadCustomWeatherSpritePalette(const u16 *palette)
{
LoadPalette(palette, OBJ_PLTT_ID(gWeatherPtr->weatherPicSpritePalIndex), PLTT_SIZE_4BPP);
UpdateSpritePaletteWithWeather(gWeatherPtr->weatherPicSpritePalIndex);
UpdateSpritePaletteWithWeather(gWeatherPtr->weatherPicSpritePalIndex, TRUE);
}
static void LoadDroughtWeatherPalette(u8 *gammaIndexPtr, u8 *a1)

View File

@@ -7,6 +7,7 @@
#include "event_data.h"
#include "event_object_movement.h"
#include "event_scripts.h"
#include "fake_rtc.h"
#include "field_camera.h"
#include "field_control_avatar.h"
#include "field_effect.h"
@@ -38,6 +39,7 @@
#include "random.h"
#include "renewable_hidden_items.h"
#include "roamer.h"
#include "rtc.h"
#include "safari_zone.h"
#include "save_location.h"
#include "scanline_effect.h"
@@ -121,6 +123,10 @@ static KeyInterCB sPlayerKeyInterceptCallback;
static bool8 sReceivingFromLink;
static u8 sRfuKeepAliveTimer;
u8 gTimeOfDay;
struct TimeBlendSettings currentTimeBlend;
u16 gTimeUpdateCounter; // playTimeVBlanks will eventually overflow, so this is used to update TOD
static u8 CountBadgesForOverworldWhiteOutLossCalculation(void);
static void Overworld_ResetStateAfterWhitingOut(void);
static void Overworld_SetWhiteoutRespawnPoint(void);
@@ -1460,6 +1466,168 @@ void CB1_Overworld(void)
}
}
#define TINT_NIGHT Q_8_8(0.456) | Q_8_8(0.456) << 8 | Q_8_8(0.615) << 16
const struct BlendSettings gTimeOfDayBlend[] =
{
[TIME_OF_DAY_NIGHT] = {.coeff = 10, .blendColor = TINT_NIGHT, .isTint = TRUE},
[TIME_OF_DAY_TWILIGHT] = {.coeff = 4, .blendColor = 0xA8B0E0, .isTint = TRUE},
[TIME_OF_DAY_DAY] = {.coeff = 0, .blendColor = 0},
};
#define MORNING_START_MINUTES (MORNING_HOUR_BEGIN * MINUTES_PER_HOUR)
#define MORNING_MID_POINT (MORNING_HOUR_BEGIN * MINUTES_PER_HOUR + (MORNING_HOUR_END * MINUTES_PER_HOUR - MORNING_HOUR_BEGIN * MINUTES_PER_HOUR) / 2)
#define MORNING_END_MINUTES (MORNING_HOUR_END * MINUTES_PER_HOUR)
#define EVENING_START_MINUTES (EVENING_HOUR_BEGIN * MINUTES_PER_HOUR)
#define EVENING_MID_POINT (EVENING_HOUR_BEGIN * MINUTES_PER_HOUR + (EVENING_HOUR_END * MINUTES_PER_HOUR - EVENING_HOUR_BEGIN * MINUTES_PER_HOUR) / 2)
#define EVENING_END_MINUTES (EVENING_HOUR_END * MINUTES_PER_HOUR)
u8 UpdateTimeOfDay(void)
{
s32 hours, minutes;
s32 minutesOfDay;
RtcCalcLocalTime();
hours = gLocalTime.hours;
minutes = gLocalTime.minutes;
minutesOfDay = hours * MINUTES_PER_HOUR + minutes;
if (minutesOfDay < MORNING_START_MINUTES) // night
{
currentTimeBlend.weight = 256;
currentTimeBlend.altWeight = 0;
gTimeOfDay = currentTimeBlend.time0 = currentTimeBlend.time1 = TIME_OF_DAY_NIGHT;
}
else if (minutesOfDay < MORNING_MID_POINT) // night->twilight
{
currentTimeBlend.time0 = TIME_OF_DAY_NIGHT;
currentTimeBlend.time1 = TIME_OF_DAY_TWILIGHT;
currentTimeBlend.weight = 256 - 256 * (hours * 60 - MORNING_START_MINUTES + minutes) / (MORNING_MID_POINT - MORNING_START_MINUTES);
currentTimeBlend.altWeight = (256 - currentTimeBlend.weight) / 2;
gTimeOfDay = TIME_OF_DAY_DAY;
}
else if (minutesOfDay < MORNING_END_MINUTES) // twilight->day
{
currentTimeBlend.time0 = TIME_OF_DAY_TWILIGHT;
currentTimeBlend.time1 = TIME_OF_DAY_DAY;
currentTimeBlend.weight = 256 - 256 * (hours * 60 - MORNING_MID_POINT + minutes) / (MORNING_END_MINUTES - MORNING_MID_POINT);
currentTimeBlend.altWeight = (256 - currentTimeBlend.weight) / 2 + 128;
gTimeOfDay = TIME_OF_DAY_DAY;
}
else if (minutesOfDay < EVENING_START_MINUTES) // day
{
currentTimeBlend.weight = currentTimeBlend.altWeight = 256;
gTimeOfDay = currentTimeBlend.time0 = currentTimeBlend.time1 = TIME_OF_DAY_DAY;
}
else if (minutesOfDay < EVENING_MID_POINT)
{
currentTimeBlend.time0 = TIME_OF_DAY_DAY;
currentTimeBlend.time1 = TIME_OF_DAY_TWILIGHT;
currentTimeBlend.weight = 256 - 256 * (hours * 60 - EVENING_START_MINUTES + minutes) / (EVENING_MID_POINT - EVENING_START_MINUTES);
currentTimeBlend.altWeight = currentTimeBlend.weight / 2 + 128;
gTimeOfDay = TIME_OF_DAY_TWILIGHT;
}
else if (minutesOfDay < EVENING_END_MINUTES) // twilight->night
{
currentTimeBlend.time0 = TIME_OF_DAY_TWILIGHT;
currentTimeBlend.time1 = TIME_OF_DAY_NIGHT;
currentTimeBlend.weight = 256 - 256 * (hours * 60 - EVENING_MID_POINT + minutes) / (EVENING_END_MINUTES - EVENING_MID_POINT);
currentTimeBlend.altWeight = currentTimeBlend.weight / 2;
gTimeOfDay = TIME_OF_DAY_NIGHT;
}
else // 22-24, night
{
currentTimeBlend.weight = 256;
currentTimeBlend.altWeight = 0;
gTimeOfDay = currentTimeBlend.time0 = currentTimeBlend.time1 = TIME_OF_DAY_NIGHT;
}
return gTimeOfDay;
}
// Whether a map type is naturally lit/outside
bool8 MapHasNaturalLight(u8 mapType)
{
return (mapType == MAP_TYPE_TOWN
|| mapType == MAP_TYPE_CITY
|| mapType == MAP_TYPE_ROUTE
|| mapType == MAP_TYPE_OCEAN_ROUTE
);
}
// Update & mix day / night bg palettes (into unfaded)
void UpdateAltBgPalettes(u16 palettes)
{
const struct Tileset *primary = gMapHeader.mapLayout->primaryTileset;
const struct Tileset *secondary = gMapHeader.mapLayout->secondaryTileset;
u32 i = 1;
if (QL_IS_PLAYBACK_STATE)
return;
if (!MapHasNaturalLight(gMapHeader.mapType))
return;
palettes &= ~((1 << NUM_PALS_IN_PRIMARY) - 1) | primary->swapPalettes;
palettes &= ((1 << NUM_PALS_IN_PRIMARY) - 1) | (secondary->swapPalettes << NUM_PALS_IN_PRIMARY);
palettes &= PALETTES_MAP ^ (1 << 0); // don't blend palette 0, [13,15]
palettes >>= 1; // start at palette 1
if (!palettes)
return;
while (palettes)
{
if (palettes & 1)
{
if (i < NUM_PALS_IN_PRIMARY)
AvgPaletteWeighted(&((u16*)primary->palettes)[i*16], &((u16*)primary->palettes)[((i+9)%16)*16], gPlttBufferUnfaded + i * 16, currentTimeBlend.altWeight);
else
AvgPaletteWeighted(&((u16*)secondary->palettes)[i*16], &((u16*)secondary->palettes)[((i+9)%16)*16], gPlttBufferUnfaded + i * 16, currentTimeBlend.altWeight);
}
i++;
palettes >>= 1;
}
}
void UpdatePalettesWithTime(u32 palettes)
{
if (QL_IS_PLAYBACK_STATE)
return;
if (MapHasNaturalLight(gMapHeader.mapType))
{
u32 i;
u32 mask = 1 << 16;
if (palettes >= (1 << 16))
for (i = 0; i < 16; i++, mask <<= 1)
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
);
}
}
u8 UpdateSpritePaletteWithTime(u8 paletteNum)
{
if (QL_IS_PLAYBACK_STATE)
return paletteNum;
if (MapHasNaturalLight(gMapHeader.mapType))
{
if (GetSpritePaletteTagByPaletteNum(paletteNum) != 0xFFFF && 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;
}
static void OverworldBasic(void)
{
ScriptContext_RunScript();
@@ -1472,6 +1640,24 @@ static void OverworldBasic(void)
UpdatePaletteFade();
UpdateTilesetAnimations();
DoScheduledBgTilemapCopiesToVram();
// Every minute if no palette fade is active, update TOD blending as needed
if (!gPaletteFade.active && ++gTimeUpdateCounter >= (SECONDS_PER_MINUTE * 1 / FakeRtc_GetSecondsRatio()))
{
struct TimeBlendSettings cachedBlend = {
.time0 = currentTimeBlend.time0,
.time1 = currentTimeBlend.time1,
.weight = currentTimeBlend.weight,
};
gTimeUpdateCounter = 0;
UpdateTimeOfDay();
if (cachedBlend.time0 != currentTimeBlend.time0
|| cachedBlend.time1 != currentTimeBlend.time1
|| cachedBlend.weight != currentTimeBlend.weight)
{
UpdateAltBgPalettes(PALETTES_BG);
UpdatePalettesWithTime(PALETTES_ALL);
}
}
}
// This CB2 is used when starting

View File

@@ -9,11 +9,13 @@ enum
NORMAL_FADE,
FAST_FADE,
HARDWARE_FADE,
TIME_OF_DAY_FADE,
};
static u32 UpdateNormalPaletteFade(void);
static void BeginFastPaletteFadeInternal(u32);
static u32 UpdateFastPaletteFade(void);
static u8 UpdateTimeOfDayPaletteFade(void);
static u32 UpdateHardwarePaletteFade(void);
static void UpdateBlendRegisters(void);
static bool32 IsSoftwarePaletteFadeFinishing(void);
@@ -77,6 +79,8 @@ u32 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();
sPlttBufferTransferPending = gPaletteFade.multipurpose1;
@@ -128,6 +132,56 @@ bool32 BeginNormalPaletteFade(u32 selectedPalettes, s8 delay, u8 startY, u8 targ
}
}
// Like normal palette fade but respects sprite/tile palettes immune to time of day fading
bool32 BeginTimeOfDayPaletteFade(u32 selectedPalettes, s8 delay, u8 startY, u8 targetY, struct BlendSettings *bld0, struct BlendSettings *bld1, u32 weight, u32 color)
{
u8 temp;
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.active = 1;
gPaletteFade.mode = TIME_OF_DAY_FADE;
gPaletteFade.blendColor = color;
gPaletteFade.bld0 = bld0;
gPaletteFade.bld1 = bld1;
gPaletteFade.weight = weight;
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;
}
}
void ResetPaletteFadeControl(void)
{
gPaletteFade.multipurpose1 = 0;
@@ -148,6 +202,119 @@ void ResetPaletteFadeControl(void)
gPaletteFade.deltaY = 2;
}
// Like normal palette fade, but respects sprite/tile palettes immune to time of day fading
static u8 UpdateTimeOfDayPaletteFade(void)
{
u16 paletteOffset;
u16 selectedPalettes;
u16 timePalettes = 0; // palettes passed to the time-blender
u16 copyPalettes;
u16 * src;
u16 * dst;
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;
}
src = gPlttBufferUnfaded + paletteOffset;
dst = gPlttBufferFaded + paletteOffset;
// First pply TOD blend to relevant subset of palettes
if (gPaletteFade.objPaletteToggle) // Sprite palettes, don't blend those with tags
{
u32 i;
u32 j = 1;
for (i = 0; i < 16; i++, j <<= 1) // Mask out palettes that should not be light blended
{
if ((selectedPalettes & j) && !IS_BLEND_IMMUNE_TAG(GetSpritePaletteTagByPaletteNum(i)))
timePalettes |= j;
}
}
else // tile palettes, don't blend [13, 15]
{
timePalettes = selectedPalettes & PALETTES_MAP;
}
TimeMixPalettes(timePalettes, src, dst, gPaletteFade.bld0, gPaletteFade.bld1, gPaletteFade.weight);
// palettes that were not blended above must be copied through
if ((copyPalettes = ~timePalettes))
{
u16 * src1 = src;
u16 * dst1 = dst;
while (copyPalettes)
{
if (copyPalettes & 1)
CpuFastCopy(src1, dst1, 32);
copyPalettes >>= 1;
src1 += 16;
dst1 += 16;
}
}
// Then, blend from faded->faded with native BlendPalettes
BlendPalettesFine(selectedPalettes, dst, dst, 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 u32 UpdateNormalPaletteFade(void)
{
u16 paletteOffset;
@@ -492,6 +659,46 @@ static bool32 IsSoftwarePaletteFadeFinishing(void)
}
}
// optimized based on lucktyphlosion's BlendPalettesFine
void BlendPalettesFine(u32 palettes, u16 *src, u16 *dst, u32 coeff, u32 color)
{
s32 newR, newG, newB;
if (!palettes)
return;
coeff *= 2;
newR = (color << 27) >> 27;
newG = (color << 22) >> 27;
newB = (color << 17) >> 27;
do
{
if (palettes & 1)
{
u16 *srcEnd = src + 16;
while (src != srcEnd) // Transparency is blended (for backdrop reasons)
{
u32 srcColor = *src;
s32 r = (srcColor << 27) >> 27;
s32 g = (srcColor << 22) >> 27;
s32 b = (srcColor << 16) >> 26;
*dst++ = ((r + (((newR - r) * (s32)coeff) >> 5)) << 0)
| ((g + (((newG - g) * (s32)coeff) >> 5)) << 5)
| ((b + (((newB - (b & 31)) * (s32)coeff) >> 5)) << 10);
src++;
}
}
else
{
src += 16;
dst += 16;
}
palettes >>= 1;
} while (palettes);
}
void BlendPalettes(u32 selectedPalettes, u8 coeff, u32 color)
{
u16 paletteOffset;
@@ -504,6 +711,243 @@ void BlendPalettes(u32 selectedPalettes, u8 coeff, u32 color)
}
}
#define DEFAULT_LIGHT_COLOR 0x3f9f
// Like BlendPalette, but ignores blendColor if the transparency high bit is set
// Optimization help by lucktyphlosion
void TimeBlendPalette(u16 palOffset, u32 coeff, u32 blendColor)
{
s32 newR, newG, newB, defR, defG, defB;
u16 * src = gPlttBufferUnfaded + palOffset;
u16 * dst = gPlttBufferFaded + palOffset;
u32 defaultBlendColor = DEFAULT_LIGHT_COLOR;
u16 *srcEnd = src + 16;
u32 altBlendColor = *dst++ = *src++; // color 0 is copied through unchanged
coeff *= 2;
newR = (blendColor << 27) >> 27;
newG = (blendColor << 22) >> 27;
newB = (blendColor << 17) >> 27;
if (altBlendColor >> 15) // Transparency high bit set; alt blend color
{
defR = (altBlendColor << 27) >> 27;
defG = (altBlendColor << 22) >> 27;
defB = (altBlendColor << 17) >> 27;
}
else
{
defR = (defaultBlendColor << 27) >> 27;
defG = (defaultBlendColor << 22) >> 27;
defB = (defaultBlendColor << 17) >> 27;
altBlendColor = 0;
}
while (src != srcEnd)
{
u32 srcColor = *src;
s32 r = (srcColor << 27) >> 27;
s32 g = (srcColor << 22) >> 27;
s32 b = (srcColor << 16) >> 26;
if (srcColor >> 15)
{
*dst = ((r + (((defR - r) * (s32)coeff) >> 5)) << 0)
| ((g + (((defG - g) * (s32)coeff) >> 5)) << 5)
| ((b + (((defB - (b & 31)) * (s32)coeff) >> 5)) << 10);
}
else // Use provided blend color
{
*dst = ((r + (((newR - r) * (s32)coeff) >> 5)) << 0)
| ((g + (((newG - g) * (s32)coeff) >> 5)) << 5)
| ((b + (((newB - (b & 31)) * (s32)coeff) >> 5)) << 10);
}
src++;
dst++;
}
}
// Blends a weighted average of two blend parameters
// Parameters can be either blended (as in BlendPalettes) or tinted (as in TintPaletteRGB_Copy)
void TimeMixPalettes(u32 palettes, u16 *src, u16 *dst, struct BlendSettings *blend0, struct BlendSettings *blend1, u16 weight0)
{
s32 r0, g0, b0, r1, g1, b1, defR, defG, defB, altR, altG, altB;
u32 color0, coeff0, color1, coeff1;
bool8 tint0, tint1;
u32 defaultColor = DEFAULT_LIGHT_COLOR;
if (!palettes)
return;
color0 = blend0->blendColor;
tint0 = blend0->isTint;
coeff0 = tint0 ? 8*2 : blend0->coeff*2;
color1 = blend1->blendColor;
tint1 = blend1->isTint;
coeff1 = tint1 ? 8*2 : blend1->coeff*2;
if (tint0)
{
r0 = (color0 << 24) >> 24;
g0 = (color0 << 16) >> 24;
b0 = (color0 << 8) >> 24;
}
else
{
r0 = (color0 << 27) >> 27;
g0 = (color0 << 22) >> 27;
b0 = (color0 << 17) >> 27;
}
if (tint1)
{
r1 = (color1 << 24) >> 24;
g1 = (color1 << 16) >> 24;
b1 = (color1 << 8) >> 24;
}
else
{
r1 = (color1 << 27) >> 27;
g1 = (color1 << 22) >> 27;
b1 = (color1 << 17) >> 27;
}
defR = (defaultColor << 27) >> 27;
defG = (defaultColor << 22) >> 27;
defB = (defaultColor << 17) >> 27;
do
{
if (palettes & 1)
{
u16 *srcEnd = src + 16;
u32 altBlendColor = *dst++ = *src++; // color 0 is copied through
if (altBlendColor >> 15) // Transparency high bit set; alt blend color
{
altR = (altBlendColor << 27) >> 27;
altG = (altBlendColor << 22) >> 27;
altB = (altBlendColor << 17) >> 27;
}
else
{
altBlendColor = 0;
}
while (src != srcEnd)
{
u32 srcColor = *src;
s32 r = (srcColor << 27) >> 27;
s32 g = (srcColor << 22) >> 27;
s32 b = (srcColor << 17) >> 27;
s32 r2, g2, b2;
if (srcColor >> 15)
{
if (altBlendColor)
{
// Use alternate blend color
r2 = r + (((altR - r) * (s32)coeff1) >> 5);
g2 = g + (((altG - g) * (s32)coeff1) >> 5);
b2 = b + (((altB - b) * (s32)coeff1) >> 5);
r = r + (((altR - r) * (s32)coeff0) >> 5);
g = g + (((altG - g) * (s32)coeff0) >> 5);
b = b + (((altB - b) * (s32)coeff0) >> 5);
}
else
{
// Use default blend color
r2 = r + (((defR - r) * (s32)coeff1) >> 5);
g2 = g + (((defG - g) * (s32)coeff1) >> 5);
b2 = b + (((defB - b) * (s32)coeff1) >> 5);
r = r + (((defR - r) * (s32)coeff0) >> 5);
g = g + (((defG - g) * (s32)coeff0) >> 5);
b = b + (((defB - b) * (s32)coeff0) >> 5);
}
}
else
{
// Use provided blend colors
if (!tint1)
{
// blend-based
r2 = (r + (((r1 - r) * (s32)coeff1) >> 5));
g2 = (g + (((g1 - g) * (s32)coeff1) >> 5));
b2 = (b + (((b1 - b) * (s32)coeff1) >> 5));
}
else
{
// tint-based
r2 = (u16)((r1 * r)) >> 8;
g2 = (u16)((g1 * g)) >> 8;
b2 = (u16)((b1 * b)) >> 8;
if (r2 > 31)
r2 = 31;
if (g2 > 31)
g2 = 31;
if (b2 > 31)
b2 = 31;
}
if (!tint0)
{
// blend-based
r = (r + (((r0 - r) * (s32)coeff0) >> 5));
g = (g + (((g0 - g) * (s32)coeff0) >> 5));
b = (b + (((b0 - b) * (s32)coeff0) >> 5));
}
else
{
// tint-based
r = (u16)((r0 * r)) >> 8;
g = (u16)((g0 * g)) >> 8;
b = (u16)((b0 * b)) >> 8;
if (r > 31)
r = 31;
if (g > 31)
g = 31;
if (b > 31)
b = 31;
}
}
r = r2 + (((r - r2) * (s32)weight0) >> 8);
g = g2 + (((g - g2) * (s32)weight0) >> 8);
b = b2 + (((b - b2) * (s32)weight0) >> 8);
*dst++ = RGB2(r, g, b);
// *dst++ = RGB2(r, g, b) | (srcColor >> 15) << 15;
src++;
}
}
else
{
src += 16;
dst += 16;
}
palettes >>= 1;
} while (palettes);
}
// Apply weighted average to palettes, preserving high bits of dst throughout
void AvgPaletteWeighted(u16 *src0, u16 *src1, u16 *dst, u16 weight0)
{
u16 *srcEnd = src0 + 16;
src0++;
src1++;
dst++; // leave dst transparency unchanged
while (src0 != srcEnd)
{
u32 src0Color = *src0++;
s32 r0 = (src0Color << 27) >> 27;
s32 g0 = (src0Color << 22) >> 27;
s32 b0 = (src0Color << 17) >> 27;
u32 src1Color = *src1++;
s32 r1 = (src1Color << 27) >> 27;
s32 g1 = (src1Color << 22) >> 27;
s32 b1 = (src1Color << 17) >> 27;
// Average and bitwise-OR
r0 = r1 + (((r0 - r1) * weight0) >> 8);
g0 = g1 + (((g0 - g1) * weight0) >> 8);
b0 = b1 + (((b0 - b1) * weight0) >> 8);
*dst = (*dst & RGB_ALPHA) | RGB2(r0, g0, b0); // preserve high bit of dst
dst++;
}
}
void BlendPalettesUnfaded(u32 selectedPalettes, u8 coeff, u32 color)
{
// This copy is done via DMA in both RUBY and EMERALD

View File

@@ -1,5 +1,6 @@
#include "global.h"
#include "gflib.h"
#include "overworld.h"
#include "palette_util.h"
#include "util.h"
@@ -374,6 +375,8 @@ void UpdatePulseBlend(struct PulseBlend *pulseBlend)
if (--pulseBlendPalette->delayCounter == 0xFF)
{
pulseBlendPalette->delayCounter = pulseBlendPalette->pulseBlendSettings.delay;
CpuFastCopy(gPlttBufferUnfaded + pulseBlendPalette->pulseBlendSettings.paletteOffset, gPlttBufferFaded + pulseBlendPalette->pulseBlendSettings.paletteOffset, PLTT_SIZE_4BPP);
UpdatePalettesWithTime(1 << (pulseBlendPalette->pulseBlendSettings.paletteOffset >> 4));
BlendPalette(pulseBlendPalette->pulseBlendSettings.paletteOffset, pulseBlendPalette->pulseBlendSettings.numColors, pulseBlendPalette->blendCoeff, pulseBlendPalette->pulseBlendSettings.blendColor);
switch (pulseBlendPalette->pulseBlendSettings.fadeType)
{

View File

@@ -1246,6 +1246,15 @@ static bool8 RestoreScreenAfterPlayback(u8 taskId)
CopyPaletteInvertedTint(&gPlttBufferUnfaded[BG_PLTT_ID(0) + 1], &gPlttBufferFaded[BG_PLTT_ID(0) + 1], 0xDF, 15 - tTimer);
CopyPaletteInvertedTint(&gPlttBufferUnfaded[OBJ_PLTT_ID(0)], &gPlttBufferFaded[OBJ_PLTT_ID(0)], 0x100, 15 - tTimer);
gTimeUpdateCounter = 0;
UpdateTimeOfDay();
if (MapHasNaturalLight(gMapHeader.mapType))
{
UpdateAltBgPalettes(PALETTES_BG);
UpdatePalettesWithTime(PALETTES_ALL);
}
FillWindowPixelRect(sWindowIds[WIN_TOP_BAR],
0x00, 0,
sWindowTemplates[WIN_TOP_BAR].height * 8 - 1 - tTimer,

View File

@@ -3,6 +3,7 @@
#include "clock.h"
#include "rtc.h"
#include "script.h"
#include "decompress.h"
#include "mystery_event_script.h"
#include "event_data.h"
#include "event_scripts.h"
@@ -646,6 +647,32 @@ bool8 ScrCmd_fadescreenspeed(struct ScriptContext * ctx)
return TRUE;
}
bool8 ScrCmd_fadescreenswapbuffers(struct ScriptContext *ctx)
{
u8 mode = ScriptReadByte(ctx);
u8 nowait = ScriptReadByte(ctx);
switch (mode)
{
case FADE_TO_BLACK:
case FADE_TO_WHITE:
default:
CpuCopy32(gPlttBufferUnfaded, gDecompressionBuffer, PLTT_SIZE);
FadeScreen(mode, 0);
break;
case FADE_FROM_BLACK:
case FADE_FROM_WHITE:
CpuCopy32(gDecompressionBuffer, gPlttBufferUnfaded, PLTT_SIZE);
FadeScreen(mode, 0);
break;
}
if (nowait)
return FALSE;
SetupNativeScript(ctx, IsPaletteNotActive);
return TRUE;
}
static bool8 RunPauseTimer(void)
{
if (--sPauseCounter == 0)