mirror of
https://github.com/GearsProgress/Poke_Transporter_GB.git
synced 2026-03-22 01:44:36 -05:00
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.
344 lines
8.8 KiB
C++
344 lines
8.8 KiB
C++
#include <tonc.h>
|
|
#include <cmath>
|
|
#include "libstd_replacements.h"
|
|
#include "global_frame_controller.h"
|
|
#include "random.h"
|
|
#include "background_engine.h"
|
|
#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;
|
|
int cable_frame = 0;
|
|
int curr_link_animation_state = 0;
|
|
int fennel_blink_timer = 0;
|
|
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();
|
|
rand_next_frame();
|
|
// tte_set_pos(0, 0);
|
|
// tte_write(ptgb::to_string(get_rand_u32()));
|
|
background_frame(global_frame_count);
|
|
determine_fennel_blink();
|
|
if (missingno_enabled)
|
|
{
|
|
set_background_pal(0xFF, false, false);
|
|
}
|
|
oam_copy(oam_mem, obj_buffer, num_sprites);
|
|
// mmFrame(); //Music
|
|
if (global_frame_count % 60 == 0)
|
|
{
|
|
set_menu_sprite_pal(0);
|
|
if (!curr_rom.verify_rom())
|
|
{
|
|
REG_BG0CNT = (REG_BG0CNT & ~BG_PRIO_MASK) | BG_PRIO(2);
|
|
REG_BG2CNT = (REG_BG2CNT & ~BG_PRIO_MASK) | BG_PRIO(1);
|
|
tte_set_pos(40, 24);
|
|
create_textbox(4, 1, 160, 80, true);
|
|
obj_hide_multi(ptgb_logo_l, num_sprites);
|
|
|
|
show_pulled_cart_error();
|
|
|
|
oam_copy(oam_mem, obj_buffer, num_sprites);
|
|
while (true)
|
|
{
|
|
};
|
|
}
|
|
}
|
|
else if (global_frame_count % 60 == 30)
|
|
{
|
|
set_menu_sprite_pal(1);
|
|
}
|
|
|
|
if (global_frame_count % (40 / curr_link_animation_state) == 0)
|
|
{
|
|
cable_frame = (cable_frame + 1) % 12;
|
|
if (curr_link_animation_state > 0)
|
|
{
|
|
run_link_cable_animation(cable_frame);
|
|
}
|
|
}
|
|
global_frame_count++;
|
|
VBlankIntrWait();
|
|
};
|
|
|
|
int get_frame_count()
|
|
{
|
|
return global_frame_count;
|
|
}
|
|
|
|
void enable_auto_random()
|
|
{
|
|
rand_enabled = true;
|
|
}
|
|
|
|
void disable_auto_random()
|
|
{
|
|
rand_enabled = false;
|
|
}
|
|
|
|
const unsigned short MENU_PALS[5][4] = {
|
|
{RGB15(31, 31, 31), RGB15(31, 19, 10), RGB15(31, 7, 01), RGB15(00, 00, 00)}, // Red
|
|
{RGB15(31, 31, 31), RGB15(31, 19, 10), RGB15(10, 9, 31), RGB15(00, 00, 00)}, // Blue
|
|
{RGB15(31, 31, 31), RGB15(31, 19, 10), RGB15(07, 23, 03), RGB15(00, 00, 00)}, // Green
|
|
{RGB15(31, 31, 31), RGB15(31, 19, 10), RGB15(15, 10, 03), RGB15(00, 00, 00)}, // Brown
|
|
{RGB15(31, 31, 31), RGB15(31, 19, 10), RGB15(29, 5, 13), RGB15(00, 00, 00)}, // Pink
|
|
};
|
|
|
|
void set_menu_sprite_pal(int frame)
|
|
{
|
|
return;
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
unsigned short curr_pal[16] = {
|
|
// frame: 1 | 2
|
|
MENU_PALS[i][(!frame ? 0 : 0)],
|
|
MENU_PALS[i][(!frame ? 0 : 1)],
|
|
MENU_PALS[i][(!frame ? 0 : 2)],
|
|
MENU_PALS[i][(!frame ? 0 : 3)],
|
|
MENU_PALS[i][(!frame ? 1 : 0)],
|
|
MENU_PALS[i][(!frame ? 1 : 1)],
|
|
MENU_PALS[i][(!frame ? 1 : 2)],
|
|
MENU_PALS[i][(!frame ? 1 : 3)],
|
|
MENU_PALS[i][(!frame ? 2 : 0)],
|
|
MENU_PALS[i][(!frame ? 2 : 1)],
|
|
MENU_PALS[i][(!frame ? 2 : 2)],
|
|
MENU_PALS[i][(!frame ? 2 : 3)],
|
|
MENU_PALS[i][(!frame ? 3 : 0)],
|
|
MENU_PALS[i][(!frame ? 3 : 1)],
|
|
MENU_PALS[i][(!frame ? 3 : 2)],
|
|
MENU_PALS[i][(!frame ? 3 : 3)],
|
|
};
|
|
memcpy(pal_obj_mem + ((MENU_PAL_START + i) * 16), curr_pal, 32);
|
|
}
|
|
}
|
|
|
|
static const int path[12][2] = {{19, 18}, {19, 19}, {18, 19}, {17, 19}, {16, 19}, {15, 19}, {14, 19}, {13, 19}, {12, 19}, {11, 19}, {10, 19}, {24, 24}};
|
|
|
|
void run_link_cable_animation(int frame)
|
|
{
|
|
switch (curr_link_animation_state)
|
|
{
|
|
case STATE_CONNECTION:
|
|
frame %= 4;
|
|
obj_hide_multi(link_frame1, 4);
|
|
obj_unhide_multi(link_frame1, 0, frame);
|
|
break;
|
|
case STATE_TRANSFER:
|
|
obj_set_pos(link_blob1, path[frame][0] * 8, path[frame][1] * 8);
|
|
obj_set_pos(link_blob2, path[frame][0] * 8, path[frame][1] * 8);
|
|
obj_set_pos(link_blob3, path[frame][0] * 8, path[frame][1] * 8);
|
|
|
|
obj_hide_multi(link_blob1, 3);
|
|
switch (frame % 3)
|
|
{
|
|
case 0:
|
|
obj_unhide(link_blob1, 0);
|
|
break;
|
|
case 1:
|
|
obj_unhide(link_blob2, 0);
|
|
break;
|
|
case 2:
|
|
obj_unhide(link_blob3, 0);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void link_animation_state(int state)
|
|
{
|
|
cable_frame = 0;
|
|
switch (state)
|
|
{
|
|
case STATE_CONNECTION:
|
|
obj_unhide(gba_cart, 0);
|
|
obj_set_pos(gba_cart, 17 * 8, 14 * 8);
|
|
|
|
obj_unhide(cart_shell, 0);
|
|
obj_set_pos(cart_shell, (8 * 8), (11 * 8) + 11);
|
|
obj_unhide(cart_label, 0);
|
|
obj_set_pos(cart_label, (8 * 8) + 8, (11 * 8) + 11 + 13);
|
|
|
|
obj_set_pos(link_frame1, 17 * 8, 17 * 8);
|
|
obj_set_pos(link_frame2, 13 * 8, 19 * 8);
|
|
obj_set_pos(link_frame3, 9 * 8, 18 * 8);
|
|
break;
|
|
case STATE_TRANSFER:
|
|
obj_unhide_multi(link_blob1, 0, 3);
|
|
case STATE_NO_ANIM:
|
|
obj_unhide(gba_cart, 0);
|
|
obj_set_pos(gba_cart, 17 * 8, 14 * 8);
|
|
|
|
obj_unhide(cart_shell, 0);
|
|
obj_set_pos(cart_shell, (8 * 8), (11 * 8) + 11);
|
|
obj_unhide(cart_label, 0);
|
|
obj_set_pos(cart_label, (8 * 8) + 8, (11 * 8) + 11 + 13);
|
|
|
|
obj_unhide(link_frame1, 0);
|
|
obj_set_pos(link_frame1, 17 * 8, 17 * 8);
|
|
obj_unhide(link_frame2, 0);
|
|
obj_set_pos(link_frame2, 13 * 8, 19 * 8);
|
|
obj_unhide(link_frame3, 0);
|
|
obj_set_pos(link_frame3, 9 * 8, 18 * 8);
|
|
break;
|
|
|
|
default:
|
|
obj_hide_multi(link_frame1, 3);
|
|
obj_hide_multi(link_blob1, 3);
|
|
obj_hide(gba_cart);
|
|
obj_hide(cart_shell);
|
|
obj_hide(cart_label);
|
|
break;
|
|
}
|
|
curr_link_animation_state = state;
|
|
}
|
|
|
|
void determine_fennel_blink()
|
|
{
|
|
if (get_curr_flex_background() == BG_FENNEL)
|
|
{
|
|
if (fennel_blink_timer == 0)
|
|
{
|
|
fennel_blink(fennel_blink_state);
|
|
fennel_blink_state = (fennel_blink_state + 1) % 4;
|
|
if (fennel_blink_state == 3) // Wait a random amount of time
|
|
{
|
|
fennel_blink_timer = get_rand_range(4 * 60, 8 * 60);
|
|
}
|
|
else // Continue with the animation
|
|
{
|
|
|
|
fennel_blink_timer = 4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fennel_blink_timer--;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fennel_blink_timer = get_rand_range(4 * 60, 8 * 60);
|
|
}
|
|
}
|
|
|
|
void set_missingno(bool val)
|
|
{
|
|
missingno_enabled = val;
|
|
if (val == false)
|
|
{
|
|
set_background_pal(curr_rom.gamecode, false, false);
|
|
fennel_blink_timer = 0;
|
|
}
|
|
}
|
|
|
|
void set_treecko(bool val)
|
|
{
|
|
treecko_enabled = val;
|
|
}
|
|
|
|
bool get_missingno_enabled()
|
|
{
|
|
return missingno_enabled;
|
|
}
|
|
|
|
bool get_treecko_enabled()
|
|
{
|
|
return treecko_enabled;
|
|
}
|
|
|
|
// FNV-1a 32-bit hash function for byte arrays
|
|
u32 fnv1a_hash(unsigned char *data, size_t length)
|
|
{
|
|
const uint32_t fnv_prime = 0x01000193;
|
|
const uint32_t fnv_offset_basis = 0x811C9DC5;
|
|
uint32_t hash = fnv_offset_basis;
|
|
|
|
for (size_t i = 0; i < length; ++i)
|
|
{
|
|
hash ^= data[i];
|
|
hash *= fnv_prime;
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
int get_string_length(const byte *str)
|
|
{
|
|
int size = 0;
|
|
while (str[size] != 0xFF)
|
|
{
|
|
size++;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
void convert_int_to_ptgb_str(int val, byte str[], int min_length)
|
|
{
|
|
int div = 1;
|
|
int count = 0;
|
|
int num;
|
|
bool non_zero = false;
|
|
bool first = true;
|
|
|
|
// Set it up so the number has all the zeros it needs
|
|
for (int i = 0; i < min_length; i++)
|
|
{
|
|
div *= 10;
|
|
}
|
|
|
|
// Increase it if the number is still larger
|
|
while (div <= val)
|
|
{
|
|
div *= 10;
|
|
}
|
|
|
|
while (div != 0)
|
|
{
|
|
num = val / div;
|
|
if (num != 0 || non_zero)
|
|
{
|
|
non_zero = true;
|
|
str[count] = num + 0xA1; // 0xA1 is 0 in the chart
|
|
count++;
|
|
}
|
|
else
|
|
{
|
|
if (!first)
|
|
{
|
|
str[count] = 0xA1; // 0xA1 is 0 in the chart
|
|
count++;
|
|
} else {
|
|
first = false;
|
|
}
|
|
}
|
|
|
|
val %= div;
|
|
div /= 10;
|
|
}
|
|
str[count] = 0xFF;
|
|
}
|
|
|
|
void convert_int_to_ptgb_str(int val, byte str[])
|
|
{
|
|
convert_int_to_ptgb_str(val, str, 0);
|
|
}
|