5 Make space for EWRAM Data for Summary screen
judicornadamsfoster edited this page 2026-07-17 20:29:45 +01:00

This is an updated guide to make this able to compile with latest pokeemerald code (as of July 2026).

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

--note: GFX_MANAGER_NUM_FRAMES is no longer used, is now MAX_MON_PIC_FRAMES


this can also be pulled from my branch

git remote add tenaya15 https://github.com/tenaya15/tenaya15emerald.git
git pull tenaya15 make_space_for_ewram_data_for_summary_screen

or check out the commit here


Important first step:

run make clean to remove any previously created files. Not doing this can cause corruption in the graphics


src/data.c

in section const union AnimCmd *const gAnims_MonPic[MAX_MON_PIC_FRAMES] = (line 293)

to

const union AnimCmd *const gAnims_MonPic[MAX_MON_PIC_FRAMES] =
{
    sAnim_MonPic_0,
    sAnim_MonPic_1,
};

src/pokemon.c

around line 81, change: EWRAM_DATA static struct MonSpritesGfxManager *sMonSpritesGfxManagers[MON_SPR_GFX_MANAGERS_COUNT] = {NULL};
To

EWRAM_DATA static struct MonSpritesGfxManager *sMonSpritesGfxManager = NULL;

__

in section
void SetMultiuseSpriteTemplateToPokemon(u16 speciesTag, u8 battlerPosition)
around (line 3487)

Replace whole section with:

{
    if (gMonSpritesGfxPtr != NULL)
        gMultiuseSpriteTemplate = gMonSpritesGfxPtr->templates[battlerPosition];
    else if (sMonSpritesGfxManager)
        gMultiuseSpriteTemplate = sMonSpritesGfxManager->templates[battlerPosition];

    gMultiuseSpriteTemplate.paletteTag = speciesTag;
    if (battlerPosition == B_POSITION_PLAYER_LEFT || battlerPosition == B_POSITION_PLAYER_RIGHT)
        gMultiuseSpriteTemplate.anims = gAnims_MonPic;
    else if (speciesTag > SPECIES_SHINY_TAG)
        gMultiuseSpriteTemplate.anims = gMonFrontAnimsPtrTable[speciesTag - SPECIES_SHINY_TAG];
    else
        gMultiuseSpriteTemplate.anims = gMonFrontAnimsPtrTable[speciesTag];
}

__

in section
static void InitMonSpritesGfx_Battle(struct MonSpritesGfxManager* gfx) (now line 7018)
Change the integer u8 to a u32 (on line 7020)
The section should now be:

