mirror of
https://github.com/risingPhil/libpokemegb.git
synced 2026-04-26 10:16:36 -05:00
Add functionality to get and set event flags
This commit is contained in:
parent
80e8397b93
commit
4a3bc9de18
|
|
@ -11,6 +11,8 @@ all:
|
||||||
$(MAKE) -C gen2_gsball $(MAKECMDGOALS) $(MAKEOVERRIDES)
|
$(MAKE) -C gen2_gsball $(MAKECMDGOALS) $(MAKEOVERRIDES)
|
||||||
$(MAKE) -C gen2_addItem $(MAKECMDGOALS) $(MAKEOVERRIDES)
|
$(MAKE) -C gen2_addItem $(MAKECMDGOALS) $(MAKEOVERRIDES)
|
||||||
$(MAKE) -C gen2_removeItem $(MAKECMDGOALS) $(MAKEOVERRIDES)
|
$(MAKE) -C gen2_removeItem $(MAKECMDGOALS) $(MAKEOVERRIDES)
|
||||||
|
$(MAKE) -C gen2_getEventFlag $(MAKECMDGOALS) $(MAKEOVERRIDES)
|
||||||
|
$(MAKE) -C gen2_setEventFlag $(MAKECMDGOALS) $(MAKEOVERRIDES)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(MAKE) -C do_stuff_gen1 clean
|
$(MAKE) -C do_stuff_gen1 clean
|
||||||
|
|
@ -22,3 +24,5 @@ clean:
|
||||||
$(MAKE) -C gen2_gsball clean
|
$(MAKE) -C gen2_gsball clean
|
||||||
$(MAKE) -C gen2_addItem clean
|
$(MAKE) -C gen2_addItem clean
|
||||||
$(MAKE) -C gen2_removeItem clean
|
$(MAKE) -C gen2_removeItem clean
|
||||||
|
$(MAKE) -C gen2_getEventFlag clean
|
||||||
|
$(MAKE) -C gen2_setEventFlag clean
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
if(argc != 3)
|
if(argc != 3)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Usage: addDistributionPoke <path/to/rom.gbc> <path/to/file.sav>\n");
|
fprintf(stderr, "Usage: gen2_addItem <path/to/rom.gbc> <path/to/file.sav>\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
48
examples/gen2_getEventFlag/Makefile
Normal file
48
examples/gen2_getEventFlag/Makefile
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
# # 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 := .
|
||||||
|
# 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))
|
||||||
|
|
||||||
|
LIBS := -lpokemegb
|
||||||
|
ifeq ($(PNG_SUPPORT),1)
|
||||||
|
LIBS += -lpng
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Ensure necessary directories exist
|
||||||
|
# This function ensures the directory for the target exists
|
||||||
|
define make_directory
|
||||||
|
@mkdir -p $(dir $@)
|
||||||
|
endef
|
||||||
|
|
||||||
|
# Target executable
|
||||||
|
TARGET := ../../gen2_getEventFlag
|
||||||
|
|
||||||
|
# Phony targets
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
|
# Default target
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
$(TARGET): $(OBJS)
|
||||||
|
$(CXX) $(CXXFLAGS) $^ -o $@ $(LIBS) -L ../../
|
||||||
|
|
||||||
|
# Rule to compile source files
|
||||||
|
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp | $(BUILD_DIR)
|
||||||
|
$(make_directory)
|
||||||
|
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
# Create the build directory if it doesn't exist
|
||||||
|
$(BUILD_DIR):
|
||||||
|
mkdir -p $(BUILD_DIR)
|
||||||
|
|
||||||
|
# Clean rule
|
||||||
|
clean:
|
||||||
|
rm -rf $(BUILD_DIR) $(TARGET)
|
||||||
79
examples/gen2_getEventFlag/main.cpp
Normal file
79
examples/gen2_getEventFlag/main.cpp
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
#include "gen2/Gen2GameReader.h"
|
||||||
|
#include "gen1/Gen1Common.h"
|
||||||
|
#include "RomReader.h"
|
||||||
|
#include "SaveManager.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
static uint16_t getFlagNumber()
|
||||||
|
{
|
||||||
|
char input[100];
|
||||||
|
printf("Enter event flag number: ");
|
||||||
|
if (fgets(input, sizeof(input), stdin) == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error reading input\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Remove the newline character if it exists
|
||||||
|
input[strcspn(input, "\n")] = '\0';
|
||||||
|
|
||||||
|
return (uint16_t)strtoul(input, 0, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
if(argc != 3)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: gen2_getEventFlag <path/to/rom.gbc> <path/to/file.sav>\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* romBuffer;
|
||||||
|
uint8_t* saveBuffer;
|
||||||
|
uint32_t romFileSize;
|
||||||
|
uint32_t saveFileSize;
|
||||||
|
|
||||||
|
romBuffer = readFileIntoBuffer(argv[1], romFileSize);
|
||||||
|
if(!romBuffer)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "ERROR: Couldn't read file %s\n", argv[1]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
saveBuffer = readFileIntoBuffer(argv[2], saveFileSize);
|
||||||
|
if(!saveBuffer)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "ERROR: Couldn't read file %s\n", argv[2]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
GameboyCartridgeHeader cartridgeHeader;
|
||||||
|
BufferBasedRomReader romReader(romBuffer, romFileSize);
|
||||||
|
BufferBasedSaveManager saveManager(saveBuffer, saveFileSize);
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "ERROR: sorry, this tool only supports gen 2!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if(gen2Type == Gen2GameType::INVALID)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "ERROR: this is not a Gen 2 pokémon game!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint16_t flagNumber = getFlagNumber();
|
||||||
|
|
||||||
|
Gen2GameReader gameReader(romReader, saveManager, gen2Type);
|
||||||
|
bool result = gameReader.getEventFlag(flagNumber);
|
||||||
|
printf("Flag %hu => %s\n", flagNumber, (result) ? "true" : "false");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -15,7 +15,7 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
if(argc != 3)
|
if(argc != 3)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Usage: addDistributionPoke <path/to/rom.gbc> <path/to/file.sav>\n");
|
fprintf(stderr, "Usage: gen2_gsball <path/to/rom.gbc> <path/to/file.sav>\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
if(argc != 3)
|
if(argc != 3)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Usage: addDistributionPoke <path/to/rom.gbc> <path/to/file.sav>\n");
|
fprintf(stderr, "Usage: gen2_removeItem <path/to/rom.gbc> <path/to/file.sav>\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
48
examples/gen2_setEventFlag/Makefile
Normal file
48
examples/gen2_setEventFlag/Makefile
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
# # 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 := .
|
||||||
|
# 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))
|
||||||
|
|
||||||
|
LIBS := -lpokemegb
|
||||||
|
ifeq ($(PNG_SUPPORT),1)
|
||||||
|
LIBS += -lpng
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Ensure necessary directories exist
|
||||||
|
# This function ensures the directory for the target exists
|
||||||
|
define make_directory
|
||||||
|
@mkdir -p $(dir $@)
|
||||||
|
endef
|
||||||
|
|
||||||
|
# Target executable
|
||||||
|
TARGET := ../../gen2_setEventFlag
|
||||||
|
|
||||||
|
# Phony targets
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
|
# Default target
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
$(TARGET): $(OBJS)
|
||||||
|
$(CXX) $(CXXFLAGS) $^ -o $@ $(LIBS) -L ../../
|
||||||
|
|
||||||
|
# Rule to compile source files
|
||||||
|
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp | $(BUILD_DIR)
|
||||||
|
$(make_directory)
|
||||||
|
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
# Create the build directory if it doesn't exist
|
||||||
|
$(BUILD_DIR):
|
||||||
|
mkdir -p $(BUILD_DIR)
|
||||||
|
|
||||||
|
# Clean rule
|
||||||
|
clean:
|
||||||
|
rm -rf $(BUILD_DIR) $(TARGET)
|
||||||
111
examples/gen2_setEventFlag/main.cpp
Normal file
111
examples/gen2_setEventFlag/main.cpp
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
#include "gen2/Gen2GameReader.h"
|
||||||
|
#include "gen1/Gen1Common.h"
|
||||||
|
#include "RomReader.h"
|
||||||
|
#include "SaveManager.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
static uint16_t getFlagNumber()
|
||||||
|
{
|
||||||
|
char input[100];
|
||||||
|
printf("Enter event flag number: ");
|
||||||
|
if (fgets(input, sizeof(input), stdin) == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error reading input\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Remove the newline character if it exists
|
||||||
|
input[strcspn(input, "\n")] = '\0';
|
||||||
|
|
||||||
|
return (uint16_t)strtoul(input, 0, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t getFlagValue()
|
||||||
|
{
|
||||||
|
char input[100];
|
||||||
|
printf("Enter new value (0-1): ");
|
||||||
|
if (fgets(input, sizeof(input), stdin) == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error reading input\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Remove the newline character if it exists
|
||||||
|
input[strcspn(input, "\n")] = '\0';
|
||||||
|
|
||||||
|
return (uint16_t)strtoul(input, 0, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
if(argc != 3)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: gen2_setEventFlag <path/to/rom.gbc> <path/to/file.sav>\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* romBuffer;
|
||||||
|
uint8_t* saveBuffer;
|
||||||
|
uint32_t romFileSize;
|
||||||
|
uint32_t saveFileSize;
|
||||||
|
|
||||||
|
romBuffer = readFileIntoBuffer(argv[1], romFileSize);
|
||||||
|
if(!romBuffer)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "ERROR: Couldn't read file %s\n", argv[1]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
saveBuffer = readFileIntoBuffer(argv[2], saveFileSize);
|
||||||
|
if(!saveBuffer)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "ERROR: Couldn't read file %s\n", argv[2]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
GameboyCartridgeHeader cartridgeHeader;
|
||||||
|
BufferBasedRomReader romReader(romBuffer, romFileSize);
|
||||||
|
BufferBasedSaveManager saveManager(saveBuffer, saveFileSize);
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "ERROR: sorry, this tool only supports gen 2!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if(gen2Type == Gen2GameType::INVALID)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "ERROR: this is not a Gen 2 pokémon game!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint16_t flagNumber = getFlagNumber();
|
||||||
|
const uint16_t flagValue = getFlagValue();
|
||||||
|
|
||||||
|
if(flagValue != 0 && flagValue != 1)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "ERROR: wrong value %hu\n", flagValue);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gen2GameReader gameReader(romReader, saveManager, gen2Type);
|
||||||
|
gameReader.setEventFlag(flagNumber, static_cast<bool>(flagValue));
|
||||||
|
gameReader.finishSave();
|
||||||
|
printf("Flag %hu => %s\n", flagNumber, (static_cast<bool>(flagValue)) ? "true" : "false");
|
||||||
|
|
||||||
|
FILE* f = fopen(argv[2], "w");
|
||||||
|
fwrite(saveBuffer, 1, saveFileSize, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
free(romBuffer);
|
||||||
|
free(saveBuffer);
|
||||||
|
romBuffer = 0;
|
||||||
|
saveBuffer = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -183,6 +183,15 @@ public:
|
||||||
* @brief Unlocks the GS Ball event in Pokemon crystal
|
* @brief Unlocks the GS Ball event in Pokemon crystal
|
||||||
*/
|
*/
|
||||||
void unlockGsBallEvent();
|
void unlockGsBallEvent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retrieves the value of the given event flag
|
||||||
|
*/
|
||||||
|
bool getEventFlag(uint16_t flagNumber);
|
||||||
|
/**
|
||||||
|
* @brief Sets the value of the given event flag number
|
||||||
|
*/
|
||||||
|
void setEventFlag(uint16_t flagNumber, bool enabled);
|
||||||
protected:
|
protected:
|
||||||
private:
|
private:
|
||||||
IRomReader &romReader_;
|
IRomReader &romReader_;
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@
|
||||||
#define CRYSTAL_PICS_FIX 0x36
|
#define CRYSTAL_PICS_FIX 0x36
|
||||||
#define CRYSTAL_BANK_PICS_1 72
|
#define CRYSTAL_BANK_PICS_1 72
|
||||||
|
|
||||||
|
#define EVENT_FLAGS_OFFSET_GOLDSILVER 0x261F
|
||||||
|
#define EVENT_FLAGS_OFFSET_CRYSTAL 0x2600
|
||||||
|
|
||||||
static const uint8_t crystalPicsBanks[] = {
|
static const uint8_t crystalPicsBanks[] = {
|
||||||
CRYSTAL_BANK_PICS_1 + 0,
|
CRYSTAL_BANK_PICS_1 + 0,
|
||||||
CRYSTAL_BANK_PICS_1 + 1,
|
CRYSTAL_BANK_PICS_1 + 1,
|
||||||
|
|
@ -696,4 +699,42 @@ void Gen2GameReader::unlockGsBallEvent()
|
||||||
saveManager_.writeByte(0xB);
|
saveManager_.writeByte(0xB);
|
||||||
saveManager_.seek(0x3E44);
|
saveManager_.seek(0x3E44);
|
||||||
saveManager_.writeByte(0xB);
|
saveManager_.writeByte(0xB);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Gen2GameReader::getEventFlag(uint16_t flagNumber)
|
||||||
|
{
|
||||||
|
const uint16_t saveOffset = (isGameCrystal()) ? EVENT_FLAGS_OFFSET_CRYSTAL : EVENT_FLAGS_OFFSET_GOLDSILVER;
|
||||||
|
uint8_t byteVal;
|
||||||
|
const uint8_t flag = 1 << (flagNumber % 8);
|
||||||
|
|
||||||
|
saveManager_.seek(saveOffset + (flagNumber / 8));
|
||||||
|
saveManager_.readByte(byteVal);
|
||||||
|
|
||||||
|
return (byteVal & flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
void Gen2GameReader::setEventFlag(uint16_t flagNumber, bool enabled)
|
||||||
|
{
|
||||||
|
const uint16_t saveOffset = (isGameCrystal()) ? EVENT_FLAGS_OFFSET_CRYSTAL : EVENT_FLAGS_OFFSET_GOLDSILVER;
|
||||||
|
uint8_t byteVal;
|
||||||
|
uint8_t resultVal;
|
||||||
|
const uint8_t flag = 1 << (flagNumber % 8);
|
||||||
|
|
||||||
|
saveManager_.seek(saveOffset + (flagNumber / 8));
|
||||||
|
saveManager_.readByte(byteVal);
|
||||||
|
saveManager_.rewind(1);
|
||||||
|
|
||||||
|
// first calculate the value of the byte with the bit reset to 0
|
||||||
|
resultVal = byteVal & (~flag);
|
||||||
|
|
||||||
|
// now apply the flag if enabled == true
|
||||||
|
if(enabled)
|
||||||
|
{
|
||||||
|
resultVal |= flag;
|
||||||
|
}
|
||||||
|
printf("%s: flagNumber %hu, enabled: %d, orig byte: 0x%02x, new byte 0x%02x\n", __FUNCTION__, flagNumber, enabled, byteVal, resultVal);
|
||||||
|
|
||||||
|
saveManager_.writeByte(resultVal);
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user