diff --git a/src/client/component/notifies.cpp b/src/client/component/notifies.cpp index ab7441cb..e9b1e2b3 100644 --- a/src/client/component/notifies.cpp +++ b/src/client/component/notifies.cpp @@ -17,6 +17,9 @@ namespace notifies namespace { + utils::hook::detour scr_entity_damage_hook; + std::vector entity_damage_callbacks; + char empty_function[2] = {0x32, 0x34}; // CHECK_CLEAR_PARAMS, END unsigned int local_id_to_entity(unsigned int local_id) @@ -99,11 +102,96 @@ namespace notifies a.mov(r14, (char*)empty_function); a.jmp(end); } + + sol::lua_value convert_entity(lua_State* state, const game::gentity_s* ent) + { + if (!ent) + { + return {}; + } + + const auto player = scripting::call("getentbynum", {ent->s.entityNum}); + + return scripting::lua::convert(state, player); + } + + std::string get_weapon_name(unsigned int weapon, bool isAlternate) + { + char output[1024] = {0}; + game::BG_GetWeaponNameComplete(weapon, isAlternate, output, 1024); + + return output; + } + + sol::lua_value convert_vector(lua_State* state, const float* vec) + { + if (!vec) + { + return {}; + } + + const auto _vec = scripting::vector(vec); + + return scripting::lua::convert(state, _vec); + } + + std::string convert_mod(const int meansOfDeath) + { + const auto value = reinterpret_cast(game::base_address + 0xBF49B0)[meansOfDeath]; + const auto string = game::SL_ConvertToString(*value); + + return string; + } + + void scr_entity_damage_stub(game::gentity_s* self, game::gentity_s* inflictor, game::gentity_s* attacker, const float* vDir, const float* vPoint, + int damage, int dflags, const unsigned int hitLoc, const unsigned int weapon, bool isAlternate, unsigned int a11, const int meansOfDeath, unsigned int a13, unsigned int a14) + { + { + const std::string _hitLoc = reinterpret_cast(game::base_address + 0xBF4AA0)[hitLoc]; + const auto _mod = convert_mod(meansOfDeath); + const auto _weapon = get_weapon_name(weapon, isAlternate); + + for (const auto& callback : entity_damage_callbacks) + { + const auto state = callback.lua_state(); + + const auto _self = convert_entity(state, self); + const auto _inflictor = convert_entity(state, inflictor); + const auto _attacker = convert_entity(state, attacker); + const auto _vDir = convert_vector(state, vDir); + + const auto result = callback(_self, _inflictor, _attacker, damage, _mod, _weapon, _vDir, _hitLoc); + scripting::lua::handle_error(result); + + if (result.valid()) + { + const auto value = result.get(); + if (value.is()) + { + damage = value.as(); + } + } + } + + if (damage == 0) + { + return; + } + } + + scr_entity_damage_hook.invoke(self, inflictor, attacker, vDir, vPoint, damage, dflags, hitLoc, weapon, isAlternate, a11, meansOfDeath, a13, a14); + } + } + + void add_entity_damage_callback(const sol::protected_function& callback) + { + entity_damage_callbacks.push_back(callback); } void clear_callbacks() { vm_execute_hooks.clear(); + entity_damage_callbacks.clear(); } class component final : public component_interface @@ -112,6 +200,8 @@ namespace notifies void post_unpack() override { utils::hook::jump(game::base_address + 0x5C90A5, utils::hook::assemble(vm_execute_stub), true); + + scr_entity_damage_hook.create(game::base_address + 0x4BD2E0, scr_entity_damage_stub); } }; } diff --git a/src/client/component/notifies.hpp b/src/client/component/notifies.hpp index e7ab5a6c..61a1dd29 100644 --- a/src/client/component/notifies.hpp +++ b/src/client/component/notifies.hpp @@ -5,5 +5,6 @@ namespace notifies extern std::unordered_map vm_execute_hooks; extern bool hook_enabled; + void add_entity_damage_callback(const sol::protected_function&); void clear_callbacks(); } \ No newline at end of file diff --git a/src/client/game/scripting/function_tables.cpp b/src/client/game/scripting/function_tables.cpp index bbaf071f..447a070b 100644 --- a/src/client/game/scripting/function_tables.cpp +++ b/src/client/game/scripting/function_tables.cpp @@ -1015,7 +1015,7 @@ namespace scripting {"setmotionblurzoomscale", 0x81BA}, {"viewkick", 0x81BB}, {"sub_4ecfe0", 0x81BC}, - {"getnodenumber", 0x81BD}, + {"getentitynumber", 0x81BD}, {"sub_4ebbc0", 0x81BE}, {"enablegrenadetouchdamage", 0x81BF}, {"disablegrenadetouchdamage", 0x81C0}, @@ -1706,7 +1706,7 @@ namespace scripting {"removecomworld", 0x8587}, {"sub_4b8f80", 0x8588}, {"sub_4b9270", 0x8589}, - {"getentitynumber", 0x858C}, + {"sub_4eab30", 0x858C}, {"cleartargetentity", 0x858D}, {"nullsub_359", 0x8590}, {"sub_4b3f60", 0x8595}, diff --git a/src/client/game/scripting/lua/context.cpp b/src/client/game/scripting/lua/context.cpp index ca065592..c20c69d4 100644 --- a/src/client/game/scripting/lua/context.cpp +++ b/src/client/game/scripting/lua/context.cpp @@ -423,7 +423,7 @@ namespace scripting::lua for (auto arg : va) { - arguments.push_back(convert({ s, arg })); + arguments.push_back(convert({s, arg})); } notifies::hook_enabled = false; @@ -438,7 +438,7 @@ namespace scripting::lua for (auto arg : va) { - arguments.push_back(convert({ s, arg })); + arguments.push_back(convert({s, arg})); } notifies::hook_enabled = false; @@ -455,7 +455,7 @@ namespace scripting::lua for (auto arg : va) { - arguments.push_back(convert({ s, arg })); + arguments.push_back(convert({s, arg})); } const auto level = entity{*::game::levelEntityId}; @@ -466,6 +466,11 @@ namespace scripting::lua return result; }; + + game_type["onentitydamage"] = [](const game&, const sol::protected_function& callback) + { + notifies::add_entity_damage_callback(callback); + }; } } diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index ab366054..501a00a4 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -58,7 +58,8 @@ namespace game struct gentity_s { - char __pad0[0x1C]; + EntityState s; + char __pad0[0x1B]; vec3_t origin; char __pad1[0xF0]; gclient_s* client; diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index e734de71..47a64cb7 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -12,6 +12,9 @@ namespace game WEAK symbol RemoveRefToValue{0x5C29B0}; WEAK symbol RemoveRefToObject{0x5C28A0}; + WEAK symbol BG_GetWeaponNameComplete{0x6A0800}; + WEAK symbol Cbuf_AddText{0x59A050}; WEAK symbol CG_GameMessage{0x37F450};