Merge branch '_RHH/master' into _RHH/upcoming

This commit is contained in:
Eduardo Quezada 2025-02-07 15:33:26 -03:00
commit e29e1c6ca7
10 changed files with 129 additions and 163 deletions

View File

@ -270,19 +270,23 @@
#define OBJ_EVENT_GFX_VAR_E (OBJ_EVENT_GFX_VARS + 0xE)
#define OBJ_EVENT_GFX_VAR_F (OBJ_EVENT_GFX_VARS + 0xF)
#define OBJ_EVENT_GFX_MON_BASE 0x200 // 512
#define OBJ_EVENT_GFX_SPECIES_BITS 12 // This will need to be updated when NUM_SPECIES is > ~3.5k
#define OBJ_EVENT_GFX_SPECIES_MASK ((1 << OBJ_EVENT_GFX_SPECIES_BITS) - 1)
#define OBJ_EVENT_MON (1 << 13)
#define OBJ_EVENT_MON_SHINY (1 << 14)
#define OBJ_EVENT_MON_FEMALE (1 << 15)
#define OBJ_EVENT_MON_SPECIES_MASK (OBJ_EVENT_MON - 1)
// Used to call a specific species' follower graphics. Useful for static encounters.
#define OBJ_EVENT_GFX_SPECIES(name) (SPECIES_##name + OBJ_EVENT_GFX_MON_BASE)
#define OBJ_EVENT_GFX_SPECIES_SHINY(name) (SPECIES_##name + OBJ_EVENT_GFX_MON_BASE + SPECIES_SHINY_TAG)
#define OBJ_EVENT_GFX_SPECIES(name) (SPECIES_##name + OBJ_EVENT_MON)
#define OBJ_EVENT_GFX_SPECIES_SHINY(name) (SPECIES_##name + OBJ_EVENT_MON + OBJ_EVENT_MON_SHINY)
#define OBJ_EVENT_GFX_SPECIES_FEMALE(name) (SPECIES_##name + OBJ_EVENT_MON + OBJ_EVENT_MON_FEMALE)
#define OBJ_EVENT_GFX_SPECIES_SHINY_FEMALE(name) (SPECIES_##name + OBJ_EVENT_MON + OBJ_EVENT_MON_SHINY + OBJ_EVENT_MON_FEMALE)
#define OW_SPECIES(x) (((x)->graphicsId & OBJ_EVENT_GFX_SPECIES_MASK) - OBJ_EVENT_GFX_MON_BASE)
#define OW_FORM(x) ((x)->graphicsId >> OBJ_EVENT_GFX_SPECIES_BITS)
#define OW_SPECIES(x) ((x)->graphicsId & OBJ_EVENT_MON_SPECIES_MASK)
#define OW_SHINY(x) ((x)->graphicsId & OBJ_EVENT_MON_SHINY)
#define OW_FEMALE(x) ((x)->graphicsId & OBJ_EVENT_MON_FEMALE)
// Whether Object Event is an OW pokemon
#define IS_OW_MON_OBJ(obj) ((obj)->graphicsId >= OBJ_EVENT_GFX_MON_BASE)
#define IS_OW_MON_OBJ(obj) ((obj)->graphicsId & OBJ_EVENT_MON)
#define SHADOW_SIZE_S 0
#define SHADOW_SIZE_M 1

View File

@ -107,13 +107,6 @@ struct LockedAnimObjectEvents
u8 count;
};
struct FollowerSpriteVisualizerData
{
u16 currentmonId;
bool8 isShiny;
bool8 isFemale;
};
extern const struct OamData gObjectEventBaseOam_32x8;
extern const struct OamData gObjectEventBaseOam_32x32;
extern const struct OamData gObjectEventBaseOam_64x64;
@ -154,7 +147,6 @@ void RemoveFollowingPokemon(void);
struct ObjectEvent *GetFollowerObject(void);
void TrySpawnObjectEvents(s16 cameraX, s16 cameraY);
u8 CreateObjectGraphicsSprite(u16, void (*)(struct Sprite *), s16 x, s16 y, u8 subpriority);
u8 CreateObjectGraphicsFollowerSpriteForVisualizer(u16, void (*)(struct Sprite *), s16 x, s16 y, u8 subpriority, struct FollowerSpriteVisualizerData *data);
u8 TrySpawnObjectEvent(u8 localId, u8 mapNum, u8 mapGroup);
u8 SpawnSpecialObjectEventParameterized(u16 graphicsId, u8 movementBehavior, u8 localId, s16 x, s16 y, u8 elevation);
u8 SpawnSpecialObjectEvent(struct ObjectEventTemplate *);

View File