{
    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 2 below it (now on line 7046)

Change struct MonSpritesGfxManager *CreateMonSpritesGfxManager(u8 managerId, u8 mode)
To

struct MonSpritesGfxManager *CreateMonSpritesGfxManager(void)

Then replace the entire section with

{
    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 = MAX_MON_PIC_FRAMES;
    // Set up sprite / sprite pointer buffers
    gfx->spriteBuffer = AllocZeroed(MON_PIC_SIZE * MAX_MON_PIC_FRAMES * 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 + (MON_PIC_SIZE * MAX_MON_PIC_FRAMES * 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;
}

__

Just below, change void DestroyMonSpritesGfxManager(u8 managerId) (now line 7195)
To

void DestroyMonSpritesGfxManager(void)

Then replace the entire section with:

{
    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, just below, change
u8 *MonSpritesGfxManager_GetSpritePtr(u8 managerId, u8 spriteNum)
To

u8 *MonSpritesGfxManager_GetSpritePtr(u8 spriteNum)

Then replace the entire section with:

{
    struct MonSpritesGfxManager *gfx = sMonSpritesGfxManager;
 
    if (gfx->active)
    {
        if (spriteNum >= gfx->numSprites)
            spriteNum = 0;
 
        return gfx->spritePointers[spriteNum];
    }
    return NULL;
}

include/pokemon.h

in section struct MonSpritesGfxManager (around line 234)
replace the entire section with:

{
    u8 numSprites;
    u8 numFrames;
    bool16 active;
    void *spriteBuffer;
    u8 **spritePointers;
    struct SpriteTemplate *templates;
    struct SpriteFrameImage *frameImages;
};

__

Change the following 3 lines (now around lines 540, 541, 542 at the end of the file)

struct MonSpritesGfxManager *CreateMonSpritesGfxManager(u8 managerId, u8 mode);
void DestroyMonSpritesGfxManager(u8 managerId);
u8 *MonSpritesGfxManager_GetSpritePtr(u8 managerId, u8 spriteNum);

To

struct MonSpritesGfxManager *CreateMonSpritesGfxManager(void);
void DestroyMonSpritesGfxManager(void);
u8 *MonSpritesGfxManager_GetSpritePtr(u8 spriteNum);

src/pokemon_summary_screen.c

in section void ShowPokemonSummaryScreen(u8 mode, void *mons, u8 monIndex, u8 maxMonIndex, void (*callback)(void)) (line 1100)
change CreateMonSpritesGfxManager(MON_SPR_GFX_MANAGER_A, MON_SPR_GFX_MODE_NORMAL); (at line 1137 near the end of the section)
To

        CreateMonSpritesGfxManager();

__

then in section static void CloseSummaryScreen(u8 taskId) (around line 1514)
change DestroyMonSpritesGfxManager(MON_SPR_GFX_MANAGER_A);
to

DestroyMonSpritesGfxManager();

so the section should now be:

{
    if (MenuHelpers_ShouldWaitForLinkRecv() != TRUE && !gPaletteFade.active)
    {
        SetMainCallback2(sMonSummaryScreen->callback);
        gLastViewedMonIndex = sMonSummaryScreen->curMonIndex;
        SummaryScreen_DestroyAnimDelayTask();
        ResetSpriteData();
        FreeAllSpritePalettes();
        StopCryAndClearCrySongs();
        m4aMPlayVolumeControl(&gMPlayInfo_BGM, TRACKS_ALL, 0x100);
        if (gMonSpritesGfxPtr == NULL)
            DestroyMonSpritesGfxManager();
		FreeSummaryScreen();
        DestroyTask(taskId);
    }
}

__

in section static u8 LoadMonGfxAndSprite(struct Pokemon *mon, s16 *state) replace both lines 3942 and 3947
MonSpritesGfxManager_GetSpritePtr(MON_SPR_GFX_MANAGER_A, B_POSITION_OPPONENT_LEFT),
with

MonSpritesGfxManager_GetSpritePtr(B_POSITION_OPPONENT_LEFT),

so the section should now be:

{
    const struct CompressedSpritePalette *pal;
    struct PokeSummary *summary = &sMonSummaryScreen->summary;

    switch (*state)
    {
    default:
        return CreateMonSprite(mon);
    case 0:
        if (gMain.inBattle)
        {
            if (ShouldIgnoreDeoxysForm(3, sMonSummaryScreen->curMonIndex))
                HandleLoadSpecialPokePic_DontHandleDeoxys(&gMonFrontPicTable[summary->species2],
                                                          gMonSpritesGfxPtr->sprites.ptr[B_POSITION_OPPONENT_LEFT],
                                                          summary->species2,
                                                          summary->pid);
            else
                HandleLoadSpecialPokePic_2(&gMonFrontPicTable[summary->species2],
                                           gMonSpritesGfxPtr->sprites.ptr[B_POSITION_OPPONENT_LEFT],
                                           summary->species2,
                                           summary->pid);
        }
        else
        {
            if (gMonSpritesGfxPtr != NULL)
            {
                if (sMonSummaryScreen->monList.mons == gPlayerParty || sMonSummaryScreen->mode == SUMMARY_MODE_BOX || sMonSummaryScreen->handleDeoxys == TRUE)
                    HandleLoadSpecialPokePic_2(&gMonFrontPicTable[summary->species2],
                                               gMonSpritesGfxPtr->sprites.ptr[B_POSITION_OPPONENT_LEFT],
                                               summary->species2,
                                               summary->pid);
                else
                    HandleLoadSpecialPokePic_DontHandleDeoxys(&gMonFrontPicTable[summary->species2],
                                                              gMonSpritesGfxPtr->sprites.ptr[B_POSITION_OPPONENT_LEFT],
                                                              summary->species2,
                                                              summary->pid);
            }
            else
            {
                if (sMonSummaryScreen->monList.mons == gPlayerParty || sMonSummaryScreen->mode == SUMMARY_MODE_BOX || sMonSummaryScreen->handleDeoxys == TRUE)
                    HandleLoadSpecialPokePic_2(&gMonFrontPicTable[summary->species2],
                                                MonSpritesGfxManager_GetSpritePtr(B_POSITION_OPPONENT_LEFT),
                                                summary->species2,
                                                summary->pid);
                else
                    HandleLoadSpecialPokePic_DontHandleDeoxys(&gMonFrontPicTable[summary->species2],
                                                              MonSpritesGfxManager_GetSpritePtr(B_POSITION_OPPONENT_LEFT),
                                                              summary->species2,
                                                              summary->pid);
            }
        }
        (*state)++;
        return 0xFF;
    case 1:
        pal = GetMonSpritePalStructFromOtIdPersonality(summary->species2, summary->OTID, summary->pid);
        LoadCompressedSpritePalette(pal);
        SetMultiuseSpriteTemplateToPokemon(pal->tag, B_POSITION_OPPONENT_LEFT);
        (*state)++;
        return 0xFF;
    }
}

include/constants/pokemon.h

line 272 (near the end of file)
#define MAX_MON_PIC_FRAMES 4

Change this to

#define MAX_MON_PIC_FRAMES 2

Original Guide (retained for archival purpose)

SonikkuA-DatH / Oct 17, 2021

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