Add option to hide substitute followers (#4765)

* Add option to hide substitute followers

* Update event_object_movement.c
This commit is contained in:
Bassoonian 2024-06-12 19:53:01 +02:00 committed by GitHub
parent 76c566a0ca
commit 03cc0ae6b3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 21 additions and 17 deletions

View File

@ -37,13 +37,14 @@
// Follower Pokémon // Follower Pokémon
#define OW_FOLLOWERS_ENABLED TRUE // Enables follower Pokémon, HGSS style. #define OW_FOLLOWERS_ENABLED TRUE // Enables follower Pokémon, HGSS style.
#define OW_MON_BOBBING TRUE // If true, follower pokemon will bob up and down during their idle & walking animations #define OW_MON_BOBBING TRUE // If true, follower pokemon will bob up and down during their idle & walking animations
#define LARGE_OW_SUPPORT TRUE // If true, adds a small amount of overhead to OW code so that large (48x48, 64x64) OWs will display correctly under bridges, etc. #define OW_LARGE_OW_SUPPORT TRUE // If true, adds a small amount of overhead to OW code so that large (48x48, 64x64) OWs will display correctly under bridges, etc.
#define OW_FOLLOWERS_SHARE_PALETTE FALSE // [WIP!! NOT ALL PALETTES HAVE BEEN ADJUSTED FOR THIS!!] If TRUE, follower palettes are taken from battle sprites. #define OW_FOLLOWERS_SHARE_PALETTE FALSE // [WIP!! NOT ALL PALETTES HAVE BEEN ADJUSTED FOR THIS!!] If TRUE, follower palettes are taken from battle sprites.
#define OW_MON_POKEBALLS TRUE // Followers will emerge from the pokeball they are stored in, instead of a normal pokeball #define OW_MON_POKEBALLS TRUE // Followers will emerge from the pokeball they are stored in, instead of a normal pokeball
#define OW_GFX_COMPRESS TRUE // Adds support for compressed OW graphics, (Also compresses pokemon follower graphics). #define OW_GFX_COMPRESS TRUE // Adds support for compressed OW graphics, (Also compresses pokemon follower graphics).
// Compressed gfx are incompatible with non-power-of-two sprite sizes: // Compressed gfx are incompatible with non-power-of-two sprite sizes:
// (You should not use 48x48 sprites/tables for compressed gfx) // (You should not use 48x48 sprites/tables for compressed gfx)
// 16x32, 32x32, 64x64 etc are fine // 16x32, 32x32, 64x64 etc are fine
#define OW_SUBSTITUTE_PLACEHOLDER TRUE // Use a substitute OW for Pokémon that are missing overworld sprites
// Out-of-battle Ability effects // 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. #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.

View File

@ -1416,7 +1416,7 @@ static const struct SubspriteTable sOamTables_88x32[] = {
{ARRAY_COUNT(sOamTable_88x32_3), sOamTable_88x32_3} {ARRAY_COUNT(sOamTable_88x32_3), sOamTable_88x32_3}
}; };
#if LARGE_OW_SUPPORT #if OW_LARGE_OW_SUPPORT
// These tables allow (virtual) sprite sizes so that // These tables allow (virtual) sprite sizes so that
// some space can be saved by making graphics smaller. // some space can be saved by making graphics smaller.
// Note: When using these for followers, the minimum // Note: When using these for followers, the minimum

View File

