Skip to content

Commit

Permalink
fix crash then there is no tiamat in tiamat level, add `set_tiamat_cu…
Browse files Browse the repository at this point in the history
…tscene_enabled`, break olmec fix for now
  • Loading branch information
Mr-Auto committed Sep 23, 2023
1 parent a6850df commit a47fa49
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 28 deletions.
109 changes: 82 additions & 27 deletions src/game_api/game_patches.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,34 +50,23 @@ void patch_orbs_limit()
once = true;
}

void clear_cutscene_behavior()
bool check_if_ent_type_exists(ENT_TYPE type, int mask)
{
StateMemory* state = State::get().ptr_local();
if (state == nullptr)
state = State::get().ptr_main();

// loop thru entities mask 7
const auto entities_map = &state->layers[0]->entities_by_mask;
for (uint8_t mask = 1; mask < 7; mask <<= 1)
const auto entities_map = &state->layers[0]->entities_by_mask; // game code only cares about the front layer, so we do the same
auto it = entities_map->find(mask);
if (it == entities_map->end())
return false;

for (auto entity : it->second.entities())
{
auto it = entities_map->find(mask);
if (it == entities_map->end())
continue;
for (auto entity : it->second.entities())
{
auto mov = entity->as<Movable>();
if (mov->ic8 != nullptr)
{
mov->ic8->~CutsceneBehavior();
mov->ic8 = nullptr;
}
}
if (entity->type->id == type)
return true;
}
// fix the camera bound
state->camera->bounds_bottom = 66.75;

// some bs, don't worry about it
state->entity_lookup->unknown3 = state->entity_lookup->unknown4;
return false;
}

void patch_olmec_kill_crash()
Expand Down Expand Up @@ -124,9 +113,9 @@ void patch_olmec_kill_crash()
auto jump_addr = memory.at_exe(end_function_jump);
auto addr_to_jump_to = jump_addr + 6 + memory_read<int32_t>(jump_addr + 2);
std::string clear_ic8_code = fmt::format(
"\x48\xb8{}" // movabs RAX, &clear_cutscene_behavior
"\xff\xd0"sv, // call RAX
to_le_bytes((size_t)&clear_cutscene_behavior));
"\x48\xb8{}" // movabs RAX, &clear_cutscene_behavior
"\xff\xd0"sv // call RAX
);

/* The idea:
* replace end of the loop jump with jump to the new code
Expand All @@ -142,7 +131,7 @@ void patch_olmec_kill_crash()
* if it's not the end of the array it's looking for olmec, jump back to the oryginal code via jump in `new_code`
* if it's end of the array (no olmec found) jump to return_addr
* the place for return_addr was kind of choosen by feel, as the code is complicated
* the whole point of the patched code is to find olmec and check it's faze, maybe for the music?
* the whole point of the patched code is to find olmec and check it's faze, maybe for the music? no idea
*/

std::string_view new_code{
Expand All @@ -158,11 +147,65 @@ void patch_olmec_kill_crash()
once = true;
}

size_t g_tiamat_patch_size;
size_t g_tiamat_patch_addr;

void patch_tiamat_kill_crash()
{
static bool once = false;
if (once)
return;

auto memory = Memory::get();
const auto patch_addr = get_address("tiamat_lookup_in_theme");
if (patch_addr == 0)
return;

size_t return_to_addr;
{
// find end of the function that sets the camera and stuff
auto rva = patch_addr - memory.exe_ptr;
auto rva_jumpout_to = find_inst(memory.exe(), "\x49\x89\x0C\xC6"sv, rva, rva + 0x5C7, "patch_tiamat_kill_crash");
if (rva_jumpout_to == 0)
return;

return_to_addr = memory.at_exe(rva_jumpout_to + 4); // +4 - after pattern
}

std::string new_code = fmt::format(
"\xb9{}"sv // mov ecx, ENT_TYPE
"\xba\x04\x00\x00\x00"sv // mov edx, 0x4 (MASK::MONSTER)
"\x48\xb8{}"sv // movabs RAX, &check_if_ent_type_exists
"\xff\xd0"sv // call RAX
"\x84\xc0"sv // test al, al
"\x0f\x85\x00\x00\x00\x00"sv, // jnz (offset needs to be updated after we know the address)
to_le_bytes(to_id("ENT_TYPE_MONS_TIAMAT")),
to_le_bytes((size_t)&check_if_ent_type_exists));

/* The idea:
* After state.screen == screen::level check, we plug our code
* it calls simple function to check if entity exists (tiamat in this case)
* if tiamat is found, we jump back to the original code, if not, jump to return_to_addr
* we can kind of ignore the replaced game code as it sets R14 register
* so we let patch_and_redirect just copy before our new code
*/
constexpr int copy_over_code_size = 7;
g_tiamat_patch_size = new_code.size() + copy_over_code_size; // without the final jump added by patch_and_redirect

g_tiamat_patch_addr = patch_and_redirect(patch_addr, copy_over_code_size, new_code, false, return_to_addr);

auto jump_addr = g_tiamat_patch_addr + g_tiamat_patch_size;
int32_t rel = static_cast<int32_t>(patch_addr + copy_over_code_size - jump_addr);
write_mem_prot(jump_addr - 4, rel, true); // update the jump offset

once = true;
}

