iw4x-client/src/Components/Modules/Movement.cpp

357 lines
12 KiB
C++
Raw Normal View History

2022-02-27 07:53:44 -05:00
#include <STDInclude.hpp>
2021-11-07 06:16:56 -05:00
namespace Components
{
Dvar::Var Movement::PlayerDuckedSpeedScale;
Dvar::Var Movement::PlayerLastStandCrawlSpeedScale;
Dvar::Var Movement::PlayerProneSpeedScale;
2022-01-07 06:20:43 -05:00
Dvar::Var Movement::PlayerSpectateSpeedScale;
Dvar::Var Movement::CGUfoScaler;
Dvar::Var Movement::CGNoclipScaler;
2022-01-18 19:49:50 -05:00
Dvar::Var Movement::BGBouncesAllAngles;
2022-02-05 11:24:59 -05:00
Dvar::Var Movement::BGRocketJump;
2022-02-09 13:02:42 -05:00
Dvar::Var Movement::BGPlayerEjection;
Dvar::Var Movement::BGPlayerCollision;
2022-01-18 19:49:50 -05:00
Game::dvar_t* Movement::BGBounces;
2021-11-07 06:16:56 -05:00
2022-01-07 06:20:43 -05:00
float Movement::PM_CmdScaleForStance(const Game::pmove_s* pm)
2021-11-07 06:16:56 -05:00
{
2022-01-07 06:20:43 -05:00
assert(pm->ps != nullptr);
2021-11-07 06:16:56 -05:00
2022-01-07 06:20:43 -05:00
const auto* playerState = pm->ps;
2021-11-07 06:16:56 -05:00
float scale;
if (playerState->viewHeightLerpTime != 0 && playerState->viewHeightLerpTarget == 0xB)
{
2022-01-07 06:20:43 -05:00
scale = pm->cmd.serverTime - playerState->viewHeightLerpTime / 400.0f;
2021-11-07 06:16:56 -05:00
if (0.0f <= scale)
{
2022-01-07 06:20:43 -05:00
if (scale > 1.0f)
2021-11-07 06:16:56 -05:00
{
scale = 1.0f;
return scale * 0.15f + (1.0f - scale) * 0.65f;
}
if (scale != 0.0f)
{
return scale * 0.15f + (1.0f - scale) * 0.65f;
}
}
}
if ((playerState->viewHeightLerpTime != 0 && playerState->viewHeightLerpTarget == 0x28) &&
playerState->viewHeightLerpDown == 0)
{
2022-01-07 06:20:43 -05:00
scale = 400.0f / pm->cmd.serverTime - playerState->viewHeightLerpTime;
2021-11-07 06:16:56 -05:00
if (0.0f <= scale)
{
2022-01-07 06:20:43 -05:00
if (scale > 1.0f)
2021-11-07 06:16:56 -05:00
{
scale = 1.0f;
}
else if (scale != 0.0f)
{
return scale * 0.65f + (1.0f - scale) * 0.15f;
}
}
}
scale = 1.0f;
2022-01-07 06:20:43 -05:00
const auto stance = Game::PM_GetEffectiveStance(playerState);
2021-11-07 06:16:56 -05:00
if (stance == Game::PM_EFF_STANCE_PRONE)
{
scale = Movement::PlayerProneSpeedScale.get<float>();
}
else if (stance == Game::PM_EFF_STANCE_DUCKED)
{
scale = Movement::PlayerDuckedSpeedScale.get<float>();
}
else if (stance == Game::PM_EFF_STANCE_LASTSTANDCRAWL)
{
scale = Movement::PlayerLastStandCrawlSpeedScale.get<float>();
}
return scale;
}
2022-01-07 06:20:43 -05:00
__declspec(naked) void Movement::PM_CmdScaleForStanceStub()
2021-11-07 06:16:56 -05:00
{
__asm
{
pushad
push edx
2022-02-09 06:41:10 -05:00
call Movement::PM_CmdScaleForStance // pm
2021-11-07 06:16:56 -05:00
add esp, 4
popad
ret
}
}
2022-01-07 06:20:43 -05:00
float Movement::PM_MoveScale(Game::playerState_s* ps, float forwardmove,
float rightmove, float upmove)
2021-11-11 08:38:51 -05:00
{
2022-01-07 06:20:43 -05:00
assert(ps != nullptr);
auto max = (std::fabsf(forwardmove) < std::fabsf(rightmove))
? std::fabsf(rightmove)
: std::fabsf(forwardmove);
if (std::fabsf(upmove) > max)
{
max = std::fabsf(upmove);
}
if (max == 0.0f)
{
return 0.0f;
}
auto total = std::sqrtf(forwardmove * forwardmove
+ rightmove * rightmove + upmove * upmove);
auto scale = (ps->speed * max) / (127.0f * total);
if (ps->pm_flags & Game::PMF_WALKING || ps->leanf != 0.0f)
{
scale *= 0.4f;
}
if (ps->pm_type == Game::PM_NOCLIP)
{
return scale * Movement::CGNoclipScaler.get<float>();
}
if (ps->pm_type == Game::PM_UFO)
{
return scale * Movement::CGUfoScaler.get<float>();
}
if (ps->pm_type == Game::PM_SPECTATOR)
{
return scale * Movement::PlayerSpectateSpeedScale.get<float>();
}
return scale;
}
__declspec(naked) void Movement::PM_MoveScaleStub()
{
__asm
{
pushad
2022-02-09 06:41:10 -05:00
push [esp + 0xC + 0x20] // upmove
push [esp + 0xC + 0x20] // rightmove
push [esp + 0xC + 0x20] // forwardmove
push esi // ps
2022-01-07 06:20:43 -05:00
call Movement::PM_MoveScale
add esp, 0x10
popad
ret
}
}
2022-01-18 19:49:50 -05:00
__declspec(naked) void Movement::PM_StepSlideMoveStub()
{
__asm
{
2022-01-18 19:53:06 -05:00
// Check the value of BGBounces
2022-01-18 19:49:50 -05:00
push ecx
push eax
mov eax, Movement::BGBounces
mov ecx, dword ptr [eax + 0x10]
test ecx, ecx
pop eax
pop ecx
2022-01-18 19:53:06 -05:00
// Do not bounce if BGBounces is 0
2022-01-18 19:49:50 -05:00
jle noBounce
// Bounce
push 0x4B1B34
retn
noBounce:
2022-02-09 06:41:10 -05:00
// Original game code
2022-01-18 19:49:50 -05:00
cmp dword ptr [esp + 0x24], 0
push 0x4B1B48
retn
}
}
void Movement::PM_ProjectVelocityStub(const float* velIn, const float* normal, float* velOut)
{
2022-01-19 05:48:33 -05:00
const auto lengthSquared2D = velIn[0] * velIn[0] + velIn[1] * velIn[1];
2022-01-18 19:49:50 -05:00
if (std::fabsf(normal[2]) < 0.001f || lengthSquared2D == 0.0)
{
velOut[0] = velIn[0];
velOut[1] = velIn[1];
velOut[2] = velIn[2];
return;
}
auto newZ = velIn[0] * normal[0] + velIn[1] * normal[1];
newZ = -newZ / normal[2];
2022-01-19 05:48:33 -05:00
const auto lengthScale = std::sqrtf((velIn[2] * velIn[2] + lengthSquared2D)
2022-01-18 19:49:50 -05:00
/ (newZ * newZ + lengthSquared2D));
if (Movement::BGBouncesAllAngles.get<bool>()
|| (lengthScale < 1.f || newZ < 0.f || velIn[2] > 0.f))
{
velOut[0] = velIn[0] * lengthScale;
velOut[1] = velIn[1] * lengthScale;
velOut[2] = newZ * lengthScale;
}
}
// Double bounces
2022-02-13 19:09:46 -05:00
void Movement::Jump_ClearState_Hk(Game::playerState_s* ps)
2022-01-18 19:49:50 -05:00
{
2022-02-13 19:09:46 -05:00
if (Movement::BGBounces->current.integer != Movement::DOUBLE)
{
Game::Jump_ClearState(ps);
}
2022-01-18 19:49:50 -05:00
}
2022-02-05 11:24:59 -05:00
Game::gentity_s* Movement::Weapon_RocketLauncher_Fire_Hk(Game::gentity_s* ent, unsigned int weaponIndex,
float spread, Game::weaponParms* wp, const float* gunVel, Game::lockonFireParms* lockParms, bool a7)
{
auto* result = Game::Weapon_RocketLauncher_Fire(ent, weaponIndex, spread, wp, gunVel, lockParms, a7);
if (ent->client != nullptr && BGRocketJump.get<bool>())
{
ent->client->ps.velocity[0] += (0 - wp->forward[0]) * 64.0f;
ent->client->ps.velocity[1] += (0 - wp->forward[1]) * 64.0f;
ent->client->ps.velocity[2] += (0 - wp->forward[2]) * 64.0f;
}
return result;
}
2022-02-09 13:02:42 -05:00
int Movement::StuckInClient_Hk(Game::gentity_s* self)
{
if (Movement::BGPlayerEjection.get<bool>())
{
return Utils::Hook::Call<int(Game::gentity_s*)>(0x402D30)(self); // StuckInClient
}
return 0;
}
void Movement::CM_TransformedCapsuleTrace_Hk(Game::trace_t* results, const float* start, const float* end,
const Game::Bounds* bounds, const Game::Bounds* capsule, int contents, const float* origin, const float* angles)
{
if (Movement::BGPlayerCollision.get<bool>())
{
Utils::Hook::Call<void(Game::trace_t*, const float*, const float*,
const Game::Bounds*, const Game::Bounds*, int, const float*, const float*)>
(0x478300)
(results, start, end, bounds, capsule, contents, origin, angles); // CM_TransformedCapsuleTrace
}
}
Game::dvar_t* Movement::Dvar_RegisterLastStandSpeedScale(const char* dvarName, float value,
float min, float max, unsigned __int16 /*flags*/, const char* description)
2022-01-07 06:20:43 -05:00
{
Movement::PlayerLastStandCrawlSpeedScale = Dvar::Register<float>(dvarName, value,
min, max, Game::DVAR_CHEAT | Game::DVAR_CODINFO, description);
2021-11-11 08:38:51 -05:00
return Movement::PlayerLastStandCrawlSpeedScale.get<Game::dvar_t*>();
}
Game::dvar_t* Movement::Dvar_RegisterSpectateSpeedScale(const char* dvarName, float value,
float min, float max, unsigned __int16 /*flags*/, const char* description)
2022-01-07 06:20:43 -05:00
{
Movement::PlayerSpectateSpeedScale = Dvar::Register<float>(dvarName, value,
min, max, Game::DVAR_CHEAT | Game::DVAR_CODINFO, description);
2022-01-07 06:20:43 -05:00
return Movement::PlayerSpectateSpeedScale.get<Game::dvar_t*>();
}
2021-11-07 06:16:56 -05:00
Movement::Movement()
{
Dvar::OnInit([]
{
2022-01-19 05:48:33 -05:00
static const char* bg_bouncesValues[] =
2022-01-18 19:49:50 -05:00
{
"disabled",
"enabled",
"double",
nullptr
};
2021-11-07 06:16:56 -05:00
Movement::PlayerDuckedSpeedScale = Dvar::Register<float>("player_duckedSpeedScale",
0.65f, 0.0f, 5.0f, Game::DVAR_CHEAT | Game::DVAR_CODINFO,
2021-11-07 06:16:56 -05:00
"The scale applied to the player speed when ducking");
Movement::PlayerProneSpeedScale = Dvar::Register<float>("player_proneSpeedScale",
0.15f, 0.0f, 5.0f, Game::DVAR_CHEAT | Game::DVAR_CODINFO,
2021-11-07 06:16:56 -05:00
"The scale applied to the player speed when crawling");
2022-01-07 06:20:43 -05:00
2022-02-09 13:02:42 -05:00
// 3arc naming convention
2022-01-07 06:20:43 -05:00
Movement::CGUfoScaler = Dvar::Register<float>("cg_ufo_scaler",
6.0f, 0.001f, 1000.0f, Game::DVAR_CHEAT | Game::DVAR_CODINFO,
2022-01-07 06:20:43 -05:00
"The speed at which ufo camera moves");
Movement::CGNoclipScaler = Dvar::Register<float>("cg_noclip_scaler",
3.0f, 0.001f, 1000.0f, Game::DVAR_CHEAT | Game::DVAR_CODINFO,
2022-01-07 06:20:43 -05:00
"The speed at which noclip camera moves");
2022-01-18 19:49:50 -05:00
Movement::BGBounces = Game::Dvar_RegisterEnum("bg_bounces",
bg_bouncesValues, Movement::DISABLED, Game::DVAR_CODINFO, "Bounce glitch settings");
2022-01-18 19:49:50 -05:00
Movement::BGBouncesAllAngles = Dvar::Register<bool>("bg_bouncesAllAngles",
false, Game::DVAR_CODINFO, "Force bounce from all angles");
2022-02-05 11:24:59 -05:00
Movement::BGRocketJump = Dvar::Register<bool>("bg_rocketJump",
false, Game::DVAR_CODINFO, "Enable CoD4 rocket jumps");
2022-02-09 13:02:42 -05:00
Movement::BGPlayerEjection = Dvar::Register<bool>("bg_playerEjection",
true, Game::DVAR_CODINFO, "Push intersecting players away from each other");
2022-02-09 13:02:42 -05:00
Movement::BGPlayerCollision = Dvar::Register<bool>("bg_playerCollision",
true, Game::DVAR_CODINFO, "Push intersecting players away from each other");
2021-11-07 06:16:56 -05:00
});
2021-11-11 08:38:51 -05:00
// Hook PM_CmdScaleForStance in PM_CmdScale_Walk
2022-01-07 06:20:43 -05:00
Utils::Hook(0x572F34, Movement::PM_CmdScaleForStanceStub, HOOK_CALL).install()->quick();
2021-11-11 08:38:51 -05:00
//Hook PM_CmdScaleForStance in PM_GetMaxSpeed
2022-01-07 06:20:43 -05:00
Utils::Hook(0x57395F, Movement::PM_CmdScaleForStanceStub, HOOK_CALL).install()->quick();
2021-11-11 08:38:51 -05:00
// Hook Dvar_RegisterFloat. Only thing that's changed is that the 0x80 flag is not used.
Utils::Hook(0x448B66, Movement::Dvar_RegisterLastStandSpeedScale, HOOK_CALL).install()->quick();
2022-01-07 06:20:43 -05:00
// Hook Dvar_RegisterFloat. Only thing that's changed is that the 0x80 flag is not used.
Utils::Hook(0x448990, Movement::Dvar_RegisterSpectateSpeedScale, HOOK_CALL).install()->quick();
// Hook PM_MoveScale so we can add custom speed scale for Ufo and Noclip
Utils::Hook(0x56F845, Movement::PM_MoveScaleStub, HOOK_CALL).install()->quick();
Utils::Hook(0x56FABD, Movement::PM_MoveScaleStub, HOOK_CALL).install()->quick();
2022-01-18 19:49:50 -05:00
2022-01-19 05:48:33 -05:00
// Bounce logic
2022-01-18 19:49:50 -05:00
Utils::Hook(0x4B1B2D, Movement::PM_StepSlideMoveStub, HOOK_JUMP).install()->quick();
2022-02-13 19:09:46 -05:00
Utils::Hook(0x57383E, Movement::Jump_ClearState_Hk, HOOK_CALL).install()->quick();
2022-01-18 19:49:50 -05:00
Utils::Hook(0x4B1B97, Movement::PM_ProjectVelocityStub, HOOK_CALL).install()->quick();
2021-11-07 06:16:56 -05:00
2022-02-05 11:24:59 -05:00
// Rocket jump
2022-02-09 13:05:52 -05:00
Utils::Hook(0x4A4F9B, Movement::Weapon_RocketLauncher_Fire_Hk, HOOK_CALL).install()->quick(); // FireWeapon
2022-02-09 13:02:42 -05:00
// Hook StuckInClient & CM_TransformedCapsuleTrace
// so we can prevent intersecting players from being pushed away from each other
2022-02-09 13:05:52 -05:00
Utils::Hook(0x5D8153, Movement::StuckInClient_Hk, HOOK_CALL).install()->quick();
2022-02-09 13:02:42 -05:00
Utils::Hook(0x45A5BF, Movement::CM_TransformedCapsuleTrace_Hk, HOOK_CALL).install()->quick(); // SV_ClipMoveToEntity
Utils::Hook(0x5A0CAD, Movement::CM_TransformedCapsuleTrace_Hk, HOOK_CALL).install()->quick(); // CG_ClipMoveToEntity
2021-11-07 06:16:56 -05:00
}
}