mirror of
https://github.com/risingPhil/libpokemegb.git
synced 2026-03-21 17:44:24 -05:00
Implement gen 2 party icon decoding
Now you can also decode the party icons for the gen 2 pokémon games
This commit is contained in:
parent
04bc493c03
commit
a44b908587
|
|
@ -1,5 +1,5 @@
|
|||
#include "gen1/Gen1GameReader.h"
|
||||
#include "gen1/Gen1SpriteDecoder.h"
|
||||
#include "gen2/Gen2GameReader.h"
|
||||
#include "SpriteRenderer.h"
|
||||
#include "RomReader.h"
|
||||
#include "SaveManager.h"
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
using OutputFormat = SpriteRenderer::OutputFormat;
|
||||
using TileOrder = SpriteRenderer::TileOrder;
|
||||
|
||||
void decodeGen1Icon(IRomReader& romReader, ISaveManager& saveManager, Gen1GameType gen1Type, Gen1PokemonIconType iconType, bool firstFrame)
|
||||
static void decodeGen1Icon(IRomReader& romReader, ISaveManager& saveManager, Gen1GameType gen1Type, Gen1PokemonIconType iconType, bool firstFrame)
|
||||
{
|
||||
Gen1GameReader gameReader(romReader, saveManager, gen1Type);
|
||||
SpriteRenderer renderer;
|
||||
|
|
@ -29,8 +29,24 @@ void decodeGen1Icon(IRomReader& romReader, ISaveManager& saveManager, Gen1GameTy
|
|||
write_png(fileNameBuf, outputBuffer, 2 * 8, 2 * 8, false);
|
||||
}
|
||||
|
||||
static void decodeGen2Icon(IRomReader& romReader, ISaveManager& saveManager, Gen2GameType gen2Type, Gen2PokemonIconType iconType, bool firstFrame)
|
||||
{
|
||||
Gen2GameReader gameReader(romReader, saveManager, gen2Type);
|
||||
SpriteRenderer renderer;
|
||||
char fileNameBuf[100];
|
||||
uint8_t *outputBuffer;
|
||||
|
||||
void decodeGen1Icons(IRomReader& romReader, ISaveManager& saveManager, Gen1GameType gen1Type)
|
||||
outputBuffer = gameReader.decodePokemonIcon(iconType, renderer, OutputFormat::RGB, firstFrame);
|
||||
if(!outputBuffer)
|
||||
{
|
||||
fprintf(stderr, "ERROR: Could not decode icon for icon type %d and firstFrame %d!\n", (int)iconType, firstFrame);
|
||||
return;
|
||||
}
|
||||
snprintf(fileNameBuf, sizeof(fileNameBuf), "%d_frame%u.png", (int)iconType, (firstFrame) ? 1 : 2);
|
||||
write_png(fileNameBuf, outputBuffer, 2 * 8, 2 * 8, false);
|
||||
}
|
||||
|
||||
static void decodeGen1Icons(IRomReader& romReader, ISaveManager& saveManager, Gen1GameType gen1Type)
|
||||
{
|
||||
for(int i=0; i < GEN1_ICONTYPE_MAX; ++i)
|
||||
{
|
||||
|
|
@ -39,6 +55,15 @@ void decodeGen1Icons(IRomReader& romReader, ISaveManager& saveManager, Gen1GameT
|
|||
}
|
||||
}
|
||||
|
||||
static void decodeGen2Icons(IRomReader& romReader, ISaveManager& saveManager, Gen2GameType gen2Type)
|
||||
{
|
||||
for(int i=1; i < GEN2_ICONTYPE_MAX; ++i)
|
||||
{
|
||||
decodeGen2Icon(romReader, saveManager, gen2Type, (Gen2PokemonIconType)i, true);
|
||||
decodeGen2Icon(romReader, saveManager, gen2Type, (Gen2PokemonIconType)i, false);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if(argc != 2)
|
||||
|
|
@ -65,13 +90,19 @@ int main(int argc, char** argv)
|
|||
|
||||
//check if we're dealing with gen 1
|
||||
const Gen1GameType gen1Type = gen1_determineGameType(cartridgeHeader);
|
||||
if(gen1Type == Gen1GameType::INVALID)
|
||||
const Gen2GameType gen2Type = gen2_determineGameType(cartridgeHeader);
|
||||
if(gen1Type != Gen1GameType::INVALID)
|
||||
{
|
||||
fprintf(stderr, "ERROR: sorry, this tool only supports gen 1!\n");
|
||||
return 1;
|
||||
decodeGen1Icons(romReader, saveManager, gen1Type);
|
||||
}
|
||||
else if(gen2Type != Gen2GameType::INVALID)
|
||||
{
|
||||
decodeGen2Icons(romReader, saveManager, gen2Type);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "ERROR: The specified rom is not a gen 1 or gen 2 pokémon game!\n");
|
||||
}
|
||||
|
||||
decodeGen1Icons(romReader, saveManager, gen1Type);
|
||||
|
||||
free(romBuffer);
|
||||
romBuffer = 0;
|
||||
|
|
|
|||
|
|
@ -94,6 +94,50 @@ enum Gen2ItemListType
|
|||
GEN2_ITEMLISTTYPE_MAX
|
||||
};
|
||||
|
||||
enum Gen2PokemonIconType
|
||||
{
|
||||
GEN2_ICONTYPE_NULL,
|
||||
GEN2_ICONTYPE_POLIWAG,
|
||||
GEN2_ICONTYPE_JIGGLYPUFF,
|
||||
GEN2_ICONTYPE_DIGLETT,
|
||||
GEN2_ICONTYPE_PIKACHU,
|
||||
GEN2_ICONTYPE_STARYU,
|
||||
GEN2_ICONTYPE_FISH,
|
||||
GEN2_ICONTYPE_BIRD,
|
||||
GEN2_ICONTYPE_MONSTER,
|
||||
GEN2_ICONTYPE_CLEFAIRY,
|
||||
GEN2_ICONTYPE_ODDISH,
|
||||
GEN2_ICONTYPE_BUG,
|
||||
GEN2_ICONTYPE_GHOST,
|
||||
GEN2_ICONTYPE_LAPRAS,
|
||||
GEN2_ICONTYPE_HUMANSHAPE,
|
||||
GEN2_ICONTYPE_FOX,
|
||||
GEN2_ICONTYPE_EQUINE,
|
||||
GEN2_ICONTYPE_SHELL,
|
||||
GEN2_ICONTYPE_BLOB,
|
||||
GEN2_ICONTYPE_SERPENT,
|
||||
GEN2_ICONTYPE_VOLTORB,
|
||||
GEN2_ICONTYPE_SQUIRTLE,
|
||||
GEN2_ICONTYPE_BULBASAUR,
|
||||
GEN2_ICONTYPE_CHARMANDER,
|
||||
GEN2_ICONTYPE_CATERPILLAR,
|
||||
GEN2_ICONTYPE_UNOWN,
|
||||
GEN2_ICONTYPE_GEODUDE,
|
||||
GEN2_ICONTYPE_FIGHTER,
|
||||
GEN2_ICONTYPE_EGG,
|
||||
GEN2_ICONTYPE_JELLYFISH,
|
||||
GEN2_ICONTYPE_MOTH,
|
||||
GEN2_ICONTYPE_BAT,
|
||||
GEN2_ICONTYPE_SNORLAX,
|
||||
GEN2_ICONTYPE_HO_OH,
|
||||
GEN2_ICONTYPE_LUGIA,
|
||||
GEN2_ICONTYPE_GYARADOS,
|
||||
GEN2_ICONTYPE_SLOWPOKE,
|
||||
GEN2_ICONTYPE_SUDOWOODO,
|
||||
GEN2_ICONTYPE_BIGMON,
|
||||
GEN2_ICONTYPE_MAX
|
||||
};
|
||||
|
||||
typedef struct Gen2TrainerPokemon
|
||||
{
|
||||
uint8_t poke_index;
|
||||
|
|
@ -129,6 +173,8 @@ typedef struct Gen2TrainerPokemon
|
|||
uint16_t special_def;
|
||||
} Gen2TrainerPokemon;
|
||||
|
||||
extern uint16_t gen2_iconColorPalette[4];
|
||||
|
||||
class Gen2ItemList
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "gen2/Gen2SpriteDecoder.h"
|
||||
#include "gen2/Gen2PlayerPokemonStorage.h"
|
||||
#include "gen2/Gen2DistributionPokemon.h"
|
||||
#include "SpriteRenderer.h"
|
||||
|
||||
class IRomReader;
|
||||
class ISaveManager;
|
||||
|
|
@ -28,6 +29,11 @@ public:
|
|||
*/
|
||||
const char *getPokemonName(uint8_t index) const;
|
||||
|
||||
/**
|
||||
* Returns the specific icon type for a given pokémon
|
||||
*/
|
||||
Gen2PokemonIconType getPokemonIconType(uint8_t index) const;
|
||||
|
||||
/**
|
||||
* @brief With this function, you can check if the index is valid and not referring to garbage data
|
||||
*/
|
||||
|
|
@ -68,6 +74,12 @@ public:
|
|||
*/
|
||||
uint8_t *decodeSprite(uint8_t bankIndex, uint16_t pointer);
|
||||
|
||||
/**
|
||||
* @brief This function decodes the given pokemon icon and returns the internal buffer of the given SpriteRenderer instance
|
||||
* The size of the returned buffer is 16x16 pixels
|
||||
*/
|
||||
uint8_t* decodePokemonIcon(Gen2PokemonIconType iconType, SpriteRenderer& renderer, SpriteRenderer::OutputFormat outputFormat, bool firstFrame = true);
|
||||
|
||||
/**
|
||||
* @brief Adds a pokemon to the save. Tries to add it to the party first. If there's no more room there, it tries to add it to the
|
||||
* first ingame PC box with open slots.
|
||||
|
|
|
|||
|
|
@ -11,6 +11,13 @@
|
|||
#define POKEMON_SILVER_CARTRIDGE_TITLE "POKEMON_SLV"
|
||||
#define POKEMON_CRYSTAL_CARTRIDGE_TITLE "PM_CRYSTAL"
|
||||
|
||||
uint16_t gen2_iconColorPalette[4] = {
|
||||
0x7FFF,
|
||||
0x2A5E,
|
||||
0x10FE,
|
||||
0x0
|
||||
};
|
||||
|
||||
static TextCodePair gen2TextCodes[] = {
|
||||
{0x56, "……"},
|
||||
{0x5D, "TRAINER"},
|
||||
|
|
|
|||
|
|
@ -304,6 +304,18 @@ const char *Gen2GameReader::getPokemonName(uint8_t index) const
|
|||
return result;
|
||||
}
|
||||
|
||||
Gen2PokemonIconType Gen2GameReader::getPokemonIconType(uint8_t index) const
|
||||
{
|
||||
const uint32_t romOffset = (isGameCrystal()) ? 0x8EAC4 : 0x8E975;
|
||||
uint8_t byteVal;
|
||||
|
||||
romReader_.seek(romOffset);
|
||||
romReader_.advance((index - 1));
|
||||
romReader_.readByte(byteVal);
|
||||
|
||||
return (Gen2PokemonIconType)byteVal;
|
||||
}
|
||||
|
||||
bool Gen2GameReader::isValidIndex(uint8_t index) const
|
||||
{
|
||||
return (index != 0) && (index < 252);
|
||||
|
|
@ -450,6 +462,40 @@ uint8_t *Gen2GameReader::decodeSprite(uint8_t bankIndex, uint16_t pointer)
|
|||
return spriteDecoder_.decode(bankIndex, pointer);
|
||||
}
|
||||
|
||||
uint8_t *Gen2GameReader::decodePokemonIcon(Gen2PokemonIconType iconType, SpriteRenderer& renderer, SpriteRenderer::OutputFormat outputFormat, bool firstFrame)
|
||||
{
|
||||
const uint32_t romOffset = (gameType_ == Gen2GameType::CRYSTAL) ? 0x8EBBF : 0x8EA70;
|
||||
const uint8_t MAX_NUM_TILES = 4;
|
||||
const uint8_t TILE_WIDTH = 8;
|
||||
const uint8_t TILE_HEIGHT = 8;
|
||||
const uint8_t BITS_PER_PIXEL = 2;
|
||||
const uint8_t BYTES_PER_TILE = ((TILE_WIDTH * TILE_HEIGHT) / 8) * BITS_PER_PIXEL;
|
||||
const uint8_t TILES_PER_ICON = 4;
|
||||
const uint32_t ENTRY_SIZE = 2;
|
||||
uint8_t iconSrcBuffer[MAX_NUM_TILES * BYTES_PER_TILE];
|
||||
const uint8_t bankIndex = 0x23;
|
||||
uint16_t pointer;
|
||||
|
||||
// read IconPointers table entry
|
||||
romReader_.seek(romOffset);
|
||||
romReader_.advance(((uint32_t)iconType) * ENTRY_SIZE);
|
||||
romReader_.readUint16(pointer);
|
||||
|
||||
// now jump to the pointer to find the sprite
|
||||
romReader_.seekToRomPointer(pointer, bankIndex);
|
||||
|
||||
// every sprite contains 2 frames.
|
||||
// if we want the second one, we need to skip 1 16x16 sprite
|
||||
if(!firstFrame)
|
||||
{
|
||||
romReader_.advance(TILES_PER_ICON * BYTES_PER_TILE);
|
||||
}
|
||||
|
||||
romReader_.read(iconSrcBuffer, TILES_PER_ICON * BYTES_PER_TILE);
|
||||
|
||||
return renderer.draw(iconSrcBuffer, outputFormat, gen2_iconColorPalette, 2, 2, SpriteRenderer::TileOrder::HORIZONTAL);
|
||||
}
|
||||
|
||||
uint8_t Gen2GameReader::addPokemon(Gen2TrainerPokemon &poke, bool isEgg, const char *originalTrainerID, const char *nickname)
|
||||
{
|
||||
Gen2Party party = getParty();
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user