Fixed follower appearance in shops.

This commit is contained in:
Ariel A 2021-12-23 01:35:11 -05:00
parent febdb7616e
commit 58a3e55b39
2 changed files with 77 additions and 27 deletions

View File

@ -174,6 +174,9 @@ static u8 DoJumpSpecialSpriteMovement(struct Sprite *sprite);
static void CreateLevitateMovementTask(struct ObjectEvent *);
static void DestroyLevitateMovementTask(u8);
static bool8 NpcTakeStep(struct Sprite *sprite);
static bool8 GetFollowerInfo(u16 *species, u8 *form, u8 *shiny);
static u8 LoadDynamicFollowerPalette(u16 species, u8 form, bool8 shiny);
static const struct ObjectEventGraphicsInfo * SpeciesToGraphicsInfo(u16 species, u8 form);
static const struct SpriteFrameImage sPicTable_PechaBerryTree[];
@ -1557,10 +1560,30 @@ u8 CreateObjectGraphicsSprite(u16 graphicsId, void (*callback)(struct Sprite *),
const struct SubspriteTable *subspriteTables;
struct Sprite *sprite;
u8 spriteId;
u16 species;
u8 form;
bool8 shiny;
u8 paletteNum;
spriteTemplate = malloc(sizeof(struct SpriteTemplate));
CopyObjectGraphicsInfoToSpriteTemplate(graphicsId, callback, spriteTemplate, &subspriteTables);
if (spriteTemplate->paletteTag != TAG_NONE)
if (graphicsId == OBJ_EVENT_GFX_OW_MON && GetFollowerInfo(&species, &form, &shiny)) {
const struct ObjectEventGraphicsInfo *graphicsInfo = SpeciesToGraphicsInfo(species, form);
spriteTemplate->tileTag = graphicsInfo->tileTag;
spriteTemplate->paletteTag = graphicsInfo->paletteTag;
spriteTemplate->oam = graphicsInfo->oam;
spriteTemplate->anims = graphicsInfo->anims;
spriteTemplate->images = graphicsInfo->images;
spriteTemplate->affineAnims = graphicsInfo->affineAnims;
spriteTemplate->callback = callback;
subspriteTables = graphicsInfo->subspriteTables;
} else
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;
} else if (spriteTemplate->paletteTag != TAG_NONE)
LoadObjectEventPalette(spriteTemplate->paletteTag);
spriteId = CreateSprite(spriteTemplate, x, y, subpriority);
@ -1661,41 +1684,61 @@ static const struct ObjectEventGraphicsInfo * SpeciesToGraphicsInfo(u16 species,
return graphicsInfo->tileTag == 0xFFFF ? graphicsInfo : &gPokemonObjectGraphics[SPECIES_PORYGON]; // avoid OOB access
}
// Set graphics & sprite for a follower object event by species & shininess.
static void FollowerSetGraphics(struct ObjectEvent *objectEvent, u16 species, u8 form, bool8 shiny) {
const struct ObjectEventGraphicsInfo *graphicsInfo = SpeciesToGraphicsInfo(species, form);
objectEvent->graphicsId = OBJ_EVENT_GFX_OW_MON;
ObjectEventSetGraphics(objectEvent, graphicsInfo);
objectEvent->graphicsId = OBJ_EVENT_GFX_OW_MON;
objectEvent->extra.mon.species = species;
objectEvent->extra.mon.form = form;
objectEvent->extra.mon.shiny = shiny;
if (graphicsInfo->paletteTag == OBJ_EVENT_PAL_TAG_DYNAMIC) { // Use palette from species palette table
struct Sprite *sprite = &gSprites[objectEvent->spriteId];
// Find, or load, the palette for the specified pokemon info
static u8 LoadDynamicFollowerPalette(u16 species, u8 form, bool8 shiny) {
u8 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];
// Free palette if otherwise unused
sprite->inUse = FALSE;
FieldEffectFreePaletteIfUnused(sprite->oam.paletteNum);
sprite->inUse = TRUE;
if (IndexOfSpritePaletteTag(spritePalette->tag) == 0xFF) { // Load compressed palette
if ((paletteNum = IndexOfSpritePaletteTag(spritePalette->tag)) == 0xFF) { // Load compressed palette
LoadCompressedSpritePalette(spritePalette);
sprite->oam.paletteNum = IndexOfSpritePaletteTag(spritePalette->tag); // Tag is always present
} else
sprite->oam.paletteNum = IndexOfSpritePaletteTag(spritePalette->tag); // Tag is always present
paletteNum = IndexOfSpritePaletteTag(spritePalette->tag); // Tag is always present
}
return paletteNum;
}
// Set graphics & sprite for a follower object event by species & shininess.
static void FollowerSetGraphics(struct ObjectEvent *objEvent, u16 species, u8 form, bool8 shiny) {
const struct ObjectEventGraphicsInfo *graphicsInfo = SpeciesToGraphicsInfo(species, form);
objEvent->graphicsId = OBJ_EVENT_GFX_OW_MON;
ObjectEventSetGraphics(objEvent, graphicsInfo);
objEvent->graphicsId = OBJ_EVENT_GFX_OW_MON;
objEvent->extra.mon.species = species;
objEvent->extra.mon.form = form;
objEvent->extra.mon.shiny = shiny;
if (graphicsInfo->paletteTag == OBJ_EVENT_PAL_TAG_DYNAMIC) { // Use palette from species palette table
struct Sprite *sprite = &gSprites[objEvent->spriteId];
// Free palette if otherwise unused
sprite->inUse = FALSE;
FieldEffectFreePaletteIfUnused(sprite->oam.paletteNum);
sprite->inUse = TRUE;
sprite->oam.paletteNum = LoadDynamicFollowerPalette(species, form, shiny);
}
}
// Retrieve graphic information about the following pokemon, if any
static bool8 GetFollowerInfo(u16 *species, u8 *form, u8 *shiny) {
struct Pokemon *mon = GetFirstLiveMon();
if (!mon) {
*species = SPECIES_NONE;
*form = 0;
*shiny = 0;
return FALSE;
}
*species = GetMonData(mon, MON_DATA_SPECIES);
*shiny = IsMonShiny(mon);
*form = *species == SPECIES_UNOWN ? GET_UNOWN_LETTER(mon->box.personality) : 0;
return TRUE;
}
void UpdateFollowingPokemon(void) { // Update following pokemon if any
struct ObjectEvent *objEvent = GetFollowerObject();
struct Pokemon *mon = GetFirstLiveMon();
struct Sprite *sprite;
u16 species;
bool8 shiny;
u8 form;
// Avoid spawning large (64x64) follower pokemon inside buildings
if (mon && !(gMapHeader.mapType == MAP_TYPE_INDOOR && SpeciesToGraphicsInfo(GetMonData(mon, MON_DATA_SPECIES), 0)->width == 64)) {
if (GetFollowerInfo(&species, &form, &shiny) && !(gMapHeader.mapType == MAP_TYPE_INDOOR && SpeciesToGraphicsInfo(species, 0)->width == 64)) {
if (objEvent == NULL) { // Spawn follower
struct ObjectEventTemplate template = {
.localId = OBJ_EVENT_ID_FOLLOWER,
@ -1709,9 +1752,6 @@ void UpdateFollowingPokemon(void) { // Update following pokemon if any
objEvent->invisible = TRUE;
}
sprite = &gSprites[objEvent->spriteId];
species = GetMonData(mon, MON_DATA_SPECIES);
shiny = IsMonShiny(mon);
form = species == SPECIES_UNOWN ? GET_UNOWN_LETTER(mon->box.personality) : 0;
// Follower appearance changed; move to player and set invisible
if (species != objEvent->extra.mon.species || shiny != objEvent->extra.mon.shiny || form != objEvent->extra.mon.form) {
MoveObjectEventToMapCoords(objEvent, gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.x, gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.y);

View File

@ -34,6 +34,7 @@
#include "text_window.h"
#include "tv.h"
#include "constants/decorations.h"
#include "constants/event_objects.h"
#include "constants/items.h"
#include "constants/metatile_behaviors.h"
#include "constants/rgb.h"
@ -805,7 +806,8 @@ static void BuyMenuCollectObjectEventData(void)
{
u8 objEventId = GetObjectEventIdByXY(facingX - 4 + x, facingY - 2 + y);
if (objEventId != OBJECT_EVENTS_COUNT)
// skip if invalid or an overworld pokemon that is not following the player
if (objEventId != OBJECT_EVENTS_COUNT && !(gObjectEvents[objEventId].active && gObjectEvents[objEventId].graphicsId == OBJ_EVENT_GFX_OW_MON && gObjectEvents[objEventId].localId != OBJ_EVENT_ID_FOLLOWER))
{
sShopData->viewportObjects[r8][OBJ_EVENT_ID] = objEventId;
sShopData->viewportObjects[r8][X_COORD] = x;
@ -839,7 +841,12 @@ static void BuyMenuDrawObjectEvents(void)
u8 i;
u8 spriteId;
const struct ObjectEventGraphicsInfo *graphicsInfo;
u8 weatherTemp = gWeatherPtr->palProcessingState;
// This function runs during fadeout, so the weather palette processing state must be temporarily changed,
// so that time-blending will work properly
if (weatherTemp == WEATHER_PAL_STATE_SCREEN_FADING_OUT)
gWeatherPtr->palProcessingState = WEATHER_PAL_STATE_IDLE;
for (i = 0; i < OBJECT_EVENTS_COUNT; i++)
{
if (sShopData->viewportObjects[i][OBJ_EVENT_ID] == OBJECT_EVENTS_COUNT)
@ -862,6 +869,9 @@ static void BuyMenuDrawObjectEvents(void)
StartSpriteAnim(&gSprites[spriteId], sShopData->viewportObjects[i][ANIM_NUM]);
}
gWeatherPtr->palProcessingState = weatherTemp; // restore weather state
CpuFastCopy(gPlttBufferFaded + 16*16, gPlttBufferUnfaded + 16*16, PLTT_BUFFER_SIZE);
}
static bool8 BuyMenuCheckIfObjectEventOverlapsMenuBg(s16 *object)