Integrated merrp's lighting branch (Day/Night System) (#6562)

This commit is contained in:
Bassoonian
2025-04-12 16:59:05 +02:00
committed by GitHub
68 changed files with 1803 additions and 327 deletions

View File

@@ -1790,11 +1790,14 @@
.4byte \text
.endm
@ Equivalent to fadescreen but copies gPlttBufferUnfaded to an allocated buffer on the fade out
@ and the reverse on the fade in, in effect saving gPlttBufferUnfaded to restore it.
.macro fadescreenswapbuffers mode:req
@ 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 SCR_OP_FADESCREENSWAPBUFFERS
.byte \mode
.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

@@ -760,12 +760,12 @@ Common_EventScript_PlayGymBadgeFanfare::
return
Common_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_RegionMap::

View File

@@ -476,6 +476,7 @@ BattleFrontier_BattleDomeBattleRoom_EventScript_SetUpObjects::
call BattleFrontier_EventScript_SetBrainObjectGfx
setobjectxyperm LOCALID_OPPONENT, 13, 9
removeobject LOCALID_OPPONENT
delay 1
addobject LOCALID_OPPONENT
applymovement LOCALID_OPPONENT, BattleFrontier_BattleDomeBattleRoom_Movement_SetInvisibleFacingUp
BattleFrontier_BattleDomeBattleRoom_EventScript_EndSetUpObjects::

View File

@@ -54,13 +54,13 @@ MtChimney_EventScript_Maxie::
msgbox MtChimney_Text_MaxieYouHaventSeenLastOfMagma, MSGBOX_DEFAULT
closemessage
delay 30
fadescreen FADE_TO_BLACK
fadescreenswapbuffers FADE_TO_BLACK
removeobject LOCALID_MAXIE
removeobject LOCALID_MAGMA_GRUNT_1
removeobject LOCALID_TABITHA
removeobject LOCALID_MAGMA_GRUNT_2
setflag FLAG_HIDE_MT_CHIMNEY_TEAM_MAGMA
fadescreen FADE_FROM_BLACK
fadescreenswapbuffers FADE_FROM_BLACK
setobjectxyperm LOCALID_ARCHIE, 10, 12
addobject LOCALID_ARCHIE
call_if_eq VAR_FACING, DIR_EAST, MtChimney_EventScript_ArchieApproachPlayerEast

View File

@@ -49,7 +49,7 @@ MtPyre_Summit_EventScript_TeamAquaExits::
call_if_eq VAR_0x8008, 2, MtPyre_Summit_EventScript_ArchieFacePlayer2
msgbox MtPyre_Summit_Text_ArchieWeGotTheOrbLetsGo, MSGBOX_DEFAULT
closemessage
fadescreen FADE_TO_BLACK
fadescreenswapbuffers FADE_TO_BLACK
removeobject LOCALID_ARCHIE
removeobject LOCALID_GRUNT_1
removeobject LOCALID_GRUNT_2
@@ -58,7 +58,7 @@ MtPyre_Summit_EventScript_TeamAquaExits::
setflag FLAG_HIDE_MT_PYRE_SUMMIT_ARCHIE
setflag FLAG_HIDE_MT_PYRE_SUMMIT_TEAM_AQUA
fadedefaultbgm
fadescreen FADE_FROM_BLACK
fadescreenswapbuffers FADE_FROM_BLACK
delay 20
setvar VAR_MT_PYRE_STATE, 1
call_if_eq VAR_0x8008, 0, MtPyre_Summit_EventScript_OldLadyApproachPlayer0

View File

@@ -48,6 +48,7 @@ SlateportCity_BattleTentBattleRoom_EventScript_EnterRoom::
factory_setopponentgfx
setobjectxyperm LOCALID_OPPONENT, 5, 1
removeobject LOCALID_OPPONENT
delay 1
addobject LOCALID_OPPONENT
applymovement LOCALID_OPPONENT, SlateportCity_BattleTentBattleRoom_Movement_OpponentEnter
waitmovement 0

View File

@@ -17,6 +17,7 @@
- [v1.6.x and earlier](tutorials/how_to_new_pokemon_1_6_0.md)
- [How to use the Testing System](tutorials/how_to_testing_system.md)
- [How to add new Trainer Slides](tutorials/how_to_new_trainer_slide.md)
- [Day/Night System FAQ](tutorials/dns.md)
- [Changelog](./CHANGELOG.md)
- [1.11.x]()
- [Version 1.11.1](changelogs/1.11.x/1.11.1.md)

25
docs/tutorials/dns.md Normal file
View File

@@ -0,0 +1,25 @@
## Day/Night system FAQ
### Q: How do I disable DNS?
A: Set `OW_ENABLE_DNS` to `FALSE` in `include/config/overworld.h`.
### Q: How do I mark certain colors in a palette as light-blended?
A: Create a `.pla` file in the same folder as the `.pal` with the same name.
In this file you can enter color indices [0,15]
on separate lines to mark those colors as being light-blended, i.e:
`06.pla:`
```
# A comment
0 # if color 0 is listed, uses it to blend with instead of the default!
1
9
10
```
### Q: How do I return to using regular shadows?
A: Set `OW_OBJECT_VANILLA_SHADOWS` to `TRUE` in `include/config/overworld.h`.
### Q: How do I disable shadows for certain locations?
A: Shadows can be disabled for certain locations by modifying the `CurrentMapHasShadows` function in `src/overworld.c`.

View File

@@ -0,0 +1,19 @@
JASC-PAL
0100
16
110 198 165
64 61 42
77 73 50
85 81 58
100 94 66
111 105 75
119 112 77
140 131 92
154 145 103
171 159 111
186 174 123
197 183 128
209 195 139
224 209 146
234 219 155
249 232 161

View File

@@ -0,0 +1,19 @@
JASC-PAL
0100
16
106 202 166
58 54 31
67 62 33
96 89 53
110 102 57
121 111 67
128 119 66
156 143 82
166 155 96
185 169 100
199 183 112
211 192 113
223 203 123
237 218 129
247 227 137
255 237 147

View File

@@ -0,0 +1,19 @@
JASC-PAL
0100
16
104 203 168
19 48 64
35 87 115
58 132 140
69 156 166
77 193 254
106 239 254
27 68 89
64 22 19
115 39 34
166 57 49
191 66 57
222 77 67
0 0 0
0 0 0
0 0 0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -5,5 +5,6 @@
void InitTimeBasedEvents(void);
void DoTimeBasedEvents(void);
void FormChangeTimeUpdate();
#endif // GUARD_CLOCK_H

View File

@@ -62,31 +62,13 @@
#define OW_FOLLOWERS_COPY_WILD_PKMN FALSE // If TRUE, follower Pokémon that know Transform or have Illusion/Imposter will copy wild Pokémon at random.
#define OW_BATTLE_ONLY_FORMS TRUE // If TRUE, loads overworld sprites for battle-only forms like Mega Evos. Requires OW_POKEMON_OBJECT_EVENTS.
#define B_FLAG_FOLLOWERS_DISABLED 0 // Enables / Disables followers by using a flag. Helpful to disable followers for a period of time.
#define OW_FOLLOWERS_SCRIPT_MOVEMENT TRUE // TRUE: Script collisions hide follower, FLAG_SAFE_FOLLOWER_MOVEMENT on by default
// FALSE: Script collisions unhandled, FLAG_SAFE_FOLLOWER_MOVEMENT off by default
// If set, the only pokemon allowed to follow you
// will be those matching species, met location,
// and/or met level;
// These accept vars, too: VAR_TEMP_1, etc
#define OW_MON_ALLOWED_SPECIES (0)
#define OW_MON_ALLOWED_MET_LVL (0)
#define OW_MON_ALLOWED_MET_LOC (0)
// Examples:
// Yellow Pikachu:
// #define OW_MON_ALLOWED_SPECIES (SPECIES_PIKACHU)
// #define OW_MON_ALLOWED_MET_LVL (0)
// #define OW_MON_ALLOWED_MET_LOC (MAPSEC_PALLET_TOWN)
// Hoenn Starter:
// #define OW_MON_ALLOWED_SPECIES (0)
// #define OW_MON_ALLOWED_MET_LVL (5)
// #define OW_MON_ALLOWED_MET_LOC (MAPSEC_ROUTE_101)
// Species set in VAR_XXXX:
// #define OW_MON_ALLOWED_SPECIES (VAR_XXXX)
// #define OW_MON_ALLOWED_MET_LVL (0)
// #define OW_MON_ALLOWED_MET_LOC (0)
#define OW_FOLLOWERS_SCRIPT_MOVEMENT TRUE // If TRUE, follower Pokémon only go back to their Poké Ball if a non-player collides with them by setting the FLAG_SAFE_FOLLOWER_MOVEMENT flag by default.
// Follower Pokémon Restrictions
// If set, the only pokemon allowed to follow you will be those matching species, met location, and/or met level; These accept vars, too: VAR_TEMP_1, etc
// For examples, see "docs/tutorials/how_to_new_pokemon.md"
#define OW_FOLLOWERS_ALLOWED_SPECIES (0)
#define OW_FOLLOWERS_ALLOWED_MET_LVL (0)
#define OW_FOLLOWERS_ALLOWED_MET_LOC (0)
// Out-of-battle Ability effects
#define OW_SYNCHRONIZE_NATURE GEN_LATEST // In Gen8+, if a Pokémon with Synchronize leads the party, wild Pokémon will always have their same Nature as opposed to the 50% chance in previous games. Gift Pokémon excluded.
@@ -111,6 +93,14 @@
#define OW_TIME_OF_DAY_DEFAULT TIME_MORNING // Should be set to whatever is the first value in the TimeOfDay enum in rtc.h
#define OW_TIME_OF_DAY_FALLBACK OW_TIME_OF_DAY_DEFAULT // The time of day that encounter tables fall back to. Defaults to whatever OW_TIME_OF_DAY_FALLBACK is set to.
// Lighting
#define OW_SHADOW_INTENSITY 4 // Ranges from 0 to 16, where 0 is fully transparent and 16 is black.
#define OW_OBJECT_SUBPRIORITY 148 // The higher the value, the farther back compared to other sprites. Shadows should be behind object events.
#define OW_ENABLE_DNS TRUE // If set to TRUE, the overworld will be tinted depending on time of day.
// Object Event Shadows
#define OW_OBJECT_VANILLA_SHADOWS FALSE // In vanilla shadows in the overworld are only shown when jumping.
// Overworld flags
// To use the following features in scripting, replace the 0s with the flag ID you're assigning it to.
// Eg: Replace with FLAG_UNUSED_0x264 so you can use that flag to toggle the feature.

View File

@@ -242,11 +242,12 @@
#define OBJ_EVENT_GFX_HOOH 238
#define OBJ_EVENT_GFX_POKE_BALL 239
#define OBJ_EVENT_GFX_OW_MON 240
#define OBJ_EVENT_GFX_LIGHT_SPRITE 241
// NOTE: The maximum amount of object events has been expanded from 255 to 65535.
// Since dynamic graphics ids still require at least 16 free values, the actual limit
// is 65519, but even considering follower Pokémon, this should be more than enough :)
#define NUM_OBJ_EVENT_GFX 241
#define NUM_OBJ_EVENT_GFX 242
// These are dynamic object gfx ids.
@@ -270,6 +271,7 @@
#define OBJ_EVENT_GFX_VAR_E (OBJ_EVENT_GFX_VARS + 0xE)
#define OBJ_EVENT_GFX_VAR_F (OBJ_EVENT_GFX_VARS + 0xF)
// Don't use (1u << 15) to avoid conflict with BLEND_IMMUNE_FLAG.
#define OBJ_EVENT_MON (1u << 14)
#define OBJ_EVENT_MON_SHINY (1u << 13)
#define OBJ_EVENT_MON_FEMALE (1u << 12)
@@ -305,12 +307,19 @@
#define TRACKS_SPOT 4
#define TRACKS_BUG 5
#define LIGHT_TYPE_BALL 0
#define LIGHT_TYPE_PKMN_CENTER_SIGN 1
#define LIGHT_TYPE_POKE_MART_SIGN 2
#define FIRST_DECORATION_SPRITE_GFX OBJ_EVENT_GFX_PICHU_DOLL
#define OBJ_KIND_NORMAL 0
#define OBJ_KIND_CLONE 255 // Exclusive to FRLG
// Special object event local ids
// Used for link player OWs in CreateLinkPlayerSprite
#define OBJ_EVENT_ID_DYNAMIC_BASE 0xF0
#define OBJ_EVENT_ID_PLAYER 0xFF
#define OBJ_EVENT_ID_CAMERA 0x7F
#define OBJ_EVENT_ID_FOLLOWER 0xFE
@@ -421,7 +430,10 @@
#endif //OW_FOLLOWERS_POKEBALLS
// Used as a placeholder follower graphic
#define OBJ_EVENT_PAL_TAG_SUBSTITUTE 0x7611
#define OBJ_EVENT_PAL_TAG_EMOTES 0x8002
#define OBJ_EVENT_PAL_TAG_LIGHT 0x8001
#define OBJ_EVENT_PAL_TAG_LIGHT_2 0x8002
#define OBJ_EVENT_PAL_TAG_EMOTES 0x8003
#define OBJ_EVENT_PAL_TAG_NEON_LIGHT 0x8004
// Not a real OW palette tag; used for the white flash applied to followers
#define OBJ_EVENT_PAL_TAG_WHITE (OBJ_EVENT_PAL_TAG_NONE - 1)
#define OBJ_EVENT_PAL_TAG_NONE 0x11FF

View File

@@ -133,5 +133,12 @@
#define FLDEFF_PAL_TAG_HOF_MONITOR 0x1010
#define FLDEFF_PAL_TAG_UNKNOWN 0x1011
#define FLDEFF_PAL_TAG_CAVE_DUST 0x1012
#define FLDEFF_PAL_TAG_FIELD_MOVE_MON 0x8400
// tile tags, for field effects that may have many copies on screen at once
#define FLDEFF_TILE_TAG_SHADOW_SMALL 0x1400
#define FLDEFF_TILE_TAG_SHADOW_MEDIUM 0x1401
#define FLDEFF_TILE_TAG_SHADOW_LARGE 0x1402
#define FLDEFF_TILE_TAG_SHADOW_EXTRA_LARGE 0x1403
#endif // GUARD_FIELD_EFFECT_CONSTANTS_H

View File

@@ -1,6 +1,16 @@
#ifndef GUARD_CONSTANTS_FIELD_WEATHER_H
#define GUARD_CONSTANTS_FIELD_WEATHER_H
#include "config/overworld.h"
// sPaletteColorMapTypes & field_effect_scripts
enum ColorMapType
{
COLOR_MAP_NONE,
COLOR_MAP_DARK_CONTRAST,
COLOR_MAP_CONTRAST,
};
#define MAX_RAIN_SPRITES 24
#define NUM_CLOUD_SPRITES 3
#define NUM_FOG_HORIZONTAL_SPRITES 20
@@ -22,4 +32,8 @@
#define FADE_FROM_WHITE 2
#define FADE_TO_WHITE 3
// Shadows values
#define BASE_SHADOW_INTENSITY (16 - OW_SHADOW_INTENSITY)
#define SHADOW_COLOR_INDEX 9 // Within the weather palette, shadow sprites' color index
#endif // GUARD_CONSTANTS_FIELD_WEATHER_H

View File

@@ -15,6 +15,7 @@
#define RGB_BLACK RGB(0, 0, 0)
#define RGB_WHITE RGB(31, 31, 31)
#define RGB_GRAY RGB(15, 15, 15)
#define RGB_RED RGB(31, 0, 0)
#define RGB_GREEN RGB(0, 31, 0)
#define RGB_BLUE RGB(0, 0, 31)

View File

@@ -145,13 +145,17 @@ u16 GetOverworldWeatherSpecies(u16 species);
void UpdateFollowingPokemon(void);
void RemoveFollowingPokemon(void);
struct ObjectEvent *GetFollowerObject(void);
u8 GetDirectionToFace(s16, s16, s16, s16);
void UpdateLightSprite(struct Sprite *);
void TrySpawnObjectEvents(s16 cameraX, s16 cameraY);
u8 CreateObjectGraphicsSpriteWithTag(u16 graphicsId, void (*callback)(struct Sprite *), s16 x, s16 y, u8 subpriority, u16 paletteTag);
u8 CreateObjectGraphicsSprite(u16, void (*)(struct Sprite *), s16 x, s16 y, u8 subpriority);
u8 TrySpawnObjectEvent(u8 localId, u8 mapNum, u8 mapGroup);
u8 SpawnSpecialObjectEventParameterized(u16 graphicsId, u8 movementBehavior, u8 localId, s16 x, s16 y, u8 elevation);
u8 SpawnSpecialObjectEvent(struct ObjectEventTemplate *);
void SetSpritePosToMapCoords(s16 mapX, s16 mapY, s16 *destX, s16 *destY);
void CameraObjectReset(void);
u8 LoadObjectEventPalette(u16);
u8 UpdateSpritePaletteByTemplate(const struct SpriteTemplate *, struct Sprite *);
void ObjectEventSetGraphicsId(struct ObjectEvent *, u16 graphicsId);
void ObjectEventTurn(struct ObjectEvent *, u8 direction);

View File

@@ -21,7 +21,7 @@ bool8 UpdateRevealDisguise(struct ObjectEvent *);
void StartRevealDisguise(struct ObjectEvent *);
void StartAshFieldEffect(s16, s16, u16, s16);
void SetUpReflection(struct ObjectEvent *, struct Sprite *, u8);
void SetUpShadow(struct ObjectEvent *, struct Sprite *);
void SetUpShadow(struct ObjectEvent *);
u32 StartFieldEffectForObjectEvent(u8, struct ObjectEvent *);
u8 FindTallGrassFieldEffectSpriteId(u8 localId, u8 mapNum, u8 mapGroup, s16 x, s16 y);
void UpdateRayquazaSpotlightEffect(struct Sprite *);

View File

