diff --git a/Client/game_sa/CFireSA.cpp b/Client/game_sa/CFireSA.cpp index a3920fa77d..94d6abbafe 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,43 @@ 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) +{ + 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 + + push eax + call AbortFireTask + add esp, 4 + + 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 06a2b426d7..7e3c802151 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 bbcea89897..9a7ca0f88b 100644 --- a/Client/game_sa/CGameSA.cpp +++ b/Client/game_sa/CGameSA.cpp @@ -245,6 +245,7 @@ CGameSA::CGameSA() CVehicleSA::StaticSetHooks(); CCheckpointSA::StaticSetHooks(); CHudSA::StaticSetHooks(); + CFireSA::StaticSetHooks(); } catch (const std::bad_alloc& e) { diff --git a/Client/game_sa/CTaskManagerSA.cpp b/Client/game_sa/CTaskManagerSA.cpp index 15589de95f..c8873c3552 100644 --- a/Client/game_sa/CTaskManagerSA.cpp +++ b/Client/game_sa/CTaskManagerSA.cpp @@ -151,6 +151,18 @@ void CTaskManagerSA::RemoveTaskSecondary(const int iTaskPriority) SetTaskSecondary(NULL, iTaskPriority); } +bool CTaskManagerSA::RemoveTaskSecondary(const int taskPriority, const int taskType) +{ + CTask* task = GetTaskSecondary(taskPriority); + if (task && task->GetTaskType() == taskType) + { + RemoveTaskSecondary(taskPriority); + return true; + } + + return false; +} + void CTaskManagerSA::SetTaskSecondary(CTaskSA* pTaskSecondary, const int iType) { DWORD dwFunc = FUNC_SetTaskSecondary; diff --git a/Client/game_sa/CTaskManagerSA.h b/Client/game_sa/CTaskManagerSA.h index bb99366621..946f3d4a1e 100644 --- a/Client/game_sa/CTaskManagerSA.h +++ b/Client/game_sa/CTaskManagerSA.h @@ -57,6 +57,7 @@ class CTaskManagerSA : public CTaskManager CTask* FindActiveTaskByType(const int iTaskType); CTask* FindTaskByType(const int iPriority, const int iTaskType); void RemoveTaskSecondary(const int iTaskPriority); + bool RemoveTaskSecondary(const int taskPriority, const int taskType); void SetTaskSecondary(CTaskSA* pTaskSecondary, const int iType); CTask* GetTaskSecondary(const int iType); // code it bool HasTaskSecondary(const CTask* pTaskSecondary); // code it diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index fdb7a897a8..1688bd7219 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -2594,7 +2594,7 @@ bool CStaticFunctionDefinitions::SetPedOnFire(CClientEntity& Entity, bool bOnFir { if (IS_PED(&Entity)) { - if (!Entity.IsLocalEntity()) + if (!Entity.IsLocalEntity() && &Entity != GetLocalPlayer()) return false; CClientPed& Ped = static_cast(Entity); diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp index daea88e46f..436e03d812 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp @@ -2520,7 +2520,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); diff --git a/Client/sdk/game/CTaskManager.h b/Client/sdk/game/CTaskManager.h index f89d145dd4..edf794ce44 100644 --- a/Client/sdk/game/CTaskManager.h +++ b/Client/sdk/game/CTaskManager.h @@ -60,6 +60,7 @@ class CTaskManager virtual CTask* FindActiveTaskByType(const int iTaskType) = 0; virtual CTask* FindTaskByType(const int iPriority, const int iTaskType) = 0; virtual void RemoveTaskSecondary(const int iTaskPriority) = 0; + virtual bool RemoveTaskSecondary(const int taskPriority, const int taskType) = 0; // virtual void SetTaskSecondary(CTask* pTaskSecondary, const int iType)=0; virtual CTask* GetTaskSecondary(const int iType) = 0; virtual bool HasTaskSecondary(const CTask* pTaskSecondary) = 0;