Dynamic overworld palette system - pret/pokeemerald GitHub Wiki

TODO: Update this tutorial properly, explaining the changes that are made and the reasoning behind. NOTE This tutorial is a work in progress. Will add everything eventually, but currently I (smithk200) am adding this bit by bit. This is a long thing to write!

Goal: To replace the static overworld palettes with a dynamic system that loads the correct palette slot when you are playing the game, versus the palette slots being hardcoded when the game begins.

The most up to date code at time of writing can be found here. This also fixes some of the problems with the below system, like broken reflections and berry trees.

If you don't want to pull from a repository, you can look at this link here, and make the changes accordingly: https://github.com/pret/pokeemerald/compare/master...ExpoSeed:pokeemerald:dynamic-ow-pals

1. include/event_object_movement.h

First, remove this line:

- extern const u8 gReflectionEffectPaletteMap[];

Then, change these two lines

extern const u8 *const gBerryTreeObjectEventGraphicsIdTablePointers[];
extern const u8 *const gBerryTreePaletteSlotTablePointers[];

to this.

extern const u16 *const gBerryTreeObjectEventGraphicsIdTablePointers[];
extern const u16 *const gBerryTreePaletteSlotTablePointers[];

Finally, after these lines,

s16 GetFigure8XOffset(s16 idx);
s16 GetFigure8YOffset(s16 idx);
void CameraObjectReset2(void);

add this one.

void LoadObjectEventPalette(u16 paletteTag);

2. include/field_effect_helpers.h

After this line

void ShowWarpArrowSprite(u8 spriteId, u8 direction, s16 x, s16 y);

add this:

void LoadFieldEffectPalette(u8 fieldEffect);

3. include/field_weather.h

After this line extern const u16 gFogPalette[];

add this:

enum
{
    GAMMA_NONE,
    GAMMA_NORMAL,
    GAMMA_ALT,
};

void UpdatePaletteGammaType(u8 index, u8 gammaType);

Next, find this line: void LoadCustomWeatherSpritePalette(const u16 *palette);

And change it to this: void LoadCustomWeatherSpritePalette(const struct SpritePalette *palette);

4. src/event_object_movement.c

Add #include "field_weather.h"

after this line: #include "field_effect_helpers.h"

Add #include "data/object_events/object_event_graphics_info_pointers.h"

after #include "data/object_events/object_event_graphics_info.h"

Delete all the ReflectionPaletteTags from sReflectionPaletteTags_Brendan to sObjectPaletteTagSets.

Replace this function

static void RemoveObjectEventInternal(struct ObjectEvent *objectEvent)

{
    struct SpriteFrameImage image;
    image.size = GetObjectEventGraphicsInfo(objectEvent->graphicsId)->size;
    gSprites[objectEvent->spriteId].images = ℑ
    DestroySprite(&gSprites[objectEvent->spriteId]);
}

with this one.

static void RemoveObjectEventInternal(struct ObjectEvent *objectEvent)

{
    u8 paletteNum;
    struct SpriteFrameImage image;
    image.size = GetObjectEventGraphicsInfo(objectEvent->graphicsId)->size;
    gSprites[objectEvent->spriteId].images = ℑ
    paletteNum = gSprites[objectEvent->spriteId].oam.paletteNum;

    DestroySprite(&gSprites[objectEvent->spriteId]);
    FieldEffectFreePaletteIfUnused(paletteNum);

}

Replace this

paletteSlot = graphicsInfo->paletteSlot;
if (paletteSlot == 0)
    {
        LoadPlayerObjectReflectionPalette(graphicsInfo->paletteTag, 0);
    }
    else if (paletteSlot == 10)
    {
        LoadSpecialObjectReflectionPalette(graphicsInfo->paletteTag, 10);
    }
    else if (paletteSlot >= 16)

    {
        paletteSlot -= 16;
        _PatchObjectPalette(graphicsInfo->paletteTag, paletteSlot);

    }
    if (objectEvent->movementType == MOVEMENT_TYPE_INVISIBLE)

        objectEvent->invisible = TRUE;
    *(u16 *)&spriteTemplate->paletteTag = 0xFFFF;

with this.

if (spriteTemplate->paletteTag != 0xFFFF)
    {
        LoadObjectEventPalette(spriteTemplate->paletteTag);
        UpdatePaletteGammaType(IndexOfSpritePaletteTag(spriteTemplate->paletteTag), GAMMA_ALT);
    }

Next, find this line and remove it:

*(u16 *)&spriteTemplate->paletteTag = 0xFFFF;

Next, find this line:

if (graphicsInfo->paletteSlot == 10)
        {
            LoadSpecialObjectReflectionPalette(graphicsInfo->paletteTag, graphicsInfo->paletteSlot);

        }

        else if (graphicsInfo->paletteSlot >= 16)

and replace it with this:

if (graphicsInfo->paletteSlot >= 16)

Next, navigate to this line:

objectEvent->movementType, &spriteTemplate, &subspriteTables);

    spriteTemplate.images = &spriteFrameImage;

Remove this:

*(u16 *)&spriteTemplate.paletteTag = 0xFFFF;
    paletteSlot = graphicsInfo->paletteSlot;
    if (paletteSlot == 0)
    {
       LoadPlayerObjectReflectionPalette(graphicsInfo->paletteTag, graphicsInfo->paletteSlot);
    }
    else if (paletteSlot == 10)

    {
        LoadSpecialObjectReflectionPalette(graphicsInfo->paletteTag, graphicsInfo->paletteSlot);
    }
    else if (paletteSlot >= 16)
    {
        paletteSlot -= 16;
        _PatchObjectPalette(graphicsInfo->paletteTag, paletteSlot);
    }
    *(u16 *)&spriteTemplate.paletteTag = 0xFFFF;

Replace it with this:

if (spriteTemplate.paletteTag != 0xFFFF)
    {
        LoadObjectEventPalette(spriteTemplate.paletteTag);
        UpdatePaletteGammaType(IndexOfSpritePaletteTag(spriteTemplate.paletteTag), GAMMA_ALT);
    }

After this line

if (berryId > ITEM_TO_BERRY(LAST_BERRY_INDEX))

            berryId = 0;

add this (this is for the berry trees)

LoadObjectEventPalette(gBerryTreePaletteTagTablePointers[berryId][berryStage]);

Replace this line: sprite->oam.paletteNum = gBerryTreePaletteSlotTablePointers[berryId][berryStage];

with this:

sprite->oam.paletteNum = IndexOfSpritePaletteTag(gBerryTreePaletteTagTablePointers[berryId][berryStage]);


        UpdatePaletteGammaType(sprite->oam.paletteNum, GAMMA_ALT);

Delete the entire functions LoadPlayerObjectReflectionPalette, LoadSpecialObjectReflectionPalette, InitObjectEventPalettes, and GetObjectPaletteTag, they're not needed.

Please see ExpoSeed's repository for the full tutorial! This tutorial is NOT complete! If I don't get to this, hopefully someone else will!