@@ -44,7 +44,8 @@ struct Weather
s8 targetColorMapIndex;
u8 colorMapStepDelay;
u8 colorMapStepCounter;
u16 fadeDestColor;
u16 fadeDestColor:15;
u16 noShadows:1; // Certain weathers require blend coeffs that do not work nice with shadows
u8 palProcessingState;
u8 fadeScreenCounter;
bool8 readyForInit;
@@ -147,9 +148,10 @@ void SetCurrentAndNextWeatherNoDelay(u8 weather);
void ApplyWeatherColorMapIfIdle(s8 colorMapIndex);
void ApplyWeatherColorMapIfIdle_Gradual(u8 colorMapIndex, u8 targetColorMapIndex, u8 colorMapStepDelay);
void FadeScreen(u8 mode, s8 delay);
void FadeScreenHardware(u32 mode, s32 delay);
bool8 IsWeatherNotFadingIn(void);
void UpdateSpritePaletteWithWeather(u8 spritePaletteIndex);
void ApplyWeatherColorMapToPal(u8 paletteIndex);
void UpdateSpritePaletteWithWeather(u8 spritePaletteIndex, bool8 allowFog);
void ApplyWeatherColorMapToPals(u8 startPalIndex, u8 numPalettes);
void LoadCustomWeatherSpritePalette(const u16 *palette);
void ResetDroughtWeatherPaletteLoading(void);
bool8 LoadDroughtWeatherPalettes(void);
@@ -164,7 +166,9 @@ void PlayRainStoppingSoundEffect(void);
u8 IsWeatherChangeComplete(void);
void SetWeatherScreenFadeOut(void);
void SetWeatherPalStateIdle(void);
const u8 *SetPaletteColorMapType(u8 paletteIndex, enum ColorMapType colorMapType);
void PreservePaletteInWeather(u8 preservedPalIndex);
void ResetPaletteColorMapType(u8 paletteIndex);
void ResetPreservedPalettesInWeather(void);
bool32 IsWeatherAlphaBlend(void);
@@ -190,6 +194,7 @@ void Thunderstorm_Main(void);
void Thunderstorm_InitAll(void);
bool8 Thunderstorm_Finish(void);
void FogHorizontal_InitVars(void);
u8 UpdateShadowColor(u16 color);
void FogHorizontal_Main(void);
void FogHorizontal_InitAll(void);
bool8 FogHorizontal_Finish(void);

View File

@@ -45,7 +45,7 @@ void InitTrainerHillMap(void);
void InitBattlePyramidMap(bool8 setPlayerPosition);
void CopyMapTilesetsToVram(struct MapLayout const *mapLayout);
void LoadMapTilesetPalettes(struct MapLayout const *mapLayout);
void LoadSecondaryTilesetPalette(struct MapLayout const *mapLayout);
void LoadSecondaryTilesetPalette(struct MapLayout const *mapLayout, bool8 skipFaded);
void CopySecondaryTilesetToVramUsingHeap(struct MapLayout const *mapLayout);
void CopyPrimaryTilesetToVram(const struct MapLayout *);
void CopySecondaryTilesetToVram(const struct MapLayout *);

View File

@@ -111,6 +111,8 @@ enum {
COND_MSG_LEAVES,
COND_MSG_ICE,
COND_MSG_BURN,
COND_MSG_DAY,
COND_MSG_NIGHT,
COND_MSG_COUNT,
};

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