void patch_liquid_OOB()
{
/*
* The idea:
* there is a loop thru all liquid entities
* there is a loop thru all liquid entities (probably for the collision stuff)
* if liquid is out of bounds (coordinate below 0) we essentially simulate `continue;` behavior
*/

Expand Down Expand Up @@ -192,7 +235,7 @@ void patch_liquid_OOB()
"\x48\x83\xFD\x00"sv // cmp ebp,0x0 (ebp = y)
"\x0f\x8C\x00\x00\x00\x00"sv // jl (offset needs to be updated after we know the address)
"\x48\x83\xfa\x00" // cmp rdx,0x0 (rdx = x)
"\x0f\x8C\x00\x00\x00\x00"sv}; // jl (same offset as before)
"\x0f\x8C\x00\x00\x00\x00"sv}; // jl (same jump as before)

auto new_code_addr = patch_and_redirect(offset, code_to_move, new_code);
new_code_addr += code_to_move;
Expand All @@ -215,3 +258,15 @@ void set_skip_olmec_cutscene(bool skip)
else
recover_mem("set_skip_olmec_cutscene");
}

void set_skip_tiamat_cutscene(bool skip)
{
patch_tiamat_kill_crash(); // just in case

// simple jump over the tiamat check, nop here just so there is no funny business
static const std::string code = fmt::format("\xEB{}\x90"sv, to_le_bytes(static_cast<int8_t>(g_tiamat_patch_size - 2)));
if (skip)
write_mem_recoverable("set_skip_tiamat_cutscene", g_tiamat_patch_addr, code, true);
else
recover_mem("set_skip_tiamat_cutscene");
}
2 changes: 2 additions & 0 deletions src/game_api/game_patches.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ void patch_orbs_limit();
void patch_olmec_kill_crash();
void patch_liquid_OOB();
void set_skip_olmec_cutscene(bool skip);
void patch_tiamat_kill_crash();
void set_skip_tiamat_cutscene(bool skip);
5 changes: 5 additions & 0 deletions src/game_api/rpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1886,3 +1886,8 @@ void set_olmec_cutscene_enabled(bool enable)
{
set_skip_olmec_cutscene(!enable);
}

void set_tiamat_cutscene_enabled(bool enable)
{
set_skip_tiamat_cutscene(!enable);
}
1 change: 1 addition & 0 deletions src/game_api/rpc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,4 @@ void save_progress();
void set_level_string(std::u16string_view text);
void set_ending_unlock(ENT_TYPE type);
void set_olmec_cutscene_enabled(bool enable);
void set_tiamat_cutscene_enabled(bool enable);
2 changes: 2 additions & 0 deletions src/game_api/script/lua_vm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2016,6 +2016,8 @@ end

lua["set_olmec_cutscene_enabled"] = set_olmec_cutscene_enabled;

lua["set_tiamat_cutscene_enabled"] = set_tiamat_cutscene_enabled;

lua.create_named_table("INPUTS", "NONE", 0, "JUMP", 1, "WHIP", 2, "BOMB", 4, "ROPE", 8, "RUN", 16, "DOOR", 32, "MENU", 64, "JOURNAL", 128, "LEFT", 256, "RIGHT", 512, "UP", 1024, "DOWN", 2048);

lua.create_named_table(
Expand Down
9 changes: 9 additions & 0 deletions src/game_api/search.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1993,6 +1993,15 @@ std::unordered_map<std::string_view, AddressRule> g_address_rules{
.offset(0x5)
.at_exe(),
},
{
"tiamat_lookup_in_theme"sv,
// find the first jump in the virtual that skips the whole function
PatternCommandBuffer{}
.get_virtual_function_address(VTABLE_OFFSET::THEME_TIAMAT, (VIRT_FUNC)24) // spawn_effects
.find_after_inst("83 78 0C 0C"_gh)
.offset(0x6) // after the jump instruction
.at_exe(),
},
};
std::unordered_map<std::string_view, size_t> g_cached_addresses;

Expand Down
3 changes: 2 additions & 1 deletion src/game_api/state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,9 @@ State& State::get()
init_state_update_hook();

// game patches
patch_tiamat_kill_crash();
patch_orbs_limit();
patch_olmec_kill_crash();
//patch_olmec_kill_crash();
patch_liquid_OOB();
}

Expand Down

0 comments on commit a47fa49

Please sign in to comment.