@ -15152,7 +15152,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
{
.name = COMPOUND_STRING("Nuzzle"),
.description = COMPOUND_STRING(
"Rubs its cheecks against\n"
"Rubs its cheeks against\n"
"the foe, paralyzing it."),
.effect = EFFECT_HIT,
.power = 20,

View File

@ -186,7 +186,7 @@ static void SetSpriteDataForNormalStep(struct Sprite *, u8, u8);
static void InitSpriteForFigure8Anim(struct Sprite *);
static bool8 AnimateSpriteInFigure8(struct Sprite *);
u8 GetDirectionToFace(s16 x1, s16 y1, s16 x2, s16 y2);
static void FollowerSetGraphics(struct ObjectEvent *, u16, u8, bool8);
static void FollowerSetGraphics(struct ObjectEvent * objectEvent, u32 species, bool32 shiny, bool32 female);
static void ObjectEventSetGraphics(struct ObjectEvent *, const struct ObjectEventGraphicsInfo *);
static void SpriteCB_VirtualObject(struct Sprite *);
static void DoShadowFieldEffect(struct ObjectEvent *);
@ -197,13 +197,16 @@ static u8 DoJumpSpriteMovement(struct Sprite *);
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, bool32 shiny);
static const struct ObjectEventGraphicsInfo *SpeciesToGraphicsInfo(u16 species, u8 form);
static bool8 GetFollowerInfo(u32 *species, bool32 *shiny, bool32 *female);
static u32 LoadDynamicFollowerPalette(u32 species, bool32 shiny, bool32 female);
static const struct ObjectEventGraphicsInfo *SpeciesToGraphicsInfo(u32 species, bool32 shiny, bool32 female);
static bool8 NpcTakeStep(struct Sprite *);
static bool8 AreElevationsCompatible(u8, u8);
static void CopyObjectGraphicsInfoToSpriteTemplate_WithMovementType(u16 graphicsId, u16 movementType, struct SpriteTemplate *spriteTemplate, const struct SubspriteTable **subspriteTables);
static u16 GetGraphicsIdForMon(u32 species, bool32 shiny, bool32 female);
static u16 GetUnownSpecies(struct Pokemon *mon);
static const struct SpriteFrameImage sPicTable_PechaBerryTree[];
static void StartSlowRunningAnim(struct ObjectEvent *objectEvent, struct Sprite *sprite, u8 direction);
@ -1678,17 +1681,8 @@ static u8 TrySetupObjectEventSprite(const struct ObjectEventTemplate *objectEven
if (OW_GFX_COMPRESS)
spriteTemplate->tileTag = LoadSheetGraphicsInfo(graphicsInfo, objectEvent->graphicsId, NULL);
if (objectEvent->graphicsId >= OBJ_EVENT_GFX_MON_BASE + SPECIES_SHINY_TAG)
{
if (objectEvent->graphicsId & OBJ_EVENT_MON && objectEvent->graphicsId & OBJ_EVENT_MON_SHINY)
objectEvent->shiny = TRUE;
objectEvent->graphicsId -= SPECIES_SHINY_TAG;
}
if (objectEvent->graphicsId >= OBJ_EVENT_GFX_MON_BASE + SPECIES_SHINY_TAG)
{
objectEvent->shiny = TRUE;
objectEvent->graphicsId -= SPECIES_SHINY_TAG;
}
spriteId = CreateSprite(spriteTemplate, 0, 0, 0);
if (spriteId == MAX_SPRITES)
@ -1700,7 +1694,7 @@ static u8 TrySetupObjectEventSprite(const struct ObjectEventTemplate *objectEven
sprite = &gSprites[spriteId];
// Use palette from species palette table
if (spriteTemplate->paletteTag == OBJ_EVENT_PAL_TAG_DYNAMIC)
sprite->oam.paletteNum = LoadDynamicFollowerPalette(OW_SPECIES(objectEvent), OW_FORM(objectEvent), objectEvent->shiny);
sprite->oam.paletteNum = LoadDynamicFollowerPalette(OW_SPECIES(objectEvent), OW_SHINY(objectEvent), OW_FEMALE(objectEvent));
if (OW_GFX_COMPRESS && sprite->usingSheet)
sprite->sheetSpan = GetSpanPerImage(sprite->oam.shape, sprite->oam.size);
GetMapCoordsFromSpritePos(objectEvent->currentCoords.x + cameraX, objectEvent->currentCoords.y + cameraY, &sprite->x, &sprite->y);
@ -1812,13 +1806,20 @@ static void UNUSED MakeSpriteTemplateFromObjectEventTemplate(const struct Object
// Loads information from graphicsId, with shininess separate
// also can write palette tag to the template
static u8 LoadDynamicFollowerPaletteFromGraphicsId(u16 graphicsId, bool8 shiny, struct SpriteTemplate *template)
static u32 LoadDynamicFollowerPaletteFromGraphicsId(u16 graphicsId, struct SpriteTemplate *template)
{
u16 species = ((graphicsId & OBJ_EVENT_GFX_SPECIES_MASK) - OBJ_EVENT_GFX_MON_BASE);
u8 form = (graphicsId >> OBJ_EVENT_GFX_SPECIES_BITS);
u8 paletteNum = LoadDynamicFollowerPalette(species, form, shiny);
u16 species = graphicsId & OBJ_EVENT_MON_SPECIES_MASK;
bool32 shiny = graphicsId & OBJ_EVENT_MON_SHINY;
bool32 female = graphicsId & OBJ_EVENT_MON_FEMALE;
u8 paletteNum = LoadDynamicFollowerPalette(species, shiny, female);
if (template)
template->paletteTag = species;
{
template->paletteTag = species + OBJ_EVENT_MON;
if (shiny)
template->paletteTag += OBJ_EVENT_MON_SHINY;
if (female)
template->paletteTag += OBJ_EVENT_MON_FEMALE;
}
return paletteNum;
}
@ -1830,7 +1831,7 @@ u8 CreateObjectGraphicsSprite(u16 graphicsId, void (*callback)(struct Sprite *),
const struct ObjectEventGraphicsInfo *graphicsInfo = GetObjectEventGraphicsInfo(graphicsId);
struct Sprite *sprite;
u8 spriteId;
bool32 isShiny = graphicsId >= SPECIES_SHINY_TAG + OBJ_EVENT_GFX_MON_BASE;
bool32 isShiny = graphicsId & OBJ_EVENT_MON_SHINY;
spriteTemplate = Alloc(sizeof(struct SpriteTemplate));
CopyObjectGraphicsInfoToSpriteTemplate(graphicsId, callback, spriteTemplate, &subspriteTables);
@ -1847,52 +1848,7 @@ u8 CreateObjectGraphicsSprite(u16 graphicsId, void (*callback)(struct Sprite *),
if (spriteTemplate->paletteTag == OBJ_EVENT_PAL_TAG_DYNAMIC)
{
u32 paletteNum = LoadDynamicFollowerPaletteFromGraphicsId(graphicsId, isShiny, spriteTemplate);
spriteTemplate->paletteTag = GetSpritePaletteTagByPaletteNum(paletteNum);
}
else if (spriteTemplate->paletteTag != TAG_NONE)
{
LoadObjectEventPalette(spriteTemplate->paletteTag);
}
spriteId = CreateSprite(spriteTemplate, x, y, subpriority);
Free(spriteTemplate);
if (spriteId != MAX_SPRITES && subspriteTables != NULL)
{
sprite = &gSprites[spriteId];
if (OW_GFX_COMPRESS && graphicsInfo->compressed)
sprite->sheetSpan = GetSpanPerImage(sprite->oam.shape, sprite->oam.size);
SetSubspriteTables(sprite, subspriteTables);
sprite->subspriteMode = SUBSPRITES_IGNORE_PRIORITY;
}
return spriteId;
}
// Horrible workaround for sprite the visualizer, this should probably be reworked later
u8 CreateObjectGraphicsFollowerSpriteForVisualizer(u16 graphicsId, void (*callback)(struct Sprite *), s16 x, s16 y, u8 subpriority, struct FollowerSpriteVisualizerData *data)
{
struct SpriteTemplate *spriteTemplate;
const struct SubspriteTable *subspriteTables;
const struct ObjectEventGraphicsInfo *graphicsInfo = GetObjectEventGraphicsInfo(graphicsId);
struct Sprite *sprite;
u8 spriteId;
bool32 isShiny = data->isShiny;
spriteTemplate = Alloc(sizeof(struct SpriteTemplate));
CopyObjectGraphicsInfoToSpriteTemplate(graphicsId, callback, spriteTemplate, &subspriteTables);
if (OW_GFX_COMPRESS)
{
// Checking only for compressed here so as not to mess with decorations
if (graphicsInfo->compressed)
spriteTemplate->tileTag = LoadSheetGraphicsInfo(graphicsInfo, graphicsId, NULL);
}
if (spriteTemplate->paletteTag == OBJ_EVENT_PAL_TAG_DYNAMIC)
{
u32 paletteNum = LoadDynamicFollowerPaletteFromGraphicsId(graphicsId, isShiny, spriteTemplate);
u32 paletteNum = LoadDynamicFollowerPaletteFromGraphicsId(graphicsId, spriteTemplate);
spriteTemplate->paletteTag = GetSpritePaletteTagByPaletteNum(paletteNum);
}
else if (spriteTemplate->paletteTag != TAG_NONE)
@ -1988,19 +1944,18 @@ struct ObjectEvent *GetFollowerObject(void)
}
// Return graphicsInfo for a pokemon species & form
static const struct ObjectEventGraphicsInfo *SpeciesToGraphicsInfo(u16 species, u8 form)
static const struct ObjectEventGraphicsInfo *SpeciesToGraphicsInfo(u32 species, bool32 shiny, bool32 female)
{
const struct ObjectEventGraphicsInfo *graphicsInfo = NULL;
#if OW_POKEMON_OBJECT_EVENTS
switch (species)
{
case SPECIES_UNOWN: // Letters >A are defined as species >= NUM_SPECIES, so are not contiguous with A
form %= NUM_UNOWN_FORMS;
graphicsInfo = &gSpeciesInfo[form ? SPECIES_UNOWN_B + form - 1 : species].overworldData;
case SPECIES_UNOWN: // Deal with Unown forms later
graphicsInfo = &gSpeciesInfo[species].overworldData;
break;
default:
#if P_GENDER_DIFFERENCES
if (form == 1 && gSpeciesInfo[species].overworldDataFemale.paletteTag == OBJ_EVENT_PAL_TAG_DYNAMIC)
if (female && gSpeciesInfo[species].overworldDataFemale.paletteTag == OBJ_EVENT_PAL_TAG_DYNAMIC)
{
graphicsInfo = &gSpeciesInfo[species].overworldDataFemale;
}
@ -2024,17 +1979,18 @@ static const struct ObjectEventGraphicsInfo *SpeciesToGraphicsInfo(u16 species,
}
// Find, or load, the palette for the specified pokemon info
static u8 LoadDynamicFollowerPalette(u16 species, u8 form, bool32 shiny)
static u32 LoadDynamicFollowerPalette(u32 species, bool32 shiny, bool32 female)
{
u32 paletteNum;
bool32 female = (form == 1);
// Use standalone palette, unless entry is OOB or NULL (fallback to front-sprite-based)
#if OW_POKEMON_OBJECT_EVENTS == TRUE && OW_PKMN_OBJECTS_SHARE_PALETTES == FALSE
if ((shiny && gSpeciesInfo[species].overworldPalette)
|| (!shiny && gSpeciesInfo[species].overworldShinyPalette))
{
struct SpritePalette spritePalette;
u16 palTag = shiny ? (species + SPECIES_SHINY_TAG + OBJ_EVENT_PAL_TAG_DYNAMIC) : (species + OBJ_EVENT_PAL_TAG_DYNAMIC);
u16 palTag = species + OBJ_EVENT_MON + (shiny ? OBJ_EVENT_MON_SHINY : 0);
if (female && gSpeciesInfo[species].overworldShinyPaletteFemale != NULL)
palTag += OBJ_EVENT_MON_FEMALE;
// palette already loaded
if ((paletteNum = IndexOfSpritePaletteTag(palTag)) < 16)
return paletteNum;
@ -2091,13 +2047,11 @@ static u8 LoadDynamicFollowerPalette(u16 species, u8 form, bool32 shiny)
}
// Set graphics & sprite for a follower object event by species & shininess.
static void FollowerSetGraphics(struct ObjectEvent *objEvent, u16 species, u8 form, bool8 shiny)
static void FollowerSetGraphics(struct ObjectEvent *objEvent, u32 species, bool32 shiny, bool32 female)
{
const struct ObjectEventGraphicsInfo *graphicsInfo = SpeciesToGraphicsInfo(species, form);
const struct ObjectEventGraphicsInfo *graphicsInfo = SpeciesToGraphicsInfo(species, shiny, female);
ObjectEventSetGraphics(objEvent, graphicsInfo);
objEvent->graphicsId = (OBJ_EVENT_GFX_MON_BASE + species) & OBJ_EVENT_GFX_SPECIES_MASK;
objEvent->graphicsId |= form << OBJ_EVENT_GFX_SPECIES_BITS;
objEvent->shiny = shiny;
objEvent->graphicsId = GetGraphicsIdForMon(species, shiny, female);
if (graphicsInfo->paletteTag == OBJ_EVENT_PAL_TAG_DYNAMIC) // Use palette from species palette table
{
struct Sprite *sprite = &gSprites[objEvent->spriteId];
@ -2105,7 +2059,7 @@ static void FollowerSetGraphics(struct ObjectEvent *objEvent, u16 species, u8 fo
sprite->inUse = FALSE;
FieldEffectFreePaletteIfUnused(sprite->oam.paletteNum);
sprite->inUse = TRUE;
sprite->oam.paletteNum = LoadDynamicFollowerPalette(species, form, shiny);
sprite->oam.paletteNum = LoadDynamicFollowerPalette(species, shiny, female);
}
else if (gWeatherPtr->currWeather != WEATHER_FOG_HORIZONTAL) // don't want to weather blend in fog
{
@ -2118,9 +2072,9 @@ static void FollowerSetGraphics(struct ObjectEvent *objEvent, u16 species, u8 fo
static void RefreshFollowerGraphics(struct ObjectEvent *objEvent)
{
u32 species = OW_SPECIES(objEvent);
u32 form = OW_FORM(objEvent);
u32 shiny = objEvent->shiny;
const struct ObjectEventGraphicsInfo *graphicsInfo = SpeciesToGraphicsInfo(species, form);
bool32 shiny = OW_SHINY(objEvent);
bool32 female = OW_FEMALE(objEvent);
const struct ObjectEventGraphicsInfo *graphicsInfo = SpeciesToGraphicsInfo(species, shiny, female);
struct Sprite *sprite = &gSprites[objEvent->spriteId];
u32 i = FindObjectEventPaletteIndexByTag(graphicsInfo->paletteTag);
@ -2149,7 +2103,7 @@ static void RefreshFollowerGraphics(struct ObjectEvent *objEvent)
sprite->inUse = FALSE;
FieldEffectFreePaletteIfUnused(sprite->oam.paletteNum);
sprite->inUse = TRUE;
sprite->oam.paletteNum = LoadDynamicFollowerPalette(species, form, shiny);
sprite->oam.paletteNum = LoadDynamicFollowerPalette(species, shiny, female);
}
else if (i != 0xFF)
{
@ -2179,23 +2133,22 @@ u16 GetOverworldWeatherSpecies(u16 species)
return species;
}
static bool8 GetMonInfo(struct Pokemon *mon, u16 *species, u8 *form, u8 *shiny)
static bool8 GetMonInfo(struct Pokemon *mon, u32 *species, bool32 *shiny, bool32 *female)
{
*form = 0; // default
if (!mon)
{
*species = SPECIES_NONE;
*form = 0;
*shiny = 0;
*shiny = FALSE;
*female = FALSE;
return FALSE;
}
*species = GetMonData(mon, MON_DATA_SPECIES);
*form = GetMonGender(mon) == MON_FEMALE;
*shiny = IsMonShiny(mon);
*shiny = IsMonShiny(mon) ? OBJ_EVENT_MON_SHINY : 0;
*female = GetMonGender(mon) == MON_FEMALE ? OBJ_EVENT_MON_FEMALE : 0;
switch (*species)
{
case SPECIES_UNOWN:
*form = GET_UNOWN_LETTER(mon->box.personality);
*species = GetUnownSpecies(mon);
break;
default:
*species = GetOverworldWeatherSpecies(*species);
@ -2205,9 +2158,9 @@ static bool8 GetMonInfo(struct Pokemon *mon, u16 *species, u8 *form, u8 *shiny)
}
// Retrieve graphic information about the following pokemon, if any
static bool8 GetFollowerInfo(u16 *species, u8 *form, u8 *shiny)
static bool8 GetFollowerInfo(u32 *species, bool32 *shiny, bool32 *female)
{
return GetMonInfo(GetFirstLiveMon(), species, form, shiny);
return GetMonInfo(GetFirstLiveMon(), species, shiny, female);
}
// Update following pokemon if any
@ -2215,18 +2168,18 @@ void UpdateFollowingPokemon(void)
{
struct ObjectEvent *objEvent = GetFollowerObject();
struct Sprite *sprite;
u16 species;
bool8 shiny;
u8 form;
u32 species;
bool32 shiny;
bool32 female;
// Don't spawn follower if:
// 1. GetFollowerInfo returns FALSE
// 2. Map is indoors and gfx is larger than 32x32
// 3. flag is set
if (OW_POKEMON_OBJECT_EVENTS == FALSE
|| OW_FOLLOWERS_ENABLED == FALSE
|| !GetFollowerInfo(&species, &form, &shiny)
|| SpeciesToGraphicsInfo(species, form) == NULL
|| (gMapHeader.mapType == MAP_TYPE_INDOOR && SpeciesToGraphicsInfo(species, form)->oam->size > ST_OAM_SIZE_2)
|| !GetFollowerInfo(&species, &shiny, &female)
|| SpeciesToGraphicsInfo(species, shiny, female) == NULL
|| (gMapHeader.mapType == MAP_TYPE_INDOOR && SpeciesToGraphicsInfo(species, shiny, female)->oam->size > ST_OAM_SIZE_2)
|| FlagGet(FLAG_TEMP_HIDE_FOLLOWER))
{
RemoveFollowingPokemon();
@ -2240,7 +2193,7 @@ void UpdateFollowingPokemon(void)
struct ObjectEventTemplate template =
{
.localId = OBJ_EVENT_ID_FOLLOWER,
.graphicsId = OBJ_EVENT_GFX_MON_BASE + species,
.graphicsId = GetGraphicsIdForMon(species, shiny, female),
.flagId = 0,
.x = gSaveBlock1Ptr->pos.x,
.y = gSaveBlock1Ptr->pos.y,
@ -2248,7 +2201,7 @@ void UpdateFollowingPokemon(void)
.elevation = gObjectEvents[objId].active ? gObjectEvents[objId].currentElevation : 3,
.movementType = MOVEMENT_TYPE_FOLLOW_PLAYER,
// store form info in template
.trainerRange_berryTreeId = (form & 0x1F) | (shiny << 5),
//.trainerRange_berryTreeId = (form & 0x1F) | (shiny << 5), // ???? what?
};
if ((objId = SpawnSpecialObjectEvent(&template)) >= OBJECT_EVENTS_COUNT)
return;
@ -2257,12 +2210,12 @@ void UpdateFollowingPokemon(void)
}
sprite = &gSprites[objEvent->spriteId];
// Follower appearance changed; move to player and set invisible
if (species != OW_SPECIES(objEvent) || shiny != objEvent->shiny || form != OW_FORM(objEvent))
if (species != OW_SPECIES(objEvent) || shiny != OW_SHINY(objEvent) || female != OW_FEMALE(objEvent))
{
MoveObjectEventToMapCoords(objEvent,
gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.x,
gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.y);
FollowerSetGraphics(objEvent, species, form, shiny);
FollowerSetGraphics(objEvent, species, shiny, female);
objEvent->invisible = TRUE;
}
sprite->data[6] = 0; // set animation data
@ -2703,7 +2656,7 @@ static void SpawnObjectEventOnReturnToField(u8 objectEventId, s16 x, s16 y)
if (spriteTemplate.paletteTag == OBJ_EVENT_PAL_TAG_DYNAMIC)
{
u32 paletteNum = LoadDynamicFollowerPalette(OW_SPECIES(objectEvent), OW_FORM(objectEvent), objectEvent->shiny);
u32 paletteNum = LoadDynamicFollowerPalette(OW_SPECIES(objectEvent), OW_SHINY(objectEvent), OW_FEMALE(objectEvent));
spriteTemplate.paletteTag = GetSpritePaletteTagByPaletteNum(paletteNum);
}
else if (spriteTemplate.paletteTag != TAG_NONE)
@ -2898,24 +2851,14 @@ static void SetBerryTreeGraphics(struct ObjectEvent *objectEvent, struct Sprite
const struct ObjectEventGraphicsInfo *GetObjectEventGraphicsInfo(u16 graphicsId)
{
u32 form = 0;
if (graphicsId >= OBJ_EVENT_GFX_VARS && graphicsId <= OBJ_EVENT_GFX_VAR_F)
graphicsId = VarGetObjectEventGraphicsId(graphicsId - OBJ_EVENT_GFX_VARS);
if (graphicsId > OBJ_EVENT_GFX_SPECIES_MASK)
{
form = graphicsId >> OBJ_EVENT_GFX_SPECIES_BITS;
graphicsId = graphicsId & OBJ_EVENT_GFX_SPECIES_MASK;
}
if (graphicsId == OBJ_EVENT_GFX_BARD)
{
return gMauvilleOldManGraphicsInfoPointers[GetCurrentMauvilleOldMan()];
}
if (graphicsId >= OBJ_EVENT_GFX_MON_BASE)
return SpeciesToGraphicsInfo(graphicsId - OBJ_EVENT_GFX_MON_BASE, form);
if (graphicsId & OBJ_EVENT_MON)
return SpeciesToGraphicsInfo(graphicsId & OBJ_EVENT_MON_SPECIES_MASK, graphicsId & OBJ_EVENT_MON_SHINY, graphicsId & OBJ_EVENT_MON_FEMALE);
if (graphicsId >= NUM_OBJ_EVENT_GFX)
graphicsId = OBJ_EVENT_GFX_NINJA_BOY;
@ -5398,7 +5341,7 @@ static bool8 UpdateFollowerTransformEffect(struct ObjectEvent *objectEvent, stru
objectEvent->graphicsId = multi;
break;
}
objectEvent->graphicsId += OBJ_EVENT_GFX_MON_BASE;
objectEvent->graphicsId += OBJ_EVENT_MON;
RefreshFollowerGraphics(objectEvent);
break;
case TRANSFORM_TYPE_RANDOM_WILD:
@ -5409,7 +5352,7 @@ static bool8 UpdateFollowerTransformEffect(struct ObjectEvent *objectEvent, stru
objectEvent->graphicsId = multi;
break;
}
objectEvent->graphicsId += OBJ_EVENT_GFX_MON_BASE;
objectEvent->graphicsId += OBJ_EVENT_MON;
RefreshFollowerGraphics(objectEvent);
objectEvent->graphicsId = multi;
break;
@ -7481,7 +7424,7 @@ bool8 MovementAction_ExitPokeball_Step1(struct ObjectEvent *objectEvent, struct
// Set graphics, palette, and affine animation
else if (sprite->sDuration == animStepFrame)
{
FollowerSetGraphics(objectEvent, OW_SPECIES(objectEvent), OW_FORM(objectEvent), objectEvent->shiny);
FollowerSetGraphics(objectEvent, OW_SPECIES(objectEvent), OW_SHINY(objectEvent), OW_FEMALE(objectEvent));
LoadFillColorPalette(RGB_WHITE, OBJ_EVENT_PAL_TAG_WHITE, sprite);
// Initialize affine animation
sprite->affineAnims = sAffineAnims_PokeballFollower;
@ -7498,7 +7441,7 @@ bool8 MovementAction_ExitPokeball_Step1(struct ObjectEvent *objectEvent, struct
sprite->affineAnimEnded = TRUE;
FreeSpriteOamMatrix(sprite);
sprite->oam.affineMode = ST_OAM_AFFINE_OFF;
FollowerSetGraphics(objectEvent, OW_SPECIES(objectEvent), OW_FORM(objectEvent), objectEvent->shiny);
FollowerSetGraphics(objectEvent, OW_SPECIES(objectEvent), OW_SHINY(objectEvent), OW_FEMALE(objectEvent));
}
return FALSE;
}
@ -7554,7 +7497,7 @@ bool8 MovementAction_EnterPokeball_Step1(struct ObjectEvent *objectEvent, struct
bool8 MovementAction_EnterPokeball_Step2(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
FollowerSetGraphics(objectEvent, OW_SPECIES(objectEvent), OW_FORM(objectEvent), objectEvent->shiny);
FollowerSetGraphics(objectEvent, OW_SPECIES(objectEvent), OW_SHINY(objectEvent), OW_FEMALE(objectEvent));
objectEvent->invisible = TRUE;
sprite->sTypeFuncId = 0;
sprite->sSpeedFlip = 0;
@ -11016,9 +10959,9 @@ void GetDaycareGraphics(struct ScriptContext *ctx)
{
u16 varGfx[] = {ScriptReadHalfword(ctx), ScriptReadHalfword(ctx)};
u16 varForm[] = {ScriptReadHalfword(ctx), ScriptReadHalfword(ctx)};
u16 specGfx;
u8 form;
u8 shiny;
u32 specGfx;
bool32 shiny;
bool32 female;
s32 i;
Script_RequestEffects(SCREFF_V1);
@ -11029,14 +10972,17 @@ void GetDaycareGraphics(struct ScriptContext *ctx)
for (i = 0; i < 2; i++)
{
GetMonInfo((struct Pokemon *) &gSaveBlock1Ptr->daycare.mons[i].mon, &specGfx, &form, &shiny);
GetMonInfo((struct Pokemon *) &gSaveBlock1Ptr->daycare.mons[i].mon, &specGfx, &shiny, &female);
if (specGfx == SPECIES_NONE)
break;
// Assemble gfx ID like FollowerSetGraphics
specGfx = (OBJ_EVENT_GFX_MON_BASE + specGfx) & OBJ_EVENT_GFX_SPECIES_MASK;
specGfx |= form << OBJ_EVENT_GFX_SPECIES_BITS;
VarSet(varGfx[i], specGfx);
VarSet(varForm[i], form | (shiny << 5));
specGfx = specGfx + OBJ_EVENT_MON;
if (shiny)
specGfx += OBJ_EVENT_MON_SHINY;
if (female)
specGfx += OBJ_EVENT_MON_FEMALE;
VarSet(varGfx[i], (u16)specGfx);
VarSet(varForm[i], 0); // This shouldn't be needed anymore, track down
}
gSpecialVar_Result = i;
}
@ -11087,3 +11033,21 @@ bool8 MovementActionFunc_RunSlow_Step1(struct ObjectEvent *objectEvent, struct S
}
return FALSE;
}
static u16 GetGraphicsIdForMon(u32 species, bool32 shiny, bool32 female)
{
u16 graphicsId = species + OBJ_EVENT_MON;
if (shiny)
graphicsId += OBJ_EVENT_MON_SHINY;
if (female)
graphicsId += OBJ_EVENT_MON_FEMALE;
return graphicsId;
}
static u16 GetUnownSpecies(struct Pokemon *mon)
{
u32 form = GET_UNOWN_LETTER(mon->box.personality);
if (form == 0)
return SPECIES_UNOWN;
return SPECIES_UNOWN_B + form - 1;
}

View File

@ -235,7 +235,7 @@ void LoadObjectEvents(void)
// Try to restore saved inactive follower
if (gObjectEvents[i].localId == OBJ_EVENT_ID_FOLLOWER &&
!gObjectEvents[i].active &&
gObjectEvents[i].graphicsId >= OBJ_EVENT_GFX_MON_BASE)
gObjectEvents[i].graphicsId & OBJ_EVENT_MON)
gObjectEvents[i].active = TRUE;
}
}

View File

@ -1311,7 +1311,7 @@ void CB2_Pokemon_Sprite_Visualizer(void)
gSprites[data->iconspriteId].oam.priority = 0;
//Follower Sprite
data->followerspriteId = CreateObjectGraphicsSprite(OBJ_EVENT_GFX_MON_BASE + species, SpriteCB_Follower, VISUALIZER_FOLLOWER_X, VISUALIZER_FOLLOWER_Y, 0);
data->followerspriteId = CreateObjectGraphicsSprite(OBJ_EVENT_MON + species, SpriteCB_Follower, VISUALIZER_FOLLOWER_X, VISUALIZER_FOLLOWER_Y, 0);
gSprites[data->followerspriteId].oam.priority = 0;
gSprites[data->followerspriteId].anims = sAnims_Follower;
@ -2002,18 +2002,16 @@ static void ReloadPokemonSprites(struct PokemonSpriteVisualizer *data)
gSprites[data->iconspriteId].oam.priority = 0;
//Follower Sprite
u16 graphicsId = (OBJ_EVENT_GFX_MON_BASE + species) & OBJ_EVENT_GFX_SPECIES_MASK;
struct FollowerSpriteVisualizerData followerData;
followerData.currentmonId = graphicsId;
followerData.isFemale = data->isFemale;
followerData.isShiny = data->isShiny;
graphicsId |= data->isFemale << OBJ_EVENT_GFX_SPECIES_BITS;
data->followerspriteId = CreateObjectGraphicsFollowerSpriteForVisualizer(graphicsId,
u16 graphicsId = species + OBJ_EVENT_MON;
if (data->isShiny)
graphicsId += OBJ_EVENT_MON_SHINY;
if (data->isFemale)
graphicsId += OBJ_EVENT_MON_FEMALE;
data->followerspriteId = CreateObjectGraphicsSprite(graphicsId,
SpriteCB_Follower,
VISUALIZER_FOLLOWER_X,
VISUALIZER_FOLLOWER_Y,
0,
&followerData);
0);
gSprites[data->followerspriteId].oam.priority = 0;
gSprites[data->followerspriteId].anims = sAnims_Follower;

View File

@ -2046,7 +2046,7 @@ bool8 ScrCmd_vmessage(struct ScriptContext *ctx)
bool8 ScrCmd_bufferspeciesname(struct ScriptContext *ctx)
{
u8 stringVarIndex = ScriptReadByte(ctx);
u16 species = VarGet(ScriptReadHalfword(ctx)) & OBJ_EVENT_GFX_SPECIES_MASK; // ignore possible shiny / form bits
u16 species = VarGet(ScriptReadHalfword(ctx)) & OBJ_EVENT_MON_SPECIES_MASK; // ignore possible shiny / form bits
Script_RequestEffects(SCREFF_V1);

View File

@ -872,7 +872,7 @@ static void BuyMenuCollectObjectEventData(void)
u8 objEventId = GetObjectEventIdByXY(facingX - 4 + x, facingY - 2 + y);
// 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_MON_BASE && gObjectEvents[objEventId].localId != OBJ_EVENT_ID_FOLLOWER))
if (objEventId != OBJECT_EVENTS_COUNT && !(gObjectEvents[objEventId].active && gObjectEvents[objEventId].graphicsId & OBJ_EVENT_MON && gObjectEvents[objEventId].localId != OBJ_EVENT_ID_FOLLOWER))
{
sShopData->viewportObjects[numObjects][OBJ_EVENT_ID] = objEventId;
sShopData->viewportObjects[numObjects][X_COORD] = x;

View File

@ -33,7 +33,7 @@ SINGLE_BATTLE_TEST("Sheer Force doesn't boost Eruption", s16 damage)
PLAYER(SPECIES_TAUROS) { Ability(ability); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_PRESENT); }
TURN { MOVE(player, MOVE_ERUPTION); }
} SCENE {
HP_BAR(opponent, captureDamage: &results[i].damage);
} FINALLY {
@ -50,7 +50,7 @@ SINGLE_BATTLE_TEST("Sheer Force doesn't boost Water Spout", s16 damage)
PLAYER(SPECIES_TAUROS) { Ability(ability); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_PRESENT); }
TURN { MOVE(player, MOVE_WATER_SPOUT); }
} SCENE {
HP_BAR(opponent, captureDamage: &results[i].damage);
} FINALLY {
@ -347,7 +347,7 @@ SINGLE_BATTLE_TEST("Sheer Force doesn't boost Comeuppance", s16 damage)
EXPECT_NE(results[0].damage, 0);
}
}
SINGLE_BATTLE_TEST("Sheer Force doesn't boost Comeuppance", s16 damage)
SINGLE_BATTLE_TEST("Sheer Force doesn't boost Payback", s16 damage)
{
u16 ability = 0;
PARAMETRIZE { ability = ABILITY_SHEER_FORCE; }

View File

@ -40,6 +40,8 @@ SINGLE_BATTLE_TEST("Electric Seed raises the holder's Defense on Electric Terrai
SEND_IN_MESSAGE("Wobbuffet");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Using Electric Seed, the Defense of Wobbuffet rose!");
} THEN {
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1);
}
}
@ -69,6 +71,8 @@ SINGLE_BATTLE_TEST("Grassy Seed raises the holder's Defense on Grassy Terrain")
SEND_IN_MESSAGE("Wobbuffet");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Using Grassy Seed, the Defense of Wobbuffet rose!");
} THEN {
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1);
}
}
@ -98,6 +102,8 @@ SINGLE_BATTLE_TEST("Misty Seed raises the holder's Sp. Defense on Misty Terrain"
SEND_IN_MESSAGE("Wobbuffet");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Using Misty Seed, the Sp. Def of Wobbuffet rose!");
} THEN {
EXPECT_EQ(player->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE + 1);
}
}
@ -127,5 +133,7 @@ SINGLE_BATTLE_TEST("Psychic Seed raises the holder's Sp. Defense on Psychic Terr
SEND_IN_MESSAGE("Wobbuffet");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Using Psychic Seed, the Sp. Def of Wobbuffet rose!");
} THEN {
EXPECT_EQ(player->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE + 1);
}
}