Merge remote-tracking branch '_merrp_origin/lighting-expanded-id' into _RHH/pr/upcoming/lighting-expansion-v2
# Conflicts: # README.md # asm/macros/event.inc # data/scripts/pkmn_center_nurse.inc # include/constants/event_objects.h # include/constants/field_weather.h # include/overworld.h # include/palette.h # include/sprite.h # src/battle_controller_player.c # src/data/object_events/object_event_graphics.h # src/event_object_movement.c # src/field_effect_helpers.c # src/field_weather.c # src/overworld.c # src/palette.c # src/scrcmd.c # src/sprite.c
This commit is contained in:
commit
00241cf569
@ -1823,9 +1823,10 @@
|
||||
.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.
|
||||
@ If nowait set, does not wait for the fade to complete
|
||||
@ Equivalent to fadescreen but uses a hardware fade and darken/lighten blend modes,
|
||||
@ to avoid modifying palettes at all.
|
||||
@ Useful for fade-out/fade-in without leaving the overworld or entering a new scene.
|
||||
@ If nowait set, doesn't wait for the fade to complete
|
||||
.macro fadescreenswapbuffers mode:req, nowait=0
|
||||
.byte SCR_OP_FADESCREENSWAPBUFFERS
|
||||
.byte \mode
|
||||
@ -2539,3 +2540,11 @@
|
||||
compare \a, \b
|
||||
cant_see_if 5
|
||||
.endm
|
||||
|
||||
@ hide any follower pokemon if present,
|
||||
@ putting them into their pokeball;
|
||||
@ by default waits for their movement to finish
|
||||
.macro hidefollower wait=1
|
||||
callfunc ScrFunc_hidefollower
|
||||
.2byte \wait
|
||||
.endm
|
||||
|
||||
@ -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
|
||||
|
||||
@ -118,7 +118,6 @@ EventScript_FollowerSwap:
|
||||
return
|
||||
|
||||
EventScript_FollowerMoveNorth:
|
||||
applymovement OBJ_EVENT_ID_FOLLOWER, Movement_WalkUp
|
||||
applymovement OBJ_EVENT_ID_PLAYER, Movement_WalkDown
|
||||
waitmovement 0
|
||||
applymovement OBJ_EVENT_ID_PLAYER, Common_Movement_FaceUp
|
||||
@ -126,7 +125,6 @@ EventScript_FollowerMoveNorth:
|
||||
return
|
||||
|
||||
EventScript_FollowerMoveEast:
|
||||
applymovement OBJ_EVENT_ID_FOLLOWER, Movement_WalkRight
|
||||
applymovement OBJ_EVENT_ID_PLAYER, Movement_WalkLeft
|
||||
waitmovement 0
|
||||
applymovement OBJ_EVENT_ID_PLAYER, Common_Movement_FaceRight
|
||||
@ -134,7 +132,6 @@ EventScript_FollowerMoveEast:
|
||||
return
|
||||
|
||||
EventScript_FollowerMoveSouth:
|
||||
applymovement OBJ_EVENT_ID_FOLLOWER, Movement_WalkDown
|
||||
applymovement OBJ_EVENT_ID_PLAYER, Movement_WalkUp
|
||||
waitmovement 0
|
||||
applymovement OBJ_EVENT_ID_PLAYER, Common_Movement_FaceDown
|
||||
@ -142,7 +139,6 @@ EventScript_FollowerMoveSouth:
|
||||
return
|
||||
|
||||
EventScript_FollowerMoveWest:
|
||||
applymovement OBJ_EVENT_ID_FOLLOWER, Movement_WalkLeft
|
||||
applymovement OBJ_EVENT_ID_PLAYER, Movement_WalkRight
|
||||
waitmovement 0
|
||||
applymovement OBJ_EVENT_ID_PLAYER, Common_Movement_FaceLeft
|
||||
|
||||
@ -33,6 +33,7 @@ EventScript_PkmnCenterNurse_IllTakeYourPkmn2::
|
||||
return
|
||||
|
||||
EventScript_PkmnCenterNurse_TakeAndHealPkmn::
|
||||
hidefollower 0
|
||||
applymovement VAR_0x800B, Movement_PkmnCenterNurse_Turn @ Changed from Common_Movement_WalkInPlaceFasterLeft to force the follower to enter their Poké Ball
|
||||
waitmovement 0
|
||||
dofieldeffect FLDEFF_POKECENTER_HEAL
|
||||
|
||||
@ -8,11 +8,13 @@ Std_MsgboxNPC:
|
||||
return
|
||||
|
||||
Std_MsgboxSign:
|
||||
setflag FLAG_SAFE_FOLLOWER_MOVEMENT
|
||||
lockall
|
||||
message NULL
|
||||
waitmessage
|
||||
waitbuttonpress
|
||||
releaseall
|
||||
clearflag FLAG_SAFE_FOLLOWER_MOVEMENT
|
||||
return
|
||||
|
||||
Std_MsgboxDefault:
|
||||
|
||||
@ -60,6 +60,33 @@
|
||||
#define OW_FOLLOWERS_WEATHER_FORMS FALSE // If TRUE, Castform and Cherrim gain FORM_CHANGE_OVERWORLD_WEATHER, which will make them transform in the overworld based on the weather.
|
||||
#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.
|
||||
|
||||
// New/old handling for followers during scripts;
|
||||
// TRUE: Script collisions hide follower, FLAG_SAFE_FOLLOWER_MOVEMENT on by default
|
||||
// (scripted player movement moves follower too!)
|
||||
// FALSE: Script collisions unhandled, FLAG_SAFE_FOLLOWER_MOVEMENT off by default
|
||||
#define OW_MON_SCRIPT_MOVEMENT TRUE
|
||||
|
||||
// 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)
|
||||
|
||||
// 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.
|
||||
// In USUM (here GEN_7), if a Pokémon with Synchronize leads the party, gift Pokémon will always have their same Nature regardless of their Egg Group.
|
||||
|
||||
@ -3,6 +3,14 @@
|
||||
|
||||
#include "config/overworld.h"
|
||||
|
||||
// sPaletteColorMapTypes & field_effect_scripts
|
||||
enum
|
||||
{
|
||||
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
|
||||
|
||||
@ -1647,7 +1647,9 @@
|
||||
#define FLAG_ENABLE_MULTI_CORRIDOR_DOOR (SPECIAL_FLAGS_START + 0x2)
|
||||
#define FLAG_SPECIAL_FLAG_UNUSED_0x4003 (SPECIAL_FLAGS_START + 0x3) // Unused Flag
|
||||
#define FLAG_STORING_ITEMS_IN_PYRAMID_BAG (SPECIAL_FLAGS_START + 0x4)
|
||||
#define FLAG_SAFE_FOLLOWER_MOVEMENT (SPECIAL_FLAGS_START + 0x5) // When set, applymovement does not put the follower inside a pokeball
|
||||
// When set, `applymovement` does not hide follower pokemon;
|
||||
// Also, scripted movements on the player will move follower(s), too
|
||||
#define FLAG_SAFE_FOLLOWER_MOVEMENT (SPECIAL_FLAGS_START + 0x5)
|
||||
// FLAG_SPECIAL_FLAG_0x4005 - 0x407F also exist and are unused
|
||||
#define SPECIAL_FLAGS_END (SPECIAL_FLAGS_START + 0x7F)
|
||||
#define NUM_SPECIAL_FLAGS (SPECIAL_FLAGS_END - SPECIAL_FLAGS_START + 1)
|
||||
|
||||
@ -190,6 +190,7 @@ u8 GetWalkInPlaceFastMovementAction(u32);
|
||||
u8 GetWalkInPlaceNormalMovementAction(u32);
|
||||
u8 GetWalkInPlaceSlowMovementAction(u32);
|
||||
u8 GetCollisionAtCoords(struct ObjectEvent *, s16 x, s16 y, u32 dir);
|
||||
u32 GetObjectObjectCollidesWith(struct ObjectEvent *objectEvent, s16 x, s16 y, bool32 addCoords);
|
||||
void MoveCoords(u8 direction, s16 *x, s16 *y);
|
||||
bool8 ObjectEventIsHeldMovementActive(struct ObjectEvent *);
|
||||
u8 ObjectEventClearHeldMovementIfFinished(struct ObjectEvent *);
|
||||
|
||||
@ -148,6 +148,7 @@ void SetCurrentAndNextWeatherNoDelay(u8 weather);
|
||||
void ApplyWeatherColorMapIfIdle(s8 colorMapIndex);
|
||||
void ApplyWeatherColorMapIfIdle_Gradual(u8 colorMapIndex, u8 targetColorMapIndex, u8 colorMapStepDelay);
|
||||
void FadeScreen(u8 mode, s8 delay);
|
||||
u16 FadeScreenHardware(u8 mode, s8 delay);
|
||||
bool8 IsWeatherNotFadingIn(void);
|
||||
void UpdateSpritePaletteWithWeather(u8 spritePaletteIndex, bool8 allowFog);
|
||||
void ApplyWeatherColorMapToPals(u8 startPalIndex, u8 numPalettes);
|
||||
@ -165,7 +166,9 @@ void PlayRainStoppingSoundEffect(void);
|
||||
u8 IsWeatherChangeComplete(void);
|
||||
void SetWeatherScreenFadeOut(void);
|
||||
void SetWeatherPalStateIdle(void);
|
||||
const u8* SetPaletteColorMapType(u8 paletteIndex, u8 colorMapType);
|
||||
void PreservePaletteInWeather(u8 preservedPalIndex);
|
||||
void ResetPaletteColorMapType(u8 paletteIndex);
|
||||
void ResetPreservedPalettesInWeather(void);
|
||||
bool32 IsWeatherAlphaBlend(void);
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 currentTimeBlend
|
||||
#define HOURS_FREEZE_BLEND 26
|
||||
|
||||
struct InitialPlayerAvatarState
|
||||
{
|
||||
u8 transitionFlags;
|
||||
@ -40,15 +45,7 @@ struct LinkPlayerObjectEvent
|
||||
u8 movementMode;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) TimeBlendSettings
|
||||
{
|
||||
u16 weight:9;
|
||||
u16 finalTimeOfDay:3;
|
||||
u16 initialTimeOfDay:3;
|
||||
u16 unused:1;
|
||||
u16 altWeight;
|
||||
};
|
||||
|
||||
// Exported RAM declarations
|
||||
extern struct WarpData gLastUsedWarp;
|
||||
extern struct LinkPlayerObjectEvent gLinkPlayerObjectEvents[4];
|
||||
|
||||
@ -63,7 +60,7 @@ extern u8 gFieldLinkPlayerCount;
|
||||
extern bool8 gExitStairsMovementDisabled;
|
||||
extern bool8 gSkipShowMonAnim;
|
||||
extern u8 gTimeOfDay;
|
||||
extern u16 gTimeUpdateCounter;
|
||||
extern s16 gTimeUpdateCounter;
|
||||
|
||||
extern struct TimeBlendSettings currentTimeBlend;
|
||||
|
||||
@ -173,6 +170,7 @@ bool32 Overworld_RecvKeysFromLinkIsRunning(void);
|
||||
bool32 Overworld_SendKeysToLinkIsRunning(void);
|
||||
bool32 IsSendingKeysOverCable(void);
|
||||
void ClearLinkPlayerObjectEvents(void);
|
||||
bool16 SetTimeOfDay(u16 hours);
|
||||
|
||||
// Item Description Headers
|
||||
enum ItemObtainFlags
|
||||
|
||||
@ -46,6 +46,13 @@ struct BlendSettings
|
||||
u32 unused:2;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) TimeBlendSettings {
|
||||
struct BlendSettings bld0;
|
||||
struct BlendSettings bld1;
|
||||
u16 weight;
|
||||
u16 altWeight;
|
||||
};
|
||||
|
||||
struct PaletteFadeControl
|
||||
{
|
||||
u32 multipurpose1; // This field needs to exist or errors will occur
|
||||
|
||||
@ -303,8 +303,7 @@ void FreeOamMatrix(u8 matrixNum);
|
||||
void InitSpriteAffineAnim(struct Sprite *sprite);
|
||||
void SetOamMatrixRotationScaling(u8 matrixNum, s16 xScale, s16 yScale, u16 rotation);
|
||||
u16 LoadSpriteSheet(const struct SpriteSheet *sheet);
|
||||
u16 LoadSpriteSheetByTemplateWithOffset(const struct SpriteTemplate *template, u32 frame, s32 offset);
|
||||
u16 LoadSpriteSheetByTemplate(const struct SpriteTemplate *template, u8 frame);
|
||||
u16 LoadSpriteSheetByTemplate(const struct SpriteTemplate *template, u32 frame, s32 offset);
|
||||
void LoadSpriteSheets(const struct SpriteSheet *sheets);
|
||||
s16 AllocSpriteTiles(u16 tileCount);
|
||||
u16 AllocTilesForSpriteSheet(struct SpriteSheet *sheet);
|
||||
|
||||
@ -2061,18 +2061,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;
|
||||
}
|
||||
|
||||
@ -2847,7 +2852,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);
|
||||
@ -2906,17 +2911,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);
|
||||
|
||||
@ -73,7 +73,7 @@ u32 LoadCompressedSpriteSheetByTemplate(const struct SpriteTemplate *template, s
|
||||
|
||||
// Check for LZ77 header and read uncompressed size, or fallback if not compressed (zero size)
|
||||
if ((size = IsLZ77Data(template->images->data, TILE_SIZE_4BPP, MAX_DECOMPRESSION_BUFFER_SIZE)) == 0)
|
||||
return LoadSpriteSheetByTemplateWithOffset(template, 0, offset);
|
||||
return LoadSpriteSheetByTemplate(template, 0, offset);
|
||||
|
||||
void *buffer = malloc_and_decompress(template->images->data, NULL);
|
||||
myImage.data = buffer;
|
||||
@ -81,7 +81,7 @@ u32 LoadCompressedSpriteSheetByTemplate(const struct SpriteTemplate *template, s
|
||||
myTemplate.images = &myImage;
|
||||
myTemplate.tileTag = template->tileTag;
|
||||
|
||||
u32 ret = LoadSpriteSheetByTemplateWithOffset(&myTemplate, 0, offset);
|
||||
u32 ret = LoadSpriteSheetByTemplate(&myTemplate, 0, offset);
|
||||
Free(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -187,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 *, u16, u8, bool8);
|
||||
static void FollowerSetGraphics(struct ObjectEvent *, u16, u8, bool8, bool8);
|
||||
static void ObjectEventSetGraphics(struct ObjectEvent *, const struct ObjectEventGraphicsInfo *);
|
||||
static void SpriteCB_VirtualObject(struct Sprite *);
|
||||
static void DoShadowFieldEffect(struct ObjectEvent *);
|
||||
@ -379,7 +379,7 @@ static const bool8 sMovementTypeHasRange[NUM_MOVEMENT_TYPES] = {
|
||||
[MOVEMENT_TYPE_COPY_PLAYER_CLOCKWISE_IN_GRASS] = TRUE,
|
||||
};
|
||||
|
||||
const u8 gInitialMovementTypeFacingDirections[] = {
|
||||
const u8 gInitialMovementTypeFacingDirections[NUM_MOVEMENT_TYPES] = {
|
||||
[MOVEMENT_TYPE_NONE] = DIR_SOUTH,
|
||||
[MOVEMENT_TYPE_LOOK_AROUND] = DIR_SOUTH,
|
||||
[MOVEMENT_TYPE_WANDER_AROUND] = DIR_SOUTH,
|
||||
@ -461,6 +461,7 @@ const u8 gInitialMovementTypeFacingDirections[] = {
|
||||
[MOVEMENT_TYPE_WALK_SLOWLY_IN_PLACE_UP] = DIR_NORTH,
|
||||
[MOVEMENT_TYPE_WALK_SLOWLY_IN_PLACE_LEFT] = DIR_WEST,
|
||||
[MOVEMENT_TYPE_WALK_SLOWLY_IN_PLACE_RIGHT] = DIR_EAST,
|
||||
[MOVEMENT_TYPE_FOLLOW_PLAYER] = DIR_SOUTH,
|
||||
};
|
||||
|
||||
#include "data/object_events/object_event_graphics_info_pointers.h"
|
||||
@ -1999,6 +2000,14 @@ struct Pokemon *GetFirstLiveMon(void)
|
||||
u32 i;
|
||||
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))
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (gPlayerParty[i].hp > 0 && !(gPlayerParty[i].box.isEgg || gPlayerParty[i].box.isBadEgg))
|
||||
return &gPlayerParty[i];
|
||||
}
|
||||
@ -2121,14 +2130,14 @@ static u8 LoadDynamicFollowerPalette(u16 species, u8 form, bool32 shiny)
|
||||
}
|
||||
|
||||
// Set graphics & sprite for a follower object event by species & shininess.
|
||||
static void FollowerSetGraphics(struct ObjectEvent *objEvent, u16 species, u8 form, bool8 shiny)
|
||||
static void FollowerSetGraphics(struct ObjectEvent *objEvent, u16 species, u8 form, bool8 shiny, bool8 doPalette)
|
||||
{
|
||||
const struct ObjectEventGraphicsInfo *graphicsInfo = SpeciesToGraphicsInfo(species, form);
|
||||
ObjectEventSetGraphics(objEvent, graphicsInfo);
|
||||
objEvent->graphicsId = (OBJ_EVENT_GFX_MON_BASE + species) & OBJ_EVENT_GFX_SPECIES_MASK;
|
||||
objEvent->graphicsId |= form << OBJ_EVENT_GFX_SPECIES_BITS;
|
||||
objEvent->shiny = shiny;
|
||||
if (graphicsInfo->paletteTag == OBJ_EVENT_PAL_TAG_DYNAMIC) // Use palette from species palette table
|
||||
if (graphicsInfo->paletteTag == OBJ_EVENT_PAL_TAG_DYNAMIC && doPalette) // Use palette from species palette table
|
||||
{
|
||||
struct Sprite *sprite = &gSprites[objEvent->spriteId];
|
||||
// Free palette if otherwise unused
|
||||
@ -2137,10 +2146,6 @@ static void FollowerSetGraphics(struct ObjectEvent *objEvent, u16 species, u8 fo
|
||||
sprite->inUse = TRUE;
|
||||
sprite->oam.paletteNum = LoadDynamicFollowerPalette(species, form, shiny);
|
||||
}
|
||||
else if (gWeatherPtr->currWeather != WEATHER_FOG_HORIZONTAL) // don't want to weather blend in fog
|
||||
{
|
||||
UpdateSpritePaletteWithWeather(gSprites[objEvent->spriteId].oam.paletteNum, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
// Like FollowerSetGraphics, but does not recenter sprite on a metatile
|
||||
@ -2289,10 +2294,8 @@ void UpdateFollowingPokemon(void)
|
||||
// Follower appearance changed; move to player and set invisible
|
||||
if (species != OW_SPECIES(objEvent) || shiny != objEvent->shiny || form != OW_FORM(objEvent))
|
||||
{
|
||||
MoveObjectEventToMapCoords(objEvent,
|
||||
gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.x,
|
||||
gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.y);
|
||||
FollowerSetGraphics(objEvent, species, form, shiny);
|
||||
MoveObjectEventToMapCoords(objEvent, gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.x, gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.y);
|
||||
FollowerSetGraphics(objEvent, species, form, shiny, TRUE);
|
||||
objEvent->invisible = TRUE;
|
||||
}
|
||||
sprite->data[6] = 0; // set animation data
|
||||
@ -2658,6 +2661,7 @@ void UpdateLightSprite(struct Sprite *sprite)
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: Don't set window registers during hardware fade!
|
||||
switch (sprite->sLightType)
|
||||
{
|
||||
default:
|
||||
@ -2703,7 +2707,7 @@ static void SpawnLightSprite(s16 x, s16 y, s16 camX, s16 camY, u32 lightType)
|
||||
}
|
||||
lightType = min(lightType, ARRAY_COUNT(gFieldEffectLightTemplates) - 1); // bounds checking
|
||||
template = gFieldEffectLightTemplates[lightType];
|
||||
LoadSpriteSheetByTemplate(template, 0);
|
||||
LoadSpriteSheetByTemplate(template, 0, 0);
|
||||
sprite = &gSprites[CreateSprite(template, 0, 0, 0)];
|
||||
if (lightType == 0 && (i = IndexOfSpritePaletteTag(template->paletteTag + 1)) < 16)
|
||||
sprite->oam.paletteNum = i;
|
||||
@ -5680,6 +5684,7 @@ bool8 MovementType_FollowPlayer_Moving(struct ObjectEvent *objectEvent, struct S
|
||||
objectEvent->movementActionId = MOVEMENT_ACTION_NONE;
|
||||
sprite->sActionFuncId = 0;
|
||||
objectEvent->singleMovementActive = FALSE;
|
||||
objectEvent->facingDirectionLocked = FALSE;
|
||||
if (sprite->sTypeFuncId) // restore nonzero state
|
||||
sprite->sTypeFuncId = 1;
|
||||
}
|
||||
@ -5749,9 +5754,8 @@ bool8 FollowablePlayerMovement_Step(struct ObjectEvent *objectEvent, struct Spri
|
||||
if (objectEvent->invisible)
|
||||
{
|
||||
// Animate exiting pokeball
|
||||
// Player is jumping, but follower is invisible
|
||||
if (PlayerGetCopyableMovement() == COPY_MOVE_JUMP2)
|
||||
{
|
||||
// don't emerge if player is jumping or moving via script
|
||||
if (PlayerGetCopyableMovement() == COPY_MOVE_JUMP2 || ArePlayerFieldControlsLocked()) {
|
||||
sprite->sTypeFuncId = 0; // return to shadowing state
|
||||
return FALSE;
|
||||
}
|
||||
@ -5771,60 +5775,35 @@ bool8 FollowablePlayerMovement_Step(struct ObjectEvent *objectEvent, struct Spri
|
||||
|
||||
// Follow player
|
||||
direction = GetDirectionToFace(x, y, targetX, targetY);
|
||||
// During a script, if player sidesteps or backsteps,
|
||||
// mirror player's direction instead
|
||||
if (ArePlayerFieldControlsLocked()
|
||||
&& gObjectEvents[gPlayerAvatar.objectEventId].facingDirection != gObjectEvents[gPlayerAvatar.objectEventId].movementDirection
|
||||
) {
|
||||
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)
|
||||
{
|
||||
// InitJumpRegular will set the proper speed
|
||||
ObjectEventSetSingleMovement(objectEvent, sprite, GetJump2MovementAction(direction));
|
||||
}
|
||||
else if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_DASH))
|
||||
{
|
||||
// Set follow speed according to player's speed
|
||||
if (playerAction >= MOVEMENT_ACTION_RUN_DOWN_SLOW && playerAction <= MOVEMENT_ACTION_RUN_RIGHT_SLOW)
|
||||
else if (playerAction >= MOVEMENT_ACTION_WALK_SLOW_DOWN && playerAction <= MOVEMENT_ACTION_WALK_SLOW_RIGHT) {
|
||||
if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_DASH)) // on sideways stairs
|
||||
objectEvent->movementActionId = GetWalkNormalMovementAction(direction);
|
||||
else
|
||||
objectEvent->movementActionId = GetWalkFastMovementAction(direction);
|
||||
}
|
||||
else if (PlayerGetCopyableMovement() == COPY_MOVE_JUMP2)
|
||||
{
|
||||
ObjectEventSetSingleMovement(objectEvent, sprite, GetWalkSlowMovementAction(direction));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (playerAction >= MOVEMENT_ACTION_WALK_SLOW_DOWN && playerAction <= MOVEMENT_ACTION_WALK_SLOW_RIGHT)
|
||||
{
|
||||
ObjectEventSetSingleMovement(objectEvent, sprite, GetWalkSlowMovementAction(direction));
|
||||
}
|
||||
else
|
||||
{
|
||||
objectEvent->movementActionId = GetWalkNormalMovementAction(direction);
|
||||
if (OW_FOLLOWERS_BOBBING == TRUE)
|
||||
sprite->y2 = -1;
|
||||
}
|
||||
}
|
||||
sprite->sActionFuncId = 0;
|
||||
if (GetLedgeJumpDirection(x, y, direction) != DIR_NONE)
|
||||
{
|
||||
// InitJumpRegular will set the proper speed
|
||||
ObjectEventSetSingleMovement(objectEvent, sprite, GetJump2MovementAction(direction));
|
||||
}
|
||||
else if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_DASH))
|
||||
{
|
||||
// Set follow speed according to player's speed
|
||||
ObjectEventSetSingleMovement(objectEvent, sprite, GetWalkFastMovementAction(direction));
|
||||
}
|
||||
else if (PlayerGetCopyableMovement() == COPY_MOVE_JUMP2)
|
||||
{
|
||||
// If *player* jumps, make step take twice as long
|
||||
} else if (PlayerGetCopyableMovement() == COPY_MOVE_JUMP2) {
|
||||
ObjectEventSetSingleMovement(objectEvent, sprite, GetWalkSlowMovementAction(direction));
|
||||
}
|
||||
else
|
||||
{
|
||||
ObjectEventSetSingleMovement(objectEvent, sprite, GetWalkNormalMovementAction(direction));
|
||||
} else if (gSprites[gPlayerAvatar.spriteId].data[4] == MOVE_SPEED_FAST_1) {
|
||||
objectEvent->movementActionId = GetWalkFastMovementAction(direction);
|
||||
} else {
|
||||
objectEvent->movementActionId = GetWalkNormalMovementAction(direction);
|
||||
if (OW_FOLLOWERS_BOBBING == TRUE)
|
||||
sprite->y2 = -1;
|
||||
}
|
||||
sprite->sActionFuncId = 0;
|
||||
objectEvent->singleMovementActive = TRUE;
|
||||
sprite->sTypeFuncId = 2;
|
||||
return TRUE;
|
||||
@ -6488,13 +6467,17 @@ static bool8 IsMetatileDirectionallyImpassable(struct ObjectEvent *objectEvent,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static bool8 DoesObjectCollideWithObjectAt(struct ObjectEvent *objectEvent, s16 x, s16 y)
|
||||
{
|
||||
u32 GetObjectObjectCollidesWith(struct ObjectEvent *objectEvent, s16 x, s16 y, bool32 addCoords) {
|
||||
u8 i;
|
||||
struct ObjectEvent *curObject;
|
||||
|
||||
if (objectEvent->localId == OBJ_EVENT_ID_FOLLOWER)
|
||||
return FALSE; // follower cannot collide with other objects, but they can collide with it
|
||||
return OBJECT_EVENTS_COUNT; // follower cannot collide with other objects, but they can collide with it
|
||||
|
||||
if (addCoords) {
|
||||
x += objectEvent->currentCoords.x;
|
||||
y += objectEvent->currentCoords.y;
|
||||
}
|
||||
|
||||
for (i = 0; i < OBJECT_EVENTS_COUNT; i++)
|
||||
{
|
||||
@ -6505,11 +6488,16 @@ static bool8 DoesObjectCollideWithObjectAt(struct ObjectEvent *objectEvent, s16
|
||||
if ((curObject->currentCoords.x == x && curObject->currentCoords.y == y) || (curObject->previousCoords.x == x && curObject->previousCoords.y == y))
|
||||
{
|
||||
if (AreElevationsCompatible(objectEvent->currentElevation, curObject->currentElevation))
|
||||
return TRUE;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
return OBJECT_EVENTS_COUNT;
|
||||
}
|
||||
|
||||
static bool8 DoesObjectCollideWithObjectAt(struct ObjectEvent *objectEvent, s16 x, s16 y)
|
||||
{
|
||||
return (GetObjectObjectCollidesWith(objectEvent, x, y, FALSE) < OBJECT_EVENTS_COUNT);
|
||||
}
|
||||
|
||||
bool8 IsBerryTreeSparkling(u8 localId, u8 mapNum, u8 mapGroup)
|
||||
@ -6661,6 +6649,19 @@ static u8 TryUpdateMovementActionOnStairs(struct ObjectEvent *objectEvent, u8 mo
|
||||
}
|
||||
}
|
||||
|
||||
static const u8 sActionIdToCopyableMovement[] = {
|
||||
[MOVEMENT_ACTION_FACE_DOWN ... MOVEMENT_ACTION_FACE_RIGHT] = COPY_MOVE_FACE,
|
||||
[MOVEMENT_ACTION_WALK_SLOW_DOWN ... MOVEMENT_ACTION_WALK_NORMAL_RIGHT] = COPY_MOVE_WALK,
|
||||
[MOVEMENT_ACTION_JUMP_2_DOWN ... MOVEMENT_ACTION_JUMP_2_RIGHT] = COPY_MOVE_JUMP2,
|
||||
[MOVEMENT_ACTION_WALK_FAST_DOWN ... MOVEMENT_ACTION_WALK_FAST_RIGHT] = COPY_MOVE_WALK,
|
||||
[MOVEMENT_ACTION_RIDE_WATER_CURRENT_DOWN ... MOVEMENT_ACTION_PLAYER_RUN_RIGHT] = COPY_MOVE_WALK,
|
||||
// Not a typo; follower needs to take an action with a duration == JUMP's,
|
||||
// and JUMP2 here will lead to WALK_SLOW later
|
||||
[MOVEMENT_ACTION_JUMP_DOWN ... MOVEMENT_ACTION_JUMP_RIGHT] = COPY_MOVE_JUMP2,
|
||||
|
||||
[MOVEMENT_ACTION_NONE] = COPY_MOVE_NONE,
|
||||
};
|
||||
|
||||
bool8 ObjectEventSetHeldMovement(struct ObjectEvent *objectEvent, u8 movementActionId)
|
||||
{
|
||||
if (ObjectEventIsMovementOverridden(objectEvent))
|
||||
@ -6673,6 +6674,16 @@ bool8 ObjectEventSetHeldMovement(struct ObjectEvent *objectEvent, u8 movementAct
|
||||
objectEvent->heldMovementActive = TRUE;
|
||||
objectEvent->heldMovementFinished = FALSE;
|
||||
gSprites[objectEvent->spriteId].sActionFuncId = 0;
|
||||
|
||||
// When player is moved via script, set copyable movement
|
||||
// for any followers via a lookup table
|
||||
if (ArePlayerFieldControlsLocked() &&
|
||||
objectEvent->isPlayer &&
|
||||
FlagGet(FLAG_SAFE_FOLLOWER_MOVEMENT))
|
||||
{
|
||||
objectEvent->playerCopyableMovement = sActionIdToCopyableMovement[objectEvent->movementActionId];
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -6696,6 +6707,15 @@ void ObjectEventClearHeldMovement(struct ObjectEvent *objectEvent)
|
||||
objectEvent->heldMovementFinished = FALSE;
|
||||
gSprites[objectEvent->spriteId].sTypeFuncId = 0;
|
||||
gSprites[objectEvent->spriteId].sActionFuncId = 0;
|
||||
|
||||
// When player is moved via script, set copyable movement
|
||||
// for any followers via a lookup table
|
||||
if (ArePlayerFieldControlsLocked() &&
|
||||
objectEvent->isPlayer &&
|
||||
FlagGet(FLAG_SAFE_FOLLOWER_MOVEMENT))
|
||||
{
|
||||
objectEvent->playerCopyableMovement = sActionIdToCopyableMovement[objectEvent->movementActionId];
|
||||
}
|
||||
}
|
||||
|
||||
u8 ObjectEventCheckHeldMovementStatus(struct ObjectEvent *objectEvent)
|
||||
@ -7683,7 +7703,7 @@ bool8 MovementAction_ExitPokeball_Step1(struct ObjectEvent *objectEvent, struct
|
||||
// Set graphics, palette, and affine animation
|
||||
else if (sprite->sDuration == animStepFrame)
|
||||
{
|
||||
FollowerSetGraphics(objectEvent, OW_SPECIES(objectEvent), OW_FORM(objectEvent), objectEvent->shiny);
|
||||
FollowerSetGraphics(objectEvent, OW_SPECIES(objectEvent), OW_FORM(objectEvent), objectEvent->shiny, FALSE);
|
||||
LoadFillColorPalette(RGB_WHITE, OBJ_EVENT_PAL_TAG_WHITE, sprite);
|
||||
// Initialize affine animation
|
||||
sprite->affineAnims = sAffineAnims_PokeballFollower;
|
||||
@ -7700,7 +7720,7 @@ bool8 MovementAction_ExitPokeball_Step1(struct ObjectEvent *objectEvent, struct
|
||||
sprite->affineAnimEnded = TRUE;
|
||||
FreeSpriteOamMatrix(sprite);
|
||||
sprite->oam.affineMode = ST_OAM_AFFINE_OFF;
|
||||
FollowerSetGraphics(objectEvent, OW_SPECIES(objectEvent), OW_FORM(objectEvent), objectEvent->shiny);
|
||||
FollowerSetGraphics(objectEvent, OW_SPECIES(objectEvent), OW_FORM(objectEvent), objectEvent->shiny, TRUE);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
@ -7756,7 +7776,7 @@ bool8 MovementAction_EnterPokeball_Step1(struct ObjectEvent *objectEvent, struct
|
||||
|
||||
bool8 MovementAction_EnterPokeball_Step2(struct ObjectEvent *objectEvent, struct Sprite *sprite)
|
||||
{
|
||||
FollowerSetGraphics(objectEvent, OW_SPECIES(objectEvent), OW_FORM(objectEvent), objectEvent->shiny);
|
||||
FollowerSetGraphics(objectEvent, OW_SPECIES(objectEvent), OW_FORM(objectEvent), objectEvent->shiny, FALSE);
|
||||
objectEvent->invisible = TRUE;
|
||||
sprite->sTypeFuncId = 0;
|
||||
sprite->sSpeedFlip = 0;
|
||||
|
||||
@ -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), TRUE);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,8 +57,8 @@ u32 FldEff_Shadow(void);
|
||||
void SetUpShadow(struct ObjectEvent *objectEvent, struct Sprite *sprite)
|
||||
{
|
||||
gFieldEffectArguments[0] = objectEvent->localId;
|
||||
gFieldEffectArguments[1] = gSaveBlock1Ptr->location.mapNum;
|
||||
gFieldEffectArguments[2] = gSaveBlock1Ptr->location.mapGroup;
|
||||
gFieldEffectArguments[1] = objectEvent->mapNum;
|
||||
gFieldEffectArguments[2] = objectEvent->mapGroup;
|
||||
FldEff_Shadow();
|
||||
}
|
||||
|
||||
@ -339,19 +339,23 @@ u32 FldEff_Shadow(void)
|
||||
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;
|
||||
LoadSpriteSheetByTemplate(gFieldEffectObjectTemplatePointers[sShadowEffectTemplateIds[graphicsInfo->shadowSize]], 0);
|
||||
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];
|
||||
|
||||
@ -23,13 +23,6 @@
|
||||
|
||||
#define DROUGHT_COLOR_INDEX(color) ((((color) >> 1) & 0xF) | (((color) >> 2) & 0xF0) | (((color) >> 3) & 0xF00))
|
||||
|
||||
enum
|
||||
{
|
||||
COLOR_MAP_NONE,
|
||||
COLOR_MAP_DARK_CONTRAST,
|
||||
COLOR_MAP_CONTRAST,
|
||||
};
|
||||
|
||||
struct RGBColor
|
||||
{
|
||||
u16 r:5;
|
||||
@ -799,10 +792,7 @@ void FadeScreen(u8 mode, s8 delay)
|
||||
else if (MapHasNaturalLight(gMapHeader.mapType))
|
||||
{
|
||||
UpdateAltBgPalettes(PALETTES_BG);
|
||||
BeginTimeOfDayPaletteFade(PALETTES_ALL, delay, 16, 0,
|
||||
(struct BlendSettings *)&gTimeOfDayBlend[currentTimeBlend.initialTimeOfDay],
|
||||
(struct BlendSettings *)&gTimeOfDayBlend[currentTimeBlend.finalTimeOfDay],
|
||||
currentTimeBlend.weight, fadeColor);
|
||||
BeginTimeOfDayPaletteFade(PALETTES_ALL, delay, 16, 0, ¤tTimeBlend.bld0, ¤tTimeBlend.bld1, currentTimeBlend.weight, fadeColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -817,6 +807,36 @@ void FadeScreen(u8 mode, s8 delay)
|
||||
}
|
||||
}
|
||||
|
||||
// fades screen using BLDY
|
||||
// Note: This enables blending in all windows;
|
||||
// These bits may need to be disabled later
|
||||
// (i.e if blending lighting effects using WINOBJ)
|
||||
u16 FadeScreenHardware(u8 mode, s8 delay) {
|
||||
u16 bldCnt = GetGpuReg(REG_OFFSET_BLDCNT) & BLDCNT_TGT2_ALL;
|
||||
bldCnt |= BLDCNT_TGT1_ALL;
|
||||
// enable blend in all windows
|
||||
SetGpuRegBits(REG_OFFSET_WININ, WININ_WIN0_CLR | WININ_WIN1_CLR);
|
||||
SetGpuRegBits(REG_OFFSET_WINOUT, WINOUT_WIN01_CLR);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case FADE_FROM_BLACK:
|
||||
BeginHardwarePaletteFade(bldCnt | BLDCNT_EFFECT_DARKEN, delay, 16, 0, TRUE);
|
||||
break;
|
||||
case FADE_TO_BLACK:
|
||||
BeginHardwarePaletteFade(bldCnt | BLDCNT_EFFECT_DARKEN, delay, 0, 16, FALSE);
|
||||
break;
|
||||
case FADE_FROM_WHITE:
|
||||
BeginHardwarePaletteFade(bldCnt | BLDCNT_EFFECT_LIGHTEN, delay, 16, 0, TRUE);
|
||||
break;
|
||||
case FADE_TO_WHITE:
|
||||
BeginHardwarePaletteFade(bldCnt | BLDCNT_EFFECT_LIGHTEN, delay, 0, 16, FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool8 IsWeatherNotFadingIn(void)
|
||||
{
|
||||
return (gWeatherPtr->palProcessingState != WEATHER_PAL_STATE_SCREEN_FADING_IN);
|
||||
@ -986,7 +1006,10 @@ void Weather_SetBlendCoeffs(u8 eva, u8 evb)
|
||||
gWeatherPtr->currBlendEVB = evb;
|
||||
gWeatherPtr->targetBlendEVA = eva;
|
||||
gWeatherPtr->targetBlendEVB = evb;
|
||||
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(eva, evb));
|
||||
|
||||
// don't update BLDALPHA if a hardware fade is on-screen
|
||||
if ((GetGpuReg(REG_OFFSET_BLDCNT) & BLDCNT_EFFECT_EFF_MASK) < BLDCNT_EFFECT_LIGHTEN)
|
||||
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(eva, evb));
|
||||
}
|
||||
|
||||
void Weather_SetTargetBlendCoeffs(u8 eva, u8 evb, int delay)
|
||||
@ -1136,11 +1159,27 @@ void SetWeatherPalStateIdle(void)
|
||||
gWeatherPtr->palProcessingState = WEATHER_PAL_STATE_IDLE;
|
||||
}
|
||||
|
||||
const u8* SetPaletteColorMapType(u8 paletteIndex, u8 colorMapType) {
|
||||
if (sPaletteColorMapTypes[paletteIndex] == colorMapType)
|
||||
return sPaletteColorMapTypes;
|
||||
// setup field effect color map
|
||||
if (sPaletteColorMapTypes != sFieldEffectPaletteColorMapTypes) {
|
||||
CpuFastCopy(sBasePaletteColorMapTypes, sFieldEffectPaletteColorMapTypes, 32);
|
||||
sPaletteColorMapTypes = sFieldEffectPaletteColorMapTypes;
|
||||
}
|
||||
sFieldEffectPaletteColorMapTypes[paletteIndex] = colorMapType;
|
||||
return sPaletteColorMapTypes;
|
||||
}
|
||||
|
||||
void PreservePaletteInWeather(u8 preservedPalIndex)
|
||||
{
|
||||
CpuCopy16(sBasePaletteColorMapTypes, sFieldEffectPaletteColorMapTypes, 32);
|
||||
sFieldEffectPaletteColorMapTypes[preservedPalIndex] = COLOR_MAP_NONE;
|
||||
sPaletteColorMapTypes = sFieldEffectPaletteColorMapTypes;
|
||||
SetPaletteColorMapType(preservedPalIndex, COLOR_MAP_NONE);
|
||||
}
|
||||
|
||||
void ResetPaletteColorMapType(u8 paletteIndex) {
|
||||
if (sPaletteColorMapTypes == sBasePaletteColorMapTypes)
|
||||
return;
|
||||
sFieldEffectPaletteColorMapTypes[paletteIndex] = sBasePaletteColorMapTypes[paletteIndex];
|
||||
}
|
||||
|
||||
void ResetPreservedPalettesInWeather(void)
|
||||
|
||||
@ -888,7 +888,7 @@ static void LoadTilesetPalette(struct Tileset const *tileset, u16 destOffset, u1
|
||||
{
|
||||
// LoadPalette(&black, destOffset, 2);
|
||||
if (skipFaded)
|
||||
CpuFastCopy(tileset->palettes, &gPlttBufferUnfaded[destOffset], size);
|
||||
CpuFastCopy(tileset->palettes, &gPlttBufferUnfaded[destOffset], size); // always word-aligned
|
||||
else
|
||||
LoadPaletteFast(tileset->palettes, destOffset, size);
|
||||
gPlttBufferFaded[destOffset] = gPlttBufferUnfaded[destOffset] = RGB_BLACK; // why does it have to be black?
|
||||
@ -898,11 +898,11 @@ static void LoadTilesetPalette(struct Tileset const *tileset, u16 destOffset, u1
|
||||
}
|
||||
else if (tileset->isSecondary == TRUE)
|
||||
{
|
||||
// (void*) is to silence 'source potentially unaligned' error
|
||||
// All 'gTilesetPalettes_' arrays should have ALIGNED(4) in them
|
||||
if (skipFaded)
|
||||
CpuFastCopy((void*)tileset->palettes[NUM_PALS_IN_PRIMARY], &gPlttBufferUnfaded[destOffset], size);
|
||||
else
|
||||
// All 'gTilesetPalettes_' arrays should have ALIGNED(4) in them,
|
||||
// but we use SmartCopy here just in case they don't
|
||||
if (skipFaded) {
|
||||
CpuSmartCopy16(tileset->palettes[NUM_PALS_IN_PRIMARY], &gPlttBufferUnfaded[destOffset], size);
|
||||
} else
|
||||
LoadPaletteFast(tileset->palettes[NUM_PALS_IN_PRIMARY], destOffset, size);
|
||||
low = NUM_PALS_IN_PRIMARY;
|
||||
high = NUM_PALS_TOTAL;
|
||||
|
||||
@ -200,7 +200,7 @@ COMMON_DATA u8 gFieldLinkPlayerCount = 0;
|
||||
|
||||
u8 gTimeOfDay;
|
||||
struct TimeBlendSettings currentTimeBlend;
|
||||
u16 gTimeUpdateCounter; // playTimeVBlanks will eventually overflow, so this is used to update TOD
|
||||
s16 gTimeUpdateCounter; // playTimeVBlanks will eventually overflow, so this is used to update TOD
|
||||
|
||||
// EWRAM vars
|
||||
EWRAM_DATA static u8 sObjectEventLoadFlag = 0;
|
||||
@ -212,6 +212,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;
|
||||
|
||||
@ -910,6 +911,8 @@ static void LoadMapFromWarp(bool32 a1)
|
||||
TrySetMapSaveWarpStatus();
|
||||
ClearTempFieldEventData();
|
||||
ResetDexNavSearch();
|
||||
// reset hours override on every warp
|
||||
sHoursOverride = 0;
|
||||
ResetCyclingRoadChallengeData();
|
||||
RestartWildEncounterImmunitySteps();
|
||||
#if FREE_MATCH_CALL == FALSE
|
||||
@ -1557,37 +1560,37 @@ void UpdateTimeOfDay(void)
|
||||
{
|
||||
s32 hours, minutes;
|
||||
RtcCalcLocalTime();
|
||||
hours = gLocalTime.hours;
|
||||
minutes = gLocalTime.minutes;
|
||||
hours = sHoursOverride ? sHoursOverride : gLocalTime.hours;
|
||||
minutes = sHoursOverride ? 0 : gLocalTime.minutes;
|
||||
|
||||
if (IsBetweenHours(hours, MORNING_HOUR_BEGIN, MORNING_HOUR_MIDDLE)) // night->morning
|
||||
{
|
||||
currentTimeBlend.initialTimeOfDay = TIME_NIGHT;
|
||||
currentTimeBlend.finalTimeOfDay = TIME_MORNING;
|
||||
currentTimeBlend.bld0 = gTimeOfDayBlend[TIME_NIGHT];
|
||||
currentTimeBlend.bld1 = gTimeOfDayBlend[TIME_MORNING];
|
||||
currentTimeBlend.weight = TIME_BLEND_WEIGHT(MORNING_HOUR_BEGIN, MORNING_HOUR_MIDDLE);
|
||||
currentTimeBlend.altWeight = (DEFAULT_WEIGHT - currentTimeBlend.weight) / 2;
|
||||
gTimeOfDay = TIME_MORNING;
|
||||
}
|
||||
else if (IsBetweenHours(hours, MORNING_HOUR_MIDDLE, MORNING_HOUR_END)) // morning->day
|
||||
{
|
||||
currentTimeBlend.initialTimeOfDay = TIME_MORNING;
|
||||
currentTimeBlend.finalTimeOfDay = TIME_DAY;
|
||||
currentTimeBlend.bld0 = gTimeOfDayBlend[TIME_MORNING];
|
||||
currentTimeBlend.bld1 = gTimeOfDayBlend[TIME_DAY];
|
||||
currentTimeBlend.weight = TIME_BLEND_WEIGHT(MORNING_HOUR_MIDDLE, MORNING_HOUR_END);
|
||||
currentTimeBlend.altWeight = (DEFAULT_WEIGHT - currentTimeBlend.weight) / 2 + (DEFAULT_WEIGHT / 2);
|
||||
gTimeOfDay = TIME_MORNING;
|
||||
}
|
||||
else if (IsBetweenHours(hours, EVENING_HOUR_BEGIN, EVENING_HOUR_END)) // evening
|
||||
{
|
||||
currentTimeBlend.initialTimeOfDay = TIME_DAY;
|
||||
currentTimeBlend.finalTimeOfDay = TIME_EVENING;
|
||||
currentTimeBlend.bld0 = gTimeOfDayBlend[TIME_DAY];
|
||||
currentTimeBlend.bld1 = gTimeOfDayBlend[TIME_EVENING];
|
||||
currentTimeBlend.weight = TIME_BLEND_WEIGHT(EVENING_HOUR_BEGIN, EVENING_HOUR_END);
|
||||
currentTimeBlend.altWeight = currentTimeBlend.weight / 2 + (DEFAULT_WEIGHT / 2);
|
||||
gTimeOfDay = TIME_EVENING;
|
||||
}
|
||||
else if (IsBetweenHours(hours, NIGHT_HOUR_BEGIN, NIGHT_HOUR_BEGIN + 1)) // evening->night
|
||||
{
|
||||
currentTimeBlend.initialTimeOfDay = TIME_EVENING;
|
||||
currentTimeBlend.finalTimeOfDay = TIME_NIGHT;
|
||||
currentTimeBlend.bld0 = gTimeOfDayBlend[TIME_EVENING];
|
||||
currentTimeBlend.bld1 = gTimeOfDayBlend[TIME_NIGHT];
|
||||
currentTimeBlend.weight = TIME_BLEND_WEIGHT(NIGHT_HOUR_BEGIN, NIGHT_HOUR_BEGIN + 1);
|
||||
currentTimeBlend.altWeight = currentTimeBlend.weight / 2;
|
||||
gTimeOfDay = TIME_NIGHT;
|
||||
@ -1596,12 +1599,14 @@ void UpdateTimeOfDay(void)
|
||||
{
|
||||
currentTimeBlend.weight = DEFAULT_WEIGHT;
|
||||
currentTimeBlend.altWeight = 0;
|
||||
gTimeOfDay = currentTimeBlend.initialTimeOfDay = currentTimeBlend.finalTimeOfDay = TIME_NIGHT;
|
||||
currentTimeBlend.bld0 = currentTimeBlend.bld1 = gTimeOfDayBlend[TIME_NIGHT];
|
||||
gTimeOfDay = TIME_NIGHT;
|
||||
}
|
||||
else // day
|
||||
{
|
||||
currentTimeBlend.weight = currentTimeBlend.altWeight = DEFAULT_WEIGHT;
|
||||
gTimeOfDay = currentTimeBlend.initialTimeOfDay = currentTimeBlend.finalTimeOfDay = TIME_DAY;
|
||||
currentTimeBlend.bld0 = currentTimeBlend.bld1 = gTimeOfDayBlend[TIME_DAY];
|
||||
gTimeOfDay = TIME_DAY;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1658,10 +1663,10 @@ void UpdatePalettesWithTime(u32 palettes)
|
||||
palettes &= ~(mask);
|
||||
}
|
||||
|
||||
palettes &= PALETTES_MAP | PALETTES_OBJECTS; // Don't blend UI pals
|
||||
if (!palettes)
|
||||
return;
|
||||
TimeMixPalettes(palettes, gPlttBufferUnfaded, gPlttBufferFaded, (struct BlendSettings *)&gTimeOfDayBlend[currentTimeBlend.initialTimeOfDay], (struct BlendSettings *)&gTimeOfDayBlend[currentTimeBlend.finalTimeOfDay], currentTimeBlend.weight);
|
||||
palettes &= PALETTES_MAP | PALETTES_OBJECTS; // Don't blend UI pals
|
||||
if (!palettes)
|
||||
return;
|
||||
TimeMixPalettes(palettes, gPlttBufferUnfaded, gPlttBufferFaded, ¤tTimeBlend.bld0, ¤tTimeBlend.bld1, currentTimeBlend.weight);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1671,8 +1676,7 @@ u8 UpdateSpritePaletteWithTime(u8 paletteNum)
|
||||
{
|
||||
if (IS_BLEND_IMMUNE_TAG(GetSpritePaletteTagByPaletteNum(paletteNum)))
|
||||
return paletteNum;
|
||||
TimeMixPalettes(1, &gPlttBufferUnfaded[OBJ_PLTT_ID(paletteNum)], &gPlttBufferFaded[OBJ_PLTT_ID(paletteNum)], (struct BlendSettings *)&gTimeOfDayBlend[currentTimeBlend.initialTimeOfDay], (struct BlendSettings *)&gTimeOfDayBlend[currentTimeBlend.finalTimeOfDay], currentTimeBlend.weight
|
||||
);
|
||||
TimeMixPalettes(1, &gPlttBufferUnfaded[OBJ_PLTT_ID(paletteNum)], &gPlttBufferFaded[OBJ_PLTT_ID(paletteNum)], ¤tTimeBlend.bld0, ¤tTimeBlend.bld1, currentTimeBlend.weight);
|
||||
}
|
||||
return paletteNum;
|
||||
}
|
||||
@ -1689,20 +1693,17 @@ static void OverworldBasic(void)
|
||||
UpdateTilesetAnimations();
|
||||
DoScheduledBgTilemapCopiesToVram();
|
||||
// Every minute if no palette fade is active, update TOD blending as needed
|
||||
if (!gPaletteFade.active && ++gTimeUpdateCounter >= (SECONDS_PER_MINUTE * 60 / FakeRtc_GetSecondsRatio()))
|
||||
{
|
||||
struct TimeBlendSettings cachedBlend = {
|
||||
.initialTimeOfDay = currentTimeBlend.initialTimeOfDay,
|
||||
.finalTimeOfDay = currentTimeBlend.finalTimeOfDay,
|
||||
.weight = currentTimeBlend.weight,
|
||||
};
|
||||
gTimeUpdateCounter = 0;
|
||||
if (!gPaletteFade.active && --gTimeUpdateCounter <= 0) {
|
||||
struct TimeBlendSettings cachedBlend = currentTimeBlend;
|
||||
u32 *bld0 = (u32*)&cachedBlend;
|
||||
u32 *bld1 = (u32*)¤tTimeBlend;
|
||||
gTimeUpdateCounter = (SECONDS_PER_MINUTE * 60 / FakeRtc_GetSecondsRatio());
|
||||
UpdateTimeOfDay();
|
||||
FormChangeTimeUpdate();
|
||||
if (cachedBlend.initialTimeOfDay != currentTimeBlend.initialTimeOfDay
|
||||
|| cachedBlend.finalTimeOfDay != currentTimeBlend.finalTimeOfDay
|
||||
|| cachedBlend.weight != currentTimeBlend.weight)
|
||||
{
|
||||
if (bld0[0] != bld1[0]
|
||||
|| bld0[1] != bld1[1]
|
||||
|| bld0[2] != bld1[2]
|
||||
) {
|
||||
UpdateAltBgPalettes(PALETTES_BG);
|
||||
UpdatePalettesWithTime(PALETTES_ALL);
|
||||
}
|
||||
@ -3679,3 +3680,15 @@ 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;
|
||||
}
|
||||
|
||||
@ -714,7 +714,8 @@ static u32 UpdateHardwarePaletteFade(void)
|
||||
{
|
||||
if (gPaletteFade.shouldResetBlendRegisters)
|
||||
{
|
||||
gPaletteFade_blendCnt = 0;
|
||||
// clear TGT1
|
||||
gPaletteFade_blendCnt &= ~0xFF;
|
||||
gPaletteFade.y = 0;
|
||||
}
|
||||
gPaletteFade.shouldResetBlendRegisters = FALSE;
|
||||
@ -725,10 +726,43 @@ 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_BLDY, gPaletteFade.y);
|
||||
// If fade-out, also adjust BLDALPHA and DISPCNT
|
||||
if (!gPaletteFade.yDec /*&& gPaletteFade.mode == HARDWARE_FADE*/) {
|
||||
u16 bldAlpha = GetGpuReg(REG_OFFSET_BLDALPHA);
|
||||
u8 tgt1 = BLDALPHA_TGT1(bldAlpha);
|
||||
u8 tgt2 = BLDALPHA_TGT2(bldAlpha);
|
||||
u8 bldFade;
|
||||
|
||||
switch (gPaletteFade_blendCnt & BLDCNT_EFFECT_EFF_MASK)
|
||||
{
|
||||
// FADE_TO_BLACK
|
||||
case BLDCNT_EFFECT_DARKEN:
|
||||
bldFade = BLDALPHA_TGT1(max(0, 16 - gPaletteFade.y));
|
||||
SetGpuReg(
|
||||
REG_OFFSET_BLDALPHA,
|
||||
BLDALPHA_BLEND(min(tgt1, bldFade), min(tgt2, bldFade))
|
||||
);
|
||||
break;
|
||||
// FADE_TO_WHITE
|
||||
case BLDCNT_EFFECT_LIGHTEN:
|
||||
SetGpuReg(
|
||||
REG_OFFSET_BLDALPHA,
|
||||
BLDALPHA_BLEND(min(++tgt1, 31), min(++tgt2, 31))
|
||||
);
|
||||
// cause display to show white when finished
|
||||
// (otherwise blend-mode sprites will still be visible)
|
||||
if (gPaletteFade.hardwareFadeFinishing && gPaletteFade.y >= 16)
|
||||
SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_FORCED_BLANK);
|
||||
break;
|
||||
}
|
||||
} else
|
||||
ClearGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_FORCED_BLANK);
|
||||
|
||||
if (gPaletteFade.hardwareFadeFinishing)
|
||||
{
|
||||
gPaletteFade.hardwareFadeFinishing = FALSE;
|
||||
|
||||
76
src/scrcmd.c
76
src/scrcmd.c
@ -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"
|
||||
@ -836,27 +837,19 @@ bool8 ScrCmd_fadescreenswapbuffers(struct ScriptContext *ctx)
|
||||
|
||||
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);
|
||||
@ -1265,6 +1258,20 @@ bool8 ScrCmd_fadeinbgm(struct ScriptContext *ctx)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
struct ObjectEvent * ScriptHideFollower(void) {
|
||||
struct ObjectEvent *obj = GetFollowerObject();
|
||||
|
||||
if (obj == NULL || obj->invisible)
|
||||
return NULL;
|
||||
|
||||
ClearObjectEventMovement(obj, &gSprites[obj->spriteId]);
|
||||
gSprites[obj->spriteId].animCmdIndex = 0; // Reset start frame of animation
|
||||
// Note: ScriptMovement_ returns TRUE on error
|
||||
if (ScriptMovement_StartObjectMovementScript(obj->localId, obj->mapGroup, obj->mapNum, EnterPokeballMovement))
|
||||
return NULL;
|
||||
return obj;
|
||||
}
|
||||
|
||||
bool8 ScrCmd_applymovement(struct ScriptContext *ctx)
|
||||
{
|
||||
u16 localId = VarGet(ScriptReadHalfword(ctx));
|
||||
@ -1283,17 +1290,11 @@ bool8 ScrCmd_applymovement(struct ScriptContext *ctx)
|
||||
gObjectEvents[GetObjectEventIdByLocalId(localId)].directionOverwrite = DIR_NONE;
|
||||
ScriptMovement_StartObjectMovementScript(localId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, movementScript);
|
||||
sMovingNpcId = localId;
|
||||
objEvent = GetFollowerObject();
|
||||
// Force follower into pokeball
|
||||
if (localId != OBJ_EVENT_ID_FOLLOWER
|
||||
&& !FlagGet(FLAG_SAFE_FOLLOWER_MOVEMENT)
|
||||
&& (movementScript < Common_Movement_FollowerSafeStart || movementScript > Common_Movement_FollowerSafeEnd)
|
||||
&& (objEvent = GetFollowerObject())
|
||||
&& !objEvent->invisible)
|
||||
if (localId != OBJ_EVENT_ID_FOLLOWER &&
|
||||
!FlagGet(FLAG_SAFE_FOLLOWER_MOVEMENT)
|
||||
&& (movementScript < Common_Movement_FollowerSafeStart || movementScript > Common_Movement_FollowerSafeEnd))
|
||||
{
|
||||
ClearObjectEventMovement(objEvent, &gSprites[objEvent->spriteId]);
|
||||
gSprites[objEvent->spriteId].animCmdIndex = 0; // Reset start frame of animation
|
||||
ScriptMovement_StartObjectMovementScript(OBJ_EVENT_ID_FOLLOWER, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, EnterPokeballMovement);
|
||||
ScriptHideFollower();
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
@ -1555,8 +1556,11 @@ bool8 ScrCmd_lockall(struct ScriptContext *ctx)
|
||||
}
|
||||
else
|
||||
{
|
||||
struct ObjectEvent *followerObj = GetFollowerObject();
|
||||
FreezeObjects_WaitForPlayer();
|
||||
SetupNativeScript(ctx, IsFreezePlayerFinished);
|
||||
if (FlagGet(FLAG_SAFE_FOLLOWER_MOVEMENT) && followerObj) // Unfreeze follower object (conditionally)
|
||||
UnfreezeObjectEvent(followerObj);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
@ -3114,3 +3118,23 @@ void Script_EndTrainerCanSeeIf(struct ScriptContext *ctx)
|
||||
if (ctx->breakOnTrainerBattle && sScriptConditionTable[condition][ctx->comparisonResult] == 1)
|
||||
StopScript(ctx);
|
||||
}
|
||||
|
||||
bool8 ScrFunc_hidefollower(struct ScriptContext *ctx) {
|
||||
bool16 wait = VarGet(ScriptReadHalfword(ctx));
|
||||
struct ObjectEvent *obj;
|
||||
|
||||
if ((obj = ScriptHideFollower()) != NULL && wait) {
|
||||
sMovingNpcId = obj->localId;
|
||||
sMovingNpcMapGroup = obj->mapGroup;
|
||||
sMovingNpcMapNum = obj->mapNum;
|
||||
SetupNativeScript(ctx, WaitForMovementFinish);
|
||||
}
|
||||
|
||||
// Just in case, prevent `applymovement`
|
||||
// from hiding the follower again
|
||||
if (obj)
|
||||
FlagSet(FLAG_SAFE_FOLLOWER_MOVEMENT);
|
||||
|
||||
// execute next script command with no delay
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include "trainer_see.h"
|
||||
#include "util.h"
|
||||
#include "constants/event_objects.h"
|
||||
#include "constants/flags.h"
|
||||
#include "constants/map_scripts.h"
|
||||
#include "field_message_box.h"
|
||||
|
||||
@ -259,6 +260,8 @@ void ScriptContext_SetupScript(const u8 *ptr)
|
||||
InitScriptContext(&sGlobalScriptContext, gScriptCmdTable, gScriptCmdTableEnd);
|
||||
SetupBytecodeScript(&sGlobalScriptContext, ptr);
|
||||
LockPlayerFieldControls();
|
||||
if (OW_MON_SCRIPT_MOVEMENT)
|
||||
FlagSet(FLAG_SAFE_FOLLOWER_MOVEMENT);
|
||||
sGlobalScriptContextStatus = CONTEXT_RUNNING;
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#include "global.h"
|
||||
#include "script_movement.h"
|
||||
#include "event_object_movement.h"
|
||||
#include "event_scripts.h"
|
||||
#include "task.h"
|
||||
#include "util.h"
|
||||
#include "constants/event_objects.h"
|
||||
@ -205,13 +206,34 @@ static void ScriptMovement_MoveObjects(u8 taskId)
|
||||
}
|
||||
}
|
||||
|
||||
// from event_object_movement
|
||||
#define sTypeFuncId data[1]
|
||||
#define sTimer data[5]
|
||||
|
||||
static void ScriptMovement_TakeStep(u8 taskId, u8 moveScrId, u8 objEventId, const u8 *movementScript)
|
||||
{
|
||||
u8 nextMoveActionId;
|
||||
struct ObjectEvent *obj = &gObjectEvents[objEventId];
|
||||
|
||||
if (ObjectEventIsHeldMovementActive(&gObjectEvents[objEventId])
|
||||
&& !ObjectEventClearHeldMovementIfFinished(&gObjectEvents[objEventId]))
|
||||
if (ObjectEventIsHeldMovementActive(obj) &&
|
||||
!ObjectEventClearHeldMovementIfFinished(obj))
|
||||
{
|
||||
// If, while undergoing scripted movement,
|
||||
// a non-player object collides with an active follower pokemon,
|
||||
// put that follower into a pokeball
|
||||
// (sTimer helps limit this expensive check to once per step)
|
||||
if (OW_MON_SCRIPT_MOVEMENT &&
|
||||
gSprites[obj->spriteId].sTimer == 1 &&
|
||||
(objEventId = GetObjectObjectCollidesWith(obj, 0, 0, TRUE)) < OBJECT_EVENTS_COUNT &&
|
||||
// switch `obj` to follower
|
||||
((obj = &gObjectEvents[objEventId])->movementType == MOVEMENT_TYPE_FOLLOW_PLAYER) &&
|
||||
gSprites[obj->spriteId].sTypeFuncId != 0)
|
||||
{
|
||||
ClearObjectEventMovement(obj, &gSprites[obj->spriteId]);
|
||||
ScriptMovement_StartObjectMovementScript(obj->localId, obj->mapNum, obj->mapGroup, EnterPokeballMovement);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
nextMoveActionId = *movementScript;
|
||||
if (nextMoveActionId == MOVEMENT_ACTION_STEP_END)
|
||||
@ -229,3 +251,5 @@ static void ScriptMovement_TakeStep(u8 taskId, u8 moveScrId, u8 objEventId, cons
|
||||
}
|
||||
}
|
||||
|
||||
#undef sTypeFuncId
|
||||
#undef sTimer
|
||||
|
||||
18
src/sprite.c
18
src/sprite.c
@ -1465,7 +1465,7 @@ u16 LoadSpriteSheet(const struct SpriteSheet *sheet)
|
||||
}
|
||||
|
||||
// Like LoadSpriteSheet, but checks if already loaded, and uses template image frames
|
||||
u16 LoadSpriteSheetByTemplateWithOffset(const struct SpriteTemplate *template, u32 frame, s32 offset)
|
||||
u16 LoadSpriteSheetByTemplate(const struct SpriteTemplate *template, u32 frame, s32 offset)
|
||||
{
|
||||
u16 tileStart;
|
||||
struct SpriteSheet sheet;
|
||||
@ -1480,22 +1480,6 @@ u16 LoadSpriteSheetByTemplateWithOffset(const struct SpriteTemplate *template, u
|
||||
return LoadSpriteSheetWithOffset(&sheet, offset);
|
||||
}
|
||||
|
||||
// Like LoadSpriteSheet, but checks if already, and uses template image frames
|
||||
u16 LoadSpriteSheetByTemplate(const struct SpriteTemplate *template, u8 frame)
|
||||
{
|
||||
u16 tileStart;
|
||||
struct SpriteSheet tempSheet;
|
||||
// error if template is null or tile tag or images not set
|
||||
if (!template || template->tileTag == TAG_NONE || !template->images)
|
||||
return 0xFFFF;
|
||||
if ((tileStart = GetSpriteTileStartByTag(template->tileTag)) != 0xFFFF) // return if already loaded
|
||||
return tileStart;
|
||||
tempSheet.data = template->images[frame].data;
|
||||
tempSheet.size = template->images[frame].size;
|
||||
tempSheet.tag = template->tileTag;
|
||||
return LoadSpriteSheet(&tempSheet);
|
||||
}
|
||||
|
||||
void LoadSpriteSheets(const struct SpriteSheet *sheets)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user