#include #include "loader/component_loader.hpp" #include "game/game.hpp" #include "game/dvars.hpp" #include #include // https://github.com/xoxor4d/iw3xo-dev/blob/develop/src/components/modules/movement.cpp :) namespace movement { namespace { utils::hook::detour pm_airmove_hook; game::dvar_t* pm_cs_airAccelerate; game::dvar_t* pm_cs_airSpeedCap; game::dvar_t* pm_cs_strafing; void pm_air_accelerate(game::vec3_t wishdir, float wishspeed, game::mp::playerState_s* ps, game::mp::pml_t* pml) { float wishspd = wishspeed, accelspeed, currentspeed, addspeed; auto accel = pm_cs_airAccelerate->current.value; auto airspeedcap = pm_cs_airSpeedCap->current.value; if (wishspd > airspeedcap) { wishspd = airspeedcap; } currentspeed = utils::vector::product(ps->velocity, wishdir); addspeed = wishspd - currentspeed; if (addspeed > 0) { accelspeed = pml->frametime * accel * wishspeed * 1.0f; if (accelspeed > addspeed) { accelspeed = addspeed; } for (auto i = 0; i < 3; i++) { ps->velocity[i] += wishdir[i] * accelspeed; } } } void pm_clip_velocity(game::vec3_t in, game::vec3_t normal, game::vec3_t out, float overbounce) { float backoff, change, angle, adjust; angle = normal[2]; backoff = utils::vector::product(in, normal) * overbounce; for (auto i = 0; i < 3; i++) { change = normal[i] * backoff; out[i] = in[i] - change; } adjust = utils::vector::product(out, normal); if (adjust < 0) { game::vec3_t reduce{}; utils::vector::scale(normal, adjust, reduce); utils::vector::subtract(out, reduce, out); } } void pm_try_playermove(game::mp::pmove_t* pm, game::mp::pml_t* pml) { const auto surf_slope = 0.7f; const auto ps = pm->ps; game::vec3_t end{}; game::trace_t trace{}; if (utils::vector::length(ps->velocity) == 0) { return; } utils::vector::ma(ps->origin, pml->frametime, ps->velocity, end); utils::hook::invoke(0x2D14C0_b, pm, &trace, ps->origin, end, &pm->bounds, ps->clientNum, pm->tracemask); // PM_playerTrace if (trace.fraction == 1) { return; } if (trace.normal[2] > surf_slope) { return; } pm_clip_velocity(ps->velocity, trace.normal, ps->velocity, 1.0f); } void pm_airmove_stub(game::mp::pmove_t* pm, game::mp::pml_t* pml) { if (!pm_cs_strafing->current.enabled) { return pm_airmove_hook.invoke(pm, pml); } const auto ps = pm->ps; ps->sprintButtonUpRequired = 1; float fmove{}, smove{}, wishspeed{}; game::vec3_t wishvel{}, wishdir{}; fmove = pm->cmd.forwardmove; smove = pm->cmd.rightmove; pml->forward[2] = 0.0f; pml->right[2] = 0.0f; utils::vector::normalize(pml->forward); utils::vector::normalize(pml->right); for (auto i = 0; i < 2; i++) { wishvel[i] = pml->forward[i] * fmove + pml->right[i] * smove; } wishvel[2] = 0; utils::vector::copy(wishvel, wishdir); wishspeed = utils::vector::normalize(wishdir); if (wishspeed != 0 && (wishspeed > 320.0f)) { utils::vector::scale(wishvel, 320.0f / wishspeed, wishvel); wishspeed = 320.0f; } pm_air_accelerate(wishdir, wishspeed, ps, pml); utils::hook::invoke(0x2D3380_b, pm, pml, 1, 1); // PM_StepSlideMove pm_try_playermove(pm, pml); } } class component final : public component_interface { public: void post_unpack() override { if (game::environment::is_sp()) { return; } pm_airmove_hook.create(0x2C93B0_b, pm_airmove_stub); pm_cs_airAccelerate = dvars::register_float("pm_cs_airAccelerate", 100.0f, 1.0f, 500.0f, game::DvarFlags::DVAR_FLAG_REPLICATED, "Defines player acceleration mid-air"); pm_cs_airSpeedCap = dvars::register_float("pm_cs_airSpeedCap", 30.0f, 1.0f, 500.0f, game::DvarFlags::DVAR_FLAG_REPLICATED, "Maximum speed mid-air"); pm_cs_strafing = dvars::register_bool("pm_cs_strafing", false, game::DvarFlags::DVAR_FLAG_REPLICATED, "Enable CS like strafing"); } }; } REGISTER_COMPONENT(movement::component)