The summary screen in RSE is surprisingly wasteful, which for Castform in particular has it so all forms are loaded in memory, despite only using 1. This tweak will fix it so it's more optimized
Thanks to ShinyDragonHunter for this
First, we'll set up this struct in src/pokemon.c
- EWRAM_DATA static struct MonSpritesGfxManager *sMonSpritesGfxManagers[MON_SPR_GFX_MANAGERS_COUNT] = {NULL};
+ EWRAM_DATA static struct MonSpritesGfxManager *sMonSpritesGfxManager = NULL;
Then, we'll set up InitMonSpritesGfx_Battle function near bottom to do the following
Change this
void SetMultiuseSpriteTemplateToPokemon(u16 speciesTag, u8 battlerPosition)
{
if (gMonSpritesGfxPtr != NULL)
gMultiuseSpriteTemplate = gMonSpritesGfxPtr->templates[battlerPosition];
else if (sMonSpritesGfxManagers[MON_SPR_GFX_MANAGER_A])
gMultiuseSpriteTemplate = sMonSpritesGfxManagers[MON_SPR_GFX_MANAGER_A]->templates[battlerPosition];
else if (sMonSpritesGfxManagers[MON_SPR_GFX_MANAGER_B])
gMultiuseSpriteTemplate = sMonSpritesGfxManagers[MON_SPR_GFX_MANAGER_B]->templates[battlerPosition];
else
gMultiuseSpriteTemplate = gBattlerSpriteTemplates[battlerPosition];
To
void SetMultiuseSpriteTemplateToPokemon(u16 speciesTag, u8 battlerPosition)
{
if (gMonSpritesGfxPtr != NULL)
gMultiuseSpriteTemplate = gMonSpritesGfxPtr->templates[battlerPosition];
else if (sMonSpritesGfxManager)
gMultiuseSpriteTemplate = sMonSpritesGfxManager->templates[battlerPosition];
Change the integer to a u32 (current version)
static void InitMonSpritesGfx_Battle(struct MonSpritesGfxManager* gfx)
{
- u16 i, j;
+ u32 i, j;
for (i = 0; i < gfx->numSprites; i++)
{
gfx->templates[i] = gBattlerSpriteTemplates[i];
for (j = 0; j < gfx->numFrames; j++)
gfx->frameImages[i * gfx->numFrames + j].data = &gfx->spritePointers[i][j * MON_PIC_SIZE];
gfx->templates[i].images = &gfx->frameImages[i * gfx->numFrames];
}
}
Next, in the struct below it (this is big) change
struct MonSpritesGfxManager *CreateMonSpritesGfxManager(u8 managerId, u8 mode)
{
u8 i;
u8 failureFlags;
struct MonSpritesGfxManager *gfx;
failureFlags = 0;
managerId %= MON_SPR_GFX_MANAGERS_COUNT;
gfx = AllocZeroed(sizeof(*gfx));
if (gfx == NULL)
return NULL;
switch (mode)
{
case MON_SPR_GFX_MODE_FULL_PARTY:
gfx->numSprites = PARTY_SIZE + 1;
gfx->numSprites2 = PARTY_SIZE + 1;
gfx->numFrames = GFX_MANAGER_NUM_FRAMES;
gfx->dataSize = 1;
gfx->mode = MON_SPR_GFX_MODE_FULL_PARTY;
break;
// case MON_SPR_GFX_MODE_BATTLE:
case MON_SPR_GFX_MODE_NORMAL:
default:
gfx->numSprites = MAX_BATTLERS_COUNT;
gfx->numSprites2 = MAX_BATTLERS_COUNT;
gfx->numFrames = GFX_MANAGER_NUM_FRAMES;
gfx->dataSize = 1;
gfx->mode = MON_SPR_GFX_MODE_NORMAL;
break;
}
// Set up sprite / sprite pointer buffers
gfx->spriteBuffer = AllocZeroed(gfx->dataSize * GFX_MANAGER_SPR_SIZE * gfx->numSprites);
gfx->spritePointers = AllocZeroed(gfx->numSprites * 32); // ? Only * 4 is necessary, perhaps they were thinking bits.
if (gfx->spriteBuffer == NULL || gfx->spritePointers == NULL)
{
failureFlags |= ALLOC_FAIL_BUFFER;
}
else
{
for (i = 0; i < gfx->numSprites; i++)
gfx->spritePointers[i] = gfx->spriteBuffer + (gfx->dataSize * GFX_MANAGER_SPR_SIZE * i);
}
// Set up sprite structs
gfx->templates = AllocZeroed(sizeof(struct SpriteTemplate) * gfx->numSprites);
gfx->frameImages = AllocZeroed(sizeof(struct SpriteFrameImage) * gfx->numSprites * gfx->numFrames);
if (gfx->templates == NULL || gfx->frameImages == NULL)
{
failureFlags |= ALLOC_FAIL_STRUCT;
}
else
{
for (i = 0; i < gfx->numFrames * gfx->numSprites; i++)
gfx->frameImages[i].size = MON_PIC_SIZE;
switch (gfx->mode)
{
case MON_SPR_GFX_MODE_FULL_PARTY:
InitMonSpritesGfx_FullParty(gfx);
break;
case MON_SPR_GFX_MODE_NORMAL:
case MON_SPR_GFX_MODE_BATTLE:
default:
InitMonSpritesGfx_Battle(gfx);
break;
}
}
// If either of the allocations failed free their respective members
if (failureFlags & ALLOC_FAIL_STRUCT)
{
TRY_FREE_AND_SET_NULL(gfx->frameImages);
TRY_FREE_AND_SET_NULL(gfx->templates);
}
if (failureFlags & ALLOC_FAIL_BUFFER)
{
TRY_FREE_AND_SET_NULL(gfx->spritePointers);
TRY_FREE_AND_SET_NULL(gfx->spriteBuffer);
}
if (failureFlags)
{
// Clear, something failed to allocate
memset(gfx, 0, sizeof(*gfx));
Free(gfx);
}
else
{
gfx->active = GFX_MANAGER_ACTIVE;
sMonSpritesGfxManagers[managerId] = gfx;
}
return sMonSpritesGfxManagers[managerId];
}
To
struct MonSpritesGfxManager *CreateMonSpritesGfxManager(void)
{
u32 i;
u8 failureFlags;
struct MonSpritesGfxManager *gfx;
failureFlags = 0;
gfx = AllocZeroed(sizeof(*gfx));
if (gfx == NULL)
return NULL;
gfx->numSprites = MAX_BATTLERS_COUNT;
gfx->numFrames = GFX_MANAGER_NUM_FRAMES;
gfx->spriteBuffer = AllocZeroed(GFX_MANAGER_SPR_SIZE * gfx->numSprites);
gfx->spritePointers = AllocZeroed(gfx->numSprites * 4);
if (gfx->spriteBuffer == NULL || gfx->spritePointers == NULL)
{
failureFlags |= ALLOC_FAIL_BUFFER;
}
else
{
for (i = 0; i < gfx->numSprites; i++)
gfx->spritePointers[i] = gfx->spriteBuffer + (GFX_MANAGER_SPR_SIZE * i);
}
// Set up sprite structs
gfx->templates = AllocZeroed(sizeof(struct SpriteTemplate) * gfx->numSprites);
gfx->frameImages = AllocZeroed(sizeof(struct SpriteFrameImage) * gfx->numSprites * gfx->numFrames);
if (gfx->templates == NULL || gfx->frameImages == NULL)
{
failureFlags |= ALLOC_FAIL_STRUCT;
}
else
{
for (i = 0; i < gfx->numFrames * gfx->numSprites; i++)
gfx->frameImages[i].size = MON_PIC_SIZE;
InitMonSpritesGfx_Battle(gfx);
}
// If either of the allocations failed free their respective members
if (failureFlags & ALLOC_FAIL_STRUCT)
{
TRY_FREE_AND_SET_NULL(gfx->frameImages);
TRY_FREE_AND_SET_NULL(gfx->templates);
}
if (failureFlags & ALLOC_FAIL_BUFFER)
{
TRY_FREE_AND_SET_NULL(gfx->spritePointers);
TRY_FREE_AND_SET_NULL(gfx->spriteBuffer);
}
if (failureFlags)
{
// Clear, something failed to allocate
memset(gfx, 0, sizeof(*gfx));
Free(gfx);
}
else
{
gfx->active = TRUE;
sMonSpritesGfxManager = gfx;
}
return sMonSpritesGfxManager;
}
Then this
void DestroyMonSpritesGfxManager(u8 managerId)
{
struct MonSpritesGfxManager *gfx;
managerId %= MON_SPR_GFX_MANAGERS_COUNT;
gfx = sMonSpritesGfxManagers[managerId];
if (gfx == NULL)
return;
if (gfx->active != GFX_MANAGER_ACTIVE)
{
memset(gfx, 0, sizeof(*gfx));
}
else
{
TRY_FREE_AND_SET_NULL(gfx->frameImages);
TRY_FREE_AND_SET_NULL(gfx->templates);
TRY_FREE_AND_SET_NULL(gfx->spritePointers);
TRY_FREE_AND_SET_NULL(gfx->spriteBuffer);
memset(gfx, 0, sizeof(*gfx));
Free(gfx);
}
}
To
void DestroyMonSpritesGfxManager(void)
{
struct MonSpritesGfxManager *gfx = sMonSpritesGfxManager;
if (gfx == NULL)
return;
if (gfx->active)
{
TRY_FREE_AND_SET_NULL(gfx->frameImages);
TRY_FREE_AND_SET_NULL(gfx->templates);
TRY_FREE_AND_SET_NULL(gfx->spritePointers);
TRY_FREE_AND_SET_NULL(gfx->spriteBuffer);
memset(gfx, 0, sizeof(*gfx));
Free(gfx);
}
else
memset(gfx, 0, sizeof(*gfx));
}
And finally, this
u8 *MonSpritesGfxManager_GetSpritePtr(u8 managerId, u8 spriteNum)
{
struct MonSpritesGfxManager *gfx = sMonSpritesGfxManagers[managerId % MON_SPR_GFX_MANAGERS_COUNT];
if (gfx->active != GFX_MANAGER_ACTIVE)
{
return NULL;
}
else
{
if (spriteNum >= gfx->numSprites)
spriteNum = 0;
return gfx->spritePointers[spriteNum];
}
}
To this
u8 *MonSpritesGfxManager_GetSpritePtr(u8 spriteNum)
{
struct MonSpritesGfxManager *gfx = sMonSpritesGfxManager;
if (gfx->active)
{
if (spriteNum >= gfx->numSprites)
spriteNum = 0;
return gfx->spritePointers[spriteNum];
}
return NULL;
}
After all that, head on to include/pokemon.h to reduce this
struct MonSpritesGfxManager
{
u32 numSprites:4;
u32 numSprites2:4; // Never read
u32 numFrames:8;
u32 active:8;
u32 dataSize:4;
u32 mode:4; // MON_SPR_GFX_MODE_*
void *spriteBuffer;
u8 **spritePointers;
struct SpriteTemplate *templates;
struct SpriteFrameImage *frameImages;
};
To this
struct MonSpritesGfxManager
{
u8 numSprites;
u8 numFrames;
bool16 active;
void *spriteBuffer;
u8 **spritePointers;
struct SpriteTemplate *templates;
struct SpriteFrameImage *frameImages;
};
And then the void changes of these
- struct MonSpritesGfxManager *CreateMonSpritesGfxManager(u8 managerId, u8 mode);
- void DestroyMonSpritesGfxManager(u8 managerId);
- u8 *MonSpritesGfxManager_GetSpritePtr(u8 managerId, u8 spriteNum);
+ struct MonSpritesGfxManager *CreateMonSpritesGfxManager(void);
+ void DestroyMonSpritesGfxManager(void);
+ u8 *MonSpritesGfxManager_GetSpritePtr(u8 spriteNum);
Along with in src/pokemon_summary_screen.c
if (gMonSpritesGfxPtr == NULL)
- CreateMonSpritesGfxManager(MON_SPR_GFX_MANAGER_A, MON_SPR_GFX_MODE_NORMAL);
+ CreateMonSpritesGfxManager();
and
static void CloseSummaryScreen(u8 taskId)
{
if (MenuHelpers_CallLinkSomething() != TRUE && !gPaletteFade.active)
{
SetMainCallback2(sMonSummaryScreen->callback);
gLastViewedMonIndex = sMonSummaryScreen->curMonIndex;
SummaryScreen_DestroyAnimDelayTask();
ResetSpriteData();
FreeAllSpritePalettes();
StopCryAndClearCrySongs();
m4aMPlayVolumeControl(&gMPlayInfo_BGM, 0xFFFF, 0x100);
if (gMonSpritesGfxPtr == NULL)
- DestroyMonSpritesGfxManager(MON_SPR_GFX_MANAGER_A);
+ DestroyMonSpritesGfxManager();
FreeSummaryScreen();
DestroyTask(taskId);
}
}
And in static u8 LoadMonGfxAndSprite
if (sMonSummaryScreen->monList.mons == gPlayerParty || sMonSummaryScreen->mode == SUMMARY_MODE_BOX || sMonSummaryScreen->unk40EF == TRUE)
HandleLoadSpecialPokePic_2(&gMonFrontPicTable[summary->species2],
- MonSpritesGfxManager_GetSpritePtr(MON_SPR_GFX_MANAGER_A, B_POSITION_OPPONENT_LEFT),
+ MonSpritesGfxManager_GetSpritePtr(B_POSITION_OPPONENT_LEFT),
summary->species2,
summary->pid);
else
HandleLoadSpecialPokePic_DontHandleDeoxys(&gMonFrontPicTable[summary->species2],
- MonSpritesGfxManager_GetSpritePtr(MON_SPR_GFX_MANAGER_A, B_POSITION_OPPONENT_LEFT),
+ MonSpritesGfxManager_GetSpritePtr(B_POSITION_OPPONENT_LEFT),
summary->species2,
summary->pid);
With all this set, you can edit the frames used on the summary screen to whatever you want
Going back to src/pokemon.c
#define ALLOC_FAIL_BUFFER (1 << 0)
#define ALLOC_FAIL_STRUCT (1 << 1)
#define GFX_MANAGER_ACTIVE 0xA3 // Arbitrary value
#define GFX_MANAGER_SPR_SIZE (MON_PIC_SIZE * 4) // * 4 is unnecessary, MON_PIC_SIZE is sufficient
#define GFX_MANAGER_NUM_FRAMES 4 // Only 2 frames are needed
Change #define GFX_MANAGER_NUM_FRAMES 4
to whatever value you want. 2 is typically preferred
If you're crazy enough to add more Castform forms later, #define GFX_MANAGER_SPR_SIZE (MON_PIC_SIZE * 4)
will need to be increased to compensate added forms
Otherwise
- #define GFX_MANAGER_NUM_FRAMES 4
+ #define GFX_MANAGER_NUM_FRAMES 2
And you're done