Skip to content

Commit

Permalink
FF8: Allow to customize card names via an msd direct file (#739)
Browse files Browse the repository at this point in the history
  • Loading branch information
myst6re authored Oct 20, 2024
1 parent 2f1bc05 commit 97424c2
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 12 deletions.
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

- Ambient: Fix missing Battle ID for battles triggered using field opcodes
- Ambient: Fix Battle ID detection for random encounters in Field
- Modding: Allow modding card names hardcoded in exe ( https://github.com/julianxhokaxhiu/FFNx/pull/739 )

# 1.20.3

Expand Down
123 changes: 111 additions & 12 deletions src/exe_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,24 @@
#include "saveload.h"

uint8_t *ff8_exe_scan_texts = nullptr;
uint8_t *ff8_exe_card_names = nullptr;

bool ff8_get_exe_path(const char *name, char *target_filename)
{
snprintf(target_filename, MAX_PATH, "%s/exe/%s.msd", direct_mode_path.c_str(), name);
normalize_path(target_filename);

return fileExists(target_filename);
}

bool ff8_get_battle_scan_texts_filename(char *filename)
{
snprintf(filename, MAX_PATH, "%s/exe/battle_scans.msd", direct_mode_path.c_str());
normalize_path(filename);
return ff8_get_exe_path("battle_scans", filename);
}

return fileExists(filename);
bool ff8_get_card_names_filename(char *filename)
{
return ff8_get_exe_path("card_names", filename);
}

void ff8_dump_battle_scan_texts()
Expand Down Expand Up @@ -76,19 +87,49 @@ void ff8_dump_battle_scan_texts()
fclose(f);
}

uint8_t *ff8_override_battle_scans()
void ff8_dump_card_names()
{
if (ff8_exe_scan_texts != nullptr) {
return ff8_exe_scan_texts;
uint8_t *data = *(uint8_t **)ff8_externals.card_name_positions;
uint16_t *positions = *(uint16_t **)ff8_externals.card_name_positions;
constexpr int text_count = 110;
uint16_t old_data_offset = (1 + text_count) * sizeof(uint16_t), new_data_offset = text_count * sizeof(uint32_t);
uint32_t offsets_rel_to_start[text_count] = {};
int higher_offset = 0;

for (int i = 0; i < text_count; ++i) {
offsets_rel_to_start[i] = positions[i + 1] - old_data_offset + new_data_offset;
if (positions[i + 1] > higher_offset) {
higher_offset = positions[i + 1];
}
}

for (int i = higher_offset; i < higher_offset + 1024; ++i) {
if (data[i] == '\0') {
higher_offset = i + 1;
break;
}
}

char filename[MAX_PATH] = {};
if (! ff8_get_battle_scan_texts_filename(filename)) {
if (trace_all || trace_direct) ffnx_warning("Direct file not found %s\n", filename);
if (ff8_get_card_names_filename(filename)) {
ffnx_warning("Save exe file skipped because the file [ %s ] already exists.\n", filename);

return nullptr;
return;
}

FILE *f = fopen(filename, "wb");

if (f == nullptr) {
return;
}

fwrite(offsets_rel_to_start, new_data_offset, 1, f);
fwrite(data + old_data_offset, higher_offset - old_data_offset, 1, f);
fclose(f);
}

uint8_t *ff8_open_msd(char *filename)
{
if (trace_all || trace_direct) ffnx_info("Direct file using %s\n", filename);

FILE *f = fopen(filename, "rb");
Expand All @@ -101,18 +142,54 @@ uint8_t *ff8_override_battle_scans()
long file_size = ftell(f);
fseek(f, 0, SEEK_SET);

ff8_exe_scan_texts = (uint8_t *)driver_malloc(file_size); // Allocated once, never freed
uint8_t *target_data = (uint8_t *)driver_malloc(file_size); // Allocated once, never freed

if (ff8_exe_scan_texts == nullptr) {
if (target_data == nullptr) {
return nullptr;
}

fread(ff8_exe_scan_texts, file_size, 1, f);
fread(target_data, file_size, 1, f);
fclose(f);

return target_data;
}

uint8_t *ff8_override_battle_scans()
{
if (ff8_exe_scan_texts != nullptr) {
return ff8_exe_scan_texts;
}

char filename[MAX_PATH] = {};
if (! ff8_get_battle_scan_texts_filename(filename)) {
if (trace_all || trace_direct) ffnx_warning("Direct file not found %s\n", filename);

return nullptr;
}

ff8_exe_scan_texts = ff8_open_msd(filename);

return ff8_exe_scan_texts;
}

uint8_t *ff8_override_card_names()
{
if (ff8_exe_card_names != nullptr) {
return ff8_exe_card_names;
}

char filename[MAX_PATH] = {};
if (! ff8_get_card_names_filename(filename)) {
if (trace_all || trace_direct) ffnx_warning("Direct file not found %s\n", filename);

return nullptr;
}

ff8_exe_card_names = ff8_open_msd(filename);

return ff8_exe_card_names;
}

uint8_t *ff8_battle_get_scan_text(uint8_t target_id)
{
uint8_t *direct_data_msd = ff8_override_battle_scans();
Expand All @@ -129,6 +206,26 @@ uint8_t *ff8_battle_get_scan_text(uint8_t target_id)
return ((uint8_t*(*)(uint8_t))ff8_externals.scan_get_text_sub_B687C0)(target_id);
}

char *ff8_get_card_name(int32_t card_id)
{
if (card_id >= 110) {
return nullptr;
}

uint8_t *direct_data_msd = ff8_override_card_names();
if (direct_data_msd != nullptr) {
uint32_t *positions = (uint32_t *)direct_data_msd;

if (trace_all) ffnx_trace("%s: get card name card_id=%d\n", __func__, card_id);

return (char *)direct_data_msd + positions[card_id];
}

uint16_t *positions = *(uint16_t **)ff8_externals.card_name_positions;

return *(char **)ff8_externals.card_name_positions + positions[card_id + 1];
}

void dump_exe_data()
{
char dirname[MAX_PATH] = {};
Expand All @@ -140,6 +237,7 @@ void dump_exe_data()
if (ff8)
{
ff8_dump_battle_scan_texts();
ff8_dump_card_names();
}
}

Expand All @@ -153,5 +251,6 @@ void exe_data_init()
if (ff8)
{
replace_call(ff8_externals.sub_84F8D0 + 0x88, ff8_battle_get_scan_text);
replace_function(ff8_externals.get_card_name, ff8_get_card_name);
}
}
5 changes: 5 additions & 0 deletions src/ff8.h
Original file line number Diff line number Diff line change
Expand Up @@ -1117,6 +1117,9 @@ struct ff8_externals
uint32_t sub_4B3140;
uint32_t sub_4BDB30;
ff8_menu_callback *menu_callbacks;
uint32_t menu_cards_render;
uint32_t sub_4EFC00;
uint32_t sub_4EFCD0;
uint32_t menu_config_controller;
uint32_t menu_config_render;
uint32_t menu_config_render_submenu;
Expand Down Expand Up @@ -1517,6 +1520,8 @@ struct ff8_externals
double *time_volume_change_related_1A78BE0;
uint32_t* game_mode_obj_1D9CF88;
uint32_t field_vars_stack_1CFE9B8;
uint32_t get_card_name;
uint32_t card_name_positions;
};

void ff8gl_field_78(struct ff8_polygon_set *polygon_set, struct ff8_game_obj *game_object);
Expand Down
5 changes: 5 additions & 0 deletions src/ff8_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,9 @@ void ff8_find_externals()
ff8_externals.sub_4B3140 = get_relative_call(ff8_externals.sub_4B3310, 0xC8);
ff8_externals.sub_4BDB30 = get_relative_call(ff8_externals.sub_4B3140, 0x4);
ff8_externals.menu_callbacks = (ff8_menu_callback *)get_absolute_value(ff8_externals.sub_4BDB30, 0x11);
ff8_externals.menu_cards_render = get_absolute_value(uint32_t(ff8_externals.menu_callbacks[7].func), 0x5);
ff8_externals.sub_4EFC00 = get_relative_call(ff8_externals.menu_cards_render, 0x2B6);
ff8_externals.sub_4EFCD0 = get_absolute_value(ff8_externals.sub_4EFC00, 0xB0);
ff8_externals.menu_config_render = get_absolute_value(uint32_t(ff8_externals.menu_callbacks[8].func), 0x3);
ff8_externals.menu_config_render_submenu = get_relative_call(ff8_externals.menu_config_render, 0x101);
ff8_externals.menu_config_controller = get_absolute_value(uint32_t(ff8_externals.menu_callbacks[8].func), 0x8);
Expand Down Expand Up @@ -826,6 +829,8 @@ void ff8_find_externals()
ff8_externals.battle_entities_1D27BCB = get_absolute_value(ff8_externals.scan_get_text_sub_B687C0, 0x18);
ff8_externals.scan_text_positions = get_absolute_value(ff8_externals.scan_get_text_sub_B687C0, 0x20);
ff8_externals.scan_text_data = get_absolute_value(ff8_externals.scan_get_text_sub_B687C0, 0x27);
ff8_externals.get_card_name = get_relative_call(ff8_externals.sub_4EFCD0, 0x89);
ff8_externals.card_name_positions = get_absolute_value(ff8_externals.get_card_name, 0xB);

ff8_externals.fps_limiter = get_relative_call(ff8_externals.field_main_loop, 0x261);
if (JP_VERSION)
Expand Down

0 comments on commit 97424c2

Please sign in to comment.