@@ -37,8 +37,11 @@ typedef void (*TilesetCB)(void);
struct Tileset
{
/*0x00*/ bool8 isCompressed;
/*0x00*/ u8 isCompressed:1;
/*0x00*/ u8 swapPalettes:7; // Bitmask determining whether palette has an alternate, night-time palette
/*0x01*/ bool8 isSecondary;
/*0x02*/ u8 lightPalettes; // Bitmask determining whether a palette should be time-blended as a light
/*0x03*/ u8 customLightColor; // Bitmask determining which light palettes have custom light colors (color 15)
/*0x04*/ const u32 *tiles;
/*0x08*/ const u16 (*palettes)[16];
/*0x0C*/ const u16 *metatiles;
@@ -188,14 +191,15 @@ struct ObjectEvent
u32 inShallowFlowingWater:1;
u32 inSandPile:1;
u32 inHotSprings:1;
u32 hasShadow:1;
u32 noShadow:1;
u32 spriteAnimPausedBackup:1;
/*0x03*/ u32 spriteAffineAnimPausedBackup:1;
u32 disableJumpLandingGroundEffect:1;
u32 fixedPriority:1;
u32 hideReflection:1;
u32 shiny:1; // OW mon shininess
u32 padding:3;
u32 jumpDone:1;
u32 padding:2;
/*0x04*/ u16 graphicsId; // 12 bits for species; high 4 bits for form
/*0x06*/ u8 movementType;
/*0x07*/ u8 trainerType;

View File

@@ -569,6 +569,8 @@ struct SaveBlock2
extern struct SaveBlock2 *gSaveBlock2Ptr;
extern u8 UpdateSpritePaletteWithTime(u8);
struct SecretBaseParty
{
u32 personality[PARTY_SIZE];

View File

@@ -26,6 +26,11 @@
#define SKIP_OBJECT_EVENT_LOAD 1
// trigger a time-of-day blend once
#define HOURS_BLEND_ONCE 25
// don't update gTimeBlend
#define HOURS_FREEZE_BLEND 26
struct InitialPlayerAvatarState
{
u8 transitionFlags;
@@ -40,6 +45,7 @@ struct LinkPlayerObjectEvent
u8 movementMode;
};
// Exported RAM declarations
extern struct WarpData gLastUsedWarp;
extern struct LinkPlayerObjectEvent gLinkPlayerObjectEvents[4];
@@ -53,6 +59,10 @@ extern u8 gLocalLinkPlayerId;
extern u8 gFieldLinkPlayerCount;
extern bool8 gExitStairsMovementDisabled;
extern bool8 gSkipShowMonAnim;
extern u8 gTimeOfDay;
extern s16 gTimeUpdateCounter;
extern struct TimeBlendSettings gTimeBlend;
extern const struct UCoords32 gDirectionToVectors[];
@@ -130,6 +140,11 @@ void CleanupOverworldWindowsAndTilemaps(void);
bool32 IsOverworldLinkActive(void);
void CB1_Overworld(void);
void CB2_OverworldBasic(void);
void UpdateTimeOfDay(void);
bool32 MapHasNaturalLight(u8 mapType);
bool32 CurrentMapHasShadows(void);
void UpdateAltBgPalettes(u16 palettes);
void UpdatePalettesWithTime(u32);
void CB2_Overworld(void);
void SetMainCallback1(void (*cb)(void));
void SetUnusedCallback(void *func);
@@ -156,6 +171,7 @@ bool32 Overworld_RecvKeysFromLinkIsRunning(void);
bool32 Overworld_SendKeysToLinkIsRunning(void);
bool32 IsSendingKeysOverCable(void);
void ClearLinkPlayerObjectEvents(void);
bool16 SetTimeOfDay(u16 hours);
// Item Description Headers
enum ItemObtainFlags

View File

@@ -1,10 +1,10 @@
#ifndef GUARD_PALETTE_H
#define GUARD_PALETTE_H
#define gPaletteFade_selectedPalettes (gPaletteFade.multipurpose1) // normal and fast fade
#define gPaletteFade_blendCnt (gPaletteFade.multipurpose1) // hardware fade
#define gPaletteFade_delay (gPaletteFade.multipurpose2) // normal and hardware fade
#define gPaletteFade_submode (gPaletteFade.multipurpose2) // fast fade
#define gPaletteFadeSelectedPalettes (gPaletteFade.multipurpose1) // normal and fast fade
#define gPaletteFadeBlendCnt (gPaletteFade.multipurpose1) // hardware fade
#define gPaletteFadeDelay (gPaletteFade.multipurpose2) // normal and hardware fade
#define gPaletteFadeSubmode (gPaletteFade.multipurpose2) // fast fade
#define PLTT_BUFFER_SIZE (PLTT_SIZE / sizeof(u16))
@@ -14,6 +14,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)
@@ -24,6 +26,10 @@
#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,
@@ -32,26 +38,50 @@ enum
FAST_FADE_OUT_TO_BLACK,
};
struct BlendSettings
{
u32 blendColor:24;
u32 isTint:1;
u32 coeff:5;
u32 unused:2;
};
struct TimeBlendSettings
{
struct BlendSettings startBlend;
struct BlendSettings endBlend;
u16 weight;
u16 altWeight;
};
struct PaletteFadeControl
{
u32 multipurpose1;
u8 delayCounter:6;
u16 y:5; // blend coefficient
u16 targetY:5; // target blend coefficient
u16 blendColor:15;
bool16 active:1;
u16 multipurpose2:6;
bool16 yDec:1; // whether blend coefficient is decreasing
bool16 bufferTransferDisabled:1;
u16 mode:2;
bool16 shouldResetBlendRegisters:1;
bool16 hardwareFadeFinishing:1;
u16 softwareFadeFinishingCounter:5;
bool16 softwareFadeFinishing:1;
bool16 objPaletteToggle:1;
u8 deltaY:4; // rate of change of blend coefficient
u32 multipurpose1; // This field needs to exist or errors will occur
// These three are only used for TOD blending
struct BlendSettings *bld0;
struct BlendSettings *bld1;
u32 weight:9; // [0, 256], so must be 9 bits
u32 delayCounter:6;
u32 y:5; // blend coefficient
u32 targetY:5; // target blend coefficient
u32 multipurpose2:6;
bool32 active:1;
u32 blendColor:15;
// end of word
bool32 yDec:1; // whether blend coefficient is decreasing
bool32 bufferTransferDisabled:1;
u32 mode:2;
bool32 shouldResetBlendRegisters:1;
bool32 hardwareFadeFinishing:1;
u32 softwareFadeFinishingCounter:5;
bool32 softwareFadeFinishing:1;
bool32 objPaletteToggle:1;
u32 deltaY:4; // rate of change of blend coefficient
u32 padding:15;
};
extern const struct BlendSettings gTimeOfDayBlend[];
extern struct PaletteFadeControl gPaletteFade;
extern u32 gPlttBufferTransferPending;
extern u16 ALIGNED(4) gPlttBufferUnfaded[PLTT_BUFFER_SIZE];
@@ -59,11 +89,14 @@ extern u16 ALIGNED(4) gPlttBufferFaded[PLTT_BUFFER_SIZE];
void LoadCompressedPalette(const u32 *src, u32 offset, u32 size);
void LoadPalette(const void *src, u32 offset, u32 size);
void LoadPaletteFast(const void *src, u32 offset, u32 size);
void FillPalette(u32 value, u32 offset, u32 size);
void TransferPlttBuffer(void);
u32 UpdatePaletteFade(void);
void ResetPaletteFade(void);
bool32 BeginNormalPaletteFade(u32 selectedPalettes, s8 delay, u8 startY, u8 targetY, u32 blendColor);
bool32 BeginTimeOfDayPaletteFade(u32 selectedPalettes, s8 delay, u8 startY, u8 targetY, struct BlendSettings *bld0, struct BlendSettings *bld1, u32 weight, u32 color);
void PaletteStruct_ResetById(u32 id);
void ResetPaletteFadeControl(void);
void InvertPlttBuffer(u32 selectedPalettes);
void TintPlttBuffer(u32 selectedPalettes, s8 r, s8 g, s8 b);
@@ -71,8 +104,13 @@ void UnfadePlttBuffer(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 BlendPalettesGradually(u32 selectedPalettes, s8 delay, u8 coeff, u8 coeffTarget, u16 color, u8 priority, u8 id);
void TimeBlendPalette(u16 palOffset, u32 coeff, u32 blendColor);
void TintPalette_RGB_Copy(u16 palOffset, u32 blendColor);
void TimeMixPalettes(u32 palettes, u16 *src, u16 *dst, struct BlendSettings *blend0, struct BlendSettings *blend1, u16 weight0);
void AvgPaletteWeighted(u16 *src0, u16 *src1, u16 *dst, u16 weight0);
void TintPalette_GrayScale(u16 *palette, u32 count);
void TintPalette_GrayScale2(u16 *palette, u32 count);
void TintPalette_SepiaTone(u16 *palette, u32 count);

View File

@@ -318,6 +318,7 @@ void RequestSpriteSheetCopy(const struct SpriteSheet *sheet);
u16 LoadSpriteSheetDeferred(const struct SpriteSheet *sheet);
void FreeAllSpritePalettes(void);
u32 LoadSpritePalette(const struct SpritePalette *palette);
u8 LoadSpritePaletteInSlot(const struct SpritePalette *palette, u8 paletteNum);
void LoadSpritePalettes(const struct SpritePalette *palettes);
u32 AllocSpritePalette(u16 tag);
u32 IndexOfSpritePaletteTag(u16 tag);

View File

@@ -2065,18 +2065,23 @@ static void SetBattlerMonData(u32 battler, struct Pokemon *party, u32 monId)
HandleLowHpMusicChange(&party[gBattlerPartyIndexes[battler]], battler);
}
// In normal singles, if follower pokemon is out, have it slide in instead of being thrown
static bool8 ShouldDoSlideInAnim(void)
// In normal singles, if follower Pokémon exists, and the Pokémon following is being sent out, have it slide in instead of being thrown
static bool8 ShouldDoSlideInAnim(u32 battler)
{
struct ObjectEvent *followerObj = GetFollowerObject();
if (!followerObj || followerObj->invisible)
return FALSE;
if (gBattleTypeFlags & (
BATTLE_TYPE_LINK | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_FRONTIER | BATTLE_TYPE_FIRST_BATTLE |
BATTLE_TYPE_SAFARI | BATTLE_TYPE_WALLY_TUTORIAL | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_TWO_OPPONENTS |
BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_RECORDED | BATTLE_TYPE_TRAINER_HILL)
)
return FALSE;
if (GetFirstLiveMon() != &gPlayerParty[gBattlerPartyIndexes[battler]])
return FALSE;
return TRUE;
}
@@ -2857,7 +2862,7 @@ void BtlController_HandleIntroTrainerBallThrow(u32 battler, u16 tagTrainerPal, c
if (side == B_SIDE_PLAYER)
{
StoreSpriteCallbackInData6(&gSprites[gBattleStruct->trainerSlideSpriteIds[battler]], SpriteCB_FreePlayerSpriteLoadMonSprite);
StartSpriteAnim(&gSprites[gBattleStruct->trainerSlideSpriteIds[battler]], ShouldDoSlideInAnim() ? 2 : 1);
StartSpriteAnim(&gSprites[gBattleStruct->trainerSlideSpriteIds[battler]], ShouldDoSlideInAnim(battler) ? 2 : 1);
paletteNum = AllocSpritePalette(tagTrainerPal);
LoadCompressedPalette(trainerPal, OBJ_PLTT_ID(paletteNum), PLTT_SIZE_4BPP);
@@ -2916,17 +2921,17 @@ static void Task_StartSendOutAnim(u8 taskId)
if (TwoMonsAtSendOut(battler))
{
gBattleResources->bufferA[battler][1] = gBattlerPartyIndexes[battler];
StartSendOutAnim(battler, FALSE, FALSE, ShouldDoSlideInAnim());
StartSendOutAnim(battler, FALSE, FALSE, ShouldDoSlideInAnim(battler));
battlerPartner = battler ^ BIT_FLANK;
gBattleResources->bufferA[battlerPartner][1] = gBattlerPartyIndexes[battlerPartner];
BattleLoadMonSpriteGfx(&gPlayerParty[gBattlerPartyIndexes[battlerPartner]], battlerPartner);
StartSendOutAnim(battlerPartner, FALSE, FALSE, ShouldDoSlideInAnim());
StartSendOutAnim(battlerPartner, FALSE, FALSE, ShouldDoSlideInAnim(battler));
}
else
{
gBattleResources->bufferA[battler][1] = gBattlerPartyIndexes[battler];
StartSendOutAnim(battler, FALSE, FALSE, ShouldDoSlideInAnim());
StartSendOutAnim(battler, FALSE, FALSE, ShouldDoSlideInAnim(battler));
}
gBattlerControllerFuncs[battler] = (void*)(GetWordTaskArg(taskId, tControllerFunc_1));
DestroyTask(taskId);

View File

@@ -1355,6 +1355,7 @@ static void InitPatternWeaveTransition(struct Task *task)
sTransitionData->WIN0V = DISPLAY_HEIGHT;
sTransitionData->BLDCNT = BLDCNT_TGT1_BG0 | BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_ALL;
sTransitionData->BLDALPHA = BLDALPHA_BLEND(task->tBlendTarget2, task->tBlendTarget1);
UpdateShadowColor(RGB_GRAY);
for (i = 0; i < DISPLAY_HEIGHT; i++)
gScanlineEffectRegBuffers[1][i] = DISPLAY_WIDTH;
@@ -3885,6 +3886,8 @@ static void VBlankCB_AngledWipes(void)
#define tFadeFromGrayIncrement data[5]
#define tDelayTimer data[6]
#define tBlend data[7]
#define tBldCntSaved data[8]
#define tShadowColor data[9]
static void CreateIntroTask(s16 fadeToGrayDelay, s16 fadeFromGrayDelay, s16 numFades, s16 fadeToGrayIncrement, s16 fadeFromGrayIncrement)
{
@@ -3912,17 +3915,28 @@ void Task_BattleTransition_Intro(u8 taskId)
static bool8 TransitionIntro_FadeToGray(struct Task *task)
{
u8 paletteNum = IndexOfSpritePaletteTag(TAG_WEATHER_START);
u16 index = OBJ_PLTT_ID(paletteNum) + SHADOW_COLOR_INDEX;
if (task->tDelayTimer == 0 || --task->tDelayTimer == 0)
{
task->tDelayTimer = task->tFadeToGrayDelay;
task->tBlend += task->tFadeToGrayIncrement;
if (task->tBlend > 16)
task->tBlend = 16;
if (paletteNum < 16)
task->tShadowColor = gPlttBufferFaded[index];
BlendPalettes(PALETTES_ALL, task->tBlend, RGB(11, 11, 11));
if (paletteNum < 16)
gPlttBufferFaded[index] = task->tShadowColor;
}
if (task->tBlend >= 16)
{
// Fade to gray complete, start fade back
// Save BLDCNT and turn off targets temporarily
task->tBldCntSaved = GetGpuReg(REG_OFFSET_BLDCNT);
SetGpuReg(REG_OFFSET_BLDCNT, task->tBldCntSaved & ~BLDCNT_TGT2_BG_ALL);
if (paletteNum < 16)
gPlttBufferFaded[index] = RGB(11, 11, 11);
task->tState++;
task->tDelayTimer = task->tFadeFromGrayDelay;
}
@@ -3933,11 +3947,19 @@ static bool8 TransitionIntro_FadeFromGray(struct Task *task)
{
if (task->tDelayTimer == 0 || --task->tDelayTimer == 0)
{
u8 paletteNum = IndexOfSpritePaletteTag(TAG_WEATHER_START);
task->tDelayTimer = task->tFadeFromGrayDelay;
task->tBlend -= task->tFadeFromGrayIncrement;
if (task->tBlend < 0)
task->tBlend = 0;
BlendPalettes(PALETTES_ALL, task->tBlend, RGB(11, 11, 11));
// Restore BLDCNT
SetGpuReg(REG_OFFSET_BLDCNT, task->tBldCntSaved);
if (paletteNum < 16)
{
u16 index = OBJ_PLTT_ID(paletteNum) + SHADOW_COLOR_INDEX;
gPlttBufferFaded[index] = task->tShadowColor;
}
}
if (task->tBlend == 0)
{
@@ -4230,6 +4252,7 @@ static bool8 FrontierLogoWave_Init(struct Task *task)
LZ77UnCompVram(sFrontierLogo_Tileset, tileset);
LoadPalette(sFrontierLogo_Palette, BG_PLTT_ID(15), sizeof(sFrontierLogo_Palette));
sTransitionData->cameraY = 0;
UpdateShadowColor(RGB_GRAY);
task->tState++;
return FALSE;

View File

@@ -1,4 +1,5 @@
#include "global.h"
#include "clock.h"
#include "event_data.h"
#include "rtc.h"
#include "time_events.h"
@@ -15,7 +16,6 @@
static void UpdatePerDay(struct Time *localTime);
static void UpdatePerMinute(struct Time *localTime);
static void FormChangeTimeUpdate();
void InitTimeBasedEvents(void)
{
@@ -72,12 +72,11 @@ static void UpdatePerMinute(struct Time *localTime)
{
BerryTreeTimeUpdate(minutes);
gSaveBlock2Ptr->lastBerryTreeUpdate = *localTime;
FormChangeTimeUpdate();
}
}
}
static void FormChangeTimeUpdate()
void FormChangeTimeUpdate()
{
s32 i;
for (i = 0; i < PARTY_SIZE; i++)

View File

@@ -35,6 +35,7 @@ extern const struct SpriteTemplate gFieldEffectObjectTemplate_AshLaunch;
extern const struct SpriteTemplate gFieldEffectObjectTemplate_Bubbles;
extern const struct SpriteTemplate gFieldEffectObjectTemplate_SmallSparkle;
extern const struct SpriteTemplate gFieldEffectObjectTemplate_Rayquaza;
extern const struct SpriteTemplate gFieldEffectObjectTemplate_BallLight;
extern const struct SpriteTemplate gFieldEffectObjectTemplate_SlitherTracks;
extern const struct SpriteTemplate gFieldEffectObjectTemplate_BugTracks;
extern const struct SpriteTemplate gFieldEffectObjectTemplate_SpotTracks;

View File

@@ -28,8 +28,56 @@ static const struct SpriteFrameImage sPicTable_ShadowExtraLarge[] = {
obj_frame_tiles(gFieldEffectObjectPic_ShadowExtraLarge),
};
const struct SpriteTemplate gFieldEffectObjectTemplate_ShadowSmall = {
const struct SpriteFrameImage gFieldEffectObjectPicTable_BallLight[] = {
obj_frame_tiles(gFieldEffectObjectPic_BallLight),
};
const struct SpriteFrameImage gFieldEffectObjectPicTable_PokeCenterLight[] = {
obj_frame_tiles(gFieldEffectObjectPic_PokeCenterLight),
};
const struct SpriteFrameImage gFieldEffectObjectPicTable_MartLight[] = {
obj_frame_tiles(gFieldEffectObjectPic_MartLight),
};
const struct SpriteTemplate gFieldEffectObjectTemplate_BallLight = {
.tileTag = OBJ_EVENT_PAL_TAG_LIGHT,
.paletteTag = OBJ_EVENT_PAL_TAG_LIGHT,
.oam = &gObjectEventBaseOam_32x32,
.anims = sAnimTable_Inanimate,
.images = gFieldEffectObjectPicTable_BallLight,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = UpdateLightSprite,
};
const struct SpriteTemplate gFieldEffectObjectTemplate_PokeCenterLight = {
.tileTag = TAG_NONE,
.paletteTag = OBJ_EVENT_PAL_TAG_NEON_LIGHT,
.oam = &gObjectEventBaseOam_16x16,
.anims = sAnimTable_Inanimate,
.images = gFieldEffectObjectPicTable_PokeCenterLight,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = UpdateLightSprite,
};
const struct SpriteTemplate gFieldEffectObjectTemplate_MartLight = {
.tileTag = TAG_NONE,
.paletteTag = OBJ_EVENT_PAL_TAG_NEON_LIGHT,
.oam = &gObjectEventBaseOam_16x16,
.anims = sAnimTable_Inanimate,
.images = gFieldEffectObjectPicTable_MartLight,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = UpdateLightSprite,
};
const struct SpriteTemplate *const gFieldEffectLightTemplates[] = {
&gFieldEffectObjectTemplate_BallLight,
&gFieldEffectObjectTemplate_PokeCenterLight,
&gFieldEffectObjectTemplate_MartLight,
};
const struct SpriteTemplate gFieldEffectObjectTemplate_ShadowSmall = {
.tileTag = FLDEFF_TILE_TAG_SHADOW_SMALL,
.paletteTag = TAG_WEATHER_START,
.oam = &gObjectEventBaseOam_8x8,
.anims = sAnimTable_Shadow,
@@ -39,7 +87,7 @@ const struct SpriteTemplate gFieldEffectObjectTemplate_ShadowSmall = {
};
const struct SpriteTemplate gFieldEffectObjectTemplate_ShadowMedium = {
.tileTag = TAG_NONE,
.tileTag = FLDEFF_TILE_TAG_SHADOW_MEDIUM,
.paletteTag = TAG_WEATHER_START,
.oam = &gObjectEventBaseOam_16x8,
.anims = sAnimTable_Shadow,
@@ -49,7 +97,7 @@ const struct SpriteTemplate gFieldEffectObjectTemplate_ShadowMedium = {
};
const struct SpriteTemplate gFieldEffectObjectTemplate_ShadowLarge = {
.tileTag = TAG_NONE,
.tileTag = FLDEFF_TILE_TAG_SHADOW_LARGE,
.paletteTag = TAG_WEATHER_START,
.oam = &gObjectEventBaseOam_32x8,
.anims = sAnimTable_Shadow,
@@ -59,7 +107,7 @@ const struct SpriteTemplate gFieldEffectObjectTemplate_ShadowLarge = {
};
const struct SpriteTemplate gFieldEffectObjectTemplate_ShadowExtraLarge = {
.tileTag = TAG_NONE,
.tileTag = FLDEFF_TILE_TAG_SHADOW_EXTRA_LARGE,
.paletteTag = TAG_WEATHER_START,
.oam = &gObjectEventBaseOam_64x32,
.anims = sAnimTable_Shadow,

View File

@@ -293,7 +293,9 @@ const u32 gFieldEffectObjectPic_ShadowSmall[] = INCBIN_U32("graphics/field_effec
const u32 gFieldEffectObjectPic_ShadowMedium[] = INCBIN_U32("graphics/field_effects/pics/shadow_medium.4bpp");
const u32 gFieldEffectObjectPic_ShadowLarge[] = INCBIN_U32("graphics/field_effects/pics/shadow_large.4bpp");
const u32 gFieldEffectObjectPic_ShadowExtraLarge[] = INCBIN_U32("graphics/field_effects/pics/shadow_extra_large.4bpp");
static const u32 sFiller[0x48] = {};
const u32 gFieldEffectObjectPic_BallLight[] = INCBIN_U32("graphics/object_events/pics/misc/light.4bpp");
const u32 gFieldEffectObjectPic_PokeCenterLight[] = INCBIN_U32("graphics/object_events/pics/misc/poke_center_light.4bpp");
const u32 gFieldEffectObjectPic_MartLight[] = INCBIN_U32("graphics/object_events/pics/misc/mart_light.4bpp");
const u8 gFieldEffectPic_CutGrass[] = INCBIN_U8("graphics/field_effects/pics/cut_grass.4bpp");
const u32 gFieldEffectPic_CutGrass_Copy[] = INCBIN_U32("graphics/field_effects/pics/cut_grass.4bpp");
const u16 gFieldEffectPal_CutGrass[] = INCBIN_U16("graphics/field_effects/palettes/cut_grass.gbapal");
@@ -380,9 +382,12 @@ const u32 gObjectEventPic_RayquazaCutscene[] = INCBIN_U32("graphics/object_event
const u16 gObjectEventPal_HoOh[] = INCBIN_U16("graphics/object_events/palettes/ho_oh.gbapal");
const u16 gObjectEventPal_Lugia[] = INCBIN_U16("graphics/object_events/palettes/lugia.gbapal");
const u16 gObjectEventPal_Substitute[] = INCBIN_U16("graphics/pokemon/question_mark/overworld.gbapal");
const u16 gObjectEventPaletteLight[] = INCBIN_U16("graphics/object_events/palettes/light.gbapal");
const u16 gObjectEventPaletteLight2[] = INCBIN_U16("graphics/object_events/palettes/light2.gbapal");
const u16 gObjectEventPal_Substitute[] = INCBIN_U16("graphics/object_events/pics/pokemon_old/substitute.gbapal");
const u16 gObjectEventPaletteEmotes[] = INCBIN_U16("graphics/misc/emotes.gbapal");
const u16 gObjectEventPaletteNeonLight[] = INCBIN_U16("graphics/object_events/palettes/neon_light.gbapal");
#if OW_FOLLOWERS_POKEBALLS
const u32 gObjectEventPic_MasterBall[] = INCBIN_U32("graphics/object_events/pics/misc/ball_master.4bpp");

View File

@@ -4671,3 +4671,22 @@ const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_Follower = {
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
};
const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_BallLight = {
.tileTag = TAG_NONE,
.paletteTag = OBJ_EVENT_PAL_TAG_LIGHT,
.reflectionPaletteTag = OBJ_EVENT_PAL_TAG_LIGHT_2,
.size = 512,
.width = 32,
.height = 32,
.paletteSlot = PALSLOT_NPC_1,
.shadowSize = SHADOW_SIZE_NONE,
.inanimate = TRUE,
.compressed = FALSE,
.tracks = TRACKS_NONE,
.oam = &gObjectEventBaseOam_32x32,
.subspriteTables = sOamTables_32x32,
.anims = sAnimTable_Inanimate,
.images = gFieldEffectObjectPicTable_BallLight,
.affineAnims = gDummySpriteAffineAnimTable,
};

View File

@@ -239,6 +239,7 @@ extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_HoOh;
// Begin pokemon event objects
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_PokeBall;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_Follower;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_BallLight;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_Bard;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_Hipster;
@@ -490,6 +491,7 @@ const struct ObjectEventGraphicsInfo *const gObjectEventGraphicsInfoPointers[NUM
[OBJ_EVENT_GFX_HOOH] = &gObjectEventGraphicsInfo_HoOh,
[OBJ_EVENT_GFX_POKE_BALL] = &gObjectEventGraphicsInfo_PokeBall,
[OBJ_EVENT_GFX_OW_MON] = &gObjectEventGraphicsInfo_Follower,
[OBJ_EVENT_GFX_LIGHT_SPRITE] = &gObjectEventGraphicsInfo_BallLight,
};
const struct ObjectEventGraphicsInfo *const gMauvilleOldManGraphicsInfoPointers[] = {

View File

@@ -1117,8 +1117,9 @@ static const struct SpriteFrameImage sPicTable_PokeBall[] = {
overworld_frame(gObjectEventPic_PokeBall, 2, 4, 0),
};
#if OW_FOLLOWERS_POKEBALLS
extern const struct SpriteFrameImage gFieldEffectObjectPicTable_BallLight[];
#if OW_FOLLOWERS_POKEBALLS
#define POKEBALL_PIC_FRAMES(name) \
overworld_frame(gObjectEventPic_##name##Ball, 2, 4, 0), \
overworld_frame(gObjectEventPic_##name##Ball, 2, 4, 1), \

View File

@@ -1,3 +1,8 @@
#include "fieldmap.h"
// Whether a palette has a night version, located at ((x + 9) % 16).pal
#define SWAP_PAL(x) ((x) < NUM_PALS_IN_PRIMARY ? 1 << (x) : 1 << ((x) - NUM_PALS_IN_PRIMARY))
const struct Tileset gTileset_General =
{
.isCompressed = TRUE,

View File

@@ -2131,7 +2131,7 @@ static u8 AddDecorationIconObjectFromObjectEvent(u16 tilesTag, u16 paletteTag, u
}
else
{
spriteId = CreateObjectGraphicsSprite(sPlaceDecorationGraphicsDataBuffer.decoration->tiles[0], SpriteCallbackDummy, 0, 0, 1);
spriteId = CreateObjectGraphicsSpriteWithTag(sPlaceDecorationGraphicsDataBuffer.decoration->tiles[0], SpriteCallbackDummy, 0, 0, 1, paletteTag);
}
return spriteId;
}

View File

@@ -30,6 +30,7 @@
#include "pokeball.h"
#include "random.h"
#include "region_map.h"
#include "rtc.h"
#include "script.h"
#include "sound.h"
#include "sprite.h"
@@ -186,7 +187,7 @@ static void SetSpriteDataForNormalStep(struct Sprite *, u8, u8);
static void InitSpriteForFigure8Anim(struct Sprite *);
static bool8 AnimateSpriteInFigure8(struct Sprite *);
u8 GetDirectionToFace(s16 x1, s16 y1, s16 x2, s16 y2);
static void FollowerSetGraphics(struct ObjectEvent * objectEvent, u32 species, bool32 shiny, bool32 female);
static void FollowerSetGraphics(struct ObjectEvent *objEvent, u32 species, bool32 shiny, bool32 female);
static void ObjectEventSetGraphics(struct ObjectEvent *, const struct ObjectEventGraphicsInfo *);
static void SpriteCB_VirtualObject(struct Sprite *);
static void DoShadowFieldEffect(struct ObjectEvent *);
@@ -545,7 +546,10 @@ static const struct SpritePalette sObjectEventSpritePalettes[] = {
#endif //ITEM_STRANGE_BALL
#endif //OW_FOLLOWERS_POKEBALLS
{gObjectEventPal_Substitute, OBJ_EVENT_PAL_TAG_SUBSTITUTE},
{gObjectEventPaletteLight, OBJ_EVENT_PAL_TAG_LIGHT},
{gObjectEventPaletteLight2, OBJ_EVENT_PAL_TAG_LIGHT_2},
{gObjectEventPaletteEmotes, OBJ_EVENT_PAL_TAG_EMOTES},
{gObjectEventPaletteNeonLight, OBJ_EVENT_PAL_TAG_NEON_LIGHT},
#ifdef BUGFIX
{NULL, OBJ_EVENT_PAL_TAG_NONE},
#else
@@ -1348,7 +1352,7 @@ u8 GetFirstInactiveObjectEventId(void)
u8 GetObjectEventIdByLocalIdAndMap(u8 localId, u8 mapNum, u8 mapGroupId)
{
if (localId < OBJ_EVENT_ID_FOLLOWER)
if (localId < OBJ_EVENT_ID_DYNAMIC_BASE)
return GetObjectEventIdByLocalIdAndMapInternal(localId, mapNum, mapGroupId);
return GetObjectEventIdByLocalId(localId);
@@ -1833,7 +1837,7 @@ static u32 LoadDynamicFollowerPaletteFromGraphicsId(u16 graphicsId, struct Sprit
}
// Used to create a sprite using a graphicsId associated with object events.
u8 CreateObjectGraphicsSprite(u16 graphicsId, void (*callback)(struct Sprite *), s16 x, s16 y, u8 subpriority)
u8 CreateObjectGraphicsSpriteWithTag(u16 graphicsId, void (*callback)(struct Sprite *), s16 x, s16 y, u8 subpriority, u16 paletteTag)
{
struct SpriteTemplate *spriteTemplate;
const struct SubspriteTable *subspriteTables;
@@ -1880,6 +1884,11 @@ u8 CreateObjectGraphicsSprite(u16 graphicsId, void (*callback)(struct Sprite *),
return spriteId;
}
u8 CreateObjectGraphicsSprite(u16 graphicsId, void (*callback)(struct Sprite *), s16 x, s16 y, u8 subpriority)
{
return CreateObjectGraphicsSpriteWithTag(graphicsId, callback, x, y, subpriority, TAG_NONE);
}
#define sVirtualObjId data[0]
#define sVirtualObjElev data[1]
@@ -1935,12 +1944,10 @@ struct Pokemon *GetFirstLiveMon(void)
for (i = 0; i < PARTY_SIZE; i++)
{
struct Pokemon *mon = &gPlayerParty[i];
if ((OW_MON_ALLOWED_SPECIES && GetMonData(mon, MON_DATA_SPECIES_OR_EGG) != VarGet(OW_MON_ALLOWED_SPECIES))
|| (OW_MON_ALLOWED_MET_LVL && GetMonData(mon, MON_DATA_MET_LEVEL) != VarGet(OW_MON_ALLOWED_MET_LVL))
|| (OW_MON_ALLOWED_MET_LOC && GetMonData(mon, MON_DATA_MET_LOCATION) != VarGet(OW_MON_ALLOWED_MET_LOC)))
{
if ((OW_FOLLOWERS_ALLOWED_SPECIES && GetMonData(mon, MON_DATA_SPECIES_OR_EGG) != VarGet(OW_FOLLOWERS_ALLOWED_SPECIES))
|| (OW_FOLLOWERS_ALLOWED_MET_LVL && GetMonData(mon, MON_DATA_MET_LEVEL) != VarGet(OW_FOLLOWERS_ALLOWED_MET_LVL))
|| (OW_FOLLOWERS_ALLOWED_MET_LOC && GetMonData(mon, MON_DATA_MET_LOCATION) != VarGet(OW_FOLLOWERS_ALLOWED_MET_LOC)))
continue;
}
if (gPlayerParty[i].hp > 0 && !(gPlayerParty[i].box.isEgg || gPlayerParty[i].box.isBadEgg))
return &gPlayerParty[i];
@@ -2061,7 +2068,7 @@ static u32 LoadDynamicFollowerPalette(u32 species, bool32 shiny, bool32 female)
}
if (gWeatherPtr->currWeather != WEATHER_FOG_HORIZONTAL) // don't want to weather blend in fog
UpdateSpritePaletteWithWeather(paletteNum);
UpdateSpritePaletteWithWeather(paletteNum, FALSE);
return paletteNum;
}
@@ -2080,10 +2087,6 @@ static void FollowerSetGraphics(struct ObjectEvent *objEvent, u32 species, bool3
sprite->inUse = TRUE;
sprite->oam.paletteNum = LoadDynamicFollowerPalette(species, shiny, female);
}
else if (gWeatherPtr->currWeather != WEATHER_FOG_HORIZONTAL) // don't want to weather blend in fog
{
UpdateSpritePaletteWithWeather(gSprites[objEvent->spriteId].oam.paletteNum);
}
}
// Like FollowerSetGraphics, but does not recenter sprite on a metatile
@@ -2128,7 +2131,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);
}
}
@@ -2341,9 +2344,15 @@ bool32 CheckMsgCondition(const struct MsgCondition *cond, struct Pokemon *mon, u
return (multi == cond->data.bytes[0] || multi == cond->data.bytes[1]);
case MSG_COND_MUSIC:
return (cond->data.raw == GetCurrentMapMusic());
// Added on `lighting` branch
// case MSG_COND_TIME_OF_DAY:
// break;
case MSG_COND_TIME_OF_DAY:
{
// Must match time of day, have natural light on the map,
// and not have weather that obscures the sky
u32 weather = GetCurrentWeather();
return (cond->data.raw == gTimeOfDay
&& MapHasNaturalLight(gMapHeader.mapType)
&& (weather == WEATHER_NONE || weather == WEATHER_SUNNY_CLOUDS || weather == WEATHER_SUNNY));
}
case MSG_COND_NEAR_MB:
multi = FindMetatileBehaviorWithinRange(obj->currentCoords.x,
obj->currentCoords.y,
@@ -2563,6 +2572,156 @@ void GetFollowerAction(struct ScriptContext *ctx) // Essentially a big switch fo
gFollowerBasicMessages[emotion].script);
}
#define sLightType data[5]
#define sLightXPos data[6]
#define sLightYPos data[7]
// Sprite 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->sLightXPos;
s16 y = sprite->sLightYPos;
u16 sheetTileStart;
u32 paletteNum;
if (!(x >= left && x <= right && y >= top && y <= bottom))
{
sheetTileStart = sprite->sheetTileStart;
paletteNum = sprite->oam.paletteNum;
DestroySprite(sprite);
FieldEffectFreeTilesIfUnused(sheetTileStart);
FieldEffectFreePaletteIfUnused(paletteNum);
Weather_SetBlendCoeffs(7, BASE_SHADOW_INTENSITY); // TODO: Restore original blend coeffs at dawn
return;
}
if (gTimeOfDay != TIME_NIGHT)
{
sprite->invisible = TRUE;
return;
}
// Note: Don't set window registers during hardware fade!
switch (sprite->sLightType)
{
default:
case LIGHT_TYPE_BALL:
if (gPaletteFade.active) // if palette fade is active, don't flicker since the timer won't be updated
{
Weather_SetBlendCoeffs(7, BASE_SHADOW_INTENSITY);
sprite->invisible = FALSE;
}
else if (gPlayerAvatar.tileTransitionState)
{
Weather_SetBlendCoeffs(7, BASE_SHADOW_INTENSITY); // As long as the second coefficient stays 12, shadows will not change
sprite->invisible = FALSE;
if (GetSpritePaletteTagByPaletteNum(sprite->oam.paletteNum) == OBJ_EVENT_PAL_TAG_LIGHT_2)
LoadSpritePaletteInSlot(&sObjectEventSpritePalettes[FindObjectEventPaletteIndexByTag(OBJ_EVENT_PAL_TAG_LIGHT)], sprite->oam.paletteNum);
}
else if ((sprite->invisible = gTimeUpdateCounter & 1))
{
Weather_SetBlendCoeffs(7, BASE_SHADOW_INTENSITY);
sprite->invisible = FALSE;
if (GetSpritePaletteTagByPaletteNum(sprite->oam.paletteNum) == OBJ_EVENT_PAL_TAG_LIGHT_2)
LoadSpritePaletteInSlot(&sObjectEventSpritePalettes[FindObjectEventPaletteIndexByTag(OBJ_EVENT_PAL_TAG_LIGHT)], sprite->oam.paletteNum);
}
break;
case LIGHT_TYPE_PKMN_CENTER_SIGN:
case LIGHT_TYPE_POKE_MART_SIGN:
Weather_SetBlendCoeffs(12, BASE_SHADOW_INTENSITY);
sprite->invisible = FALSE;
break;
}
}
// Spawn a light at a map coordinate
static void SpawnLightSprite(s16 x, s16 y, s16 camX, s16 camY, u32 lightType)
{
struct Sprite *sprite;
const struct SpriteTemplate *template;
u32 i;
for (i = 0; i < MAX_SPRITES; i++)
{
sprite = &gSprites[i];
if (sprite->inUse && sprite->callback == UpdateLightSprite && sprite->sLightXPos == x && sprite->sLightYPos == y)
return;
}
lightType = min(lightType, ARRAY_COUNT(gFieldEffectLightTemplates) - 1); // bounds checking
template = gFieldEffectLightTemplates[lightType];
LoadSpriteSheetByTemplate(template, 0, 0);
sprite = &gSprites[CreateSprite(template, 0, 0, 0)];
if (lightType == 0 && (i = IndexOfSpritePaletteTag(template->paletteTag + 1)) < 16)
sprite->oam.paletteNum = i;
else
UpdateSpritePaletteByTemplate(template, sprite);
GetMapCoordsFromSpritePos(x + camX, y + camY, &sprite->x, &sprite->y);
sprite->sLightType = lightType;
sprite->sLightXPos = x;
sprite->sLightYPos = y;
sprite->affineAnims = gDummySpriteAffineAnimTable;
sprite->affineAnimBeginning = TRUE;
sprite->coordOffsetEnabled = TRUE;
switch (lightType)
{
default:
case LIGHT_TYPE_BALL:
sprite->centerToCornerVecX = -(32 >> 1);
sprite->centerToCornerVecY = -(32 >> 1);
sprite->oam.priority = 1;
sprite->oam.objMode = ST_OAM_OBJ_BLEND;
sprite->oam.affineMode = ST_OAM_AFFINE_NORMAL;
sprite->x += 8;
sprite->y += 22 + sprite->centerToCornerVecY;
break;
case LIGHT_TYPE_PKMN_CENTER_SIGN:
case LIGHT_TYPE_POKE_MART_SIGN:
sprite->centerToCornerVecX = -(16 >> 1);
sprite->centerToCornerVecY = -(16 >> 1);
sprite->oam.priority = 2;
sprite->subpriority = 0xFF;
sprite->oam.objMode = ST_OAM_OBJ_BLEND;
break;
}
}
#undef sLightType
#undef sLightXPos
#undef sLightYPos
void TrySpawnLightSprites(s16 camX, s16 camY)
{
u32 i;
u8 objectCount;
s16 left = gSaveBlock1Ptr->pos.x - 2;
s16 right = gSaveBlock1Ptr->pos.x + MAP_OFFSET_W + 2;
s16 top = gSaveBlock1Ptr->pos.y;
s16 bottom = gSaveBlock1Ptr->pos.y + MAP_OFFSET_H + 2;
if (gMapHeader.events == NULL)
return;
if (InBattlePyramid())
objectCount = GetNumBattlePyramidObjectEvents();
else if (InTrainerHill())
objectCount = 2;
else
objectCount = gMapHeader.events->objectEventCount;
for (i = 0; i < objectCount; i++)
{
struct ObjectEventTemplate *template = &gSaveBlock1Ptr->objectEventTemplates[i];
s16 npcX = template->x + MAP_OFFSET;
s16 npcY = template->y + MAP_OFFSET;
if (top <= npcY && bottom >= npcY
&& left <= npcX && right >= npcX
&& !FlagGet(template->flagId)
&& template->graphicsId == OBJ_EVENT_GFX_LIGHT_SPRITE) // event is light sprite instead
SpawnLightSprite(npcX, npcY, camX, camY, template->trainerRange_berryTreeId);
}
}
void TrySpawnObjectEvents(s16 cameraX, s16 cameraY)
{
u8 i;
@@ -2588,9 +2747,13 @@ void TrySpawnObjectEvents(s16 cameraX, s16 cameraY)
s16 npcX = template->x + MAP_OFFSET;
s16 npcY = template->y + MAP_OFFSET;
if (top <= npcY && bottom >= npcY && left <= npcX && right >= npcX
&& !FlagGet(template->flagId))
TrySpawnObjectEventTemplate(template, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, cameraX, cameraY);
if (top <= npcY && bottom >= npcY && left <= npcX && right >= npcX && !FlagGet(template->flagId))
{
if (template->graphicsId == OBJ_EVENT_GFX_LIGHT_SPRITE)
SpawnLightSprite(npcX, npcY, cameraX, cameraY, template->trainerRange_berryTreeId); // light sprite instead
else
TrySpawnObjectEventTemplate(template, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, cameraX, cameraY);
}
}
}
}
@@ -2646,6 +2809,7 @@ void SpawnObjectEventsOnReturnToField(s16 x, s16 y)
SpawnObjectEventOnReturnToField(i, x, y);
}
CreateReflectionEffectSprites();
TrySpawnLightSprites(x, y);
}
static void SpawnObjectEventOnReturnToField(u8 objectEventId, s16 x, s16 y)
@@ -2720,7 +2884,7 @@ static void ResetObjectEventFldEffData(struct ObjectEvent *objectEvent)
{
objectEvent->singleMovementActive = FALSE;
objectEvent->triggerGroundEffectsOnMove = TRUE;
objectEvent->hasShadow = FALSE;
objectEvent->noShadow = FALSE;
objectEvent->hasReflection = FALSE;
objectEvent->inShortGrass = FALSE;
objectEvent->inShallowFlowingWater = FALSE;
@@ -2744,7 +2908,17 @@ static u8 UpdateSpritePalette(const struct SpritePalette *spritePalette, struct
sprite->inUse = FALSE;
FieldEffectFreePaletteIfUnused(sprite->oam.paletteNum);
sprite->inUse = TRUE;
return sprite->oam.paletteNum = LoadSpritePalette(spritePalette);
if (IndexOfSpritePaletteTag(spritePalette->tag) == 0xFF)
{
sprite->oam.paletteNum = LoadSpritePalette(spritePalette);
UpdateSpritePaletteWithWeather(sprite->oam.paletteNum, FALSE);
}
else
{
sprite->oam.paletteNum = LoadSpritePalette(spritePalette);
}
return sprite->oam.paletteNum;
}
// Find and update based on template's paletteTag
@@ -2999,12 +3173,15 @@ static void UNUSED LoadObjectEventPaletteSet(u16 *paletteTags)
LoadObjectEventPalette(paletteTags[i]);
}
// Really just loads the palette and applies weather fade
static u8 LoadSpritePaletteIfTagExists(const struct SpritePalette *spritePalette)
{
u8 paletteNum = IndexOfSpritePaletteTag(spritePalette->tag);
if (paletteNum != 0xFF) // don't load twice; return
return paletteNum;
paletteNum = LoadSpritePalette(spritePalette);
if (paletteNum != 0xFF)
UpdateSpritePaletteWithWeather(paletteNum, FALSE);
return paletteNum;
}
@@ -5542,7 +5719,7 @@ bool8 FollowablePlayerMovement_Step(struct ObjectEvent *objectEvent, struct Spri
direction = gObjectEvents[gPlayerAvatar.objectEventId].movementDirection;
objectEvent->facingDirectionLocked = TRUE;
}
MoveCoords(direction, &x, &y);
GetCollisionAtCoords(objectEvent, x, y, direction); // Sets directionOverwrite for stairs
if (GetLedgeJumpDirection(x, y, direction) != DIR_NONE)
@@ -7050,6 +7227,8 @@ static void InitJump(struct ObjectEvent *objectEvent, struct Sprite *sprite, u8
static void InitJumpRegular(struct ObjectEvent *objectEvent, struct Sprite *sprite, u8 direction, u8 distance, u8 type)
{
if (OW_OBJECT_VANILLA_SHADOWS)
SetUpShadow(objectEvent);
// For follower only, match the anim duration of the player's movement, whether dashing, walking or jumping
if (objectEvent->localId == OBJ_EVENT_ID_FOLLOWER
&& type == JUMP_TYPE_HIGH
@@ -7088,6 +7267,10 @@ static u8 UpdateJumpAnim(struct ObjectEvent *objectEvent, struct Sprite *sprite,
objectEvent->triggerGroundEffectsOnStop = TRUE;
objectEvent->landingJump = TRUE;
sprite->animPaused = TRUE;
if (OW_OBJECT_VANILLA_SHADOWS)
// Somewhat ugly workaround, the shadow is disabled in UpdateShadowFieldEffect,
// but due to code changes from DNS, it needs new signaling
objectEvent->jumpDone = TRUE;
}
return result;
}
@@ -7144,7 +7327,7 @@ bool8 MovementAction_Jump2Down_Step1(struct ObjectEvent *objectEvent, struct Spr
{
if (DoJumpAnim(objectEvent, sprite))
{
objectEvent->hasShadow = FALSE;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -7161,7 +7344,7 @@ bool8 MovementAction_Jump2Up_Step1(struct ObjectEvent *objectEvent, struct Sprit
{
if (DoJumpAnim(objectEvent, sprite))
{
objectEvent->hasShadow = FALSE;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -7178,7 +7361,7 @@ bool8 MovementAction_Jump2Left_Step1(struct ObjectEvent *objectEvent, struct Spr
{
if (DoJumpAnim(objectEvent, sprite))
{
objectEvent->hasShadow = FALSE;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -7195,7 +7378,7 @@ bool8 MovementAction_Jump2Right_Step1(struct ObjectEvent *objectEvent, struct Sp
{
if (DoJumpAnim(objectEvent, sprite))
{
objectEvent->hasShadow = FALSE;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -8081,7 +8264,7 @@ bool8 MovementAction_JumpDown_Step1(struct ObjectEvent *objectEvent, struct Spri
{
if (DoJumpAnim(objectEvent, sprite))
{
objectEvent->hasShadow = 0;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -8098,7 +8281,7 @@ bool8 MovementAction_JumpUp_Step1(struct ObjectEvent *objectEvent, struct Sprite
{
if (DoJumpAnim(objectEvent, sprite))
{
objectEvent->hasShadow = 0;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -8115,7 +8298,7 @@ bool8 MovementAction_JumpLeft_Step1(struct ObjectEvent *objectEvent, struct Spri
{
if (DoJumpAnim(objectEvent, sprite))
{
objectEvent->hasShadow = 0;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -8132,7 +8315,7 @@ bool8 MovementAction_JumpRight_Step1(struct ObjectEvent *objectEvent, struct Spr
{
if (DoJumpAnim(objectEvent, sprite))
{
objectEvent->hasShadow = 0;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -8149,7 +8332,7 @@ bool8 MovementAction_JumpInPlaceDown_Step1(struct ObjectEvent *objectEvent, stru
{
if (DoJumpAnim(objectEvent, sprite))
{
objectEvent->hasShadow = 0;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -8166,7 +8349,7 @@ bool8 MovementAction_JumpInPlaceUp_Step1(struct ObjectEvent *objectEvent, struct
{
if (DoJumpAnim(objectEvent, sprite))
{
objectEvent->hasShadow = 0;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -8183,7 +8366,7 @@ bool8 MovementAction_JumpInPlaceLeft_Step1(struct ObjectEvent *objectEvent, stru
{
if (DoJumpAnim(objectEvent, sprite))
{
objectEvent->hasShadow = 0;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -8200,7 +8383,7 @@ bool8 MovementAction_JumpInPlaceRight_Step1(struct ObjectEvent *objectEvent, str
{
if (DoJumpAnim(objectEvent, sprite))
{
objectEvent->hasShadow = 0;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -8217,7 +8400,7 @@ bool8 MovementAction_JumpInPlaceDownUp_Step1(struct ObjectEvent *objectEvent, st
{
if (DoJumpInPlaceAnim(objectEvent, sprite))
{
objectEvent->hasShadow = 0;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -8234,7 +8417,7 @@ bool8 MovementAction_JumpInPlaceUpDown_Step1(struct ObjectEvent *objectEvent, st
{
if (DoJumpInPlaceAnim(objectEvent, sprite))
{
objectEvent->hasShadow = 0;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -8251,7 +8434,7 @@ bool8 MovementAction_JumpInPlaceLeftRight_Step1(struct ObjectEvent *objectEvent,
{
if (DoJumpInPlaceAnim(objectEvent, sprite))
{
objectEvent->hasShadow = 0;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -8268,7 +8451,7 @@ bool8 MovementAction_JumpInPlaceRightLeft_Step1(struct ObjectEvent *objectEvent,
{
if (DoJumpInPlaceAnim(objectEvent, sprite))
{
objectEvent->hasShadow = 0;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -8713,7 +8896,7 @@ bool8 MovementAction_AcroWheelieHopFaceDown_Step1(struct ObjectEvent *objectEven
{
if (DoJumpAnim(objectEvent, sprite))
{
objectEvent->hasShadow = FALSE;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -8730,7 +8913,7 @@ bool8 MovementAction_AcroWheelieHopFaceUp_Step1(struct ObjectEvent *objectEvent,
{
if (DoJumpAnim(objectEvent, sprite))
{
objectEvent->hasShadow = FALSE;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -8747,7 +8930,7 @@ bool8 MovementAction_AcroWheelieHopFaceLeft_Step1(struct ObjectEvent *objectEven
{
if (DoJumpAnim(objectEvent, sprite))
{
objectEvent->hasShadow = FALSE;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -8764,7 +8947,7 @@ bool8 MovementAction_AcroWheelieHopFaceRight_Step1(struct ObjectEvent *objectEve
{
if (DoJumpAnim(objectEvent, sprite))
{
objectEvent->hasShadow = FALSE;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -8781,7 +8964,7 @@ bool8 MovementAction_AcroWheelieHopDown_Step1(struct ObjectEvent *objectEvent, s
{
if (DoJumpAnim(objectEvent, sprite))
{
objectEvent->hasShadow = FALSE;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -8798,7 +8981,7 @@ bool8 MovementAction_AcroWheelieHopUp_Step1(struct ObjectEvent *objectEvent, str
{
if (DoJumpAnim(objectEvent, sprite))
{
objectEvent->hasShadow = FALSE;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -8818,7 +9001,7 @@ bool8 MovementAction_AcroWheelieHopLeft_Step1(struct ObjectEvent *objectEvent, s
{
if (DoJumpAnim(objectEvent, sprite))
{
objectEvent->hasShadow = FALSE;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -8838,7 +9021,7 @@ bool8 MovementAction_AcroWheelieHopRight_Step1(struct ObjectEvent *objectEvent,
{
if (DoJumpAnim(objectEvent, sprite))
{
objectEvent->hasShadow = FALSE;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -8855,7 +9038,7 @@ bool8 MovementAction_AcroWheelieJumpDown_Step1(struct ObjectEvent *objectEvent,
{
if (DoJumpAnim(objectEvent, sprite))
{
objectEvent->hasShadow = FALSE;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -8872,7 +9055,7 @@ bool8 MovementAction_AcroWheelieJumpUp_Step1(struct ObjectEvent *objectEvent, st
{
if (DoJumpAnim(objectEvent, sprite))
{
objectEvent->hasShadow = FALSE;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -8892,7 +9075,7 @@ bool8 MovementAction_AcroWheelieJumpLeft_Step1(struct ObjectEvent *objectEvent,
{
if (DoJumpAnim(objectEvent, sprite))
{
objectEvent->hasShadow = FALSE;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -8912,7 +9095,7 @@ bool8 MovementAction_AcroWheelieJumpRight_Step1(struct ObjectEvent *objectEvent,
{
if (DoJumpAnim(objectEvent, sprite))
{
objectEvent->hasShadow = FALSE;
objectEvent->noShadow = FALSE;
sprite->sActionFuncId = 2;
return TRUE;
}
@@ -10025,14 +10208,17 @@ static void (*const sGroundEffectFuncs[])(struct ObjectEvent *objEvent, struct S
static void DoFlaggedGroundEffects(struct ObjectEvent *objEvent, struct Sprite *sprite, u32 flags)
{
u8 i;
u32 i;
if (ObjectEventIsFarawayIslandMew(objEvent) == TRUE && !ShouldMewShakeGrass(objEvent))
return;
for (i = 0; i < ARRAY_COUNT(sGroundEffectFuncs); i++, flags >>= 1)
if (flags & 1)
sGroundEffectFuncs[i](objEvent, sprite);
if (!OW_OBJECT_VANILLA_SHADOWS && CurrentMapHasShadows() && !(gWeatherPtr->noShadows || objEvent->inHotSprings || objEvent->inSandPile || MetatileBehavior_IsPuddle(objEvent->currentMetatileBehavior)))
{
SetUpShadow(objEvent);
}
}
void filters_out_some_ground_effects(struct ObjectEvent *objEvent, u32 *flags)
@@ -10791,9 +10977,9 @@ u32 StartFieldEffectForObjectEvent(u8 fieldEffectId, struct ObjectEvent *objectE
static void DoShadowFieldEffect(struct ObjectEvent *objectEvent)
{
if (!objectEvent->hasShadow)
if (objectEvent->noShadow)
{
objectEvent->hasShadow = TRUE;
objectEvent->noShadow = FALSE;
StartFieldEffectForObjectEvent(FLDEFF_SHADOW, objectEvent);
}
}

View File

@@ -392,7 +392,7 @@ void SetMewAboveGrass(void)
gSprites[mew->spriteId].subpriority = 1;
LoadSpritePalette(&gSpritePalette_GeneralFieldEffect1);
UpdateSpritePaletteWithWeather(IndexOfSpritePaletteTag(gSpritePalette_GeneralFieldEffect1.tag));
UpdateSpritePaletteWithWeather(IndexOfSpritePaletteTag(gSpritePalette_GeneralFieldEffect1.tag), FALSE);
x = mew->currentCoords.x;
y = mew->currentCoords.y;

View File

@@ -791,9 +791,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));
u32 paletteSlot = LoadSpritePalette(palette);
(*script) += 4;
SetPaletteColorMapType(paletteSlot + 16, T1_READ_8(*script));
UpdateSpritePaletteWithWeather(paletteSlot, TRUE);
(*script)++;
}
void FieldEffectScript_LoadPalette(u8 **script)
@@ -849,6 +851,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);
}
}
@@ -1626,6 +1629,7 @@ static bool8 EscalatorWarpOut_WaitForPlayer(struct Task *task)
if (!ObjectEventIsMovementOverridden(objectEvent) || ObjectEventClearHeldMovementIfFinished(objectEvent))
{
ObjectEventSetHeldMovement(objectEvent, GetFaceDirectionMovementAction(GetPlayerFacingDirection()));
objectEvent->noShadow = TRUE; // hide shadow for cleaner movement
task->tState++;
task->data[2] = 0;
task->data[3] = 0;
@@ -1747,6 +1751,7 @@ static bool8 EscalatorWarpIn_Init(struct Task *task)
u8 behavior;
CameraObjectFreeze();
objectEvent = &gObjectEvents[gPlayerAvatar.objectEventId];
objectEvent->noShadow = TRUE;
ObjectEventSetHeldMovement(objectEvent, GetFaceDirectionMovementAction(DIR_EAST));
PlayerGetDestCoords(&x, &y);
behavior = MapGridGetMetatileBehaviorAt(x, y);
@@ -1843,6 +1848,7 @@ static bool8 EscalatorWarpIn_End(struct Task *task)
{
struct ObjectEvent *objectEvent;
objectEvent = &gObjectEvents[gPlayerAvatar.objectEventId];
objectEvent->noShadow = FALSE;
if (ObjectEventClearHeldMovementIfFinished(objectEvent))
{
CameraObjectReset();
@@ -1995,6 +2001,7 @@ static bool8 LavaridgeGymB1FWarpEffect_Init(struct Task *task, struct ObjectEven
SetCameraPanningCallback(NULL);
gPlayerAvatar.preventStep = TRUE;
objectEvent->fixedPriority = 1;
objectEvent->noShadow = TRUE;
task->data[1] = 1;
task->data[0]++;
if (objectEvent->localId == OBJ_EVENT_ID_PLAYER) // Hide follower before warping
@@ -2191,6 +2198,7 @@ static bool8 LavaridgeGym1FWarpEffect_Init(struct Task *task, struct ObjectEvent
CameraObjectFreeze();
gPlayerAvatar.preventStep = TRUE;
objectEvent->fixedPriority = 1;
objectEvent->noShadow = TRUE;
task->data[0]++;
if (objectEvent->localId == OBJ_EVENT_ID_PLAYER) // Hide follower before warping
HideFollowerForFieldEffect();
@@ -3314,7 +3322,7 @@ static void FlyOutFieldEffect_FlyOffWithBird(struct Task *task)
struct ObjectEvent *objectEvent = &gObjectEvents[gPlayerAvatar.objectEventId];
ObjectEventClearHeldMovementIfActive(objectEvent);
objectEvent->inanimate = FALSE;
objectEvent->hasShadow = FALSE;
objectEvent->noShadow = TRUE;
SetFlyBirdPlayerSpriteId(task->tBirdSpriteId, objectEvent->spriteId);
CameraObjectFreeze();
task->tState++;
@@ -3536,6 +3544,7 @@ static void FlyInFieldEffect_BirdSwoopDown(struct Task *task)
ObjectEventTurn(objectEvent, DIR_WEST);
StartSpriteAnim(&gSprites[objectEvent->spriteId], ANIM_GET_ON_OFF_POKEMON_WEST);
objectEvent->invisible = FALSE;
objectEvent->noShadow = TRUE;
task->tBirdSpriteId = CreateFlyBirdSprite();
StartFlyBirdSwoopDown(task->tBirdSpriteId);
SetFlyBirdPlayerSpriteId(task->tBirdSpriteId, objectEvent->spriteId);

View File

@@ -54,11 +54,11 @@ u32 FldEff_Shadow(void);
#define sReflectionVerticalOffset data[2]
#define sIsStillReflection data[7]
void SetUpShadow(struct ObjectEvent *objectEvent, struct Sprite *sprite)
void SetUpShadow(struct ObjectEvent *objectEvent)
{
gFieldEffectArguments[0] = objectEvent->localId;
gFieldEffectArguments[1] = gSaveBlock1Ptr->location.mapNum;
gFieldEffectArguments[2] = gSaveBlock1Ptr->location.mapGroup;
gFieldEffectArguments[1] = objectEvent->mapNum;
gFieldEffectArguments[2] = objectEvent->mapGroup;
FldEff_Shadow();
}
@@ -114,15 +114,16 @@ static void LoadObjectReflectionPalette(struct ObjectEvent *objectEvent, struct
// Apply a blue tint effect to a palette
static void ApplyPondFilter(u8 paletteNum, u16 *dest)
{
u32 i, r, g, b;
// CpuCopy16(gPlttBufferUnfaded + 0x100 + paletteNum * 16, dest, 32);
u32 i;
s32 r, g, b;
u16 *src = gPlttBufferUnfaded + OBJ_PLTT_ID(paletteNum);
*dest++ = *src++; // copy transparency
for (i = 0; i < 16 - 1; i++)
{
r = GET_R(src[i]);
g = GET_G(src[i]);
b = GET_B(src[i]);
u32 color = *src++;
r = (color << 27) >> 27;
g = (color << 22) >> 27;
b = (color << 17) >> 27;
b += 10;
if (b > 31)
b = 31;
@@ -133,21 +134,22 @@ static void ApplyPondFilter(u8 paletteNum, u16 *dest)
// Apply a ice tint effect to a palette
static void ApplyIceFilter(u8 paletteNum, u16 *dest)
{
u32 i, r, g, b;
// CpuCopy16(gPlttBufferUnfaded + 0x100 + paletteNum * 16, dest, 32);
u32 i;
s32 r, g, b;
u16 *src = gPlttBufferUnfaded + OBJ_PLTT_ID(paletteNum);
*dest++ = *src++; // copy transparency
for (i = 0; i < 16 - 1; i++)
{
r = GET_R(src[i]);
u32 color = *src++;
r = (color << 27) >> 27;
g = (color << 22) >> 27;
b = (color << 17) >> 27;
r -= 5;
if (r > 31)
if (r < 0)
r = 0;
g = GET_G(src[i]);
g += 3;
if (g > 31)
g = 31;
b = GET_B(src[i]);
b += 16;
if (b > 31)
b = 31;
@@ -171,7 +173,7 @@ static void LoadObjectRegularReflectionPalette(struct ObjectEvent *objectEvent,
else
ApplyIceFilter(mainSprite->oam.paletteNum, filteredData);
paletteNum = LoadSpritePalette(&filteredPal);
UpdateSpritePaletteWithWeather(paletteNum);
UpdateSpritePaletteWithWeather(paletteNum, TRUE);
}
sprite->oam.paletteNum = paletteNum;
sprite->oam.objMode = ST_OAM_OBJ_BLEND;
@@ -185,7 +187,7 @@ static void LoadObjectHighBridgeReflectionPalette(struct ObjectEvent *objectEven
struct SpritePalette bluePalette = {.tag = HIGH_BRIDGE_PAL_TAG, .data = blueData};
CpuFill16(0x55C9, blueData, PLTT_SIZE_4BPP);
sprite->oam.paletteNum = LoadSpritePalette(&bluePalette);
UpdateSpritePaletteWithWeather(sprite->oam.paletteNum);
UpdateSpritePaletteWithWeather(sprite->oam.paletteNum, TRUE);
}
static void UpdateObjectReflectionSprite(struct Sprite *reflectionSprite)
@@ -221,7 +223,7 @@ static void UpdateObjectReflectionSprite(struct Sprite *reflectionSprite)
else
ApplyIceFilter(mainSprite->oam.paletteNum, filteredData);
paletteNum = LoadSpritePalette(&filteredPal);
UpdateSpritePaletteWithWeather(paletteNum);
UpdateSpritePaletteWithWeather(paletteNum, TRUE);
}
reflectionSprite->oam.paletteNum = paletteNum;
}
@@ -333,22 +335,26 @@ u32 FldEff_Shadow(void)
u8 objectEventId;
const struct ObjectEventGraphicsInfo *graphicsInfo;
u8 spriteId;
u8 i;
for (i = 0; i < MAX_SPRITES; i++)
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]);
graphicsInfo = GetObjectEventGraphicsInfo(gObjectEvents[objectEventId].graphicsId);
if (graphicsInfo->shadowSize == SHADOW_SIZE_NONE) // don't create a shadow at all
return 0;
spriteId = CreateSpriteAtEnd(gFieldEffectObjectTemplatePointers[sShadowEffectTemplateIds[graphicsInfo->shadowSize]], 0, 0, 0x94);
LoadSpriteSheetByTemplate(gFieldEffectObjectTemplatePointers[sShadowEffectTemplateIds[graphicsInfo->shadowSize]], 0, 0);
spriteId = CreateSpriteAtEnd(gFieldEffectObjectTemplatePointers[sShadowEffectTemplateIds[graphicsInfo->shadowSize]], 0, 0, OW_OBJECT_SUBPRIORITY + 1);
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];
@@ -383,8 +389,19 @@ void UpdateShadowFieldEffect(struct Sprite *sprite)
sprite->y = linkedSprite->y + sprite->sYOffset;
#endif
sprite->invisible = linkedSprite->invisible;
if (!objectEvent->active || !objectEvent->hasShadow
if (objectEvent->jumpDone)
{
// Ugly signaling to disable shadows after a jump
objectEvent->noShadow = TRUE;
objectEvent->jumpDone = FALSE;
}
if (!objectEvent->active
|| objectEvent->noShadow
|| objectEvent->inHotSprings
|| objectEvent->inSandPile
|| gWeatherPtr->noShadows
|| MetatileBehavior_IsPokeGrass(objectEvent->currentMetatileBehavior)
|| MetatileBehavior_IsPuddle(objectEvent->currentMetatileBehavior)
|| MetatileBehavior_IsSurfableWaterOrUnderwater(objectEvent->currentMetatileBehavior)
|| MetatileBehavior_IsSurfableWaterOrUnderwater(objectEvent->previousMetatileBehavior))
{
@@ -1516,7 +1533,7 @@ static u32 ShowDisguiseFieldEffect(u8 fldEff, u8 fldEffObj, u8 paletteNum)
if (spriteId != MAX_SPRITES)
{
struct Sprite *sprite = &gSprites[spriteId];
UpdateSpritePaletteByTemplate(gFieldEffectObjectTemplatePointers[fldEffObj], sprite);
sprite->oam.paletteNum = LoadObjectEventPalette(gFieldEffectObjectTemplatePointers[fldEffObj]->paletteTag);
sprite->coordOffsetEnabled ++;
sprite->sFldEff = fldEff;
sprite->sLocalId = gFieldEffectArguments[0];

View File

@@ -1157,6 +1157,7 @@ static void Task_OrbEffect(u8 taskId)
ClearGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN1_ON);
SetGpuRegBits(REG_OFFSET_BLDCNT, gOrbEffectBackgroundLayerFlags[0]);
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(12, 7));
UpdateShadowColor(RGB(9, 8, 8));
SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR);
SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG1 | WINOUT_WIN01_BG2 | WINOUT_WIN01_BG3 | WINOUT_WIN01_OBJ);
SetBgTilemapPalette(0, 0, 0, DISPLAY_TILE_WIDTH, DISPLAY_TILE_HEIGHT, 0xF);
@@ -1224,6 +1225,7 @@ static void Task_OrbEffect(u8 taskId)
SetGpuReg(REG_OFFSET_DISPCNT, tDispCnt);
SetGpuReg(REG_OFFSET_BLDCNT, tBldCnt);
SetGpuReg(REG_OFFSET_BLDALPHA, tBldAlpha);
UpdateShadowColor(RGB_BLACK);
SetGpuReg(REG_OFFSET_WININ, tWinIn);
SetGpuReg(REG_OFFSET_WINOUT, tWinOut);
ScriptContext_Enable();

View File

@@ -68,6 +68,7 @@
#include "constants/battle_frontier.h"
#include "constants/weather.h"
#include "constants/metatile_labels.h"
#include "constants/rgb.h"
#include "palette.h"
#include "battle_util.h"
#include "naming_screen.h"
@@ -3281,6 +3282,7 @@ static void ChangeDeoxysRockLevel(u8 rockLevel)
{
u8 paletteNum = IndexOfSpritePaletteTag(OBJ_EVENT_PAL_TAG_BIRTH_ISLAND_STONE);
LoadPalette(&sDeoxysRockPalettes[rockLevel], OBJ_PLTT_ID(paletteNum), PLTT_SIZEOF(4));
UpdateSpritePaletteWithWeather(paletteNum, FALSE);
if (rockLevel == 0)
PlaySE(SE_M_CONFUSE_RAY); // Failure sound
@@ -3332,7 +3334,7 @@ void SetDeoxysRockPalette(void)
u32 paletteNum = IndexOfSpritePaletteTag(OBJ_EVENT_PAL_TAG_BIRTH_ISLAND_STONE);
LoadPalette(&sDeoxysRockPalettes[(u8)VarGet(VAR_DEOXYS_ROCK_LEVEL)], OBJ_PLTT_ID(paletteNum), PLTT_SIZEOF(4));
// Set faded to all black, weather blending handled during fade-in
CpuFill16(0, &gPlttBufferFaded[OBJ_PLTT_ID(paletteNum)], 32);
CpuFill16(RGB_BLACK, &gPlttBufferFaded[OBJ_PLTT_ID(paletteNum)], PLTT_SIZE_4BPP);
}
void SetPCBoxToSendMon(u8 boxId)

View File

@@ -3,6 +3,7 @@
#include "constants/weather.h"
#include "constants/rgb.h"
#include "util.h"
#include "decompress.h"
#include "event_object_movement.h"
#include "field_weather.h"
#include "fieldmap.h"
@@ -18,16 +19,10 @@
#include "trig.h"
#include "gpu_regs.h"
#include "field_camera.h"
#include "overworld.h"
#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;
@@ -208,7 +203,7 @@ void StartWeather(void)
sPaletteColorMapTypes = sBasePaletteColorMapTypes;
gWeatherPtr->contrastColorMapSpritePalIndex = index;
gWeatherPtr->weatherPicSpritePalIndex = AllocSpritePalette(PALTAG_WEATHER_2);
gWeatherPtr->weatherPicSpritePalIndex = 0xFF; // defer allocation until needed
gWeatherPtr->rainSpriteCount = 0;
gWeatherPtr->curRainSpriteIndex = 0;
gWeatherPtr->cloudSpritesCreated = 0;
@@ -318,7 +313,8 @@ static void Task_WeatherMain(u8 taskId)
static void None_Init(void)
{
Weather_SetBlendCoeffs(8, 12); // Indoor shadows
Weather_SetBlendCoeffs(8, BASE_SHADOW_INTENSITY); // Indoor shadows
gWeatherPtr->noShadows = FALSE;
gWeatherPtr->targetColorMapIndex = 0;
gWeatherPtr->colorMapStepDelay = 0;
}
@@ -458,18 +454,31 @@ static void ApplyColorMap(u8 startPalIndex, u8 numPalettes, s8 colorMapIndex)
if (colorMapIndex > 0)
{
// Create the palette mask
u32 palettes = PALETTES_ALL;
numPalettes += startPalIndex;
palettes = (palettes >> startPalIndex) << startPalIndex;
palettes = (palettes << (32 - numPalettes)) >> (32 - numPalettes);
numPalettes -= startPalIndex;
colorMapIndex--;
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 (colorMapIndex <= 3 && MapHasNaturalLight(gMapHeader.mapType))
UpdatePalettesWithTime(palettes);
else
CpuFastCopy(gPlttBufferUnfaded + palOffset, gPlttBufferFaded + palOffset, PLTT_SIZE_4BPP * numPalettes);
numPalettes += startPalIndex;
curPalIndex = startPalIndex;
// Loop through the specified palette range and apply necessary color maps.
while (curPalIndex < numPalettes)
{
if (sPaletteColorMapTypes[curPalIndex] == COLOR_MAP_NONE)
// don't blend special palettes immune to blending
if (sPaletteColorMapTypes[curPalIndex] == COLOR_MAP_NONE ||
(curPalIndex >= 16 && IS_BLEND_IMMUNE_TAG(GetSpritePaletteTagByPaletteNum(curPalIndex - 16))))
{
// No palette change.
CpuFastCopy(&gPlttBufferUnfaded[palOffset], &gPlttBufferFaded[palOffset], PLTT_SIZE_4BPP);
palOffset += 16;
}
else
@@ -484,7 +493,7 @@ static void ApplyColorMap(u8 startPalIndex, u8 numPalettes, s8 colorMapIndex)
for (i = 0; i < 16; i++)
{
// Apply color map to the original color.
struct RGBColor baseColor = *(struct RGBColor *)&gPlttBufferUnfaded[palOffset];
struct RGBColor baseColor = *(struct RGBColor *)&gPlttBufferFaded[palOffset];
r = colorMap[baseColor.r];
g = colorMap[baseColor.g];
b = colorMap[baseColor.b];
@@ -525,8 +534,17 @@ static void ApplyColorMap(u8 startPalIndex, u8 numPalettes, s8 colorMapIndex)
}
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
{
CpuFastCopy(&gPlttBufferUnfaded[PLTT_ID(startPalIndex)], &gPlttBufferFaded[PLTT_ID(startPalIndex)], numPalettes * PLTT_SIZE_4BPP);
}
}
}
@@ -547,10 +565,13 @@ static void ApplyColorMapWithBlend(u8 startPalIndex, u8 numPalettes, s8 colorMap
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 (sPaletteColorMapTypes[curPalIndex] == COLOR_MAP_NONE)
{
// No color map. Simply blend the colors.
BlendPalette(palOffset, 16, blendCoeff, blendColor);
BlendPalettesFine(1, gPlttBufferFaded + palOffset, gPlttBufferFaded + palOffset, blendCoeff, blendColor);
palOffset += 16;
}
else
@@ -564,7 +585,7 @@ static void ApplyColorMapWithBlend(u8 startPalIndex, u8 numPalettes, s8 colorMap
for (i = 0; i < 16; i++)
{
struct RGBColor baseColor = *(struct RGBColor *)&gPlttBufferUnfaded[palOffset];
struct RGBColor baseColor = *(struct RGBColor *)&gPlttBufferFaded[palOffset];
u8 r = colorMap[baseColor.r];
u8 g = colorMap[baseColor.g];
u8 b = colorMap[baseColor.b];
@@ -636,51 +657,28 @@ static void ApplyDroughtColorMapWithBlend(s8 colorMapIndex, u8 blendCoeff, u32 b
}
}
// This is only called during fade-in/fade-out in fog
// blendCoeff & blendColor are the *fade* colors, not fog colors
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(BG_PLTT_ID(0), 16 * 16, 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] = RGB2(r, g, b);
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)
@@ -694,7 +692,10 @@ static void MarkFogSpritePalToLighten(u8 paletteIndex)
static bool8 LightenSpritePaletteInFog(u8 paletteIndex)
{
u16 i;
u32 i;
if (paletteIndex >= 16 && IS_BLEND_IMMUNE_TAG(GetSpritePaletteTagByPaletteNum(paletteIndex - 16)))
return FALSE;
for (i = 0; i < gWeatherPtr->lightenedFogSpritePalsCount; i++)
{
@@ -772,8 +773,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_BUFFER_SIZE * 2);
BeginNormalPaletteFade(PALETTES_ALL, delay, 0, 16, fadeColor);
gWeatherPtr->palProcessingState = WEATHER_PAL_STATE_SCREEN_FADING_OUT;
@@ -781,10 +784,20 @@ void FadeScreen(u8 mode, s8 delay)
else
{
gWeatherPtr->fadeDestColor = fadeColor;
UpdateTimeOfDay();
if (useWeatherPal)
gWeatherPtr->fadeScreenCounter = 0;
{
gWeatherPtr->fadeScreenCounter = 0; // Triggers gamma-shift-based fade-in
}
else if (MapHasNaturalLight(gMapHeader.mapType))
{
UpdateAltBgPalettes(PALETTES_BG);
BeginTimeOfDayPaletteFade(PALETTES_ALL, delay, 16, 0, &gTimeBlend.startBlend, &gTimeBlend.endBlend, gTimeBlend.weight, fadeColor);
}
else
{
BeginNormalPaletteFade(PALETTES_ALL, delay, 16, 0, fadeColor);
}
gWeatherPtr->palProcessingState = WEATHER_PAL_STATE_SCREEN_FADING_IN;
gWeatherPtr->fadeInFirstFrame = TRUE;
@@ -794,12 +807,41 @@ 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)
void FadeScreenHardware(u32 mode, s32 delay)
{
u32 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;
}
}
bool8 IsWeatherNotFadingIn(void)
{
return (gWeatherPtr->palProcessingState != WEATHER_PAL_STATE_SCREEN_FADING_IN);
}
void UpdateSpritePaletteWithWeather(u8 spritePaletteIndex)
void UpdateSpritePaletteWithWeather(u8 spritePaletteIndex, bool8 allowFog)
{
u16 paletteIndex = 16 + spritePaletteIndex;
u16 i;
@@ -826,20 +868,37 @@ void UpdateSpritePaletteWithWeather(u8 spritePaletteIndex)
default:
if (gWeatherPtr->currWeather != WEATHER_FOG_HORIZONTAL)
{
ApplyColorMap(paletteIndex, 1, gWeatherPtr->colorMapIndex);
if (gWeatherPtr->colorMapIndex)
ApplyColorMap(paletteIndex, 1, gWeatherPtr->colorMapIndex);
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;
}
}
void ApplyWeatherColorMapToPal(u8 paletteIndex)
void ApplyWeatherColorMapToPals(u8 startPalIndex, u8 numPalettes)
{
ApplyColorMap(paletteIndex, 1, gWeatherPtr->colorMapIndex);
ApplyColorMap(startPalIndex, numPalettes, gWeatherPtr->colorMapIndex);
}
static bool8 UNUSED IsFirstFrameOfWeatherFadeIn(void)
@@ -852,8 +911,11 @@ static bool8 UNUSED IsFirstFrameOfWeatherFadeIn(void)
void LoadCustomWeatherSpritePalette(const u16 *palette)
{
if (gWeatherPtr->weatherPicSpritePalIndex > 16 // haven't allocated palette yet
&& (gWeatherPtr->weatherPicSpritePalIndex = AllocSpritePalette(PALTAG_WEATHER_2)) > 16)
return;
LoadPalette(palette, OBJ_PLTT_ID(gWeatherPtr->weatherPicSpritePalIndex), PLTT_SIZE_4BPP);
UpdateSpritePaletteWithWeather(gWeatherPtr->weatherPicSpritePalIndex);
UpdateSpritePaletteWithWeather(gWeatherPtr->weatherPicSpritePalIndex, TRUE);
}
static void LoadDroughtWeatherPalette(u8 *palsIndex, u8 *palsOffset)
@@ -934,7 +996,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)
@@ -1084,11 +1149,29 @@ void SetWeatherPalStateIdle(void)
gWeatherPtr->palProcessingState = WEATHER_PAL_STATE_IDLE;
}
const u8 *SetPaletteColorMapType(u8 paletteIndex, enum ColorMapType colorMapType)
{
if (sPaletteColorMapTypes[paletteIndex] == colorMapType)
return sPaletteColorMapTypes;
// setup field effect color map
if (sPaletteColorMapTypes != sFieldEffectPaletteColorMapTypes)
{
CpuCopy16(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)
sFieldEffectPaletteColorMapTypes[paletteIndex] = sBasePaletteColorMapTypes[paletteIndex];
}
void ResetPreservedPalettesInWeather(void)

View File

@@ -8,11 +8,13 @@
#include "script.h"
#include "constants/weather.h"
#include "constants/songs.h"
#include "constants/rgb.h"
#include "sound.h"
#include "sprite.h"
#include "task.h"
#include "trig.h"
#include "gpu_regs.h"
#include "palette.h"
EWRAM_DATA static u8 sCurrentAbnormalWeather = 0;
@@ -93,6 +95,7 @@ static const struct SpriteTemplate sCloudSpriteTemplate =
void Clouds_InitVars(void)
{
gWeatherPtr->noShadows = FALSE;
gWeatherPtr->targetColorMapIndex = 0;
gWeatherPtr->colorMapStepDelay = 20;
gWeatherPtr->weatherGfxLoaded = FALSE;
@@ -149,11 +152,14 @@ bool8 Clouds_Finish(void)
return FALSE;
}
STATIC_ASSERT(OW_SHADOW_INTENSITY >= 0 && OW_SHADOW_INTENSITY <= 16, ObjEventShadowTransparencyNotInRange)
void Sunny_InitVars(void)
{
gWeatherPtr->targetColorMapIndex = 0;
gWeatherPtr->colorMapStepDelay = 20;
Weather_SetBlendCoeffs(8, 12);
Weather_SetBlendCoeffs(8, BASE_SHADOW_INTENSITY); // preserve shadow darkness
gWeatherPtr->noShadows = FALSE;
}
void Sunny_InitAll(void)
@@ -237,6 +243,7 @@ void Drought_InitVars(void)
gWeatherPtr->weatherGfxLoaded = FALSE;
gWeatherPtr->targetColorMapIndex = 0;
gWeatherPtr->colorMapStepDelay = 0;
gWeatherPtr->noShadows = FALSE;
}
void Drought_InitAll(void)
@@ -479,6 +486,8 @@ void Rain_InitVars(void)
gWeatherPtr->targetColorMapIndex = 3;
gWeatherPtr->colorMapStepDelay = 20;
SetRainStrengthFromSoundEffect(SE_RAIN);
Weather_SetBlendCoeffs(8, BASE_SHADOW_INTENSITY); // preserve shadow darkness
gWeatherPtr->noShadows = FALSE;
}
void Rain_InitAll(void)
@@ -772,6 +781,8 @@ void Snow_InitVars(void)
gWeatherPtr->colorMapStepDelay = 20;
gWeatherPtr->targetSnowflakeSpriteCount = NUM_SNOWFLAKE_SPRITES;
gWeatherPtr->snowflakeVisibleCounter = 0;
Weather_SetBlendCoeffs(8, BASE_SHADOW_INTENSITY); // preserve shadow darkness
gWeatherPtr->noShadows = FALSE;
}
void Snow_InitAll(void)
@@ -1019,6 +1030,8 @@ void Thunderstorm_InitVars(void)
gWeatherPtr->weatherGfxLoaded = FALSE; // duplicate assignment
gWeatherPtr->thunderEnqueued = FALSE;
SetRainStrengthFromSoundEffect(SE_THUNDERSTORM);
Weather_SetBlendCoeffs(8, BASE_SHADOW_INTENSITY); // preserve shadow darkness
gWeatherPtr->noShadows = FALSE;
}
void Thunderstorm_InitAll(void)
@@ -1047,6 +1060,8 @@ void Downpour_InitVars(void)
gWeatherPtr->colorMapStepDelay = 20;
gWeatherPtr->weatherGfxLoaded = FALSE; // duplicate assignment
SetRainStrengthFromSoundEffect(SE_DOWNPOUR);
Weather_SetBlendCoeffs(8, BASE_SHADOW_INTENSITY); // preserve shadow darkness
gWeatherPtr->noShadows = FALSE;
}
void Downpour_InitAll(void)
@@ -1339,6 +1354,26 @@ void FogHorizontal_Main(void);
static void CreateFogHorizontalSprites(void);
static void DestroyFogHorizontalSprites(void);
// Updates just the color of shadows to match special weather blending
u8 UpdateShadowColor(u16 color)
{
u8 paletteNum = IndexOfSpritePaletteTag(TAG_WEATHER_START);
u16 ALIGNED(4) tempBuffer[16];
u16 blendedColor;
if (paletteNum < 16)
{
u16 index = OBJ_PLTT_ID(paletteNum) + SHADOW_COLOR_INDEX;
gPlttBufferUnfaded[index] = gPlttBufferFaded[index] = color;
// Copy to temporary buffer, blend, and keep just the shadow color index
CpuFastCopy(&gPlttBufferFaded[index - SHADOW_COLOR_INDEX], tempBuffer, PLTT_SIZE_4BPP);
UpdateSpritePaletteWithTime(paletteNum);
blendedColor = gPlttBufferFaded[index];
CpuFastCopy(tempBuffer, &gPlttBufferFaded[index - SHADOW_COLOR_INDEX], PLTT_SIZE_4BPP);
gPlttBufferFaded[index] = blendedColor;
}
return paletteNum;
}
void FogHorizontal_InitVars(void)
{
gWeatherPtr->initStep = 0;
@@ -1352,6 +1387,7 @@ void FogHorizontal_InitVars(void)
gWeatherPtr->fogHScrollPosX = 0;
Weather_SetBlendCoeffs(0, 16);
}
gWeatherPtr->noShadows = FALSE;
}
void FogHorizontal_InitAll(void)
@@ -1374,9 +1410,14 @@ void FogHorizontal_Main(void)
case 0:
CreateFogHorizontalSprites();
if (gWeatherPtr->currWeather == WEATHER_FOG_HORIZONTAL)
{
Weather_SetTargetBlendCoeffs(12, 8, 3);
UpdateShadowColor(RGB_GRAY);
}
else
{
Weather_SetTargetBlendCoeffs(4, 16, 0);
}
gWeatherPtr->initStep++;
break;
case 1:
@@ -1413,6 +1454,7 @@ bool8 FogHorizontal_Finish(void)
gWeatherPtr->finishStep++;
break;
default:
UpdateShadowColor(RGB_BLACK);
return FALSE;
}
return TRUE;
@@ -1503,9 +1545,9 @@ void Ash_InitVars(void)
gWeatherPtr->ashUnused = 20; // Never read
if (!gWeatherPtr->ashSpritesCreated)
{
Weather_SetBlendCoeffs(0, 16);
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(64, 63)); // These aren't valid blend coefficients!
Weather_SetBlendCoeffs(0, BASE_SHADOW_INTENSITY);
}
gWeatherPtr->noShadows = FALSE;
}
void Ash_InitAll(void)
@@ -1531,7 +1573,7 @@ void Ash_Main(void)
if (!gWeatherPtr->ashSpritesCreated)
CreateAshSprites();
Weather_SetTargetBlendCoeffs(16, 0, 1);
Weather_SetTargetBlendCoeffs(10, 12, 1);
gWeatherPtr->initStep++;
break;
case 2:
@@ -1552,7 +1594,7 @@ bool8 Ash_Finish(void)
switch (gWeatherPtr->finishStep)
{
case 0:
Weather_SetTargetBlendCoeffs(0, 16, 1);
Weather_SetTargetBlendCoeffs(0, 12, 1);
gWeatherPtr->finishStep++;
break;
case 1:
@@ -1722,6 +1764,7 @@ void FogDiagonal_InitVars(void)
gWeatherPtr->fogDPosY = 0;
Weather_SetBlendCoeffs(0, 16);
}
gWeatherPtr->noShadows = TRUE;
}
void FogDiagonal_InitAll(void)
@@ -1935,6 +1978,7 @@ void Sandstorm_InitVars(void)
Weather_SetBlendCoeffs(0, 16);
}
gWeatherPtr->noShadows = FALSE;
}
void Sandstorm_InitAll(void)
@@ -1959,7 +2003,8 @@ void Sandstorm_Main(void)
gWeatherPtr->initStep++;
break;
case 1:
Weather_SetTargetBlendCoeffs(16, 0, 0);
Weather_SetTargetBlendCoeffs(16, 2, 0);
UpdateShadowColor(RGB_GRAY);
gWeatherPtr->initStep++;
break;
case 2:
@@ -1985,9 +2030,12 @@ bool8 Sandstorm_Finish(void)
case 1:
if (Weather_UpdateBlend())
gWeatherPtr->finishStep++;
if (gWeatherPtr->currBlendEVB == 12)
UpdateShadowColor(RGB_BLACK);
break;
case 2:
DestroySandstormSprites();
UpdateShadowColor(RGB_BLACK);
gWeatherPtr->finishStep++;
break;
default:
@@ -2221,6 +2269,8 @@ void Shade_InitVars(void)
gWeatherPtr->initStep = 0;
gWeatherPtr->targetColorMapIndex = 3;
gWeatherPtr->colorMapStepDelay = 20;
Weather_SetBlendCoeffs(8, BASE_SHADOW_INTENSITY); // preserve shadow darkness
gWeatherPtr->noShadows = FALSE;
}
void Shade_InitAll(void)
@@ -2282,6 +2332,7 @@ void Bubbles_InitVars(void)
gWeatherPtr->bubblesCoordsIndex = 0;
gWeatherPtr->bubblesSpriteCount = 0;
}
gWeatherPtr->noShadows = TRUE;
}
void Bubbles_InitAll(void)

View File

@@ -877,22 +877,27 @@ static void UNUSED ApplyGlobalTintToPaletteSlot(u8 slot, u8 count)
}
static void LoadTilesetPalette(struct Tileset const *tileset, u16 destOffset, u16 size)
static void LoadTilesetPalette(struct Tileset const *tileset, u16 destOffset, u16 size, bool8 skipFaded)
{
u16 black = RGB_BLACK;
if (tileset)
{
if (tileset->isSecondary == FALSE)
{
LoadPalette(&black, destOffset, PLTT_SIZEOF(1));
LoadPalette(tileset->palettes[0] + 1, destOffset + 1, size - PLTT_SIZEOF(1));
ApplyGlobalTintToPaletteEntries(destOffset + 1, (size - PLTT_SIZEOF(1)) >> 1);
if (skipFaded)
CpuFastCopy(tileset->palettes, &gPlttBufferUnfaded[destOffset], size); // always word-aligned
else
LoadPaletteFast(tileset->palettes, destOffset, size);
gPlttBufferFaded[destOffset] = gPlttBufferUnfaded[destOffset] = RGB_BLACK;
ApplyGlobalTintToPaletteEntries(destOffset + 1, (size - 2) >> 1);
}
else if (tileset->isSecondary == TRUE)
{
LoadPalette(tileset->palettes[NUM_PALS_IN_PRIMARY], destOffset, size);
ApplyGlobalTintToPaletteEntries(destOffset, size >> 1);
// All 'gTilesetPalettes_' arrays should have ALIGNED(4) in them,
// but we use SmartCopy here just in case they don't
if (skipFaded)
CpuCopy16(tileset->palettes[NUM_PALS_IN_PRIMARY], &gPlttBufferUnfaded[destOffset], size);
else
LoadPaletteFast(tileset->palettes[NUM_PALS_IN_PRIMARY], destOffset, size);
}
else
{
@@ -919,12 +924,12 @@ void CopySecondaryTilesetToVramUsingHeap(struct MapLayout const *mapLayout)
static void LoadPrimaryTilesetPalette(struct MapLayout const *mapLayout)
{
LoadTilesetPalette(mapLayout->primaryTileset, BG_PLTT_ID(0), NUM_PALS_IN_PRIMARY * PLTT_SIZE_4BPP);
LoadTilesetPalette(mapLayout->primaryTileset, 0, NUM_PALS_IN_PRIMARY * PLTT_SIZE_4BPP, FALSE);
}
void LoadSecondaryTilesetPalette(struct MapLayout const *mapLayout)
void LoadSecondaryTilesetPalette(struct MapLayout const *mapLayout, bool8 skipFaded)
{
LoadTilesetPalette(mapLayout->secondaryTileset, BG_PLTT_ID(NUM_PALS_IN_PRIMARY), (NUM_PALS_TOTAL - NUM_PALS_IN_PRIMARY) * PLTT_SIZE_4BPP);
LoadTilesetPalette(mapLayout->secondaryTileset, NUM_PALS_IN_PRIMARY * 16, (NUM_PALS_TOTAL - NUM_PALS_IN_PRIMARY) * PLTT_SIZE_4BPP, skipFaded);
}
void CopyMapTilesetsToVram(struct MapLayout const *mapLayout)
@@ -941,6 +946,6 @@ void LoadMapTilesetPalettes(struct MapLayout const *mapLayout)
if (mapLayout)
{
LoadPrimaryTilesetPalette(mapLayout);
LoadSecondaryTilesetPalette(mapLayout);
LoadSecondaryTilesetPalette(mapLayout, FALSE);
}
}

View File

@@ -2,6 +2,8 @@
#include "data.h"
#include "event_scripts.h"
#include "follower_helper.h"
#include "overworld.h"
#include "rtc.h"
#include "constants/battle.h"
#include "constants/followers.h"
#include "constants/metatile_behaviors.h"
@@ -66,6 +68,12 @@ static const u8 sCondMsg40[] = _("{STR_VAR_1} is gnawing at the ice.");
static const u8 sCondMsg41[] = _("{STR_VAR_1} is touching the ice.");
static const u8* const sIceTexts[] = {sCondMsg26, sCondMsg40, sCondMsg41, NULL};
static const u8 sCondMsg42[] = _("{STR_VAR_1}'s burn looks painful!");
static const u8 sCondMsg43[] = _("{STR_VAR_1} is happy to see what's\noutdoors!");
static const u8 sCondMsg44[] = _("{STR_VAR_1} is looking up at the\nsky.");
static const u8* const sDayTexts[] = {sCondMsg43, sCondMsg44, NULL};
static const u8 sCondMsg45[] = _("Your POKéMON is staring spellbound\nat the night sky!");
static const u8 sCondMsg46[] = _("Your POKéMON is happily gazing at\nthe beautiful, starry sky!");
static const u8* const sNightTexts[] = {sCondMsg45, sCondMsg46, NULL};
// See the struct definition in follower_helper.h for more info
const struct FollowerMsgInfoExtended gFollowerConditionalMessages[COND_MSG_COUNT] =
@@ -350,6 +358,26 @@ const struct FollowerMsgInfoExtended gFollowerConditionalMessages[COND_MSG_COUNT
MATCH_STATUS(STATUS1_BURN),
},
},
[COND_MSG_DAY] =
{
.text = (u8*)sDayTexts,
.textSpread = 1,
.emotion = FOLLOWER_EMOTION_MUSIC,
.conditions =
{
MATCH_TIME_OF_DAY(TIME_DAY),
},
},
[COND_MSG_NIGHT] =
{
.text = (u8*)sNightTexts,
.textSpread = 1,
.emotion = FOLLOWER_EMOTION_MUSIC,
.conditions =
{
MATCH_TIME_OF_DAY(TIME_NIGHT),
},
},
};
// Pool of "unconditional" follower messages

View File

@@ -1996,7 +1996,7 @@ const u32 gUnionRoomChat_Keyboard_Gfx[] = INCBIN_U32("graphics/union_room_chat/k
const u32 gUnionRoomChat_Keyboard_Tilemap[] = INCBIN_U32("graphics/union_room_chat/keyboard.bin.lz");
const u32 gUnionRoomChat_RButtonLabels[] = INCBIN_U32("graphics/union_room_chat/r_button_labels.4bpp.lz");
const u16 gTilesetPalettes_General[][16] =
const u16 ALIGNED(4) gTilesetPalettes_General[][16] =
{
INCBIN_U16("data/tilesets/primary/general/palettes/00.gbapal"),
INCBIN_U16("data/tilesets/primary/general/palettes/01.gbapal"),

View File

@@ -41,6 +41,7 @@ enum MapPopUp_Themes_BW
// static functions
static void Task_MapNamePopUpWindow(u8 taskId);
static void UpdateSecondaryPopUpWindow(u8 secondaryPopUpWindowId);
static void ShowMapNamePopUpWindow(void);
static void LoadMapNamePopUpWindowBg(void);
@@ -423,6 +424,7 @@ static void Task_MapNamePopUpWindow(u8 taskId)
break;
case STATE_WAIT:
// Wait while the window is fully onscreen.
UpdateSecondaryPopUpWindow(GetSecondaryPopUpWindowId());
if (++task->tOnscreenTimer > 120)
{
task->tOnscreenTimer = 0;
@@ -500,6 +502,20 @@ void HideMapNamePopUpWindow(void)
}
}
static void UpdateSecondaryPopUpWindow(u8 secondaryPopUpWindowId)
{
u8 mapDisplayHeader[24];
u8 *withoutPrefixPtr = &(mapDisplayHeader[0]);
if (OW_POPUP_BW_TIME_MODE != OW_POPUP_BW_TIME_NONE)
{
RtcCalcLocalTime();
FormatDecimalTimeWithoutSeconds(withoutPrefixPtr, gLocalTime.hours, gLocalTime.minutes, OW_POPUP_BW_TIME_MODE == OW_POPUP_BW_TIME_24_HR);
AddTextPrinterParameterized(secondaryPopUpWindowId, FONT_SMALL, mapDisplayHeader, GetStringRightAlignXOffset(FONT_SMALL, mapDisplayHeader, DISPLAY_WIDTH) - 5, 8, TEXT_SKIP_DRAW, NULL);
}
CopyWindowToVram(secondaryPopUpWindowId, COPYWIN_FULL);
}
static void ShowMapNamePopUpWindow(void)
{
u8 mapDisplayHeader[24];
@@ -550,16 +566,8 @@ static void ShowMapNamePopUpWindow(void)
if (OW_POPUP_GENERATION == GEN_5)
{
AddTextPrinterParameterized(mapNamePopUpWindowId, FONT_SHORT, mapDisplayHeader, 8, 2, TEXT_SKIP_DRAW, NULL);
if (OW_POPUP_BW_TIME_MODE != OW_POPUP_BW_TIME_NONE)
{
RtcCalcLocalTime();
FormatDecimalTimeWithoutSeconds(withoutPrefixPtr, gLocalTime.hours, gLocalTime.minutes, OW_POPUP_BW_TIME_MODE == OW_POPUP_BW_TIME_24_HR);
AddTextPrinterParameterized(secondaryPopUpWindowId, FONT_SMALL, mapDisplayHeader, GetStringRightAlignXOffset(FONT_SMALL, mapDisplayHeader, DISPLAY_WIDTH) - 5, 8, TEXT_SKIP_DRAW, NULL);
}
CopyWindowToVram(mapNamePopUpWindowId, COPYWIN_FULL);
CopyWindowToVram(secondaryPopUpWindowId, COPYWIN_FULL);
UpdateSecondaryPopUpWindow(secondaryPopUpWindowId);
}
else
{

View File

@@ -10,9 +10,11 @@
#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"
#include "field_effect_helpers.h"
#include "field_message_box.h"
#include "field_player_avatar.h"
#include "field_screen_effect.h"
@@ -66,6 +68,7 @@
#include "vs_seeker.h"
#include "frontier_util.h"
#include "constants/abilities.h"
#include "constants/event_objects.h"
#include "constants/layouts.h"
#include "constants/map_types.h"
#include "constants/region_map_sections.h"
@@ -197,6 +200,11 @@ COMMON_DATA bool8 (*gFieldCallback2)(void) = NULL;
COMMON_DATA u8 gLocalLinkPlayerId = 0; // This is our player id in a multiplayer mode.
COMMON_DATA u8 gFieldLinkPlayerCount = 0;
u8 gTimeOfDay;
struct TimeBlendSettings gTimeBlend;
s16 gTimeUpdateCounter; // playTimeVBlanks will eventually overflow, so this is used to update TOD
// EWRAM vars
EWRAM_DATA static u8 sObjectEventLoadFlag = 0;
EWRAM_DATA struct WarpData gLastUsedWarp = {0};
EWRAM_DATA static struct WarpData sWarpDestination = {0}; // new warp position
@@ -206,6 +214,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};
EWRAM_DATA bool8 gExitStairsMovementDisabled = FALSE;
@@ -828,8 +837,6 @@ bool8 SetDiveWarpDive(u16 x, u16 y)
void LoadMapFromCameraTransition(u8 mapGroup, u8 mapNum)
{
s32 paletteIndex;
SetWarpDestination(mapGroup, mapNum, WARP_ID_NONE, -1, -1);
// Dont transition map music between BF Outside West/East
@@ -859,10 +866,9 @@ if (I_VS_SEEKER_CHARGING != 0)
RunOnTransitionMapScript();
InitMap();
CopySecondaryTilesetToVramUsingHeap(gMapHeader.mapLayout);
LoadSecondaryTilesetPalette(gMapHeader.mapLayout);
LoadSecondaryTilesetPalette(gMapHeader.mapLayout, TRUE); // skip copying to Faded, gamma shift will take care of it
for (paletteIndex = NUM_PALS_IN_PRIMARY; paletteIndex < NUM_PALS_TOTAL; paletteIndex++)
ApplyWeatherColorMapToPal(paletteIndex);
ApplyWeatherColorMapToPals(NUM_PALS_IN_PRIMARY, NUM_PALS_TOTAL - NUM_PALS_IN_PRIMARY); // palettes [6,12]
InitSecondaryTilesetAnimation();
UpdateLocationHistoryForRoamer();
@@ -907,6 +913,8 @@ static void LoadMapFromWarp(bool32 a1)
TrySetMapSaveWarpStatus();
ClearTempFieldEventData();
ResetDexNavSearch();
// reset hours override on every warp
sHoursOverride = 0;
ResetCyclingRoadChallengeData();
RestartWildEncounterImmunitySteps();
#if FREE_MATCH_CALL == FALSE
@@ -1535,6 +1543,155 @@ void CB1_Overworld(void)
DoCB1_Overworld(gMain.newKeys, gMain.heldKeys);
}
#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_MORNING] = {.coeff = 4, .blendColor = 0xA8B0E0, .isTint = TRUE},
[TIME_DAY] = {.coeff = 0, .blendColor = 0, .isTint = FALSE},
[TIME_EVENING] = {.coeff = 4, .blendColor = 0xA8B0E0, .isTint = TRUE},
[TIME_NIGHT] = {.coeff = 10, .blendColor = TINT_NIGHT, .isTint = TRUE},
};
#define DEFAULT_WEIGHT 256
#define TIME_BLEND_WEIGHT(begin, end) (DEFAULT_WEIGHT - (DEFAULT_WEIGHT * ((hours - begin) * MINUTES_PER_HOUR + minutes) / ((end - begin) * MINUTES_PER_HOUR)))
#define MORNING_HOUR_MIDDLE (MORNING_HOUR_BEGIN + ((MORNING_HOUR_END - MORNING_HOUR_BEGIN) / 2))
void UpdateTimeOfDay(void)
{
if (!OW_ENABLE_DNS)
return;
s32 hours, minutes;
RtcCalcLocalTime();
hours = sHoursOverride ? sHoursOverride : gLocalTime.hours;
minutes = sHoursOverride ? 0 : gLocalTime.minutes;
if (IsBetweenHours(hours, MORNING_HOUR_BEGIN, MORNING_HOUR_MIDDLE)) // night->morning
{
gTimeBlend.startBlend = gTimeOfDayBlend[TIME_NIGHT];
gTimeBlend.endBlend = gTimeOfDayBlend[TIME_MORNING];
gTimeBlend.weight = TIME_BLEND_WEIGHT(MORNING_HOUR_BEGIN, MORNING_HOUR_MIDDLE);
gTimeBlend.altWeight = (DEFAULT_WEIGHT - gTimeBlend.weight) / 2;
gTimeOfDay = TIME_MORNING;
}
else if (IsBetweenHours(hours, MORNING_HOUR_MIDDLE, MORNING_HOUR_END)) // morning->day
{
gTimeBlend.startBlend = gTimeOfDayBlend[TIME_MORNING];
gTimeBlend.endBlend = gTimeOfDayBlend[TIME_DAY];
gTimeBlend.weight = TIME_BLEND_WEIGHT(MORNING_HOUR_MIDDLE, MORNING_HOUR_END);
gTimeBlend.altWeight = (DEFAULT_WEIGHT - gTimeBlend.weight) / 2 + (DEFAULT_WEIGHT / 2);
gTimeOfDay = TIME_MORNING;
}
else if (IsBetweenHours(hours, EVENING_HOUR_BEGIN, EVENING_HOUR_END)) // evening
{
gTimeBlend.startBlend = gTimeOfDayBlend[TIME_DAY];
gTimeBlend.endBlend = gTimeOfDayBlend[TIME_EVENING];
gTimeBlend.weight = TIME_BLEND_WEIGHT(EVENING_HOUR_BEGIN, EVENING_HOUR_END);
gTimeBlend.altWeight = gTimeBlend.weight / 2 + (DEFAULT_WEIGHT / 2);
gTimeOfDay = TIME_EVENING;
}
else if (IsBetweenHours(hours, NIGHT_HOUR_BEGIN, NIGHT_HOUR_BEGIN + 1)) // evening->night
{
gTimeBlend.startBlend = gTimeOfDayBlend[TIME_EVENING];
gTimeBlend.endBlend = gTimeOfDayBlend[TIME_NIGHT];
gTimeBlend.weight = TIME_BLEND_WEIGHT(NIGHT_HOUR_BEGIN, NIGHT_HOUR_BEGIN + 1);
gTimeBlend.altWeight = gTimeBlend.weight / 2;
gTimeOfDay = TIME_NIGHT;
}
else if (IsBetweenHours(hours, NIGHT_HOUR_BEGIN, NIGHT_HOUR_END)) // night
{
gTimeBlend.weight = DEFAULT_WEIGHT;
gTimeBlend.altWeight = 0;
gTimeBlend.startBlend = gTimeBlend.endBlend = gTimeOfDayBlend[TIME_NIGHT];
gTimeOfDay = TIME_NIGHT;
}
else // day
{
gTimeBlend.weight = gTimeBlend.altWeight = DEFAULT_WEIGHT;
gTimeBlend.startBlend = gTimeBlend.endBlend = gTimeOfDayBlend[TIME_DAY];
gTimeOfDay = TIME_DAY;
}
}
#undef MORNING_HOUR_MIDDLE
#undef TIME_BLEND_WEIGHT
#undef DEFAULT_WEIGHT
// Whether a map type is naturally lit/outside
bool32 MapHasNaturalLight(u8 mapType)
{
return (mapType == MAP_TYPE_TOWN
|| mapType == MAP_TYPE_CITY
|| mapType == MAP_TYPE_ROUTE
|| mapType == MAP_TYPE_OCEAN_ROUTE);
}
bool32 CurrentMapHasShadows(void)
{
// Add all conditionals here for maps that shouldn't have shadows
// By default only cave maps are excluded from having shadows under object events
return (gMapHeader.mapType != MAP_TYPE_UNDERGROUND);
}
// Update & mix day / night bg palettes (into unfaded)
void UpdateAltBgPalettes(u16 palettes)
{
if (!OW_ENABLE_DNS)
return;
const struct Tileset *primary = gMapHeader.mapLayout->primaryTileset;
const struct Tileset *secondary = gMapHeader.mapLayout->secondaryTileset;
u32 i = 1;
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, gTimeBlend.altWeight);
else
AvgPaletteWeighted(&((u16 *)secondary->palettes)[i * 16], &((u16 *)secondary->palettes)[((i + 9) % 16) * 16], gPlttBufferUnfaded + i * 16, gTimeBlend.altWeight);
}
i++;
palettes >>= 1;
}
}
void UpdatePalettesWithTime(u32 palettes)
{
if (!OW_ENABLE_DNS || !MapHasNaturalLight(gMapHeader.mapType))
return;
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, &gTimeBlend.startBlend, &gTimeBlend.endBlend, gTimeBlend.weight);
}
u8 UpdateSpritePaletteWithTime(u8 paletteNum)
{
if (OW_ENABLE_DNS
&& MapHasNaturalLight(gMapHeader.mapType)
&& !IS_BLEND_IMMUNE_TAG(GetSpritePaletteTagByPaletteNum(paletteNum)))
TimeMixPalettes(1, &gPlttBufferUnfaded[OBJ_PLTT_ID(paletteNum)], &gPlttBufferFaded[OBJ_PLTT_ID(paletteNum)], &gTimeBlend.startBlend, &gTimeBlend.endBlend, gTimeBlend.weight);
return paletteNum;
}
static void OverworldBasic(void)
{
ScriptContext_RunScript();
@@ -1546,6 +1703,23 @@ static void OverworldBasic(void)
UpdatePaletteFade();
UpdateTilesetAnimations();
DoScheduledBgTilemapCopiesToVram();
// Every minute if no palette fade is active, update TOD blending as needed
if (!gPaletteFade.active && --gTimeUpdateCounter <= 0)
{
struct TimeBlendSettings cachedBlend = gTimeBlend;
u32 *bld0 = (u32*)&cachedBlend;
u32 *bld1 = (u32*)&gTimeBlend;
gTimeUpdateCounter = (SECONDS_PER_MINUTE * 60 / FakeRtc_GetSecondsRatio());
UpdateTimeOfDay();
FormChangeTimeUpdate();
if (bld0[0] != bld1[0]
|| bld0[1] != bld1[1]
|| bld0[2] != bld1[2])
{
UpdateAltBgPalettes(PALETTES_BG);
UpdatePalettesWithTime(PALETTES_ALL);
}
}
}
// This CB2 is used when starting
@@ -3283,6 +3457,8 @@ static void CreateLinkPlayerSprite(u8 linkPlayerId, u8 gameVersion)
sprite->coordOffsetEnabled = TRUE;
sprite->data[0] = linkPlayerId;
objEvent->triggerGroundEffectsOnMove = FALSE;
objEvent->localId = OBJ_EVENT_ID_DYNAMIC_BASE + linkPlayerId;
SetUpShadow(objEvent);
}
}
@@ -3516,3 +3692,17 @@ void ScriptHideItemDescription(struct ScriptContext *ctx)
#endif // OW_SHOW_ITEM_DESCRIPTIONS
// 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

@@ -13,11 +13,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);
@@ -53,6 +55,16 @@ void LoadPalette(const void *src, u32 offset, u32 size)
CpuCopy16(src, &gPlttBufferFaded[offset], size);
}
// Drop in replacement for LoadPalette, uses CpuFastCopy, size must be 0 % 32
void LoadPaletteFast(const void *src, u32 offset, u32 size)
{
if ((u32)src & 3) // In case palette is not 4 byte aligned
return LoadPalette(src, offset, size);
CpuFastCopy(src, &gPlttBufferUnfaded[offset], size);
// Copying from EWRAM->EWRAM is faster than ROM->EWRAM
CpuFastCopy(&gPlttBufferUnfaded[offset], &gPlttBufferFaded[offset], size);
}
void FillPalette(u32 value, u32 offset, u32 size)
{
CpuFill16(value, &gPlttBufferUnfaded[offset], size);
@@ -83,6 +95,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();
@@ -114,9 +128,9 @@ bool32 BeginNormalPaletteFade(u32 selectedPalettes, s8 delay, u8 startY, u8 targ
delay = 0;
}
gPaletteFade_selectedPalettes = selectedPalettes;
gPaletteFadeSelectedPalettes = selectedPalettes;
gPaletteFade.delayCounter = delay;
gPaletteFade_delay = delay;
gPaletteFadeDelay = delay;
gPaletteFade.y = startY;
gPaletteFade.targetY = targetY;
gPaletteFade.blendColor = blendColor;
@@ -141,6 +155,52 @@ 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;
gPaletteFade.deltaY = 2;
if (delay < 0)
{
gPaletteFade.deltaY += (delay * -1);
delay = 0;
}
gPaletteFadeSelectedPalettes = selectedPalettes;
gPaletteFade.delayCounter = delay;
gPaletteFadeDelay = 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;
@@ -161,6 +221,117 @@ 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 < gPaletteFadeDelay)
{
gPaletteFade.delayCounter++;
return PALETTE_FADE_STATUS_DELAY;
}
gPaletteFade.delayCounter = 0;
}
paletteOffset = 0;
if (!gPaletteFade.objPaletteToggle)
{
selectedPalettes = gPaletteFadeSelectedPalettes;
}
else
{
selectedPalettes = gPaletteFadeSelectedPalettes >> 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))
{
gPaletteFadeSelectedPalettes = 0;
gPaletteFade.softwareFadeFinishing = 1;
}
else
{
s8 val;
if (!gPaletteFade.yDec)
{
val = gPaletteFade.y + gPaletteFade.deltaY;
if (val > gPaletteFade.targetY)
val = gPaletteFade.targetY;
gPaletteFade.y = val;
}
else
{
val = gPaletteFade.y - 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;
@@ -177,10 +348,10 @@ static u32 UpdateNormalPaletteFade(void)
{
if (!gPaletteFade.objPaletteToggle)
{
if (gPaletteFade.delayCounter < gPaletteFade_delay)
if (gPaletteFade.delayCounter < gPaletteFadeDelay)
{
gPaletteFade.delayCounter++;
return 2;
return PALETTE_FADE_STATUS_DELAY;
}
gPaletteFade.delayCounter = 0;
}
@@ -189,11 +360,11 @@ static u32 UpdateNormalPaletteFade(void)
if (!gPaletteFade.objPaletteToggle)
{
selectedPalettes = gPaletteFade_selectedPalettes;
selectedPalettes = gPaletteFadeSelectedPalettes;
}
else
{
selectedPalettes = gPaletteFade_selectedPalettes >> 16;
selectedPalettes = gPaletteFadeSelectedPalettes >> 16;
paletteOffset = OBJ_PLTT_OFFSET;
}
@@ -215,7 +386,7 @@ static u32 UpdateNormalPaletteFade(void)
{
if (gPaletteFade.y == gPaletteFade.targetY)
{
gPaletteFade_selectedPalettes = 0;
gPaletteFadeSelectedPalettes = 0;
gPaletteFade.softwareFadeFinishing = TRUE;
}
else
@@ -312,7 +483,7 @@ void BeginFastPaletteFade(u32 submode)
static void BeginFastPaletteFadeInternal(u32 submode)
{
gPaletteFade.y = 31;
gPaletteFade_submode = submode & 0x3F;
gPaletteFadeSubmode = submode & 0x3F;
gPaletteFade.active = TRUE;
gPaletteFade.mode = FAST_FADE;
@@ -355,7 +526,7 @@ static u32 UpdateFastPaletteFade(void)
paletteOffsetEnd = OBJ_PLTT_OFFSET;
}
switch (gPaletteFade_submode)
switch (gPaletteFadeSubmode)
{
case FAST_FADE_IN_FROM_WHITE:
for (i = paletteOffsetStart; i < paletteOffsetEnd; i++)
@@ -460,7 +631,7 @@ static u32 UpdateFastPaletteFade(void)
if (gPaletteFade.y == 0)
{
switch (gPaletteFade_submode)
switch (gPaletteFadeSubmode)
{
case FAST_FADE_IN_FROM_WHITE:
case FAST_FADE_IN_FROM_BLACK:
@@ -485,9 +656,9 @@ static u32 UpdateFastPaletteFade(void)
void BeginHardwarePaletteFade(u32 blendCnt, u32 delay, u32 y, u32 targetY, u32 shouldResetBlendRegisters)
{
gPaletteFade_blendCnt = blendCnt;
gPaletteFadeBlendCnt = blendCnt;
gPaletteFade.delayCounter = delay;
gPaletteFade_delay = delay;
gPaletteFadeDelay = delay;
gPaletteFade.y = y;
gPaletteFade.targetY = targetY;
gPaletteFade.active = TRUE;
@@ -506,7 +677,7 @@ static u32 UpdateHardwarePaletteFade(void)
if (!gPaletteFade.active)
return PALETTE_FADE_STATUS_DONE;
if (gPaletteFade.delayCounter < gPaletteFade_delay)
if (gPaletteFade.delayCounter < gPaletteFadeDelay)
{
gPaletteFade.delayCounter++;
return PALETTE_FADE_STATUS_DELAY;
@@ -537,7 +708,8 @@ static u32 UpdateHardwarePaletteFade(void)
{
if (gPaletteFade.shouldResetBlendRegisters)
{
gPaletteFade_blendCnt = 0;
// clear TGT1
gPaletteFadeBlendCnt &= ~0xFF;
gPaletteFade.y = 0;
}
gPaletteFade.shouldResetBlendRegisters = FALSE;
@@ -548,15 +720,48 @@ static u32 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_BLDCNT, (u16)gPaletteFadeBlendCnt);
SetGpuReg(REG_OFFSET_BLDY, gPaletteFade.y);
// If fade-out, also adjust BLDALPHA and DISPCNT
if (!gPaletteFade.yDec)
{
u16 bldAlpha = GetGpuReg(REG_OFFSET_BLDALPHA);
u8 tgt1 = BLDALPHA_TGT1(bldAlpha);
u8 tgt2 = BLDALPHA_TGT2(bldAlpha);
u8 bldFade;
switch (gPaletteFadeBlendCnt & 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;
gPaletteFade.mode = 0;
gPaletteFade_blendCnt = 0;
gPaletteFadeBlendCnt = 0;
gPaletteFade.y = 0;
gPaletteFade.active = FALSE;
}
@@ -585,15 +790,285 @@ 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;
BlendPalettesFine(selectedPalettes, gPlttBufferUnfaded, gPlttBufferFaded, coeff, color);
}
for (paletteOffset = 0; selectedPalettes; paletteOffset += 16)
#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
{
if (selectedPalettes & 1)
BlendPalette(paletteOffset, 16, coeff, color);
selectedPalettes >>= 1;
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 ? 16 : blend0->coeff * 2;
color1 = blend1->blendColor;
tint1 = blend1->isTint;
coeff1 = tint1 ? 16 : 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++;
}
}
@@ -696,6 +1171,79 @@ void TintPalette_CustomTone(u16 *palette, u32 count, u16 rTone, u16 gTone, u16 b
}
}
// Tints from Unfaded to Faded, using a 15-bit GBA color
void TintPalette_RGB_Copy(u16 palOffset, u32 blendColor)
{
s32 newR, newG, newB, rTone = 0, gTone = 0, bTone = 0;
u16 *src = gPlttBufferUnfaded + palOffset;
u16 *dst = gPlttBufferFaded + palOffset;
u32 defaultBlendColor = DEFAULT_LIGHT_COLOR;
u16 *srcEnd = src + 16;
u16 altBlendIndices = *dst++ = *src++; // color 0 is copied through unchanged
u32 altBlendColor;
newR = ((blendColor << 27) >> 27) << 3;
newG = ((blendColor << 22) >> 27) << 3;
newB = ((blendColor << 17) >> 27) << 3;
if (altBlendIndices >> 15) // High bit set; bitmask of which colors to alt-blend
{
// Note that bit 0 of altBlendIndices specifies color 1
altBlendColor = src[14]; // color 15
if (altBlendColor >> 15)
{
// Set alternate blend color
rTone = ((altBlendColor << 27) >> 27) << 3;
gTone = ((altBlendColor << 22) >> 27) << 3;
bTone = ((altBlendColor << 17) >> 27) << 3;
}
else
{
// Set default blend color
rTone = ((defaultBlendColor << 27) >> 27) << 3;
gTone = ((defaultBlendColor << 22) >> 27) << 3;
bTone = ((defaultBlendColor << 17) >> 27) << 3;
}
}
else
{
altBlendIndices = 0;
}
while (src != srcEnd)
{
u32 srcColor = *src;
s32 r = (srcColor << 27) >> 27;
s32 g = (srcColor << 22) >> 27;
s32 b = (srcColor << 17) >> 27;
if (altBlendIndices & 1)
{
r = (u16)((rTone * r)) >> 8;
g = (u16)((gTone * g)) >> 8;
b = (u16)((bTone * b)) >> 8;
}
else
{
// Use provided blend color
r = (u16)((newR * r)) >> 8;
g = (u16)((newG * g)) >> 8;
b = (u16)((newB * b)) >> 8;
}
if (r > 31)
r = 31;
if (g > 31)
g = 31;
if (b > 31)
b = 31;
src++;
*dst++ = RGB2(r, g, b);
altBlendIndices >>= 1;
}
}
#undef DEFAULT_LIGHT_COLOR
#define tCoeff data[0]
#define tCoeffTarget data[1]
#define tCoeffDelta data[2]

View File

@@ -2,6 +2,7 @@
#include "palette.h"
#include "palette_util.h"
#include "util.h"
#include "overworld.h"
// "RouletteFlash" is more accurately a general flashing/fading util
// this file handles fading the palettes for the color/icon selections on the Roulette wheel
@@ -384,7 +385,11 @@ void UpdatePulseBlend(struct PulseBlend *pulseBlend)
if (--pulseBlendPalette->delayCounter == 0xFF)
{
pulseBlendPalette->delayCounter = pulseBlendPalette->pulseBlendSettings.delay;
BlendPalette(pulseBlendPalette->pulseBlendSettings.paletteOffset, pulseBlendPalette->pulseBlendSettings.numColors, pulseBlendPalette->blendCoeff, pulseBlendPalette->pulseBlendSettings.blendColor);
CpuFastCopy(gPlttBufferUnfaded + pulseBlendPalette->pulseBlendSettings.paletteOffset, gPlttBufferFaded + pulseBlendPalette->pulseBlendSettings.paletteOffset, PLTT_SIZE_4BPP);
UpdatePalettesWithTime(1 << (pulseBlendPalette->pulseBlendSettings.paletteOffset >> 4));
// pulseBlendSettings has a numColors field, but it is only ever set to 16 (for Mirage Tower)
// So, it's ok to use the fine blending here which blends the entire palette
BlendPalettesFine(1, gPlttBufferFaded + pulseBlendPalette->pulseBlendSettings.paletteOffset, gPlttBufferFaded + pulseBlendPalette->pulseBlendSettings.paletteOffset, pulseBlendPalette->blendCoeff, pulseBlendPalette->pulseBlendSettings.blendColor);
switch (pulseBlendPalette->pulseBlendSettings.fadeType)
{
case 0: // Fade all the way to the max blend amount, then wrap around

View File

@@ -741,7 +741,7 @@ static u8 RotatingGate_CreateGate(u8 gateId, s16 deltaX, s16 deltaY)
template.tileTag = gate->shape + ROTATING_GATE_TILE_TAG;
spriteId = CreateSprite(&template, 0, 0, 0x93);
spriteId = CreateSprite(&template, 0, 0, OW_OBJECT_SUBPRIORITY - 1); // Above shadows
if (spriteId == MAX_SPRITES)
return MAX_SPRITES;

View File

@@ -6,6 +6,7 @@
#include "strings.h"
#include "text.h"
#include "fake_rtc.h"
#include "overworld.h"
// iwram bss
static u16 sErrorStatus;
@@ -329,14 +330,8 @@ bool8 IsBetweenHours(s32 hours, s32 begin, s32 end)
enum TimeOfDay GetTimeOfDay(void)
{
RtcCalcLocalTime();
if (IsBetweenHours(gLocalTime.hours, MORNING_HOUR_BEGIN, MORNING_HOUR_END))
return TIME_MORNING;
else if (IsBetweenHours(gLocalTime.hours, EVENING_HOUR_BEGIN, EVENING_HOUR_END))
return TIME_EVENING;
else if (IsBetweenHours(gLocalTime.hours, NIGHT_HOUR_BEGIN, NIGHT_HOUR_END))
return TIME_NIGHT;
return TIME_DAY;
UpdateTimeOfDay();
return gTimeOfDay;
}
enum TimeOfDay GetTimeOfDayForDex(void)

View File

@@ -24,6 +24,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"
@@ -795,6 +796,13 @@ static bool8 IsPaletteNotActive(void)
return FALSE;
}
// pauses script until palette fade inactive
bool8 ScrFunc_WaitPaletteNotActive(struct ScriptContext *ctx)
{
SetupNativeScript(ctx, IsPaletteNotActive);
return TRUE;
}
bool8 ScrCmd_fadescreen(struct ScriptContext *ctx)
{
u32 mode = ScriptReadByte(ctx);
@@ -818,37 +826,28 @@ bool8 ScrCmd_fadescreenspeed(struct ScriptContext *ctx)
return TRUE;
}
static EWRAM_DATA u32 *sPalBuffer = NULL;
bool8 ScrCmd_fadescreenswapbuffers(struct ScriptContext *ctx)
{
u8 mode = ScriptReadByte(ctx);
u8 nowait = ScriptReadByte(ctx);
Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE);
switch (mode)
{
case FADE_TO_BLACK:
case FADE_TO_WHITE:
default:
if (sPalBuffer == NULL)
{
sPalBuffer = Alloc(PLTT_SIZE);
CpuCopy32(gPlttBufferUnfaded, sPalBuffer, PLTT_SIZE);
FadeScreen(mode, 0);
}
break;
case FADE_FROM_BLACK:
case FADE_FROM_WHITE:
if (sPalBuffer != NULL)
{
CpuCopy32(sPalBuffer, gPlttBufferUnfaded, PLTT_SIZE);
FadeScreen(mode, 0);
FREE_AND_SET_NULL(sPalBuffer);
}
// 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);
return TRUE;
}

View File

@@ -42,7 +42,7 @@
#include "constants/songs.h"
#define TAG_SCROLL_ARROW 2100
#define TAG_ITEM_ICON_BASE 2110
#define TAG_ITEM_ICON_BASE 9110 // immune to time blending
#define MAX_ITEMS_SHOWN 8

View File

@@ -1603,9 +1603,17 @@ void LoadSpritePalettes(const struct SpritePalette *palettes)
break;
}
u8 LoadSpritePaletteInSlot(const struct SpritePalette *palette, u8 paletteNum)
{
paletteNum = min(15, paletteNum);
sSpritePaletteTags[paletteNum] = palette->tag;
DoLoadSpritePalette(palette->data, paletteNum * 16);
return paletteNum;
}
void DoLoadSpritePalette(const u16 *src, u16 paletteOffset)
{
LoadPalette(src, OBJ_PLTT_OFFSET + paletteOffset, PLTT_SIZE_4BPP);
LoadPaletteFast(src, OBJ_PLTT_OFFSET + paletteOffset, PLTT_SIZE_4BPP);
}
u32 AllocSpritePalette(u16 tag)

View File

@@ -228,6 +228,7 @@ u32 CalcByteArraySum(const u8 *data, u32 length)
void BlendPalette(u16 palOffset, u16 numEntries, u8 coeff, u32 blendColor)
{
u16 i;
struct PlttData *data2 = (struct PlttData *) & blendColor;
for (i = 0; i < numEntries; i++)
{
u16 index = i + palOffset;
@@ -235,7 +236,7 @@ void BlendPalette(u16 palOffset, u16 numEntries, u8 coeff, u32 blendColor)
s8 r = data1->r;
s8 g = data1->g;
s8 b = data1->b;
struct PlttData *data2 = (struct PlttData *)&blendColor;
gPlttBufferFaded[index] = RGB(r + (((data2->r - r) * coeff) >> 4),
g + (((data2->g - g) * coeff) >> 4),
b + (((data2->b - b) * coeff) >> 4));

View File

@@ -14,6 +14,7 @@
#define GET_GBA_PAL_BLUE(x) (((x) >> 10) & 0x1F)
#define SET_GBA_PAL(r, g, b) (((b) << 10) | ((g) << 5) | (r))
#define SET_GBA_PAL_RGBA(r, g, b, a) (((a) << 15) | ((b) << 10) | ((g) << 5) | (r))
#define UPCONVERT_BIT_DEPTH(x) (((x) * 255) / 31)
@@ -578,8 +579,9 @@ void WriteGbaPalette(char *path, struct Palette *palette)
unsigned char red = DOWNCONVERT_BIT_DEPTH(palette->colors[i].red);
unsigned char green = DOWNCONVERT_BIT_DEPTH(palette->colors[i].green);
unsigned char blue = DOWNCONVERT_BIT_DEPTH(palette->colors[i].blue);
bool alpha = palette->colors[i].alpha;
uint16_t paletteEntry = SET_GBA_PAL(red, green, blue);
uint16_t paletteEntry = SET_GBA_PAL_RGBA(red, green, blue, alpha);
fputc(paletteEntry & 0xFF, fp);
fputc(paletteEntry >> 8, fp);

View File

@@ -10,6 +10,7 @@ struct Color {
unsigned char red;
unsigned char green;
unsigned char blue;
bool alpha;
};
struct Palette {

View File

@@ -22,7 +22,7 @@
// Blue - "0 0 255\r\n"
// Brown - "150 75 0\r\n"
#define MAX_LINE_LENGTH 11
#define MAX_LINE_LENGTH 64
void ReadJascPaletteLine(FILE *fp, char *line)
{
@@ -156,6 +156,42 @@ void ReadJascPalette(char *path, struct Palette *palette)
FATAL_ERROR("Garbage after color data.\n");
fclose(fp);
// Try to parse alpha/high bit info for colors from auxiliary .pla file
char *dot = strrchr(path, '.');
if (strcmp(dot, ".pal") != 0)
return;
strcpy(dot, ".pla"); // replace .pal with .pla
fp = fopen(path, "rb");
if (fp == NULL)
return;
int i = 0;
// Keep reading lines until number of colors is reached or we run out
while (i < palette->numColors && fgets(line, MAX_LINE_LENGTH, fp) != NULL)
{
if (line[0] == '#') // comment line; ignore
continue;
char *s = line;
char *end;
int colorIndex;
if (!ParseNumber(s, &end, 10, &colorIndex))
FATAL_ERROR("Failed to parse aux color index.\n");
s = end;
if (colorIndex >= palette->numColors)
FATAL_ERROR("Aux color index %d out of bounds.\n", colorIndex);
palette->colors[colorIndex].alpha = 1; // set alpha color
// fprintf(stderr, "Color index: %d\n", colorIndex);
i++;
}
fclose(fp);
}
void WriteJascPalette(char *path, struct Palette *palette)

View File

@@ -291,7 +291,7 @@ void HandlePngToGbaCommand(char *inputPath, char *outputPath, int argc, char **a
void HandlePngToJascPaletteCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
{
struct Palette palette = {};
struct Palette palette = {0};
ReadPngPalette(inputPath, &palette);
WriteJascPalette(outputPath, &palette);
@@ -299,7 +299,7 @@ void HandlePngToJascPaletteCommand(char *inputPath, char *outputPath, int argc U
void HandlePngToGbaPaletteCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
{
struct Palette palette = {};
struct Palette palette = {0};
ReadPngPalette(inputPath, &palette);
WriteGbaPalette(outputPath, &palette);
@@ -307,7 +307,7 @@ void HandlePngToGbaPaletteCommand(char *inputPath, char *outputPath, int argc UN
void HandleGbaToJascPaletteCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
{
struct Palette palette = {};
struct Palette palette = {0};
ReadGbaPalette(inputPath, &palette);
WriteJascPalette(outputPath, &palette);
@@ -340,7 +340,7 @@ void HandleJascToGbaPaletteCommand(char *inputPath, char *outputPath, int argc,
}
}
struct Palette palette = {};
struct Palette palette = {0};
ReadJascPalette(inputPath, &palette);