diff --git a/build-count.txt b/build-count.txt index 066cbfe..74fa38c 100644 --- a/build-count.txt +++ b/build-count.txt @@ -1 +1 @@ -401 +407 diff --git a/lib/CPed.cc b/lib/CPed.cc index aa36f53..570b851 100644 --- a/lib/CPed.cc +++ b/lib/CPed.cc @@ -1,3 +1,5 @@ +#include "CVehicle.hh" +#include "Patterns/Patterns.hh" #include #include @@ -5,6 +7,8 @@ void *(*CPedInventory__GiveWeapon) (CPedInventory *, uint32_t, uint32_t); CInventoryItem *(*CInventoryItemRepository__FindWeapon) ( CInventoryItemRepository *, uint32_t); CPed *(*fwScriptGuidPool__GetPed) (uint32_t handle); +CMotionTaskDataSet *(*CMotionTaskDataManager__FindByName) (uint32_t name); +aiTask *(*CPed__CreateMotionTask) (CPed *, sMotionTaskData *, bool); /*******************************************************/ CInventoryItem *__cdecl CInventoryItemRepository::FindWeapon (uint32_t hash) @@ -60,6 +64,41 @@ CPedInventory::AddWeapon (uint32_t hash, uint32_t ammo) return CPedInventory__GiveWeapon (this, hash, ammo); } +/*******************************************************/ +CMotionTaskDataSet * +CMotionTaskDataManager::FindByName (uint32_t name) +{ + return CMotionTaskDataManager__FindByName (name); +} + +/*******************************************************/ +aiTask * +CPed::CreateMotionTask (sMotionTaskData *set, bool lowLod) +{ + return CPed__CreateMotionTask (this, set, lowLod); +} + +/*******************************************************/ +CVehicle * +CPed::GetVehicle () +{ + static uint32_t nVehicleIndex = *hook::get_pattern ( + "8b ? ? ? ? ? c1 e8 1e 41 84 c5 74 ? ? 83 ? ? ? ? ? 00 74 ? ba 0c 00 " + "00 00 e9", + 17); + + return *GetAtOffset (this, nVehicleIndex); +} + +/*******************************************************/ +uint32_t +CPed::GetMotionState () +{ + static uint32_t nMotionStateIndex = *hook::get_pattern ( + "44 8b f2 ? 8b e9 e8 ? ? ? ? 33 ff 44 89 ? ? ? ? ?", 16); + return *GetAtOffset (this, nMotionStateIndex); +} + /*******************************************************/ void CPedInventory::InitialisePatterns () @@ -78,6 +117,16 @@ CPedInventory::InitialisePatterns () "? 83 ec 20 ? 8b f8 8b ea e8 ? ? ? ? 33 db ? 85 c0", 9), fwScriptGuidPool__GetPed); + ReadCall ( + hook::get_pattern ("? 89 ? ? ? ? ? 8b ? ? ? ? ? e8 ? ? ? ? ? 89 ? ? ? " + "? ? 8b ? ? ? ? ? e8 ? ? ? ? 33 d2 ? 8d ? ? ? ? ?", + 13), + CMotionTaskDataManager__FindByName); + + ReadCall (hook::get_pattern ( + "? 8b 52 08 45 8a c1 e8 ? ? ? ? ? 8b c0 ? 8b c0 ", 7), + CPed__CreateMotionTask); + //?? 8b 05 ?? ?? ?? ?? ?? 8b d9 ?? 8b ?? ?? ?? 8b 42 20 ?? 85 c0 CPedFactory::sm_Instance = GetRelativeReference ( "? 8b 05 ? ? ? ? ? 8b d9 ? 8b ? ? ? 8b 42 20 ? 85 c0", 3, 7); diff --git a/lib/CPed.hh b/lib/CPed.hh index eee8938..4e66c6c 100644 --- a/lib/CPed.hh +++ b/lib/CPed.hh @@ -3,9 +3,12 @@ #include #include #include "CEntity.hh" +#include "ParserUtils.hh" class CInventoryItem; class CPed; +class CVehicle; +struct aiTask; class CPedWeaponManager { @@ -127,6 +130,22 @@ public: rage::bitset &GetCombatBehaviourFlags (); }; +class sMotionTaskData : public ParserWrapper +{ +}; + +class CMotionTaskDataSet : public ParserWrapper +{ +}; + +class CMotionTaskDataManager +{ +public: + atArray aMotionTaskData; + + static CMotionTaskDataSet *FindByName (uint32_t name); +}; + struct CPedInventory { public: @@ -160,6 +179,9 @@ public: CPedInventory * GetInventory (); CPedIntelligence *GetIntelligence (); + aiTask * CreateMotionTask (sMotionTaskData *set, bool lowLod); + CVehicle * GetVehicle (); + uint32_t GetMotionState (); }; class CPedFactory diff --git a/lib/CTask.cc b/lib/CTask.cc index 2dc6ea6..3ccc870 100644 --- a/lib/CTask.cc +++ b/lib/CTask.cc @@ -51,4 +51,21 @@ aiTask::InitialisePatterns () CTaskGun::vftable = GetRelativeReference ( "? 8d 05 ? ? ? ? f3 0f 10 74 ? ? 0f 57 ff 0f 2f 35 ? ? ? ? ? 89 ? ", 3, 7); + + CTaskHumanLocomotion::vftable + = GetRelativeReference ("? 8d 05 ? ? ? ? 0f 57 c0 ? 89 ? ? 8d 8e 30 01 " + "00 00 0f 29 86 20 01 00 00 ", + 3, 7); + + CTaskBirdLocomotion::vftable = GetRelativeReference ( + "? 8d 05 ? ? ? ? ? 8d 8e 20 01 00 00 ? 89 ? e8 ? ? ? ? ? 8b 44 ? ? 33 " + "d2 ? 89 96 40 01 00 00 ", + 3, 7); + + CTaskMotionInVehicle::vftable = GetRelativeReference ( + "? 8d 05 ? ? ? ? ? 8d 8b 58 01 00 00 ? 89 ? ? 89 bb 20 01 00 00 ", 3, + 7); + + CTaskMotionAiming::vftable = GetRelativeReference ( + "? 8d 05 ? ? ? ? 0f 57 c0 ? 89 ? ? 8d 8e 38 01 00 00 ", 3, 7); } diff --git a/lib/CTask.hh b/lib/CTask.hh index a0b39b7..4d07ca0 100644 --- a/lib/CTask.hh +++ b/lib/CTask.hh @@ -531,6 +531,40 @@ public: inline static void *vftable; }; +class CTaskHumanLocomotion : public aiTask +{ +public: + inline static void *vftable; +}; + +class CTaskBirdLocomotion : public aiTask +{ +public: + inline static void *vftable; +}; + +class CTaskMotionInVehicle : public aiTask +{ +public: + inline static void *vftable; + + static auto *Create [[nodiscard]] () + { + return TaskHelper::CreateTask (); + } +}; + +class CTaskMotionAiming : public aiTask +{ +public: + inline static void *vftable; + + static auto *Create [[nodiscard]] () + { + return TaskHelper::CreateTask (); + } +}; + class CTaskWeapon : public aiTask { public: diff --git a/src/peds/peds.cc b/src/peds/peds.cc index 3cbc39a..cbbb84e 100644 --- a/src/peds/peds.cc +++ b/src/peds/peds.cc @@ -106,8 +106,12 @@ class PedRandomizer const ModelSwapper swap (newModel, model); swap.OverrideClipset (Config ().ForcedClipset); + PedRandomizerCompatibility::SetRandomizingPed ( + CStreaming::GetModelByIndex (model)); + CPed *ped = CPedFactory__CreatePed (fac, p2, newModel, p4, p5); + PedRandomizerCompatibility::SetRandomizingPed (nullptr); PedRandomizerCompatibility::AddRandomizedPed (ped, model, newModel); PedRandomizer_PlayerFixes::UpdatePlayerHash (); PedRandomizer_PlayerFixes::RandomizeSpecialAbility (ped); diff --git a/src/peds/peds_AnimalExperiments.cc b/src/peds/peds_AnimalExperiments.cc new file mode 100644 index 0000000..cef8c4a --- /dev/null +++ b/src/peds/peds_AnimalExperiments.cc @@ -0,0 +1,203 @@ +#include "CModelInfo.hh" +#include "CStreaming.hh" +#include "Utils.hh" + +#include + +#include +#include + +#include +#include +#include + +class PedRandomizer_AnimalExperiments +{ + /*******************************************************/ + static auto * + GetOnFootMotion (CMotionTaskDataSet *set) + { + return set->Get ("onFoot"_joaat); + } + + /*******************************************************/ + // Returns pair + static std::pair + GetPedMotionTaskDataSet (CPed *ped) + { + CPedModelInfo *rand = static_cast (ped->m_pModelInfo); + CPedModelInfo *orig + = PedRandomizerCompatibility::GetOriginalModel (ped); + + return std::make_pair ( + CMotionTaskDataManager::FindByName ( + orig->GetInitInfo ().m_nMotionTaskDataSetName), + CMotionTaskDataManager::FindByName ( + rand->GetInitInfo ().m_nMotionTaskDataSetName)); + } + + /*******************************************************/ + static aiTask * + GetNewMotionSubtaskForPed (CPed *ped) + { + auto [origMS, newMS] = GetPedMotionTaskDataSet (ped); + + newMS->Get ("inWater"_joaat) + = CMotionTaskDataManager::FindByName ("standard_ped"_joaat) + ->Get ("inWater"_joaat); + ; + + // Check if the new motion set is actually a human locomotion + // if (GetOnFootMotion (newMS)->Equate ("Type"_joaat) + // == GetOnFootMotion (origMS)->Equate ("Type"_joaat)) + // return nullptr; + + return ped->CreateMotionTask (GetOnFootMotion (origMS), false); + } + + /*******************************************************/ + template + static uint32_t + ManageAnimalMotion (CTaskHumanLocomotion *task, uint32_t fsmState, + uint32_t fsmEvent) + { + if (!task->subTask && task->pPed == CPedFactory::Get ()->pPlayer) + { + if (auto subTask = GetNewMotionSubtaskForPed (task->pPed)) + { + Rainbomizer::Logger::LogMessage ( + "Created ped subtask thingy for ped: %p %p and " + "fsmState = %d, fsmEvent = %d", + task->pPed, task, fsmState, fsmEvent); + task->SetSubTask (subTask); + return 0; + } + } + else + return 0; + + return CTaskHumanLocomotion_UpdateFSM (task, fsmState, fsmEvent); + } + + /*******************************************************/ + template + static uint32_t + ManageBirdLocomotion (CTaskBirdLocomotion *task, uint32_t fsmState, + uint32_t fsmEvent) + { + if (task->pPed->GetVehicle ()) + { + task->DoSetState (100); + return 0; + } + else if (task->pPed->GetMotionState () == "motionstate_aiming"_joaat) + { + task->DoSetState (101); + return 0; + } + + if (fsmState == 100) + { + if (fsmEvent == 0 || !task->subTask) + { + Rainbomizer::Logger::LogMessage ( + "Creating task in motion vehicle"); + task->SetSubTask (CTaskMotionInVehicle::Create ()); + } + else if (fsmEvent == 1) + { + if (!task->pPed->GetVehicle ()) + { + task->DoSetState (0); + } + } + + return 0; + } + + if (fsmState == 101) + { + if (fsmEvent == 0) + { + CTaskMotionAiming *subTask + = CTaskMotionAiming::Create (); + + Rainbomizer::Logger::LogMessage ( + "Creating aiming sub task"); + task->SetSubTask (subTask); + } + else if (fsmState == 1) + { + if (task->pPed->GetMotionState () + != "motionstate_aiming"_joaat) + { + task->DoSetState (0); + } + } + + return 0; + } + + return CTaskBirdLocomotion_UpdateFSM (task, fsmState, fsmEvent); + } + + template + static aiTask * + ImproveAnimalMotion (CPed *ped, sMotionTaskData *data, bool lowLod) + { + auto *model = static_cast (ped->m_pModelInfo); + auto *origModel + = PedRandomizerCompatibility::GetCurrentPedRandomizing (); + + if (!origModel) + origModel = PedRandomizerCompatibility::GetOriginalModel (ped); + + auto *origMotionSet + = GetOnFootMotion (CMotionTaskDataManager::FindByName ( + origModel->GetInitInfo ().m_nMotionTaskDataSetName)); + + uint32_t origClipset = model->m_nMovementClipSet; + + if (data->Equate ("Type"_joaat) == "FISH_IN_WATER"_joaat) + { + auto *newMotion + = CMotionTaskDataManager::FindByName ("seagull"_joaat); + + auto *seagull = CStreaming::GetModelByHash ( + "a_c_seagull"_joaat); + + if (newMotion && seagull) + { + data = GetOnFootMotion (newMotion); + model->m_nMovementClipSet = seagull->m_nMovementClipSet; + } + } + + if ((origMotionSet->Equate ("Type"_joaat) == "BIRD_ON_FOOT"_joaat + || origMotionSet->Equate ("Type"_joaat) == "FISH_IN_FOOT"_joaat) + && origMotionSet->Get ("Type"_joaat) + != data->Get ("Type"_joaat)) + { + data = origMotionSet; + model->m_nMovementClipSet = origModel->m_nMovementClipSet; + } + + aiTask *task = CPed__CreateMotioNTask (ped, data, lowLod); + + model->m_nMovementClipSet = origClipset; + return task; + } + +public: + PedRandomizer_AnimalExperiments () + { + InitialiseAllComponents (); + + REGISTER_VFT_HOOK (CTaskHumanLocomotion, 14, ManageAnimalMotion, + uint64_t, CTaskHumanLocomotion *, uint32_t, + uint32_t); + + REGISTER_VFT_HOOK (CTaskBirdLocomotion, 14, ManageBirdLocomotion, + uint64_t, CTaskBirdLocomotion *, uint32_t, uint32_t); + } +} /* animalExperiments */; diff --git a/src/peds/peds_AnimalMotion.cc b/src/peds/peds_AnimalMotion.cc new file mode 100644 index 0000000..eaaf051 --- /dev/null +++ b/src/peds/peds_AnimalMotion.cc @@ -0,0 +1,156 @@ +#include "CModelInfo.hh" +#include "CStreaming.hh" +#include "Utils.hh" + +#include + +#include +#include + +#include +#include +#include + +class PedRandomizer_AnimalMotion +{ + /*******************************************************/ + static auto * + GetOnFootMotion (CMotionTaskDataSet *set) + { + return set->Get ("onFoot"_joaat); + } + + /*******************************************************/ + struct RandomMotionContext + { + CPed * Ped; + CPedModelInfo * RandModel; + CPedModelInfo * OrigModel; + sMotionTaskData *OrigMotion; + sMotionTaskData *RandMotion; + uint32_t OrigMovementClipset; + + /*******************************************************/ + static CPedModelInfo * + GetOriginalModel (CPed *ped) + { + auto *model + = PedRandomizerCompatibility::GetCurrentPedRandomizing (); + return model ? model + : PedRandomizerCompatibility::GetOriginalModel (ped); + } + + /*******************************************************/ + uint32_t + GetRandMotionType () const + { + return RandMotion->Equate ("Type"_joaat).ToHash (); + } + + /*******************************************************/ + uint32_t + GetOrigMotionType () const + { + return OrigMotion->Equate ("Type"_joaat).ToHash (); + } + + /*******************************************************/ + bool + AreOriginalAndRandomMotionSameType () const + { + return GetRandMotionType () == GetOrigMotionType (); + } + + /*******************************************************/ + RandomMotionContext (CPed *ped, sMotionTaskData *data) + { + Ped = ped; + RandMotion = data; + RandModel = static_cast (ped->m_pModelInfo); + OrigModel = GetOriginalModel (ped); + + OrigMotion = GetOnFootMotion (CMotionTaskDataManager::FindByName ( + OrigModel->GetInitInfo ().m_nMotionTaskDataSetName)); + ; + + OrigMovementClipset = RandModel->m_nMovementClipSet; + } + + /*******************************************************/ + ~RandomMotionContext () + { + RandModel->m_nMovementClipSet = OrigMovementClipset; + } + }; + + /*******************************************************/ + static sMotionTaskData * + MakeFishFly (const RandomMotionContext &ctx) + { + if (ctx.AreOriginalAndRandomMotionSameType ()) + return nullptr; + + if (ctx.GetRandMotionType () != "FISH_IN_WATER"_joaat) + return nullptr; + + auto *seagullMotion + = CMotionTaskDataManager::FindByName ("seagull"_joaat); + + auto *seagullModel + = CStreaming::GetModelByHash ("a_c_seagull"_joaat); + + if (!seagullMotion || !seagullModel) + return nullptr; + + ctx.RandModel->m_nMovementClipSet = seagullModel->m_nMovementClipSet; + return GetOnFootMotion (seagullMotion); + } + + /*******************************************************/ + static sMotionTaskData * + RestoreOriginalMotion (const RandomMotionContext &ctx) + { + if (ctx.AreOriginalAndRandomMotionSameType ()) + return nullptr; + + switch (ctx.GetOrigMotionType ()) + { + // Only for bird and fish + case "BIRD_ON_FOOT"_joaat: + case "FISH_IN_WATER"_joaat: + + ctx.RandModel->m_nMovementClipSet + = ctx.OrigModel->m_nMovementClipSet; + + return ctx.OrigMotion; + } + + return nullptr; + } + + /*******************************************************/ + template + static aiTask * + ImproveAnimalMotion (CPed *ped, sMotionTaskData *data, bool lowLod) + { + RandomMotionContext ctx (ped, data); + + if (auto newMotion = MakeFishFly (ctx)) + data = newMotion; + + if (auto newMotion = RestoreOriginalMotion (ctx)) + data = newMotion; + + return CPed__CreateMotioNTask (ped, data, lowLod); + } + +public: + PedRandomizer_AnimalMotion () + { + InitialiseAllComponents (); + + REGISTER_HOOK ("? 8b 52 08 45 8a c1 e8 ? ? ? ? ? 8b c0 ? 8b c0 ", 7, + ImproveAnimalMotion, aiTask *, CPed *, sMotionTaskData *, + bool); + } +} animlMo; diff --git a/src/peds/peds_Compatibility.hh b/src/peds/peds_Compatibility.hh index 7fdfc20..7f9b371 100644 --- a/src/peds/peds_Compatibility.hh +++ b/src/peds/peds_Compatibility.hh @@ -11,6 +11,8 @@ class PedRandomizerCompatibility inline static std::map> sm_PedModelFixupMap; + inline static CPedModelInfo *sm_CurrentRandomizingPed = nullptr; + static bool IsPlayerModel (uint32_t model); /*******************************************************/ @@ -20,9 +22,22 @@ class PedRandomizerCompatibility sm_PedModelFixupMap[ped] = std::make_pair (from, to); } + /*******************************************************/ + static void + SetRandomizingPed (CPedModelInfo *model) + { + sm_CurrentRandomizingPed = model; + } + public: /*******************************************************/ static CPedModelInfo *GetOriginalModel (CPed *ped); + static CPedModelInfo * + GetCurrentPedRandomizing () + { + return sm_CurrentRandomizingPed; + } + friend class PedRandomizer; }; diff --git a/src/peds/peds_Projectiles.cc b/src/peds/peds_Projectiles.cc new file mode 100644 index 0000000..5df720f --- /dev/null +++ b/src/peds/peds_Projectiles.cc @@ -0,0 +1,76 @@ +#include "Utils.hh" +#include +#include +#include + +class TeachPedsHowToThrowProjectiles +{ + + template + static uint64_t + TeachPedsProjectileThrowing (CTaskShootAtTarget *task, uint32_t fsmState, + uint32_t fsmEvent) + { + + if ((fsmState == 1 || fsmState == 2) && fsmEvent == 0) + { + auto *subTask + = CTaskAimAndThrowProjectile::Create (task->targetInfo); + // subTask->nTaskId = eTaskType::CTaskGun; + task->SetSubTask (subTask); + + return 0; + } + else + { + bool change = false; + if (task->subTask + && task->nTaskId == eTaskType::CTaskAimAndThrowProjectile) + { + task->subTask->nTaskId = eTaskType::CTaskGun; + change = true; + } + uint64_t ret + = CTaskShootAtTarget_UpdateFSM (task, fsmState, fsmEvent); + + if (change) + task->subTask->nTaskId + = eTaskType::CTaskAimAndThrowProjectile; + + return ret; + } + } + + template + static uint64_t + CombatHook (CTaskCombat *task, uint32_t fsmState, uint32_t fsmEvent) + { + if (fsmEvent == 0) + Rainbomizer::Logger::LogMessage ("FSM State: %d", fsmState); + if (fsmState == 2 && fsmEvent == 0) + { + task->DoSetState (33); + return false; + } + + return CTaskCombat_UpdateFSM (task, fsmState, fsmEvent); + } + +public: + TeachPedsHowToThrowProjectiles () + { + return; + InitialiseAllComponents (); + + // REGISTER_VFT_HOOK (CTaskShootAtTarget, 14, + // TeachPedsProjectileThrowing, + // uint64_t, CTaskShootAtTarget*, uint32_t, + // uint32_t); + + // REGISTER_VFT_HOOK (CTaskGun, 14, TeachPedsProjectileThrowingGun, + // uint64_t, CTaskGun*, uint32_t, uint32_t); + + REGISTER_VFT_HOOK (CTaskCombat, 14, CombatHook, uint64_t, CTaskCombat *, + uint32_t, uint32_t); + } +} _teachPedsHowToThrowProjectiles;