Added override table for standalone follower palettes.

This commit is contained in:
Ariel A 2024-02-17 16:55:11 -05:00
parent 4afb386ab4
commit 6bceacf403
4 changed files with 56 additions and 12 deletions

View file

@ -8,6 +8,8 @@ extern u8 ALIGNED(4) gDecompressionBuffer[0x4000];
void LZDecompressWram(const u32 *src, void *dest);
void LZDecompressVram(const u32 *src, void *dest);
bool32 IsLZ77Data(const void *ptr, u32 minSize, u32 maxSize);
u16 LoadCompressedSpriteSheet(const struct CompressedSpriteSheet *src);
void LoadCompressedSpriteSheetOverrideBuffer(const struct CompressedSpriteSheet *src, void *buffer);
bool8 LoadCompressedSpriteSheetUsingHeap(const struct CompressedSpriteSheet *src);

View file

@ -426,6 +426,17 @@ const struct ObjectEventGraphicsInfo gCastformObjectGraphics[] =
{TAG_NONE, OBJ_EVENT_PAL_TAG_CASTFORM_SNOWY, OBJ_EVENT_PAL_TAG_NONE, 512, 32, 32, 2, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_NONE, &gObjectEventBaseOam_32x32, sOamTables_32x32, sAnimTable_Following, sPicTable_CastformSnowy, gDummySpriteAffineAnimTable},
};
// Standalone follower palettes
// If not NULL, entries here override the front-sprite-based pals
// used by OBJ_EVENT_PAL_TAG_DYNAMIC
// Palette data may be compressed, or not
const void* const gFollowerPalettes[][2] =
{
// Must have at least one entry, or ARRAY_COUNT comparison fails
// (SPECIES_NONE does not use OBJ_EVENT_PAL_TAG_DYNAMIC anyway)
[SPECIES_NONE] = {gMonPalette_CircledQuestionMark, gMonShinyPalette_CircledQuestionMark},
};
#if OW_MON_POKEBALLS
#define POKEBALL_GFX_INFO(NAME) \

View file

@ -19,6 +19,24 @@ void LZDecompressVram(const u32 *src, void *dest)
LZ77UnCompVram(src, dest);
}
// Checks if `ptr` is likely LZ77 data
// Checks word-alignment, min/max size, and header byte
bool32 IsLZ77Data(const void *ptr, u32 minSize, u32 maxSize) {
const u8 *data = ptr;
u32 size;
// Compressed data must be word aligned
if (((u32)ptr) & 3)
return FALSE;
// Check LZ77 header byte
// See https://problemkaputt.de/gbatek.htm#biosdecompressionfunctions
if (data[0] != 0x10)
return FALSE;
// Read 24-bit uncompressed size
size = data[1] | (data[2] << 8) | (data[3] << 16);
return (size >= minSize && size <= maxSize);
}
u16 LoadCompressedSpriteSheet(const struct CompressedSpriteSheet *src)
{
struct SpriteSheet dest;

View file

@ -19,6 +19,7 @@
#include "fieldmap.h"
#include "follower_helper.h"
#include "gpu_regs.h"
#include "graphics.h"
#include "mauville_old_man.h"
#include "metatile_behavior.h"
#include "overworld.h"
@ -189,7 +190,7 @@ static u8 DoJumpSpecialSpriteMovement(struct Sprite *);
static void CreateLevitateMovementTask(struct ObjectEvent *);
static void DestroyLevitateMovementTask(u8);
static bool8 GetFollowerInfo(u16 *species, u8 *form, u8 *shiny);
static u8 LoadDynamicFollowerPalette(u16 species, u8 form, bool8 shiny);
static u8 LoadDynamicFollowerPalette(u16 species, u8 form, bool32 shiny);
static const struct ObjectEventGraphicsInfo * SpeciesToGraphicsInfo(u16 species, u8 form);
static bool8 NpcTakeStep(struct Sprite *);
static bool8 IsElevationMismatchAt(u8, s16, s16);
@ -1698,7 +1699,7 @@ u8 CreateObjectGraphicsSprite(u16 graphicsId, void (*callback)(struct Sprite *),
u16 species;
u8 form;
bool8 shiny;
u8 paletteNum;
u32 paletteNum;
spriteTemplate = Alloc(sizeof(struct SpriteTemplate));
if (graphicsId == OBJ_EVENT_GFX_OW_MON && GetFollowerInfo(&species, &form, &shiny)) {
@ -1715,9 +1716,8 @@ u8 CreateObjectGraphicsSprite(u16 graphicsId, void (*callback)(struct Sprite *),
CopyObjectGraphicsInfoToSpriteTemplate(graphicsId, callback, spriteTemplate, &subspriteTables);
if (spriteTemplate->paletteTag == OBJ_EVENT_PAL_TAG_DYNAMIC) {
const struct CompressedSpritePalette *spritePalette = &(shiny ? gMonShinyPaletteTable : gMonPaletteTable)[species];
paletteNum = LoadDynamicFollowerPalette(species, form, shiny);
spriteTemplate->paletteTag = spritePalette->tag;
spriteTemplate->paletteTag = GetSpritePaletteTagByPaletteNum(paletteNum);
} else if (spriteTemplate->paletteTag != TAG_NONE)
LoadObjectEventPalette(spriteTemplate->paletteTag);
@ -1825,18 +1825,31 @@ static const struct ObjectEventGraphicsInfo * SpeciesToGraphicsInfo(u16 species,
}
// Find, or load, the palette for the specified pokemon info
static u8 LoadDynamicFollowerPalette(u16 species, u8 form, bool8 shiny) {
static u8 LoadDynamicFollowerPalette(u16 species, u8 form, bool32 shiny) {
u32 paletteNum;
// Note that the shiny palette tag is `species + SPECIES_SHINY_TAG`, which must be increased with more pokemon
// so that palette tags do not overlap
const struct CompressedSpritePalette *spritePalette = &(shiny ? gMonShinyPaletteTable : gMonPaletteTable)[species];
if ((paletteNum = IndexOfSpritePaletteTag(spritePalette->tag)) == 0xFF) {
// Load compressed palette
LoadCompressedSpritePalette(spritePalette);
paletteNum = IndexOfSpritePaletteTag(spritePalette->tag); // Tag is always present
struct SpritePalette spritePalette = {.tag = shiny ? (species + SPECIES_SHINY_TAG) : species};
// palette already loaded
if ((paletteNum = IndexOfSpritePaletteTag(spritePalette.tag)) < 16)
return paletteNum;
// Use matching front sprite's normal/shiny palettes
spritePalette.data = (u16*)((shiny ? gMonShinyPaletteTable : gMonPaletteTable)[species].data);
// Use standalone palette, unless entry is OOB or NULL (fallback to front-sprite-based)
if (species < ARRAY_COUNT(gFollowerPalettes) && gFollowerPalettes[species][shiny & 1])
spritePalette.data = gFollowerPalettes[species][shiny & 1];
// Check if pal data must be decompressed
if (IsLZ77Data(spritePalette.data, PLTT_SIZE_4BPP, PLTT_SIZE_4BPP)) {
// IsLZ77Data guarantees word-alignment, so casting this is safe
LZ77UnCompWram((u32*)spritePalette.data, gDecompressionBuffer);
spritePalette.data = (void*)gDecompressionBuffer;
}
paletteNum = LoadSpritePalette(&spritePalette);
if (gWeatherPtr->currWeather != WEATHER_FOG_HORIZONTAL) // don't want to weather blend in fog
UpdateSpritePaletteWithWeather(paletteNum);
}
return paletteNum;
}