pokeemerald/src/pokedex_area_screen.c

798 lines
28 KiB
C
Raw Normal View History

2018-11-30 17:41:03 +01:00
#include "global.h"
#include "bg.h"
#include "event_data.h"
#include "gpu_regs.h"
#include "graphics.h"
#include "main.h"
#include "malloc.h"
2018-11-30 17:41:03 +01:00
#include "menu.h"
#include "overworld.h"
#include "palette.h"
#include "pokedex_area_screen.h"
#include "region_map.h"
#include "roamer.h"
#include "sound.h"
#include "string_util.h"
#include "trig.h"
2020-02-05 08:47:32 +01:00
#include "pokedex_area_region_map.h"
2018-11-30 17:41:03 +01:00
#include "wild_encounter.h"
#include "constants/region_map_sections.h"
#include "constants/rgb.h"
#include "constants/songs.h"
2021-12-29 09:23:58 +01:00
// There are two types of indicators for the area screen to show where a Pokémon can occur:
// - Area glows, which highlight any of the maps in MAP_GROUP_TOWNS_AND_ROUTES that have the species.
// These are a tilemap with colored rectangular areas that blends in and out. The positions of the
// rectangles is determined by the positions of the matching MAPSEC values on the region map layout.
// - Area markers, which highlight any of the maps in MAP_GROUP_DUNGEONS or MAP_GROUP_SPECIAL_AREA that
// have the species. These are circular sprites that flash twice. The positions of the sprites is
// determined by the data for the corresponding MAPSEC in gRegionMapEntries.
// Only maps in the following map groups have their encounters considered for the area screen
#define MAP_GROUP_TOWNS_AND_ROUTES MAP_GROUP(PETALBURG_CITY)
#define MAP_GROUP_DUNGEONS MAP_GROUP(METEOR_FALLS_1F_1R)
#define MAP_GROUP_SPECIAL_AREA MAP_GROUP(SAFARI_ZONE_NORTHWEST)
#define AREA_SCREEN_WIDTH 32
#define AREA_SCREEN_HEIGHT 20
2021-12-29 09:23:58 +01:00
#define GLOW_FULL 0xFFFF
#define GLOW_EDGE_R (1 << 0)
#define GLOW_EDGE_L (1 << 1)
#define GLOW_EDGE_B (1 << 2)
#define GLOW_EDGE_T (1 << 3)
#define GLOW_CORNER_TL (1 << 4)
#define GLOW_CORNER_BL (1 << 5)
#define GLOW_CORNER_TR (1 << 6)
#define GLOW_CORNER_BR (1 << 7)
#define GLOW_PALETTE 10
#define TAG_AREA_MARKER 2
#define TAG_AREA_UNKNOWN 3
2021-12-29 09:23:58 +01:00
#define MAX_AREA_HIGHLIGHTS 64 // Maximum number of rectangular route highlights
#define MAX_AREA_MARKERS 32 // Maximum number of circular spot highlights
struct OverworldArea
2018-11-30 17:41:03 +01:00
{
u8 mapGroup;
u8 mapNum;
u16 regionMapSectionId;
};
2021-12-29 09:23:58 +01:00
struct
2018-11-30 17:41:03 +01:00
{
/*0x000*/ void (*callback)(void); // unused
/*0x004*/ MainCallback prev; // unused
/*0x008*/ MainCallback next; // unused
/*0x00C*/ u16 state; // unused
/*0x00E*/ u16 species;
2021-12-29 09:23:58 +01:00
/*0x010*/ struct OverworldArea overworldAreasWithMons[MAX_AREA_HIGHLIGHTS];
2018-11-30 17:41:03 +01:00
/*0x110*/ u16 numOverworldAreas;
/*0x112*/ u16 numSpecialAreas;
/*0x114*/ u16 drawAreaGlowState;
2021-12-29 09:23:58 +01:00
/*0x116*/ u16 areaGlowTilemap[AREA_SCREEN_WIDTH * AREA_SCREEN_HEIGHT];
/*0x616*/ u16 markerTimer;
/*0x618*/ u16 glowTimer;
2018-11-30 17:41:03 +01:00
/*0x61A*/ u16 areaShadeBldArgLo;
/*0x61C*/ u16 areaShadeBldArgHi;
2021-12-29 09:23:58 +01:00
/*0x61E*/ bool8 showingMarkers;
/*0x61F*/ u8 markerFlashCounter;
/*0x620*/ u16 specialAreaRegionMapSectionIds[MAX_AREA_MARKERS];
/*0x660*/ struct Sprite *areaMarkerSprites[MAX_AREA_MARKERS];
2018-11-30 17:41:03 +01:00
/*0x6E0*/ u16 numAreaMarkerSprites;
2021-12-29 09:23:58 +01:00
/*0x6E2*/ u16 alteringCaveCounter;
/*0x6E4*/ u16 alteringCaveId;
2020-03-08 18:24:22 +01:00
/*0x6E8*/ u8 *screenSwitchState;
2018-11-30 17:41:03 +01:00
/*0x6EC*/ struct RegionMap regionMap;
2021-12-29 09:23:58 +01:00
/*0xF70*/ u8 charBuffer[64];
2018-11-30 17:41:03 +01:00
/*0xFB0*/ struct Sprite * areaUnknownSprites[3];
/*0xFBC*/ u8 areaUnknownGraphicsBuffer[0x600];
2021-12-29 09:23:58 +01:00
} static EWRAM_DATA *sPokedexAreaScreen = NULL;
2018-11-30 17:41:03 +01:00
static void FindMapsWithMon(u16);
static void BuildAreaGlowTilemap(void);
static void SetAreaHasMon(u16, u16);
static void SetSpecialMapHasMon(u16, u16);
static u16 GetRegionMapSectionId(u8, u8);
2021-12-29 09:23:58 +01:00
static bool8 MapHasSpecies(const struct WildPokemonHeader *, u16);
static bool8 MonListHasSpecies(const struct WildPokemonInfo *, u16, u16);
2018-11-30 17:41:03 +01:00
static void DoAreaGlow(void);
2020-03-08 18:24:22 +01:00
static void Task_ShowPokedexAreaScreen(u8);
2018-11-30 17:41:03 +01:00
static void CreateAreaMarkerSprites(void);
static void LoadAreaUnknownGraphics(void);
static void CreateAreaUnknownSprites(void);
2020-03-08 18:24:22 +01:00
static void Task_HandlePokedexAreaScreenInput(u8);
2021-09-24 20:30:15 +02:00
static void ResetPokedexAreaMapBg(void);
2021-12-29 09:23:58 +01:00
static void DestroyAreaScreenSprites(void);
2018-11-30 17:41:03 +01:00
static const u32 sAreaGlow_Pal[] = INCBIN_U32("graphics/pokedex/area_glow.gbapal");
static const u32 sAreaGlow_Gfx[] = INCBIN_U32("graphics/pokedex/area_glow.4bpp.lz");
static const u16 sSpeciesHiddenFromAreaScreen[] = { SPECIES_WYNAUT };
static const u16 sMovingRegionMapSections[3] =
{
MAPSEC_MARINE_CAVE,
MAPSEC_UNDERWATER_MARINE_CAVE,
MAPSEC_TERRA_CAVE
};
2018-11-30 17:41:03 +01:00
static const u16 sFeebasData[][3] =
{
2018-11-30 17:41:03 +01:00
{SPECIES_FEEBAS, MAP_GROUP(ROUTE119), MAP_NUM(ROUTE119)},
{NUM_SPECIES}
};
static const u16 sLandmarkData[][2] =
{
2018-11-30 17:41:03 +01:00
{MAPSEC_SKY_PILLAR, FLAG_LANDMARK_SKY_PILLAR},
{MAPSEC_SEAFLOOR_CAVERN, FLAG_LANDMARK_SEAFLOOR_CAVERN},
2020-02-05 08:47:32 +01:00
{MAPSEC_ALTERING_CAVE, FLAG_LANDMARK_ALTERING_CAVE},
2018-11-30 17:41:03 +01:00
{MAPSEC_MIRAGE_TOWER, FLAG_LANDMARK_MIRAGE_TOWER},
{MAPSEC_DESERT_UNDERPASS, FLAG_LANDMARK_DESERT_UNDERPASS},
2019-01-02 22:12:43 +01:00
{MAPSEC_ARTISAN_CAVE, FLAG_LANDMARK_ARTISAN_CAVE},
2018-11-30 17:41:03 +01:00
{MAPSEC_NONE}
};
2021-12-29 09:23:58 +01:00
#include "data/pokedex_area_glow.h"
2018-11-30 17:41:03 +01:00
2020-02-05 08:47:32 +01:00
static const struct PokedexAreaMapTemplate sPokedexAreaMapTemplate =
{
2018-11-30 17:41:03 +01:00
.bg = 3,
2020-02-05 08:47:32 +01:00
.offset = 0,
.mode = 0,
.unk = 2,
2018-11-30 17:41:03 +01:00
};
static const u8 sAreaMarkerTiles[];
static const struct SpriteSheet sAreaMarkerSpriteSheet =
{
2021-12-29 09:23:58 +01:00
.data = sAreaMarkerTiles, .size = 0x80, .tag = TAG_AREA_MARKER
2018-11-30 17:41:03 +01:00
};
static const u16 sAreaMarkerPalette[];
static const struct SpritePalette sAreaMarkerSpritePalette =
{
2021-12-29 09:23:58 +01:00
.data = sAreaMarkerPalette, .tag = TAG_AREA_MARKER
2018-11-30 17:41:03 +01:00
};
static const struct OamData sAreaMarkerOamData =
{
.shape = SPRITE_SHAPE(16x16),
.size = SPRITE_SIZE(16x16),
2018-11-30 17:41:03 +01:00
.priority = 1
};
static const struct SpriteTemplate sAreaMarkerSpriteTemplate =
{
2021-12-29 09:23:58 +01:00
.tileTag = TAG_AREA_MARKER,
.paletteTag = TAG_AREA_MARKER,
.oam = &sAreaMarkerOamData,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCallbackDummy
2018-11-30 17:41:03 +01:00
};
static const u16 sAreaMarkerPalette[] = INCBIN_U16("graphics/pokedex/area_marker.gbapal");
static const u8 sAreaMarkerTiles[] = INCBIN_U8("graphics/pokedex/area_marker.4bpp");
static const struct SpritePalette sAreaUnknownSpritePalette =
{
2021-12-29 09:23:58 +01:00
.data = gPokedexAreaScreenAreaUnknown_Pal, .tag = TAG_AREA_UNKNOWN
2018-11-30 17:41:03 +01:00
};
static const struct OamData sAreaUnknownOamData =
{
.shape = SPRITE_SHAPE(32x32),
.size = SPRITE_SIZE(32x32),
2018-11-30 17:41:03 +01:00
.priority = 1
};
static const struct SpriteTemplate sAreaUnknownSpriteTemplate =
{
2021-12-29 09:23:58 +01:00
.tileTag = TAG_AREA_UNKNOWN,
.paletteTag = TAG_AREA_UNKNOWN,
.oam = &sAreaUnknownOamData,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCallbackDummy
2018-11-30 17:41:03 +01:00
};
static void ResetDrawAreaGlowState(void)
{
sPokedexAreaScreen->drawAreaGlowState = 0;
}
static bool8 DrawAreaGlow(void)
{
switch (sPokedexAreaScreen->drawAreaGlowState)
{
case 0:
FindMapsWithMon(sPokedexAreaScreen->species);
break;
case 1:
BuildAreaGlowTilemap();
break;
case 2:
2020-05-14 10:37:09 +02:00
DecompressAndCopyTileDataToVram(2, sAreaGlow_Gfx, 0, 0, 0);
2021-12-29 09:23:58 +01:00
LoadBgTilemap(2, sPokedexAreaScreen->areaGlowTilemap, sizeof(sPokedexAreaScreen->areaGlowTilemap), 0);
2018-11-30 17:41:03 +01:00
break;
case 3:
2020-05-14 10:37:09 +02:00
if (!FreeTempTileDataBuffersIfPossible())
2018-11-30 17:41:03 +01:00
{
2021-12-29 09:23:58 +01:00
CpuCopy32(sAreaGlow_Pal, &gPlttBufferUnfaded[GLOW_PALETTE * 16], sizeof(sAreaGlow_Pal));
2018-11-30 17:41:03 +01:00
sPokedexAreaScreen->drawAreaGlowState++;
}
return TRUE;
case 4:
2021-12-29 09:23:58 +01:00
ChangeBgY(2, -BG_SCREEN_SIZE, BG_COORD_SET);
2018-11-30 17:41:03 +01:00
break;
default:
return FALSE;
}
sPokedexAreaScreen->drawAreaGlowState++;
return TRUE;
}
static void FindMapsWithMon(u16 species)
{
u16 i;
struct Roamer *roamer;
2021-12-29 09:23:58 +01:00
sPokedexAreaScreen->alteringCaveCounter = 0;
sPokedexAreaScreen->alteringCaveId = VarGet(VAR_ALTERING_CAVE_WILD_SET);
if (sPokedexAreaScreen->alteringCaveId >= NUM_ALTERING_CAVE_TABLES)
sPokedexAreaScreen->alteringCaveId = 0;
2018-11-30 17:41:03 +01:00
roamer = &gSaveBlock1Ptr->roamer;
if (species != roamer->species)
{
sPokedexAreaScreen->numOverworldAreas = 0;
sPokedexAreaScreen->numSpecialAreas = 0;
2021-12-29 09:23:58 +01:00
// Check if this species should be hidden from the area map.
// This only applies to Wynaut, to hide the encounters on Mirage Island.
2018-11-30 17:41:03 +01:00
for (i = 0; i < ARRAY_COUNT(sSpeciesHiddenFromAreaScreen); i++)
{
if (sSpeciesHiddenFromAreaScreen[i] == species)
return;
}
2021-12-29 09:23:58 +01:00
// Add Pokémon with special encounter circumstances (i.e. not listed
// in the regular wild encounter table) to the area map.
// This only applies to Feebas on Route 119, but it was clearly set
// up to allow handling others.
2018-11-30 17:41:03 +01:00
for (i = 0; sFeebasData[i][0] != NUM_SPECIES; i++)
{
if (species == sFeebasData[i][0])
{
switch (sFeebasData[i][1])
{
2021-12-29 09:23:58 +01:00
case MAP_GROUP_TOWNS_AND_ROUTES:
SetAreaHasMon(sFeebasData[i][1], sFeebasData[i][2]);
break;
case MAP_GROUP_DUNGEONS:
case MAP_GROUP_SPECIAL_AREA:
SetSpecialMapHasMon(sFeebasData[i][1], sFeebasData[i][2]);
break;
2018-11-30 17:41:03 +01:00
}
}
}
2021-12-29 09:23:58 +01:00
// Add regular species to the area map
for (i = 0; gWildMonHeaders[i].mapGroup != MAP_GROUP(UNDEFINED); i++)
2018-11-30 17:41:03 +01:00
{
2021-12-29 09:23:58 +01:00
if (MapHasSpecies(&gWildMonHeaders[i], species))
2018-11-30 17:41:03 +01:00
{
switch (gWildMonHeaders[i].mapGroup)
{
2021-12-29 09:23:58 +01:00
case MAP_GROUP_TOWNS_AND_ROUTES:
SetAreaHasMon(gWildMonHeaders[i].mapGroup, gWildMonHeaders[i].mapNum);
break;
case MAP_GROUP_DUNGEONS:
case MAP_GROUP_SPECIAL_AREA:
SetSpecialMapHasMon(gWildMonHeaders[i].mapGroup, gWildMonHeaders[i].mapNum);
break;
2018-11-30 17:41:03 +01:00
}
}
}
}
else
{
2021-12-29 09:23:58 +01:00
// This is the roamer's species, show where the roamer is currently
2018-11-30 17:41:03 +01:00
sPokedexAreaScreen->numSpecialAreas = 0;
if (roamer->active)
{
GetRoamerLocation(&sPokedexAreaScreen->overworldAreasWithMons[0].mapGroup, &sPokedexAreaScreen->overworldAreasWithMons[0].mapNum);
sPokedexAreaScreen->overworldAreasWithMons[0].regionMapSectionId = Overworld_GetMapHeaderByGroupAndId(sPokedexAreaScreen->overworldAreasWithMons[0].mapGroup, sPokedexAreaScreen->overworldAreasWithMons[0].mapNum)->regionMapSectionId;
sPokedexAreaScreen->numOverworldAreas = 1;
}
else
{
sPokedexAreaScreen->numOverworldAreas = 0;
}
}
}
static void SetAreaHasMon(u16 mapGroup, u16 mapNum)
{
2021-12-29 09:23:58 +01:00
if (sPokedexAreaScreen->numOverworldAreas < MAX_AREA_HIGHLIGHTS)
2018-11-30 17:41:03 +01:00
{
sPokedexAreaScreen->overworldAreasWithMons[sPokedexAreaScreen->numOverworldAreas].mapGroup = mapGroup;
sPokedexAreaScreen->overworldAreasWithMons[sPokedexAreaScreen->numOverworldAreas].mapNum = mapNum;
sPokedexAreaScreen->overworldAreasWithMons[sPokedexAreaScreen->numOverworldAreas].regionMapSectionId = CorrectSpecialMapSecId(Overworld_GetMapHeaderByGroupAndId(mapGroup, mapNum)->regionMapSectionId);
sPokedexAreaScreen->numOverworldAreas++;
}
}
static void SetSpecialMapHasMon(u16 mapGroup, u16 mapNum)
{
int i;
2021-12-29 09:23:58 +01:00
if (sPokedexAreaScreen->numSpecialAreas < MAX_AREA_MARKERS)
2018-11-30 17:41:03 +01:00
{
u16 regionMapSectionId = GetRegionMapSectionId(mapGroup, mapNum);
if (regionMapSectionId < MAPSEC_NONE)
{
2021-12-29 09:23:58 +01:00
// Don't highlight the area if it's a moving area (Marine/Terra Cave)
2018-11-30 17:41:03 +01:00
for (i = 0; i < ARRAY_COUNT(sMovingRegionMapSections); i++)
{
if (regionMapSectionId == sMovingRegionMapSections[i])
return;
}
2021-12-29 09:23:58 +01:00
// Don't highlight the area if it's an undiscovered landmark (e.g. Sky Pillar)
2018-11-30 17:41:03 +01:00
for (i = 0; sLandmarkData[i][0] != MAPSEC_NONE; i++)
{
if (regionMapSectionId == sLandmarkData[i][0] && !FlagGet(sLandmarkData[i][1]))
return;
}
2021-12-29 09:23:58 +01:00
// Check if this special area is already being tracked
2018-11-30 17:41:03 +01:00
for (i = 0; i < sPokedexAreaScreen->numSpecialAreas; i++)
{
if (sPokedexAreaScreen->specialAreaRegionMapSectionIds[i] == regionMapSectionId)
break;
}
if (i == sPokedexAreaScreen->numSpecialAreas)
{
2021-12-29 09:23:58 +01:00
// New special area
2018-11-30 17:41:03 +01:00
sPokedexAreaScreen->specialAreaRegionMapSectionIds[i] = regionMapSectionId;
sPokedexAreaScreen->numSpecialAreas++;
}
}
}
}
static u16 GetRegionMapSectionId(u8 mapGroup, u8 mapNum)
{
return Overworld_GetMapHeaderByGroupAndId(mapGroup, mapNum)->regionMapSectionId;
}
2021-12-29 09:23:58 +01:00
static bool8 MapHasSpecies(const struct WildPokemonHeader *info, u16 species)
2018-11-30 17:41:03 +01:00
{
2021-12-29 09:23:58 +01:00
// If this is a header for Altering Cave, skip it if it's not the current Altering Cave encounter set
2020-02-05 08:47:32 +01:00
if (GetRegionMapSectionId(info->mapGroup, info->mapNum) == MAPSEC_ALTERING_CAVE)
2018-11-30 17:41:03 +01:00
{
2021-12-29 09:23:58 +01:00
sPokedexAreaScreen->alteringCaveCounter++;
if (sPokedexAreaScreen->alteringCaveCounter != sPokedexAreaScreen->alteringCaveId + 1)
2018-11-30 17:41:03 +01:00
return FALSE;
}
2021-12-29 09:23:58 +01:00
if (MonListHasSpecies(info->landMonsInfo, species, LAND_WILD_COUNT))
2018-11-30 17:41:03 +01:00
return TRUE;
2021-12-29 09:23:58 +01:00
if (MonListHasSpecies(info->waterMonsInfo, species, WATER_WILD_COUNT))
2018-11-30 17:41:03 +01:00
return TRUE;
2021-12-29 09:23:58 +01:00
// When searching the fishing encounters, this incorrectly uses the size of the land encounters.
// As a result it's reading out of bounds of the fishing encounters tables.
#ifdef BUGFIX
if (MonListHasSpecies(info->fishingMonsInfo, species, FISH_WILD_COUNT))
#else
if (MonListHasSpecies(info->fishingMonsInfo, species, LAND_WILD_COUNT))
#endif
2018-11-30 17:41:03 +01:00
return TRUE;
2021-12-29 09:23:58 +01:00
if (MonListHasSpecies(info->rockSmashMonsInfo, species, ROCK_WILD_COUNT))
2018-11-30 17:41:03 +01:00
return TRUE;
return FALSE;
}
2021-12-29 09:23:58 +01:00
static bool8 MonListHasSpecies(const struct WildPokemonInfo *info, u16 species, u16 size)
2018-11-30 17:41:03 +01:00
{
u16 i;
if (info != NULL)
{
for (i = 0; i < size; i++)
{
if (info->wildPokemon[i].species == species)
return TRUE;
}
}
return FALSE;
}
static void BuildAreaGlowTilemap(void)
{
u16 i, y, x, j;
2021-12-29 09:23:58 +01:00
// Reset tilemap
for (i = 0; i < ARRAY_COUNT(sPokedexAreaScreen->areaGlowTilemap); i++)
2018-11-30 17:41:03 +01:00
sPokedexAreaScreen->areaGlowTilemap[i] = 0;
2021-12-29 09:23:58 +01:00
// For each area with this species, scan the region map layout and find any locations that have a matching mapsec.
// Add a "full glow" indicator for these matching spaces.
2018-11-30 17:41:03 +01:00
for (i = 0; i < sPokedexAreaScreen->numOverworldAreas; i++)
{
j = 0;
for (y = 0; y < AREA_SCREEN_HEIGHT; y++)
2018-11-30 17:41:03 +01:00
{
for (x = 0; x < AREA_SCREEN_WIDTH; x++)
2018-11-30 17:41:03 +01:00
{
2020-02-05 08:47:32 +01:00
if (GetRegionMapSecIdAt(x, y) == sPokedexAreaScreen->overworldAreasWithMons[i].regionMapSectionId)
2021-12-29 09:23:58 +01:00
sPokedexAreaScreen->areaGlowTilemap[j] = GLOW_FULL;
2018-11-30 17:41:03 +01:00
j++;
}
}
}
2021-12-29 09:23:58 +01:00
// Scan the tilemap. For every "full glow" indicator added above, fill in its edges and corners.
2018-11-30 17:41:03 +01:00
j = 0;
for (y = 0; y < AREA_SCREEN_HEIGHT; y++)
2018-11-30 17:41:03 +01:00
{
for (x = 0; x < AREA_SCREEN_WIDTH; x++)
2018-11-30 17:41:03 +01:00
{
2021-12-29 09:23:58 +01:00
if (sPokedexAreaScreen->areaGlowTilemap[j] == GLOW_FULL)
2018-11-30 17:41:03 +01:00
{
2021-12-29 09:23:58 +01:00
// The "tile != GLOW_FULL" check is pointless in all of these conditionals,
// since there's no harm in OR'ing 0xFFFF with anything else.
// Edges
2021-12-29 09:23:58 +01:00
if (x != 0 && sPokedexAreaScreen->areaGlowTilemap[j - 1] != GLOW_FULL)
sPokedexAreaScreen->areaGlowTilemap[j - 1] |= GLOW_EDGE_L;
if (x != AREA_SCREEN_WIDTH - 1 && sPokedexAreaScreen->areaGlowTilemap[j + 1] != GLOW_FULL)
sPokedexAreaScreen->areaGlowTilemap[j + 1] |= GLOW_EDGE_R;
if (y != 0 && sPokedexAreaScreen->areaGlowTilemap[j - AREA_SCREEN_WIDTH] != GLOW_FULL)
sPokedexAreaScreen->areaGlowTilemap[j - AREA_SCREEN_WIDTH] |= GLOW_EDGE_T;
if (y != AREA_SCREEN_HEIGHT - 1 && sPokedexAreaScreen->areaGlowTilemap[j + AREA_SCREEN_WIDTH] != GLOW_FULL)
sPokedexAreaScreen->areaGlowTilemap[j + AREA_SCREEN_WIDTH] |= GLOW_EDGE_B;
// Corners
if (x != 0 && y != 0 && sPokedexAreaScreen->areaGlowTilemap[j - AREA_SCREEN_WIDTH - 1] != GLOW_FULL)
sPokedexAreaScreen->areaGlowTilemap[j - AREA_SCREEN_WIDTH - 1] |= GLOW_CORNER_TL;
if (x != AREA_SCREEN_WIDTH - 1 && y != 0 && sPokedexAreaScreen->areaGlowTilemap[j - AREA_SCREEN_WIDTH + 1] != GLOW_FULL)
sPokedexAreaScreen->areaGlowTilemap[j - AREA_SCREEN_WIDTH + 1] |= GLOW_CORNER_TR;
if (x != 0 && y != AREA_SCREEN_HEIGHT - 1 && sPokedexAreaScreen->areaGlowTilemap[j + AREA_SCREEN_WIDTH - 1] != GLOW_FULL)
sPokedexAreaScreen->areaGlowTilemap[j + AREA_SCREEN_WIDTH - 1] |= GLOW_CORNER_BL;
if (x != AREA_SCREEN_WIDTH - 1 && y != AREA_SCREEN_HEIGHT - 1 && sPokedexAreaScreen->areaGlowTilemap[j + AREA_SCREEN_WIDTH + 1] != GLOW_FULL)
sPokedexAreaScreen->areaGlowTilemap[j + AREA_SCREEN_WIDTH + 1] |= GLOW_CORNER_BR;
2018-11-30 17:41:03 +01:00
}
j++;
}
}
2021-12-29 09:23:58 +01:00
// Scan the tilemap again. Replace the "full tile" indicators with the actual tile id,
// and remove corner flags when they're overlapped by an edge.
for (i = 0; i < ARRAY_COUNT(sPokedexAreaScreen->areaGlowTilemap); i++)
2018-11-30 17:41:03 +01:00
{
2021-12-29 09:23:58 +01:00
if (sPokedexAreaScreen->areaGlowTilemap[i] == GLOW_FULL)
2018-11-30 17:41:03 +01:00
{
2021-12-29 09:23:58 +01:00
sPokedexAreaScreen->areaGlowTilemap[i] = GLOW_TILE_FULL;
sPokedexAreaScreen->areaGlowTilemap[i] |= (GLOW_PALETTE << 12);
2018-11-30 17:41:03 +01:00
}
else if (sPokedexAreaScreen->areaGlowTilemap[i])
{
2021-12-29 09:23:58 +01:00
// Get rid of overlapping flags.
// This is pointless, as sAreaGlowTilemapMapping can handle overlaps.
if (sPokedexAreaScreen->areaGlowTilemap[i] & GLOW_EDGE_L)
sPokedexAreaScreen->areaGlowTilemap[i] &= ~(GLOW_CORNER_TL | GLOW_CORNER_BL);
if (sPokedexAreaScreen->areaGlowTilemap[i] & GLOW_EDGE_R)
sPokedexAreaScreen->areaGlowTilemap[i] &= ~(GLOW_CORNER_TR | GLOW_CORNER_BR);
if (sPokedexAreaScreen->areaGlowTilemap[i] & GLOW_EDGE_T)
sPokedexAreaScreen->areaGlowTilemap[i] &= ~(GLOW_CORNER_TR | GLOW_CORNER_TL);
if (sPokedexAreaScreen->areaGlowTilemap[i] & GLOW_EDGE_B)
sPokedexAreaScreen->areaGlowTilemap[i] &= ~(GLOW_CORNER_BR | GLOW_CORNER_BL);
// Assign tile id
2018-11-30 17:41:03 +01:00
sPokedexAreaScreen->areaGlowTilemap[i] = sAreaGlowTilemapMapping[sPokedexAreaScreen->areaGlowTilemap[i]];
2021-12-29 09:23:58 +01:00
sPokedexAreaScreen->areaGlowTilemap[i] |= (GLOW_PALETTE << 12);
2018-11-30 17:41:03 +01:00
}
}
}
static void StartAreaGlow(void)
{
if (sPokedexAreaScreen->numSpecialAreas && sPokedexAreaScreen->numOverworldAreas == 0)
2021-12-29 09:23:58 +01:00
sPokedexAreaScreen->showingMarkers = TRUE;
2018-11-30 17:41:03 +01:00
else
2021-12-29 09:23:58 +01:00
sPokedexAreaScreen->showingMarkers = FALSE;
2018-11-30 17:41:03 +01:00
2021-12-29 09:23:58 +01:00
sPokedexAreaScreen->markerTimer = 0;
sPokedexAreaScreen->glowTimer = 0;
2018-11-30 17:41:03 +01:00
sPokedexAreaScreen->areaShadeBldArgLo = 0;
2021-12-29 09:23:58 +01:00
sPokedexAreaScreen->areaShadeBldArgHi = 64;
sPokedexAreaScreen->markerFlashCounter = 1;
2018-11-30 17:41:03 +01:00
SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG2 | BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_ALL);
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(0, 16));
DoAreaGlow();
}
static void DoAreaGlow(void)
{
u16 x, y;
u16 i;
2021-12-29 09:23:58 +01:00
if (!sPokedexAreaScreen->showingMarkers)
2018-11-30 17:41:03 +01:00
{
2021-12-29 09:23:58 +01:00
// Showing area glow
if (sPokedexAreaScreen->markerTimer == 0)
2018-11-30 17:41:03 +01:00
{
2021-12-29 09:23:58 +01:00
sPokedexAreaScreen->glowTimer++;
if (sPokedexAreaScreen->glowTimer & 1)
2018-11-30 17:41:03 +01:00
sPokedexAreaScreen->areaShadeBldArgLo = (sPokedexAreaScreen->areaShadeBldArgLo + 4) & 0x7f;
else
sPokedexAreaScreen->areaShadeBldArgHi = (sPokedexAreaScreen->areaShadeBldArgHi + 4) & 0x7f;
x = gSineTable[sPokedexAreaScreen->areaShadeBldArgLo] >> 4;
y = gSineTable[sPokedexAreaScreen->areaShadeBldArgHi] >> 4;
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(x, y));
2021-12-29 09:23:58 +01:00
sPokedexAreaScreen->markerTimer = 0;
if (sPokedexAreaScreen->glowTimer == 64)
2018-11-30 17:41:03 +01:00
{
2021-12-29 09:23:58 +01:00
// Done glowing, reset and try to switch to the special area markers
sPokedexAreaScreen->glowTimer = 0;
2018-11-30 17:41:03 +01:00
if (sPokedexAreaScreen->numSpecialAreas != 0)
2021-12-29 09:23:58 +01:00
sPokedexAreaScreen->showingMarkers = TRUE;
2018-11-30 17:41:03 +01:00
}
}
else
2021-12-29 09:23:58 +01:00
sPokedexAreaScreen->markerTimer--;
2018-11-30 17:41:03 +01:00
}
else
{
2021-12-29 09:23:58 +01:00
// Showing special area markers
sPokedexAreaScreen->markerTimer++;
if (sPokedexAreaScreen->markerTimer > 12)
2018-11-30 17:41:03 +01:00
{
2021-12-29 09:23:58 +01:00
sPokedexAreaScreen->markerTimer = 0;
// Flash the marker
// With a max of 4, the marker will disappear twice
sPokedexAreaScreen->markerFlashCounter++;
2018-11-30 17:41:03 +01:00
for (i = 0; i < sPokedexAreaScreen->numSpecialAreas; i++)
2021-12-29 09:23:58 +01:00
sPokedexAreaScreen->areaMarkerSprites[i]->invisible = sPokedexAreaScreen->markerFlashCounter & 1;
2018-11-30 17:41:03 +01:00
2021-12-29 09:23:58 +01:00
if (sPokedexAreaScreen->markerFlashCounter > 4)
2018-11-30 17:41:03 +01:00
{
2021-12-29 09:23:58 +01:00
// Done flashing, reset and try to switch to the area glow
sPokedexAreaScreen->markerFlashCounter = 1;
2018-11-30 17:41:03 +01:00
if (sPokedexAreaScreen->numOverworldAreas != 0)
2021-12-29 09:23:58 +01:00
sPokedexAreaScreen->showingMarkers = FALSE;
2018-11-30 17:41:03 +01:00
}
}
}
}
2020-03-08 18:24:22 +01:00
#define tState data[0]
void ShowPokedexAreaScreen(u16 species, u8 *screenSwitchState)
2018-11-30 17:41:03 +01:00
{
u8 taskId;
sPokedexAreaScreen = AllocZeroed(sizeof(*sPokedexAreaScreen));
sPokedexAreaScreen->species = species;
2020-03-08 18:24:22 +01:00
sPokedexAreaScreen->screenSwitchState = screenSwitchState;
screenSwitchState[0] = 0;
taskId = CreateTask(Task_ShowPokedexAreaScreen, 0);
gTasks[taskId].tState = 0;
2018-11-30 17:41:03 +01:00
}
2020-03-08 18:24:22 +01:00
static void Task_ShowPokedexAreaScreen(u8 taskId)
2018-11-30 17:41:03 +01:00
{
2020-03-08 18:24:22 +01:00
switch (gTasks[taskId].tState)
2018-11-30 17:41:03 +01:00
{
2021-12-29 09:23:58 +01:00
case 0:
ResetSpriteData();
FreeAllSpritePalettes();
HideBg(3);
HideBg(2);
HideBg(0);
break;
case 1:
SetBgAttribute(3, BG_ATTR_CHARBASEINDEX, 3);
LoadPokedexAreaMapGfx(&sPokedexAreaMapTemplate);
StringFill(sPokedexAreaScreen->charBuffer, CHAR_SPACE, 16);
break;
case 2:
if (TryShowPokedexAreaMap() == TRUE)
2018-11-30 17:41:03 +01:00
return;
2021-12-29 09:23:58 +01:00
PokedexAreaMapChangeBgY(-8);
break;
case 3:
ResetDrawAreaGlowState();
break;
case 4:
if (DrawAreaGlow())
return;
break;
case 5:
ShowRegionMapForPokedexAreaScreen(&sPokedexAreaScreen->regionMap);
CreateRegionMapPlayerIcon(1, 1);
PokedexAreaScreen_UpdateRegionMapVariablesAndVideoRegs(0, -8);
break;
case 6:
CreateAreaMarkerSprites();
break;
case 7:
LoadAreaUnknownGraphics();
break;
case 8:
CreateAreaUnknownSprites();
break;
case 9:
BeginNormalPaletteFade(PALETTES_ALL & ~(0x14), 0, 16, 0, RGB_BLACK);
break;
case 10:
SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG0 | BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_BG0 | BLDCNT_TGT2_ALL);
StartAreaGlow();
ShowBg(2);
ShowBg(3); // TryShowPokedexAreaMap will have done this already
SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON);
break;
case 11:
gTasks[taskId].func = Task_HandlePokedexAreaScreenInput;
gTasks[taskId].tState = 0;
return;
2018-11-30 17:41:03 +01:00
}
2020-03-08 18:24:22 +01:00
gTasks[taskId].tState++;
2018-11-30 17:41:03 +01:00
}
2020-03-08 18:24:22 +01:00
static void Task_HandlePokedexAreaScreenInput(u8 taskId)
2018-11-30 17:41:03 +01:00
{
DoAreaGlow();
2020-03-08 18:24:22 +01:00
switch (gTasks[taskId].tState)
2018-11-30 17:41:03 +01:00
{
default:
2020-03-08 18:24:22 +01:00
gTasks[taskId].tState = 0;
2018-11-30 17:41:03 +01:00
// fall through
case 0:
if (gPaletteFade.active)
return;
break;
case 1:
2020-09-05 03:11:55 +02:00
if (JOY_NEW(B_BUTTON))
2018-11-30 17:41:03 +01:00
{
gTasks[taskId].data[1] = 1;
PlaySE(SE_PC_OFF);
}
2020-09-05 03:11:55 +02:00
else if (JOY_NEW(DPAD_RIGHT) || (JOY_NEW(R_BUTTON) && gSaveBlock2Ptr->optionsButtonMode == OPTIONS_BUTTON_MODE_LR))
2018-11-30 17:41:03 +01:00
{
gTasks[taskId].data[1] = 2;
2020-08-21 00:02:00 +02:00
PlaySE(SE_DEX_PAGE);
2018-11-30 17:41:03 +01:00
}
else
return;
break;
case 2:
2021-02-24 17:01:02 +01:00
BeginNormalPaletteFade(PALETTES_ALL & ~(0x14), 0, 0, 16, RGB_BLACK);
2018-11-30 17:41:03 +01:00
break;
case 3:
if (gPaletteFade.active)
return;
2021-12-29 09:23:58 +01:00
DestroyAreaScreenSprites();
2020-03-08 18:24:22 +01:00
sPokedexAreaScreen->screenSwitchState[0] = gTasks[taskId].data[1];
2021-09-24 20:30:15 +02:00
ResetPokedexAreaMapBg();
2018-11-30 17:41:03 +01:00
DestroyTask(taskId);
2020-02-05 08:47:32 +01:00
FreePokedexAreaMapBgNum();
2018-11-30 17:41:03 +01:00
FREE_AND_SET_NULL(sPokedexAreaScreen);
return;
}
2020-03-08 18:24:22 +01:00
gTasks[taskId].tState++;
2018-11-30 17:41:03 +01:00
}
2021-09-24 20:30:15 +02:00
static void ResetPokedexAreaMapBg(void)
2018-11-30 17:41:03 +01:00
{
2018-12-26 13:05:02 +01:00
SetBgAttribute(3, BG_ATTR_CHARBASEINDEX, 0);
SetBgAttribute(3, BG_ATTR_PALETTEMODE, 0);
2018-11-30 17:41:03 +01:00
}
2021-12-29 09:23:58 +01:00
// Creates the circular sprites to highlight special areas (like caves) where a Pokémon can be found
2018-11-30 17:41:03 +01:00
static void CreateAreaMarkerSprites(void)
{
u8 spriteId;
static s16 x;
static s16 y;
static s16 i;
static s16 mapSecId;
static s16 numSprites;
2018-11-30 17:41:03 +01:00
LoadSpriteSheet(&sAreaMarkerSpriteSheet);
LoadSpritePalette(&sAreaMarkerSpritePalette);
numSprites = 0;
for (i = 0; i < sPokedexAreaScreen->numSpecialAreas; i++)
{
mapSecId = sPokedexAreaScreen->specialAreaRegionMapSectionIds[i];
x = 8 * (gRegionMapEntries[mapSecId].x + 1) + 4;
y = 8 * (gRegionMapEntries[mapSecId].y) + 28;
x += 4 * (gRegionMapEntries[mapSecId].width - 1);
y += 4 * (gRegionMapEntries[mapSecId].height - 1);
spriteId = CreateSprite(&sAreaMarkerSpriteTemplate, x, y, 0);
if (spriteId != MAX_SPRITES)
{
gSprites[spriteId].invisible = TRUE;
sPokedexAreaScreen->areaMarkerSprites[numSprites++] = &gSprites[spriteId];
}
}
sPokedexAreaScreen->numAreaMarkerSprites = numSprites;
}
2021-12-29 09:23:58 +01:00
static void DestroyAreaScreenSprites(void)
2018-11-30 17:41:03 +01:00
{
u16 i;
2021-12-29 09:23:58 +01:00
// Destroy area marker sprites
FreeSpriteTilesByTag(TAG_AREA_MARKER);
FreeSpritePaletteByTag(TAG_AREA_MARKER);
2018-11-30 17:41:03 +01:00
for (i = 0; i < sPokedexAreaScreen->numAreaMarkerSprites; i++)
DestroySprite(sPokedexAreaScreen->areaMarkerSprites[i]);
2021-12-29 09:23:58 +01:00
// Destroy "Area Unknown" sprites
FreeSpriteTilesByTag(TAG_AREA_UNKNOWN);
FreeSpritePaletteByTag(TAG_AREA_UNKNOWN);
for (i = 0; i < ARRAY_COUNT(sPokedexAreaScreen->areaUnknownSprites); i++)
2018-11-30 17:41:03 +01:00
{
if (sPokedexAreaScreen->areaUnknownSprites[i])
DestroySprite(sPokedexAreaScreen->areaUnknownSprites[i]);
}
}
static void LoadAreaUnknownGraphics(void)
{
struct SpriteSheet spriteSheet = {
.data = sPokedexAreaScreen->areaUnknownGraphicsBuffer,
2021-12-29 09:23:58 +01:00
.size = sizeof(sPokedexAreaScreen->areaUnknownGraphicsBuffer),
.tag = TAG_AREA_UNKNOWN,
2018-11-30 17:41:03 +01:00
};
LZ77UnCompWram(gPokedexAreaScreenAreaUnknown_Gfx, sPokedexAreaScreen->areaUnknownGraphicsBuffer);
LoadSpriteSheet(&spriteSheet);
LoadSpritePalette(&sAreaUnknownSpritePalette);
}
static void CreateAreaUnknownSprites(void)
{
u16 i;
if (sPokedexAreaScreen->numOverworldAreas || sPokedexAreaScreen->numSpecialAreas)
{
2021-12-29 09:23:58 +01:00
// The current species is present on the map, don't create any "Area Unknown" sprites
for (i = 0; i < ARRAY_COUNT(sPokedexAreaScreen->areaUnknownSprites); i++)
2018-11-30 17:41:03 +01:00
sPokedexAreaScreen->areaUnknownSprites[i] = NULL;
}
else
{
2021-12-29 09:23:58 +01:00
// The current species is absent on the map, try to create "Area Unknown" sprites
for (i = 0; i < ARRAY_COUNT(sPokedexAreaScreen->areaUnknownSprites); i++)
2018-11-30 17:41:03 +01:00
{
2021-12-29 09:23:58 +01:00
u8 spriteId = CreateSprite(&sAreaUnknownSpriteTemplate, i * 32 + 160, 140, 0);
2018-11-30 17:41:03 +01:00
if (spriteId != MAX_SPRITES)
{
gSprites[spriteId].oam.tileNum += i * 16;
2021-12-29 09:23:58 +01:00
sPokedexAreaScreen->areaUnknownSprites[i] = &gSprites[spriteId];
2018-11-30 17:41:03 +01:00
}
else
{
2021-12-29 09:23:58 +01:00
// Failed to create sprite
2018-11-30 17:41:03 +01:00
sPokedexAreaScreen->areaUnknownSprites[i] = NULL;
}
}
}
}