@ -1890,10 +1890,12 @@ static const struct ObjectEventGraphicsInfo *SpeciesToGraphicsInfo(u16 species,
break; break;
} }
// Try to avoid OOB or undefined access // Try to avoid OOB or undefined access
if (graphicsInfo->tileTag == 0 && species < NUM_SPECIES) if ((graphicsInfo->tileTag == 0 && species < NUM_SPECIES) || (graphicsInfo->tileTag != TAG_NONE && species >= NUM_SPECIES))
return &gSpeciesInfo[SPECIES_NONE].followerData; {
else if (graphicsInfo->tileTag != TAG_NONE && species >= NUM_SPECIES) if (OW_SUBSTITUTE_PLACEHOLDER)
return &gSpeciesInfo[SPECIES_NONE].followerData; return &gSpeciesInfo[SPECIES_NONE].followerData;
return NULL;
}
#endif #endif
return graphicsInfo; return graphicsInfo;
} }
@ -1983,7 +1985,7 @@ static void RefreshFollowerGraphics(struct ObjectEvent *objEvent)
if (graphicsInfo->oam->size != sprite->oam.size) if (graphicsInfo->oam->size != sprite->oam.size)
{ {
if (LARGE_OW_SUPPORT && !OW_GFX_COMPRESS) if (OW_LARGE_OW_SUPPORT && !OW_GFX_COMPRESS)
ReallocSpriteTiles(sprite, graphicsInfo->images->size); ReallocSpriteTiles(sprite, graphicsInfo->images->size);
// Add difference in Y vectors // Add difference in Y vectors
sprite->y += -(graphicsInfo->height >> 1) - sprite->centerToCornerVecY; sprite->y += -(graphicsInfo->height >> 1) - sprite->centerToCornerVecY;
@ -2077,7 +2079,8 @@ void UpdateFollowingPokemon(void)
// 3. flag is set // 3. flag is set
if (OW_FOLLOWERS_ENABLED == FALSE if (OW_FOLLOWERS_ENABLED == FALSE
|| !GetFollowerInfo(&species, &form, &shiny) || !GetFollowerInfo(&species, &form, &shiny)
|| (gMapHeader.mapType == MAP_TYPE_INDOOR && SpeciesToGraphicsInfo(species, 0)->oam->size > ST_OAM_SIZE_2) || SpeciesToGraphicsInfo(species, form) == NULL
|| (gMapHeader.mapType == MAP_TYPE_INDOOR && SpeciesToGraphicsInfo(species, form)->oam->size > ST_OAM_SIZE_2)
|| FlagGet(FLAG_TEMP_HIDE_FOLLOWER)) || FlagGet(FLAG_TEMP_HIDE_FOLLOWER))
{ {
RemoveFollowingPokemon(); RemoveFollowingPokemon();
@ -2636,7 +2639,7 @@ static void ObjectEventSetGraphics(struct ObjectEvent *objectEvent, const struct
UpdateSpritePalette(&sObjectEventSpritePalettes[i], sprite); UpdateSpritePalette(&sObjectEventSpritePalettes[i], sprite);
// If gfx size changes, we need to reallocate tiles // If gfx size changes, we need to reallocate tiles
if (LARGE_OW_SUPPORT && !OW_GFX_COMPRESS && graphicsInfo->oam->size != sprite->oam.size) if (OW_LARGE_OW_SUPPORT && !OW_GFX_COMPRESS && graphicsInfo->oam->size != sprite->oam.size)
ReallocSpriteTiles(sprite, graphicsInfo->images->size); ReallocSpriteTiles(sprite, graphicsInfo->images->size);
#if OW_GFX_COMPRESS #if OW_GFX_COMPRESS
@ -7147,7 +7150,7 @@ bool8 MovementAction_ExitPokeball_Step1(struct ObjectEvent *objectEvent, struct
LoadFillColorPalette(RGB_WHITE, OBJ_EVENT_PAL_TAG_WHITE, sprite); LoadFillColorPalette(RGB_WHITE, OBJ_EVENT_PAL_TAG_WHITE, sprite);
// Initialize affine animation // Initialize affine animation
sprite->affineAnims = sAffineAnims_PokeballFollower; sprite->affineAnims = sAffineAnims_PokeballFollower;
if (LARGE_OW_SUPPORT && !IS_POW_OF_TWO(-sprite->centerToCornerVecX)) if (OW_LARGE_OW_SUPPORT && !IS_POW_OF_TWO(-sprite->centerToCornerVecX))
return FALSE; return FALSE;
sprite->affineAnims = sAffineAnims_PokeballFollower; sprite->affineAnims = sAffineAnims_PokeballFollower;
sprite->oam.affineMode = ST_OAM_AFFINE_NORMAL; sprite->oam.affineMode = ST_OAM_AFFINE_NORMAL;
@ -7194,7 +7197,7 @@ bool8 MovementAction_EnterPokeball_Step1(struct ObjectEvent *objectEvent, struct
sprite->subspriteTableNum = 0; sprite->subspriteTableNum = 0;
// Only do affine if sprite width is power of 2 // Only do affine if sprite width is power of 2
// (effect looks weird on sprites composed of subsprites like 48x48, etc) // (effect looks weird on sprites composed of subsprites like 48x48, etc)
if (LARGE_OW_SUPPORT && !IS_POW_OF_TWO(-sprite->centerToCornerVecX)) if (OW_LARGE_OW_SUPPORT && !IS_POW_OF_TWO(-sprite->centerToCornerVecX))
return FALSE; return FALSE;
sprite->affineAnims = sAffineAnims_PokeballFollower; sprite->affineAnims = sAffineAnims_PokeballFollower;
sprite->oam.affineMode = ST_OAM_AFFINE_NORMAL; sprite->oam.affineMode = ST_OAM_AFFINE_NORMAL;
@ -9237,7 +9240,7 @@ static void UpdateObjectEventElevationAndPriority(struct ObjectEvent *objEvent,
{ {
// keep subspriteMode synced with player's // keep subspriteMode synced with player's
// so that it disappears under bridges when they do // so that it disappears under bridges when they do
if (LARGE_OW_SUPPORT) if (OW_LARGE_OW_SUPPORT)
sprite->subspriteMode |= gSprites[gPlayerAvatar.spriteId].subspriteMode & SUBSPRITES_IGNORE_PRIORITY; sprite->subspriteMode |= gSprites[gPlayerAvatar.spriteId].subspriteMode & SUBSPRITES_IGNORE_PRIORITY;
// if transitioning between elevations, use the player's elevation // if transitioning between elevations, use the player's elevation
if (!objEvent->currentElevation) if (!objEvent->currentElevation)
@ -9269,7 +9272,7 @@ void ObjectEventUpdateElevation(struct ObjectEvent *objEvent, struct Sprite *spr
{ {
// Ignore subsprite priorities under bridges // Ignore subsprite priorities under bridges
// so all subsprites will display below it // so all subsprites will display below it
if (LARGE_OW_SUPPORT) if (OW_LARGE_OW_SUPPORT)
sprite->subspriteMode = SUBSPRITES_IGNORE_PRIORITY; sprite->subspriteMode = SUBSPRITES_IGNORE_PRIORITY;
return; return;
} }
@ -9667,7 +9670,7 @@ static void DoGroundEffects_OnSpawn(struct ObjectEvent *objEvent, struct Sprite
#endif #endif
{ {
flags = 0; flags = 0;
if (LARGE_OW_SUPPORT && !sprite->oam.affineMode) if (OW_LARGE_OW_SUPPORT && !sprite->oam.affineMode)
sprite->subspriteMode = SUBSPRITES_ON; sprite->subspriteMode = SUBSPRITES_ON;
UpdateObjectEventElevationAndPriority(objEvent, sprite); UpdateObjectEventElevationAndPriority(objEvent, sprite);
GetAllGroundEffectFlags_OnSpawn(objEvent, &flags); GetAllGroundEffectFlags_OnSpawn(objEvent, &flags);
@ -9689,7 +9692,7 @@ static void DoGroundEffects_OnBeginStep(struct ObjectEvent *objEvent, struct Spr
#endif #endif
{ {
flags = 0; flags = 0;
if (LARGE_OW_SUPPORT && !sprite->oam.affineMode) if (OW_LARGE_OW_SUPPORT && !sprite->oam.affineMode)
sprite->subspriteMode = SUBSPRITES_ON; sprite->subspriteMode = SUBSPRITES_ON;
UpdateObjectEventElevationAndPriority(objEvent, sprite); UpdateObjectEventElevationAndPriority(objEvent, sprite);
GetAllGroundEffectFlags_OnBeginStep(objEvent, &flags); GetAllGroundEffectFlags_OnBeginStep(objEvent, &flags);

View File

@ -353,7 +353,7 @@ u32 FldEff_Shadow(void)
gSprites[spriteId].sLocalId = gFieldEffectArguments[0]; gSprites[spriteId].sLocalId = gFieldEffectArguments[0];
gSprites[spriteId].sMapNum = gFieldEffectArguments[1]; gSprites[spriteId].sMapNum = gFieldEffectArguments[1];
gSprites[spriteId].sMapGroup = gFieldEffectArguments[2]; gSprites[spriteId].sMapGroup = gFieldEffectArguments[2];
#if LARGE_OW_SUPPORT #if OW_LARGE_OW_SUPPORT
gSprites[spriteId].sYOffset = gShadowVerticalOffsets[graphicsInfo->shadowSize]; gSprites[spriteId].sYOffset = gShadowVerticalOffsets[graphicsInfo->shadowSize];
#else #else
gSprites[spriteId].sYOffset = (graphicsInfo->height >> 1) - gShadowVerticalOffsets[graphicsInfo->shadowSize]; gSprites[spriteId].sYOffset = (graphicsInfo->height >> 1) - gShadowVerticalOffsets[graphicsInfo->shadowSize];
@ -376,7 +376,7 @@ void UpdateShadowFieldEffect(struct Sprite *sprite)
struct Sprite *linkedSprite = &gSprites[objectEvent->spriteId]; struct Sprite *linkedSprite = &gSprites[objectEvent->spriteId];
sprite->oam.priority = linkedSprite->oam.priority; sprite->oam.priority = linkedSprite->oam.priority;
sprite->x = linkedSprite->x; sprite->x = linkedSprite->x;
#if LARGE_OW_SUPPORT #if OW_LARGE_OW_SUPPORT
// Read 'live' size from linked sprite // Read 'live' size from linked sprite
sprite->y = linkedSprite->y - linkedSprite->centerToCornerVecY - sprite->sYOffset; sprite->y = linkedSprite->y - linkedSprite->centerToCornerVecY - sprite->sYOffset;
#else #else