diff --git a/src/client/component/gameplay.cpp b/src/client/component/gameplay.cpp index 5939d40f..891ea57e 100644 --- a/src/client/component/gameplay.cpp +++ b/src/client/component/gameplay.cpp @@ -266,6 +266,52 @@ namespace gameplay vel_out[2] = new_z * length_scale; } } + + void* pm_can_start_sprint_stub() + { + return utils::hook::assemble([=](utils::hook::assembler& a) + { + const auto skip_jz = a.newLabel(); + const auto loc_2C98EF = a.newLabel(); + + // save rax's original value + a.push(rax); + + // move dvar pointer to rax + a.mov(rax, qword_ptr(reinterpret_cast(&dvars::pm_sprintInAir))); + + // move *(rax + 16) into al + a.mov(al, byte_ptr(rax, 0x10)); + + // compare al with 1 + a.cmp(al, 1); + + // restore rax to its original value + a.pop(rax); + + // jz == jump zero, jumps if the two operands in cmp are equal + a.jz(skip_jz); // skip the last cmp & jz + + // execute original code at 0x2C98C0 & 0x2C98C6 + // necessary because our jump overwrites 12 bytes after it + a.mov(eax, 0x7FF); // rax got overwritted by our long jump (it does mov rax, ; jmp rax) + a.cmp(word_ptr(rbx, 0x22), ax); + a.jz(loc_2C98EF); + + a.bind(skip_jz); + + // execute original code from 0x2C98C6 to 0x2C98CC + a.mov(edx, dword_ptr(rdi, 0x8)); + a.mov(rcx, rbx); + + // the section of code that was overwritten by our jump is finished so we can jump back to the game code + a.jmp(0x2C98CC_b); + + // original code + a.bind(loc_2C98EF); + a.jmp(0x2C98EF_b); + }); + } } class component final : public component_interface @@ -307,6 +353,10 @@ namespace gameplay utils::hook::jump(0x3FF812_b, client_end_frame_stub(), true); utils::hook::nop(0x3FF808_b, 1); + dvars::pm_sprintInAir = dvars::register_bool("pm_sprintInAir", false, + game::DVAR_FLAG_REPLICATED, "Enable Mid-Air Sprinting"); + utils::hook::jump(0x2C98C0_b, pm_can_start_sprint_stub(), true); + auto* timescale = dvars::register_float("timescale", 1.0f, 0.1f, 50.0f, game::DVAR_FLAG_REPLICATED, "Changes Timescale of the game"); utils::hook::inject(0x15B204_b, ×cale->current.value); // Com_GetTimeScale utils::hook::inject(0x17D243_b, ×cale->current.value); // Com_Restart diff --git a/src/client/game/dvars.cpp b/src/client/game/dvars.cpp index 0db9ad56..739a087a 100644 --- a/src/client/game/dvars.cpp +++ b/src/client/game/dvars.cpp @@ -32,6 +32,7 @@ namespace dvars game::dvar_t* pm_bouncing = nullptr; game::dvar_t* pm_bouncingAllAngles = nullptr; + game::dvar_t* pm_sprintInAir = nullptr; game::dvar_t* jump_ladderPushVel = nullptr; diff --git a/src/client/game/dvars.hpp b/src/client/game/dvars.hpp index 9225a8ca..d884877f 100644 --- a/src/client/game/dvars.hpp +++ b/src/client/game/dvars.hpp @@ -35,6 +35,7 @@ namespace dvars extern game::dvar_t* pm_bouncing; extern game::dvar_t* pm_bouncingAllAngles; + extern game::dvar_t* pm_sprintInAir; extern game::dvar_t* jump_ladderPushVel;