Merge branch 'romhack' into lighting
This commit is contained in:
commit
ced9fcd509
3 changed files with 81 additions and 32 deletions
|
@ -9,13 +9,12 @@ There are several branches, each with additional features compared to vanilla:
|
|||
**romhack** branch:
|
||||
* [HGSS-style pokémon followers](https://bulbapedia.bulbagarden.net/wiki/Walking_Pok%C3%A9mon#Pok.C3.A9mon_HeartGold_and_SoulSilver) for all 386 pokémon, including emotes, the 28 Unown forms and a majority of follower messages.
|
||||
* Dynamic overworld palettes & reflections compatible with vanilla berry trees.
|
||||
* HGSS-style alpha-blended shadows for object events.
|
||||
* A way to change a pokemon's nature while mangling its PID as little as possible.
|
||||
* Function to detect newer emulators/new GBA hardware.
|
||||
|
||||
**icons** branch:
|
||||
* Everything from the **romhack** branch.
|
||||
* All pokemon icons updated to nicer looking Gen 6 style, based on [this repo](https://github.com/msikma/pokesprite/tree/master/icons/pokemon/regular)
|
||||
* All pokemon icons updated to Gen 6, based on [this repo](https://github.com/msikma/pokesprite/tree/master/icons/pokemon/regular)
|
||||
* This includes compatibility with the PC, trade, contests, mail, Battle Dome. Examples:
|
||||
![PC](https://i.imgur.com/wzwJfd1.png)
|
||||
![Party](https://i.imgur.com/8hbE88t.png)
|
||||
|
@ -27,6 +26,7 @@ There are several branches, each with additional features compared to vanilla:
|
|||
* Day/night shading compatible with weather.
|
||||
* GSC-style window lights.
|
||||
* WIP interframe-blended lamp lights at night, i.e in Rustboro.
|
||||
* HGSS-style alpha-blended shadows for object events.
|
||||
|
||||
To set up the repository, see [INSTALL.md](INSTALL.md).
|
||||
|
||||
|
|
|
@ -173,6 +173,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[];
|
||||
|
||||
|
@ -1558,10 +1561,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);
|
||||
|
@ -1662,6 +1685,27 @@ static const struct ObjectEventGraphicsInfo * SpeciesToGraphicsInfo(u16 species,
|
|||
return graphicsInfo->tileTag == 0xFFFF ? graphicsInfo : &gPokemonObjectGraphics[SPECIES_PORYGON]; // avoid OOB access
|
||||
}
|
||||
|
||||
// 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];
|
||||
if ((paletteNum = IndexOfSpritePaletteTag(spritePalette->tag)) == 0xFF) { // Load compressed palette
|
||||
LoadCompressedSpritePalette(spritePalette);
|
||||
paletteNum = IndexOfSpritePaletteTag(spritePalette->tag); // Tag is always present
|
||||
if (species == SPECIES_AMPHAROS) { // palette should be light-blended TODO: Add more glowing pokemon
|
||||
// CHARIZARD LINE ? CHINCHOU LANTERN FLAAFY MAREEP UMBREON VOLBEAT ?
|
||||
u16 * palette = &gPlttBufferUnfaded[(paletteNum+16)*16];
|
||||
palette[0] |= 0x8000;
|
||||
if (palette[0] & 0x4000) // If color 15 is blended, use it as the alternate color
|
||||
palette[15] |= 0x8000;
|
||||
}
|
||||
UpdateSpritePaletteWithWeather(paletteNum, FALSE);
|
||||
}
|
||||
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, bool8 doPalette) {
|
||||
const struct ObjectEventGraphicsInfo *graphicsInfo = SpeciesToGraphicsInfo(species, form);
|
||||
|
@ -1672,40 +1716,38 @@ static void FollowerSetGraphics(struct ObjectEvent *objEvent, u16 species, u8 fo
|
|||
objEvent->extra.mon.form = form;
|
||||
objEvent->extra.mon.shiny = shiny;
|
||||
if (graphicsInfo->paletteTag == OBJ_EVENT_PAL_TAG_DYNAMIC && doPalette) { // Use palette from species palette table
|
||||
u8 paletteNum;
|
||||
struct Sprite *sprite = &gSprites[objEvent->spriteId];
|
||||
// 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 ((paletteNum = IndexOfSpritePaletteTag(spritePalette->tag)) == 0xFF) { // Load compressed palette
|
||||
LoadCompressedSpritePalette(spritePalette);
|
||||
sprite->oam.paletteNum = paletteNum = IndexOfSpritePaletteTag(spritePalette->tag); // Tag is always present
|
||||
if (species == SPECIES_AMPHAROS) { // palette should be light-blended TODO: Add more glowing pokemon
|
||||
// CHARIZARD LINE ? CHINCHOU LANTERN FLAAFY MAREEP UMBREON VOLBEAT ?
|
||||
u16 * palette = &gPlttBufferUnfaded[(paletteNum+16)*16];
|
||||
palette[0] |= 0x8000;
|
||||
if (palette[0] & 0x4000) // If color 15 is blended, use it as the alternate color
|
||||
palette[15] |= 0x8000;
|
||||
}
|
||||
UpdateSpritePaletteWithWeather(paletteNum, FALSE);
|
||||
} else
|
||||
sprite->oam.paletteNum = paletteNum;
|
||||
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,
|
||||
|
@ -1719,9 +1761,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);
|
||||
|
|
12
src/shop.c
12
src/shop.c
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue