Reduce binary size by eliminating libstdc++

This commit removes all references to things in the libstdc++ library to remove a decent chunk of bloat.

This means every std::to_string() call, std::string and std::vector. (as well as iostream related stuff).

I replaced those with my own versions ptgb::to_string() and ptgb::vector. Especially the latter is not exactly the same,
but close enough.

I also replaced operator new and delete with my own implementation to avoid pulling in everything related to exceptions
from libstdc++

Another problem was the fact that libtonc uses siscanf, which pulls in everything related to the scanf family of functions
and locale support. The worst part of that was that it included a 13KB "categories" symbol from libc_a-categories.o,
which was pulled in because of the locale support integrated into newlibc's siscanf() function. To fix that, I created a
custom, extremely restricted implementation of siscanf. libtonc only used this function to parse at most 2 integers from a
string anyway.
This commit is contained in:
Philippe Symons 2025-04-09 20:04:08 +02:00
parent 7338828331
commit 9268cbd42e
25 changed files with 1763 additions and 199 deletions

View File

@ -46,7 +46,7 @@ CFLAGS := -g -Wall -O2\
$(ARCH)
CFLAGS += $(INCLUDE) -ffunction-sections -fdata-sections -Os -Wall -mthumb -mcpu=arm7tdmi -mtune=arm7tdmi
CXXFLAGS := $(CFLAGS) -g0 -fno-rtti -fno-exceptions -std=c++20 -Wno-volatile -D_GLIBCXX_USE_CXX20_ABI=0
CXXFLAGS := $(CFLAGS) -g0 -fno-rtti -fno-exceptions -fdata-sections -ffunction-sections -std=c++20 -Wno-volatile -D_GLIBCXX_USE_CXX20_ABI=0
ifeq ($(BUILD_TYPE), debug)
CFLAGS += -g -DDEBUG
@ -57,7 +57,7 @@ else ifeq ($(BUILD_TYPE), release)
endif
ASFLAGS := -g $(ARCH)
LDFLAGS = -Os -g $(ARCH) -Wl,-Map,$(notdir $*.map) -Wl,--gc-sections -mthumb -mcpu=arm7tdmi -mtune=arm7tdmi
LDFLAGS = -Os -g $(ARCH) -Wl,-Map,$(notdir $*.map) -Wl,--gc-sections -mthumb -mcpu=arm7tdmi -mtune=arm7tdmi -Wl,-Map,output.map,--cref -nodefaultlibs
CFLAGS += -flto
LDFLAGS += -flto
@ -65,7 +65,7 @@ LDFLAGS += -flto
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS := -lmm -ltonc -lgba -lc -lgcc
LIBS := -lmm -ltonc -lgba -lc -lgcc -lsysbase
#---------------------------------------------------------------------------------

View File

@ -2,7 +2,7 @@
#define MAIN_MENU_H
#include <tonc.h>
#include <vector>
#include "libstd_replacements.h"
#include "button_handler.h"
@ -33,8 +33,8 @@ public:
void clear_vector();
private:
std::vector<Button> button_vector;
std::vector<int> return_values;
ptgb::vector<Button> button_vector;
ptgb::vector<int> return_values;
int columns;
int rows;
int button_height;

View File

@ -4,7 +4,6 @@
#define GAMEBOY_COLOUR_H_
#include <tonc.h>
#include <string>
#include "libraries/gba-link-connection/LinkSPI.hpp"
#include "pokemon_party.h"

View File

@ -73,8 +73,9 @@ typedef enum
#define GB_LINK_H
#include <tonc.h>
//#include <string>
void log(std::string text);
//void log(std::string text);
void wait(u32 verticalLines);
inline void VBLANK() {}
void init();

View File

