mirror of
https://github.com/GearsProgress/Poke_Transporter_GB.git
synced 2026-03-21 17:34:42 -05:00
Add compression for the text data, output stack usage .su files and rework script_array
Add a binary table format and convert the text entries into this format in text_helper/main.py. It then gets compressed with zx0. The new text_data_table and streamed_data_table classes exist to read the various entries from this binary table. streamed_data_table specifically exists to use a decompression buffer that is smaller than the actual binary table. But it requires a decompression buffer that is still larger than ZX0_DEFAULT_WINDOW_SIZE (default: 2048 bytes) and will only be able to decompress in chunks of (<decompression_buffer_size> - <ZX0_DEFAULT_WINDOW_SIZE>) bytes Try to keep the binary text tables sufficiently small though, because since zx0 doesn't actually support random access, getting to the last entry is significantly more expensive than reading the first one. And unless you use streamed_data_table, it also requires <uncompressed_size> bytes of stack space, therefore IWRAM to decompress them. I also had to rework script_array because it can no longer reference the strings directly. Instead we now reference the DIA_* "enum" values. We also no longer store an array of script_obj instances, because these were getting stored in IWRAM since they're non-const global variables originally. Instead we now have const arrays of script_obj_params structs, which should end up in .rodata -> therefore EWRAM. Right now, script_obj only supports the PTGB text table (originally the dialogue array). But if the need arises to support other tables as well, I'd consider adding a separate enum to script_obj_params to indicate the specific table. The compilation process will also output .su files in the build folder from now on. These files indicate the stack frame size for every function in every compilation unit, so be sure to check them from time to time. Note that they will only show the stack consumption for that specific function. So to get the worst case stack consumption, you need to manually add all the functions in a certain stack flow.
This commit is contained in:
parent
12d1d10fc7
commit
26fd1e2dd3
|
|
@ -9,4 +9,4 @@ ARG GROUP_ID
|
|||
|
||||
ENV DEBIAN_FRONTEND="noninteractive"
|
||||
|
||||
RUN apt update && apt install -y build-essential
|
||||
RUN apt update && apt install -y build-essential python3-pip && pip install pandas requests openpyxl
|
||||
|
|
|
|||
12
Makefile
12
Makefile
|
|
@ -45,8 +45,8 @@ CFLAGS := -Wall -O2\
|
|||
-mcpu=arm7tdmi -mtune=arm7tdmi -masm-syntax-unified\
|
||||
$(ARCH)
|
||||
|
||||
CFLAGS += $(INCLUDE) -ffunction-sections -fdata-sections -Os -Wall -mthumb -mcpu=arm7tdmi -mtune=arm7tdmi
|
||||
CXXFLAGS := $(CFLAGS) -g0 -fno-rtti -fno-exceptions -fdata-sections -ffunction-sections -std=c++20 -Wno-volatile -D_GLIBCXX_USE_CXX20_ABI=0
|
||||
CFLAGS += $(INCLUDE) -ffunction-sections -fdata-sections -Os -Wall -mthumb -mcpu=arm7tdmi -mtune=arm7tdmi -fstack-usage
|
||||
CXXFLAGS := $(CFLAGS) -g0 -fno-rtti -fno-exceptions -fdata-sections -ffunction-sections -std=c++20 -Wno-volatile -D_GLIBCXX_USE_CXX20_ABI=0 -fstack-usage
|
||||
|
||||
ifeq ($(BUILD_TYPE), debug)
|
||||
CFLAGS += -g -DDEBUG
|
||||
|
|
@ -144,10 +144,12 @@ all: $(BUILD)
|
|||
|
||||
generate_data:
|
||||
mkdir -p data
|
||||
mkdir -p to_compress
|
||||
@env -i PATH=$(PATH) $(MAKE) -C tools/compressZX0
|
||||
@env -i PATH=$(PATH) $(MAKE) -C tools/data-generator
|
||||
@cd tools/data-generator && ./data-generator
|
||||
@find tools/data-generator -name *.bin | xargs -i tools/compressZX0/compressZX0 {} data/
|
||||
@tools/data-generator/data-generator to_compress
|
||||
@python3 text_helper/main.py
|
||||
@find to_compress -name "*.bin" | xargs -i tools/compressZX0/compressZX0 {} data/
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
$(BUILD): generate_data
|
||||
|
|
@ -163,7 +165,7 @@ clean:
|
|||
@$(MAKE) -C tools/compressZX0 clean
|
||||
@$(MAKE) -C tools/data-generator clean
|
||||
@$(MAKE) -C loader clean
|
||||
@rm -fr $(BUILD) $(TARGET).elf $(TARGET).gba data/
|
||||
@rm -fr $(BUILD) $(TARGET).elf $(TARGET).gba data/ to_compress/
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -256,7 +256,6 @@
|
|||
#define CPU_SET_32BIT 0x04000000
|
||||
class mystery_gift_script
|
||||
{
|
||||
PokemonTables &data_tables;
|
||||
int curr_mg_index;
|
||||
int curr_section30_index;
|
||||
u8 mg_script[MG_SCRIPT_SIZE] = {};
|
||||
|
|
@ -265,7 +264,7 @@ class mystery_gift_script
|
|||
u8 four_align_value = 0;
|
||||
|
||||
public:
|
||||
mystery_gift_script(PokemonTables &data_tables);
|
||||
mystery_gift_script();
|
||||
void build_script(Pokemon_Party &incoming_box_data);
|
||||
//void build_script_old(Pokemon_Party &incoming_box_data);
|
||||
u8 get_script_value_at(int index);
|
||||
|
|
|
|||
|
|
@ -59,11 +59,10 @@
|
|||
|
||||
#define SCRIPT_SIZE COND_END
|
||||
|
||||
extern script_obj transfer_script[];
|
||||
extern script_obj event_script[];
|
||||
extern const script_obj_params transfer_script_params[];
|
||||
extern const script_obj_params event_script_params[];
|
||||
extern rom_data curr_rom;
|
||||
|
||||
void populate_script();
|
||||
void populate_lang_menu();
|
||||
void populate_game_menu(int lang);
|
||||
bool run_conditional(int index);
|
||||
|
|
|
|||
|
|
@ -1,28 +1,29 @@
|
|||
#ifndef SCRIPT_OBJ_H
|
||||
#define SCRIPT_OBJ_H
|
||||
|
||||
#include <string>
|
||||
#include "pokemon_party.h"
|
||||
#include <tonc.h>
|
||||
typedef struct
|
||||
{
|
||||
u16 text_entry_index;
|
||||
u16 conditional_index;
|
||||
u16 next_if_true;
|
||||
u16 next_if_false;
|
||||
} script_obj_params;
|
||||
|
||||
class script_obj
|
||||
{
|
||||
public:
|
||||
script_obj();
|
||||
script_obj(const byte* nText, uint16_t nNext); // For dialogue
|
||||
script_obj(uint16_t nRun, uint16_t nNext); // For commands
|
||||
script_obj(uint16_t nRun, uint16_t nNext_if_true, uint16_t nNext_if_false); // for conditionals
|
||||
script_obj(const script_obj_params ¶ms);
|
||||
|
||||
const byte* get_text();
|
||||
uint16_t get_true_index();
|
||||
uint16_t get_false_index();
|
||||
uint16_t get_cond_id();
|
||||
bool has_text() const;
|
||||
u8 get_text_entry_index() const;
|
||||
u16 get_true_index() const;
|
||||
u16 get_false_index() const;
|
||||
u16 get_cond_id() const;
|
||||
|
||||
private:
|
||||
const byte* text;
|
||||
bool has_text = false;
|
||||
uint16_t next_index;
|
||||
uint16_t conditional_index;
|
||||
uint16_t next_false_index;
|
||||
script_obj_params params_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -49,9 +49,8 @@ class textbox_var : public xse_var
|
|||
public:
|
||||
using xse_var::xse_var;
|
||||
void set_text(const byte nText[]);
|
||||
void insert_text(const u16 *charset, u8 mg_array[]);
|
||||
void insert_text(const u16 *charset, u8 mg_array[], bool should_set_virtual_start = false);
|
||||
void set_start();
|
||||
void insert_virtual_text(const u16 *charset, u8 mg_array[]);
|
||||
void set_virtual_start();
|
||||
const byte *text;
|
||||
int text_length;
|
||||
|
|
|
|||
|
|
@ -16,11 +16,11 @@ public:
|
|||
void hide_menu();
|
||||
void show_menu();
|
||||
void clear_options();
|
||||
void add_option(const byte *option, u8 return_value);
|
||||
void add_option(const u8 option, u8 return_value);
|
||||
void set_lang(u8 nLang);
|
||||
|
||||
private:
|
||||
ptgb::vector<const byte*> menu_options;
|
||||
ptgb::vector<u8> menu_options;
|
||||
ptgb::vector<u8> return_values;
|
||||
u16 curr_selection;
|
||||
bool cancel_enabled;
|
||||
|
|
|
|||
83
include/text_data_table.h
Normal file
83
include/text_data_table.h
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
#ifndef _TEXT_DATA_TABLE_H
|
||||
#define _TEXT_DATA_TABLE_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
/**
|
||||
* This class fully decompresses a text table in the specified decompression_buffer
|
||||
* and then gives you utility functions to retrieve the text entries
|
||||
*
|
||||
* But it requires a buffer large enough to contain the entire decompressed table.
|
||||
* It will also completely decompress the table, which may not what you want.
|
||||
*
|
||||
* If you want to use a text table in a streamed manner (use smaller decompression buffer and only decompress what's needed)
|
||||
* consider using streamed_text_data_table instead.
|
||||
*/
|
||||
class text_data_table
|
||||
{
|
||||
public:
|
||||
text_data_table(uint8_t *decompression_buffer);
|
||||
|
||||
/**
|
||||
* This function will start the full decompression for the specified compressed_table
|
||||
* and stores it in the decompression_buffer_
|
||||
*/
|
||||
void decompress(const uint8_t *compressed_table);
|
||||
|
||||
/**
|
||||
* Returns the number of text entries in the decompression_buffer_
|
||||
*/
|
||||
uint16_t get_number_of_text_entries() const;
|
||||
|
||||
/**
|
||||
* This function returns a pointer to a text entry in the decompression_buffer
|
||||
*/
|
||||
const uint8_t* get_text_entry(uint8_t index) const;
|
||||
private:
|
||||
uint8_t *decompression_buffer_;
|
||||
};
|
||||
|
||||
/**
|
||||
* This class is an alternative to translated_text table.
|
||||
* It provides the same functionality, yet in a streamed manner.
|
||||
*
|
||||
* This allows you to use a decompression_buffer that is smaller than the fully decoded text table and only decompress until
|
||||
* you have what you need.
|
||||
*
|
||||
* To make sure we have access to the table index at all times, you need to specify a buffer to hold the table index as well.
|
||||
*
|
||||
* REQUIREMENT: decompression_buffer needs to be larger than the zx0 window size!!
|
||||
*/
|
||||
class streamed_text_data_table
|
||||
{
|
||||
public:
|
||||
streamed_text_data_table(uint8_t *decompression_buffer, uint32_t decompression_buffer_size, uint8_t *index_buffer);
|
||||
|
||||
/**
|
||||
* This function sets up the zx0 decompressor and decompresses the index into the index_buffer
|
||||
*/
|
||||
void decompress(const uint8_t *compressed_table);
|
||||
|
||||
/**
|
||||
* Returns the number of text entries in the decompression_buffer_
|
||||
*/
|
||||
uint16_t get_number_of_text_entries() const;
|
||||
|
||||
/**
|
||||
* This function returns a pointer to a text entry in the decompression_buffer
|
||||
*/
|
||||
const uint8_t* get_text_entry(uint8_t index);
|
||||
private:
|
||||
uint8_t* get_window_start() const;
|
||||
uint8_t* get_window_end() const;
|
||||
uint16_t get_current_zx0_window_size() const;
|
||||
|
||||
const uint8_t *compressed_table_;
|
||||
uint8_t *decompression_buffer_;
|
||||
uint32_t decompression_buffer_size_;
|
||||
uint8_t *index_buffer_;
|
||||
mutable uint16_t bytes_decompressed_;
|
||||
uint16_t last_chunk_size_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include <cstdint>
|
||||
|
||||
#define ZX0_DEFAULT_WINDOW_SIZE 2048
|
||||
|
||||
// The ZX0 decompressor offers functionality to decompress data
|
||||
// compressed with the ZX0 algorithm (see tools/compressZX0)
|
||||
// This algorithm was invented by Einar Saukas
|
||||
|
|
@ -25,9 +27,23 @@ extern "C"
|
|||
|
||||
/**
|
||||
* @brief This function copies <num_bytes> of decompressed data into the specified <output_buffer>
|
||||
* It will trigger decompression on the go (streaming basis)
|
||||
* It will append to the existing output_buffer you set earlier with zx0_decompressor_start()
|
||||
*/
|
||||
void zx0_decompressor_read(uint32_t num_bytes);
|
||||
|
||||
/**
|
||||
* @brief this function does a partial decompress into output_buffer.
|
||||
* HOWEVER: zx0 decompression requires you to use previously decompressed bytes to decompress the current ones.
|
||||
* In order to accomplish this, output_buffer MUST NOT point to the start of the buffer!!
|
||||
* Instead it should refer to a point within the buffer with previously decoded bytes available before it,
|
||||
* with up to the <ZX0 window size> bytes available before that point.
|
||||
* (So if you decoded >= window size, <window size> bytes should be available before output_buffer.
|
||||
* If not, before output_buffer should have <all decompressed bytes up until that point>)
|
||||
*
|
||||
* This function is intended as a way to read data in a "streamed" way into a smaller buffer that is smaller than the actual decompressed file size.
|
||||
* NOTE: when used in a loop, you should manually move the decompressed data from the previous iteration to the front of the buffer (output_buffer + window_size - num_bytes)
|
||||
*/
|
||||
void zx0_decompressor_read_partial(uint8_t *output_buffer, uint16_t num_bytes);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -9,11 +9,16 @@
|
|||
#include "pokemon_data.h"
|
||||
#include "text_engine.h"
|
||||
#include "translated_text.h"
|
||||
#include "text_data_table.h"
|
||||
#include "zx0_decompressor.h"
|
||||
|
||||
Box_Menu::Box_Menu() {};
|
||||
|
||||
int Box_Menu::box_main(Pokemon_Party party_data)
|
||||
{
|
||||
u8 names_decompression_buffer[3072];
|
||||
text_data_table PKMN_NAMES(names_decompression_buffer);
|
||||
|
||||
tte_erase_screen();
|
||||
load_flex_background(BG_BOX, 2);
|
||||
REG_BG1VOFS = 0;
|
||||
|
|
@ -32,6 +37,9 @@ int Box_Menu::box_main(Pokemon_Party party_data)
|
|||
bool update_pos = true;
|
||||
obj_unhide(box_select, 0);
|
||||
int index = 0;
|
||||
|
||||
PKMN_NAMES.decompress(get_compressed_pkmn_names_table());
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (get_frame_count() % 20 == 0)
|
||||
|
|
@ -140,12 +148,12 @@ int Box_Menu::box_main(Pokemon_Party party_data)
|
|||
tte_set_pos(14, 98);
|
||||
if (curr_pkmn.is_missingno)
|
||||
{
|
||||
ptgb_write(PKMN_NAMES[0], true);
|
||||
ptgb_write(PKMN_NAMES.get_text_entry(0), true);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
ptgb_write(PKMN_NAMES[curr_pkmn.dex_number], true);
|
||||
ptgb_write(PKMN_NAMES.get_text_entry(curr_pkmn.dex_number), true);
|
||||
}
|
||||
tte_set_pos(6, 108);
|
||||
val[0] = 0xC6; // L
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include "text_engine.h"
|
||||
#include "sprite_data.h"
|
||||
#include "string.h"
|
||||
#include "text_data_table.h"
|
||||
|
||||
int global_frame_count = 0;
|
||||
bool rand_enabled = true;
|
||||
|
|
@ -17,6 +18,18 @@ int fennel_blink_state = 0;
|
|||
bool missingno_enabled = false;
|
||||
bool treecko_enabled = false;
|
||||
|
||||
// split off from global_next_frame to limit the stack usage of the general_text_table_buffer to
|
||||
// the execution of this function
|
||||
// the noinline attribute prevents the compiler from inlining this function back into the global_next_frame function
|
||||
static void __attribute__((noinline)) show_pulled_cart_error()
|
||||
{
|
||||
u8 general_text_table_buffer[2048];
|
||||
text_data_table general_text(general_text_table_buffer);
|
||||
|
||||
general_text.decompress(get_compressed_general_table());
|
||||
ptgb_write(general_text.get_text_entry(GENERAL_pulled_cart_error), true);
|
||||
}
|
||||
|
||||
void global_next_frame()
|
||||
{
|
||||
key_poll();
|
||||
|
|
@ -41,7 +54,9 @@ void global_next_frame()
|
|||
tte_set_pos(40, 24);
|
||||
create_textbox(4, 1, 160, 80, true);
|
||||
obj_hide_multi(ptgb_logo_l, num_sprites);
|
||||
ptgb_write(pulled_cart_error, true);
|
||||
|
||||
show_pulled_cart_error();
|
||||
|
||||
oam_copy(oam_mem, obj_buffer, num_sprites);
|
||||
while (true)
|
||||
{
|
||||
|
|
|
|||
267
source/main.cpp
267
source/main.cpp
|
|
@ -29,6 +29,7 @@
|
|||
#include "multiboot_upload.h"
|
||||
#include "rom_data.h"
|
||||
#include "libraries/Pokemon-Gen3-to-Gen-X/include/save.h"
|
||||
#include "text_data_table.h"
|
||||
|
||||
/*
|
||||
|
||||
|
|
@ -134,8 +135,7 @@ void initalization_script(void)
|
|||
oam_init(obj_buffer, 128);
|
||||
load_graphics();
|
||||
|
||||
// Prepare dialouge
|
||||
populate_script();
|
||||
// Prepare text engine for dialogue
|
||||
init_text_engine();
|
||||
|
||||
// Set the random seed
|
||||
|
|
@ -153,7 +153,15 @@ void game_load_error(void)
|
|||
REG_BG2CNT = (REG_BG2CNT & ~BG_PRIO_MASK) | BG_PRIO(1);
|
||||
|
||||
create_textbox(4, 1, 152, 100, true);
|
||||
ptgb_write(cart_load_error, true);
|
||||
|
||||
{
|
||||
u8 general_text_table_buffer[2048];
|
||||
text_data_table general_text(general_text_table_buffer);
|
||||
|
||||
general_text.decompress(get_compressed_general_table());
|
||||
ptgb_write(general_text.get_text_entry(GENERAL_cart_load_error), true);
|
||||
}
|
||||
|
||||
key_poll();
|
||||
do
|
||||
{
|
||||
|
|
@ -187,7 +195,15 @@ void first_load_message(void)
|
|||
tte_set_margins(8, 8, H_MAX - 8, V_MAX);
|
||||
tte_set_pos(8, 8);
|
||||
tte_set_ink(INK_ROM_COLOR);
|
||||
ptgb_write(intro_first, true);
|
||||
|
||||
{
|
||||
u8 general_text_table_buffer[2048];
|
||||
text_data_table general_text(general_text_table_buffer);
|
||||
|
||||
general_text.decompress(get_compressed_general_table());
|
||||
ptgb_write(general_text.get_text_entry(GENERAL_intro_first), true);
|
||||
}
|
||||
|
||||
while (!key_hit(KEY_A))
|
||||
{
|
||||
global_next_frame();
|
||||
|
|
@ -195,34 +211,64 @@ void first_load_message(void)
|
|||
tte_erase_rect(0, 0, H_MAX, V_MAX);
|
||||
}
|
||||
|
||||
#define TIMER_ENABLE 0x80
|
||||
#define TIMER_CASCADE 0x4
|
||||
#define TIMER_FREQ_1 0x0 // 16.78 MHz
|
||||
#define TIMER_FREQ_64 0x1 // 262,144 Hz
|
||||
#define TIMER_FREQ_256 0x2 // 65,536 Hz
|
||||
#define TIMER_FREQ_1024 0x3 // 16,384 Hz
|
||||
|
||||
int test_decompress()
|
||||
{
|
||||
uint16_t charset[256];
|
||||
|
||||
// Reset both timers
|
||||
REG_TM0CNT = 0;
|
||||
REG_TM1CNT = 0;
|
||||
REG_TM0D = 0;
|
||||
REG_TM1D = 0;
|
||||
|
||||
// Set up TIMER0: count with no prescaler
|
||||
REG_TM0CNT = TIMER_ENABLE | TIMER_FREQ_1;
|
||||
// Set up TIMER1: cascade mode (increment when TIMER0 overflows)
|
||||
REG_TM1CNT = TIMER_ENABLE | TIMER_CASCADE;
|
||||
|
||||
load_localized_charset(charset, 3, ENG_ID);
|
||||
|
||||
// Read combined 32-bit timer value
|
||||
const u32 ticks = ((u32)REG_TM1D << 16) | REG_TM0D;
|
||||
|
||||
// Stop timers
|
||||
REG_TM0CNT = 0;
|
||||
REG_TM1CNT = 0;
|
||||
|
||||
create_textbox(4, 1, 160, 80, true);
|
||||
|
||||
ptgb_write_debug(charset, "Test results:\n\nDecompress: ", true);
|
||||
ptgb_write_debug(charset, ptgb::to_string(ticks * 1000 / 16777), true);
|
||||
ptgb_write_debug(charset, " usec\n", true);
|
||||
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (key_hit(KEY_B))
|
||||
{
|
||||
hide_text_box();
|
||||
reset_textbox();
|
||||
return 0;
|
||||
}
|
||||
global_next_frame();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int credits()
|
||||
{
|
||||
char hexBuffer[16];
|
||||
#define CREDITS_ARRAY_SIZE 19
|
||||
u8 text_decompression_buffer[2048];
|
||||
text_data_table credits_text_table(text_decompression_buffer);
|
||||
int curr_credits_num = 0;
|
||||
const byte *credits_array[CREDITS_ARRAY_SIZE] = {
|
||||
credits_page_1,
|
||||
credits_page_2,
|
||||
credits_page_3,
|
||||
credits_page_4,
|
||||
credits_page_5,
|
||||
credits_page_6,
|
||||
credits_page_7,
|
||||
credits_page_8,
|
||||
credits_page_9,
|
||||
credits_page_10,
|
||||
credits_page_11,
|
||||
credits_page_12,
|
||||
credits_page_13,
|
||||
credits_page_14,
|
||||
credits_page_15,
|
||||
credits_page_16,
|
||||
credits_page_17,
|
||||
credits_page_18,
|
||||
credits_page_19,
|
||||
// Add translators
|
||||
};
|
||||
|
||||
credits_text_table.decompress(get_compressed_credits_table());
|
||||
bool update = true;
|
||||
|
||||
global_next_frame();
|
||||
|
|
@ -232,7 +278,7 @@ int credits()
|
|||
{
|
||||
create_textbox(4, 1, 160, 80, true);
|
||||
show_text_box();
|
||||
ptgb_write(credits_array[curr_credits_num], true);
|
||||
ptgb_write(credits_text_table.get_text_entry(curr_credits_num), true);
|
||||
update = false;
|
||||
}
|
||||
|
||||
|
|
@ -247,13 +293,19 @@ int credits()
|
|||
curr_credits_num--;
|
||||
update = true;
|
||||
}
|
||||
if (key_hit(KEY_RIGHT) && curr_credits_num < (CREDITS_ARRAY_SIZE - 1))
|
||||
if (key_hit(KEY_RIGHT) && curr_credits_num < (credits_text_table.get_number_of_text_entries() - 1))
|
||||
{
|
||||
curr_credits_num++;
|
||||
update = true;
|
||||
}
|
||||
if(key_hit(KEY_SELECT))
|
||||
{
|
||||
return test_decompress();
|
||||
}
|
||||
#if 0
|
||||
if (ENABLE_DEBUG_SCREEN && key_hit(KEY_SELECT))
|
||||
{
|
||||
char hexBuffer[16];
|
||||
uint16_t charset[256];
|
||||
load_localized_charset(charset, 3, ENG_ID);
|
||||
if (key_held(KEY_UP) && key_held(KEY_L) && key_held(KEY_R))
|
||||
|
|
@ -327,6 +379,7 @@ int credits()
|
|||
global_next_frame();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
global_next_frame();
|
||||
}
|
||||
};
|
||||
|
|
@ -335,10 +388,16 @@ int credits()
|
|||
|
||||
int main_menu_loop()
|
||||
{
|
||||
uint8_t general_text_table_buffer[2048];
|
||||
text_data_table general_text(general_text_table_buffer);
|
||||
bool update = true;
|
||||
const byte *menu_options[NUM_MENU_OPTIONS] = {option_transfer, option_dreamdex, option_credits};
|
||||
const uint8_t menu_options[NUM_MENU_OPTIONS] = {GENERAL_option_transfer, GENERAL_option_dreamdex, GENERAL_option_credits};
|
||||
const uint8_t *text_entry;
|
||||
int return_values[NUM_MENU_OPTIONS] = {BTN_TRANSFER, BTN_POKEDEX, BTN_CREDITS};
|
||||
u16 test = 0;
|
||||
|
||||
general_text.decompress(get_compressed_general_table());
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (update)
|
||||
|
|
@ -346,7 +405,8 @@ int main_menu_loop()
|
|||
tte_erase_rect(0, 80, 240, 160);
|
||||
for (int i = 0; i < NUM_MENU_OPTIONS; i++)
|
||||
{
|
||||
int size = get_string_length(menu_options[i]);
|
||||
text_entry = general_text.get_text_entry(menu_options[i]);
|
||||
int size = get_string_length(text_entry);
|
||||
int char_width = (PTGB_BUILD_LANGUAGE == JPN_ID ? 8 : 6);
|
||||
int x = ((240 - (size * char_width)) / 2);
|
||||
tte_set_pos(x, ((i * 17) + 80));
|
||||
|
|
@ -358,7 +418,7 @@ int main_menu_loop()
|
|||
{
|
||||
tte_set_ink(INK_ROM_COLOR);
|
||||
}
|
||||
ptgb_write(menu_options[i], true);
|
||||
ptgb_write(text_entry, true);
|
||||
test++;
|
||||
}
|
||||
}
|
||||
|
|
@ -387,6 +447,93 @@ int main_menu_loop()
|
|||
}
|
||||
}
|
||||
|
||||
// Legal mumbo jumbo
|
||||
static void show_legal_text(const u8* intro_text)
|
||||
{
|
||||
tte_set_margins(8, 8, H_MAX - 8, V_MAX - 8);
|
||||
tte_set_pos(8, 8);
|
||||
tte_set_ink(INK_ROM_COLOR);
|
||||
ptgb_write(intro_text, true);
|
||||
bool wait = true;
|
||||
while (wait)
|
||||
{
|
||||
global_next_frame();
|
||||
if (key_hit(KEY_A))
|
||||
{
|
||||
wait = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Gears of Progress
|
||||
static void show_gears_of_progress()
|
||||
{
|
||||
tte_erase_rect(0, 0, 240, 160);
|
||||
REG_BG1VOFS = 0;
|
||||
delay_counter = 0;
|
||||
while (delay_counter < (15 * 60))
|
||||
{
|
||||
global_next_frame();
|
||||
delay_counter++;
|
||||
if (key_hit(KEY_A))
|
||||
{
|
||||
delay_counter = (15 * 60);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// split off from the main function in order to keep the scope of the variables limited to the execution of this function
|
||||
// otherwise they stick around for the entire runtime of the program
|
||||
// the attribute noinline is used to prevent the compiler from inlining this function back into the main function
|
||||
// this decision was based on the output of build/main.su after adding the -fstack-usage compile flag
|
||||
static void __attribute__((noinline)) show_intro()
|
||||
{
|
||||
bool start_pressed = false;
|
||||
u8 general_text_table_buffer[2048];
|
||||
u8 press_start_text[32];
|
||||
u8 press_start_text_length;
|
||||
|
||||
text_data_table general_text(general_text_table_buffer);
|
||||
const u8 *text_entry;
|
||||
|
||||
general_text.decompress(get_compressed_general_table());
|
||||
|
||||
text_entry = general_text.get_text_entry(GENERAL_press_start);
|
||||
press_start_text_length = get_string_length(text_entry);
|
||||
memcpy(press_start_text, text_entry, press_start_text_length + 1);
|
||||
text_entry = general_text.get_text_entry(GENERAL_intro_legal);
|
||||
|
||||
show_legal_text(text_entry);
|
||||
show_gears_of_progress();
|
||||
|
||||
REG_BG1CNT = REG_BG1CNT | BG_PRIO(3);
|
||||
|
||||
key_poll(); // Reset the keys
|
||||
curr_rom.load_rom();
|
||||
|
||||
obj_set_pos(ptgb_logo_l, 56, 12);
|
||||
obj_set_pos(ptgb_logo_r, 56 + 64, 12);
|
||||
obj_unhide_multi(ptgb_logo_l, 1, 2);
|
||||
|
||||
REG_BLDCNT = BLD_BUILD(BLD_BG3, BLD_BG0, 1);
|
||||
|
||||
int char_width = (PTGB_BUILD_LANGUAGE == JPN_ID ? 8 : 6);
|
||||
int x = ((240 - (press_start_text_length * char_width)) / 2);
|
||||
tte_set_pos(x, 12 * 8);
|
||||
|
||||
tte_set_ink(INK_DARK_GREY);
|
||||
ptgb_write(press_start_text, true);
|
||||
|
||||
int fade = 0;
|
||||
while (!start_pressed)
|
||||
{
|
||||
fade = abs(((get_frame_count() / 6) % 24) - 12);
|
||||
global_next_frame();
|
||||
start_pressed = key_hit(KEY_START) | key_hit(KEY_A);
|
||||
REG_BLDALPHA = BLDA_BUILD(0b10000, fade);
|
||||
};
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
initalization_script();
|
||||
|
|
@ -400,60 +547,8 @@ int main(void)
|
|||
first_load_message();
|
||||
}*/
|
||||
|
||||
// Legal mumbo jumbo
|
||||
tte_set_margins(8, 8, H_MAX - 8, V_MAX - 8);
|
||||
tte_set_pos(8, 8);
|
||||
tte_set_ink(INK_ROM_COLOR);
|
||||
ptgb_write(intro_legal, true);
|
||||
bool wait = true;
|
||||
while (wait)
|
||||
{
|
||||
global_next_frame();
|
||||
if (key_hit(KEY_A))
|
||||
{
|
||||
wait = false;
|
||||
}
|
||||
}
|
||||
show_intro();
|
||||
|
||||
// Gears of Progress
|
||||
tte_erase_rect(0, 0, 240, 160);
|
||||
REG_BG1VOFS = 0;
|
||||
delay_counter = 0;
|
||||
while (delay_counter < (15 * 60))
|
||||
{
|
||||
global_next_frame();
|
||||
delay_counter++;
|
||||
if (key_hit(KEY_A))
|
||||
{
|
||||
delay_counter = (15 * 60);
|
||||
}
|
||||
}
|
||||
REG_BG1CNT = REG_BG1CNT | BG_PRIO(3);
|
||||
|
||||
key_poll(); // Reset the keys
|
||||
curr_rom.load_rom();
|
||||
|
||||
obj_set_pos(ptgb_logo_l, 56, 12);
|
||||
obj_set_pos(ptgb_logo_r, 56 + 64, 12);
|
||||
obj_unhide_multi(ptgb_logo_l, 1, 2);
|
||||
bool start_pressed = false;
|
||||
REG_BLDCNT = BLD_BUILD(BLD_BG3, BLD_BG0, 1);
|
||||
|
||||
int size = get_string_length(press_start);
|
||||
int char_width = (PTGB_BUILD_LANGUAGE == JPN_ID ? 8 : 6);
|
||||
int x = ((240 - (size * char_width)) / 2);
|
||||
tte_set_pos(x, 12 * 8);
|
||||
|
||||
tte_set_ink(INK_DARK_GREY);
|
||||
ptgb_write(press_start, true);
|
||||
int fade = 0;
|
||||
while (!start_pressed)
|
||||
{
|
||||
fade = abs(((get_frame_count() / 6) % 24) - 12);
|
||||
global_next_frame();
|
||||
start_pressed = key_hit(KEY_START) | key_hit(KEY_A);
|
||||
REG_BLDALPHA = BLDA_BUILD(0b10000, fade);
|
||||
};
|
||||
key_poll();
|
||||
tte_erase_rect(0, 0, H_MAX, V_MAX);
|
||||
REG_BLDALPHA = BLDA_BUILD(0b10000, 0); // Reset fade
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "background_engine.h"
|
||||
#include "libraries/gba-link-connection/LinkCableMultiboot.hpp"
|
||||
#include "text_engine.h"
|
||||
#include "text_data_table.h"
|
||||
|
||||
static void multiboot_show_textbox()
|
||||
{
|
||||
|
|
@ -13,9 +14,14 @@ static void multiboot_show_textbox()
|
|||
|
||||
void multiboot_upload_screen()
|
||||
{
|
||||
u8 general_text_table_buffer[2048];
|
||||
text_data_table general_text(general_text_table_buffer);
|
||||
LinkCableMultiboot linkCableMultiboot;
|
||||
|
||||
general_text.decompress(get_compressed_general_table());
|
||||
|
||||
multiboot_show_textbox();
|
||||
ptgb_write(send_multiboot_instructions, true);
|
||||
ptgb_write(general_text.get_text_entry(GENERAL_send_multiboot_instructions), true);
|
||||
|
||||
// wait for key press
|
||||
do
|
||||
|
|
@ -31,7 +37,7 @@ void multiboot_upload_screen()
|
|||
|
||||
// start upload
|
||||
multiboot_show_textbox();
|
||||
ptgb_write(send_multiboot_wait, true);
|
||||
ptgb_write(general_text.get_text_entry(GENERAL_send_multiboot_wait), true);
|
||||
global_next_frame();
|
||||
|
||||
const u32 romSize = 256 * 1024; // EWRAM = 256 KB
|
||||
|
|
@ -49,11 +55,11 @@ void multiboot_upload_screen()
|
|||
multiboot_show_textbox();
|
||||
if (multibootResult == LinkCableMultiboot::Result::SUCCESS)
|
||||
{
|
||||
ptgb_write(send_multiboot_success, true);
|
||||
ptgb_write(general_text.get_text_entry(GENERAL_send_multiboot_success), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ptgb_write(send_multiboot_failure, true);
|
||||
ptgb_write(general_text.get_text_entry(GENERAL_send_multiboot_failure), true);
|
||||
}
|
||||
|
||||
// wait for keypress again.
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "pokemon_data.h"
|
||||
#include "rom_data.h"
|
||||
#include "translated_text.h"
|
||||
#include "text_data_table.h"
|
||||
|
||||
#define MG_SCRIPT false
|
||||
#define S30_SCRIPT true
|
||||
|
|
@ -40,8 +41,45 @@ int var_script_ptr_low = (VAR_ID_START + 0x01);
|
|||
int var_script_ptr_high = (VAR_ID_START + 0x02);
|
||||
int var_call_return_1 = (VAR_ID_START + 0x03);
|
||||
|
||||
mystery_gift_script::mystery_gift_script(PokemonTables &data_tables)
|
||||
: data_tables(data_tables)
|
||||
// the below structs and union are a scheme to reuse stack (IWRAM) memory of the
|
||||
// PokemonTables instance for storing decompressed text data once it's no longer needed.
|
||||
// The reason is that depending on the optimization level (-O0 specifically), the compiler may not do so automatically
|
||||
// if you'd use anonymous scopes for that purpose.
|
||||
// Having a union forces this behaviour.
|
||||
|
||||
// this struct is used to hold the PokemonTables data
|
||||
// within the decompressed_store union
|
||||
struct decompressed_data_tables
|
||||
{
|
||||
// This is about 3,4 KB
|
||||
PokemonTables data;
|
||||
};
|
||||
|
||||
// this struct is used to hold decompressed text data
|
||||
// within the decompressed_store union
|
||||
struct decompressed_text_data
|
||||
{
|
||||
// the buffer is specifically chosen to be -at least- the size of PokemonTables
|
||||
// to ensure that writing to gen3_charset_eng FROM the PokemonTables instance of the
|
||||
// union doesn't overwrite said instance during the copy
|
||||
u8 buffer[sizeof(PokemonTables)];
|
||||
u16 gen3_charset[256];
|
||||
};
|
||||
|
||||
// This union is used to hold the PokemonTables data on the stack when it's needed,
|
||||
// and reclaim the memory for decompressed text data when it's not.
|
||||
union decompressed_data_storage_union
|
||||
{
|
||||
decompressed_data_tables tables;
|
||||
decompressed_text_data text;
|
||||
|
||||
// constructor and destructor are needed to make the compiler stop complaining
|
||||
// about the decompressed_data_tables struct not being trivial
|
||||
decompressed_data_storage_union(){}
|
||||
~decompressed_data_storage_union(){}
|
||||
};
|
||||
|
||||
mystery_gift_script::mystery_gift_script()
|
||||
{
|
||||
curr_mg_index = NPC_LOCATION_OFFSET;
|
||||
curr_section30_index = 0;
|
||||
|
|
@ -64,6 +102,8 @@ mystery_gift_script::mystery_gift_script(PokemonTables &data_tables)
|
|||
|
||||
void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
|
||||
{
|
||||
decompressed_data_storage_union decompressed_store;
|
||||
text_data_table decompressed_text_table(decompressed_store.text.buffer);
|
||||
ptgb::vector<script_var *> mg_variable_list;
|
||||
ptgb::vector<script_var *> sec30_variable_list;
|
||||
|
||||
|
|
@ -141,51 +181,6 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
|
|||
}
|
||||
}
|
||||
|
||||
// Ş = Wait for button and scroll text
|
||||
// ȼ = Wait for button and clear text
|
||||
// Ȇ = Escape character
|
||||
// À = Change text color
|
||||
// Ç = Red
|
||||
// É = Green
|
||||
// Ë = Blue
|
||||
// Ʋ = Variable escape sequence
|
||||
// À = Player name
|
||||
// Ň = New line
|
||||
// ƞ = string terminator
|
||||
|
||||
switch (curr_rom.gamecode)
|
||||
{
|
||||
case RUBY_ID:
|
||||
textGreet.set_text(dia_textGreet_rse);
|
||||
textMoveBox.set_text(dia_textMoveBox_rs);
|
||||
textWeHere.set_text(dia_textWeHere_r);
|
||||
break;
|
||||
case SAPPHIRE_ID:
|
||||
textGreet.set_text(dia_textGreet_rse);
|
||||
textMoveBox.set_text(dia_textMoveBox_rs);
|
||||
textWeHere.set_text(dia_textWeHere_s);
|
||||
break;
|
||||
case FIRERED_ID:
|
||||
case LEAFGREEN_ID:
|
||||
textGreet.set_text(dia_textGreet_frlg);
|
||||
textMoveBox.set_text(dia_textMoveBox_frlg);
|
||||
textWeHere.set_text(dia_textWeHere_frlg);
|
||||
break;
|
||||
case EMERALD_ID:
|
||||
textGreet.set_text(dia_textGreet_rse);
|
||||
textMoveBox.set_text(dia_textMoveBox_e);
|
||||
textWeHere.set_text(dia_textWeHere_e);
|
||||
break;
|
||||
}
|
||||
textReceived.set_text(dia_textRecieved);
|
||||
textYouMustBe.set_text(first_time ? dia_textYouMustBe_first : dia_textYouMustBe_second);
|
||||
textIAm.set_text(first_time ? dia_textIAm_first : dia_textIAm_second);
|
||||
textPCConvo.set_text(dia_textPCConvo); // ȼDon’t worry ƲÀ,Ňyou won’t have to do a thing!");
|
||||
textPCThanks.set_text(dia_textPCThanks);
|
||||
textThank.set_text(dia_textThank);
|
||||
textPCFull.set_text(dia_textPCFull);
|
||||
textLookerFull.set_text(dia_textLookerFull);
|
||||
|
||||
const int movementSlowSpinArray[16] = {
|
||||
MOVEMENT_ACTION_FACE_LEFT,
|
||||
MOVEMENT_ACTION_DELAY_8,
|
||||
|
|
@ -330,9 +325,12 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
|
|||
|
||||
int dex_nums[MAX_PKMN_IN_BOX] = {};
|
||||
|
||||
// placement new is required to run the constructor of PokemonTables for the decompressed_store's instance
|
||||
// it won't get called automatically because it's part of the union (and neither will the destructor)
|
||||
new (&decompressed_store.tables.data) PokemonTables();
|
||||
for (int i = 0; i < MAX_PKMN_IN_BOX; i++) // Add in the Pokemon data
|
||||
{
|
||||
Pokemon curr_pkmn = incoming_box_data.get_converted_pkmn(data_tables, i);
|
||||
Pokemon curr_pkmn = incoming_box_data.get_converted_pkmn(decompressed_store.tables.data, i);
|
||||
if (curr_pkmn.get_validity())
|
||||
{
|
||||
for (int curr_byte = 0; curr_byte < POKEMON_SIZE; curr_byte++)
|
||||
|
|
@ -347,6 +345,14 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
|
|||
curr_section30_index += POKEMON_SIZE;
|
||||
}
|
||||
}
|
||||
// the PokemonTables instance is no longer needed, but we do need to keep the english gen3 charset around
|
||||
// for our insert_text() calls
|
||||
decompressed_store.tables.data.load_gen3_charset(ENG_ID);
|
||||
// we specifically defined the decompressed_text_data struct to ensure the memcpy shouldn't overlap
|
||||
memcpy(decompressed_store.text.gen3_charset, decompressed_store.tables.data.gen3_charset, sizeof(decompressed_store.text.gen3_charset));
|
||||
// calling the destructor is nothing more than a formality for our PokemonTables class,
|
||||
// but let's do it anyway for the sake of being explicit after having used placement new
|
||||
decompressed_store.tables.data.~PokemonTables();
|
||||
|
||||
for (int i = 0; i < MAX_PKMN_IN_BOX; i++) // Add in the dex numbers
|
||||
{
|
||||
|
|
@ -355,16 +361,63 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
|
|||
}
|
||||
|
||||
// insert text
|
||||
data_tables.load_gen3_charset(ENG_ID);
|
||||
|
||||
textThank.insert_text(data_tables.gen3_charset, save_section_30);
|
||||
textPCFull.insert_text(data_tables.gen3_charset, save_section_30);
|
||||
textWeHere.insert_text(data_tables.gen3_charset, save_section_30);
|
||||
textPCConvo.insert_text(data_tables.gen3_charset, save_section_30);
|
||||
textPCThanks.insert_text(data_tables.gen3_charset, save_section_30);
|
||||
textLookerFull.insert_text(data_tables.gen3_charset, save_section_30);
|
||||
textMoveBox.insert_text(data_tables.gen3_charset, save_section_30);
|
||||
textReceived.insert_text(data_tables.gen3_charset, save_section_30);
|
||||
// Ş = Wait for button and scroll text
|
||||
// ȼ = Wait for button and clear text
|
||||
// Ȇ = Escape character
|
||||
// À = Change text color
|
||||
// Ç = Red
|
||||
// É = Green
|
||||
// Ë = Blue
|
||||
// Ʋ = Variable escape sequence
|
||||
// À = Player name
|
||||
// Ň = New line
|
||||
// ƞ = string terminator
|
||||
|
||||
// this decompresses the ZX0 compressed text table into the buffer inside of the decompressed_store union
|
||||
// thereby reusing the stack (=IWRAM) memory used earlier for the PokemonTables instance we used above
|
||||
decompressed_text_table.decompress(get_compressed_rsefrlg_table());
|
||||
switch (curr_rom.gamecode)
|
||||
{
|
||||
case RUBY_ID:
|
||||
textGreet.set_text(decompressed_text_table.get_text_entry(RSEFRLG_dia_textGreet_rse));
|
||||
textMoveBox.set_text(decompressed_text_table.get_text_entry(RSEFRLG_dia_textMoveBox_rs));
|
||||
textWeHere.set_text(decompressed_text_table.get_text_entry(RSEFRLG_dia_textWeHere_r));
|
||||
break;
|
||||
case SAPPHIRE_ID:
|
||||
textGreet.set_text(decompressed_text_table.get_text_entry(RSEFRLG_dia_textGreet_rse));
|
||||
textMoveBox.set_text(decompressed_text_table.get_text_entry(RSEFRLG_dia_textMoveBox_rs));
|
||||
textWeHere.set_text(decompressed_text_table.get_text_entry(RSEFRLG_dia_textWeHere_s));
|
||||
break;
|
||||
case FIRERED_ID:
|
||||
case LEAFGREEN_ID:
|
||||
textGreet.set_text(decompressed_text_table.get_text_entry(RSEFRLG_dia_textGreet_frlg));
|
||||
textMoveBox.set_text(decompressed_text_table.get_text_entry(RSEFRLG_dia_textMoveBox_frlg));
|
||||
textWeHere.set_text(decompressed_text_table.get_text_entry(RSEFRLG_dia_textWeHere_frlg));
|
||||
break;
|
||||
case EMERALD_ID:
|
||||
textGreet.set_text(decompressed_text_table.get_text_entry(RSEFRLG_dia_textGreet_rse));
|
||||
textMoveBox.set_text(decompressed_text_table.get_text_entry(RSEFRLG_dia_textMoveBox_e));
|
||||
textWeHere.set_text(decompressed_text_table.get_text_entry(RSEFRLG_dia_textWeHere_e));
|
||||
break;
|
||||
}
|
||||
textReceived.set_text(decompressed_text_table.get_text_entry(RSEFRLG_dia_textRecieved));
|
||||
textYouMustBe.set_text(decompressed_text_table.get_text_entry(first_time ? RSEFRLG_dia_textYouMustBe_first : RSEFRLG_dia_textYouMustBe_second));
|
||||
textIAm.set_text(decompressed_text_table.get_text_entry(first_time ? RSEFRLG_dia_textIAm_first : RSEFRLG_dia_textIAm_second));
|
||||
textPCConvo.set_text(decompressed_text_table.get_text_entry(RSEFRLG_dia_textPCConvo)); // ȼDon’t worry ƲÀ,Ňyou won’t have to do a thing!");
|
||||
textPCThanks.set_text(decompressed_text_table.get_text_entry(RSEFRLG_dia_textPCThanks));
|
||||
textThank.set_text(decompressed_text_table.get_text_entry(RSEFRLG_dia_textThank));
|
||||
textPCFull.set_text(decompressed_text_table.get_text_entry(RSEFRLG_dia_textPCFull));
|
||||
textLookerFull.set_text(decompressed_text_table.get_text_entry(RSEFRLG_dia_textLookerFull));
|
||||
|
||||
textThank.insert_text(decompressed_store.text.gen3_charset, save_section_30);
|
||||
textPCFull.insert_text(decompressed_store.text.gen3_charset, save_section_30);
|
||||
textWeHere.insert_text(decompressed_store.text.gen3_charset, save_section_30);
|
||||
textPCConvo.insert_text(decompressed_store.text.gen3_charset, save_section_30);
|
||||
textPCThanks.insert_text(decompressed_store.text.gen3_charset, save_section_30);
|
||||
textLookerFull.insert_text(decompressed_store.text.gen3_charset, save_section_30);
|
||||
textMoveBox.insert_text(decompressed_store.text.gen3_charset, save_section_30);
|
||||
textReceived.insert_text(decompressed_store.text.gen3_charset, save_section_30);
|
||||
|
||||
movementSlowSpin.insert_movement(save_section_30);
|
||||
movementFastSpin.insert_movement(save_section_30);
|
||||
|
|
@ -786,9 +839,10 @@ void mystery_gift_script::build_script(Pokemon_Party &incoming_box_data)
|
|||
add_word(flashBuffer_ptr.place_word());
|
||||
add_word(readFlashSector_ptr.place_word());
|
||||
|
||||
textGreet.insert_virtual_text(data_tables.gen3_charset, mg_script);
|
||||
textYouMustBe.insert_virtual_text(data_tables.gen3_charset, mg_script);
|
||||
textIAm.insert_virtual_text(data_tables.gen3_charset, mg_script);
|
||||
constexpr bool should_set_virtual_start = true;
|
||||
textGreet.insert_text(decompressed_store.text.gen3_charset, mg_script, should_set_virtual_start);
|
||||
textYouMustBe.insert_text(decompressed_store.text.gen3_charset, mg_script, should_set_virtual_start);
|
||||
textIAm.insert_text(decompressed_store.text.gen3_charset, mg_script, should_set_virtual_start);
|
||||
|
||||
for (unsigned int i = 0; i < mg_variable_list.size(); i++) // Fill all the refrences for script variables in the mg
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,10 +14,37 @@ static u8 em_wonder_card[0x14E] = {
|
|||
static u8 frlg_wonder_card[0x14E] = {
|
||||
0x67, 0x18, 0x00, 0x00, 0xBA, 0xB4, 0xBE, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xCA, 0xCC, 0xC9, 0xC0, 0xBF, 0xCD, 0xCD, 0xC9, 0xCC, 0x00, 0xC0, 0xBF, 0xC8, 0xC8, 0xBF, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xE6, 0xD5, 0xE2, 0xE7, 0xDA, 0xD9, 0xE6, 0x00, 0xBD, 0xD9, 0xE6, 0xE8, 0xDD, 0xDA, 0xDD, 0xD7, 0xD5, 0xE8, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xDD, 0xE7, 0xDD, 0xE8, 0x00, 0xE8, 0xDC, 0xD9, 0x00, 0xDC, 0xE3, 0xE9, 0xE7, 0xD9, 0x00, 0xE7, 0xE3, 0xE9, 0xE8, 0xDC, 0x00, 0xE3, 0xDA, 0x00, 0xE8, 0xDC, 0xD9, 0x00, 0xCA, 0xC9, 0xC5, 0x1B, 0xC7, 0xC9, 0xC8, 0x00, 0x00, 0x00, 0x00, 0xBD, 0xBF, 0xC8, 0xCE, 0xBF, 0xCC, 0x00, 0xE3, 0xE2, 0x00, 0xCD, 0xD9, 0xEA, 0xD9, 0xE2, 0x00, 0xC3, 0xE7, 0xE0, 0xD5, 0xE2, 0xD8, 0x00, 0xE8, 0xE3, 0x00, 0xE6, 0xD9, 0xD7, 0xDD, 0xD9, 0xEA, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0xE3, 0xE9, 0xE6, 0x00, 0xE8, 0xE6, 0xD5, 0xE2, 0xE7, 0xDA, 0xD9, 0xE6, 0xD9, 0xD8, 0x00, 0xCA, 0xC9, 0xC5, 0x1B, 0xC7, 0xC9, 0xC8, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xE3, 0x00, 0xE2, 0xE3, 0xE8, 0x00, 0xE8, 0xE3, 0xE7, 0xE7, 0x00, 0xE8, 0xDC, 0xDD, 0xE7, 0x00, 0xBF, 0xEC, 0xD7, 0xDC, 0xD5, 0xE2, 0xDB, 0xD9, 0x00, 0xBD, 0xD5, 0xE6, 0xD8, 0x00, 0xD6, 0xD9, 0xDA, 0xE3, 0xE6, 0xD9, 0x00, 0x00, 0x00, 0xE6, 0xD9, 0xD7, 0xD9, 0xDD, 0xEA, 0xDD, 0xE2, 0xDB, 0x00, 0xED, 0xE3, 0xE9, 0xE6, 0x00, 0xE8, 0xE6, 0xD5, 0xE2, 0xE7, 0xDA, 0xD9, 0xE6, 0xD9, 0xD8, 0x00, 0xCA, 0xC9, 0xC5, 0x1B, 0xC7, 0xC9, 0xC8, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // checksum
|
||||
|
||||
bool inject_mystery(Pokemon_Party &incoming_box_data)
|
||||
static void __attribute__((noinline)) handle_old_event(Pokemon_Party &incoming_box_data, int &curr_index, int *dex_nums)
|
||||
{
|
||||
PokemonTables data_tables;
|
||||
mystery_gift_script script(data_tables);
|
||||
for (int i = 0; i < MAX_PKMN_IN_BOX; i++) // Add in the Pokemon data
|
||||
{
|
||||
Pokemon curr_pkmn = incoming_box_data.get_converted_pkmn(data_tables, i);
|
||||
if (curr_pkmn.get_validity())
|
||||
{
|
||||
|
||||
for (int curr_byte = 0; curr_byte < POKEMON_SIZE; curr_byte++)
|
||||
{
|
||||
global_memory_buffer[curr_index] = curr_pkmn.get_gen_3_data(curr_byte);
|
||||
curr_index++;
|
||||
}
|
||||
dex_nums[i] = curr_pkmn.get_dex_number();
|
||||
}
|
||||
else
|
||||
{
|
||||
curr_index += POKEMON_SIZE;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < MAX_PKMN_IN_BOX; i++) // Add in the dex numbers
|
||||
{
|
||||
global_memory_buffer[curr_index] = dex_nums[i];
|
||||
curr_index++;
|
||||
}
|
||||
}
|
||||
|
||||
bool inject_mystery(Pokemon_Party &incoming_box_data)
|
||||
{
|
||||
mystery_gift_script script;
|
||||
if (ENABLE_OLD_EVENT)
|
||||
{
|
||||
// script.build_script_old(incoming_box_data);
|
||||
|
|
@ -80,31 +107,10 @@ bool inject_mystery(Pokemon_Party &incoming_box_data)
|
|||
copy_save_to_ram(0x1E000, &global_memory_buffer[0], 0x1000);
|
||||
int curr_index = 0;
|
||||
int dex_nums[MAX_PKMN_IN_BOX] = {};
|
||||
|
||||
if (ENABLE_OLD_EVENT)
|
||||
{
|
||||
for (int i = 0; i < MAX_PKMN_IN_BOX; i++) // Add in the Pokemon data
|
||||
{
|
||||
Pokemon curr_pkmn = incoming_box_data.get_converted_pkmn(data_tables, i);
|
||||
if (curr_pkmn.get_validity())
|
||||
{
|
||||
|
||||
for (int curr_byte = 0; curr_byte < POKEMON_SIZE; curr_byte++)
|
||||
{
|
||||
global_memory_buffer[curr_index] = curr_pkmn.get_gen_3_data(curr_byte);
|
||||
curr_index++;
|
||||
}
|
||||
dex_nums[i] = curr_pkmn.get_dex_number();
|
||||
}
|
||||
else
|
||||
{
|
||||
curr_index += POKEMON_SIZE;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < MAX_PKMN_IN_BOX; i++) // Add in the dex numbers
|
||||
{
|
||||
global_memory_buffer[curr_index] = dex_nums[i];
|
||||
curr_index++;
|
||||
}
|
||||
handle_old_event(incoming_box_data, curr_index, dex_nums);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#include <tonc.h>
|
||||
#include <string>
|
||||
#include <cmath>
|
||||
|
||||
#include "pokedex.h"
|
||||
|
|
@ -12,6 +11,7 @@
|
|||
#include "translated_text.h"
|
||||
#include "text_engine.h"
|
||||
#include "zx0_decompressor.h"
|
||||
#include "text_data_table.h"
|
||||
#include "TYPES_zx0_bin.h"
|
||||
|
||||
Dex dex_array[DEX_MAX];
|
||||
|
|
@ -30,6 +30,24 @@ bool mew_caught;
|
|||
bool celebi_caught;
|
||||
bool missingno_caught = false;
|
||||
|
||||
static void load_text_entry_into_buffer(text_data_table& data_table, u8 *output_buffer, u8 entry_index)
|
||||
{
|
||||
const u8 *entry = data_table.get_text_entry(entry_index);
|
||||
const u8 *entry_end = (const u8*)strchr((const char*)entry, 0xFF);
|
||||
|
||||
// copy the text_entry including the 0xFF at the end
|
||||
memcpy(output_buffer, entry, entry_end + 1 - entry);
|
||||
}
|
||||
|
||||
static void load_general_table_text_entries(u8 *decompression_buffer, u8 *kanto_buffer, u8 *johto_buffer)
|
||||
{
|
||||
text_data_table data_table(decompression_buffer);
|
||||
data_table.decompress(get_compressed_general_table());
|
||||
|
||||
load_text_entry_into_buffer(data_table, kanto_buffer, GENERAL_kanto_name);
|
||||
load_text_entry_into_buffer(data_table, johto_buffer, GENERAL_johto_name);
|
||||
}
|
||||
|
||||
void pokedex_init()
|
||||
{
|
||||
for (int i = 0; i < DEX_MAX; i++)
|
||||
|
|
@ -71,18 +89,33 @@ void pokedex_init()
|
|||
obj_hide(down_arrow);
|
||||
}
|
||||
|
||||
#include "gen_3_charsets_zx0_bin.h"
|
||||
#include "libstd_replacements.h"
|
||||
|
||||
int pokedex_loop()
|
||||
{
|
||||
u8 TYPES[POKEMON_ARRAY_SIZE * 2];
|
||||
u8 TYPES[POKEMON_ARRAY_SIZE][2];
|
||||
u8 kanto_name[12];
|
||||
u8 johto_name[12];
|
||||
u8 decompression_buffer[3072];
|
||||
u16 charset[256];
|
||||
|
||||
zx0_decompressor_start((uint8_t*)TYPES, TYPES_zx0_bin);
|
||||
zx0_decompressor_start((u8*)TYPES, TYPES_zx0_bin);
|
||||
zx0_decompressor_read(zx0_decompressor_get_decompressed_size());
|
||||
|
||||
zx0_decompressor_start((u8*)charset, gen_3_charsets_zx0_bin);
|
||||
zx0_decompressor_read(zx0_decompressor_get_decompressed_size());
|
||||
|
||||
load_general_table_text_entries(decompression_buffer, kanto_name, johto_name);
|
||||
|
||||
text_data_table PKMN_NAMES(decompression_buffer);
|
||||
PKMN_NAMES.decompress(get_compressed_pkmn_names_table());
|
||||
|
||||
pokedex_init();
|
||||
pokedex_show();
|
||||
bool update = true;
|
||||
|
||||
byte undiscovered_text[] = {0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xFF};
|
||||
const byte undiscovered_text[] = {0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xFF};
|
||||
byte temp_string[4] = {}; // Should never be longer than 4 characters (including endline)
|
||||
// TODO: For some reason there is screen tearing here. Probably not noticable on console,
|
||||
// but it should be removed at some point
|
||||
|
|
@ -199,13 +232,14 @@ int pokedex_loop()
|
|||
ptgb_write(temp_string, true);
|
||||
|
||||
tte_set_pos(dex_x_cord + (7 * 8), (i * 8 * 2) + 32);
|
||||
ptgb_write(is_caught(dex_shift + i + 1 + mythic_skip) ? PKMN_NAMES[dex_shift + i + 1 + mythic_skip] : undiscovered_text, true);
|
||||
ptgb_write(is_caught(dex_shift + i + 1 + mythic_skip) ? PKMN_NAMES.get_text_entry(dex_shift + i + 1 + mythic_skip) : undiscovered_text, true);
|
||||
|
||||
}
|
||||
global_next_frame(); // This is a bit silly, but it works. Makes the types one frame off from the text, but that's 'fine'
|
||||
// Eventually it could be optimized to move the labels around, but this honestly makes the most sense. Less code but one frame different
|
||||
for (int i = 0; i < DEX_MAX; i++)
|
||||
{
|
||||
load_type_sprites(TYPES, dex_shift + i + 1 + mythic_skip, i, is_caught(dex_shift + i + 1 + mythic_skip));
|
||||
load_type_sprites((const u8*)TYPES, dex_shift + i + 1 + mythic_skip, i, is_caught(dex_shift + i + 1 + mythic_skip));
|
||||
}
|
||||
update = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,132 +14,681 @@
|
|||
#include "translated_text.h"
|
||||
|
||||
int last_error;
|
||||
Pokemon_Party party_data = Pokemon_Party();
|
||||
Pokemon_Party party_data;
|
||||
|
||||
Select_Menu langs(false, LANG_MENU, 18, 0);
|
||||
Select_Menu games(false, CART_MENU, 18, 0);
|
||||
Box_Menu box_viewer;
|
||||
|
||||
script_obj transfer_script[SCRIPT_SIZE];
|
||||
script_obj event_script[SCRIPT_SIZE];
|
||||
// For documentation purposes, here's an overview of the categories of the transfer script:
|
||||
// -------- TRANSFER SCRIPT --------
|
||||
//
|
||||
// Check that the conditions are set for the transfer
|
||||
// T_SCRIPT_START
|
||||
// COND_TUTORIAL_COMPLETE
|
||||
// DIA_OPEN
|
||||
// CMD_SET_TUTOR_TRUE
|
||||
// COND_BEAT_E4
|
||||
// DIA_E4
|
||||
// COND_MG_ENABLED
|
||||
// COND_IS_FRLGE
|
||||
// DIA_MG_FRLGE
|
||||
// DIA_MG_RS
|
||||
// COND_MG_OTHER_EVENT
|
||||
// COND_PKMN_TO_COLLECT
|
||||
// DIA_MG_OTHER_EVENT
|
||||
// DIA_PKMN_TO_COLLECT
|
||||
//
|
||||
// Ask the user what game and language they're using
|
||||
// DIA_WHAT_GAME_TRANS
|
||||
// CMD_GAME_MENU
|
||||
// DIA_WHAT_LANG_TRANS
|
||||
// CMD_LANG_MENU
|
||||
// DIA_ASK_QUEST
|
||||
// CMD_SLIDE_PROF_LEFT
|
||||
// CMD_SLIDE_PROF_RIGHT
|
||||
// COND_GB_ROM_EXISTS
|
||||
// DIA_NO_GB_ROM
|
||||
// DIA_MENU_BACK
|
||||
//
|
||||
// Initiate the transfer and check for errors
|
||||
// DIA_LETS_START
|
||||
// DIA_START
|
||||
// CMD_START_LINK
|
||||
// COND_ERROR_TIMEOUT_ONE
|
||||
// DIA_ERROR_TIME_ONE
|
||||
// COND_ERROR_TIMEOUT_TWO
|
||||
// DIA_ERROR_TIME_TWO
|
||||
// COND_ERROR_COM_ENDED
|
||||
// DIA_ERROR_COM_ENDED
|
||||
// COND_ERROR_COLOSSEUM
|
||||
// DIA_ERROR_COLOSSEUM
|
||||
// COND_ERROR_DISCONNECT
|
||||
// DIA_ERROR_DISCONNECT
|
||||
//
|
||||
// Pause the transfer and show the user their box data
|
||||
// CMD_LOAD_SIMP
|
||||
// DIA_NO_VALID_PKMN
|
||||
// COND_SOME_INVALID_PKMN
|
||||
// DIA_SOME_INVALID_PKMN
|
||||
// COND_CHECK_MYTHIC
|
||||
// DIA_MYTHIC_CONVERT
|
||||
// CMD_MYTHIC_MENU
|
||||
// COND_CHECK_MISSINGNO
|
||||
// DIA_IS_MISSINGNO
|
||||
// DIA_IN_BOX
|
||||
// CMD_BOX_MENU
|
||||
// DIA_CANCEL
|
||||
// CMD_IMPORT_POKEMON
|
||||
// CMD_CONTINUE_LINK
|
||||
// CMD_CANCEL_LINK
|
||||
// CMD_END_MISSINGNO
|
||||
//
|
||||
// Complete the transfer and give messages based on the transfered Pokemon
|
||||
// DIA_TRANS_GOOD
|
||||
// COND_NEW_POKEMON
|
||||
// DIA_NEW_DEX
|
||||
// DIA_NO_NEW_DEX
|
||||
// COND_IS_HOENN_RS
|
||||
// COND_IS_HOENN_E
|
||||
// DIA_SEND_FRIEND_HOENN_RS
|
||||
// DIA_SEND_FRIEND_HOENN_E
|
||||
// DIA_SEND_FRIEND_KANTO
|
||||
// DIA_THANK
|
||||
//
|
||||
// Hide the dialogue and professor
|
||||
// CMD_END_SCRIPT
|
||||
// CMD_BACK_TO_MENU
|
||||
|
||||
void populate_script()
|
||||
{
|
||||
// -------- TRANSFER SCRIPT --------
|
||||
// Check that the conditions are set for the transfer
|
||||
transfer_script[T_SCRIPT_START] = script_obj(CMD_SHOW_PROF, COND_TUTORIAL_COMPLETE);
|
||||
transfer_script[COND_TUTORIAL_COMPLETE] = script_obj(COND_TUTORIAL_COMPLETE, COND_BEAT_E4, DIA_OPEN);
|
||||
transfer_script[DIA_OPEN] = script_obj(dialogue[DIA_OPEN], CMD_SET_TUTOR_TRUE);
|
||||
transfer_script[CMD_SET_TUTOR_TRUE] = script_obj(CMD_SET_TUTOR_TRUE, CMD_END_SCRIPT);
|
||||
transfer_script[COND_BEAT_E4] = script_obj(COND_BEAT_E4, COND_MG_ENABLED, DIA_E4);
|
||||
transfer_script[DIA_E4] = script_obj(dialogue[DIA_E4], CMD_END_SCRIPT);
|
||||
transfer_script[COND_MG_ENABLED] = script_obj(COND_MG_ENABLED, COND_MG_OTHER_EVENT, COND_IS_FRLGE);
|
||||
transfer_script[COND_IS_FRLGE] = script_obj(COND_IS_FRLGE, DIA_MG_FRLGE, DIA_MG_RS);
|
||||
transfer_script[DIA_MG_FRLGE] = script_obj(dialogue[DIA_MG_FRLGE], CMD_END_SCRIPT);
|
||||
transfer_script[DIA_MG_RS] = script_obj(dialogue[DIA_MG_RS], CMD_END_SCRIPT);
|
||||
transfer_script[COND_MG_OTHER_EVENT] = script_obj(COND_MG_OTHER_EVENT, DIA_MG_OTHER_EVENT, COND_PKMN_TO_COLLECT);
|
||||
transfer_script[COND_PKMN_TO_COLLECT] = script_obj(COND_PKMN_TO_COLLECT, DIA_PKMN_TO_COLLECT, DIA_ASK_QUEST);
|
||||
transfer_script[DIA_MG_OTHER_EVENT] = script_obj(dialogue[DIA_MG_OTHER_EVENT], DIA_ASK_QUEST);
|
||||
transfer_script[DIA_PKMN_TO_COLLECT] = script_obj(dialogue[DIA_PKMN_TO_COLLECT], CMD_END_SCRIPT);
|
||||
// The array below is exactly in order of the DIA, commands and condition int values
|
||||
// So if adding a new dia, command or condition, make sure to add it in the right position/index.
|
||||
// defining it this way does not generate an expensive function. It's all stored as read-only data in EWRAM.
|
||||
const script_obj_params transfer_script_params[SCRIPT_SIZE] = {
|
||||
// DIA_OPEN
|
||||
{
|
||||
.text_entry_index = DIA_OPEN,
|
||||
.next_if_true = CMD_SET_TUTOR_TRUE
|
||||
},
|
||||
// DIA_E4
|
||||
{
|
||||
.text_entry_index = DIA_E4,
|
||||
.next_if_true = CMD_END_SCRIPT
|
||||
},
|
||||
// DIA_MG_FRLGE
|
||||
{
|
||||
.text_entry_index = DIA_MG_FRLGE,
|
||||
.next_if_true = CMD_END_SCRIPT
|
||||
},
|
||||
// DIA_MG_RS
|
||||
{
|
||||
.text_entry_index = DIA_MG_RS,
|
||||
.next_if_true = CMD_END_SCRIPT
|
||||
},
|
||||
// DIA_LETS_START
|
||||
{
|
||||
.text_entry_index = DIA_LETS_START,
|
||||
.next_if_true = DIA_START
|
||||
},
|
||||
// DIA_START
|
||||
{
|
||||
.text_entry_index = DIA_START,
|
||||
.next_if_true = CMD_START_LINK
|
||||
},
|
||||
// DIA_TRANS_GOOD
|
||||
{
|
||||
.text_entry_index = DIA_TRANS_GOOD,
|
||||
.next_if_true = COND_NEW_POKEMON
|
||||
},
|
||||
// DIA_NEW_DEX
|
||||
{
|
||||
.text_entry_index = DIA_NEW_DEX,
|
||||
.next_if_true = COND_IS_HOENN_RS
|
||||
},
|
||||
// DIA_NO_NEW_DEX
|
||||
{
|
||||
.text_entry_index = DIA_NO_NEW_DEX,
|
||||
.next_if_true = COND_IS_HOENN_RS
|
||||
},
|
||||
// DIA_SEND_FRIEND_KANTO
|
||||
{
|
||||
.text_entry_index = DIA_SEND_FRIEND_KANTO,
|
||||
.next_if_true = DIA_THANK
|
||||
},
|
||||
// DIA_SEND_FRIEND_HOENN_RS
|
||||
{
|
||||
.text_entry_index = DIA_SEND_FRIEND_HOENN_RS,
|
||||
.next_if_true = DIA_THANK
|
||||
},
|
||||
// DIA_SEND_FRIEND_HOENN_E
|
||||
{
|
||||
.text_entry_index = DIA_SEND_FRIEND_HOENN_E,
|
||||
.next_if_true = DIA_THANK
|
||||
},
|
||||
// DIA_THANK
|
||||
{
|
||||
.text_entry_index = DIA_THANK,
|
||||
.next_if_true = CMD_END_SCRIPT
|
||||
},
|
||||
// DIA_GET_MON (unused)
|
||||
{
|
||||
.text_entry_index = DIA_GET_MON,
|
||||
.next_if_true = CMD_END_SCRIPT
|
||||
},
|
||||
// DIA_MG_OTHER_EVENT
|
||||
{
|
||||
.text_entry_index = DIA_MG_OTHER_EVENT,
|
||||
.next_if_true = DIA_ASK_QUEST
|
||||
},
|
||||
// DIA_PKMN_TO_COLLECT
|
||||
{
|
||||
.text_entry_index = DIA_PKMN_TO_COLLECT,
|
||||
.next_if_true = CMD_END_SCRIPT
|
||||
},
|
||||
// DIA_NO_VALID_PKMN
|
||||
{
|
||||
.text_entry_index = DIA_NO_VALID_PKMN,
|
||||
.next_if_true = CMD_CANCEL_LINK
|
||||
},
|
||||
// DIA_ASK_QUEST
|
||||
{
|
||||
.text_entry_index = DIA_ASK_QUEST,
|
||||
.next_if_true = CMD_SLIDE_PROF_LEFT
|
||||
},
|
||||
// DIA_WHAT_GAME_TRANS
|
||||
{
|
||||
.text_entry_index = DIA_WHAT_GAME_TRANS,
|
||||
.next_if_true = CMD_GAME_MENU
|
||||
},
|
||||
// DIA_WHAT_LANG_TRANS
|
||||
{
|
||||
.text_entry_index = DIA_WHAT_LANG_TRANS,
|
||||
.next_if_true = CMD_LANG_MENU
|
||||
},
|
||||
// DIA_NO_GB_ROM
|
||||
{
|
||||
.text_entry_index = DIA_NO_GB_ROM,
|
||||
.next_if_true = DIA_WHAT_LANG_TRANS
|
||||
},
|
||||
// DIA_IN_BOX
|
||||
{
|
||||
.text_entry_index = DIA_IN_BOX,
|
||||
.next_if_true = CMD_BOX_MENU
|
||||
},
|
||||
// DIA_MYTHIC_CONVERT
|
||||
{
|
||||
.text_entry_index = DIA_MYTHIC_CONVERT,
|
||||
.next_if_true = CMD_MYTHIC_MENU
|
||||
},
|
||||
// DIA_CANCEL
|
||||
{
|
||||
.text_entry_index = DIA_CANCEL,
|
||||
.next_if_true = CMD_CANCEL_LINK
|
||||
},
|
||||
// DIA_SOME_INVALID_PKMN
|
||||
{
|
||||
.text_entry_index = DIA_SOME_INVALID_PKMN,
|
||||
.next_if_true = COND_CHECK_MYTHIC
|
||||
},
|
||||
// DIA_MENU_BACK
|
||||
{
|
||||
.text_entry_index = DIA_MENU_BACK,
|
||||
.next_if_true = CMD_END_SCRIPT
|
||||
},
|
||||
// DIA_IS_MISSINGNO
|
||||
{
|
||||
.text_entry_index = DIA_IS_MISSINGNO,
|
||||
.next_if_true = DIA_IN_BOX
|
||||
},
|
||||
// DIA_ERROR_COLOSSEUM
|
||||
{
|
||||
.text_entry_index = DIA_ERROR_COLOSSEUM,
|
||||
.next_if_true = DIA_START
|
||||
},
|
||||
// DIA_ERROR_COM_ENDED
|
||||
{
|
||||
.text_entry_index = DIA_ERROR_COM_ENDED,
|
||||
.next_if_true = DIA_START
|
||||
},
|
||||
// DIA_ERROR_DISCONNECT
|
||||
{
|
||||
.text_entry_index = DIA_ERROR_DISCONNECT,
|
||||
.next_if_true = DIA_START
|
||||
},
|
||||
// DIA_ERROR_TIME_ONE
|
||||
{
|
||||
.text_entry_index = DIA_ERROR_TIME_ONE,
|
||||
.next_if_true = DIA_START
|
||||
},
|
||||
// DIA_ERROR_TIME_TWO
|
||||
{
|
||||
.text_entry_index = DIA_ERROR_TIME_TWO,
|
||||
.next_if_true = DIA_START
|
||||
},
|
||||
// DIA_WHAT_LANG_EVENT
|
||||
{
|
||||
.text_entry_index = DIA_WHAT_LANG_EVENT,
|
||||
.next_if_true = CMD_LANG_MENU
|
||||
},
|
||||
// DIA_WHAT_GAME_EVENT
|
||||
{
|
||||
.text_entry_index = DIA_WHAT_GAME_EVENT,
|
||||
.next_if_true = CMD_GAME_MENU
|
||||
},
|
||||
// DIA_K_DEX_NOT_FULL
|
||||
{
|
||||
.text_entry_index = DIA_K_DEX_NOT_FULL,
|
||||
.next_if_true = CMD_END_SCRIPT
|
||||
},
|
||||
// DIA_J_DEX_NOT_FULL
|
||||
{
|
||||
.text_entry_index = DIA_J_DEX_NOT_FULL,
|
||||
.next_if_true = CMD_END_SCRIPT
|
||||
},
|
||||
// T_SCRIPT_START
|
||||
{
|
||||
.conditional_index = CMD_SHOW_PROF,
|
||||
.next_if_true = COND_TUTORIAL_COMPLETE
|
||||
},
|
||||
// E_SCRIPT_START
|
||||
{
|
||||
.conditional_index = CMD_SHOW_PROF,
|
||||
.next_if_true = DIA_ASK_QUEST
|
||||
},
|
||||
// CMD_START_LINK
|
||||
{
|
||||
.conditional_index = CMD_START_LINK,
|
||||
.next_if_true = COND_ERROR_TIMEOUT_ONE
|
||||
},
|
||||
// CMD_IMPORT_POKEMON
|
||||
{
|
||||
.conditional_index = CMD_IMPORT_POKEMON,
|
||||
.next_if_true = CMD_CONTINUE_LINK
|
||||
},
|
||||
// CMD_BACK_TO_MENU
|
||||
{
|
||||
.conditional_index = CMD_BACK_TO_MENU,
|
||||
.next_if_true = T_SCRIPT_START
|
||||
},
|
||||
// CMD_SHOW_PROF (unused in this manner (not used in a next_if_true). Therefore this is a dummy entry)
|
||||
// we even need to define such unused values to keep the array element positions in order
|
||||
{
|
||||
},
|
||||
// CMD_HIDE_PROF (unused in this manner (not used in a next_if_true). Therefore this is a dummy entry)
|
||||
{
|
||||
},
|
||||
// CMD_SET_TUTOR_TRUE
|
||||
{
|
||||
.conditional_index = CMD_SET_TUTOR_TRUE,
|
||||
.next_if_true = CMD_END_SCRIPT
|
||||
},
|
||||
// CMD_END_SCRIPT
|
||||
{
|
||||
.conditional_index = CMD_END_SCRIPT,
|
||||
.next_if_true = CMD_BACK_TO_MENU
|
||||
},
|
||||
// CMD_GAME_MENU
|
||||
{
|
||||
.conditional_index = CMD_GAME_MENU,
|
||||
.next_if_true = COND_GB_ROM_EXISTS,
|
||||
.next_if_false = DIA_WHAT_LANG_TRANS
|
||||
},
|
||||
// CMD_LANG_MENU
|
||||
{
|
||||
.conditional_index = CMD_LANG_MENU,
|
||||
.next_if_true = DIA_WHAT_GAME_TRANS
|
||||
},
|
||||
// CMD_SLIDE_PROF_LEFT
|
||||
{
|
||||
.conditional_index = CMD_SLIDE_PROF_LEFT,
|
||||
.next_if_true = DIA_WHAT_LANG_TRANS
|
||||
},
|
||||
// CMD_SLIDE_PROF_RIGHT
|
||||
{
|
||||
.conditional_index = CMD_SLIDE_PROF_RIGHT,
|
||||
.next_if_true = DIA_LETS_START
|
||||
},
|
||||
// CMD_CONTINUE_LINK
|
||||
{
|
||||
.conditional_index = CMD_CONTINUE_LINK,
|
||||
.next_if_true = CMD_END_MISSINGNO
|
||||
},
|
||||
// CMD_BOX_MENU
|
||||
{
|
||||
.conditional_index = CMD_BOX_MENU,
|
||||
.next_if_true = CMD_IMPORT_POKEMON,
|
||||
.next_if_false = DIA_CANCEL
|
||||
},
|
||||
// CMD_MYTHIC_MENU
|
||||
{
|
||||
.conditional_index = CMD_MYTHIC_MENU,
|
||||
.next_if_true = COND_CHECK_MISSINGNO
|
||||
},
|
||||
// CMD_LOAD_SIMP
|
||||
{
|
||||
.conditional_index = CMD_LOAD_SIMP,
|
||||
.next_if_true = COND_SOME_INVALID_PKMN,
|
||||
.next_if_false = DIA_NO_VALID_PKMN
|
||||
},
|
||||
// CMD_CANCEL_LINK
|
||||
{
|
||||
.conditional_index = CMD_CANCEL_LINK,
|
||||
.next_if_true = CMD_END_SCRIPT
|
||||
},
|
||||
// CMD_END_MISSINGNO
|
||||
{
|
||||
.conditional_index = CMD_END_MISSINGNO,
|
||||
.next_if_true = DIA_TRANS_GOOD
|
||||
},
|
||||
// COND_ERROR_TIMEOUT_ONE
|
||||
{
|
||||
.conditional_index = COND_ERROR_TIMEOUT_ONE,
|
||||
.next_if_true = COND_ERROR_TIMEOUT_TWO,
|
||||
.next_if_false = DIA_ERROR_TIME_ONE
|
||||
},
|
||||
// COND_ERROR_DISCONNECT
|
||||
{
|
||||
.conditional_index = COND_ERROR_DISCONNECT,
|
||||
.next_if_true = CMD_LOAD_SIMP,
|
||||
.next_if_false = DIA_ERROR_DISCONNECT
|
||||
},
|
||||
// COND_ERROR_COM_ENDED
|
||||
{
|
||||
.conditional_index = COND_ERROR_COM_ENDED,
|
||||
.next_if_true = COND_ERROR_COLOSSEUM,
|
||||
.next_if_false = DIA_ERROR_COM_ENDED
|
||||
},
|
||||
// COND_ERROR_TIMEOUT_TWO
|
||||
{
|
||||
.conditional_index = COND_ERROR_TIMEOUT_TWO,
|
||||
.next_if_true = COND_ERROR_COM_ENDED,
|
||||
.next_if_false = DIA_ERROR_TIME_TWO
|
||||
},
|
||||
// COND_ERROR_COLOSSEUM
|
||||
{
|
||||
.conditional_index = COND_ERROR_COLOSSEUM,
|
||||
.next_if_true = COND_ERROR_DISCONNECT,
|
||||
.next_if_false = DIA_ERROR_COLOSSEUM
|
||||
},
|
||||
// COND_BEAT_E4
|
||||
{
|
||||
.conditional_index = COND_BEAT_E4,
|
||||
.next_if_true = COND_MG_ENABLED,
|
||||
.next_if_false = DIA_E4
|
||||
},
|
||||
// COND_MG_ENABLED
|
||||
{
|
||||
.conditional_index = COND_MG_ENABLED,
|
||||
.next_if_true = COND_MG_OTHER_EVENT,
|
||||
.next_if_false = COND_IS_FRLGE
|
||||
},
|
||||
// COND_TUTORIAL_COMPLETE
|
||||
{
|
||||
.conditional_index = COND_TUTORIAL_COMPLETE,
|
||||
.next_if_true = COND_BEAT_E4,
|
||||
.next_if_false = DIA_OPEN
|
||||
},
|
||||
// COND_NEW_POKEMON
|
||||
{
|
||||
.conditional_index = COND_NEW_POKEMON,
|
||||
.next_if_true = DIA_NEW_DEX,
|
||||
.next_if_false = DIA_NO_NEW_DEX
|
||||
},
|
||||
// COND_IS_HOENN_RS
|
||||
{
|
||||
.conditional_index = COND_IS_HOENN_RS,
|
||||
.next_if_true = DIA_SEND_FRIEND_HOENN_RS,
|
||||
.next_if_false = DIA_SEND_FRIEND_KANTO
|
||||
},
|
||||
// COND_IS_FRLGE
|
||||
{
|
||||
.conditional_index = COND_IS_FRLGE,
|
||||
.next_if_true = DIA_MG_FRLGE,
|
||||
.next_if_false = DIA_MG_RS
|
||||
},
|
||||
// COND_MG_OTHER_EVENT
|
||||
{
|
||||
.conditional_index = COND_MG_OTHER_EVENT,
|
||||
.next_if_true = DIA_MG_OTHER_EVENT,
|
||||
.next_if_false = COND_PKMN_TO_COLLECT
|
||||
},
|
||||
// COND_PKMN_TO_COLLECT
|
||||
{
|
||||
.conditional_index = COND_PKMN_TO_COLLECT,
|
||||
.next_if_true = DIA_PKMN_TO_COLLECT,
|
||||
.next_if_false = DIA_ASK_QUEST
|
||||
},
|
||||
// COND_GB_ROM_EXISTS
|
||||
{
|
||||
.conditional_index = COND_GB_ROM_EXISTS,
|
||||
.next_if_true = CMD_SLIDE_PROF_RIGHT,
|
||||
.next_if_false = DIA_NO_GB_ROM
|
||||
},
|
||||
// COND_CHECK_MYTHIC
|
||||
{
|
||||
.conditional_index = COND_CHECK_MYTHIC,
|
||||
.next_if_true = DIA_MYTHIC_CONVERT,
|
||||
.next_if_false = COND_CHECK_MISSINGNO
|
||||
},
|
||||
// COND_CHECK_DEX
|
||||
{
|
||||
.conditional_index = COND_CHECK_DEX,
|
||||
.next_if_true = 0,
|
||||
.next_if_false = COND_CHECK_KANTO
|
||||
},
|
||||
// COND_CHECK_KANTO
|
||||
{
|
||||
.conditional_index = COND_CHECK_KANTO,
|
||||
.next_if_true = DIA_K_DEX_NOT_FULL,
|
||||
.next_if_false = DIA_J_DEX_NOT_FULL
|
||||
},
|
||||
// COND_SOME_INVALID_PKMN
|
||||
{
|
||||
.conditional_index = COND_SOME_INVALID_PKMN,
|
||||
.next_if_true = DIA_SOME_INVALID_PKMN,
|
||||
.next_if_false = COND_CHECK_MYTHIC
|
||||
},
|
||||
// COND_IS_HOENN_E
|
||||
{
|
||||
.conditional_index = COND_IS_HOENN_E,
|
||||
.next_if_true = DIA_SEND_FRIEND_HOENN_E,
|
||||
.next_if_false = DIA_SEND_FRIEND_KANTO
|
||||
},
|
||||
// COND_CHECK_MISSINGNO
|
||||
{
|
||||
.conditional_index = COND_CHECK_MISSINGNO,
|
||||
.next_if_true = DIA_IS_MISSINGNO,
|
||||
.next_if_false = DIA_IN_BOX
|
||||
}
|
||||
};
|
||||
|
||||
// Ask the user what game and language they're using
|
||||
transfer_script[DIA_WHAT_GAME_TRANS] = script_obj(dialogue[DIA_WHAT_GAME_TRANS], CMD_GAME_MENU);
|
||||
transfer_script[CMD_GAME_MENU] = script_obj(CMD_GAME_MENU, COND_GB_ROM_EXISTS, DIA_WHAT_LANG_TRANS);
|
||||
transfer_script[DIA_WHAT_LANG_TRANS] = script_obj(dialogue[DIA_WHAT_LANG_TRANS], CMD_LANG_MENU);
|
||||
transfer_script[CMD_LANG_MENU] = script_obj(CMD_LANG_MENU, DIA_WHAT_GAME_TRANS, DIA_MENU_BACK);
|
||||
transfer_script[DIA_ASK_QUEST] = script_obj(dialogue[DIA_ASK_QUEST], CMD_SLIDE_PROF_LEFT);
|
||||
transfer_script[CMD_SLIDE_PROF_LEFT] = script_obj(CMD_SLIDE_PROF_LEFT, DIA_WHAT_LANG_TRANS);
|
||||
transfer_script[CMD_SLIDE_PROF_RIGHT] = script_obj(CMD_SLIDE_PROF_RIGHT, DIA_LETS_START);
|
||||
transfer_script[COND_GB_ROM_EXISTS] = script_obj(COND_GB_ROM_EXISTS, CMD_SLIDE_PROF_RIGHT, DIA_NO_GB_ROM);
|
||||
transfer_script[DIA_NO_GB_ROM] = script_obj(dialogue[DIA_NO_GB_ROM], DIA_WHAT_LANG_TRANS);
|
||||
transfer_script[DIA_MENU_BACK] = script_obj(dialogue[DIA_MENU_BACK], CMD_END_SCRIPT);
|
||||
// For documentation purposes, here's an overview of the categories of the events script:
|
||||
// -------- EVENTS SCRIPT --------
|
||||
// Start the dialogue and show the menu
|
||||
// E_SCRIPT_START
|
||||
// DIA_ASK_QUEST
|
||||
//
|
||||
// Ask the user what game and language they're using
|
||||
// DIA_WHAT_GAME_EVENT
|
||||
// CMD_GAME_MENU
|
||||
// DIA_WHAT_LANG_EVENT
|
||||
// CMD_LANG_MENU
|
||||
// DIA_ASK_QUEST
|
||||
// CMD_SLIDE_PROF_LEFT
|
||||
// CMD_SLIDE_PROF_RIGHT
|
||||
// COND_GB_ROM_EXISTS
|
||||
// DIA_NO_GB_ROM
|
||||
//
|
||||
// Check the player's dex
|
||||
// COND_CHECK_DEX
|
||||
// COND_CHECK_KANTO
|
||||
// DIA_K_DEX_NOT_FULL
|
||||
// DIA_J_DEX_NOT_FULL
|
||||
//
|
||||
// Hide the dialogue and professor
|
||||
// CMD_END_SCRIPT
|
||||
// CMD_BACK_TO_MENU
|
||||
|
||||
// Initiate the transfer and check for errors
|
||||
transfer_script[DIA_LETS_START] = script_obj(dialogue[DIA_LETS_START], DIA_START);
|
||||
transfer_script[DIA_START] = script_obj(dialogue[DIA_START], CMD_START_LINK);
|
||||
transfer_script[CMD_START_LINK] = script_obj(CMD_START_LINK, COND_ERROR_TIMEOUT_ONE);
|
||||
transfer_script[COND_ERROR_TIMEOUT_ONE] = script_obj(COND_ERROR_TIMEOUT_ONE, COND_ERROR_TIMEOUT_TWO, DIA_ERROR_TIME_ONE);
|
||||
transfer_script[DIA_ERROR_TIME_ONE] = script_obj(dialogue[DIA_ERROR_TIME_ONE], DIA_START);
|
||||
transfer_script[COND_ERROR_TIMEOUT_TWO] = script_obj(COND_ERROR_TIMEOUT_TWO, COND_ERROR_COM_ENDED, DIA_ERROR_TIME_TWO);
|
||||
transfer_script[DIA_ERROR_TIME_TWO] = script_obj(dialogue[DIA_ERROR_TIME_TWO], DIA_START);
|
||||
transfer_script[COND_ERROR_COM_ENDED] = script_obj(COND_ERROR_COM_ENDED, COND_ERROR_COLOSSEUM, DIA_ERROR_COM_ENDED);
|
||||
transfer_script[DIA_ERROR_COM_ENDED] = script_obj(dialogue[DIA_ERROR_COM_ENDED], DIA_START);
|
||||
transfer_script[COND_ERROR_COLOSSEUM] = script_obj(COND_ERROR_COLOSSEUM, COND_ERROR_DISCONNECT, DIA_ERROR_COLOSSEUM);
|
||||
transfer_script[DIA_ERROR_COLOSSEUM] = script_obj(dialogue[DIA_ERROR_COLOSSEUM], DIA_START);
|
||||
transfer_script[COND_ERROR_DISCONNECT] = script_obj(COND_ERROR_DISCONNECT, CMD_LOAD_SIMP, DIA_ERROR_DISCONNECT);
|
||||
transfer_script[DIA_ERROR_DISCONNECT] = script_obj(dialogue[DIA_ERROR_DISCONNECT], DIA_START);
|
||||
|
||||
// Pause the transfer and show the user their box data
|
||||
transfer_script[CMD_LOAD_SIMP] = script_obj(CMD_LOAD_SIMP, COND_SOME_INVALID_PKMN, DIA_NO_VALID_PKMN);
|
||||
transfer_script[DIA_NO_VALID_PKMN] = script_obj(dialogue[DIA_NO_VALID_PKMN], CMD_CANCEL_LINK);
|
||||
transfer_script[COND_SOME_INVALID_PKMN] = script_obj(COND_SOME_INVALID_PKMN, DIA_SOME_INVALID_PKMN, COND_CHECK_MYTHIC);
|
||||
transfer_script[DIA_SOME_INVALID_PKMN] = script_obj(dialogue[DIA_SOME_INVALID_PKMN], COND_CHECK_MYTHIC);
|
||||
transfer_script[COND_CHECK_MYTHIC] = script_obj(COND_CHECK_MYTHIC, DIA_MYTHIC_CONVERT, COND_CHECK_MISSINGNO);
|
||||
transfer_script[DIA_MYTHIC_CONVERT] = script_obj(dialogue[DIA_MYTHIC_CONVERT], CMD_MYTHIC_MENU);
|
||||
transfer_script[CMD_MYTHIC_MENU] = script_obj(CMD_MYTHIC_MENU, COND_CHECK_MISSINGNO);
|
||||
transfer_script[COND_CHECK_MISSINGNO] = script_obj(COND_CHECK_MISSINGNO, DIA_IS_MISSINGNO, DIA_IN_BOX);
|
||||
transfer_script[DIA_IS_MISSINGNO] = script_obj(dialogue[DIA_IS_MISSINGNO], DIA_IN_BOX);
|
||||
transfer_script[DIA_IN_BOX] = script_obj(dialogue[DIA_IN_BOX], CMD_BOX_MENU);
|
||||
transfer_script[CMD_BOX_MENU] = script_obj(CMD_BOX_MENU, CMD_IMPORT_POKEMON, DIA_CANCEL);
|
||||
transfer_script[DIA_CANCEL] = script_obj(dialogue[DIA_CANCEL], CMD_CANCEL_LINK);
|
||||
transfer_script[CMD_IMPORT_POKEMON] = script_obj(CMD_IMPORT_POKEMON, CMD_CONTINUE_LINK);
|
||||
transfer_script[CMD_CONTINUE_LINK] = script_obj(CMD_CONTINUE_LINK, CMD_END_MISSINGNO);
|
||||
transfer_script[CMD_CANCEL_LINK] = script_obj(CMD_CANCEL_LINK, CMD_END_SCRIPT);
|
||||
transfer_script[CMD_END_MISSINGNO] = script_obj(CMD_END_MISSINGNO, DIA_TRANS_GOOD);
|
||||
|
||||
// Complete the transfer and give messages based on the transfered Pokemon
|
||||
transfer_script[DIA_TRANS_GOOD] = script_obj(dialogue[DIA_TRANS_GOOD], COND_NEW_POKEMON);
|
||||
transfer_script[COND_NEW_POKEMON] = script_obj(COND_NEW_POKEMON, DIA_NEW_DEX, DIA_NO_NEW_DEX);
|
||||
transfer_script[DIA_NEW_DEX] = script_obj(dialogue[DIA_NEW_DEX], COND_IS_HOENN_RS);
|
||||
transfer_script[DIA_NO_NEW_DEX] = script_obj(dialogue[DIA_NO_NEW_DEX], COND_IS_HOENN_RS);
|
||||
transfer_script[COND_IS_HOENN_RS] = script_obj(COND_IS_HOENN_RS, DIA_SEND_FRIEND_HOENN_RS, COND_IS_HOENN_E);
|
||||
transfer_script[COND_IS_HOENN_E] = script_obj(COND_IS_HOENN_E, DIA_SEND_FRIEND_HOENN_E, DIA_SEND_FRIEND_KANTO);
|
||||
transfer_script[DIA_SEND_FRIEND_HOENN_RS] = script_obj(dialogue[DIA_SEND_FRIEND_HOENN_RS], DIA_THANK);
|
||||
transfer_script[DIA_SEND_FRIEND_HOENN_E] = script_obj(dialogue[DIA_SEND_FRIEND_HOENN_E], DIA_THANK);
|
||||
transfer_script[DIA_SEND_FRIEND_KANTO] = script_obj(dialogue[DIA_SEND_FRIEND_KANTO], DIA_THANK);
|
||||
transfer_script[DIA_THANK] = script_obj(dialogue[DIA_THANK], CMD_END_SCRIPT);
|
||||
|
||||
// Hide the dialouge and professor
|
||||
transfer_script[CMD_END_SCRIPT] = script_obj(CMD_END_SCRIPT, CMD_BACK_TO_MENU);
|
||||
transfer_script[CMD_BACK_TO_MENU] = script_obj(CMD_BACK_TO_MENU, T_SCRIPT_START);
|
||||
|
||||
// -------- EVENTS SCRIPT --------
|
||||
// Start the dialogue and show the menu
|
||||
event_script[E_SCRIPT_START] = script_obj(CMD_SHOW_PROF, DIA_ASK_QUEST);
|
||||
event_script[DIA_ASK_QUEST] = script_obj(dialogue[DIA_ASK_QUEST], CMD_SLIDE_PROF_LEFT);
|
||||
|
||||
// Ask the user what game and language they're using
|
||||
event_script[DIA_WHAT_GAME_EVENT] = script_obj(dialogue[DIA_WHAT_GAME_EVENT], CMD_GAME_MENU);
|
||||
event_script[CMD_GAME_MENU] = script_obj(CMD_GAME_MENU, COND_GB_ROM_EXISTS, DIA_WHAT_LANG_EVENT);
|
||||
event_script[DIA_WHAT_LANG_EVENT] = script_obj(dialogue[DIA_WHAT_LANG_EVENT], CMD_LANG_MENU);
|
||||
event_script[CMD_LANG_MENU] = script_obj(CMD_LANG_MENU, DIA_WHAT_GAME_EVENT);
|
||||
event_script[DIA_ASK_QUEST] = script_obj(dialogue[DIA_ASK_QUEST], CMD_SLIDE_PROF_LEFT);
|
||||
event_script[CMD_SLIDE_PROF_LEFT] = script_obj(CMD_SLIDE_PROF_LEFT, DIA_WHAT_LANG_EVENT);
|
||||
event_script[CMD_SLIDE_PROF_RIGHT] = script_obj(CMD_SLIDE_PROF_RIGHT, COND_CHECK_DEX);
|
||||
event_script[COND_GB_ROM_EXISTS] = script_obj(COND_GB_ROM_EXISTS, CMD_SLIDE_PROF_RIGHT, DIA_NO_GB_ROM);
|
||||
event_script[DIA_NO_GB_ROM] = script_obj(dialogue[DIA_NO_GB_ROM], DIA_WHAT_LANG_EVENT);
|
||||
|
||||
// Check the player's dex
|
||||
event_script[COND_CHECK_DEX] = script_obj(COND_CHECK_DEX, 0, COND_CHECK_KANTO);
|
||||
event_script[COND_CHECK_KANTO] = script_obj(COND_CHECK_KANTO, DIA_K_DEX_NOT_FULL, DIA_J_DEX_NOT_FULL);
|
||||
event_script[DIA_K_DEX_NOT_FULL] = script_obj(dialogue[DIA_K_DEX_NOT_FULL], CMD_END_SCRIPT);
|
||||
event_script[DIA_J_DEX_NOT_FULL] = script_obj(dialogue[DIA_J_DEX_NOT_FULL], CMD_END_SCRIPT);
|
||||
|
||||
// Hide the dialouge and professor
|
||||
event_script[CMD_END_SCRIPT] = script_obj(CMD_END_SCRIPT, CMD_BACK_TO_MENU);
|
||||
event_script[CMD_BACK_TO_MENU] = script_obj(CMD_BACK_TO_MENU, T_SCRIPT_START);
|
||||
// The array below is exactly in order of the DIA, commands and condition int values
|
||||
// So if adding a new dia, command or condition, make sure to add it in the right position/index.
|
||||
// because things are in order, it also means we have to define every possible entry even if we don't use it.
|
||||
// defining it this way does not generate an expensive function. It's all stored as read-only data in EWRAM.
|
||||
// Although frankly given the small amount of defined entries, we ARE wasting a lot of space with this one. (probably around 500 bytes)
|
||||
const script_obj_params event_script_params[SCRIPT_SIZE] = {
|
||||
{}, // DIA_OPEN
|
||||
{}, // DIA_E4
|
||||
{}, // DIA_MG_FRLGE
|
||||
{}, // DIA_MG_RS
|
||||
{}, // DIA_LETS_START
|
||||
{}, // DIA_START
|
||||
{}, // DIA_TRANS_GOOD
|
||||
{}, // DIA_NEW_DEX
|
||||
{}, // DIA_NO_NEW_DEX
|
||||
{}, // DIA_SEND_FRIEND_KANTO
|
||||
{}, // DIA_SEND_FRIEND_HOENN_RS
|
||||
{}, // DIA_SEND_FRIEND_HOENN_E
|
||||
{}, // DIA_THANK
|
||||
{}, // DIA_GET_MON
|
||||
{}, // DIA_MG_OTHER_EVENT
|
||||
{}, // DIA_PKMN_TO_COLLECT
|
||||
{}, // DIA_NO_VALID_PKMN
|
||||
// DIA_ASK_QUEST
|
||||
{
|
||||
.text_entry_index = DIA_ASK_QUEST,
|
||||
.next_if_true = CMD_SLIDE_PROF_LEFT
|
||||
},
|
||||
{}, // DIA_WHAT_GAME_TRANS
|
||||
{}, // DIA_WHAT_LANG_TRANS
|
||||
// DIA_NO_GB_ROM
|
||||
{
|
||||
.text_entry_index = DIA_NO_GB_ROM,
|
||||
.next_if_true = DIA_WHAT_LANG_EVENT
|
||||
},
|
||||
{}, // DIA_IN_BOX
|
||||
{}, // DIA_MYTHIC_CONVERT
|
||||
{}, // DIA_CANCEL
|
||||
{}, // DIA_SOME_INVALID_PKMN
|
||||
{}, // DIA_MENU_BACK
|
||||
{}, // DIA_IS_MISSINGNO
|
||||
{}, // DIA_ERROR_COLOSSEUM
|
||||
{}, // DIA_ERROR_COM_ENDED
|
||||
{}, // DIA_ERROR_DISCONNECT
|
||||
{}, // DIA_ERROR_TIME_ONE
|
||||
{}, // DIA_ERROR_TIME_TWO
|
||||
// DIA_WHAT_LANG_EVENT
|
||||
{
|
||||
.text_entry_index = DIA_WHAT_LANG_EVENT,
|
||||
.next_if_true = CMD_LANG_MENU
|
||||
},
|
||||
// DIA_WHAT_GAME_EVENT
|
||||
{
|
||||
.text_entry_index = DIA_WHAT_GAME_EVENT,
|
||||
.next_if_true = CMD_GAME_MENU
|
||||
},
|
||||
// DIA_K_DEX_NOT_FULL
|
||||
{
|
||||
.text_entry_index = DIA_K_DEX_NOT_FULL,
|
||||
.next_if_true = CMD_END_SCRIPT
|
||||
},
|
||||
// DIA_J_DEX_NOT_FULL
|
||||
{
|
||||
.text_entry_index = DIA_J_DEX_NOT_FULL,
|
||||
.next_if_true = CMD_END_SCRIPT
|
||||
},
|
||||
{}, // T_SCRIPT_START
|
||||
// E_SCRIPT_START
|
||||
{
|
||||
.conditional_index = CMD_SHOW_PROF,
|
||||
.next_if_true = DIA_ASK_QUEST
|
||||
},
|
||||
{}, // CMD_START_LINK
|
||||
{}, // CMD_IMPORT_POKEMON
|
||||
// CMD_BACK_TO_MENU
|
||||
{
|
||||
.conditional_index = CMD_BACK_TO_MENU,
|
||||
.next_if_true = T_SCRIPT_START
|
||||
},
|
||||
{}, // CMD_SHOW_PROF
|
||||
{}, // CMD_HIDE_PROF
|
||||
{}, // CMD_SET_TUTOR_TRUE
|
||||
// CMD_END_SCRIPT
|
||||
{
|
||||
.conditional_index = CMD_END_SCRIPT,
|
||||
.next_if_true = CMD_BACK_TO_MENU
|
||||
},
|
||||
// CMD_GAME_MENU
|
||||
{
|
||||
.conditional_index = CMD_GAME_MENU,
|
||||
.next_if_true = COND_GB_ROM_EXISTS,
|
||||
.next_if_false = DIA_WHAT_LANG_EVENT
|
||||
},
|
||||
// CMD_LANG_MENU
|
||||
{
|
||||
.conditional_index = CMD_LANG_MENU,
|
||||
.next_if_true = DIA_WHAT_GAME_EVENT
|
||||
},
|
||||
// CMD_SLIDE_PROF_LEFT
|
||||
{
|
||||
.conditional_index = CMD_SLIDE_PROF_LEFT,
|
||||
.next_if_true = DIA_WHAT_LANG_EVENT
|
||||
},
|
||||
// CMD_SLIDE_PROF_RIGHT
|
||||
{
|
||||
.conditional_index = CMD_SLIDE_PROF_RIGHT,
|
||||
.next_if_true = COND_CHECK_DEX
|
||||
},
|
||||
{}, // CMD_CONTINUE_LINK
|
||||
{}, // CMD_BOX_MENU
|
||||
{}, // CMD_MYTHIC_MENU
|
||||
{}, // CMD_LOAD_SIMP
|
||||
{}, // CMD_CANCEL_LINK
|
||||
{}, // CMD_END_MISSINGNO
|
||||
{}, // COND_ERROR_TIMEOUT_ONE
|
||||
{}, // COND_ERROR_DISCONNECT
|
||||
{}, // COND_ERROR_COM_ENDED
|
||||
{}, // COND_ERROR_TIMEOUT_TWO
|
||||
{}, // COND_ERROR_COLOSSEUM
|
||||
{}, // COND_BEAT_E4
|
||||
{}, // COND_MG_ENABLED
|
||||
{}, // COND_TUTORIAL_COMPLETE
|
||||
{}, // COND_NEW_POKEMON
|
||||
{}, // COND_IS_HOENN_RS
|
||||
{}, // COND_IS_FRLGE
|
||||
{}, // COND_MG_OTHER_EVENT
|
||||
{}, // COND_PKMN_TO_COLLECT
|
||||
// COND_GB_ROM_EXISTS
|
||||
{
|
||||
.conditional_index = COND_GB_ROM_EXISTS,
|
||||
.next_if_true = CMD_SLIDE_PROF_RIGHT,
|
||||
.next_if_false = DIA_NO_GB_ROM
|
||||
},
|
||||
{}, // COND_CHECK_MYTHIC
|
||||
// COND_CHECK_DEX
|
||||
{
|
||||
.conditional_index = COND_CHECK_DEX,
|
||||
.next_if_true = 0,
|
||||
.next_if_false = COND_CHECK_KANTO
|
||||
},
|
||||
// COND_CHECK_KANTO
|
||||
{
|
||||
.conditional_index = COND_CHECK_KANTO,
|
||||
.next_if_true = DIA_K_DEX_NOT_FULL,
|
||||
.next_if_false = DIA_J_DEX_NOT_FULL
|
||||
},
|
||||
{}, // COND_SOME_INVALID_PKMN
|
||||
{}, // COND_IS_HOENN_E
|
||||
{}, // COND_CHECK_MISSINGNO
|
||||
};
|
||||
|
||||
void populate_lang_menu()
|
||||
{
|
||||
langs.add_option(option_english, ENG_ID);
|
||||
langs.add_option(option_japanese, JPN_ID);
|
||||
langs.add_option(option_spanish, SPA_ID);
|
||||
langs.add_option(option_french, FRE_ID);
|
||||
langs.add_option(option_german, GER_ID);
|
||||
langs.add_option(option_italian, ITA_ID);
|
||||
langs.add_option(option_korean, KOR_ID);
|
||||
langs.add_option(option_cancel, UINT8_MAX);
|
||||
langs.add_option(GENERAL_option_english, ENG_ID);
|
||||
langs.add_option(GENERAL_option_japanese, JPN_ID);
|
||||
langs.add_option(GENERAL_option_spanish, SPA_ID);
|
||||
langs.add_option(GENERAL_option_french, FRE_ID);
|
||||
langs.add_option(GENERAL_option_german, GER_ID);
|
||||
langs.add_option(GENERAL_option_italian, ITA_ID);
|
||||
langs.add_option(GENERAL_option_korean, KOR_ID);
|
||||
langs.add_option(GENERAL_option_cancel, UINT8_MAX);
|
||||
}
|
||||
|
||||
void populate_game_menu(int lang)
|
||||
|
|
@ -147,34 +696,40 @@ void populate_game_menu(int lang)
|
|||
switch (lang)
|
||||
{
|
||||
case (JPN_ID):
|
||||
games.add_option(option_red, RED_ID);
|
||||
games.add_option(option_green, GREEN_ID);
|
||||
games.add_option(option_blue, BLUE_ID);
|
||||
games.add_option(option_yellow, YELLOW_ID);
|
||||
games.add_option(option_gold, GOLD_ID);
|
||||
games.add_option(option_silver, SILVER_ID);
|
||||
games.add_option(option_crystal, CRYSTAL_ID);
|
||||
games.add_option(option_cancel, UINT8_MAX);
|
||||
games.add_option(GENERAL_option_red, RED_ID);
|
||||
games.add_option(GENERAL_option_green, GREEN_ID);
|
||||
games.add_option(GENERAL_option_blue, BLUE_ID);
|
||||
games.add_option(GENERAL_option_yellow, YELLOW_ID);
|
||||
games.add_option(GENERAL_option_gold, GOLD_ID);
|
||||
games.add_option(GENERAL_option_silver, SILVER_ID);
|
||||
games.add_option(GENERAL_option_crystal, CRYSTAL_ID);
|
||||
games.add_option(GENERAL_option_cancel, UINT8_MAX);
|
||||
break;
|
||||
|
||||
case (KOR_ID):
|
||||
games.add_option(option_gold, GOLD_ID);
|
||||
games.add_option(option_silver, SILVER_ID);
|
||||
games.add_option(option_cancel, UINT8_MAX);
|
||||
games.add_option(GENERAL_option_gold, GOLD_ID);
|
||||
games.add_option(GENERAL_option_silver, SILVER_ID);
|
||||
games.add_option(GENERAL_option_cancel, UINT8_MAX);
|
||||
break;
|
||||
|
||||
default:
|
||||
games.add_option(option_red, RED_ID);
|
||||
games.add_option(option_blue, BLUE_ID);
|
||||
games.add_option(option_yellow, YELLOW_ID);
|
||||
games.add_option(option_gold, GOLD_ID);
|
||||
games.add_option(option_silver, SILVER_ID);
|
||||
games.add_option(option_crystal, CRYSTAL_ID);
|
||||
games.add_option(option_cancel, UINT8_MAX);
|
||||
games.add_option(GENERAL_option_red, RED_ID);
|
||||
games.add_option(GENERAL_option_blue, BLUE_ID);
|
||||
games.add_option(GENERAL_option_yellow, YELLOW_ID);
|
||||
games.add_option(GENERAL_option_gold, GOLD_ID);
|
||||
games.add_option(GENERAL_option_silver, SILVER_ID);
|
||||
games.add_option(GENERAL_option_crystal, CRYSTAL_ID);
|
||||
games.add_option(GENERAL_option_cancel, UINT8_MAX);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool load_simple_party_data()
|
||||
{
|
||||
PokemonTables data_tables;
|
||||
return party_data.fill_simple_pkmn_array(data_tables);
|
||||
}
|
||||
|
||||
bool run_conditional(int index)
|
||||
{
|
||||
// Here is most of the logic that drives what lines show up where. It's probably not the best way to code it, but it works
|
||||
|
|
@ -348,10 +903,7 @@ bool run_conditional(int index)
|
|||
return true;
|
||||
|
||||
case CMD_LOAD_SIMP:
|
||||
{
|
||||
PokemonTables data_tables;
|
||||
return party_data.fill_simple_pkmn_array(data_tables);
|
||||
}
|
||||
return load_simple_party_data();
|
||||
case CMD_CANCEL_LINK:
|
||||
party_data.continue_link(true);
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1,53 +1,40 @@
|
|||
#include <tonc.h>
|
||||
#include <string>
|
||||
#include "script_obj.h"
|
||||
#include "pokemon.h"
|
||||
#include "pokemon_party.h"
|
||||
#include "script_array.h"
|
||||
#include "translated_text.h"
|
||||
|
||||
script_obj::script_obj(){};
|
||||
|
||||
script_obj::script_obj(const byte* nText, uint16_t nNext)
|
||||
script_obj::script_obj()
|
||||
: params_({0})
|
||||
{
|
||||
};
|
||||
|
||||
script_obj::script_obj(const script_obj_params ¶ms)
|
||||
: params_(params)
|
||||
{
|
||||
text = nText;
|
||||
next_index = nNext;
|
||||
conditional_index = 0;
|
||||
next_false_index = 0;
|
||||
}
|
||||
|
||||
script_obj::script_obj(uint16_t nRun, uint16_t nNext)
|
||||
bool script_obj::has_text() const
|
||||
{
|
||||
text = nullptr;
|
||||
next_index = nNext;
|
||||
conditional_index = nRun;
|
||||
next_false_index = nNext;
|
||||
// So the thing is: when conditional_index is set, its value will always be higher than 0
|
||||
// because the way these integer defines have been set up.
|
||||
// So that means that if conditional_index IS 0, then we must have a text entry index defined instead!
|
||||
// We can't base this check on the text_entry_index itself since unfortunately its value being zero can be legit.
|
||||
return (params_.conditional_index == 0);
|
||||
}
|
||||
|
||||
script_obj::script_obj(uint16_t nRun, uint16_t nNext_if_true, uint16_t nNext_if_false)
|
||||
u8 script_obj::get_text_entry_index() const
|
||||
{
|
||||
text = nullptr;
|
||||
next_index = nNext_if_true;
|
||||
conditional_index = nRun;
|
||||
next_false_index = nNext_if_false;
|
||||
return params_.text_entry_index;
|
||||
}
|
||||
|
||||
const byte* script_obj::get_text()
|
||||
u16 script_obj::get_true_index() const
|
||||
{
|
||||
return text;
|
||||
return params_.next_if_true;
|
||||
}
|
||||
|
||||
uint16_t script_obj::get_true_index()
|
||||
u16 script_obj::get_false_index() const
|
||||
{
|
||||
return next_index;
|
||||
return params_.next_if_false;
|
||||
}
|
||||
|
||||
uint16_t script_obj::get_false_index()
|
||||
u16 script_obj::get_cond_id() const
|
||||
{
|
||||
return next_false_index;
|
||||
}
|
||||
|
||||
uint16_t script_obj::get_cond_id()
|
||||
{
|
||||
return conditional_index;
|
||||
return params_.conditional_index;
|
||||
}
|
||||
|
|
@ -153,28 +153,17 @@ void textbox_var::set_virtual_start()
|
|||
start_location_in_script = *curr_loc_ptr - 4;
|
||||
}
|
||||
|
||||
void textbox_var::insert_text(const u16 *charset, u8 mg_array[])
|
||||
void textbox_var::insert_text(const u16 *charset, u8 mg_array[], bool should_set_virtual_start)
|
||||
{
|
||||
set_start();
|
||||
for (int parser = 0; parser < text_length; parser++)
|
||||
if(!should_set_virtual_start)
|
||||
{
|
||||
if (curr_rom.is_hoenn() && (text[parser] == 0xFC) && (get_char_from_charset(charset, (char16_t)(text[parser + 1])) == 0x01)) // Removes colored text
|
||||
{
|
||||
parser += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
mg_array[*curr_loc_ptr] = text[parser];
|
||||
(*curr_loc_ptr)++;
|
||||
}
|
||||
set_start();
|
||||
}
|
||||
else
|
||||
{
|
||||
set_virtual_start();
|
||||
}
|
||||
mg_array[*curr_loc_ptr] = 0xFF; // End string
|
||||
(*curr_loc_ptr)++;
|
||||
}
|
||||
|
||||
void textbox_var::insert_virtual_text(const u16 *charset, u8 mg_array[])
|
||||
{
|
||||
set_virtual_start();
|
||||
for (int parser = 0; parser < text_length; parser++)
|
||||
{
|
||||
if (curr_rom.is_hoenn() && (text[parser] == 0xFC) && (get_char_from_charset(charset, (char16_t)(text[parser + 1])) == 0x01)) // Removes colored text
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "select_menu.h"
|
||||
#include "sprite_data.h"
|
||||
#include "translated_text.h"
|
||||
#include "text_data_table.h"
|
||||
|
||||
#define TEXT_HEIGHT 10
|
||||
#define TEXT_WIDTH 8
|
||||
|
|
@ -14,7 +16,7 @@ Select_Menu::Select_Menu(bool enable_cancel, u8 nMenu_type, int nStartTileX, int
|
|||
startTileY = nStartTileY;
|
||||
}
|
||||
|
||||
void Select_Menu::add_option(const byte *option, u8 return_value)
|
||||
void Select_Menu::add_option(const u8 option, u8 return_value)
|
||||
{
|
||||
menu_options.push_back(option);
|
||||
return_values.push_back(return_value);
|
||||
|
|
@ -101,11 +103,15 @@ int Select_Menu::select_menu_main()
|
|||
|
||||
void Select_Menu::show_menu()
|
||||
{
|
||||
u8 decompression_buffer[2048];
|
||||
text_data_table text_data(decompression_buffer);
|
||||
text_data.decompress(get_compressed_general_table());
|
||||
|
||||
add_menu_box(menu_options.size(), startTileX, startTileY);
|
||||
for (unsigned int i = 0; i < menu_options.size(); i++)
|
||||
{
|
||||
tte_set_pos((startTileX + 2) * TEXT_WIDTH, (startTileY + 1) * TILE_HEIGHT + (i * TEXT_HEIGHT));
|
||||
ptgb_write(menu_options[i], true);
|
||||
ptgb_write(text_data.get_text_entry(menu_options[i]), true);
|
||||
}
|
||||
obj_unhide(point_arrow, 0);
|
||||
// obj_set_pos(point_arrow, startTileX + (2 * TEXT_WIDTH), (1 + i) * TEXT_HEIGHT);
|
||||
|
|
|
|||
154
source/text_data_table.cpp
Normal file
154
source/text_data_table.cpp
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
#include "text_data_table.h"
|
||||
#include "zx0_decompressor.h"
|
||||
#include <cstring>
|
||||
|
||||
static uint16_t get_entry_offset_by_index(const uint8_t *text_table, uint8_t index)
|
||||
{
|
||||
return *((uint16_t*)(text_table + 2 + index * 2));
|
||||
}
|
||||
|
||||
static uint16_t get_entries_start_offset_of(uint8_t num_text_entries)
|
||||
{
|
||||
// This returns the byte offset to skip the table index and reach the start of the actual entries.
|
||||
return 2 + (num_text_entries * 2);
|
||||
}
|
||||
|
||||
text_data_table::text_data_table(uint8_t *decompression_buffer)
|
||||
: decompression_buffer_(decompression_buffer)
|
||||
{
|
||||
}
|
||||
|
||||
void text_data_table::decompress(const uint8_t *compressed_table)
|
||||
{
|
||||
zx0_decompressor_start(decompression_buffer_, compressed_table);
|
||||
zx0_decompressor_read(zx0_decompressor_get_decompressed_size());
|
||||
}
|
||||
|
||||
uint16_t text_data_table::get_number_of_text_entries() const
|
||||
{
|
||||
return *((uint16_t*)decompression_buffer_);
|
||||
}
|
||||
|
||||
const uint8_t* text_data_table::get_text_entry(uint8_t index) const
|
||||
{
|
||||
const uint16_t entry_offset = get_entry_offset_by_index(decompression_buffer_, index);
|
||||
return decompression_buffer_ + get_entries_start_offset_of(get_number_of_text_entries()) + entry_offset;
|
||||
}
|
||||
|
||||
streamed_text_data_table::streamed_text_data_table(uint8_t *decompression_buffer, uint32_t decompression_buffer_size, uint8_t *index_buffer)
|
||||
: compressed_table_(nullptr)
|
||||
, decompression_buffer_(decompression_buffer)
|
||||
, decompression_buffer_size_(decompression_buffer_size)
|
||||
, index_buffer_(index_buffer)
|
||||
, bytes_decompressed_(0)
|
||||
, last_chunk_size_(0)
|
||||
{
|
||||
}
|
||||
|
||||
void streamed_text_data_table::decompress(const uint8_t *compressed_table)
|
||||
{
|
||||
zx0_decompressor_start(index_buffer_, compressed_table);
|
||||
zx0_decompressor_read(2);
|
||||
zx0_decompressor_read(get_number_of_text_entries() * 2);
|
||||
compressed_table_ = compressed_table;
|
||||
bytes_decompressed_ = 2 + get_number_of_text_entries() * 2;
|
||||
|
||||
// for further decompressing, we need this data to be available in the decompression buffer too.
|
||||
// ZX0 looks back to already decompressed data after all.
|
||||
memcpy(decompression_buffer_ + ZX0_DEFAULT_WINDOW_SIZE, index_buffer_, bytes_decompressed_);
|
||||
last_chunk_size_ = bytes_decompressed_;
|
||||
}
|
||||
|
||||
uint16_t streamed_text_data_table::get_number_of_text_entries() const
|
||||
{
|
||||
return *((uint16_t*)index_buffer_);
|
||||
}
|
||||
|
||||
const uint8_t* streamed_text_data_table::get_text_entry(uint8_t index)
|
||||
{
|
||||
const uint8_t num_text_entries = get_number_of_text_entries();
|
||||
const uint16_t entries_start_offset = get_entries_start_offset_of(num_text_entries);
|
||||
const uint16_t entry_offset = get_entry_offset_by_index(index_buffer_, index);
|
||||
const uint16_t entry_byte_offset = entries_start_offset + entry_offset;
|
||||
const uint16_t space_remaining_outside_lookback_window = decompression_buffer_size_ - ZX0_DEFAULT_WINDOW_SIZE;
|
||||
const uint16_t current_window_size = get_current_zx0_window_size();
|
||||
const uint16_t window_start_offset = bytes_decompressed_ - current_window_size;
|
||||
uint16_t bytes_to_decompress;
|
||||
uint16_t chunk_size;
|
||||
uint16_t entry_size_in_bytes;
|
||||
uint16_t entry_end_byte_offset;
|
||||
|
||||
// figure out how many bytes we need to read to have the entire text entry
|
||||
// unfortunately ZX0 doesn't have random access, so we need to linearly decompress
|
||||
// until we have reached the bytes we actually want.
|
||||
if(index != num_text_entries - 1)
|
||||
{
|
||||
const uint16_t next_entry_offset = get_entry_offset_by_index(index_buffer_, index + 1);
|
||||
entry_size_in_bytes = next_entry_offset - entry_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we don't have a next entry. So we need to consider the end of the file
|
||||
const uint32_t decompressed_size = zx0_decompressor_get_decompressed_size();
|
||||
entry_size_in_bytes = decompressed_size - entry_byte_offset;
|
||||
}
|
||||
entry_end_byte_offset = entry_byte_offset + entry_size_in_bytes;
|
||||
|
||||
if(entry_end_byte_offset < bytes_decompressed_)
|
||||
{
|
||||
// already decoded, let's check if we have it completely in our current decompressed window
|
||||
if(entry_byte_offset >= window_start_offset)
|
||||
{
|
||||
// one thing to realize is that when we have less than our ZX0 window size, the decoded data doesn't start
|
||||
// at the start of the buffer. But instead it ends at decompression_buffer + ZX0_DEFAULT_WINDOW_SIZE
|
||||
return get_window_start() + (entry_byte_offset - window_start_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
// unfortunately it's in front of our current decompression window.
|
||||
// Since ZX0 doesn't actually have random access, it means we have to start
|
||||
// decompression from scratch
|
||||
decompress(compressed_table_);
|
||||
// now that we decompressed JUST the index table again,
|
||||
// we should be able to reach desired_byte_offset.
|
||||
}
|
||||
}
|
||||
|
||||
bytes_to_decompress = entry_end_byte_offset - bytes_decompressed_;
|
||||
// keep decompressing until we have decompressed what we need.
|
||||
while(bytes_to_decompress > 0)
|
||||
{
|
||||
// move the last decompressed chunk backwards
|
||||
memmove(decompression_buffer_, decompression_buffer_ + last_chunk_size_, ZX0_DEFAULT_WINDOW_SIZE);
|
||||
chunk_size = (bytes_to_decompress > space_remaining_outside_lookback_window) ? space_remaining_outside_lookback_window : bytes_to_decompress;
|
||||
|
||||
zx0_decompressor_read_partial(decompression_buffer_ + ZX0_DEFAULT_WINDOW_SIZE, chunk_size);
|
||||
last_chunk_size_ = chunk_size;
|
||||
bytes_to_decompress -= chunk_size;
|
||||
bytes_decompressed_ += chunk_size;
|
||||
}
|
||||
|
||||
// we know the last byte we decompressed should be the last byte of the entry
|
||||
// so we need to count backwards to get to the beginning
|
||||
return decompression_buffer_ + ZX0_DEFAULT_WINDOW_SIZE + last_chunk_size_ - entry_size_in_bytes;
|
||||
}
|
||||
|
||||
uint8_t* streamed_text_data_table::get_window_start() const
|
||||
{
|
||||
uint16_t without_last_chunk_size = (bytes_decompressed_ - last_chunk_size_);
|
||||
if(without_last_chunk_size > ZX0_DEFAULT_WINDOW_SIZE)
|
||||
{
|
||||
without_last_chunk_size = ZX0_DEFAULT_WINDOW_SIZE;
|
||||
}
|
||||
return decompression_buffer_ + ZX0_DEFAULT_WINDOW_SIZE - without_last_chunk_size;
|
||||
}
|
||||
|
||||
uint8_t* streamed_text_data_table::get_window_end() const
|
||||
{
|
||||
return decompression_buffer_ + ZX0_DEFAULT_WINDOW_SIZE + last_chunk_size_;
|
||||
}
|
||||
|
||||
uint16_t streamed_text_data_table::get_current_zx0_window_size() const
|
||||
{
|
||||
return static_cast<uint16_t>(get_window_end() - get_window_start());
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
#include "sprite_data.h"
|
||||
#include "latin_short.h"
|
||||
#include "japanese_small.h"
|
||||
#include "text_data_table.h"
|
||||
|
||||
#define TEXT_CBB 0
|
||||
#define TEXT_SBB 10
|
||||
|
|
@ -55,17 +56,23 @@ void init_text_engine()
|
|||
|
||||
int text_loop(int script)
|
||||
{
|
||||
u8 text_decompression_buffer[3072];
|
||||
u8 index_buffer[100];
|
||||
streamed_text_data_table dialogue_table(text_decompression_buffer, sizeof(text_decompression_buffer), index_buffer);
|
||||
|
||||
dialogue_table.decompress(get_compressed_PTGB_table());
|
||||
switch (script)
|
||||
{
|
||||
case BTN_TRANSFER:
|
||||
curr_line = transfer_script[T_SCRIPT_START];
|
||||
curr_line = transfer_script_params[T_SCRIPT_START];
|
||||
break;
|
||||
|
||||
case BTN_EVENTS:
|
||||
curr_line = event_script[E_SCRIPT_START];
|
||||
curr_line = event_script_params[E_SCRIPT_START];
|
||||
break;
|
||||
}
|
||||
curr_text = curr_line.get_text();
|
||||
|
||||
curr_text = (curr_line.has_text()) ? dialogue_table.get_text_entry(curr_line.get_text_entry_index()) : NULL;
|
||||
|
||||
REG_BG1CNT = (REG_BG1CNT && !BG_PRIO_MASK) | BG_PRIO(2); // Show Fennel
|
||||
show_text_box();
|
||||
|
|
@ -85,13 +92,14 @@ int text_loop(int script)
|
|||
switch (script)
|
||||
{
|
||||
case BTN_TRANSFER:
|
||||
curr_line = transfer_script[text_next_obj_id(curr_line)];
|
||||
curr_line = transfer_script_params[text_next_obj_id(curr_line)];
|
||||
break;
|
||||
case BTN_EVENTS:
|
||||
curr_line = event_script[text_next_obj_id(curr_line)];
|
||||
curr_line = event_script_params[text_next_obj_id(curr_line)];
|
||||
break;
|
||||
}
|
||||
curr_text = curr_line.get_text();
|
||||
|
||||
curr_text = (curr_line.has_text()) ? dialogue_table.get_text_entry(curr_line.get_text_entry_index()) : NULL;
|
||||
char_index = 0;
|
||||
|
||||
if (text_exit)
|
||||
|
|
@ -154,14 +162,6 @@ int ptgb_write(const byte *text, bool instant, int length)
|
|||
TFont *font;
|
||||
int num = 0;
|
||||
|
||||
if (curr_text[char_index] == 0xFB) // This will need to be moved
|
||||
{
|
||||
line_char_index += char_index;
|
||||
line_char_index++;
|
||||
// Low key kinda scuffed, but it works to split the string
|
||||
curr_text = &curr_line.get_text()[line_char_index];
|
||||
}
|
||||
|
||||
while ((ch = *str) != 0xFF && num < length)
|
||||
{
|
||||
if (get_frame_count() % 2 == 0 || key_held(KEY_B) || key_held(KEY_A) || instant)
|
||||
|
|
|
|||
|
|
@ -64,6 +64,11 @@ public:
|
|||
* @brief This function reads <numBytes> of data into <outputBuffer>
|
||||
*/
|
||||
IWRAM_CODE void read(uint32_t num_bytes);
|
||||
|
||||
/**
|
||||
* @brief This function swaps out the current output buffer for the given one
|
||||
*/
|
||||
IWRAM_CODE void swap_output_buffer(uint8_t *new_output_buffer);
|
||||
protected:
|
||||
private:
|
||||
IWRAM_CODE void read_next_command();
|
||||
|
|
@ -73,7 +78,7 @@ private:
|
|||
ZX0Command cur_command_;
|
||||
const uint8_t *input_data_;
|
||||
uint8_t *back_pos_;
|
||||
uint8_t *cur_out;
|
||||
uint8_t *cur_out_;
|
||||
uint32_t last_offset_;
|
||||
};
|
||||
|
||||
|
|
@ -145,7 +150,7 @@ ZX0Decompressor::ZX0Decompressor()
|
|||
, cur_command_({ZX0OperationType::NONE, 0, 0, 0})
|
||||
, input_data_(nullptr)
|
||||
, back_pos_(nullptr)
|
||||
, cur_out(nullptr)
|
||||
, cur_out_(nullptr)
|
||||
, last_offset_(UINT32_MAX)
|
||||
{
|
||||
}
|
||||
|
|
@ -156,7 +161,7 @@ void ZX0Decompressor::start(uint8_t *output_buffer, const uint8_t *input_data)
|
|||
cur_command_ = {ZX0OperationType::NONE, 0, 0, 0};
|
||||
input_data_ = input_data;
|
||||
back_pos_ = nullptr;
|
||||
cur_out = output_buffer;
|
||||
cur_out_ = output_buffer;
|
||||
last_offset_ = UINT32_MAX;
|
||||
}
|
||||
|
||||
|
|
@ -185,6 +190,13 @@ IWRAM_CODE void ZX0Decompressor::read(uint32_t num_bytes)
|
|||
}
|
||||
}
|
||||
|
||||
IWRAM_CODE void ZX0Decompressor::swap_output_buffer(uint8_t *new_output_buffer)
|
||||
{
|
||||
const uint32_t current_offset = cur_out_ - back_pos_;
|
||||
cur_out_ = new_output_buffer;
|
||||
back_pos_ = new_output_buffer - current_offset;
|
||||
}
|
||||
|
||||
IWRAM_CODE inline void ZX0Decompressor::read_next_command()
|
||||
{
|
||||
const uint32_t cmd_bit = reader_.read(1);
|
||||
|
|
@ -226,10 +238,10 @@ IWRAM_CODE uint32_t ZX0Decompressor::copy_block(uint32_t num_bytes)
|
|||
{
|
||||
// Literal copy
|
||||
|
||||
// Align cur_out first
|
||||
while (bytes_remaining && ((uintptr_t)cur_out & 3))
|
||||
// Align cur_out_ first
|
||||
while (bytes_remaining && ((uintptr_t)cur_out_ & 3))
|
||||
{
|
||||
(*cur_out++) = reader_.read(8);
|
||||
(*cur_out_++) = reader_.read(8);
|
||||
bytes_remaining--;
|
||||
}
|
||||
|
||||
|
|
@ -239,27 +251,27 @@ IWRAM_CODE uint32_t ZX0Decompressor::copy_block(uint32_t num_bytes)
|
|||
// we need to swap again, because the data was originally stored in big endian format
|
||||
// BitReader converted it to little endian format to make reading easier.
|
||||
// and now we need to convert it back to big endian format.
|
||||
*(uint32_t*)cur_out = __builtin_bswap32(reader_.read(32));
|
||||
cur_out += 4;
|
||||
*(uint32_t*)cur_out_ = __builtin_bswap32(reader_.read(32));
|
||||
cur_out_ += 4;
|
||||
bytes_remaining -= 4;
|
||||
}
|
||||
// Handle remaining bytes
|
||||
while (bytes_remaining--)
|
||||
{
|
||||
(*cur_out++) = reader_.read(8);
|
||||
(*cur_out_++) = reader_.read(8);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!cur_command_.byte_pos)
|
||||
{
|
||||
back_pos_ = cur_out - cur_command_.offset;
|
||||
back_pos_ = cur_out_ - cur_command_.offset;
|
||||
}
|
||||
|
||||
// try to get cur_out and back_pos aligned to 32 bit accesses first
|
||||
while (bytes_remaining && (((uintptr_t)cur_out & 3) || ((uintptr_t)back_pos_ & 3)))
|
||||
// try to get cur_out_ and back_pos aligned to 32 bit accesses first
|
||||
while (bytes_remaining && (((uintptr_t)cur_out_ & 3) || ((uintptr_t)back_pos_ & 3)))
|
||||
{
|
||||
(*cur_out++) = (*back_pos_++);
|
||||
(*cur_out_++) = (*back_pos_++);
|
||||
bytes_remaining--;
|
||||
}
|
||||
|
||||
|
|
@ -268,15 +280,15 @@ IWRAM_CODE uint32_t ZX0Decompressor::copy_block(uint32_t num_bytes)
|
|||
{
|
||||
// these don't need to be byteswapped, because the data is being read with the same endianness as it is being written.
|
||||
// this is different when reading from BitReader.
|
||||
*(uint32_t*)cur_out = *((uint32_t*)back_pos_);
|
||||
cur_out += 4;
|
||||
*(uint32_t*)cur_out_ = *((uint32_t*)back_pos_);
|
||||
cur_out_ += 4;
|
||||
back_pos_ += 4;
|
||||
bytes_remaining -= 4;
|
||||
}
|
||||
|
||||
while(bytes_remaining--)
|
||||
{
|
||||
(*cur_out++) = (*back_pos_++);
|
||||
(*cur_out_++) = (*back_pos_++);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -304,4 +316,11 @@ void zx0_decompressor_read(uint32_t num_bytes)
|
|||
{
|
||||
decompressor.read(num_bytes);
|
||||
}
|
||||
|
||||
void zx0_decompressor_read_partial(uint8_t *output_buffer, uint16_t num_bytes)
|
||||
{
|
||||
decompressor.swap_output_buffer(output_buffer);
|
||||
decompressor.read(num_bytes);
|
||||
}
|
||||
|
||||
}
|
||||
218
text_helper/main.py
Normal file → Executable file
218
text_helper/main.py
Normal file → Executable file
|
|
@ -10,14 +10,14 @@ import math
|
|||
|
||||
update = True
|
||||
|
||||
print ("\n\n\n\n\n---------------")
|
||||
print ("\nRunning text_helper:\n\n\n\n---------------")
|
||||
|
||||
if (update == True):
|
||||
|
||||
url = 'https://docs.google.com/spreadsheets/d/14LLs5lLqWasFcssBmJdGXjjYxARAJBa_QUOUhXZt4v8/export?format=xlsx'
|
||||
|
||||
response = requests.get(url)
|
||||
file_Path = 'text_helper\\text.xlsx'
|
||||
file_Path = 'text_helper/text.xlsx'
|
||||
|
||||
if response.status_code == 200:
|
||||
with open(file_Path, 'wb') as file:
|
||||
|
|
@ -272,7 +272,7 @@ class Languages(Enum):
|
|||
SpanishLA = 6
|
||||
|
||||
# read by default 1st sheet of an excel file
|
||||
dir = os.curdir + "\\text_helper"
|
||||
dir = os.curdir + "/text_helper"
|
||||
|
||||
mainDict = {}
|
||||
|
||||
|
|
@ -357,18 +357,57 @@ def convert_item(ogDict):
|
|||
else:
|
||||
arr = engCharArray
|
||||
for char in outStr[:-1]:
|
||||
byteStr += hex(convertByte(ord(char), arr)) + ", "
|
||||
byteStr += f"{convertByte(ord(char), arr):02x} "
|
||||
if (len(outStr) > 0 and outStr[-1] != ' '): # Check if the last char is a space
|
||||
byteStr += hex(convertByte(ord(outStr[-1]), arr)) + ", "
|
||||
byteStr += f"{convertByte(ord(outStr[-1]), arr):02x} "
|
||||
|
||||
byteStr += "0xff"
|
||||
byteStr += "ff"
|
||||
|
||||
ogDict["bytes"] = byteStr
|
||||
return ogDict
|
||||
|
||||
def write_text_bin_file(filename, dictionary):
|
||||
with open(filename, 'wb') as binFile:
|
||||
# Let the first byte indicate the number of entries
|
||||
dict_size = len(dictionary)
|
||||
# We need to store 2 bytes instead of one, because not aligning the data to 16 bits will cause corruption on the gba.
|
||||
binFile.write(bytes([dict_size & 0xFF, (dict_size >> 8) & 0xFF]))
|
||||
# After this initial byte, we will read the offset (16 bit) of each line (relative to the last index byte)
|
||||
index = bytearray(len(dictionary) * 2)
|
||||
# bindata will contain the binary data of each entry
|
||||
bindata = bytearray()
|
||||
current_offset = 0
|
||||
|
||||
num = 0
|
||||
# Append every line's binary data to bindata
|
||||
# keep an index of the binary offset within bindata at which each line starts
|
||||
for key, line in dictionary.items():
|
||||
dictionary[key] = convert_item(line)
|
||||
# store the offset of the line in the index as a 16 bit little endian value
|
||||
index[num * 2] = (current_offset & 0xFF)
|
||||
index[num * 2 + 1] = (current_offset >> 8) & 0xFF
|
||||
linedata = bytes.fromhex(dictionary[key]['bytes'])
|
||||
bindata.extend(linedata)
|
||||
current_offset += len(linedata)
|
||||
num += 1
|
||||
|
||||
# Write the index and bindata to the file
|
||||
binFile.write(index)
|
||||
binFile.write(bindata)
|
||||
binFile.close()
|
||||
|
||||
def write_enum_to_header_file(hFile, prefix, dictionary):
|
||||
num = 0
|
||||
for key, line in dictionary.items():
|
||||
hFile.write(f"#define {prefix}{key} {num}\n")
|
||||
num += 1
|
||||
hFile.write("\n")
|
||||
return num
|
||||
|
||||
|
||||
print("\n\nStarting parse: \n")
|
||||
|
||||
currSheet = pd.read_excel(dir + "\\text.xlsx", sheet_name="Translations")
|
||||
currSheet = pd.read_excel(dir + "/text.xlsx", sheet_name="Translations")
|
||||
for row in currSheet.iterrows():
|
||||
#print(row)
|
||||
for lang in Languages:
|
||||
|
|
@ -383,99 +422,118 @@ for row in currSheet.iterrows():
|
|||
"pixelsInLine" : currRow.iloc[4],
|
||||
"includeBoxBreaks": currRow.iloc[5],
|
||||
}
|
||||
|
||||
with open(os.curdir + '\\source\\translated_text.cpp', 'w') as cppFile:
|
||||
cppFile.write("#include \"translated_text.h\"\n#include \"debug_mode.h\"\n#include \"pokemon_data.h\"\n")
|
||||
for lang in Languages: # putting this here is a really silly way to loop through all the CPP values but only write to H once
|
||||
with open (os.curdir + '\\include\\translated_text.h', 'w') as hFile:
|
||||
hFile.write("#ifndef DIALOGUE_H\n#define DIALOGUE_H\n\n#include <string>\n#include <tonc.h>\n\n")
|
||||
cppFile.write(f"#if PTGB_BUILD_LANGUAGE == {lang.value + 1}\n")
|
||||
|
||||
# generate the header file
|
||||
with open (os.curdir + '/include/translated_text.h', 'w') as hFile:
|
||||
hFile.write("#ifndef DIALOGUE_H\n#define DIALOGUE_H\n\n#include <tonc.h>\n\n")
|
||||
|
||||
# PTGB
|
||||
PTGB = mainDict[lang.name]["PTGB"]
|
||||
|
||||
num = 0
|
||||
for key, line in PTGB.items():
|
||||
#print("--------")
|
||||
PTGB[key] = convert_item(line)
|
||||
cppFile.write("\nconst byte dialogueLine" + str(num) + "[] = {" + PTGB[key]["bytes"] + "};")
|
||||
hFile.write(f"#define {key} {num}\n")
|
||||
num += 1
|
||||
|
||||
cppFile.write("\n")
|
||||
hFile.write(f"\n#define DIA_SIZE {num}\n#define DIA_END DIA_SIZE\n\n")
|
||||
# PTGB
|
||||
num = write_enum_to_header_file(hFile, "", mainDict[lang.name]["PTGB"])
|
||||
hFile.write(f"\n#define DIA_SIZE {num}\n#define DIA_END DIA_SIZE\n\n")
|
||||
|
||||
cppFile.write("\n\nconst byte *dialogue[DIA_SIZE] = {")
|
||||
for i in range(num):
|
||||
cppFile.write("\ndialogueLine" + str(i) + ", ")
|
||||
cppFile.write("\n};\n")
|
||||
hFile.write("extern const byte *dialogue[DIA_SIZE];\n")
|
||||
# RSEFRLG
|
||||
write_enum_to_header_file(hFile, "RSEFRLG_", mainDict[lang.name]["RSEFRLG"])
|
||||
|
||||
# RSEFRLG
|
||||
RSEFRLG = mainDict[lang.name]["RSEFRLG"]
|
||||
for key, line in RSEFRLG.items():
|
||||
RSEFRLG[key] = convert_item(line)
|
||||
cppFile.write(f"\nconst byte {key}[] = {{{RSEFRLG[key]["bytes"]}}};")
|
||||
hFile.write(f"\nextern const byte {key}[];")
|
||||
# GENERAL
|
||||
write_enum_to_header_file(hFile, "GENERAL_", mainDict[lang.name]["GENERAL"])
|
||||
|
||||
# General
|
||||
GENERAL = mainDict[lang.name]["GENERAL"]
|
||||
for key, line in GENERAL.items():
|
||||
GENERAL[key] = convert_item(line)
|
||||
cppFile.write(f"const byte {key}[] = {{{GENERAL[key]["bytes"]}}};\n")
|
||||
hFile.write(f"extern const byte {key}[];\n")
|
||||
|
||||
# Credits
|
||||
CREDITS = mainDict[lang.name]["CREDITS"]
|
||||
for key, line in CREDITS.items():
|
||||
CREDITS[key] = convert_item(line)
|
||||
cppFile.write(f"const byte {key}[] = {{{CREDITS[key]["bytes"]}}};\n")
|
||||
hFile.write(f"extern const byte {key}[];\n")
|
||||
cppFile.write("\n")
|
||||
|
||||
# Pokemon Names
|
||||
PKMN_NAMES = mainDict[lang.name]["PKMN_NAMES"]
|
||||
|
||||
num = 0
|
||||
for key, line in PKMN_NAMES.items():
|
||||
#print("--------")
|
||||
PKMN_NAMES[key] = convert_item(line)
|
||||
cppFile.write("const byte PKMN_NAMES" + str(num) + "[] = {" + PKMN_NAMES[key]["bytes"] + "};\n")
|
||||
num += 1
|
||||
|
||||
cppFile.write("\n")
|
||||
# CREDITS
|
||||
write_enum_to_header_file(hFile, "CREDITS_", mainDict[lang.name]["CREDITS"])
|
||||
|
||||
cppFile.write(f"\n\nconst byte *PKMN_NAMES[{num}] = " + "{")
|
||||
for i in range(num):
|
||||
cppFile.write("\nPKMN_NAMES" + str(i) + ", ")
|
||||
cppFile.write("\n};\n")
|
||||
hFile.write(f"extern const byte *PKMN_NAMES[{num}];\n")
|
||||
# PKMN_NAMES
|
||||
write_enum_to_header_file(hFile, "PKMN_NAMES_", mainDict[lang.name]["PKMN_NAMES"])
|
||||
|
||||
hFile.write("/** Returns the ZX0 compressed PTGB text table.*/\n")
|
||||
hFile.write("const u8* get_compressed_PTGB_table();\n\n")
|
||||
hFile.write("/** Returns the ZX0 compressed RSEFRLG text table.*/\n")
|
||||
hFile.write("const u8* get_compressed_rsefrlg_table();\n\n")
|
||||
hFile.write("/** Returns the ZX0 compressed GENERAL text table.*/\n")
|
||||
hFile.write("const u8* get_compressed_general_table();\n\n")
|
||||
hFile.write("/** Returns the ZX0 compressed CREDITS text table.*/\n")
|
||||
hFile.write("const u8* get_compressed_credits_table();\n\n")
|
||||
hFile.write("/** Returns the ZX0 compressed PKMN_NAMES text table.*/\n")
|
||||
hFile.write("const u8* get_compressed_pkmn_names_table();\n\n")
|
||||
|
||||
hFile.write("\n#endif")
|
||||
hFile.close()
|
||||
|
||||
# now generate the text tables
|
||||
for lang in Languages:
|
||||
# PTGB
|
||||
table_file = os.curdir + '/to_compress/PTGB_' + lang.name.lower() + '.bin'
|
||||
write_text_bin_file(table_file, mainDict[lang.name]["PTGB"])
|
||||
|
||||
# RSEFRLG
|
||||
table_file = os.curdir + '/to_compress/RSEFRLG_' + lang.name.lower() + '.bin'
|
||||
write_text_bin_file(table_file, mainDict[lang.name]["RSEFRLG"])
|
||||
|
||||
# GENERAL
|
||||
table_file = os.curdir + '/to_compress/GENERAL_' + lang.name.lower() + '.bin'
|
||||
write_text_bin_file(table_file, mainDict[lang.name]["GENERAL"])
|
||||
|
||||
# CREDITS
|
||||
table_file = os.curdir + '/to_compress/CREDITS_' + lang.name.lower() + '.bin'
|
||||
write_text_bin_file(table_file, mainDict[lang.name]["CREDITS"])
|
||||
|
||||
# PKMN_NAMES
|
||||
table_file = os.curdir + '/to_compress/PKMN_NAMES_' + lang.name.lower() + '.bin'
|
||||
write_text_bin_file(table_file, mainDict[lang.name]["PKMN_NAMES"])
|
||||
|
||||
# now generate the cpp file.
|
||||
with open(os.curdir + '/source/translated_text.cpp', 'w') as cppFile:
|
||||
cppFile.write("#include \"translated_text.h\"\n#include \"debug_mode.h\"\n#include \"pokemon_data.h\"\n#include \"zx0_decompressor.h\"\n")
|
||||
# generate includes for each language
|
||||
for lang in Languages:
|
||||
for cat in mainDict[lang.name]:
|
||||
if cat in {"PTGB", "RSEFRLG", "GENERAL", "CREDITS", "PKMN_NAMES"}:
|
||||
cppFile.write("#include \"" + cat.upper() + "_" + lang.name.lower() + "_zx0_bin.h\"\n")
|
||||
|
||||
for lang in Languages:
|
||||
cppFile.write(f"\n#if PTGB_BUILD_LANGUAGE == {lang.value + 1}\n")
|
||||
# PTGB
|
||||
cppFile.write("const u8* get_compressed_PTGB_table()\n")
|
||||
cppFile.write("{\n")
|
||||
cppFile.write("\treturn PTGB_" + lang.name.lower() + "_zx0_bin;\n")
|
||||
cppFile.write("}\n\n")
|
||||
# RSEFRLG
|
||||
cppFile.write("const u8* get_compressed_rsefrlg_table()\n")
|
||||
cppFile.write("{\n")
|
||||
cppFile.write("\treturn RSEFRLG_" + lang.name.lower() + "_zx0_bin;\n")
|
||||
cppFile.write("}\n\n")
|
||||
# GENERAL
|
||||
cppFile.write("const u8* get_compressed_general_table()\n")
|
||||
cppFile.write("{\n")
|
||||
cppFile.write("\treturn GENERAL_" + lang.name.lower() + "_zx0_bin;\n")
|
||||
cppFile.write("}\n\n")
|
||||
# CREDITS
|
||||
cppFile.write("const u8* get_compressed_credits_table()\n")
|
||||
cppFile.write("{\n")
|
||||
cppFile.write("\treturn CREDITS_" + lang.name.lower() + "_zx0_bin;\n")
|
||||
cppFile.write("}\n\n")
|
||||
# PKMN_NAMES
|
||||
cppFile.write("const u8* get_compressed_pkmn_names_table()\n")
|
||||
cppFile.write("{\n")
|
||||
cppFile.write("\treturn PKMN_NAMES_" + lang.name.lower() + "_zx0_bin;\n")
|
||||
cppFile.write("}\n\n")
|
||||
|
||||
cppFile.write(f"#endif\n\n\n")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cppFile.write("\n")
|
||||
cppFile.write(f"#endif\n\n\n")
|
||||
|
||||
hFile.write("\n#endif")
|
||||
|
||||
for lang in Languages:
|
||||
for cat in mainDict[lang.name]:
|
||||
if cat in {"PTGB", "RSEFRLG", "GENERAL", "CREDITS", "PKMN_NAMES"}:
|
||||
for item in mainDict[lang.name][cat]:
|
||||
string = mainDict[lang.name][cat][item]["bytes"].split(", ")
|
||||
string = mainDict[lang.name][cat][item]["bytes"].split(" ")
|
||||
outText = ""
|
||||
if lang == Languages.Japanese:
|
||||
arr = jpnCharArray
|
||||
else:
|
||||
arr = engCharArray
|
||||
for byte in string:
|
||||
byte = engCharArray[int(byte, 0)]
|
||||
byte = engCharArray[int(byte, 16)]
|
||||
outText += chr(byte)
|
||||
mainDict[lang.name][cat][item]["text"] = outText
|
||||
|
||||
with open(dir + '\\output.json', 'w') as jsonFile:
|
||||
with open(dir + '/output.json', 'w') as jsonFile:
|
||||
jsonFile.write(json.dumps(mainDict))
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,6 @@
|
|||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
void writeTable(const char* filename, const uint8_t *buffer, size_t buffer_size);
|
||||
void writeTable(const char *output_path, const char *filename, const uint8_t *buffer, size_t buffer_size);
|
||||
|
||||
#endif
|
||||
|
|
@ -12,6 +12,6 @@ typedef uint8_t byte;
|
|||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
|
||||
void generate_pokemon_data();
|
||||
void generate_pokemon_data(const char *output_path);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,12 +1,23 @@
|
|||
#include "common.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
void writeTable(const char* filename, const uint8_t *buffer, size_t buffer_size)
|
||||
void writeTable(const char* output_path, const char *filename, const uint8_t *buffer, size_t buffer_size)
|
||||
{
|
||||
char full_path[4096];
|
||||
FILE* f;
|
||||
|
||||
f = fopen(filename, "wb+");
|
||||
if(output_path[0] != '\0')
|
||||
{
|
||||
snprintf(full_path, sizeof(full_path), "%s/%s", output_path, filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(full_path, filename, sizeof(full_path));
|
||||
}
|
||||
|
||||
f = fopen(full_path, "wb+");
|
||||
fwrite(buffer, 1, buffer_size, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
|
@ -1,11 +1,12 @@
|
|||
#include "pokemon_data.h"
|
||||
|
||||
#include <cstdio>
|
||||
// This application holds the various long static data arrays that Poke Transporter GB uses
|
||||
// and it writes them to .bin files that can be compressed with compressZX0 later.
|
||||
// it's useful to do it this way because it keeps this data easy to view, edit and document
|
||||
|
||||
int main(int /*argc*/, char **/*argv*/)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
generate_pokemon_data();
|
||||
const char *output_path = (argc > 1) ? argv[1] : "";
|
||||
generate_pokemon_data(output_path);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -4703,18 +4703,18 @@ const u8 TYPES[POKEMON_ARRAY_SIZE][2]{
|
|||
{0xc, 0xc}, // Treecko is grass/grass
|
||||
};
|
||||
|
||||
void generate_pokemon_data()
|
||||
void generate_pokemon_data(const char *output_path)
|
||||
{
|
||||
writeTable("gen_1_charsets.bin", (const uint8_t*)gen_1_charsets, sizeof(gen_1_charsets));
|
||||
writeTable("gen_2_charsets.bin", (const uint8_t*)gen_2_charsets, sizeof(gen_2_charsets));
|
||||
writeTable("gen_3_charsets.bin", (const uint8_t*)gen_3_charsets, sizeof(gen_3_charsets));
|
||||
writeTable("EXP_GROUPS.bin", EXP_GROUPS, sizeof(EXP_GROUPS));
|
||||
writeTable("GENDER_RATIO.bin", GENDER_RATIO, sizeof(GENDER_RATIO));
|
||||
writeTable("NUM_ABILITIES.bin", (const uint8_t*)(NUM_ABILITIES), sizeof(NUM_ABILITIES));
|
||||
writeTable("FIRST_MOVES.bin", FIRST_MOVES, sizeof(FIRST_MOVES));
|
||||
writeTable("JPN_NAMES.bin", (const uint8_t*)JPN_NAMES, sizeof(JPN_NAMES));
|
||||
writeTable("POWER_POINTS.bin", POWER_POINTS, sizeof(POWER_POINTS));
|
||||
writeTable("MENU_SPRITE_PALS.bin", (const uint8_t*)MENU_SPRITE_PALS, sizeof(MENU_SPRITE_PALS));
|
||||
writeTable("EVENT_PKMN.bin", (const uint8_t*)EVENT_PKMN, sizeof(EVENT_PKMN));
|
||||
writeTable("TYPES.bin", (const uint8_t*)TYPES, sizeof(TYPES));
|
||||
writeTable(output_path, "gen_1_charsets.bin", (const uint8_t*)gen_1_charsets, sizeof(gen_1_charsets));
|
||||
writeTable(output_path, "gen_2_charsets.bin", (const uint8_t*)gen_2_charsets, sizeof(gen_2_charsets));
|
||||
writeTable(output_path, "gen_3_charsets.bin", (const uint8_t*)gen_3_charsets, sizeof(gen_3_charsets));
|
||||
writeTable(output_path, "EXP_GROUPS.bin", EXP_GROUPS, sizeof(EXP_GROUPS));
|
||||
writeTable(output_path, "GENDER_RATIO.bin", GENDER_RATIO, sizeof(GENDER_RATIO));
|
||||
writeTable(output_path, "NUM_ABILITIES.bin", (const uint8_t*)(NUM_ABILITIES), sizeof(NUM_ABILITIES));
|
||||
writeTable(output_path, "FIRST_MOVES.bin", FIRST_MOVES, sizeof(FIRST_MOVES));
|
||||
writeTable(output_path, "JPN_NAMES.bin", (const uint8_t*)JPN_NAMES, sizeof(JPN_NAMES));
|
||||
writeTable(output_path, "POWER_POINTS.bin", POWER_POINTS, sizeof(POWER_POINTS));
|
||||
writeTable(output_path, "MENU_SPRITE_PALS.bin", (const uint8_t*)MENU_SPRITE_PALS, sizeof(MENU_SPRITE_PALS));
|
||||
writeTable(output_path, "EVENT_PKMN.bin", (const uint8_t*)EVENT_PKMN, sizeof(EVENT_PKMN));
|
||||
writeTable(output_path, "TYPES.bin", (const uint8_t*)TYPES, sizeof(TYPES));
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user