add weapon inspect and actionslot 8
This commit is contained in:
parent
99db27c36d
commit
c532fabff7
@ -1,150 +0,0 @@
|
|||||||
#include <std_include.hpp>
|
|
||||||
#include "loader/component_loader.hpp"
|
|
||||||
#include "game/game.hpp"
|
|
||||||
|
|
||||||
#include <utils/hook.hpp>
|
|
||||||
#include <utils/string.hpp>
|
|
||||||
|
|
||||||
namespace binding
|
|
||||||
{
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
std::vector<std::string> custom_binds = {};
|
|
||||||
|
|
||||||
utils::hook::detour cl_execute_key_hook;
|
|
||||||
|
|
||||||
int get_num_keys()
|
|
||||||
{
|
|
||||||
return 118;
|
|
||||||
}
|
|
||||||
|
|
||||||
int key_write_bindings_to_buffer_stub(int, char* buffer, const int buffer_size)
|
|
||||||
{
|
|
||||||
auto bytes_used = 0;
|
|
||||||
const auto buffer_size_align = static_cast<std::int32_t>(buffer_size) - 4;
|
|
||||||
|
|
||||||
for (auto key_index = 0; key_index < 256; ++key_index)
|
|
||||||
{
|
|
||||||
const auto* const key_button = game::Key_KeynumToString(key_index, 0, 1);
|
|
||||||
auto value = game::playerKeys->keys[key_index].binding;
|
|
||||||
|
|
||||||
if (value && value < get_num_keys())
|
|
||||||
{
|
|
||||||
const auto len = sprintf_s(&buffer[bytes_used], (buffer_size_align - bytes_used),
|
|
||||||
"bind %s \"%s\"\n", key_button, game::command_whitelist[value]);
|
|
||||||
|
|
||||||
if (len < 0)
|
|
||||||
{
|
|
||||||
return bytes_used;
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes_used += len;
|
|
||||||
}
|
|
||||||
else if (value >= get_num_keys())
|
|
||||||
{
|
|
||||||
value -= get_num_keys();
|
|
||||||
if (static_cast<size_t>(value) < custom_binds.size() && !custom_binds[value].empty())
|
|
||||||
{
|
|
||||||
const auto len = sprintf_s(&buffer[bytes_used], (buffer_size_align - bytes_used),
|
|
||||||
"bind %s \"%s\"\n", key_button, custom_binds[value].data());
|
|
||||||
|
|
||||||
if (len < 0)
|
|
||||||
{
|
|
||||||
return bytes_used;
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes_used += len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer[bytes_used] = 0;
|
|
||||||
return bytes_used;
|
|
||||||
}
|
|
||||||
|
|
||||||
int get_binding_for_custom_command(const char* command)
|
|
||||||
{
|
|
||||||
auto index = 0;
|
|
||||||
for (auto& bind : custom_binds)
|
|
||||||
{
|
|
||||||
if (bind == command)
|
|
||||||
{
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
custom_binds.emplace_back(command);
|
|
||||||
index = static_cast<unsigned int>(custom_binds.size()) - 1;
|
|
||||||
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
int key_get_binding_for_cmd_stub(const char* command)
|
|
||||||
{
|
|
||||||
// original binds
|
|
||||||
for (auto i = 0; i < get_num_keys(); i++)
|
|
||||||
{
|
|
||||||
if (game::command_whitelist[i] && !strcmp(command, game::command_whitelist[i]))
|
|
||||||
{
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// custom binds
|
|
||||||
return get_num_keys() + get_binding_for_custom_command(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::optional<std::string> get_custom_binding_for_key(int key)
|
|
||||||
{
|
|
||||||
key -= get_num_keys();
|
|
||||||
|
|
||||||
if (static_cast<size_t>(key) < custom_binds.size() && !custom_binds[key].empty())
|
|
||||||
{
|
|
||||||
return { custom_binds[key] };
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void cl_execute_key_stub(const int local_client_num, int key, const int down, const unsigned int time)
|
|
||||||
{
|
|
||||||
if (key >= get_num_keys())
|
|
||||||
{
|
|
||||||
const auto bind = get_custom_binding_for_key(key);
|
|
||||||
if (!bind.has_value())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return game::Cbuf_AddText(local_client_num, utils::string::va("%s\n", bind.value().data()));
|
|
||||||
}
|
|
||||||
|
|
||||||
cl_execute_key_hook.invoke<void>(local_client_num, key, down, time);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class component final : public component_interface
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void post_unpack() override
|
|
||||||
{
|
|
||||||
if (game::environment::is_dedi())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// write all bindings to config file
|
|
||||||
utils::hook::jump(0x9A9F70_b, key_write_bindings_to_buffer_stub);
|
|
||||||
|
|
||||||
// links a custom command to an index
|
|
||||||
utils::hook::jump(0x9A8EA0_b, key_get_binding_for_cmd_stub);
|
|
||||||
|
|
||||||
// execute custom binds
|
|
||||||
cl_execute_key_hook.create(0x32A3B0_b, &cl_execute_key_stub);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
REGISTER_COMPONENT(binding::component)
|
|
@ -6,13 +6,20 @@
|
|||||||
#include "game_console.hpp"
|
#include "game_console.hpp"
|
||||||
|
|
||||||
#include <utils/hook.hpp>
|
#include <utils/hook.hpp>
|
||||||
|
#include <utils/string.hpp>
|
||||||
|
|
||||||
namespace input
|
namespace input
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
std::vector<std::string> custom_binds = {};
|
||||||
|
|
||||||
utils::hook::detour cl_char_event_hook;
|
utils::hook::detour cl_char_event_hook;
|
||||||
utils::hook::detour cl_key_event_hook;
|
utils::hook::detour cl_key_event_hook;
|
||||||
|
utils::hook::detour cl_execute_key_hook;
|
||||||
|
utils::hook::detour key_get_binding_for_key_hook;
|
||||||
|
|
||||||
|
int key_get_binding_for_cmd_stub(const char* command);
|
||||||
|
|
||||||
void cl_char_event_stub(const int local_client_num, const int key)
|
void cl_char_event_stub(const int local_client_num, const int key)
|
||||||
{
|
{
|
||||||
@ -32,6 +39,133 @@ namespace input
|
|||||||
}
|
}
|
||||||
|
|
||||||
cl_key_event_hook.invoke<void>(local_client_num, key, down);
|
cl_key_event_hook.invoke<void>(local_client_num, key, down);
|
||||||
|
|
||||||
|
const auto key_catchers = *game::keyCatchers;
|
||||||
|
if (key_catchers != 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto binding = game::playerKeys->keys[key].binding;
|
||||||
|
static const auto binding1 = key_get_binding_for_cmd_stub("+actionslot 8");
|
||||||
|
if (binding == binding1)
|
||||||
|
{
|
||||||
|
if (!down)
|
||||||
|
{
|
||||||
|
binding = binding + 1;
|
||||||
|
}
|
||||||
|
utils::hook::invoke<void>(0x35DFB0_b, local_client_num, binding, key, 1); // CL_InputMP_ExecBinding
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_num_keys()
|
||||||
|
{
|
||||||
|
return 118;
|
||||||
|
}
|
||||||
|
|
||||||
|
int key_write_bindings_to_buffer_stub(int, char* buffer, const int buffer_size)
|
||||||
|
{
|
||||||
|
auto bytes_used = 0;
|
||||||
|
const auto buffer_size_align = static_cast<std::int32_t>(buffer_size) - 4;
|
||||||
|
|
||||||
|
for (auto key_index = 0; key_index < 256; ++key_index)
|
||||||
|
{
|
||||||
|
const auto* const key_button = game::Key_KeynumToString(key_index, 0, 1);
|
||||||
|
auto value = game::playerKeys->keys[key_index].binding;
|
||||||
|
|
||||||
|
if (value && value < get_num_keys())
|
||||||
|
{
|
||||||
|
const auto len = sprintf_s(&buffer[bytes_used], (buffer_size_align - bytes_used),
|
||||||
|
"bind %s \"%s\"\n", key_button, game::command_whitelist[value]);
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
{
|
||||||
|
return bytes_used;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes_used += len;
|
||||||
|
}
|
||||||
|
else if (value >= get_num_keys())
|
||||||
|
{
|
||||||
|
value -= get_num_keys();
|
||||||
|
if (static_cast<size_t>(value) < custom_binds.size() && !custom_binds[value].empty())
|
||||||
|
{
|
||||||
|
const auto len = sprintf_s(&buffer[bytes_used], (buffer_size_align - bytes_used),
|
||||||
|
"bind %s \"%s\"\n", key_button, custom_binds[value].data());
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
{
|
||||||
|
return bytes_used;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes_used += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[bytes_used] = 0;
|
||||||
|
return bytes_used;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_binding_for_custom_command(const char* command)
|
||||||
|
{
|
||||||
|
auto index = 0;
|
||||||
|
for (auto& bind : custom_binds)
|
||||||
|
{
|
||||||
|
if (bind == command)
|
||||||
|
{
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
custom_binds.emplace_back(command);
|
||||||
|
index = static_cast<unsigned int>(custom_binds.size()) - 1;
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
int key_get_binding_for_cmd_stub(const char* command)
|
||||||
|
{
|
||||||
|
// original binds
|
||||||
|
for (auto i = 0; i < get_num_keys(); i++)
|
||||||
|
{
|
||||||
|
if (game::command_whitelist[i] && !strcmp(command, game::command_whitelist[i]))
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// custom binds
|
||||||
|
return get_num_keys() + get_binding_for_custom_command(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> get_custom_binding_for_key(int key)
|
||||||
|
{
|
||||||
|
key -= get_num_keys();
|
||||||
|
|
||||||
|
if (static_cast<size_t>(key) < custom_binds.size() && !custom_binds[key].empty())
|
||||||
|
{
|
||||||
|
return { custom_binds[key] };
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void cl_execute_key_stub(const int local_client_num, int key, const int down, const unsigned int time)
|
||||||
|
{
|
||||||
|
if (key >= get_num_keys())
|
||||||
|
{
|
||||||
|
const auto bind = get_custom_binding_for_key(key);
|
||||||
|
if (!bind.has_value())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return game::Cbuf_AddText(local_client_num, utils::string::va("%s\n", bind.value().data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
cl_execute_key_hook.invoke<void>(local_client_num, key, down, time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,6 +181,18 @@ namespace input
|
|||||||
|
|
||||||
cl_char_event_hook.create(0x9A7350_b, cl_char_event_stub);
|
cl_char_event_hook.create(0x9A7350_b, cl_char_event_stub);
|
||||||
cl_key_event_hook.create(0x9A7980_b, cl_key_event_stub);
|
cl_key_event_hook.create(0x9A7980_b, cl_key_event_stub);
|
||||||
|
|
||||||
|
custom_binds.push_back("+actionslot 8");
|
||||||
|
custom_binds.push_back("-actionslot 8");
|
||||||
|
|
||||||
|
// write all bindings to config file
|
||||||
|
utils::hook::jump(0x9A9F70_b, key_write_bindings_to_buffer_stub);
|
||||||
|
|
||||||
|
// links a custom command to an index
|
||||||
|
utils::hook::jump(0x9A8EA0_b, key_get_binding_for_cmd_stub);
|
||||||
|
|
||||||
|
// execute custom binds
|
||||||
|
cl_execute_key_hook.create(0x32A3B0_b, &cl_execute_key_stub);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
318
src/client/component/weapon.cpp
Normal file
318
src/client/component/weapon.cpp
Normal file
@ -0,0 +1,318 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "loader/component_loader.hpp"
|
||||||
|
|
||||||
|
#include "game/game.hpp"
|
||||||
|
#include "game/dvars.hpp"
|
||||||
|
|
||||||
|
#include "command.hpp"
|
||||||
|
#include "console/console.hpp"
|
||||||
|
#include "scheduler.hpp"
|
||||||
|
|
||||||
|
#include "gsc/script_extension.hpp"
|
||||||
|
#include "gsc/script_error.hpp"
|
||||||
|
|
||||||
|
#include <utils/hook.hpp>
|
||||||
|
|
||||||
|
#define WEAP_ANIM_INSPECT WEAP_ANIM_RELOAD_MULTIPLE_FAST_8
|
||||||
|
#define WEAP_STATE_INSPECT 34 // night vision wear?
|
||||||
|
|
||||||
|
#define WEAP_FLAG2_INSPECT 0x4
|
||||||
|
|
||||||
|
namespace weapon
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
template <typename T>
|
||||||
|
void set_weapon_field(const std::string& weapon_name, unsigned int field, T value)
|
||||||
|
{
|
||||||
|
auto weapon = game::DB_FindXAssetHeader(game::ASSET_TYPE_WEAPON, weapon_name.data(), false).weapon;
|
||||||
|
if (weapon)
|
||||||
|
{
|
||||||
|
if (field && field < (sizeof(game::WeaponDef)))
|
||||||
|
{
|
||||||
|
*reinterpret_cast<T*>(reinterpret_cast<std::uintptr_t>(weapon->weapDef) + field) = value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
console::warn("weapon field: %d is higher than the size of weapon struct!\n", field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
console::warn("weapon %s not found!\n", weapon_name.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_weapon_field_float(const std::string& weapon_name, unsigned int field, float value)
|
||||||
|
{
|
||||||
|
set_weapon_field<float>(weapon_name, field, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_weapon_field_int(const std::string& weapon_name, unsigned int field, int value)
|
||||||
|
{
|
||||||
|
set_weapon_field<int>(weapon_name, field, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_weapon_field_bool(const std::string& weapon_name, unsigned int field, bool value)
|
||||||
|
{
|
||||||
|
set_weapon_field<bool>(weapon_name, field, value);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
game::WeaponDef* GetWeaponDef(unsigned __int16* weapon)
|
||||||
|
{
|
||||||
|
game::symbol<game::WeaponDef*> bg_weaponDefs{ 0x5210120 };
|
||||||
|
auto* weapon_def = bg_weaponDefs[*weapon];
|
||||||
|
return weapon_def;
|
||||||
|
}
|
||||||
|
|
||||||
|
int XAnimPartsGetLengthMsec(game::XAnimParts* parts)
|
||||||
|
{
|
||||||
|
return (int)(((float)parts->numframes / parts->framerate) * 1000.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasAnimState(int num, int compare)
|
||||||
|
{
|
||||||
|
return (num == compare || (num | 0x80) == compare);
|
||||||
|
}
|
||||||
|
|
||||||
|
int BG_GetWeaponInspectTime(game::playerState_s* ps, unsigned __int16* weapon, char isAlternate, char isDualWielding)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
auto* weapon_def = GetWeaponDef(weapon);
|
||||||
|
if (!weapon_def->szXAnims)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = weapon_def->szXAnims->pad;
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
if (weapon_def->szXAnims->anims[game::WEAP_ANIM_INSPECT])
|
||||||
|
{
|
||||||
|
result = XAnimPartsGetLengthMsec(weapon_def->szXAnims->anims[game::WEAP_ANIM_INSPECT]) + 33;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::hook::detour CG_Weapons_GetWeaponAnimRate_hook;
|
||||||
|
float CG_Weapons_GetWeaponAnimRate_stub(int localClientNum, game::playerState_s* ps, int hand, __int64* weapon, unsigned __int8 isAlternate,
|
||||||
|
unsigned __int8 isDualWielding, game::XAnim_s* anims, game::weapAnimFiles_t animIndex, game::weapAnimFiles_t animIndex2)
|
||||||
|
{
|
||||||
|
// inspect animation time
|
||||||
|
if (animIndex == game::WEAP_ANIM_INSPECT)
|
||||||
|
{
|
||||||
|
animIndex2 = animIndex;
|
||||||
|
|
||||||
|
auto time = BG_GetWeaponInspectTime(ps, (unsigned __int16*)weapon, isAlternate, isDualWielding);
|
||||||
|
if (!time)
|
||||||
|
return 0.0f;
|
||||||
|
auto anim_time = game::XAnimGetLengthMsec(anims, animIndex2);
|
||||||
|
return (float)anim_time / (float)time;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CG_Weapons_GetWeaponAnimRate_hook.invoke<float>(localClientNum, ps, hand, weapon,
|
||||||
|
isAlternate, isDualWielding, anims, animIndex, animIndex2);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::hook::detour BG_MapWeaponAnimStateToAnimIndex_hook;
|
||||||
|
game::weapAnimFiles_t BG_MapWeaponAnimStateToAnimIndex_stub(__int64 a1, game::playerState_s* ps, int animState, __int64* weapon, unsigned __int8 isAlternate,
|
||||||
|
int handIndex, unsigned __int8 pmoveHandler)
|
||||||
|
{
|
||||||
|
if (HasAnimState(game::WEAP_INSPECT, animState) && ps->weapState[handIndex].weaponState == WEAP_STATE_INSPECT)
|
||||||
|
{
|
||||||
|
return game::WEAP_ANIM_INSPECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BG_MapWeaponAnimStateToAnimIndex_hook.invoke<game::weapAnimFiles_t>(a1, ps, animState, weapon, isAlternate, handIndex, pmoveHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BG_GetWeaponInspectEnabled()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PM_Weap_Inspect(game::pmove_t* pm, game::playerState_s* ps, unsigned short* weapon, int hand)
|
||||||
|
{
|
||||||
|
if (pm->ps->weapState[hand].weaponState != game::WEAPON_READY)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pm->ps->weapState[hand].weaponState == WEAP_STATE_INSPECT)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!game::BG_ViewModelAnimExists(pm->ps, game::WEAP_ANIM_INSPECT, hand, pm->handler))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ps->weapState[hand].weaponState = WEAP_STATE_INSPECT;
|
||||||
|
ps->weapState[hand].weaponTime = BG_GetWeaponInspectTime(ps, weapon, false, false);
|
||||||
|
ps->weapState[hand].weaponDelay = 0;
|
||||||
|
|
||||||
|
if (ps->pm_type < 7)
|
||||||
|
ps->weapState[hand].weapAnim = ~(unsigned __int8)ps->weapState[hand].weapAnim & 0x80 | game::WEAP_INSPECT;
|
||||||
|
|
||||||
|
//PM_BuildWeaponAnimArrays(*(__int64*)((char*)pm + 568), pm->ps, *(char*)((char*)pm + 576));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PM_Weapon_CheckForInspect(game::pmove_t* pm, game::pml_t* pml)
|
||||||
|
{
|
||||||
|
if ((pm->ps->weapFlags[1] & WEAP_FLAG2_INSPECT) != 0)
|
||||||
|
{
|
||||||
|
pm->ps->weapFlags[1] = ~pm->ps->weapFlags[1] & WEAP_FLAG2_INSPECT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!BG_GetWeaponInspectEnabled())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto v3 = *(__int64*)((char*)pm + 568) + 16i64 * *(unsigned __int16*)((char*)pm->ps + 2176);
|
||||||
|
unsigned short* weapon = (unsigned short*)((char*)v3 + 10);
|
||||||
|
|
||||||
|
unsigned int hand = 0;
|
||||||
|
if (game::BG_PlayerLastWeaponHandForViewWeapon(weapon, pm->ps) >= 0)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
PM_Weap_Inspect(pm, pm->ps, weapon, hand++);
|
||||||
|
} while (hand <= game::BG_PlayerLastWeaponHandForViewWeapon(weapon, pm->ps));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::hook::detour PM_Weapon_Check_hook;
|
||||||
|
void PM_Weapon_Check_stub(game::pmove_t* pm, game::pml_t* pml)
|
||||||
|
{
|
||||||
|
PM_Weapon_Check_hook.invoke<void>(pm, pml);
|
||||||
|
|
||||||
|
PM_Weapon_CheckForInspect(pm, pml);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::hook::detour PM_Weapon_IsInInterruptibleState_hook;
|
||||||
|
bool PM_Weapon_IsInInterruptibleState_stub(__int64 weaponMap, game::playerState_s* ps, unsigned int hand, unsigned __int8 pmoveHandler)
|
||||||
|
{
|
||||||
|
auto result = PM_Weapon_IsInInterruptibleState_hook.invoke<bool>(weaponMap, ps, hand, pmoveHandler);
|
||||||
|
|
||||||
|
if (HasAnimState(game::WEAP_INSPECT, ps->weapState[hand].weapAnim) && ps->weapState[hand].weaponState == WEAP_STATE_INSPECT)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::hook::detour PM_WeaponProcessState_hook;
|
||||||
|
unsigned int PM_WeaponProcessState_stub(game::pmove_t* pm, game::pml_t* pml, unsigned int delayedAction, int hand, unsigned __int8 interruptable)
|
||||||
|
{
|
||||||
|
if (HasAnimState(game::WEAP_INSPECT, pm->ps->weapState[hand].weapAnim) && pm->ps->weapState[hand].weaponState == WEAP_STATE_INSPECT)
|
||||||
|
{
|
||||||
|
if (pm->ps->weapState[hand].weaponTime > 0)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pm->ps->weapState->weaponState = game::WEAPON_READY;
|
||||||
|
if (pm->ps->pm_type < 7)
|
||||||
|
pm->ps->weapState[hand].weapAnim = ~(unsigned __int8)pm->ps->weapState[hand].weapAnim & 0x80;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PM_WeaponProcessState_hook.invoke<unsigned int>(pm, pml, delayedAction, hand, interruptable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class component final : public component_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void post_unpack() override
|
||||||
|
{
|
||||||
|
if (game::environment::is_dedi())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
command::add("setWeaponFieldFloat", [](const command::params& params)
|
||||||
|
{
|
||||||
|
if (params.size() <= 3)
|
||||||
|
{
|
||||||
|
console::info("usage: setWeaponFieldInt <weapon> <field> <value>\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
set_weapon_field_float(params.get(1), atoi(params.get(2)), static_cast<float>(atof(params.get(3))));
|
||||||
|
});
|
||||||
|
|
||||||
|
command::add("setWeaponFieldInt", [](const command::params& params)
|
||||||
|
{
|
||||||
|
if (params.size() <= 3)
|
||||||
|
{
|
||||||
|
console::info("usage: setWeaponFieldInt <weapon> <field> <value>\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
set_weapon_field_int(params.get(1), atoi(params.get(2)), static_cast<int>(atoi(params.get(3))));
|
||||||
|
});
|
||||||
|
|
||||||
|
command::add("setWeaponFieldBool", [](const command::params& params)
|
||||||
|
{
|
||||||
|
if (params.size() <= 3)
|
||||||
|
{
|
||||||
|
console::info("usage: setWeaponFieldBool <weapon> <field> <value>\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
set_weapon_field_bool(params.get(1), atoi(params.get(2)), static_cast<bool>(atoi(params.get(3))));
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CG_Weapons_GetWeaponAnimRate_hook.create(0x932550_b, CG_Weapons_GetWeaponAnimRate_stub);
|
||||||
|
BG_MapWeaponAnimStateToAnimIndex_hook.create(0x74A300_b, BG_MapWeaponAnimStateToAnimIndex_stub);
|
||||||
|
PM_Weapon_Check_hook.create(0x723350_b, PM_Weapon_Check_stub);
|
||||||
|
PM_Weapon_IsInInterruptibleState_hook.create(0x728210_b, PM_Weapon_IsInInterruptibleState_stub);
|
||||||
|
PM_WeaponProcessState_hook.create(0x72C3B0_b, PM_WeaponProcessState_stub);
|
||||||
|
|
||||||
|
gsc::method::add("startweaponinspection", [](game::scr_entref_t ent_ref, const gsc::function_args& args)
|
||||||
|
{
|
||||||
|
auto* ent = game::GetEntity(ent_ref);
|
||||||
|
if (!ent->client)
|
||||||
|
{
|
||||||
|
gsc::scr_error(utils::string::va("entity %i is not player", ent_ref));
|
||||||
|
return scripting::script_value{};
|
||||||
|
}
|
||||||
|
|
||||||
|
ent->client->ps.weapFlags[1] |= WEAP_FLAG2_INSPECT; // lets hope the game doesn't use this flag already...
|
||||||
|
return scripting::script_value{};
|
||||||
|
});
|
||||||
|
|
||||||
|
gsc::method::add("isinspectingweapon", [](game::scr_entref_t ent_ref, const gsc::function_args& args)
|
||||||
|
{
|
||||||
|
auto* ent = game::GetEntity(ent_ref);
|
||||||
|
if (!ent->client)
|
||||||
|
{
|
||||||
|
gsc::scr_error(utils::string::va("entity %i is not player", ent_ref));
|
||||||
|
return scripting::script_value{ false };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ent->client->ps.weapState[0].weaponState == WEAP_STATE_INSPECT && HasAnimState(game::WEAP_INSPECT, ent->client->ps.weapState[0].weapAnim))
|
||||||
|
{
|
||||||
|
return scripting::script_value{ true };
|
||||||
|
}
|
||||||
|
return scripting::script_value{ false };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_COMPONENT(weapon::component)
|
@ -517,6 +517,42 @@ namespace game
|
|||||||
int time;
|
int time;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct XAnimParent
|
||||||
|
{
|
||||||
|
unsigned __int16 flags;
|
||||||
|
unsigned __int16 children;
|
||||||
|
};
|
||||||
|
|
||||||
|
union $1A6660B292B883AB62F4E15A2C35B0BF
|
||||||
|
{
|
||||||
|
game::XAnimParts* parts;
|
||||||
|
XAnimParent animParent;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct XAnimEntry
|
||||||
|
{
|
||||||
|
char nodeType[1];
|
||||||
|
char lod;
|
||||||
|
unsigned __int16 numAnims;
|
||||||
|
unsigned __int16 parent;
|
||||||
|
unsigned __int16 bindingIndex;
|
||||||
|
$1A6660B292B883AB62F4E15A2C35B0BF ___u2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct XAnim_s
|
||||||
|
{
|
||||||
|
unsigned int size;
|
||||||
|
bool initialized;
|
||||||
|
bool dirtyBindings;
|
||||||
|
unsigned __int16 numGameParameters;
|
||||||
|
unsigned __int16 maxGameParameters;
|
||||||
|
unsigned __int16 numBindings;
|
||||||
|
unsigned __int16 maxBindings;
|
||||||
|
const void** gameParameterNames;
|
||||||
|
void* bindings;
|
||||||
|
XAnimEntry entries[1];
|
||||||
|
};
|
||||||
|
|
||||||
namespace entity
|
namespace entity
|
||||||
{
|
{
|
||||||
enum connstate_t : std::uint32_t
|
enum connstate_t : std::uint32_t
|
||||||
@ -560,9 +596,134 @@ namespace game
|
|||||||
|
|
||||||
assert_offsetof(entityState_t, clientNum, 156);
|
assert_offsetof(entityState_t, clientNum, 156);
|
||||||
|
|
||||||
|
enum weaponstate_t : std::int32_t
|
||||||
|
{
|
||||||
|
WEAPON_READY = 0,
|
||||||
|
WEAPON_RAISING = 1,
|
||||||
|
WEAPON_RAISING_ALTSWITCH = 2,
|
||||||
|
WEAPON_RAISING_ALTSWITCH_ADS = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum WeaponAnimNumber : std::int32_t
|
||||||
|
{
|
||||||
|
WEAP_IDLE = 0,
|
||||||
|
WEAP_FORCE_IDLE = 1,
|
||||||
|
WEAP_ATTACK = 2,
|
||||||
|
WEAP_ATTACK_LASTSHOT = 3,
|
||||||
|
WEAP_RECHAMBER = 4,
|
||||||
|
WEAP_ADS_ATTACK = 5,
|
||||||
|
WEAP_ADS_ATTACK_LASTSHOT = 6,
|
||||||
|
WEAP_ADS_RECHAMBER = 7,
|
||||||
|
WEAP_GRENADE_PRIME = 8,
|
||||||
|
WEAP_GRENADE_PRIME_READY_TO_THROW = 9,
|
||||||
|
WEAP_MELEE_SWIPE = 10,
|
||||||
|
WEAP_MELEE_HIT = 11,
|
||||||
|
WEAP_MELEE_FATAL = 12,
|
||||||
|
WEAP_MELEE_MISS = 13,
|
||||||
|
WEAP_MELEE_VICTIM_CROUCHING_HIT = 14,
|
||||||
|
WEAP_MELEE_VICTIM_CROUCHING_FATAL = 15,
|
||||||
|
WEAP_MELEE_VICTIM_CROUCHING_MISS = 16,
|
||||||
|
WEAP_DROP = 17,
|
||||||
|
WEAP_RAISE = 18,
|
||||||
|
WEAP_FIRST_RAISE = 19,
|
||||||
|
WEAP_RELOAD = 20,
|
||||||
|
WEAP_RELOAD_EMPTY = 21,
|
||||||
|
WEAP_RELOAD_START = 22,
|
||||||
|
WEAP_RELOAD_END = 23,
|
||||||
|
WEAP_ALTSWITCHFROM = 24,
|
||||||
|
WEAP_ALTSWITCHFROM_ADS = 25,
|
||||||
|
WEAP_ALTSWITCHFROM_AKIMBO = 26,
|
||||||
|
WEAP_ALTSWITCHTO = 27,
|
||||||
|
WEAP_ALTSWITCHTO_ADS = 28,
|
||||||
|
WEAP_ALTSWITCHTO_AKIMBO = 29,
|
||||||
|
WEAP_QUICK_DROP = 30,
|
||||||
|
WEAP_QUICK_RAISE = 31,
|
||||||
|
WEAP_EMPTY_DROP = 32,
|
||||||
|
WEAP_EMPTY_RAISE = 33,
|
||||||
|
WEAP_SPRINT_IN = 34,
|
||||||
|
WEAP_SPRINT_IN_CANCEL = 35,
|
||||||
|
WEAP_SPRINT_LOOP = 36,
|
||||||
|
WEAP_SPRINT_OUT = 37,
|
||||||
|
WEAP_STUNNED_START = 38,
|
||||||
|
WEAP_STUNNED_LOOP = 39,
|
||||||
|
WEAP_STUNNED_END = 40,
|
||||||
|
WEAP_HOLD_FIRE = 41,
|
||||||
|
WEAP_DETONATE = 42,
|
||||||
|
WEAP_NIGHTVISION_WEAR = 43,
|
||||||
|
WEAP_NIGHTVISION_REMOVE = 44,
|
||||||
|
WEAP_BLAST_IMPACT_FRONT = 45,
|
||||||
|
WEAP_BLAST_IMPACT_LEFT = 46,
|
||||||
|
WEAP_BLAST_IMPACT_BACK = 47,
|
||||||
|
WEAP_BLAST_IMPACT_RIGHT = 48,
|
||||||
|
WEAP_SLIDE = 49,
|
||||||
|
WEAP_SWIM_LOOP = 50,
|
||||||
|
WEAP_DODGE = 51,
|
||||||
|
WEAP_LEAP_IN = 52,
|
||||||
|
WEAP_LEAP_LOOP = 53,
|
||||||
|
WEAP_LEAP_OUT = 54,
|
||||||
|
WEAP_LEAP_CANCEL = 55,
|
||||||
|
WEAP_CHARGE_INT = 56,
|
||||||
|
WEAP_CHARGE_LOOP = 57,
|
||||||
|
WEAP_CHARGE_OUT = 58,
|
||||||
|
WEAP_ADS_CHARGE_INT = 59,
|
||||||
|
WEAP_ADS_CHARGE_LOOP = 60,
|
||||||
|
WEAP_ADS_CHARGE_OUT = 61,
|
||||||
|
WEAP_WALLRUN = 62,
|
||||||
|
WEAP_INSPECT = 100, // custom added
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PlayerActiveWeaponState
|
||||||
|
{
|
||||||
|
int weapAnim;
|
||||||
|
int weaponTime;
|
||||||
|
int weaponDelay;
|
||||||
|
int weaponRestrictKickTime;
|
||||||
|
int weaponState;
|
||||||
|
char __pad0[32];
|
||||||
|
};
|
||||||
|
assert_sizeof(PlayerActiveWeaponState, 52);
|
||||||
|
assert_offsetof(PlayerActiveWeaponState, weapAnim, 0);
|
||||||
|
assert_offsetof(PlayerActiveWeaponState, weaponTime, 4);
|
||||||
|
assert_offsetof(PlayerActiveWeaponState, weaponDelay, 8);
|
||||||
|
assert_offsetof(PlayerActiveWeaponState, weaponState, 16);
|
||||||
|
|
||||||
|
typedef int GameModeFlagValues[2];
|
||||||
|
|
||||||
|
struct playerState_s
|
||||||
|
{
|
||||||
|
int commandTime;
|
||||||
|
int pm_type;
|
||||||
|
char __pad0[1612];
|
||||||
|
PlayerActiveWeaponState weapState[2];
|
||||||
|
char __pad1[464];
|
||||||
|
GameModeFlagValues weapFlags;
|
||||||
|
};
|
||||||
|
assert_offsetof(playerState_s, weapState, 1620);
|
||||||
|
assert_offsetof(playerState_s, weapFlags, 2188);
|
||||||
|
|
||||||
|
struct pmove_t
|
||||||
|
{
|
||||||
|
void* unk;
|
||||||
|
playerState_s* ps;
|
||||||
|
char __pad0[560];
|
||||||
|
unsigned char handler;
|
||||||
|
};
|
||||||
|
assert_offsetof(pmove_t, handler, 576);
|
||||||
|
|
||||||
|
struct pml_t
|
||||||
|
{
|
||||||
|
float forward[3];
|
||||||
|
float right[3];
|
||||||
|
float up[3];
|
||||||
|
float frametime;
|
||||||
|
int msec;
|
||||||
|
};
|
||||||
|
assert_offsetof(pml_t, msec, 40);
|
||||||
|
|
||||||
struct gclient_s
|
struct gclient_s
|
||||||
{
|
{
|
||||||
char __pad0[19376];
|
playerState_s ps;
|
||||||
|
char __pad0[17180];
|
||||||
char name[32]; // 19376
|
char name[32]; // 19376
|
||||||
char __pad1[1516];
|
char __pad1[1516];
|
||||||
int flags; // 20924
|
int flags; // 20924
|
||||||
|
@ -19,6 +19,8 @@ namespace game
|
|||||||
WEAK symbol<unsigned int(int handle, int num_param)> Scr_ExecThread{ 0xC0ACD0 };
|
WEAK symbol<unsigned int(int handle, int num_param)> Scr_ExecThread{ 0xC0ACD0 };
|
||||||
|
|
||||||
WEAK symbol<float()> BG_GetGravity{ 0x68DD0 };
|
WEAK symbol<float()> BG_GetGravity{ 0x68DD0 };
|
||||||
|
WEAK game::symbol<unsigned int(unsigned short* weapon, game::playerState_s* ps)> BG_PlayerLastWeaponHandForViewWeapon{ 0x74B410 };
|
||||||
|
WEAK game::symbol<bool(game::playerState_s* ps, game::weapAnimFiles_t anim, int hand, unsigned char pmoveHandler)> BG_ViewModelAnimExists{ 0x751200 };
|
||||||
|
|
||||||
WEAK symbol<void(errorParm code, const char* message, ...)> Com_Error{ 0xB8D830 };
|
WEAK symbol<void(errorParm code, const char* message, ...)> Com_Error{ 0xB8D830 };
|
||||||
|
|
||||||
@ -126,6 +128,7 @@ namespace game
|
|||||||
WEAK symbol<void(char* buffer)> FS_FreeFile{ 0xCDE1F0 };
|
WEAK symbol<void(char* buffer)> FS_FreeFile{ 0xCDE1F0 };
|
||||||
WEAK symbol<void(int h, const char* fmt, ...)> FS_Printf{ 0xCDD1C0 };
|
WEAK symbol<void(int h, const char* fmt, ...)> FS_Printf{ 0xCDD1C0 };
|
||||||
|
|
||||||
|
WEAK symbol<gentity_s* (scr_entref_t ent)> GetEntity{ 0xB50EA0 };
|
||||||
WEAK symbol<unsigned int(unsigned int)> GetObjectType{ 0xC059E0 };
|
WEAK symbol<unsigned int(unsigned int)> GetObjectType{ 0xC059E0 };
|
||||||
WEAK symbol<unsigned int(unsigned int, unsigned int)> GetVariable{ 0xC05A90 };
|
WEAK symbol<unsigned int(unsigned int, unsigned int)> GetVariable{ 0xC05A90 };
|
||||||
WEAK symbol<unsigned int(unsigned int parentId, unsigned int unsignedValue)> GetNewVariable{ 0xC05660 };
|
WEAK symbol<unsigned int(unsigned int parentId, unsigned int unsignedValue)> GetNewVariable{ 0xC05660 };
|
||||||
@ -215,6 +218,10 @@ namespace game
|
|||||||
WEAK symbol<char* (const size_t size, unsigned int alignment, int type, int source)> PMem_AllocFromSource_NoDebug{ 0xCF0A90 };
|
WEAK symbol<char* (const size_t size, unsigned int alignment, int type, int source)> PMem_AllocFromSource_NoDebug{ 0xCF0A90 };
|
||||||
WEAK symbol<void(const char* name, int allocDir)> PMem_Free{ 0xCF10D0 };
|
WEAK symbol<void(const char* name, int allocDir)> PMem_Free{ 0xCF10D0 };
|
||||||
|
|
||||||
|
WEAK game::symbol<bool(__int64 weaponMap, game::playerState_s* ps, unsigned int hand, unsigned char pmoveHandler)> PM_Weapon_IsInInterruptibleState{ 0x728210 };
|
||||||
|
WEAK game::symbol<void(__int64 weaponMap, game::playerState_s* ps, unsigned char pmoveHandler)> PM_BuildWeaponAnimArrays{ 0x71AC50 };
|
||||||
|
WEAK game::symbol<void(game::pmove_t* pm, int hand)> PM_Weapon_Idle{ 0x727910 };
|
||||||
|
|
||||||
WEAK symbol<unsigned int(unsigned int localId, const char* pos,
|
WEAK symbol<unsigned int(unsigned int localId, const char* pos,
|
||||||
unsigned int paramcount)> VM_Execute{ 0xC0CDB0 };
|
unsigned int paramcount)> VM_Execute{ 0xC0CDB0 };
|
||||||
|
|
||||||
@ -229,6 +236,7 @@ namespace game
|
|||||||
WEAK symbol<int(unsigned int classnum, int entnum, int offset)> Scr_SetObjectField{ 0x40B6E0 };
|
WEAK symbol<int(unsigned int classnum, int entnum, int offset)> Scr_SetObjectField{ 0x40B6E0 };
|
||||||
WEAK symbol<int()> Scr_GetInt{ 0xC0B950 };
|
WEAK symbol<int()> Scr_GetInt{ 0xC0B950 };
|
||||||
WEAK symbol<void()> Scr_ErrorInternal{ 0xC0AC30 };
|
WEAK symbol<void()> Scr_ErrorInternal{ 0xC0AC30 };
|
||||||
|
WEAK symbol<void(const char* str)> Scr_AllocGlobalString{ 0xC03C70 };
|
||||||
|
|
||||||
WEAK symbol<ScreenPlacement* ()> ScrPlace_GetViewPlacement{ 0x9E4090 };
|
WEAK symbol<ScreenPlacement* ()> ScrPlace_GetViewPlacement{ 0x9E4090 };
|
||||||
|
|
||||||
@ -271,6 +279,8 @@ namespace game
|
|||||||
WEAK symbol<void(unsigned int localClientNum, const char** args)> UI_RunMenuScript{ 0xCC9710 };
|
WEAK symbol<void(unsigned int localClientNum, const char** args)> UI_RunMenuScript{ 0xCC9710 };
|
||||||
WEAK symbol<const char* (const char* string)> UI_SafeTranslateString{ 0xCC9790 };
|
WEAK symbol<const char* (const char* string)> UI_SafeTranslateString{ 0xCC9790 };
|
||||||
|
|
||||||
|
WEAK game::symbol<float(game::XAnim_s* anims, unsigned int anim)> XAnimGetLengthMsec{ 0xD761C0 };
|
||||||
|
|
||||||
WEAK symbol<void* (jmp_buf* Buf, int Value)> longjmp{ 0x12C0758 };
|
WEAK symbol<void* (jmp_buf* Buf, int Value)> longjmp{ 0x12C0758 };
|
||||||
WEAK symbol<int(jmp_buf* Buf)> _setjmp{ 0x1423110 };
|
WEAK symbol<int(jmp_buf* Buf)> _setjmp{ 0x1423110 };
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user