@ -0,0 +1,10 @@
# Contributors
## Special thanks for all the people who had helped this project so far:
* [Dino Dai Zovi](https://github.com/ddz)
* [Shang Yuanchun](https://github.com/ideal)
* [Shreyas Balakrishna](https://github.com/shreyasbharath)
* [Jim Keener](https://github.com/jimktrains)
* [Dean T](https://github.com/deanoburrito)
* [Oskars Rubenis](https://github.com/Okarss)

View File

@ -0,0 +1,53 @@
Nanoprintf is dual-licensed under both the "Unlicense" and the
"Zero-Clause BSD" (0BSD) licenses. The intent of this dual-licensing
structure is to make nanoprintf as consumable as possible in as many
environments / countries / companies as possible without encumbering
users.
This license applies to all of the nanoprintf source code, build code,
and tests, with the explicit exception of doctest.h, which exists under
its own license and is included in this repository.
The text of the two licenses follows below:
============================== UNLICENSE ==============================
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org>
================================ 0BSD =================================
Copyright (C) 2019 by Charles Nicholson <charles.nicholson+nanoprintf@gmail.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,187 @@
#ifndef _LIBSTD_REPLACEMENTS_H
#define _LIBSTD_REPLACEMENTS_H
#include <inttypes.h>
#include <cstring>
#include <new>
// To reduce the binary size, we need to get rid of libstdc++
// But we were happily using some functions that made life easier.
// so this file was created to provide some similar functions/functionalities
// (although stripped down to the bare minimum we're using)
namespace ptgb
{
/**
* This utility/convenience function converts the given value to a string.
* WARNING: it AND its other variants always use the same buffer.
* So calling it more than once will overwrite the previously returned string!
*
* Be careful!
* In case you want to convert more than one int to string within the same call,
* consider using npf_snprintf instead!
*
* Also: if you want to hold on to the converted value, consider copying the returned string
*/
const char* to_string(int intVal);
/**
* This utility/convenience function converts the given value to a string.
* WARNING: it AND its other variants always use the same buffer.
* So calling it more than once will overwrite the previously returned string!
*
* Be careful!
* In case you want to convert more than one int to string within the same call,
* consider using npf_snprintf instead!
*
* Also: if you want to hold on to the converted value, consider copying the returned string
*/
const char* to_string(unsigned int wordVal);
template <class ValueType>
class vector
{
public:
static constexpr size_t default_capacity = 10;
vector()
: buffer_()
, capacity_(default_capacity)
, count_(0)
{
buffer_ = static_cast<ValueType*>(::operator new(capacity_ * sizeof(ValueType)));
}
vector(const ValueType* valueList, size_t listSize)
: buffer_()
, capacity_(listSize)
, count_(0)
{
buffer_ = static_cast<ValueType*>(::operator new(capacity_ * sizeof(ValueType)));
insert(valueList, listSize);
}
~vector()
{
clear();
::operator delete(buffer_);
}
void reserve(size_t newSize)
{
ValueType *oldValue;
ValueType *oldBuffer;
if(newSize <= capacity_)
{
return;
}
oldBuffer = buffer_;
buffer_ = static_cast<ValueType*>(::operator new(newSize * sizeof(ValueType)));
capacity_ = newSize;
for (size_t i = 0; i < count_; ++i)
{
oldValue = oldBuffer + i;
new(buffer_ + i) ValueType(*oldValue);
oldValue->~ValueType();
}
::operator delete(oldBuffer);
}
void resize(size_t newSize)
{
resize(newSize, ValueType());
}
void resize(size_t newSize, const ValueType& value)
{
if(newSize < count_)
{
for(size_t i=0; i < (count_ - newSize); ++i)
{
pop_back();
}
}
else if(newSize > count_)
{
for(size_t i=0; i < (newSize - count_); ++i)
{
push_back(value);
}
}
}
void push_back(const ValueType& value)
{
if(count_ == capacity_)
{
reserve(capacity_ * 2);
}
new(buffer_ + count_) ValueType(value);
++count_;
}
void pop_back()
{
ValueType *value = buffer_ + ((count_ - 1));
value->~ValueType();
--count_;
}
void insert(vector<ValueType>& otherList)
{
reserve(count_ + otherList.size());
for(size_t i=0; i < otherList.size(); ++i)
{
push_back(otherList.at(i));
}
}
void insert(const ValueType* list, size_t listSize)
{
reserve(count_ + listSize);
for(size_t i=0; i < listSize; ++i)
{
push_back(list[i]);
}
}
void clear()
{
resize(0);
}
size_t size() const { return count_; }
size_t capacity() const { return capacity_; }
ValueType& at(size_t index)
{
return operator[](index);
}
const ValueType& at(size_t index) const
{
return operator[](index);
}
ValueType& operator[](size_t index)
{
return *reinterpret_cast<ValueType*>(buffer_ + index);
}
const ValueType& operator[](size_t index) const
{
return *reinterpret_cast<const ValueType*>(buffer_ + index);
}
private:
ValueType *buffer_;
size_t capacity_;
size_t count_;
};
}
#endif

View File

@ -2,7 +2,6 @@
#define POKEMON_DATA_H
#include <tonc.h>
#include <string>
#define erratic_max (u32)600000
#define fast_max (u32)800000

View File

@ -1,19 +1,19 @@
#include <tonc.h>
#include <vector>
#include "libstd_replacements.h"
#include <string>
#include "rom_data.h"
class script_var
{
public:
script_var(u32 nValue, std::vector<script_var *> &var_list_ref, int *nCurr_loc_ptr);
script_var(std::vector<script_var *> &var_list_ref, int *nCurr_loc_ptr);
script_var(u32 nValue, ptgb::vector<script_var *> &var_list_ref, int *nCurr_loc_ptr);
script_var(ptgb::vector<script_var *> &var_list_ref, int *nCurr_loc_ptr);
virtual void fill_refrences(u8 mg_array_ptr[]); // goes through all the script locations and updates them to point to the start
virtual void set_start(); // Add a pointer to where the start is
u32 place_word(); // Place the value in memory
int *curr_loc_ptr;
u32 value;
std::vector<u32> location_list; // stores all the locations in the script that need to be updated
ptgb::vector<u32> location_list; // stores all the locations in the script that need to be updated
u32 start_location_in_script;
};
@ -82,8 +82,8 @@ public:
using xse_var::xse_var;
void insert_music_data(u8 mg_array[], u8 blockCount, u8 priority, u8 reverb, u32 toneDataPointer);
void set_start();
void add_track(std::vector<byte> track);
void add_track(const byte* trackBytes, size_t trackSize);
int numTracks;
std::vector<u32> trackPointers;
std::vector<std::vector<byte>> trackArrays;
ptgb::vector<u32> trackPointers;
ptgb::vector<ptgb::vector<byte>> trackArrays;
};

View File

@ -2,8 +2,7 @@
#define SELECT_MENU_H
#include <tonc.h>
#include <vector>
#include <string>
#include "libstd_replacements.h"
#include "text_engine.h"
#define LANG_MENU 1
@ -21,8 +20,8 @@ public:
void set_lang(int nLang);
private:
std::vector<const byte*> menu_options;
std::vector<int> return_values;
ptgb::vector<const byte*> menu_options;
ptgb::vector<int> return_values;
unsigned int curr_selection;
bool cancel_enabled;
int menu_type;

View File

@ -1,9 +1,8 @@
#ifndef Z80_ASM_H
#define Z80_ASM_H
#include <string>
#include <stdarg.h>
#include <vector>
#include "libstd_replacements.h"
/*
All registers are above 16 to not confuse them with u8 or u16
@ -56,7 +55,7 @@ class z80_asm_handler
public:
int index;
int memory_offset;
std::vector<byte> data_vector;
ptgb::vector<byte> data_vector;
z80_asm_handler(int data_size, int mem_offset);
void add_byte(u8 value);
@ -110,31 +109,30 @@ public:
private:
void ROT(int reg, int info);
void throw_error(std::string message);
};
class z80_variable
{
public:
std::vector<byte> data;
ptgb::vector<byte> data;
int size;
z80_variable(std::vector<z80_variable*> *var_vec, int data_size, ...);
z80_variable(std::vector<z80_variable*> *var_vec);
z80_variable(ptgb::vector<z80_variable*> *var_vec, int data_size, ...);
z80_variable(ptgb::vector<z80_variable*> *var_vec);
void load_data(int data_size, byte array_data[]);
int place_ptr(z80_asm_handler *z80_instance);
void insert_variable(z80_asm_handler *var);
void update_ptrs();
private:
std::vector<int> ptr_locations;
std::vector<z80_asm_handler *> asm_handlers;
ptgb::vector<int> ptr_locations;
ptgb::vector<z80_asm_handler *> asm_handlers;
int var_mem_location;
};
class z80_jump
{
public:
z80_jump(std::vector<z80_jump*> *jump_vec);
z80_jump(ptgb::vector<z80_jump*> *jump_vec);
int place_relative_jump(z80_asm_handler *z80_instance);
int place_direct_jump(z80_asm_handler *z80_instance);
int place_pointer(z80_asm_handler *z80_instance);
@ -142,9 +140,9 @@ public:
void update_jumps();
private:
std::vector<int> ptr_locations;
std::vector<z80_asm_handler *> asm_handlers;
std::vector<bool> jump_types;
ptgb::vector<int> ptr_locations;
ptgb::vector<z80_asm_handler *> asm_handlers;
ptgb::vector<bool> jump_types;
int jump_mem_location;
};

Binary file not shown.

View File

@ -118,9 +118,9 @@ void Button_Menu::show_buttons()
void Button_Menu::hide_buttons()
{
for (Button &curr_btn : button_vector)
for(size_t i=0; i < button_vector.size(); ++i)
{
curr_btn.hide();
button_vector[i].hide();
}
}

View File

@ -1,5 +1,5 @@
#include <tonc.h>
#include <string>
#include "libstd_replacements.h"
#include "flash_mem.h"
#include "pokemon.h"
#include "rom_data.h"
@ -54,7 +54,7 @@ void initalize_memory_locations()
copy_save_to_ram(memory_section_array[mem_section], &global_memory_buffer[0], 0x1000);
tte_set_pos(8, 0);
tte_write("loc: ");
tte_write(std::to_string(memory_section_array[mem_section] + mem_start).c_str());
tte_write(ptgb::to_string(memory_section_array[mem_section] + mem_start));
tte_write("\n");
for (int i = mem_start; i < (128 + mem_start); i++)
{
@ -66,7 +66,7 @@ void initalize_memory_locations()
{
tte_write("#{cx:0xD000}");
}
tte_write(std::to_string(global_memory_buffer[i]).c_str());
tte_write(ptgb::to_string(global_memory_buffer[i]));
if (i % 8 == 7)
{
tte_write("\n");
@ -153,15 +153,15 @@ bool read_flag(u16 flag_id)
{
tte_set_pos(0, 0);
tte_write("#{cx:0xD000}Attempting to read byte ");
tte_write(std::to_string((curr_rom.offset_flags + (flag_id / 8)) % 0xF80).c_str());
tte_write(ptgb::to_string((curr_rom.offset_flags + (flag_id / 8)) % 0xF80));
tte_write(" of memory section ");
tte_write(std::to_string(1 + ((curr_rom.offset_flags + (flag_id / 8)) / 0xF80)).c_str());
tte_write(ptgb::to_string(1 + ((curr_rom.offset_flags + (flag_id / 8)) / 0xF80)));
tte_write(" for flag ");
tte_write(std::to_string(flag_id).c_str());
tte_write(ptgb::to_string(flag_id));
tte_write(". Flag is ");
copy_save_to_ram(memory_section_array[1 + ((curr_rom.offset_flags + (flag_id / 8)) / 0xF80)], &global_memory_buffer[0], 0x1000);
u8 flags = global_memory_buffer[(curr_rom.offset_flags + (flag_id / 8)) % 0xF80];
tte_write(std::to_string((flags >> (flag_id % 8)) & 0b1).c_str());
tte_write(ptgb::to_string((flags >> (flag_id % 8)) & 0b1));
while (true)
{
};

View File

@ -2,7 +2,10 @@
// Source: https://github.com/stevenchaulk/arduino-poke-gen2
#include <tonc.h>
#include <string>
#include <stdarg.h>
#include <inttypes.h>
#include "libraries/nanoprintf/nanoprintf.h"
#include "libstd_replacements.h"
#include "gameboy_colour.h"
#include "pokemon_trade.h"
#include "script_array.h"
@ -71,22 +74,40 @@ bool end_of_data;
byte data_packet[PACKET_SIZE];
std::string spi_text_out_array[10];
#define SPI_TEXT_OUT_ARRAY_ELEMENT_SIZE 64
// 10 elements of 64 bytes, zero-initialized.
char spi_text_out_array[10][SPI_TEXT_OUT_ARRAY_ELEMENT_SIZE] = {
{0},
{0},
{0},
{0},
{0},
{0},
{0},
{0},
{0},
{0}
};
void print(std::string str)
void print(const char* format, ...)
{
va_list args;
va_start(args, format);
for (int i = 10; i > 0; i--)
{
spi_text_out_array[i] = spi_text_out_array[i - 1];
strncpy(spi_text_out_array[i], spi_text_out_array[i - 1], SPI_TEXT_OUT_ARRAY_ELEMENT_SIZE);
}
spi_text_out_array[0] = str + "\n";
npf_vsnprintf(spi_text_out_array[0], SPI_TEXT_OUT_ARRAY_ELEMENT_SIZE, format, args);
va_end(args);
tte_erase_rect(LEFT, TOP, RIGHT, BOTTOM);
tte_set_pos(LEFT, 0);
for (int j = 0; j < 10; j++)
{
ptgb_write("#{cx:0xE000}");
ptgb_write(spi_text_out_array[j].c_str());
ptgb_write(spi_text_out_array[j]);
}
}
@ -314,12 +335,7 @@ int loop(byte *box_data_storage, byte *curr_payload, GB_ROM *curr_gb_rom, Simpli
if (PRINT_LINK_DATA && false)
{
tte_set_margins(0, 0, H_MAX, V_MAX);
print(
std::to_string(counter) + ": [" +
std::to_string(data_counter) + "][" +
std::to_string(state) + "][" +
std::to_string(in_data) + "][" +
std::to_string(out_data) + "]\n");
print("%d: [%d][%d][%" PRIu8 "][%" PRIu8 "]\n\n", counter, data_counter, state, in_data, out_data);
}
out_data = handleIncomingByte(in_data, box_data_storage, curr_payload, curr_gb_rom, curr_simple_array, cancel_connection);
@ -400,20 +416,20 @@ byte exchange_boxes(byte curr_in, byte *box_data_storage, GB_ROM *curr_gb_rom)
if (SHOW_DATA_PACKETS)
{
ptgb_write("P: ");
ptgb_write(std::to_string(data_packet[0]).c_str());
ptgb_write(ptgb::to_string(data_packet[0]));
ptgb_write("\n");
for (int i = 0; i < DATA_PER_PACKET; i++)
{
ptgb_write(std::to_string(i).c_str());
ptgb_write(ptgb::to_string(i));
ptgb_write(": ");
ptgb_write(std::to_string(data_packet[PACKET_DATA_AT(i)]).c_str());
ptgb_write(ptgb::to_string(data_packet[PACKET_DATA_AT(i)]));
ptgb_write(" [");
ptgb_write(std::to_string(data_packet[PACKET_FLAG_AT(i)]).c_str());
ptgb_write(ptgb::to_string(data_packet[PACKET_FLAG_AT(i)]));
ptgb_write("]\n");
}
ptgb_write(std::to_string(checksum).c_str());
ptgb_write(ptgb::to_string(checksum));
ptgb_write(" = ");
ptgb_write(std::to_string(data_packet[PACKET_CHECKSUM]).c_str());
ptgb_write(ptgb::to_string(data_packet[PACKET_CHECKSUM]));
}
if (checksum == data_packet[PACKET_CHECKSUM] && !init_packet && !(test_packet_fail && received_offset == 128)) // Verify if the data matches the checksum
@ -452,9 +468,9 @@ byte exchange_boxes(byte curr_in, byte *box_data_storage, GB_ROM *curr_gb_rom)
if (SHOW_DATA_PACKETS)
{
ptgb_write("\nNO: ");
ptgb_write(std::to_string(next_offset).c_str());
ptgb_write(ptgb::to_string(next_offset));
ptgb_write("\nFP: ");
ptgb_write(std::to_string(failed_packet).c_str());
ptgb_write(ptgb::to_string(failed_packet));
}
if (!init_packet)
@ -477,9 +493,9 @@ byte exchange_boxes(byte curr_in, byte *box_data_storage, GB_ROM *curr_gb_rom)
if (SHOW_DATA_PACKETS)
{
ptgb_write("\nRO: ");
ptgb_write(std::to_string(received_offset).c_str());
ptgb_write(ptgb::to_string(received_offset));
ptgb_write("\nIP: ");
ptgb_write(std::to_string(init_packet).c_str());
ptgb_write(ptgb::to_string(init_packet));
while (!key_held(KEY_A))
{

View File

@ -1,6 +1,6 @@
#include <tonc.h>
#include <cmath>
#include "libstd_replacements.h"
#include "global_frame_controller.h"
#include "random.h"
#include "background_engine.h"
@ -22,7 +22,7 @@ void global_next_frame()
key_poll();
rand_next_frame();
// tte_set_pos(0, 0);
// tte_write(std::to_string(get_rand_u32()).c_str());
// tte_write(ptgb::to_string(get_rand_u32()));
background_frame(global_frame_count);
determine_fennel_blink();
if (missingno_enabled)

View File

@ -0,0 +1,117 @@
#define NANOPRINTF_IMPLEMENTATION 1
#include "libstd_replacements.h"
#include "libraries/nanoprintf/nanoprintf.h"
#include <cstdlib>
#include <stdarg.h>
#include <ctype.h>
// recommended for a 32 bit system to have at least 33 bytes available
// source: https://cplusplus.com/reference/cstdlib/itoa/
// unfortunately itoa is not standardized, so we'll have to make do with snprintf
static char conversion_buffer[33];
extern "C"
{
// HACK:
// Unfortunately, libtonc references siscanf, which in turn causes a "lot" of binary bloat from newlibc (in regards to locale support)
// to be pulled in by the linker.
// However, if you look at what it is actually used for (in libtonc's tte_iohook.c), is just to extract 1 or 2 integers from a string
// by specifying a custom -extremely simplified- version, we can avoid pulling in the version from libc (alongside all the symbols IT references)
// Obviously it doesn't support everything it should. Just enough to support libtonc's current iteration.
//
// Anyway, doing this optimizes away a lot of scanf related functions from newlib and locale support among which a 13KB "categories" symbol.
int siscanf(const char *str, const char *format, ...)
{
bool expectingFormatSpecifier = false;
va_list args;
int* resultVal;
int ret = 0;
va_start(args, format);
while(*format != '\0')
{
if(*str == '\0')
{
//EOF encountered.
return -1;
}
if(expectingFormatSpecifier)
{
if(*format == 'd')
{
resultVal = va_arg(args, int*);
(*resultVal) = 0;
while(isdigit(*str))
{
(*resultVal) *= 10;
(*resultVal) += (*str) - '0';
++str;
}
// go back to the last character of the int, because we'll forward by one again at the end of the outer loop
--str;
++ret;
}
expectingFormatSpecifier = false;
}
else if((*format) == '%')
{
expectingFormatSpecifier = true;
}
++format;
++str;
}
va_end(args);
return ret;
}
}
const char* ptgb::to_string(int intVal)
{
npf_snprintf(conversion_buffer, sizeof(conversion_buffer), "%d", intVal);
return conversion_buffer;
}
const char* ptgb::to_string(unsigned int wordVal)
{
npf_snprintf(conversion_buffer, sizeof(conversion_buffer), "%u", wordVal);
return conversion_buffer;
}
// when compiling with -nostdlib++, we need to provide our own operator new and delete implementations
// Regular operator new
void* operator new(std::size_t size) {
void* ptr = std::malloc(size);
if (!ptr) {
// mimic standard behavior: throw std::bad_alloc
// but we can't use std::bad_alloc without libstdc++
// so instead we can abort or return nullptr
// You can also implement a custom exception if needed
std::abort();
}
return ptr;
}
// nothrow version
void* operator new(std::size_t size, const std::nothrow_t&) noexcept {
return std::malloc(size);
}
// operator delete
void operator delete(void* ptr) noexcept {
std::free(ptr);
}
// nothrow delete
void operator delete(void* ptr, const std::nothrow_t&) noexcept {
std::free(ptr);
}
// sized delete (optional, for C++14 and newer)
void operator delete(void* ptr, std::size_t size) noexcept {
(void)size;
std::free(ptr);
}

View File

@ -1,8 +1,7 @@
#include <tonc.h>
#include <string>
#include <cstring>
// #include <maxmod.h> //Music
#include "libstd_replacements.h"
#include "flash_mem.h"
#include "interrupt.h"
#include "gb_link.h"
@ -85,14 +84,16 @@ int test_main(void) Music
// (R + G*32 + B*1024)
#define RGB(r, g, b) (r + (g * 32) + (b * 1024))
// make sure outBuffer is large enough! Should be at least hex_len + 1
template <typename I>
std::string n2hexstr(I w, size_t hex_len = sizeof(I) << 1)
void n2hexstr(char* outBuffer, I w, size_t hex_len = sizeof(I) << 1)
{
static const char *digits = "0123456789ABCDEF";
std::string rc(hex_len, '0');
memset(outBuffer, '0', hex_len);
outBuffer[hex_len] = '\0'; // we must make sure to terminate the string
for (size_t i = 0, j = (hex_len - 1) * 4; i < hex_len; ++i, j -= 4)
rc[i] = digits[(w >> j) & 0x0f];
return rc;
outBuffer[i] = digits[(w >> j) & 0x0f];
}
void load_graphics()
@ -196,6 +197,7 @@ void first_load_message(void)
int credits()
{
char hexBuffer[16];
#define CREDITS_ARRAY_SIZE 19
int curr_credits_num = 0;
const byte *credits_array[CREDITS_ARRAY_SIZE] = {
@ -269,9 +271,7 @@ int credits()
create_textbox(4, 1, 160, 80, true);
ptgb_write_debug("Debug info:\n\nG: ", true);
std::string lang;
lang += curr_rom.language;
ptgb_write_debug(lang.c_str(), true);
ptgb_write_debug(ptgb::to_string(curr_rom.language), true);
switch (curr_rom.gamecode)
{
case RUBY_ID:
@ -290,18 +290,22 @@ int credits()
ptgb_write_debug("-E-", true);
break;
}
ptgb_write_debug(std::to_string(curr_rom.version).c_str(), true);
ptgb_write_debug(ptgb::to_string(curr_rom.version), true);
ptgb_write_debug("\nF: ", true);
ptgb_write_debug(std::to_string(e4_flag).c_str(), true);
ptgb_write_debug(std::to_string(mg_flag).c_str(), true);
ptgb_write_debug(std::to_string(all_collected_flag).c_str(), true);
ptgb_write_debug(ptgb::to_string(e4_flag), true);
ptgb_write_debug(ptgb::to_string(mg_flag), true);
ptgb_write_debug(ptgb::to_string(all_collected_flag), true);
ptgb_write_debug("-", true);
ptgb_write_debug((n2hexstr(pkmn_flags)).c_str(), true);
n2hexstr(hexBuffer, pkmn_flags);
ptgb_write_debug(hexBuffer, true);
ptgb_write_debug("\nS: ", true);
ptgb_write_debug(std::to_string(tutorial).c_str(), true);
ptgb_write_debug(ptgb::to_string(tutorial), true);
ptgb_write_debug("-", true);
ptgb_write_debug((n2hexstr(def_lang)).c_str(), true);
n2hexstr(hexBuffer, def_lang);
ptgb_write_debug(hexBuffer, true);
ptgb_write_debug("\n", true);
ptgb_write_debug(VERSION, true);

View File

@ -1,5 +1,5 @@
#include <tonc.h>
#include <vector>
#include "libstd_replacements.h"
#include "mystery_gift_builder.h"
#include "pokemon_party.h"
#include "pokemon_data.h"
@ -63,8 +63,8 @@ mystery_gift_script::mystery_gift_script()
void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
{
std::vector<script_var *> mg_variable_list;
std::vector<script_var *> sec30_variable_list;
ptgb::vector<script_var *> mg_variable_list;
ptgb::vector<script_var *> sec30_variable_list;
asm_var sendMonToPC_ptr(curr_rom.loc_sendMonToPC + READ_AS_THUMB, sec30_variable_list, &curr_section30_index);
asm_var returned_box_success_ptr(ptr_box_return, sec30_variable_list, &curr_section30_index);
@ -283,13 +283,26 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
const int movementGoDownArray[2] = {MOVEMENT_ACTION_WALK_FAST_DOWN, MOVEMENT_ACTION_FACE_UP};
movementGoDown.set_movement(movementGoDownArray, 2);
// songLooker.add_track({0xBC, 0x00, 0xBB, 0x38, 0xBD, 0x38, 0xC4, 0x00, 0xBE, 0x60, 0xBF, 0x3D, 0xC0, 0x40, 0xD4, 0x51, 0x70, 0x86, 0xD4, 0x8C, 0x53, 0x86, 0xD4, 0x8C, 0x54, 0x86, 0xD4, 0x92, 0xE8, 0x55, 0x92, 0xBE, 0x64, 0x82, 0x6C, 0x84, 0x74, 0x85, 0xB1});
songLooker.add_track({0xBC, 0x00, 0xBD, 0x38, 0xC4, 0x00, 0xBE, 0x60, 0xBF, 0x46, 0xC0, 0x40, 0x83, 0xD4, 0x51, 0x3C, 0x86, 0xD4, 0x8C, 0x53, 0x86, 0xD4, 0x8C, 0x54, 0x86, 0xD4, 0x92, 0xE8, 0x55, 0x99, 0x81, 0xB1});
songLooker.add_track({0xBC, 0x00, 0xBD, 0x38, 0xC4, 0x00, 0xBF, 0x34, 0xBE, 0x6E, 0xC0, 0x40, 0xD4, 0x3C, 0x70, 0x86, 0xD4, 0x8C, 0x3B, 0x86, 0xD4, 0x8C, 0x3C, 0x86, 0xD4, 0x92, 0xEA, 0x3D, 0x9B, 0x83, 0xB1});
songLooker.add_track({0xBC, 0x00, 0xBD, 0x38, 0xC4, 0x00, 0xBF, 0x34, 0xBE, 0x6E, 0xC0, 0x40, 0xD4, 0x39, 0x70, 0x86, 0xD4, 0x8C, 0x36, 0x86, 0xD4, 0x8C, 0x37, 0x86, 0xD4, 0x92, 0xEA, 0x39, 0x9B, 0x83, 0xB1});
songLooker.add_track({0xBC, 0x00, 0xBD, 0x38, 0xC4, 0x00, 0xBF, 0x34, 0xBE, 0x6E, 0xC0, 0x40, 0xD4, 0x34, 0x70, 0x86, 0xD4, 0x8C, 0x32, 0x86, 0xD4, 0x8C, 0x34, 0x86, 0xD4, 0x92, 0xEA, 0x37, 0x9B, 0x83, 0xB1});
// songLooker.add_track({0xBC, 0x00, 0xBD, 0x3C, 0xC4, 0x00, 0xBF, 0x58, 0xBE, 0x3B, 0xC0, 0x40, 0xD4, 0x40, 0x70, 0x86, 0xD4, 0x8C, 0x42, 0x86, 0xD4, 0x8C, 0x43, 0x86, 0xD4, 0x92, 0xE8, 0x99, 0x81, 0xB1});
// songLooker.add_track({0xBC, 0x00, 0xBD, 0x18, 0xC4, 0x00, 0xBE, 0x48, 0xBF, 0x1E, 0xC0, 0x40, 0xA0, 0xD0, 0x43, 0x70, 0x86, 0x45, 0x8C, 0x46, 0x8C, 0x45, 0x86, 0x47, 0x86, 0x49, 0x81, 0xB1});
// const byte track_1[] = {0xBC, 0x00, 0xBB, 0x38, 0xBD, 0x38, 0xC4, 0x00, 0xBE, 0x60, 0xBF, 0x3D, 0xC0, 0x40, 0xD4, 0x51, 0x70, 0x86, 0xD4, 0x8C, 0x53, 0x86, 0xD4, 0x8C, 0x54, 0x86, 0xD4, 0x92, 0xE8, 0x55, 0x92, 0xBE, 0x64, 0x82, 0x6C, 0x84, 0x74, 0x85, 0xB1};
// songLooker.add_track(track_1, sizeof(track_1));
const byte track_2[] = {0xBC, 0x00, 0xBD, 0x38, 0xC4, 0x00, 0xBE, 0x60, 0xBF, 0x46, 0xC0, 0x40, 0x83, 0xD4, 0x51, 0x3C, 0x86, 0xD4, 0x8C, 0x53, 0x86, 0xD4, 0x8C, 0x54, 0x86, 0xD4, 0x92, 0xE8, 0x55, 0x99, 0x81, 0xB1};
songLooker.add_track(track_2, sizeof(track_2));
const byte track_3[] = {0xBC, 0x00, 0xBD, 0x38, 0xC4, 0x00, 0xBF, 0x34, 0xBE, 0x6E, 0xC0, 0x40, 0xD4, 0x3C, 0x70, 0x86, 0xD4, 0x8C, 0x3B, 0x86, 0xD4, 0x8C, 0x3C, 0x86, 0xD4, 0x92, 0xEA, 0x3D, 0x9B, 0x83, 0xB1};
songLooker.add_track(track_3, sizeof(track_3));
const byte track_4[] = {0xBC, 0x00, 0xBD, 0x38, 0xC4, 0x00, 0xBF, 0x34, 0xBE, 0x6E, 0xC0, 0x40, 0xD4, 0x39, 0x70, 0x86, 0xD4, 0x8C, 0x36, 0x86, 0xD4, 0x8C, 0x37, 0x86, 0xD4, 0x92, 0xEA, 0x39, 0x9B, 0x83, 0xB1};
songLooker.add_track(track_4, sizeof(track_4));
const byte track_5[] = {0xBC, 0x00, 0xBD, 0x38, 0xC4, 0x00, 0xBF, 0x34, 0xBE, 0x6E, 0xC0, 0x40, 0xD4, 0x34, 0x70, 0x86, 0xD4, 0x8C, 0x32, 0x86, 0xD4, 0x8C, 0x34, 0x86, 0xD4, 0x92, 0xEA, 0x37, 0x9B, 0x83, 0xB1};
songLooker.add_track(track_5, sizeof(track_5));
// const byte track_6[] = {0xBC, 0x00, 0xBD, 0x3C, 0xC4, 0x00, 0xBF, 0x58, 0xBE, 0x3B, 0xC0, 0x40, 0xD4, 0x40, 0x70, 0x86, 0xD4, 0x8C, 0x42, 0x86, 0xD4, 0x8C, 0x43, 0x86, 0xD4, 0x92, 0xE8, 0x99, 0x81, 0xB1};
// songLooker.add_track(track_6, sizeof(track_6));
// const byte track_7[] = {0xBC, 0x00, 0xBD, 0x18, 0xC4, 0x00, 0xBE, 0x48, 0xBF, 0x1E, 0xC0, 0x40, 0xA0, 0xD0, 0x43, 0x70, 0x86, 0x45, 0x8C, 0x46, 0x8C, 0x45, 0x86, 0x47, 0x86, 0x49, 0x81, 0xB1};
// songLooker.add_track(track_7, sizeof(track_7));
unsigned char instrument;
switch (curr_rom.gamecode)
@ -307,8 +320,12 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
instrument = 0x26;
break;
};
songLooker.add_track({0xBC, 0x00, 0xBD, instrument, 0xC4, 0x00, 0xBE, 0x7F, 0xBF, 0x40, 0xC0, 0x40, 0xD4, 0x21, 0x70, 0x86, 0xD4, 0x8C, 0x20, 0x86, 0xD4, 0x8C, 0x1F, 0x86, 0xDA, 0x8C, 0xD4, 0x2D, 0x86, 0x21, 0x8C, 0xD4, 0x86, 0xD4, 0x8C, 0xD4, 0x85, 0xB1});
// songLooker.add_track({0xBC, 0x00, 0xBD, 0x7E, 0xC4, 0x00, 0xBE, 0x53, 0xBF, 0x40, 0xD4, 0x24, 0x70, 0x8C, 0xD4, 0x98, 0x32, 0x86, 0xD4, 0x86, 0x30, 0x86, 0xD4, 0x86, 0xD4, 0x86, 0xD4, 0x86, 0x2D, 0x86, 0xD4, 0x86, 0xD4, 0x86, 0xD4, 0x85, 0xB1});
const byte track_instrument_1[] = {0xBC, 0x00, 0xBD, instrument, 0xC4, 0x00, 0xBE, 0x7F, 0xBF, 0x40, 0xC0, 0x40, 0xD4, 0x21, 0x70, 0x86, 0xD4, 0x8C, 0x20, 0x86, 0xD4, 0x8C, 0x1F, 0x86, 0xDA, 0x8C, 0xD4, 0x2D, 0x86, 0x21, 0x8C, 0xD4, 0x86, 0xD4, 0x8C, 0xD4, 0x85, 0xB1};
songLooker.add_track(track_instrument_1, sizeof(track_instrument_1));
// const byte track_unused[] = {0xBC, 0x00, 0xBD, 0x7E, 0xC4, 0x00, 0xBE, 0x53, 0xBF, 0x40, 0xD4, 0x24, 0x70, 0x8C, 0xD4, 0x98, 0x32, 0x86, 0xD4, 0x86, 0x30, 0x86, 0xD4, 0x86, 0xD4, 0x86, 0xD4, 0x86, 0x2D, 0x86, 0xD4, 0x86, 0xD4, 0x86, 0xD4, 0x85, 0xB1};
// songLooker.add_track(track_unused, sizeof(track_unused));
int dex_nums[MAX_PKMN_IN_BOX] = {};
@ -785,7 +802,7 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
tte_erase_screen();
int val = (curr_mg_index - MG_SCRIPT_SIZE) - four_align_value;
tte_write("MG Script exceeded by ");
tte_write(std::to_string(val).c_str());
tte_write(ptgb::to_string(val));
tte_write(" bytes");
while (true)
{
@ -797,7 +814,7 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
tte_erase_screen();
int val = (curr_section30_index - 0x4096) - four_align_value;
tte_write("S30 Script exceeded by ");
tte_write(std::to_string(val).c_str());
tte_write(ptgb::to_string(val));
tte_write(" bytes");
while (true)
{
@ -808,7 +825,7 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
/*
void mystery_gift_script::build_script_old(Pokemon_Party &incoming_box_data)
{
std::vector<script_var *> asm_variable_list;
ptgb::vector<script_var *> asm_variable_list;
asm_var sendMonToPC_ptr(curr_rom.loc_sendMonToPC + READ_AS_THUMB, asm_variable_list, &curr_mg_index);
asm_var returned_box_success_ptr(ptr_box_return, asm_variable_list, &curr_mg_index);
asm_var curr_pkmn_index_ptr(ptr_pkmn_offset, asm_variable_list, &curr_mg_index);
@ -1013,7 +1030,7 @@ void mystery_gift_script::build_script_old(Pokemon_Party &incoming_box_data)
tte_erase_screen();
int val = (curr_mg_index - MG_SCRIPT_SIZE) - four_align_value;
tte_write("Script exceeded by ");
tte_write(std::to_string(val).c_str());
tte_write(ptgb::to_string(val));
tte_write(" bytes");
while (true)
{

View File

@ -4,10 +4,6 @@
#include "debug_mode.h"
#include "z80_asm.h"
#include <iostream>
#include <fstream>
#include <iomanip>
#define DATA_LOC (SHOW_DATA_PACKETS ? curr_rom.transferStringLocation : curr_rom.wEnemyMonSpecies)
byte out_array[PAYLOAD_SIZE] = {};
@ -25,8 +21,8 @@ byte *generate_payload(GB_ROM curr_rom, int type, bool debug)
if ((curr_rom.generation == 1 && curr_rom.version != YELLOW_ID))
{
std::vector<z80_jump *> jump_vector;
std::vector<z80_variable *> var_vector;
ptgb::vector<z80_jump *> jump_vector;
ptgb::vector<z80_variable *> var_vector;
z80_asm_handler z80_rng_seed(0x0A, curr_rom.wSerialOtherGameboyRandomNumberListBlock + 8);
z80_asm_handler z80_payload(0x1AA, curr_rom.wSerialEnemyDataBlock);
@ -280,21 +276,24 @@ byte *generate_payload(GB_ROM curr_rom, int type, bool debug)
}
// Combine the vectors into the full payload
std::vector<byte> full_data;
ptgb::vector<byte> full_data;
full_data.reserve(z80_rng_seed.data_vector.size() + z80_payload.data_vector.size() + z80_patchlist.data_vector.size());
full_data.insert(full_data.end(), z80_rng_seed.data_vector.begin(), z80_rng_seed.data_vector.end());
full_data.insert(full_data.end(), z80_payload.data_vector.begin(), z80_payload.data_vector.end());
full_data.insert(full_data.end(), z80_patchlist.data_vector.begin(), z80_patchlist.data_vector.end());
full_data.insert(z80_rng_seed.data_vector);
full_data.insert(z80_payload.data_vector);
full_data.insert(z80_patchlist.data_vector);
std::copy(full_data.begin(), full_data.end(), out_array);
for(size_t i=0; i < full_data.size(); ++i)
{
out_array[i] = full_data[i];
}
return out_array;
}
else if ((curr_rom.generation == 1 && curr_rom.version == YELLOW_ID))
{
std::vector<z80_jump *> jump_vector;
std::vector<z80_variable *> var_vector;
ptgb::vector<z80_jump *> jump_vector;
ptgb::vector<z80_variable *> var_vector;
z80_asm_handler z80_rng_seed(0x0A, curr_rom.wSerialOtherGameboyRandomNumberListBlock + 8);
z80_asm_handler z80_payload(0x1AA, curr_rom.wSerialEnemyDataBlock - 8); // Subtracting 8 is because the data is shifted after patching, removing part of the enemy name. May change depending on language
@ -591,13 +590,16 @@ byte *generate_payload(GB_ROM curr_rom, int type, bool debug)
}
// Combine the vectors into the full payload
std::vector<byte> full_data;
ptgb::vector<byte> full_data;
full_data.reserve(z80_rng_seed.data_vector.size() + z80_payload.data_vector.size() + z80_patchlist.data_vector.size());
full_data.insert(full_data.end(), z80_rng_seed.data_vector.begin(), z80_rng_seed.data_vector.end());
full_data.insert(full_data.end(), z80_payload.data_vector.begin(), z80_payload.data_vector.end());
full_data.insert(full_data.end(), z80_patchlist.data_vector.begin(), z80_patchlist.data_vector.end());
full_data.insert(z80_rng_seed.data_vector);
full_data.insert(z80_payload.data_vector);
full_data.insert(z80_patchlist.data_vector);
std::copy(full_data.begin(), full_data.end(), out_array);
for(size_t i=0; i < full_data.size(); ++i)
{
out_array[i] = full_data[i];
}
return out_array;
@ -664,8 +666,8 @@ byte *generate_payload(GB_ROM curr_rom, int type, bool debug)
else if (curr_rom.generation == 2)
{
std::vector<z80_jump *> jump_vector;
std::vector<z80_variable *> var_vector;
ptgb::vector<z80_jump *> jump_vector;
ptgb::vector<z80_variable *> var_vector;
z80_asm_handler z80_rng_seed(0x0A, curr_rom.wSerialOtherGameboyRandomNumberListBlock);
z80_asm_handler z80_payload(0x1CD, curr_rom.wSerialEnemyDataBlock); // wOTPartyData
@ -935,13 +937,16 @@ byte *generate_payload(GB_ROM curr_rom, int type, bool debug)
}
// Combine the vectors into the full payload
std::vector<byte> full_data;
ptgb::vector<byte> full_data;
full_data.reserve(z80_rng_seed.data_vector.size() + z80_payload.data_vector.size() + z80_patchlist.data_vector.size());
full_data.insert(full_data.end(), z80_rng_seed.data_vector.begin(), z80_rng_seed.data_vector.end());
full_data.insert(full_data.end(), z80_payload.data_vector.begin(), z80_payload.data_vector.end());
full_data.insert(full_data.end(), z80_patchlist.data_vector.begin(), z80_patchlist.data_vector.end());
full_data.insert(z80_rng_seed.data_vector);
full_data.insert(z80_payload.data_vector);
full_data.insert(z80_patchlist.data_vector);
std::copy(full_data.begin(), full_data.end(), out_array);
for(size_t i = 0; i < full_data.size(); ++i)
{
out_array[i] = full_data[i];
}
return out_array;
@ -953,21 +958,23 @@ byte *generate_payload(GB_ROM curr_rom, int type, bool debug)
return nullptr;
};
int test_main() // Rename to "main" to send the payload to test_payload.txt
// Uncomment to send the payload to test_payload.txt
#if 0
#include <cstdio>
int main()
{
freopen("test_payload.txt", "w", stdout);
std::cout << std::endl;
printf("\n");
byte *payload = generate_payload(ENG_RED, TRANSFER, true);
if (true)
{
for (int i = 0; i < 0x2A0; i++)
{
std::cout << "0x" << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << (unsigned int)payload[i] << ", ";
printf("0x%02X, ", (unsigned int)payload[i]);
if (i % 0x10 == 0xF)
{
std::cout << std::endl
<< "# 0x" << std::hex << i + 1 << std::endl;
printf("\n# 0x%X\n", i + 1);
}
}
return 0;
@ -976,12 +983,13 @@ int test_main() // Rename to "main" to send the payload to test_payload.txt
{
for (int i = 0; i < 0x150; i++)
{
std::cout << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << (unsigned int)payload[i + ((0x10 * 28) + 9)] << " ";
printf("%02X ", (unsigned int)payload[i + ((0x10 * 28) + 9)]);
if (i % 0x10 == 0xF)
{
std::cout << std::endl;
printf("\n");
}
}
return 0;
}
}
}
#endif

View File

@ -1,4 +1,5 @@
#include <tonc.h>
#include "libstd_replacements.h"
#include "pokemon.h"
#include "pokemon_data.h"
#include "random.h"
@ -93,7 +94,7 @@ void Pokemon::load_data(int index, const byte *party_data, int game, int lang)
switch (gen)
{
case 1:
// ptgb_write(std::to_string(party_data[1121]).c_str());
// ptgb_write(ptgb::to_string(party_data[1121]));
// while (true){};
species_index_party = party_data[party_species_offset];
species_index_struct = party_data[box_struct_offset + 0x00];
@ -142,15 +143,15 @@ void Pokemon::load_data(int index, const byte *party_data, int game, int lang)
{
tte_set_pos(8, 120);
ptgb_write("struct offset: ");
ptgb_write(std::to_string(box_struct_offset).c_str());
ptgb_write(ptgb::to_string(box_struct_offset));
ptgb_write("\nbox_size: ");
ptgb_write(std::to_string(box_size).c_str());
ptgb_write(ptgb::to_string(box_size));
ptgb_write("\npkmn_size: ");
ptgb_write(std::to_string(pkmn_size).c_str());
ptgb_write(ptgb::to_string(pkmn_size));
ptgb_write("\nindex: ");
ptgb_write(std::to_string(index).c_str());
ptgb_write(ptgb::to_string(index));
ptgb_write(", game: ");
ptgb_write(std::to_string(game).c_str());
ptgb_write(ptgb::to_string(game));
while (!key_hit(KEY_A))
{
global_next_frame();

View File

@ -9,6 +9,7 @@
#include "gba_rom_values/ger_gba_rom_values.h"
#include "gba_rom_values/ita_gba_rom_values.h"
#include "gba_rom_values/spa_gba_rom_values.h"
#include "libraries/nanoprintf/nanoprintf.h"
extern rom_data curr_rom;
@ -162,31 +163,34 @@ bool rom_data::is_ruby_sapphire()
void rom_data::print_rom_info()
{
std::string out;
char buffer[64];
char gameTypeChar;
switch (gamecode)
{
case (RUBY_ID):
out += "R";
gameTypeChar = 'R';
break;
case (SAPPHIRE_ID):
out += "S";
gameTypeChar = 'S';
break;
case (FIRERED_ID):
out += "F";
gameTypeChar = 'F';
break;
case (LEAFGREEN_ID):
out += "L";
gameTypeChar = 'L';
break;
case (EMERALD_ID):
out += "E";
gameTypeChar = 'E';
break;
default:
gameTypeChar = '0';
break;
}
out += "-";
out += std::to_string(version);
out += "-";
out += char(language);
npf_snprintf(buffer, sizeof(buffer), "%c-%d-%c", gameTypeChar, version, language);
tte_set_pos(0, 8);
ptgb_write(out.c_str());
ptgb_write(buffer);
}
bool rom_data::verify_rom()

View File

@ -1,5 +1,5 @@
#include <tonc.h>
#include <string>
#include "libstd_replacements.h"
#include "script_var.h"
#include "pokemon_data.h"
#include "debug_mode.h"
@ -7,14 +7,14 @@
extern rom_data curr_rom;
script_var::script_var(u32 nValue, std::vector<script_var *> &var_list_ref, int *nCurr_loc_ptr)
script_var::script_var(u32 nValue, ptgb::vector<script_var *> &var_list_ref, int *nCurr_loc_ptr)
{
var_list_ref.push_back(this); // Place the new object in the var_list
value = nValue;
curr_loc_ptr = nCurr_loc_ptr;
};
script_var::script_var(std::vector<script_var *> &var_list_ref, int *nCurr_loc_ptr)
script_var::script_var(ptgb::vector<script_var *> &var_list_ref, int *nCurr_loc_ptr)
{
var_list_ref.push_back(this); // Place the new object in the var_list
curr_loc_ptr = nCurr_loc_ptr;
@ -256,8 +256,9 @@ void music_var::set_start()
start_location_in_script = *curr_loc_ptr;
}
void music_var::add_track(std::vector<byte> track)
void music_var::add_track(const byte* trackBytes, size_t trackSize)
{
const ptgb::vector track(trackBytes, trackSize);
trackArrays.push_back(track);
}

View File

@ -1,11 +1,30 @@
#include "z80_asm.h"
#include <stdexcept>
#include <string>
#include <vector>
#include <stdarg.h>
#include "libraries/nanoprintf/nanoprintf.h"
#include "libstd_replacements.h"
#define DIRECT false
#define RELATIVE true
// this function generates an error message based on vsnprintf
// and throws it.
static void throw_error(const char* format, ...)
{
// reserved 33 bytes for 2 ints alongside a format string
char error_msg_buffer[96];
va_list args;
va_start(args, format);
npf_vsnprintf(error_msg_buffer, sizeof(error_msg_buffer), format, args);
va_end(args);
// we should avoid exceptions and <stdexcept>
// throw std::runtime_error(message);
while (true)
{
}
}
z80_asm_handler::z80_asm_handler(int data_size, int mem_offset)
{
data_vector.resize(data_size, 0x00);
@ -44,15 +63,6 @@ void z80_asm_handler::generate_patchlist(z80_asm_handler *bytes_to_patch){
add_byte(0xFF);
}
void z80_asm_handler::throw_error(std::string message)
{
// throw std::runtime_error(message);
while (true)
{
}
}
/* Figuring out pointers automatically is tricky since there are two seperate sections where our code is going. One is wSerialEnemyDataBlock, and the other is wSerialPartyMonsPatchList (0xC5D0)
However, theoretically all of our code should be in the patch list and all of the payload hijack stuff should be in the enemy data block.
Yellow is (currently) weird, but that will be fixed. The only time they cross over outside of that is in Gen 2 due to the box saving corrupting the code we're reading.
@ -129,7 +139,7 @@ void z80_asm_handler::LD(int destination, int source)
}
else
{
throw_error("Invalid Z80 LD command: " + std::to_string(source) + ", " + std::to_string(destination));
throw_error("Invalid Z80 LD command: %d, %d", source, destination);
}
}
void z80_asm_handler::HALT()
@ -163,7 +173,7 @@ void z80_asm_handler::ADD(int destination, int source)
}
else
{
throw_error("Invalid Z80 ADD command: " + std::to_string(source) + ", " + std::to_string(destination));
throw_error("Invalid Z80 ADD command: %d, %d", source, destination);
}
}
void z80_asm_handler::ADC(int destination, int source)
@ -181,7 +191,7 @@ void z80_asm_handler::ADC(int destination, int source)
}
else
{
throw_error("Invalid Z80 ADC command: " + std::to_string(source) + ", " + std::to_string(destination));
throw_error("Invalid Z80 ADC command: %d, %d", source, destination);
}
}
void z80_asm_handler::SUB(int destination, int source)
@ -199,7 +209,7 @@ void z80_asm_handler::SUB(int destination, int source)
}
else
{
throw_error("Invalid Z80 SUB command: " + std::to_string(source) + ", " + std::to_string(destination));
throw_error("Invalid Z80 SUB command: %d, %d", source, destination);
}
}
void z80_asm_handler::SBC(int destination, int source)
@ -217,7 +227,7 @@ void z80_asm_handler::SBC(int destination, int source)
}
else
{
throw_error("Invalid Z80 SBC command: " + std::to_string(source) + ", " + std::to_string(destination));
throw_error("Invalid Z80 SBC command: %d, %d", source, destination);
}
}
void z80_asm_handler::AND(int destination, int source)
@ -235,7 +245,7 @@ void z80_asm_handler::AND(int destination, int source)
}
else
{
throw_error("Invalid Z80 AND command: " + std::to_string(source) + ", " + std::to_string(destination));
throw_error("Invalid Z80 AND command: %d, %d", source, destination);
}
}
void z80_asm_handler::XOR(int destination, int source)
@ -253,7 +263,7 @@ void z80_asm_handler::XOR(int destination, int source)
}
else
{
throw_error("Invalid Z80 XOR command: " + std::to_string(source) + ", " + std::to_string(destination));
throw_error("Invalid Z80 XOR command: %d, %d", source, destination);
}
}
void z80_asm_handler::OR(int destination, int source)
@ -271,7 +281,7 @@ void z80_asm_handler::OR(int destination, int source)
}
else
{
throw_error("Invalid Z80 OR command: " + std::to_string(source) + ", " + std::to_string(destination));
throw_error("Invalid Z80 OR command: %d, %d", source, destination);
}
}
void z80_asm_handler::CP(int destination, int source)
@ -289,7 +299,7 @@ void z80_asm_handler::CP(int destination, int source)
}
else
{
throw_error("Invalid Z80 CP command: " + std::to_string(source) + ", " + std::to_string(destination));
throw_error("Invalid Z80 CP command: %d, %d", source, destination);
}
}
void z80_asm_handler::NOP()
@ -316,7 +326,7 @@ void z80_asm_handler::INC(int reg)
}
else
{
throw_error("Invalid Z80 INC command: " + std::to_string(reg));
throw_error("Invalid Z80 INC command: %d", reg);
}
}
void z80_asm_handler::DEC(int reg)
@ -333,7 +343,7 @@ void z80_asm_handler::DEC(int reg)
}
else
{
throw_error("Invalid Z80 DEC command: " + std::to_string(reg));
throw_error("Invalid Z80 DEC command: %d", reg);
}
}
void z80_asm_handler::RLC(int reg)
@ -366,7 +376,7 @@ void z80_asm_handler::ROT(int reg, int info)
}
else
{
throw_error("Invalid Z80 ROT command: " + std::to_string(reg));
throw_error("Invalid Z80 ROT command: %d", reg);
}
}
void z80_asm_handler::JR(int distance)
@ -379,7 +389,7 @@ void z80_asm_handler::JR(int distance)
}
else
{
throw_error("Invalid Z80 JR command: " + std::to_string(distance));
throw_error("Invalid Z80 JR command: %d", distance);
}
}
void z80_asm_handler::JR(int flag, int distance)
@ -392,7 +402,7 @@ void z80_asm_handler::JR(int flag, int distance)
}
else
{
throw_error("Invalid Z80 JR command: " + std::to_string(flag) + ", " + std::to_string(distance));
throw_error("Invalid Z80 JR command: %d, %d", flag, distance);
}
}
void z80_asm_handler::DDA()
@ -423,7 +433,7 @@ void z80_asm_handler::RET(int flag)
}
else
{
throw_error("Invalid Z80 RET command: " + std::to_string(flag));
throw_error("Invalid Z80 RET command: %d", flag);
}
};
void z80_asm_handler::RETI()
@ -438,7 +448,7 @@ void z80_asm_handler::PUSH(int source)
}
else
{
throw_error("Invalid Z80 PUSH command: " + std::to_string(source));
throw_error("Invalid Z80 PUSH command: %d", source);
}
}
void z80_asm_handler::POP(int destination)
@ -449,7 +459,7 @@ void z80_asm_handler::POP(int destination)
}
else
{
throw_error("Invalid Z80 PUSH command: " + std::to_string(destination));
throw_error("Invalid Z80 PUSH command: %d", destination);
}
}
void z80_asm_handler::JP(int destination)
@ -468,7 +478,7 @@ void z80_asm_handler::JP(int destination)
}
else
{
throw_error("Invalid Z80 JP command: " + std::to_string(destination));
throw_error("Invalid Z80 JP command: %d", destination);
}
}
void z80_asm_handler::JP(int flag, int destination)
@ -482,7 +492,7 @@ void z80_asm_handler::JP(int flag, int destination)
}
else
{
throw_error("Invalid Z80 JP command: " + std::to_string(flag) + ", " + std::to_string(destination));
throw_error("Invalid Z80 JP command: %d, %d", flag, destination);
}
}
void z80_asm_handler::CALL(int destination)
@ -496,7 +506,7 @@ void z80_asm_handler::CALL(int destination)
}
else
{
throw_error("Invalid Z80 CALL command: " + std::to_string(destination));
throw_error("Invalid Z80 CALL command: %d", destination);
}
}
void z80_asm_handler::CALL(int flag, int destination)
@ -510,7 +520,7 @@ void z80_asm_handler::CALL(int flag, int destination)
}
else
{
throw_error("Invalid Z80 CALL command: " + std::to_string(flag) + ", " + std::to_string(destination));
throw_error("Invalid Z80 CALL command: %d, %d", flag, destination);
}
}
void z80_asm_handler::RST(int value)
@ -521,7 +531,7 @@ void z80_asm_handler::RST(int value)
}
else
{
throw_error("Invalid Z80 RST command: " + std::to_string(value));
throw_error("Invalid Z80 RST command: %d", value);
}
}
void z80_asm_handler::LDH(int source, int destination)
@ -550,7 +560,7 @@ void z80_asm_handler::LDH(int source, int destination)
}
else
{
throw_error("Invalid Z80 LDH command: " + std::to_string(source) + ", " + std::to_string(destination));
throw_error("Invalid Z80 LDH command: %d, %d", source, destination);
}
}
void z80_asm_handler::DI()
@ -571,7 +581,7 @@ void z80_asm_handler::LDHL(int offset)
}
else
{
throw_error("Invalid Z80 LDHL command: " + std::to_string(offset));
throw_error("Invalid Z80 LDHL command: %d", offset);
}
}
void z80_asm_handler::SLA(int reg)
@ -583,7 +593,7 @@ void z80_asm_handler::SLA(int reg)
}
else
{
throw_error("Invalid Z80 SLA command: " + std::to_string(reg));
throw_error("Invalid Z80 SLA command: %d", reg);
}
}
void z80_asm_handler::SRA(int reg)
@ -595,7 +605,7 @@ void z80_asm_handler::SRA(int reg)
}
else
{
throw_error("Invalid Z80 SRA command: " + std::to_string(reg));
throw_error("Invalid Z80 SRA command: %d", reg);
}
}
void z80_asm_handler::SWAP(int reg)
@ -607,7 +617,7 @@ void z80_asm_handler::SWAP(int reg)
}
else
{
throw_error("Invalid Z80 SWAP command: " + std::to_string(reg));
throw_error("Invalid Z80 SWAP command: %d", reg);
}
}
void z80_asm_handler::SRL(int reg)
@ -619,7 +629,7 @@ void z80_asm_handler::SRL(int reg)
}
else
{
throw_error("Invalid Z80 SRL command: " + std::to_string(reg));
throw_error("Invalid Z80 SRL command: %d", reg);
}
}
void z80_asm_handler::BIT(int bit, int reg)
@ -631,7 +641,7 @@ void z80_asm_handler::BIT(int bit, int reg)
}
else
{
throw_error("Invalid Z80 BIT command: " + std::to_string(reg));
throw_error("Invalid Z80 BIT command: %d", reg);
}
}
void z80_asm_handler::RES(int bit, int reg)
@ -643,7 +653,7 @@ void z80_asm_handler::RES(int bit, int reg)
}
else
{
throw_error("Invalid Z80 RES command: " + std::to_string(reg));
throw_error("Invalid Z80 RES command: %d", reg);
}
}
void z80_asm_handler::SET(int bit, int reg)
@ -655,16 +665,16 @@ void z80_asm_handler::SET(int bit, int reg)
}
else
{
throw_error("Invalid Z80 SET command: " + std::to_string(reg));
throw_error("Invalid Z80 SET command: %d", reg);
}
}
z80_variable::z80_variable(std::vector<z80_variable *> *var_vec)
z80_variable::z80_variable(ptgb::vector<z80_variable *> *var_vec)
{
var_vec->push_back(this);
}
z80_variable::z80_variable(std::vector<z80_variable *> *var_vec, int data_size, ...)
z80_variable::z80_variable(ptgb::vector<z80_variable *> *var_vec, int data_size, ...)
{
var_vec->push_back(this);
data.resize(data_size);
@ -713,7 +723,7 @@ void z80_variable::update_ptrs()
}
}
z80_jump::z80_jump(std::vector<z80_jump *> *jump_vec)
z80_jump::z80_jump(ptgb::vector<z80_jump *> *jump_vec)
{
jump_vec->push_back(this);
}