mirror of
https://github.com/risingPhil/libpokemegb.git
synced 2026-03-21 17:44:24 -05:00
Merge pull request #8 from risingPhil/feature/support-trainer-money
Support reading and writing the trainers' money from the save file.
This commit is contained in:
commit
06f894d52c
116
Makefile
116
Makefile
|
|
@ -1,58 +1,58 @@
|
|||
# # Compiler flags
|
||||
CXXFLAGS := -std=c++11 -fno-rtti -fno-exceptions -fno-unwind-tables -Wall -Wextra -I $(CURDIR) -I $(CURDIR)/include -g -Os
|
||||
|
||||
# Source files directory
|
||||
SRC_DIR := src
|
||||
# Build directory
|
||||
BUILD_DIR := build
|
||||
|
||||
# Source files (add more as needed)
|
||||
SRCS := $(shell find $(SRC_DIR) -type f -name '*.cpp')
|
||||
# Object files
|
||||
OBJS := $(patsubst $(SRC_DIR)/%.cpp,$(BUILD_DIR)/%.o,$(SRCS))
|
||||
|
||||
PNG_SUPPORT ?= 1
|
||||
|
||||
# Add PNG support flag if PNG_SUPPORT is set to 1
|
||||
ifeq ($(PNG_SUPPORT),1)
|
||||
CXXFLAGS += -DPNG_SUPPORT
|
||||
MAKEOVERRIDES := PNG_SUPPORT=1
|
||||
endif
|
||||
|
||||
# Ensure necessary directories exist
|
||||
# This function ensures the directory for the target exists
|
||||
define make_directory
|
||||
@mkdir -p $(dir $@)
|
||||
endef
|
||||
|
||||
# Target executable
|
||||
TARGET := libpokemegb.a
|
||||
|
||||
# Phony targets
|
||||
.PHONY: all clean
|
||||
|
||||
# Default target
|
||||
all: $(TARGET) examples
|
||||
|
||||
examples: $(TARGET)
|
||||
$(MAKE) -C examples $(MAKECMDGOALS) $(MAKEOVERRIDES)
|
||||
|
||||
# Rule to build the target executable
|
||||
$(TARGET): $(OBJS)
|
||||
@echo "Creating static library $(TARGET)"
|
||||
ar rcs $@ $(OBJS)
|
||||
ranlib $(TARGET)
|
||||
|
||||
# Rule to compile source files
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp | $(BUILD_DIR) $(C_FILE)
|
||||
$(make_directory)
|
||||
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
# Create the build directory if it doesn't exist
|
||||
$(BUILD_DIR):
|
||||
mkdir -p $(BUILD_DIR)
|
||||
|
||||
# Clean rule
|
||||
clean:
|
||||
make -C examples clean $(MAKEOVERRIDES)
|
||||
rm -rf $(BUILD_DIR) $(TARGET)
|
||||
# # Compiler flags
|
||||
CXXFLAGS := -std=c++11 -fno-rtti -fno-exceptions -fno-unwind-tables -Wall -Wextra -I $(CURDIR) -I $(CURDIR)/include -g -Os
|
||||
|
||||
# Source files directory
|
||||
SRC_DIR := src
|
||||
# Build directory
|
||||
BUILD_DIR := build
|
||||
|
||||
# Source files (add more as needed)
|
||||
SRCS := $(shell find $(SRC_DIR) -type f -name '*.cpp')
|
||||
# Object files
|
||||
OBJS := $(patsubst $(SRC_DIR)/%.cpp,$(BUILD_DIR)/%.o,$(SRCS))
|
||||
|
||||
PNG_SUPPORT ?= 1
|
||||
|
||||
# Add PNG support flag if PNG_SUPPORT is set to 1
|
||||
ifeq ($(PNG_SUPPORT),1)
|
||||
CXXFLAGS += -DPNG_SUPPORT
|
||||
MAKEOVERRIDES := PNG_SUPPORT=1
|
||||
endif
|
||||
|
||||
# Ensure necessary directories exist
|
||||
# This function ensures the directory for the target exists
|
||||
define make_directory
|
||||
@mkdir -p $(dir $@)
|
||||
endef
|
||||
|
||||
# Target executable
|
||||
TARGET := libpokemegb.a
|
||||
|
||||
# Phony targets
|
||||
.PHONY: all clean
|
||||
|
||||
# Default target
|
||||
all: $(TARGET) examples
|
||||
|
||||
examples: $(TARGET)
|
||||
$(MAKE) -C examples $(MAKECMDGOALS) $(MAKEOVERRIDES)
|
||||
|
||||
# Rule to build the target executable
|
||||
$(TARGET): $(OBJS)
|
||||
@echo "Creating static library $(TARGET)"
|
||||
ar rcs $@ $(OBJS)
|
||||
ranlib $(TARGET)
|
||||
|
||||
# Rule to compile source files
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp | $(BUILD_DIR) $(C_FILE)
|
||||
$(make_directory)
|
||||
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
# Create the build directory if it doesn't exist
|
||||
$(BUILD_DIR):
|
||||
mkdir -p $(BUILD_DIR)
|
||||
|
||||
# Clean rule
|
||||
clean:
|
||||
make -C examples clean $(MAKEOVERRIDES)
|
||||
rm -rf $(BUILD_DIR) $(TARGET)
|
||||
|
|
|
|||
|
|
@ -1,73 +1,79 @@
|
|||
#include "gen1/Gen1GameReader.h"
|
||||
#include "gen2/Gen2GameReader.h"
|
||||
#include "RomReader.h"
|
||||
#include "SaveManager.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
static void print_usage()
|
||||
{
|
||||
printf("Usage: checkSave <path/to/rom.gbc> <path/to/file.sav>\n");
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if(argc != 3)
|
||||
{
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
uint8_t* romBuffer;
|
||||
uint8_t* savBuffer;
|
||||
uint32_t romFileSize;
|
||||
uint32_t savFileSize;
|
||||
|
||||
printf("rom: %s, save: %s\n", argv[1], argv[2]);
|
||||
|
||||
romBuffer = readFileIntoBuffer(argv[1], romFileSize);
|
||||
if(!romBuffer)
|
||||
{
|
||||
fprintf(stderr, "ERROR: Couldn't read file %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
savBuffer = readFileIntoBuffer(argv[2], savFileSize);
|
||||
if(!savBuffer)
|
||||
{
|
||||
fprintf(stderr, "ERROR: Couldn't read file %s\n", argv[2]);
|
||||
free(romBuffer);
|
||||
romBuffer = nullptr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
GameboyCartridgeHeader cartridgeHeader;
|
||||
BufferBasedRomReader romReader(romBuffer, romFileSize);
|
||||
BufferBasedSaveManager saveManager(savBuffer, savFileSize);
|
||||
|
||||
readGameboyCartridgeHeader(romReader, cartridgeHeader);
|
||||
|
||||
// check if we're dealing with gen 1
|
||||
const Gen1GameType gen1Type = gen1_determineGameType(cartridgeHeader);
|
||||
const Gen2GameType gen2Type = gen2_determineGameType(cartridgeHeader);
|
||||
if (gen1Type != Gen1GameType::INVALID)
|
||||
{
|
||||
Gen1GameReader gameReader(romReader, saveManager, gen1Type);
|
||||
printf("%s", (gameReader.isMainChecksumValid()) ? "Game save valid!\n" : "Game save NOT valid!\n");
|
||||
}
|
||||
else if (gen2Type != Gen2GameType::INVALID)
|
||||
{
|
||||
Gen2GameReader gameReader(romReader, saveManager, gen2Type);
|
||||
printf("%s", (gameReader.isMainChecksumValid()) ? "Main save valid!\n" : "Main save NOT valid!\n");
|
||||
printf("%s", (gameReader.isBackupChecksumValid()) ? "Backup save valid!\n" : "Backup save NOT valid!\n");
|
||||
}
|
||||
|
||||
free(romBuffer);
|
||||
romBuffer = 0;
|
||||
|
||||
free(savBuffer);
|
||||
savBuffer = 0;
|
||||
|
||||
return 0;
|
||||
#include "gen1/Gen1GameReader.h"
|
||||
#include "gen2/Gen2GameReader.h"
|
||||
#include "RomReader.h"
|
||||
#include "SaveManager.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
static void print_usage()
|
||||
{
|
||||
printf("Usage: checkSave <path/to/rom.gbc> <path/to/file.sav>\n");
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if(argc != 3)
|
||||
{
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
uint8_t* romBuffer;
|
||||
uint8_t* savBuffer;
|
||||
uint32_t romFileSize;
|
||||
uint32_t savFileSize;
|
||||
|
||||
printf("rom: %s, save: %s\n", argv[1], argv[2]);
|
||||
|
||||
romBuffer = readFileIntoBuffer(argv[1], romFileSize);
|
||||
if(!romBuffer)
|
||||
{
|
||||
fprintf(stderr, "ERROR: Couldn't read file %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
savBuffer = readFileIntoBuffer(argv[2], savFileSize);
|
||||
if(!savBuffer)
|
||||
{
|
||||
fprintf(stderr, "ERROR: Couldn't read file %s\n", argv[2]);
|
||||
free(romBuffer);
|
||||
romBuffer = nullptr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
GameboyCartridgeHeader cartridgeHeader;
|
||||
BufferBasedRomReader romReader(romBuffer, romFileSize);
|
||||
BufferBasedSaveManager saveManager(savBuffer, savFileSize);
|
||||
|
||||
readGameboyCartridgeHeader(romReader, cartridgeHeader);
|
||||
|
||||
// check if we're dealing with gen 1
|
||||
const Gen1GameType gen1Type = gen1_determineGameType(cartridgeHeader);
|
||||
const Gen2GameType gen2Type = gen2_determineGameType(cartridgeHeader);
|
||||
if (gen1Type != Gen1GameType::INVALID)
|
||||
{
|
||||
Gen1GameReader gameReader(romReader, saveManager, gen1Type);
|
||||
printf("%s", (gameReader.isMainChecksumValid()) ? "Game save valid!\n" : "Game save NOT valid!\n");
|
||||
printf("OT: %u\n", gameReader.getTrainerID());
|
||||
printf("Name: %s\n", gameReader.getTrainerName());
|
||||
printf("Money: %u\n", gameReader.getTrainerMoney());
|
||||
}
|
||||
else if (gen2Type != Gen2GameType::INVALID)
|
||||
{
|
||||
Gen2GameReader gameReader(romReader, saveManager, gen2Type);
|
||||
printf("%s", (gameReader.isMainChecksumValid()) ? "Main save valid!\n" : "Main save NOT valid!\n");
|
||||
printf("%s", (gameReader.isBackupChecksumValid()) ? "Backup save valid!\n" : "Backup save NOT valid!\n");
|
||||
printf("OT: %u\n", gameReader.getTrainerID());
|
||||
printf("Name: %s\n", gameReader.getTrainerName());
|
||||
printf("Money: %u\n", gameReader.getTrainerMoney());
|
||||
}
|
||||
|
||||
free(romBuffer);
|
||||
romBuffer = 0;
|
||||
|
||||
free(savBuffer);
|
||||
savBuffer = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,204 +1,215 @@
|
|||
#ifndef GEN1GAMEREADER_H
|
||||
#define GEN1GAMEREADER_H
|
||||
|
||||
#include "gen1/Gen1SpriteDecoder.h"
|
||||
#include "gen1/Gen1IconDecoder.h"
|
||||
#include "gen1/Gen1PlayerPokemonStorage.h"
|
||||
#include "gen1/Gen1DistributionPokemon.h"
|
||||
#include "gen1/Gen1Localization.h"
|
||||
#include "gen1/Gen1Maps.h"
|
||||
|
||||
class IRomReader;
|
||||
class ISaveManager;
|
||||
|
||||
class Gen1GameReader
|
||||
{
|
||||
public:
|
||||
Gen1GameReader(IRomReader& romReader, ISaveManager& saveManager, Gen1GameType gameType, Gen1LocalizationLanguage language = Gen1LocalizationLanguage::MAX);
|
||||
|
||||
/**
|
||||
* @brief Retrieves the current game cartridges'/roms' language
|
||||
*/
|
||||
Gen1LocalizationLanguage getGameLanguage() const;
|
||||
|
||||
/**
|
||||
* @brief get the name of a pokémon based on an index number
|
||||
* Note: you don't own the returned pointer. The data will get overwritten on the next call to this function,
|
||||
* so make sure to strdup() it if you need to store it for later
|
||||
*
|
||||
* @return const char*
|
||||
*/
|
||||
const char* getPokemonName(uint8_t index) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the pokedex number of a pokemon at the given internal index
|
||||
*/
|
||||
uint8_t getPokemonNumber(uint8_t index) const;
|
||||
|
||||
/**
|
||||
* @brief This function returns the Gen1PokemonIconType for a pokemon at the given index
|
||||
*/
|
||||
Gen1PokemonIconType getPokemonIconType(uint8_t index) const;
|
||||
|
||||
/**
|
||||
* @brief With this function, you can check if the index is valid and not referring to missingno
|
||||
*/
|
||||
bool isValidIndex(uint8_t index) const;
|
||||
|
||||
/**
|
||||
* @brief This function reads the pokemon stats at the given index
|
||||
*
|
||||
* @return whether or not this operation was successful
|
||||
*/
|
||||
bool readPokemonStatsForIndex(uint8_t index, Gen1PokeStats& stats) const;
|
||||
|
||||
/**
|
||||
* @brief Get the index of the color palette based on the pokedex number of a certain pokemon
|
||||
*/
|
||||
uint8_t getColorPaletteIndexByPokemonNumber(uint8_t pokeNumber);
|
||||
|
||||
/**
|
||||
* @brief This function reads the color palette with the given ID into outColorPalette
|
||||
* outColorPalette should be a pointer to an uint16_t array with 4 elements
|
||||
*
|
||||
* Based on: https://bulbapedia.bulbagarden.net/wiki/List_of_color_palettes_by_index_number_(Generation_I)
|
||||
*
|
||||
* @param outColorPalette
|
||||
*/
|
||||
void readColorPalette(uint8_t paletteId, uint16_t* outColorPalette);
|
||||
|
||||
/**
|
||||
* @brief Get the trainer name from the save file
|
||||
* Note: the resulting const char* does not need to be free'd.
|
||||
* However, it needs to be either used rightaway or strdup()'d, because the data will get overwritten on the next call to this function.
|
||||
*/
|
||||
const char* getTrainerName() const;
|
||||
|
||||
/**
|
||||
* @brief Get the rival name from the save file
|
||||
* Note: the resulting const char* does not need to be free'd.
|
||||
* However, it needs to be either used rightaway or strdup()'d, because the data will get overwritten on the next call to this function.
|
||||
*/
|
||||
const char* getRivalName() const;
|
||||
|
||||
/**
|
||||
* @brief Get the player ID from the save file
|
||||
*/
|
||||
uint16_t getTrainerID() const;
|
||||
|
||||
/**
|
||||
* Retrieves the current map the player is in.
|
||||
*/
|
||||
Gen1Maps getCurrentMap() const;
|
||||
|
||||
/**
|
||||
* @brief Returns a Gen1Party instance, which can be used to retrieve the information about the pokemon currently in the trainers' party
|
||||
*/
|
||||
Gen1Party getParty();
|
||||
|
||||
/**
|
||||
* @brief Returns a Gen1Box instance, which can be used to retrieve information about the pokemon currently in the Trainers' PC box at the specified index
|
||||
*/
|
||||
Gen1Box getBox(uint8_t boxIndex);
|
||||
|
||||
/**
|
||||
* @brief Returns the 0-based index of the currently selected PC box for pokemon
|
||||
*/
|
||||
uint8_t getCurrentBoxIndex();
|
||||
|
||||
/**
|
||||
* @brief This function returns whether the pokemon with the given pokedexNumber has been SEEN/OWNED.
|
||||
*/
|
||||
bool getPokedexFlag(PokedexFlag dexFlag, uint8_t pokedexNumber) const;
|
||||
|
||||
/**
|
||||
* @brief This function sets the pokedex flag for the given pokedexNumber
|
||||
*/
|
||||
void setPokedexFlag(PokedexFlag dexFlag, uint8_t pokedexNumber) const;
|
||||
|
||||
/**
|
||||
* @brief This function returns the counter value of the given dex flag
|
||||
*/
|
||||
uint8_t getPokedexCounter(PokedexFlag dexFlag) const;
|
||||
|
||||
/**
|
||||
* @brief This function decodes a sprite at the given bank and pointer.
|
||||
* Returns a pointer to a buffer containing the decoded gameboy sprite in gameboy sprite format.
|
||||
* The size of the returned buffer is SPRITE_BITPLANE_BUFFER_SIZE_IN_BYTES * 2
|
||||
*
|
||||
* WARNING: this function returns a pointer to an internal buffer of the Gen1SpriteDecoder. It will get overwritten on the next call to this function.
|
||||
* If you want to keep the content around for longer, make a copy of this data.
|
||||
*/
|
||||
uint8_t* decodeSprite(uint8_t bankIndex, uint16_t pointer);
|
||||
|
||||
/**
|
||||
* @brief This function decodes the given pokemon icon and returns an internal buffer
|
||||
* Note that this returns a 16x16 buffer in gameboy format with tiles in vertical order.
|
||||
* You need to feed it to an instance of SpriteRenderer to convert it to a useful format
|
||||
*
|
||||
* WARNING: this function returns a buffer to an internal buffer of Gen1IconDecoder. That means it will get overwritten on the next call to this function.
|
||||
* If you want to keep the content around for longer, make a copy of this data
|
||||
*/
|
||||
uint8_t* decodePokemonIcon(Gen1PokemonIconType iconType, 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
|
||||
*
|
||||
* @param originalTrainerID optional parameter. If not specified (=null), the original trainer id string will be set to the players'
|
||||
* @param nickname optional parameter. If not specified (= null), the pokemon species name will be used instead.
|
||||
*
|
||||
* @return
|
||||
* 0xFF - Could not add pokemon (probably no space left)
|
||||
* 0xFE - Added to players' party
|
||||
* 0x0 - 0xB - Added to box at index <value>
|
||||
*/
|
||||
uint8_t addPokemon(Gen1TrainerPokemon& poke, const char* originalTrainerID = 0, const char* nickname = 0);
|
||||
|
||||
/**
|
||||
* @brief Adds a distribution 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
|
||||
*
|
||||
* @param nickname optional parameter. If not specified (= null), the pokemon species name will be used instead.
|
||||
*
|
||||
* @return
|
||||
* 0xFF - Could not add pokemon (probably no space left)
|
||||
* 0xFE - Added to players' party
|
||||
* 0x0 - 0xB - Added to box at index <value>
|
||||
*/
|
||||
uint8_t addDistributionPokemon(const Gen1DistributionPokemon& distributionPoke, const char* nickname = 0);
|
||||
|
||||
/**
|
||||
* @brief This function checks whether the main checksum of bank 1 is valid
|
||||
*/
|
||||
bool isMainChecksumValid();
|
||||
|
||||
/**
|
||||
* @brief Updates the main data checksum in bank 1
|
||||
*/
|
||||
void updateMainChecksum();
|
||||
/**
|
||||
* @brief Checks whether the whole bank checksum of the given memory bank is valid.
|
||||
* As you may or may not know, bank 2 and bank 3 contain the PC Pokemon boxes of the player
|
||||
* These memory banks have 2 types of checksums: a whole memory bank checksum (which is this one)
|
||||
* And a checksum per box. (which will be dealt with in the Gen1Box class)
|
||||
*
|
||||
* So yeah, this function is about the whole memory bank checksums in memory bank 2 and 3
|
||||
*/
|
||||
bool isWholeBoxBankValid(uint8_t bankIndex);
|
||||
|
||||
/**
|
||||
* @brief This function updates the checksum value of the whole box bank (bank 2 or 3)
|
||||
*/
|
||||
void updateWholeBoxBankChecksum(uint8_t bankIndex);
|
||||
protected:
|
||||
private:
|
||||
IRomReader& romReader_;
|
||||
ISaveManager& saveManager_;
|
||||
Gen1SpriteDecoder spriteDecoder_;
|
||||
Gen1IconDecoder iconDecoder_;
|
||||
Gen1GameType gameType_;
|
||||
Gen1LocalizationLanguage localization_;
|
||||
};
|
||||
|
||||
#ifndef GEN1GAMEREADER_H
|
||||
#define GEN1GAMEREADER_H
|
||||
|
||||
#include "gen1/Gen1SpriteDecoder.h"
|
||||
#include "gen1/Gen1IconDecoder.h"
|
||||
#include "gen1/Gen1PlayerPokemonStorage.h"
|
||||
#include "gen1/Gen1DistributionPokemon.h"
|
||||
#include "gen1/Gen1Localization.h"
|
||||
#include "gen1/Gen1Maps.h"
|
||||
|
||||
class IRomReader;
|
||||
class ISaveManager;
|
||||
|
||||
class Gen1GameReader
|
||||
{
|
||||
public:
|
||||
Gen1GameReader(IRomReader& romReader, ISaveManager& saveManager, Gen1GameType gameType, Gen1LocalizationLanguage language = Gen1LocalizationLanguage::MAX);
|
||||
|
||||
/**
|
||||
* @brief Retrieves the current game cartridges'/roms' language
|
||||
*/
|
||||
Gen1LocalizationLanguage getGameLanguage() const;
|
||||
|
||||
/**
|
||||
* @brief get the name of a pokémon based on an index number
|
||||
* Note: you don't own the returned pointer. The data will get overwritten on the next call to this function,
|
||||
* so make sure to strdup() it if you need to store it for later
|
||||
*
|
||||
* @return const char*
|
||||
*/
|
||||
const char* getPokemonName(uint8_t index) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the pokedex number of a pokemon at the given internal index
|
||||
*/
|
||||
uint8_t getPokemonNumber(uint8_t index) const;
|
||||
|
||||
/**
|
||||
* @brief This function returns the Gen1PokemonIconType for a pokemon at the given index
|
||||
*/
|
||||
Gen1PokemonIconType getPokemonIconType(uint8_t index) const;
|
||||
|
||||
/**
|
||||
* @brief With this function, you can check if the index is valid and not referring to missingno
|
||||
*/
|
||||
bool isValidIndex(uint8_t index) const;
|
||||
|
||||
/**
|
||||
* @brief This function reads the pokemon stats at the given index
|
||||
*
|
||||
* @return whether or not this operation was successful
|
||||
*/
|
||||
bool readPokemonStatsForIndex(uint8_t index, Gen1PokeStats& stats) const;
|
||||
|
||||
/**
|
||||
* @brief Get the index of the color palette based on the pokedex number of a certain pokemon
|
||||
*/
|
||||
uint8_t getColorPaletteIndexByPokemonNumber(uint8_t pokeNumber);
|
||||
|
||||
/**
|
||||
* @brief This function reads the color palette with the given ID into outColorPalette
|
||||
* outColorPalette should be a pointer to an uint16_t array with 4 elements
|
||||
*
|
||||
* Based on: https://bulbapedia.bulbagarden.net/wiki/List_of_color_palettes_by_index_number_(Generation_I)
|
||||
*
|
||||
* @param outColorPalette
|
||||
*/
|
||||
void readColorPalette(uint8_t paletteId, uint16_t* outColorPalette);
|
||||
|
||||
/**
|
||||
* @brief Get the trainer name from the save file
|
||||
* Note: the resulting const char* does not need to be free'd.
|
||||
* However, it needs to be either used rightaway or strdup()'d, because the data will get overwritten on the next call to this function.
|
||||
*/
|
||||
const char* getTrainerName() const;
|
||||
|
||||
/**
|
||||
* @brief Get the rival name from the save file
|
||||
* Note: the resulting const char* does not need to be free'd.
|
||||
* However, it needs to be either used rightaway or strdup()'d, because the data will get overwritten on the next call to this function.
|
||||
*/
|
||||
const char* getRivalName() const;
|
||||
|
||||
/**
|
||||
* @brief Get the player ID from the save file
|
||||
*/
|
||||
uint16_t getTrainerID() const;
|
||||
|
||||
/**
|
||||
* @brief This function retrieves the amount of pokédollars the trainer currently has
|
||||
*/
|
||||
uint32_t getTrainerMoney() const;
|
||||
|
||||
/**
|
||||
* @brief Sets the amount of pokédollars the trainer currently has
|
||||
* NOTE: the value is capped to 16777215 as this is the maximum value that can be represented by 3 bytes
|
||||
*/
|
||||
void setTrainerMoney(uint32_t amount);
|
||||
|
||||
/**
|
||||
* Retrieves the current map the player is in.
|
||||
*/
|
||||
Gen1Maps getCurrentMap() const;
|
||||
|
||||
/**
|
||||
* @brief Returns a Gen1Party instance, which can be used to retrieve the information about the pokemon currently in the trainers' party
|
||||
*/
|
||||
Gen1Party getParty();
|
||||
|
||||
/**
|
||||
* @brief Returns a Gen1Box instance, which can be used to retrieve information about the pokemon currently in the Trainers' PC box at the specified index
|
||||
*/
|
||||
Gen1Box getBox(uint8_t boxIndex);
|
||||
|
||||
/**
|
||||
* @brief Returns the 0-based index of the currently selected PC box for pokemon
|
||||
*/
|
||||
uint8_t getCurrentBoxIndex();
|
||||
|
||||
/**
|
||||
* @brief This function returns whether the pokemon with the given pokedexNumber has been SEEN/OWNED.
|
||||
*/
|
||||
bool getPokedexFlag(PokedexFlag dexFlag, uint8_t pokedexNumber) const;
|
||||
|
||||
/**
|
||||
* @brief This function sets the pokedex flag for the given pokedexNumber
|
||||
*/
|
||||
void setPokedexFlag(PokedexFlag dexFlag, uint8_t pokedexNumber) const;
|
||||
|
||||
/**
|
||||
* @brief This function returns the counter value of the given dex flag
|
||||
*/
|
||||
uint8_t getPokedexCounter(PokedexFlag dexFlag) const;
|
||||
|
||||
/**
|
||||
* @brief This function decodes a sprite at the given bank and pointer.
|
||||
* Returns a pointer to a buffer containing the decoded gameboy sprite in gameboy sprite format.
|
||||
* The size of the returned buffer is SPRITE_BITPLANE_BUFFER_SIZE_IN_BYTES * 2
|
||||
*
|
||||
* WARNING: this function returns a pointer to an internal buffer of the Gen1SpriteDecoder. It will get overwritten on the next call to this function.
|
||||
* If you want to keep the content around for longer, make a copy of this data.
|
||||
*/
|
||||
uint8_t* decodeSprite(uint8_t bankIndex, uint16_t pointer);
|
||||
|
||||
/**
|
||||
* @brief This function decodes the given pokemon icon and returns an internal buffer
|
||||
* Note that this returns a 16x16 buffer in gameboy format with tiles in vertical order.
|
||||
* You need to feed it to an instance of SpriteRenderer to convert it to a useful format
|
||||
*
|
||||
* WARNING: this function returns a buffer to an internal buffer of Gen1IconDecoder. That means it will get overwritten on the next call to this function.
|
||||
* If you want to keep the content around for longer, make a copy of this data
|
||||
*/
|
||||
uint8_t* decodePokemonIcon(Gen1PokemonIconType iconType, 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
|
||||
*
|
||||
* @param originalTrainerID optional parameter. If not specified (=null), the original trainer id string will be set to the players'
|
||||
* @param nickname optional parameter. If not specified (= null), the pokemon species name will be used instead.
|
||||
*
|
||||
* @return
|
||||
* 0xFF - Could not add pokemon (probably no space left)
|
||||
* 0xFE - Added to players' party
|
||||
* 0x0 - 0xB - Added to box at index <value>
|
||||
*/
|
||||
uint8_t addPokemon(Gen1TrainerPokemon& poke, const char* originalTrainerID = 0, const char* nickname = 0);
|
||||
|
||||
/**
|
||||
* @brief Adds a distribution 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
|
||||
*
|
||||
* @param nickname optional parameter. If not specified (= null), the pokemon species name will be used instead.
|
||||
*
|
||||
* @return
|
||||
* 0xFF - Could not add pokemon (probably no space left)
|
||||
* 0xFE - Added to players' party
|
||||
* 0x0 - 0xB - Added to box at index <value>
|
||||
*/
|
||||
uint8_t addDistributionPokemon(const Gen1DistributionPokemon& distributionPoke, const char* nickname = 0);
|
||||
|
||||
/**
|
||||
* @brief This function checks whether the main checksum of bank 1 is valid
|
||||
*/
|
||||
bool isMainChecksumValid();
|
||||
|
||||
/**
|
||||
* @brief Updates the main data checksum in bank 1
|
||||
*/
|
||||
void updateMainChecksum();
|
||||
/**
|
||||
* @brief Checks whether the whole bank checksum of the given memory bank is valid.
|
||||
* As you may or may not know, bank 2 and bank 3 contain the PC Pokemon boxes of the player
|
||||
* These memory banks have 2 types of checksums: a whole memory bank checksum (which is this one)
|
||||
* And a checksum per box. (which will be dealt with in the Gen1Box class)
|
||||
*
|
||||
* So yeah, this function is about the whole memory bank checksums in memory bank 2 and 3
|
||||
*/
|
||||
bool isWholeBoxBankValid(uint8_t bankIndex);
|
||||
|
||||
/**
|
||||
* @brief This function updates the checksum value of the whole box bank (bank 2 or 3)
|
||||
*/
|
||||
void updateWholeBoxBankChecksum(uint8_t bankIndex);
|
||||
protected:
|
||||
private:
|
||||
IRomReader& romReader_;
|
||||
ISaveManager& saveManager_;
|
||||
Gen1SpriteDecoder spriteDecoder_;
|
||||
Gen1IconDecoder iconDecoder_;
|
||||
Gen1GameType gameType_;
|
||||
Gen1LocalizationLanguage localization_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,90 +1,91 @@
|
|||
#ifndef _GEN1LOCALIZATION_H
|
||||
#define _GEN1LOCALIZATION_H
|
||||
|
||||
#include "gen1/Gen1Common.h"
|
||||
|
||||
/**
|
||||
* @brief This enum defines the supported localization languages for gen 1.
|
||||
* MAX is invalid. It is defined to be used in a for loop if needed.
|
||||
* It can also be used as an invalid value to force Gen1GameReader to identify
|
||||
* the localization language
|
||||
*/
|
||||
enum class Gen1LocalizationLanguage
|
||||
{
|
||||
ENGLISH,
|
||||
FRENCH,
|
||||
SPANISH,
|
||||
GERMAN,
|
||||
ITALIAN,
|
||||
JAPANESE,
|
||||
MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Different pokémon localizations unfortunately also store data at different locations in the rom.
|
||||
* This is because stuff shifts around because of the different text.
|
||||
*
|
||||
* So to deal with different localizations of the same game, we need to keep track of the various rom offsets we need
|
||||
* for each of them.
|
||||
*
|
||||
*/
|
||||
typedef struct Gen1LocalizationRomOffsets
|
||||
{
|
||||
/**
|
||||
* @brief The rom offset at which the species structs can be found containing the base stats
|
||||
* of the various pokémon. https://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_species_data_structure_(Generation_I)
|
||||
*/
|
||||
uint32_t stats;
|
||||
/**
|
||||
* @brief For some reason, in the Pokémon Blue and Red versions, the mew species(stats) struct is stored separately.
|
||||
* This does not apply to Pokémon Yellow
|
||||
*/
|
||||
uint32_t statsMew;
|
||||
/**
|
||||
* @brief This is the rom offset at which the pokedex numbers of pokémon are stored in pokemon index order
|
||||
*/
|
||||
uint32_t numbers;
|
||||
/**
|
||||
* @brief This is the rom offset at which we can find the encoded pokémon names.
|
||||
* These can be decoded with gen1_decodePokeText()
|
||||
*/
|
||||
uint32_t names;
|
||||
|
||||
/**
|
||||
* @brief This is the rom offset at which we can find the party menu icon type for each pokémon in pokedex number order.
|
||||
*/
|
||||
uint32_t iconTypes;
|
||||
/**
|
||||
* @brief This is the rom offset at which we can find the MonPartySpritePointers pointer table
|
||||
* This defines where the icon sprites are stored in the rom (and the number of tiles)
|
||||
*
|
||||
* see https://github.com/pret/pokered/blob/master/data/icon_pointers.asm
|
||||
*/
|
||||
uint32_t icons;
|
||||
|
||||
/**
|
||||
* @brief This is the rom offset at which a palette index is stored for each pokémon in pokedex number order.
|
||||
*/
|
||||
uint32_t paletteIndices;
|
||||
|
||||
/**
|
||||
* @brief This is the rom offset at which each pokémon sprite color palette is stored in palette index order
|
||||
*/
|
||||
uint32_t palettes;
|
||||
} Gen1LocalizationRomOffsets;
|
||||
|
||||
typedef struct Gen1LocalizationSRAMOffsets
|
||||
{
|
||||
uint32_t trainerID;
|
||||
uint32_t currentMap;
|
||||
uint32_t dexSeen;
|
||||
uint32_t dexOwned;
|
||||
uint32_t rivalName;
|
||||
uint32_t party;
|
||||
uint32_t currentBoxIndex;
|
||||
uint32_t checksum;
|
||||
} Gen1LocalizationSRAMOffsets;
|
||||
|
||||
const Gen1LocalizationRomOffsets& gen1_getRomOffsets(Gen1GameType gameType, Gen1LocalizationLanguage language);
|
||||
const Gen1LocalizationSRAMOffsets& gen1_getSRAMOffsets(Gen1LocalizationLanguage language);
|
||||
#ifndef _GEN1LOCALIZATION_H
|
||||
#define _GEN1LOCALIZATION_H
|
||||
|
||||
#include "gen1/Gen1Common.h"
|
||||
|
||||
/**
|
||||
* @brief This enum defines the supported localization languages for gen 1.
|
||||
* MAX is invalid. It is defined to be used in a for loop if needed.
|
||||
* It can also be used as an invalid value to force Gen1GameReader to identify
|
||||
* the localization language
|
||||
*/
|
||||
enum class Gen1LocalizationLanguage
|
||||
{
|
||||
ENGLISH,
|
||||
FRENCH,
|
||||
SPANISH,
|
||||
GERMAN,
|
||||
ITALIAN,
|
||||
JAPANESE,
|
||||
MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Different pokémon localizations unfortunately also store data at different locations in the rom.
|
||||
* This is because stuff shifts around because of the different text.
|
||||
*
|
||||
* So to deal with different localizations of the same game, we need to keep track of the various rom offsets we need
|
||||
* for each of them.
|
||||
*
|
||||
*/
|
||||
typedef struct Gen1LocalizationRomOffsets
|
||||
{
|
||||
/**
|
||||
* @brief The rom offset at which the species structs can be found containing the base stats
|
||||
* of the various pokémon. https://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_species_data_structure_(Generation_I)
|
||||
*/
|
||||
uint32_t stats;
|
||||
/**
|
||||
* @brief For some reason, in the Pokémon Blue and Red versions, the mew species(stats) struct is stored separately.
|
||||
* This does not apply to Pokémon Yellow
|
||||
*/
|
||||
uint32_t statsMew;
|
||||
/**
|
||||
* @brief This is the rom offset at which the pokedex numbers of pokémon are stored in pokemon index order
|
||||
*/
|
||||
uint32_t numbers;
|
||||
/**
|
||||
* @brief This is the rom offset at which we can find the encoded pokémon names.
|
||||
* These can be decoded with gen1_decodePokeText()
|
||||
*/
|
||||
uint32_t names;
|
||||
|
||||
/**
|
||||
* @brief This is the rom offset at which we can find the party menu icon type for each pokémon in pokedex number order.
|
||||
*/
|
||||
uint32_t iconTypes;
|
||||
/**
|
||||
* @brief This is the rom offset at which we can find the MonPartySpritePointers pointer table
|
||||
* This defines where the icon sprites are stored in the rom (and the number of tiles)
|
||||
*
|
||||
* see https://github.com/pret/pokered/blob/master/data/icon_pointers.asm
|
||||
*/
|
||||
uint32_t icons;
|
||||
|
||||
/**
|
||||
* @brief This is the rom offset at which a palette index is stored for each pokémon in pokedex number order.
|
||||
*/
|
||||
uint32_t paletteIndices;
|
||||
|
||||
/**
|
||||
* @brief This is the rom offset at which each pokémon sprite color palette is stored in palette index order
|
||||
*/
|
||||
uint32_t palettes;
|
||||
} Gen1LocalizationRomOffsets;
|
||||
|
||||
typedef struct Gen1LocalizationSRAMOffsets
|
||||
{
|
||||
uint32_t trainerID;
|
||||
uint32_t trainerMoney;
|
||||
uint32_t currentMap;
|
||||
uint32_t dexSeen;
|
||||
uint32_t dexOwned;
|
||||
uint32_t rivalName;
|
||||
uint32_t party;
|
||||
uint32_t currentBoxIndex;
|
||||
uint32_t checksum;
|
||||
} Gen1LocalizationSRAMOffsets;
|
||||
|
||||
const Gen1LocalizationRomOffsets& gen1_getRomOffsets(Gen1GameType gameType, Gen1LocalizationLanguage language);
|
||||
const Gen1LocalizationSRAMOffsets& gen1_getSRAMOffsets(Gen1LocalizationLanguage language);
|
||||
#endif
|
||||
|
|
@ -131,6 +131,18 @@ public:
|
|||
*/
|
||||
const char *getTrainerName() const;
|
||||
|
||||
/**
|
||||
* @brief This function retrieves the amount of pokédollars the trainer currently has
|
||||
*/
|
||||
uint32_t getTrainerMoney() const;
|
||||
|
||||
/**
|
||||
* @brief Sets the amount of pokédollars the trainer currently has
|
||||
* NOTE: the value is capped to 16777215 as this is the maximum value that can be represented by 3 bytes
|
||||
*/
|
||||
void setTrainerMoney(uint32_t amount);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the rival name from the save file
|
||||
* Note: the resulting const char* does not need to be free'd.
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ typedef struct Gen2LocalizationSRAMOffsets
|
|||
uint32_t currentBox;
|
||||
uint32_t dexSeen;
|
||||
uint32_t dexOwned;
|
||||
uint32_t trainerMoney;
|
||||
uint32_t party;
|
||||
uint32_t eventFlags;
|
||||
uint32_t mainChecksum;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,197 +1,199 @@
|
|||
#include "gen1/Gen1Localization.h"
|
||||
|
||||
static const Gen1LocalizationRomOffsets g1_localizationROMOffsetsRGB[] = {
|
||||
// English
|
||||
{
|
||||
.stats = 0x383DE,
|
||||
.statsMew = 0x425B,
|
||||
.numbers = 0x41024,
|
||||
.names = 0x1c21e,
|
||||
.iconTypes = 0x7190D,
|
||||
.icons = 0x717C0,
|
||||
.paletteIndices = 0x725C9,
|
||||
.palettes = 0x72660
|
||||
},
|
||||
// French
|
||||
{
|
||||
.stats = 0x383DE,
|
||||
.statsMew = 0x425B,
|
||||
.numbers = 0x40FAA,
|
||||
.names = 0x1C21E,
|
||||
.iconTypes = 0x718DE,
|
||||
.icons = 0x71791,
|
||||
.paletteIndices = 0x7259A,
|
||||
.palettes = 0x72631
|
||||
},
|
||||
// Spanish
|
||||
{
|
||||
.stats = 0x383DE,
|
||||
.statsMew = 0x425B,
|
||||
.numbers = 0x40FB4,
|
||||
.names = 0x1C21E,
|
||||
.iconTypes = 0x718FD,
|
||||
.icons = 0x717B0,
|
||||
.paletteIndices = 0x725B9,
|
||||
.palettes = 0x72650
|
||||
},
|
||||
// German
|
||||
{
|
||||
.stats = 0x383DE,
|
||||
.statsMew = 0x425B,
|
||||
.numbers = 0x40F96,
|
||||
.names = 0x1C21E,
|
||||
.iconTypes = 0x718E7,
|
||||
.icons = 0x7179A,
|
||||
.paletteIndices = 0x725A3,
|
||||
.palettes = 0x7263A
|
||||
},
|
||||
// Italian
|
||||
{
|
||||
.stats = 0x383DE,
|
||||
.statsMew = 0x425B,
|
||||
.numbers = 0x40FB6,
|
||||
.names = 0x1C21E,
|
||||
.iconTypes = 0x7194D,
|
||||
.icons = 0x71800,
|
||||
.paletteIndices = 0x72609,
|
||||
.palettes = 0x726A0
|
||||
},
|
||||
// Japanese
|
||||
{
|
||||
.stats = 0x38000,
|
||||
.statsMew = 0x4200,
|
||||
.numbers = 0x4279A,
|
||||
.names = 0x39068,
|
||||
.iconTypes = 0x71DD1,
|
||||
.icons = 0x71C84,
|
||||
.paletteIndices = 0x72A1F,
|
||||
.palettes = 0x72AB6
|
||||
}
|
||||
};
|
||||
|
||||
static const Gen1LocalizationRomOffsets g1_localizationROMOffsetsBlueJpn = {
|
||||
.stats = 0x383DE,
|
||||
.statsMew = 0x425B,
|
||||
.numbers = 0x42784,
|
||||
.names = 0x39446,
|
||||
.iconTypes = 0x71DC1,
|
||||
.icons = 0x71C74,
|
||||
.paletteIndices = 0x72A0E,
|
||||
.palettes = 0x72AA5
|
||||
};
|
||||
|
||||
static const Gen1LocalizationRomOffsets g1_localizationROMOffsetsY[] = {
|
||||
// English
|
||||
{
|
||||
.stats = 0x383DE,
|
||||
.statsMew = 0x0, // IRRELEVANT because mew is included in the stats list for Yellow
|
||||
.numbers = 0x410B1,
|
||||
.names = 0xE8000,
|
||||
.iconTypes = 0x719BA,
|
||||
.icons = 0x7184D,
|
||||
.paletteIndices = 0x72922,
|
||||
.palettes = 0x72AF9
|
||||
},
|
||||
// French
|
||||
{
|
||||
.stats = 0x383DE,
|
||||
.statsMew = 0x0, // IRRELEVANT because mew is included in the stats list for Yellow
|
||||
.numbers = 0x41036,
|
||||
.names = 0xE8000,
|
||||
.iconTypes = 0x7198B,
|
||||
.icons = 0x7181E,
|
||||
.paletteIndices = 0x728F3,
|
||||
.palettes = 0x72ACA
|
||||
},
|
||||
// Spanish
|
||||
{
|
||||
.stats = 0x383DE,
|
||||
.statsMew = 0x0, // IRRELEVANT because mew is included in the stats list for Yellow
|
||||
.numbers = 0x41041,
|
||||
.names = 0xE8000,
|
||||
.iconTypes = 0x719AA,
|
||||
.icons = 0x7183D,
|
||||
.paletteIndices = 0x72912,
|
||||
.palettes = 0x72AE9
|
||||
},
|
||||
// German
|
||||
{
|
||||
.stats = 0x383DE,
|
||||
.statsMew = 0x0, // IRRELEVANT because mew is included in the stats list for Yellow
|
||||
.numbers = 0x41023,
|
||||
.names = 0xE8000,
|
||||
.iconTypes = 0x71999,
|
||||
.icons = 0x7182c,
|
||||
.paletteIndices = 0x72901,
|
||||
.palettes = 0x72AD8
|
||||
},
|
||||
// Italian
|
||||
{
|
||||
.stats = 0x383DE,
|
||||
.statsMew = 0x0, // IRRELEVANT because mew is included in the stats list for Yellow
|
||||
.numbers = 0x41043,
|
||||
.names = 0xE8000,
|
||||
.iconTypes = 0x719FA,
|
||||
.icons = 0x7188D,
|
||||
.paletteIndices = 0x72962,
|
||||
.palettes = 0x72B39
|
||||
},
|
||||
// Japanese
|
||||
{
|
||||
.stats = 0x383DE,
|
||||
.statsMew = 0x0, // IRRELEVANT because mew is included in the stats list for Yellow
|
||||
.numbers = 0x4282D,
|
||||
.names = 0x39462,
|
||||
.iconTypes = 0x71911,
|
||||
.icons = 0x717A4,
|
||||
.paletteIndices = 0x72650,
|
||||
.palettes = 0x726E7
|
||||
}
|
||||
};
|
||||
|
||||
static const Gen1LocalizationSRAMOffsets g1_sRAMOffsetsInternational = {
|
||||
.trainerID = 0x2605,
|
||||
.currentMap = 0x260A,
|
||||
.dexSeen = 0x25B6,
|
||||
.dexOwned = 0x25A3,
|
||||
.rivalName = 0x25F6,
|
||||
.party = 0x2F2C,
|
||||
.currentBoxIndex = 0x284C,
|
||||
.checksum = 0x3523
|
||||
};
|
||||
|
||||
static const Gen1LocalizationSRAMOffsets g1_sRAMOffsetsJapan = {
|
||||
.trainerID = 0x25FB,
|
||||
.currentMap = 0x2600,
|
||||
.dexSeen = 0x25B1,
|
||||
.dexOwned = 0x259E,
|
||||
.rivalName = 0x25F1,
|
||||
.party = 0x2ED5,
|
||||
.currentBoxIndex = 0x2842,
|
||||
.checksum = 0x3594
|
||||
};
|
||||
|
||||
const Gen1LocalizationRomOffsets& gen1_getRomOffsets(Gen1GameType gameType, Gen1LocalizationLanguage language)
|
||||
{
|
||||
if(language == Gen1LocalizationLanguage::JAPANESE && gameType == Gen1GameType::BLUE)
|
||||
{
|
||||
return g1_localizationROMOffsetsBlueJpn;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(gameType)
|
||||
{
|
||||
case Gen1GameType::RED:
|
||||
case Gen1GameType::BLUE:
|
||||
case Gen1GameType::GREEN:
|
||||
return g1_localizationROMOffsetsRGB[(uint8_t)language];
|
||||
default:
|
||||
return g1_localizationROMOffsetsY[(uint8_t)language];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Gen1LocalizationSRAMOffsets& gen1_getSRAMOffsets(Gen1LocalizationLanguage language)
|
||||
{
|
||||
return (language != Gen1LocalizationLanguage::JAPANESE) ? g1_sRAMOffsetsInternational : g1_sRAMOffsetsJapan;
|
||||
#include "gen1/Gen1Localization.h"
|
||||
|
||||
static const Gen1LocalizationRomOffsets g1_localizationROMOffsetsRGB[] = {
|
||||
// English
|
||||
{
|
||||
.stats = 0x383DE,
|
||||
.statsMew = 0x425B,
|
||||
.numbers = 0x41024,
|
||||
.names = 0x1c21e,
|
||||
.iconTypes = 0x7190D,
|
||||
.icons = 0x717C0,
|
||||
.paletteIndices = 0x725C9,
|
||||
.palettes = 0x72660
|
||||
},
|
||||
// French
|
||||
{
|
||||
.stats = 0x383DE,
|
||||
.statsMew = 0x425B,
|
||||
.numbers = 0x40FAA,
|
||||
.names = 0x1C21E,
|
||||
.iconTypes = 0x718DE,
|
||||
.icons = 0x71791,
|
||||
.paletteIndices = 0x7259A,
|
||||
.palettes = 0x72631
|
||||
},
|
||||
// Spanish
|
||||
{
|
||||
.stats = 0x383DE,
|
||||
.statsMew = 0x425B,
|
||||
.numbers = 0x40FB4,
|
||||
.names = 0x1C21E,
|
||||
.iconTypes = 0x718FD,
|
||||
.icons = 0x717B0,
|
||||
.paletteIndices = 0x725B9,
|
||||
.palettes = 0x72650
|
||||
},
|
||||
// German
|
||||
{
|
||||
.stats = 0x383DE,
|
||||
.statsMew = 0x425B,
|
||||
.numbers = 0x40F96,
|
||||
.names = 0x1C21E,
|
||||
.iconTypes = 0x718E7,
|
||||
.icons = 0x7179A,
|
||||
.paletteIndices = 0x725A3,
|
||||
.palettes = 0x7263A
|
||||
},
|
||||
// Italian
|
||||
{
|
||||
.stats = 0x383DE,
|
||||
.statsMew = 0x425B,
|
||||
.numbers = 0x40FB6,
|
||||
.names = 0x1C21E,
|
||||
.iconTypes = 0x7194D,
|
||||
.icons = 0x71800,
|
||||
.paletteIndices = 0x72609,
|
||||
.palettes = 0x726A0
|
||||
},
|
||||
// Japanese
|
||||
{
|
||||
.stats = 0x38000,
|
||||
.statsMew = 0x4200,
|
||||
.numbers = 0x4279A,
|
||||
.names = 0x39068,
|
||||
.iconTypes = 0x71DD1,
|
||||
.icons = 0x71C84,
|
||||
.paletteIndices = 0x72A1F,
|
||||
.palettes = 0x72AB6
|
||||
}
|
||||
};
|
||||
|
||||
static const Gen1LocalizationRomOffsets g1_localizationROMOffsetsBlueJpn = {
|
||||
.stats = 0x383DE,
|
||||
.statsMew = 0x425B,
|
||||
.numbers = 0x42784,
|
||||
.names = 0x39446,
|
||||
.iconTypes = 0x71DC1,
|
||||
.icons = 0x71C74,
|
||||
.paletteIndices = 0x72A0E,
|
||||
.palettes = 0x72AA5
|
||||
};
|
||||
|
||||
static const Gen1LocalizationRomOffsets g1_localizationROMOffsetsY[] = {
|
||||
// English
|
||||
{
|
||||
.stats = 0x383DE,
|
||||
.statsMew = 0x0, // IRRELEVANT because mew is included in the stats list for Yellow
|
||||
.numbers = 0x410B1,
|
||||
.names = 0xE8000,
|
||||
.iconTypes = 0x719BA,
|
||||
.icons = 0x7184D,
|
||||
.paletteIndices = 0x72922,
|
||||
.palettes = 0x72AF9
|
||||
},
|
||||
// French
|
||||
{
|
||||
.stats = 0x383DE,
|
||||
.statsMew = 0x0, // IRRELEVANT because mew is included in the stats list for Yellow
|
||||
.numbers = 0x41036,
|
||||
.names = 0xE8000,
|
||||
.iconTypes = 0x7198B,
|
||||
.icons = 0x7181E,
|
||||
.paletteIndices = 0x728F3,
|
||||
.palettes = 0x72ACA
|
||||
},
|
||||
// Spanish
|
||||
{
|
||||
.stats = 0x383DE,
|
||||
.statsMew = 0x0, // IRRELEVANT because mew is included in the stats list for Yellow
|
||||
.numbers = 0x41041,
|
||||
.names = 0xE8000,
|
||||
.iconTypes = 0x719AA,
|
||||
.icons = 0x7183D,
|
||||
.paletteIndices = 0x72912,
|
||||
.palettes = 0x72AE9
|
||||
},
|
||||
// German
|
||||
{
|
||||
.stats = 0x383DE,
|
||||
.statsMew = 0x0, // IRRELEVANT because mew is included in the stats list for Yellow
|
||||
.numbers = 0x41023,
|
||||
.names = 0xE8000,
|
||||
.iconTypes = 0x71999,
|
||||
.icons = 0x7182c,
|
||||
.paletteIndices = 0x72901,
|
||||
.palettes = 0x72AD8
|
||||
},
|
||||
// Italian
|
||||
{
|
||||
.stats = 0x383DE,
|
||||
.statsMew = 0x0, // IRRELEVANT because mew is included in the stats list for Yellow
|
||||
.numbers = 0x41043,
|
||||
.names = 0xE8000,
|
||||
.iconTypes = 0x719FA,
|
||||
.icons = 0x7188D,
|
||||
.paletteIndices = 0x72962,
|
||||
.palettes = 0x72B39
|
||||
},
|
||||
// Japanese
|
||||
{
|
||||
.stats = 0x383DE,
|
||||
.statsMew = 0x0, // IRRELEVANT because mew is included in the stats list for Yellow
|
||||
.numbers = 0x4282D,
|
||||
.names = 0x39462,
|
||||
.iconTypes = 0x71911,
|
||||
.icons = 0x717A4,
|
||||
.paletteIndices = 0x72650,
|
||||
.palettes = 0x726E7
|
||||
}
|
||||
};
|
||||
|
||||
static const Gen1LocalizationSRAMOffsets g1_sRAMOffsetsInternational = {
|
||||
.trainerID = 0x2605,
|
||||
.trainerMoney = 0x25F3,
|
||||
.currentMap = 0x260A,
|
||||
.dexSeen = 0x25B6,
|
||||
.dexOwned = 0x25A3,
|
||||
.rivalName = 0x25F6,
|
||||
.party = 0x2F2C,
|
||||
.currentBoxIndex = 0x284C,
|
||||
.checksum = 0x3523
|
||||
};
|
||||
|
||||
static const Gen1LocalizationSRAMOffsets g1_sRAMOffsetsJapan = {
|
||||
.trainerID = 0x25FB,
|
||||
.trainerMoney = 0x25EE,
|
||||
.currentMap = 0x2600,
|
||||
.dexSeen = 0x25B1,
|
||||
.dexOwned = 0x259E,
|
||||
.rivalName = 0x25F1,
|
||||
.party = 0x2ED5,
|
||||
.currentBoxIndex = 0x2842,
|
||||
.checksum = 0x3594
|
||||
};
|
||||
|
||||
const Gen1LocalizationRomOffsets& gen1_getRomOffsets(Gen1GameType gameType, Gen1LocalizationLanguage language)
|
||||
{
|
||||
if(language == Gen1LocalizationLanguage::JAPANESE && gameType == Gen1GameType::BLUE)
|
||||
{
|
||||
return g1_localizationROMOffsetsBlueJpn;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(gameType)
|
||||
{
|
||||
case Gen1GameType::RED:
|
||||
case Gen1GameType::BLUE:
|
||||
case Gen1GameType::GREEN:
|
||||
return g1_localizationROMOffsetsRGB[(uint8_t)language];
|
||||
default:
|
||||
return g1_localizationROMOffsetsY[(uint8_t)language];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Gen1LocalizationSRAMOffsets& gen1_getSRAMOffsets(Gen1LocalizationLanguage language)
|
||||
{
|
||||
return (language != Gen1LocalizationLanguage::JAPANESE) ? g1_sRAMOffsetsInternational : g1_sRAMOffsetsJapan;
|
||||
}
|
||||
|
|
@ -642,6 +642,24 @@ const char *Gen2GameReader::getTrainerName() const
|
|||
return result;
|
||||
}
|
||||
|
||||
uint32_t Gen2GameReader::getTrainerMoney() const
|
||||
{
|
||||
uint32_t result = 0;
|
||||
const uint32_t savOffset = gen2_getSRAMOffsets(gameType_, localization_).trainerMoney;
|
||||
|
||||
saveManager_.seek(savOffset);
|
||||
saveManager_.readUint24(result, Endianness::BIG);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Gen2GameReader::setTrainerMoney(uint32_t amount)
|
||||
{
|
||||
const uint32_t savOffset = gen2_getSRAMOffsets(gameType_, localization_).trainerMoney;
|
||||
|
||||
saveManager_.seek(savOffset);
|
||||
saveManager_.writeUint24(amount, Endianness::BIG);
|
||||
}
|
||||
|
||||
const char *Gen2GameReader::getRivalName() const
|
||||
{
|
||||
static char result[20];
|
||||
|
|
|
|||
|
|
@ -222,6 +222,7 @@ static const Gen2LocalizationSRAMOffsets g2_dummySRAMOffsets = {
|
|||
.currentBox = 0,
|
||||
.dexSeen = 0,
|
||||
.dexOwned = 0,
|
||||
.trainerMoney = 0,
|
||||
.party = 0,
|
||||
.eventFlags = 0,
|
||||
.mainChecksum = 0,
|
||||
|
|
@ -243,6 +244,7 @@ static const Gen2LocalizationSRAMOffsets g2_internationalSRAMOffsetsGS = {
|
|||
.currentBox = 0x2D6C,
|
||||
.dexSeen = 0x2A6C,
|
||||
.dexOwned = 0x2A4C,
|
||||
.trainerMoney = 0x23DB,
|
||||
.party = 0x288A,
|
||||
.eventFlags = 0x261F,
|
||||
.mainChecksum = 0x2D69,
|
||||
|
|
@ -264,6 +266,7 @@ static const Gen2LocalizationSRAMOffsets g2_internationalSRAMOffsetsC = {
|
|||
.currentBox = 0x2D10,
|
||||
.dexSeen = 0x2A47,
|
||||
.dexOwned = 0x2A27,
|
||||
.trainerMoney = 0x23DC,
|
||||
.party = 0x2865,
|
||||
.eventFlags = 0x2600,
|
||||
.mainChecksum = 0x2D0D,
|
||||
|
|
@ -297,6 +300,7 @@ static const Gen2LocalizationSRAMOffsets g2_localizationSRAMOffsetsGS[] = {
|
|||
.currentBox = 0x2DAE,
|
||||
.dexSeen = 0x2AAE,
|
||||
.dexOwned = 0x2A8E,
|
||||
.trainerMoney = 0x23D3,
|
||||
.party = 0x28CC,
|
||||
.eventFlags = 0x25F7,
|
||||
.mainChecksum = 0x2DAB,
|
||||
|
|
@ -318,6 +322,7 @@ static const Gen2LocalizationSRAMOffsets g2_localizationSRAMOffsetsGS[] = {
|
|||
.currentBox = 0x2D10,
|
||||
.dexSeen = 0x29EE,
|
||||
.dexOwned = 0x29CE,
|
||||
.trainerMoney = 0x23BC,
|
||||
.party = 0x283E,
|
||||
.eventFlags = 0x2600,
|
||||
.mainChecksum = 0x2D0D,
|
||||
|
|
@ -354,6 +359,7 @@ static const Gen2LocalizationSRAMOffsets g2_localizationSRAMOffsetsC[] = {
|
|||
.currentBox = 0x2D10,
|
||||
.dexSeen = 0x29CA,
|
||||
.dexOwned = 0x29AA,
|
||||
.trainerMoney = 0x23BE,
|
||||
.party = 0x281A,
|
||||
.eventFlags = 0x25E2,
|
||||
.mainChecksum = 0x2D0D,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user