Poke_Transporter_GB/source/global_frame_controller.cpp
Philippe Symons 9268cbd42e Reduce binary size by eliminating libstdc++
This commit removes all references to things in the libstdc++ library to remove a decent chunk of bloat.

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

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

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

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

329 lines
8.2 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"
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;
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);
ptgb_write(pulled_cart_error, true);
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);
}
}
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);
}