diff --git a/Client/game_sa/CFireSA.cpp b/Client/game_sa/CFireSA.cpp index b2622c6745e..5065f2ff016 100644 --- a/Client/game_sa/CFireSA.cpp +++ b/Client/game_sa/CFireSA.cpp @@ -14,6 +14,8 @@ #include "CFireSA.h" #include "CGameSA.h" #include "CPoolsSA.h" +#include +#include extern CGameSA* pGame; @@ -209,3 +211,49 @@ void CFireSA::SetNumGenerationsAllowed(char generations) { internalInterface->nNumGenerationsAllowed = generations; } + +//////////////////////////////////////////////////////////////////////// +// CFire::Extinguish +// +// Fix GH #3249 (PLAYER_ON_FIRE task is not aborted after the fire is extinguished) +//////////////////////////////////////////////////////////////////////// +static void AbortFireTask(CEntitySAInterface* entityOnFire, DWORD returnAddress) +{ + // We can't and shouldn't remove the task if we're in CTaskSimplePlayerOnFire::ProcessPed. Otherwise we will crash. + if (returnAddress == 0x633783) + return; + + auto* ped = pGame->GetPools()->GetPed(reinterpret_cast(entityOnFire)); + if (!ped || !ped->pEntity) + return; + + CTaskManager* taskManager = ped->pEntity->GetPedIntelligence()->GetTaskManager(); + if (!taskManager) + return; + + taskManager->RemoveTaskSecondary(TASK_SECONDARY_PARTIAL_ANIM, TASK_SIMPLE_PLAYER_ON_FIRE); +} + +#define HOOKPOS_CFire_Extinguish 0x539429 +#define HOOKSIZE_CFire_Extinguish 6 +static constexpr std::uintptr_t CONTINUE_CFire_Extinguish = 0x53942F; +static void _declspec(naked) HOOK_CFire_Extinguish() +{ + _asm + { + mov [eax+730h], edi + mov ebx, [esp+8] + + push ebx + push eax + call AbortFireTask + add esp, 8 + + jmp CONTINUE_CFire_Extinguish + } +} + +void CFireSA::StaticSetHooks() +{ + EZHookInstall(CFire_Extinguish); +} diff --git a/Client/game_sa/CFireSA.h b/Client/game_sa/CFireSA.h index 9b4ee4609b2..6a3e66a58ed 100644 --- a/Client/game_sa/CFireSA.h +++ b/Client/game_sa/CFireSA.h @@ -64,4 +64,6 @@ class CFireSA : public CFire void SetStrength(float fStrength); void SetNumGenerationsAllowed(char generations); CFireSAInterface* GetInterface() { return internalInterface; } + + static void StaticSetHooks(); }; diff --git a/Client/game_sa/CGameSA.cpp b/Client/game_sa/CGameSA.cpp index 61d58ce303d..6874500f71a 100644 --- a/Client/game_sa/CGameSA.cpp +++ b/Client/game_sa/CGameSA.cpp @@ -247,6 +247,7 @@ CGameSA::CGameSA() CVehicleSA::StaticSetHooks(); CCheckpointSA::StaticSetHooks(); CHudSA::StaticSetHooks(); + CFireSA::StaticSetHooks(); CPtrNodeSingleLinkPoolSA::StaticSetHooks(); CVehicleAudioSettingsManagerSA::StaticSetHooks(); } diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp index ba5c1054d63..0c23f9ef818 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp @@ -2522,7 +2522,7 @@ bool CLuaElementDefs::SetLowLodElement(lua_State* luaVM, CClientEntity* pEntity, bool CLuaElementDefs::SetElementOnFire(CClientEntity* entity, bool onFire) noexcept { - if (!entity->IsLocalEntity()) + if (!entity->IsLocalEntity() && entity != CStaticFunctionDefinitions::GetLocalPlayer()) return false; return entity->SetOnFire(onFire);