diff --git a/src/client/component/free_move.cpp b/src/client/component/free_move.cpp new file mode 100644 index 0000000..15cd6fc --- /dev/null +++ b/src/client/component/free_move.cpp @@ -0,0 +1,76 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include "command.hpp" + +#include + +namespace free_move { +namespace { +void cg_noclip_f() { + if (!game::cgArray[game::LOCAL_CLIENT_0].nextSnap) { + return; + } + + if (!(*dvars::sv_cheats)->current.enabled) { + game::Com_Printf(game::CON_CHANNEL_SYSTEM, "%s is cheat protected.\n", + "cg_noclip"); + return; + } + + if ((*dvars::cl_freemove)->current.integer == 1) { + if ((*dvars::cg_paused)->current.integer == 2) { + game::Dvar_SetInt(*dvars::cg_paused, 1); + } + } + + game::Dvar_SetInt(*dvars::cl_freemove, + (*dvars::cl_freemove)->current.integer == 1 ? 0 : 1); + game::Com_Printf( + game::CON_CHANNEL_DONT_FILTER, "%s\n", + game::SEH_LocalizeTextMessage((*dvars::cl_freemove)->current.integer == 1 + ? "GAME_NOCLIPON" + : "GAME_NOCLIPOFF", + "noclip print", game::LOCMSG_SAFE)); +} + +void cg_ufo_f() { + if (!game::cgArray[game::LOCAL_CLIENT_0].nextSnap) { + return; + } + + if (!(*dvars::sv_cheats)->current.enabled) { + game::Com_Printf(game::CON_CHANNEL_SYSTEM, "%s is cheat protected.\n", + "cg_ufo"); + return; + } + + if ((*dvars::cl_freemove)->current.integer == 2) { + if ((*dvars::cg_paused)->current.integer == 2) { + game::Dvar_SetInt(*dvars::cg_paused, 1); + } + } + + game::Dvar_SetInt(*dvars::cl_freemove, + (*dvars::cl_freemove)->current.integer == 2 ? 0 : 2); + game::Com_Printf( + game::CON_CHANNEL_DONT_FILTER, "%s\n", + game::SEH_LocalizeTextMessage((*dvars::cl_freemove)->current.integer == 2 + ? "GAME_UFOON" + : "GAME_UFOOFF", + "ufo print", game::LOCMSG_SAFE)); +} +} // namespace + +class component final : public component_interface { +public: + void post_load() override { + command::add("cg_noclip", cg_noclip_f); + command::add("cg_ufo", cg_ufo_f); + } +}; +} // namespace free_move + +REGISTER_COMPONENT(free_move::component) diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp index bf64ac9..597bac9 100644 --- a/src/client/component/patches.cpp +++ b/src/client/component/patches.cpp @@ -72,31 +72,34 @@ void __declspec(naked) string_table_get_column_value_for_row() { static const char* fmt = "Looking up row %i, column %i of table \'%s\' results in an empty string " "(first column is %s, second column is %s for that row)\n"; - static const DWORD Com_PrintError = 0x4C6980; + static const DWORD Com_PrintError_t = 0x4C6980; + + using namespace game; // EAX is safe to reuse because it's nuked by the game's code after this stub exits __asm { // game's code - mov eax, dword ptr [ecx + eax * 0x8] - push edx - push eax + mov eax, dword ptr [ecx + eax * 0x8]; + push edx; + push eax; - mov eax, [esp + 0xC] // get table pointer - mov eax, [eax] // get table->name - push eax + mov eax, [esp + 0xC]; // get table pointer + mov eax, [eax]; // get table->name + push eax; // game's code - push edi // column - push ebx // row + push edi; // column + push ebx; // row - push fmt + // game's format string + push fmt; - push 0xD // channel - call Com_PrintError - add esp, 0x1C + push CON_CHANNEL_UI; // channel + call Com_PrintError_t; + add esp, 0x1C; - push 0x4BC84E - ret + push 0x4BC84E; + ret; } } // clang-format on diff --git a/src/client/game/dvars.cpp b/src/client/game/dvars.cpp index d73bb96..c692bb5 100644 --- a/src/client/game/dvars.cpp +++ b/src/client/game/dvars.cpp @@ -25,11 +25,21 @@ const game::dvar_t* bug_name = nullptr; const game::dvar_t* g_log = nullptr; // Game dvars +const game::dvar_t** cg_paused = + reinterpret_cast(0x86D7C0); + +const game::dvar_t** cl_freemove = + reinterpret_cast(0x89776C); +const game::dvar_t** cl_freemoveScale = + reinterpret_cast(0x897750); + const game::dvar_t** g_specialops = reinterpret_cast(0x1B2E1E8); const game::dvar_t** sv_mapname = reinterpret_cast(0x1B2E1E4); +const game::dvar_t** sv_cheats = + reinterpret_cast(0x1B2E1EC); const game::dvar_t** version = reinterpret_cast(0x145D690); diff --git a/src/client/game/dvars.hpp b/src/client/game/dvars.hpp index d6494cc..bafde14 100644 --- a/src/client/game/dvars.hpp +++ b/src/client/game/dvars.hpp @@ -25,9 +25,15 @@ extern const game::dvar_t* bug_name; extern const game::dvar_t* g_log; // Game dvars +extern const game::dvar_t** cg_paused; + +extern const game::dvar_t** cl_freemove; +extern const game::dvar_t** cl_freemoveScale; + extern const game::dvar_t** g_specialops; extern const game::dvar_t** sv_mapname; +extern const game::dvar_t** sv_cheats; extern const game::dvar_t** version; diff --git a/src/client/game/game.cpp b/src/client/game/game.cpp index 7a3cae4..5404b58 100644 --- a/src/client/game/game.cpp +++ b/src/client/game/game.cpp @@ -3,7 +3,7 @@ namespace game { int FS_FOpenFileReadForThread(const char* filename, int* file, FsThread thread) { - const static DWORD FS_FOpenFileReadForThread_t = 0x630380; + static const DWORD FS_FOpenFileReadForThread_t = 0x630380; int result{}; __asm { @@ -23,7 +23,7 @@ int FS_FOpenFileReadForThread(const char* filename, int* file, } void IN_KeyDown(kbutton_t* b) { - const static DWORD IN_KeyDown_t = 0x57A350; + static const DWORD IN_KeyDown_t = 0x57A350; __asm { pushad; @@ -36,7 +36,7 @@ void IN_KeyDown(kbutton_t* b) { } void IN_KeyUp(kbutton_t* b) { - const static DWORD IN_KeyUp_t = 0x57A3F0; + static const DWORD IN_KeyUp_t = 0x57A3F0; __asm { pushad; @@ -94,7 +94,7 @@ HANDLE Sys_OpenFileReliable(const char* filename) { } int PC_Int_Parse(int handle, int* i) { - const static DWORD PC_Int_Parse_t = 0x62DF10; + static const DWORD PC_Int_Parse_t = 0x62DF10; int result{}; __asm { @@ -112,7 +112,7 @@ int PC_Int_Parse(int handle, int* i) { } int PC_Float_Parse(int handle, float* f) { - const static DWORD PC_Float_Parse_t = 0x62DE40; + static const DWORD PC_Float_Parse_t = 0x62DE40; int result{}; __asm { @@ -130,7 +130,7 @@ int PC_Float_Parse(int handle, float* f) { } void Menu_FreeItemMemory(itemDef_s* item) { - const static DWORD Menu_FreeItemMemory_t = 0x62B7E0; + static const DWORD Menu_FreeItemMemory_t = 0x62B7E0; __asm { pushad; diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index d7fd699..7da37ee 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -369,6 +369,11 @@ enum { VAR_INTEGER = 0x6, }; +enum msgLocErrType_t { + LOCMSG_SAFE = 0x0, + LOCMSG_NOERR = 0x1, +}; + enum { CON_CHANNEL_DONT_FILTER = 0x0, CON_CHANNEL_ERROR = 0x1, @@ -1745,6 +1750,109 @@ struct localization_t { struct Sys_File { HANDLE handle; }; + +enum ShockViewTypes { + SHELLSHOCK_VIEWTYPE_BLURRED = 0x0, + SHELLSHOCK_VIEWTYPE_FLASHED = 0x1, + SHELLSHOCK_VIEWTYPE_NONE = 0x2, +}; + +struct shellshock_parms_t { + struct { + int blurredFadeTime; + int blurredEffectTime; + int flashWhiteFadeTime; + int flashShotFadeTime; + ShockViewTypes type; + } screenBlend; + struct { + int fadeTime; + float kickRate; + float kickRadius; + } view; + struct { + bool affect; + char loop[64]; + char loopSilent[64]; + char end[64]; + char endAbort[64]; + int fadeInTime; + int fadeOutTime; + float drylevel; + float wetlevel; + char roomtype[16]; + float channelvolume[64]; + int modEndDelay; + int loopFadeTime; + int loopEndDelay; + } sound; + struct { + bool affect; + int fadeTime; + float mouseSensitivity; + float maxPitchSpeed; + float maxYawSpeed; + } lookControl; + struct { + bool affect; + } movement; +}; + +struct cgs_t { + int viewX; + int viewY; + int viewWidth; + int viewHeight; + float viewAspect; + bool started; + shellshock_parms_t holdBreathParams; +}; + +static_assert(sizeof(cgs_t) == 0x280); + +struct cpose_t { + unsigned char __pad0[0x64]; +}; + +static_assert(sizeof(cpose_t) == 0x64); + +enum CubemapShot { + CUBEMAPSHOT_NONE = 0x0, + CUBEMAPSHOT_RIGHT = 0x1, + CUBEMAPSHOT_LEFT = 0x2, + CUBEMAPSHOT_BACK = 0x3, + CUBEMAPSHOT_FRONT = 0x4, + CUBEMAPSHOT_UP = 0x5, + CUBEMAPSHOT_DOWN = 0x6, + CUBEMAPSHOT_COUNT = 0x7, +}; + +struct snapshot_s { + int snapFlags; + int serverTime; + int numEntities; + unsigned __int16 entityNums[2048]; + int numFxEntities; + unsigned __int16 fxEntityNums[768]; +}; + +struct cg_s { + int clientNum; + int localClientNum; + CubemapShot cubemapShot; + int cubemapSize; + int serverCommandSequence; + int serverLatestCommandSequence; + int loaded; + snapshot_s* snap; + snapshot_s* nextSnap; + playerState_s* ps; + playerState_s* nextPs; +}; // Incomplete + +static_assert(offsetof(cg_s, snap) == 0x1C); +static_assert(offsetof(cg_s, nextSnap) == 0x20); +static_assert(offsetof(cg_s, nextPs) == 0x28); } // namespace game #pragma warning(pop) diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 1913343..830d69c 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -24,6 +24,9 @@ WEAK symbol va{0x4869F0}; // Con WEAK symbol Con_IsDvarCommand{0x4B6610}; +// SV +WEAK symbol SV_ClientThink{0x4B43D0}; + // ScrPlace WEAK symbol ScrPlace_GetActivePlacement{ 0x4D2A60}; @@ -289,11 +292,17 @@ WEAK symbol R_TextWidth{ 0x508960}; +WEAK symbol + SEH_LocalizeTextMessage{0x4CD8D0}; + // Variables WEAK symbol cmd_args{0x144FED0}; WEAK symbol sv_cmd_args{0x145ABA0}; WEAK symbol g_entities{0xEAAC38}; WEAK symbol g_clients{0x10911E8}; +WEAK symbol cgsArray{0x762008}; +WEAK symbol cgArray{0x7622A0}; WEAK symbol scrVmPub{0x190DDF0}; WEAK symbol scrVarPub{0x18E7508};