From 970455ff89948dda24d0ce85f526392da8528c3d Mon Sep 17 00:00:00 2001 From: Pirulax Date: Sun, 1 Oct 2023 18:58:22 +0200 Subject: [PATCH 1/9] Avoid division when `soundLength` is 0 in `CAESound::UpdatePlayTime` (#622) --- source/game_sa/Audio/AESound.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/source/game_sa/Audio/AESound.cpp b/source/game_sa/Audio/AESound.cpp index 0134881377..4b438ea2ed 100644 --- a/source/game_sa/Audio/AESound.cpp +++ b/source/game_sa/Audio/AESound.cpp @@ -184,8 +184,12 @@ void CAESound::UpdatePlayTime(int16 soundLength, int16 loopStartTime, int16 play return; } - assert(soundLength > 0); - m_nCurrentPlayPosition = loopStartTime + (m_nCurrentPlayPosition % soundLength); + // Avoid division by 0 + // This seems to have been fixed the same way in Android + // The cause is/can be missing audio files, but I'm lazy to fix it, so this is gonna be fine for now + m_nCurrentPlayPosition = !notsa::IsFixBugs() || soundLength > 0 + ? loopStartTime + (m_nCurrentPlayPosition % soundLength) + : loopStartTime; } // 0x4EF350 From 3bcd2bbc9471132a66ffeb77ad6ca31002231557 Mon Sep 17 00:00:00 2001 From: Pirulax Date: Sun, 1 Oct 2023 19:02:14 +0200 Subject: [PATCH 2/9] Improve `.clang-format` (#612) --- .clang-format | 188 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 180 insertions(+), 8 deletions(-) diff --git a/.clang-format b/.clang-format index 3383c95a59..a2f48c5c85 100644 --- a/.clang-format +++ b/.clang-format @@ -1,10 +1,182 @@ -Language: Cpp -PointerAlignment: Left +AccessModifierOffset: -4 +AlignAfterOpenBracket: BlockIndent +AlignArrayOfStructures: Left +AlignConsecutiveAssignments: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveBitFields: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveDeclarations: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveMacros: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignEscapedNewlines: Right +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: true +AllowShortEnumsOnASingleLine: false +AllowShortFunctionsOnASingleLine: InlineOnly +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: None +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +AttributeMacros: + - __capability +AlignOperands: DontAlign +BreakBeforeBinaryOperators: NonAssignment +BinPackArguments: false +BinPackParameters: false +BitFieldColonSpacing: Both +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: true + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: false + SplitEmptyNamespace: true +BreakAfterAttributes: Never +BreakBeforeTernaryOperators: true +BreakAfterJavaFieldAnnotations: false +BreakArrays: true +BreakBeforeBraces: Attach +BreakBeforeConceptDeclarations: Always +BreakBeforeInlineASMColon: OnlyMultiline +BreakConstructorInitializers: AfterColon +BreakInheritanceList: BeforeComma +BreakStringLiterals: true +ColumnLimit: 0 +CommentPragmas: "^ IWYU pragma:" +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: false DerivePointerAlignment: false -IndentWrappedFunctionNames: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: false +IncludeBlocks: Preserve +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: false +IndentExternBlock: AfterExternBlock +IndentGotoLabels: false +IndentPPDirectives: BeforeHash +IndentRequiresClause: true IndentWidth: 4 -ColumnLimit: 180 -SortIncludes: false -AccessModifierOffset: -4 -AllowShortFunctionsOnASingleLine: Empty -#AlignConsecutiveDeclarations: true \ No newline at end of file +IndentWrappedFunctionNames: false +InsertBraces: true +InsertNewlineAtEOF: true +InsertTrailingCommas: None +IntegerLiteralSeparator: + Binary: 4 + Decimal: 3 +KeepEmptyLinesAtTheStartOfBlocks: false +LambdaBodyIndentation: Signature +Language: Cpp +LineEnding: DeriveLF +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +PPIndentWidth: -1 +PackConstructorInitializers: Never +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +QualifierAlignment: Left +ReferenceAlignment: Pointer +ReflowComments: false +RemoveBracesLLVM: false +RemoveSemicolon: true +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Always +ShortNamespaceLines: 1 +SortIncludes: Never +SortUsingDeclarations: Never +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDeclarationName: false + AfterFunctionDefinitionName: false + AfterIfMacros: true + AfterOverloadedOperator: false + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInCStyleCastParentheses: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Latest +TabWidth: 4 +UseTab: Never +WhitespaceSensitiveMacros: + - RwRenderStateSet + - RwRenderStateGet + - RH_ScopedOverloadedInstall + - RH_ScopedInstall + - RH_ScopedVMTInstall + - RH_ScopedVirtualInstall + - RH_ScopedGlobalInstall +AlignConsecutiveShortCaseStatements: + Enabled: true + AcrossEmptyLines: true + AcrossComments: true + AlignCaseColons: false \ No newline at end of file From 5ebb4583178df8d24c9fcd769da431d999c0d088 Mon Sep 17 00:00:00 2001 From: Pirulax Date: Wed, 4 Oct 2023 17:40:36 +0200 Subject: [PATCH 3/9] `CTaskComplexGoToCarDoorAndStandStill` (#624) * Refactor code, rename variables * Fix `CPool::Delete` * Fix .clang-format for VS * Add `CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse` * Add `CTaskComplexGoToCarDoorAndStandStill` --- .clang-format | 12 +- source/InjectHooksMain.cpp | 3 +- source/game_sa/Core/Pool.h | 5 + source/game_sa/Core/Vector.h | 4 +- .../TaskTypes/TaskComplexFollowPointRoute.h | 11 +- .../TaskComplexGoToCarDoorAndStandStill.cpp | 280 +++++++++++++++--- .../TaskComplexGoToCarDoorAndStandStill.h | 73 +++-- ...eCarGoToPointNearDoorUntilDoorNotInUse.cpp | 65 ++++ ...pleCarGoToPointNearDoorUntilDoorNotInUse.h | 54 ++++ .../TaskSimpleCarWaitForDoorNotToBeInUse.h | 2 +- .../Tasks/TaskTypes/TaskSimpleGoToPoint.h | 2 + 11 files changed, 432 insertions(+), 79 deletions(-) create mode 100644 source/game_sa/Tasks/TaskTypes/TaskSimpleCarGoToPointNearDoorUntilDoorNotInUse.cpp create mode 100644 source/game_sa/Tasks/TaskTypes/TaskSimpleCarGoToPointNearDoorUntilDoorNotInUse.h diff --git a/.clang-format b/.clang-format index a2f48c5c85..18ca88c1c8 100644 --- a/.clang-format +++ b/.clang-format @@ -175,8 +175,10 @@ WhitespaceSensitiveMacros: - RH_ScopedVMTInstall - RH_ScopedVirtualInstall - RH_ScopedGlobalInstall -AlignConsecutiveShortCaseStatements: - Enabled: true - AcrossEmptyLines: true - AcrossComments: true - AlignCaseColons: false \ No newline at end of file + +# VS's clang-format is not up-to-date enough for this yet +#AlignConsecutiveShortCaseStatements: +# Enabled: true +# AcrossEmptyLines: true +# AcrossComments: true +# AlignCaseColons: false \ No newline at end of file diff --git a/source/InjectHooksMain.cpp b/source/InjectHooksMain.cpp index f99bdbd9ed..466617af76 100644 --- a/source/InjectHooksMain.cpp +++ b/source/InjectHooksMain.cpp @@ -253,6 +253,7 @@ #include "TaskComplexCrossRoadLookAndAchieveHeading.h" #include "TaskComplexGoToPointAndStandStill.h" #include "TaskSimpleAchieveHeading.h" +#include "TaskSimpleCarGoToPointNearDoorUntilDoorNotInUse.h" #include "TaskSimpleGiveCPR.h" #include "TaskSimpleCarSetPedInAsPassenger.h" #include "TaskComplexDriveFireTruck.h" @@ -943,7 +944,7 @@ void InjectHooksMain() { // CTaskSimpleCarForcePedOut::InjectHooks(); CTaskSimpleCarGetOut::InjectHooks(); CTaskSimpleCarGetIn::InjectHooks(); - // CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse::InjectHooks(); + CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse::InjectHooks(); CTaskSimpleCarOpenDoorFromOutside::InjectHooks(); CTaskSimpleCarJumpOut::InjectHooks(); CTaskSimpleCarOpenLockedDoorFromOutside::InjectHooks(); diff --git a/source/game_sa/Core/Pool.h b/source/game_sa/Core/Pool.h index 6e0cbf5e23..a81cfdfa8a 100644 --- a/source/game_sa/Core/Pool.h +++ b/source/game_sa/Core/Pool.h @@ -205,6 +205,11 @@ template class CPool { // Deallocates object void Delete(A* obj) { +#ifdef FIX_BUGS // C++ says that `delete nullptr` is well defined, and should do nothing. + if (!obj) { + return; + } +#endif int32 index = GetIndex(obj); m_byteMap[index].bEmpty = true; if (index < m_nFirstFree) diff --git a/source/game_sa/Core/Vector.h b/source/game_sa/Core/Vector.h index e97d9bdbe1..11a0447a7f 100644 --- a/source/game_sa/Core/Vector.h +++ b/source/game_sa/Core/Vector.h @@ -139,8 +139,8 @@ class CVector : public RwV3d { //! Get a copy of `*this` vector projected onto `projectOnTo` (which is assumed to be unit length) //! The result will have a magnitude of `sqrt(abs(this->Dot(projectOnTo)))` - CVector ProjectOnToNormal(const CVector& projectOnTo) const { - return projectOnTo * Dot(projectOnTo); + CVector ProjectOnToNormal(const CVector& projectOnTo, float offset = 0.f) const { + return projectOnTo * (Dot(projectOnTo) + offset); } //! Calculate the average position diff --git a/source/game_sa/Tasks/TaskTypes/TaskComplexFollowPointRoute.h b/source/game_sa/Tasks/TaskTypes/TaskComplexFollowPointRoute.h index 083fd443bd..eef7805c8b 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskComplexFollowPointRoute.h +++ b/source/game_sa/Tasks/TaskTypes/TaskComplexFollowPointRoute.h @@ -47,7 +47,16 @@ class NOTSA_EXPORT_VTABLE CTaskComplexFollowPointRoute : public CTaskComplex { static constexpr auto Type = eTaskType::TASK_COMPLEX_FOLLOW_POINT_ROUTE; - CTaskComplexFollowPointRoute(eMoveState moveState, CPointRoute const& route, Mode mode, float targetRadius, float slowDownDist, bool overshootTarget, bool useBlending, bool standStillAfterMove); + CTaskComplexFollowPointRoute( + eMoveState moveState, + CPointRoute const& route, + Mode mode = Mode::ONE_WAY, + float targetRadius = 0.5f, + float slowDownDist = 5.f, + bool overshootTarget = false, + bool useBlending = true, + bool standStillAfterMove = true + ); CTaskComplexFollowPointRoute(const CTaskComplexFollowPointRoute&); ~CTaskComplexFollowPointRoute() override; diff --git a/source/game_sa/Tasks/TaskTypes/TaskComplexGoToCarDoorAndStandStill.cpp b/source/game_sa/Tasks/TaskTypes/TaskComplexGoToCarDoorAndStandStill.cpp index 1180286a61..ec1c61c72b 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskComplexGoToCarDoorAndStandStill.cpp +++ b/source/game_sa/Tasks/TaskTypes/TaskComplexGoToCarDoorAndStandStill.cpp @@ -1,82 +1,288 @@ #include "StdInc.h" #include "TaskComplexGoToCarDoorAndStandStill.h" +#include "TaskSimpleCarGoToPointNearDoorUntilDoorNotInUse.h" +#include "TaskSimplePause.h" +#include "TaskSimpleStandStill.h" +#include "TaskSimpleCarWaitForDoorNotToBeInUse.h" +#include "TaskComplexFollowPointRoute.h" +#include "TaskSimpleGoToPoint.h" void CTaskComplexGoToCarDoorAndStandStill::InjectHooks() { - RH_ScopedClass(CTaskComplexGoToCarDoorAndStandStill); + RH_ScopedVirtualClass(CTaskComplexGoToCarDoorAndStandStill, 0x86ec4c, 11); RH_ScopedCategory("Tasks/TaskTypes"); RH_ScopedInstall(Constructor, 0x645780); RH_ScopedInstall(Destructor, 0x64A580); - RH_ScopedInstall(IsVehicleInRange, 0x6458A0, { .reversed = false }); - RH_ScopedInstall(ComputeRouteToDoor, 0x645910, { .reversed = false }); - - RH_ScopedVirtualInstall2(CreateSubTask, 0x64A5F0, { .reversed = false }); - RH_ScopedVirtualInstall2(Clone, 0x6498B0, { .reversed = false }); - RH_ScopedVirtualInstall2(MakeAbortable, 0x645840, { .reversed = false }); - RH_ScopedVirtualInstall2(CreateNextSubTask, 0x64D2B0, { .reversed = false }); - RH_ScopedVirtualInstall2(CreateFirstSubTask, 0x64D440, { .reversed = false }); - RH_ScopedVirtualInstall2(ControlSubTask, 0x64A820, { .reversed = false }); + + RH_ScopedInstall(IsVehicleInRange, 0x6458A0); + RH_ScopedInstall(ComputeRouteToDoor, 0x645910); + RH_ScopedInstall(CreateSubTask, 0x64A5F0); + + RH_ScopedVMTInstall(Clone, 0x6498B0); + RH_ScopedVMTInstall(GetTaskType, 0x645830); + RH_ScopedVMTInstall(MakeAbortable, 0x645840); + RH_ScopedVMTInstall(CreateNextSubTask, 0x64D2B0); + RH_ScopedVMTInstall(CreateFirstSubTask, 0x64D440); + RH_ScopedVMTInstall(ControlSubTask, 0x64A820); } // 0x645780 -CTaskComplexGoToCarDoorAndStandStill::CTaskComplexGoToCarDoorAndStandStill(CVehicle* vehicle, int32 moveState, bool a4, int32 a5, float radius, float a7, float a8, int32 a9) { - m_Vehicle = vehicle; - m_nMoveState = moveState; - f14 = a4; - m_fRadius = radius; - f1C = a7; - f20 = a8; - f24 = a9; - f28 = 0; - f2C = 0.0f; - f30 = false; - m_nDoorId = 0; - m_vecPositionToOpenCarDoor = CVector{}; - f44 = a5; - f48 = false; - f49 = false; - m_PointRoute = nullptr; +CTaskComplexGoToCarDoorAndStandStill::CTaskComplexGoToCarDoorAndStandStill( + CVehicle* vehicle, + eMoveState moveState, + bool bIsDriver, + int32 targetSeat, + float targetRadius, + float slowDownDist, + float maxSeekDist, + int32 maxSeekTime +) : + m_Vehicle{vehicle}, + m_MoveState{moveState}, + m_bIsDriver{bIsDriver}, + m_TargetRadius{targetRadius}, + m_SlowDownDist{slowDownDist}, + m_MaxSeekDist{maxSeekDist}, + m_MaxSeekTime{maxSeekTime}, + m_TargetSeat{targetSeat} +{ CEntity::SafeRegisterRef(m_Vehicle); } +// 0x6498B0 +CTaskComplexGoToCarDoorAndStandStill::CTaskComplexGoToCarDoorAndStandStill(const CTaskComplexGoToCarDoorAndStandStill& o) : + CTaskComplexGoToCarDoorAndStandStill{ o.m_Vehicle, o.m_MoveState, o.m_bIsDriver, o.m_TargetSeat, o.m_TargetRadius, o.m_SlowDownDist, o.m_MaxSeekDist, o.m_MaxSeekTime } +{ +} + // 0x64A580 CTaskComplexGoToCarDoorAndStandStill::~CTaskComplexGoToCarDoorAndStandStill() { CEntity::SafeCleanUpRef(m_Vehicle); - if (m_PointRoute) delete m_PointRoute; // allocated on the pool, a check is required + delete m_RouteToDoor; } // 0x645840 bool CTaskComplexGoToCarDoorAndStandStill::MakeAbortable(CPed* ped, eAbortPriority priority, const CEvent* event) { - return plugin::CallMethodAndReturn(this, ped, priority, event); + if (m_bTryingToEnterInWater) { + if (m_pSubTask && m_pSubTask->GetTaskType() == TASK_SIMPLE_PAUSE) { + if (event && notsa::contains({ EVENT_IN_WATER, EVENT_IN_AIR }, event->GetEventType())) { + return false; + } + } + } + return m_pSubTask->MakeAbortable(ped, priority, event); } // 0x64A5F0 -CTask* CTaskComplexGoToCarDoorAndStandStill::CreateSubTask(eTaskType taskType, const CPed* ped) { - return plugin::CallMethodAndReturn(this, taskType, ped); +CTask* CTaskComplexGoToCarDoorAndStandStill::CreateSubTask(eTaskType taskType, CPed* ped) { + switch (taskType) { + case TASK_SIMPLE_GO_TO_POINT_NEAR_CAR_DOOR_UNTIL_DOOR_NOT_IN_USE: + return new CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse{ m_Vehicle, m_TargetDoor, m_TargetPt, m_MoveState }; + case TASK_SIMPLE_PAUSE: + return new CTaskSimplePause{ 1 }; + case TASK_SIMPLE_STAND_STILL: + return new CTaskSimpleStandStill{ 1 }; + case TASK_SIMPLE_CAR_WAIT_FOR_DOOR_NOT_TO_BE_IN_USE: + return new CTaskSimpleCarWaitForDoorNotToBeInUse{ m_Vehicle, (uint32)m_TargetDoor }; + case TASK_COMPLEX_FOLLOW_POINT_ROUTE: + return new CTaskComplexFollowPointRoute{ m_MoveState, *m_RouteToDoor }; + case TASK_SIMPLE_GO_TO_POINT: { + ped->bHasJustLeftCar = true; + return new CTaskSimpleGoToPoint{ m_MoveState, m_TargetPt, m_TargetRadius }; + } + case TASK_FINISHED: + return nullptr; + default: + NOTSA_UNREACHABLE(); + } } // 0x64D2B0 CTask* CTaskComplexGoToCarDoorAndStandStill::CreateNextSubTask(CPed* ped) { - return plugin::CallMethodAndReturn(this, ped); + switch (const auto tt = m_pSubTask->GetTaskType()) { + case TASK_COMPLEX_FOLLOW_POINT_ROUTE: { // 0x64D3B8 + m_TargetPt = CCarEnterExit::GetPositionToOpenCarDoor(m_Vehicle, m_TargetDoor); + return CreateSubTask(TASK_SIMPLE_GO_TO_POINT, ped); + } + case TASK_SIMPLE_GO_TO_POINT: { // 0x64D3E9 + m_bAchievedTargetDoor |= static_cast(m_pSubTask)->WasTaskSuccessful(ped); + return CreateSubTask(TASK_FINISHED, ped); + } + case TASK_SIMPLE_GO_TO_POINT_NEAR_CAR_DOOR_UNTIL_DOOR_NOT_IN_USE: // 0x64D387 + return CreateSubTask(TASK_SIMPLE_CAR_WAIT_FOR_DOOR_NOT_TO_BE_IN_USE, ped); + case TASK_SIMPLE_CAR_WAIT_FOR_DOOR_NOT_TO_BE_IN_USE: // 0x64D2EB + return CreateFirstSubTask(ped); + case TASK_SIMPLE_STAND_STILL: // 0x64D420 + return CreateSubTask(TASK_FINISHED, ped); + case TASK_SIMPLE_PAUSE: { // 0x64D314 + if (m_bTryingToEnterInWater) { + m_bAchievedTargetDoor |= (ped->GetPosition() - m_TargetPt).SquaredMagnitude2D() <= sq(0.5f); + } + return CreateSubTask(TASK_FINISHED, ped); + } + default: + NOTSA_UNREACHABLE("SubTaskType: {}", (int)tt); + } } // 0x64D440 CTask* CTaskComplexGoToCarDoorAndStandStill::CreateFirstSubTask(CPed* ped) { - return plugin::CallMethodAndReturn(this, ped); + return CreateSubTask([this, ped] { + if (!IsVehicleInRange(*ped)) { + return TASK_SIMPLE_STAND_STILL; + } + + if (m_bTryingToEnterInWater) { + return TASK_SIMPLE_PAUSE; + } + + if (m_TargetSeat != 0 && !m_bIsDriver) { + if (const auto psgrAtDoor = m_Vehicle->GetPassengers()[CCarEnterExit::ComputePassengerIndexFromCarDoor(m_Vehicle, m_TargetDoor)]) { + if (psgrAtDoor->bThisPedIsATargetPriority) { + return TASK_SIMPLE_STAND_STILL; + } + } + } + + // Calculate the door to use + bool bCanWaitForDoorToBeFree; + if (!CalculateTargetDoor(ped, bCanWaitForDoorToBeFree)) { + if (!bCanWaitForDoorToBeFree) { + return TASK_SIMPLE_STAND_STILL; + } + } + + // If it's blocked by something we first have to get into a position where it's not blocked + if (CCarEnterExit::IsPathToDoorBlockedByVehicleCollisionModel(ped, m_Vehicle, m_TargetPt)) { + ComputeRouteToDoor(*ped); + return TASK_COMPLEX_FOLLOW_POINT_ROUTE; // 0x64D4E7 + } + + // Otherwise we can just go to the door straight + return bCanWaitForDoorToBeFree + ? TASK_SIMPLE_GO_TO_POINT_NEAR_CAR_DOOR_UNTIL_DOOR_NOT_IN_USE + : TASK_SIMPLE_GO_TO_POINT; + }(), ped); } // 0x64A820 CTask* CTaskComplexGoToCarDoorAndStandStill::ControlSubTask(CPed* ped) { - return plugin::CallMethodAndReturn(this, ped); + if (!m_Vehicle) { + return nullptr; + } + + if (!ped->IsCop()) { + if (const auto drvr = m_Vehicle->m_pDriver) { + if (drvr->IsPlayer() && drvr->m_nPedState == PEDSTATE_ARRESTED) { + return CreateSubTask(TASK_SIMPLE_STAND_STILL, ped); // 0x64A875 + } + } + } + + switch (const auto tt = m_pSubTask->GetTaskType()) { + case TASK_SIMPLE_GO_TO_POINT_NEAR_CAR_DOOR_UNTIL_DOOR_NOT_IN_USE: + case TASK_SIMPLE_PAUSE: + case TASK_SIMPLE_STAND_STILL: + case TASK_SIMPLE_CAR_WAIT_FOR_DOOR_NOT_TO_BE_IN_USE: { // 0x64A890 + if (m_TargetDoor != 0) { // TODO: Enum + m_TargetPt = CCarEnterExit::GetPositionToOpenCarDoor(m_Vehicle, m_TargetDoor); + } + return m_pSubTask; + } + case TASK_SIMPLE_GO_TO_POINT: { // 0x64AA11 + ped->bPushOtherPeds = true; + + if (!IsVehicleInRange(*ped)) { // Inverted + m_TargetPt = CCarEnterExit::GetPositionToOpenCarDoor(m_Vehicle, m_TargetDoor); + return CreateSubTask(TASK_SIMPLE_STAND_STILL, ped); // 0x64AA50 + } + + if (bool bCanWaitForDoorToBeFree; !CalculateTargetDoor(ped, bCanWaitForDoorToBeFree)) { + return CreateSubTask(bCanWaitForDoorToBeFree ? TASK_SIMPLE_GO_TO_POINT_NEAR_CAR_DOOR_UNTIL_DOOR_NOT_IN_USE : TASK_SIMPLE_STAND_STILL, ped); + } + static_cast(m_pSubTask)->UpdatePoint(m_TargetPt, m_TargetRadius); + + return m_pSubTask; + } + case TASK_COMPLEX_FOLLOW_POINT_ROUTE: { // 0x64A8FA + const auto doorOpenPos = CCarEnterExit::GetPositionToOpenCarDoor(m_Vehicle, m_TargetDoor); + + if (!IsVehicleInRange(*ped)) { + m_TargetPt = doorOpenPos; + return CreateSubTask(TASK_SIMPLE_STAND_STILL, ped); // 0x64A94A + } + + if (!CCarEnterExit::IsPathToDoorBlockedByVehicleCollisionModel(ped, m_Vehicle, doorOpenPos)) { + m_TargetPt = doorOpenPos; + return CreateSubTask(TASK_SIMPLE_GO_TO_POINT, ped); // 0x64A990 + } + + if ((m_TargetPt - doorOpenPos).SquaredMagnitude() >= sq(0.1f)) { // 0x64A9D1 + m_TargetPt = doorOpenPos; + return CreateFirstSubTask(ped); + } + + return m_pSubTask; + } + default: + NOTSA_UNREACHABLE("SubTaskType: {}", (int)tt); + } } // 0x6458A0 bool CTaskComplexGoToCarDoorAndStandStill::IsVehicleInRange(const CPed& ped) { - return plugin::CallMethodAndReturn(this, ped); + return (ped.GetPosition() - m_Vehicle->GetPosition()).SquaredMagnitude() <= sq(m_MaxSeekDist); } // 0x645910 -CVector* CTaskComplexGoToCarDoorAndStandStill::ComputeRouteToDoor(const CPed& ped) { - return plugin::CallMethodAndReturn(this, ped); +void CTaskComplexGoToCarDoorAndStandStill::ComputeRouteToDoor(const CPed& ped) { + if (!m_RouteToDoor) { + m_RouteToDoor = new CPointRoute{}; + } + m_RouteToDoor->Clear(); + + const CVector pedPos = ped.GetPosition(); + + CVector vehBBPlanes[4]; + float vehBBPlanesDot[4]; + CPedGeometryAnalyser::ComputeEntityBoundingBoxPlanesUncachedAll(pedPos.z, *m_Vehicle, &vehBBPlanes, vehBBPlanesDot); + const auto CalculatePositionOnPlane = [&](CVector pos, int32 side) { + return pos - pos.ProjectOnToNormal(vehBBPlanes[side], vehBBPlanesDot[side]); + }; + + const auto pedPosOnBBPlane = CalculatePositionOnPlane(pedPos, CPedGeometryAnalyser::ComputeEntityHitSide(pedPos, *m_Vehicle)); + const auto doorPosOnBBPlane = CalculatePositionOnPlane(m_TargetPt, CPedGeometryAnalyser::ComputeEntityHitSide(m_TargetPt, *m_Vehicle)); + + CPointRoute routeAroundVeh{}; + CPedGeometryAnalyser::ComputeRouteRoundEntityBoundingBox(ped, pedPosOnBBPlane, *m_Vehicle, doorPosOnBBPlane, routeAroundVeh, 0); + + m_RouteToDoor->MaybeAddPoint(pedPosOnBBPlane); + for (const auto& pt : routeAroundVeh.GetPoints()) { + m_RouteToDoor->MaybeAddPoint(pt); + } + m_RouteToDoor->MaybeAddPoint(doorPosOnBBPlane); +} + +// Based on SA code +// Calculate door to use and it's position +// Original code is much different, I had to refactor it to get rid of the copy pasta +bool CTaskComplexGoToCarDoorAndStandStill::CalculateTargetDoor(CPed* ped, bool& bCanWaitForDoorToBeFree) { + bCanWaitForDoorToBeFree = false; + if (m_TargetSeat != 0) { + m_TargetDoor = m_TargetSeat; + m_TargetPt = CCarEnterExit::GetPositionToOpenCarDoor(m_Vehicle, m_TargetSeat); + } else { + if (m_bIsDriver) { + if (!CCarEnterExit::GetNearestCarDoor(ped, m_Vehicle, m_TargetPt, m_TargetDoor)) { + return false; + } + } else { + if (!CCarEnterExit::GetNearestCarPassengerDoor(ped, m_Vehicle, &m_TargetPt, &m_TargetDoor, true, true, true)) { + bCanWaitForDoorToBeFree = CCarEnterExit::GetNearestCarPassengerDoor(ped, m_Vehicle, &m_TargetPt, &m_TargetDoor, true, false, true); + return false; + } + } + } + return true; } diff --git a/source/game_sa/Tasks/TaskTypes/TaskComplexGoToCarDoorAndStandStill.h b/source/game_sa/Tasks/TaskTypes/TaskComplexGoToCarDoorAndStandStill.h index 877f6a7ac8..b297f80dd6 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskComplexGoToCarDoorAndStandStill.h +++ b/source/game_sa/Tasks/TaskTypes/TaskComplexGoToCarDoorAndStandStill.h @@ -5,48 +5,57 @@ class CVector; class CVehicle; -class CTaskComplexGoToCarDoorAndStandStill : public CTaskComplex { -public: - CVehicle* m_Vehicle; - int32 m_nMoveState; - bool f14; - float m_fRadius; // radius - float f1C; - float f20; - int32 f24; - uint32 f28; // time - float f2C; - bool f30; - int32 m_nDoorId; - CVector m_vecPositionToOpenCarDoor; - int32 f44; // next/prev door id - bool f48; - bool f49; - CPointRoute* m_PointRoute; - int32 dword44; - +class NOTSA_EXPORT_VTABLE CTaskComplexGoToCarDoorAndStandStill : public CTaskComplex { public: static constexpr auto Type = TASK_COMPLEX_GO_TO_CAR_DOOR_AND_STAND_STILL; - CTaskComplexGoToCarDoorAndStandStill(CVehicle* vehicle, int32 moveState, bool a4, int32 a5, float a6, float a7, float a8, int32 a9); + CTaskComplexGoToCarDoorAndStandStill( + CVehicle* vehicle, + eMoveState moveState, + bool bIsDriver, + int32 targetSeat, + float targetRadius, + float slowDownDist, + float maxSeekDist, + int32 maxSeekTime + ); + CTaskComplexGoToCarDoorAndStandStill(const CTaskComplexGoToCarDoorAndStandStill&); ~CTaskComplexGoToCarDoorAndStandStill() override; + CTask* Clone() const override { return new CTaskComplexGoToCarDoorAndStandStill{ *this }; } eTaskType GetTaskType() const override { return Type; } - CTask* Clone() const override { return new CTaskComplexGoToCarDoorAndStandStill(m_Vehicle, m_nMoveState, f14, f44, m_fRadius, f1C, f20, f24); } // 0x6498B0 - bool MakeAbortable(CPed* ped, eAbortPriority priority = ABORT_PRIORITY_URGENT, const CEvent* event = nullptr) override; - CTask* CreateNextSubTask(CPed* ped) override; - CTask* CreateFirstSubTask(CPed* ped) override; - CTask* ControlSubTask(CPed* ped) override; + bool MakeAbortable(CPed* ped, eAbortPriority priority = ABORT_PRIORITY_URGENT, CEvent const* event = nullptr) override; + CTask* CreateNextSubTask(CPed* ped) override; + CTask* CreateFirstSubTask(CPed* ped) override; + CTask* ControlSubTask(CPed* ped) override; - bool IsVehicleInRange(const CPed& ped); - CVector* ComputeRouteToDoor(const CPed & ped); - CTask* CreateSubTask(eTaskType taskType, const CPed* ped); +protected: + CTask* CreateSubTask(eTaskType taskType, CPed* ped); + bool IsVehicleInRange(const CPed& ped); + void ComputeRouteToDoor(const CPed& ped); + bool CalculateTargetDoor(CPed* ped, bool& bCanWaitForDoorToBeFree); private: friend void InjectHooksMain(); static void InjectHooks(); - CTaskComplexGoToCarDoorAndStandStill* Constructor(CVehicle* vehicle, int32 a3, bool a4, int32 a5, float a6, float a7, float a8, int32 a9) { this->CTaskComplexGoToCarDoorAndStandStill::CTaskComplexGoToCarDoorAndStandStill(vehicle, a3, a4, a5, a6, a7, a8, a9); return this; } + + CTaskComplexGoToCarDoorAndStandStill* Constructor(CVehicle* vehicle, eMoveState a3, bool a4, int32 a5, float a6, float a7, float a8, int32 a9) { this->CTaskComplexGoToCarDoorAndStandStill::CTaskComplexGoToCarDoorAndStandStill(vehicle, a3, a4, a5, a6, a7, a8, a9); return this; } CTaskComplexGoToCarDoorAndStandStill* Destructor() { this->CTaskComplexGoToCarDoorAndStandStill::~CTaskComplexGoToCarDoorAndStandStill(); return this; } - bool MakeAbortable_Reversed(CPed* ped, eAbortPriority priority, const CEvent* event); + +public: + CVehicle* m_Vehicle{}; + eMoveState m_MoveState{}; + bool m_bIsDriver{}; + float m_TargetRadius{}; + float m_SlowDownDist{}; + float m_MaxSeekDist{}; + int32 m_MaxSeekTime{}; + CTaskTimer m_SeekTimer{}; + int32 m_TargetDoor{}; + CVector m_TargetPt{}; + int32 m_TargetSeat{}; + bool m_bTryingToEnterInWater{}; + bool m_bAchievedTargetDoor{}; + CPointRoute* m_RouteToDoor{}; }; -VALIDATE_SIZE(CTaskComplexGoToCarDoorAndStandStill, 0x54); +VALIDATE_SIZE(CTaskComplexGoToCarDoorAndStandStill, 0x50); diff --git a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarGoToPointNearDoorUntilDoorNotInUse.cpp b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarGoToPointNearDoorUntilDoorNotInUse.cpp new file mode 100644 index 0000000000..5546f7d4da --- /dev/null +++ b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarGoToPointNearDoorUntilDoorNotInUse.cpp @@ -0,0 +1,65 @@ +#include "StdInc.h" + +#include "TaskSimpleCarGoToPointNearDoorUntilDoorNotInUse.h" +#include "TaskSimpleGoToPoint.h" +#include "TaskSimpleCarWaitForDoorNotToBeInUse.h" +#include "TaskSimpleStandStill.h" + +void CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse::InjectHooks() { + RH_ScopedVirtualClass(CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse, 0x86ede0, 9); + RH_ScopedCategory("Tasks/TaskTypes"); + + RH_ScopedInstall(Constructor, 0x646D70); + RH_ScopedInstall(Destructor, 0x646E50); + + RH_ScopedVMTInstall(Clone, 0x646EC0); + RH_ScopedVMTInstall(GetTaskType, 0x646E30); + RH_ScopedVMTInstall(MakeAbortable, 0x646E40); + RH_ScopedVMTInstall(ProcessPed, 0x64B4A0); +} + +// 0x646D70 +CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse::CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse( + CVehicle* vehicle, + int32 targetDoor, + const CVector& targetPt, + eMoveState moveState +) : + m_TaskGoToPoint{ new CTaskSimpleGoToPoint{ moveState, targetPt } }, + m_TaskWaitForDoor{ new CTaskSimpleCarWaitForDoorNotToBeInUse{ vehicle, (uint32)targetDoor } } +{ +} + +// 0x646EC0 +CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse::CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse(const CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse&) : + CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse{ + m_TaskWaitForDoor->m_veh, + static_cast(m_TaskWaitForDoor->m_doorsToWaitFor[0]), + m_TaskGoToPoint->m_vecTargetPoint, + m_TaskGoToPoint->m_moveState + } +{ +} + +// 0x646E50 +CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse::~CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse() { + delete m_TaskGoToPoint; + delete m_TaskWaitForDoor; +} + +// 0x64B4A0 +bool CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse::ProcessPed(CPed* ped) { + m_TaskGoToPoint->UpdatePoint(ComputeTarget()); + if (!m_TaskGoToPoint->ProcessPed(ped)) { + return m_TaskWaitForDoor->ProcessPed(ped); + } + CTaskSimpleStandStill{-1}.ProcessPed(ped); + return true; +} + +// 0x646F40 +CVector CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse::ComputeTarget() const { + const auto veh = m_TaskWaitForDoor->m_veh; + const CVector vehPos = veh->GetPosition(); + return vehPos + (CCarEnterExit::GetPositionToOpenCarDoor(veh, m_TaskWaitForDoor->m_doorsToWaitFor[0]) - vehPos) * 2.f; +} diff --git a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarGoToPointNearDoorUntilDoorNotInUse.h b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarGoToPointNearDoorUntilDoorNotInUse.h new file mode 100644 index 0000000000..8b33bd90ba --- /dev/null +++ b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarGoToPointNearDoorUntilDoorNotInUse.h @@ -0,0 +1,54 @@ +#pragma once + +#include "TaskSimple.h" +#include "Vector.h" + +#include "Enums/eTargetDoor.h" +#include "Enums/eMoveState.h" + +class CPed; +class CTaskSimpleGoToPoint; +class CTaskSimpleCarWaitForDoorNotToBeInUse; +class CEvent; +class CVehicle; + +class NOTSA_EXPORT_VTABLE CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse : public CTaskSimple { +public: + static constexpr auto Type = eTaskType::TASK_SIMPLE_GO_TO_POINT_NEAR_CAR_DOOR_UNTIL_DOOR_NOT_IN_USE; + + static void InjectHooks(); + + CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse( + CVehicle* vehicle, + int32 targetDoor, + const CVector& targetPt, + eMoveState moveState + ); + CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse(const CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse&); + ~CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse(); + + CTask* Clone() const override { return new CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse{ *this }; } + eTaskType GetTaskType() const override { return Type; } + bool MakeAbortable(CPed* ped, eAbortPriority priority = ABORT_PRIORITY_URGENT, CEvent const* event = nullptr) override { return true; } + bool ProcessPed(CPed* ped) override; + +protected: + CVector ComputeTarget() const; + +protected: + CTaskSimpleGoToPoint* m_TaskGoToPoint{}; + CTaskSimpleCarWaitForDoorNotToBeInUse* m_TaskWaitForDoor{}; + +private: // Wrappers for hooks + // 0x646D70 + CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse* Constructor(CVehicle* vehicle, int32 targetDoor, const CVector& targetPt, eMoveState moveState) { + this->CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse::CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse(vehicle, targetDoor, targetPt, moveState); + return this; + } + + // 0x646E50 + CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse* Destructor() { + this->CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse::~CTaskSimpleCarGoToPointNearDoorUntilDoorNotInUse(); + return this; + } +}; diff --git a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarWaitForDoorNotToBeInUse.h b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarWaitForDoorNotToBeInUse.h index 3b65896f1d..c1bd47ff72 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarWaitForDoorNotToBeInUse.h +++ b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarWaitForDoorNotToBeInUse.h @@ -18,7 +18,7 @@ class NOTSA_EXPORT_VTABLE CTaskSimpleCarWaitForDoorNotToBeInUse : public CTaskSi constexpr static auto Type = eTaskType::TASK_SIMPLE_CAR_WAIT_FOR_DOOR_NOT_TO_BE_IN_USE; - CTaskSimpleCarWaitForDoorNotToBeInUse(CVehicle * veh, uint32 doorToWaitFor1, uint32 doorToWaitFor2); + CTaskSimpleCarWaitForDoorNotToBeInUse(CVehicle * veh, uint32 doorToWaitFor1, uint32 doorToWaitFor2 = 0); CTaskSimpleCarWaitForDoorNotToBeInUse(const CTaskSimpleCarWaitForDoorNotToBeInUse&); ~CTaskSimpleCarWaitForDoorNotToBeInUse(); diff --git a/source/game_sa/Tasks/TaskTypes/TaskSimpleGoToPoint.h b/source/game_sa/Tasks/TaskTypes/TaskSimpleGoToPoint.h index 88b6969c4f..08326be2df 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskSimpleGoToPoint.h +++ b/source/game_sa/Tasks/TaskTypes/TaskSimpleGoToPoint.h @@ -30,6 +30,8 @@ class CTaskSimpleGoToPoint : public CTaskSimpleGoTo { // bDontCheckRadius is always false void UpdatePoint(const CVector& targetPosition, float fRadius = 0.5f, bool bDontCheckRadius = false); + bool WasTaskSuccessful(CPed* ped) const { return gotoPointFlags.m_b03 && std::abs(m_vecTargetPoint.z - ped->GetPosition().z) < 3.f; } + static void InjectHooks(); auto Constructor(eMoveState moveState, const CVector& targetPoint, float fRadius, bool bMoveTowardsTargetPoint, bool a6) { this->CTaskSimpleGoToPoint::CTaskSimpleGoToPoint(moveState, targetPoint, fRadius, bMoveTowardsTargetPoint, a6); return this; } bool MakeAbortable_Reversed(CPed* ped, eAbortPriority priority, const CEvent* event); From e240f03b5da9f16ba0b921700330e43502eda45f Mon Sep 17 00:00:00 2001 From: Pirulax Date: Thu, 5 Oct 2023 19:46:43 +0200 Subject: [PATCH 4/9] `CTaskSimpleCarShuffle` (#627) --- source/InjectHooksMain.cpp | 3 +- .../game_sa/Animation/AnimBlendAssociation.h | 6 +- .../Tasks/TaskTypes/TaskSimpleCarAlign.cpp | 2 +- .../TaskSimpleCarCloseDoorFromInside.cpp | 4 +- .../TaskSimpleCarCloseDoorFromOutside.cpp | 2 +- .../Tasks/TaskTypes/TaskSimpleCarGetIn.cpp | 2 +- .../Tasks/TaskTypes/TaskSimpleCarGetOut.cpp | 2 +- .../Tasks/TaskTypes/TaskSimpleCarJumpOut.cpp | 2 +- .../TaskSimpleCarOpenDoorFromOutside.cpp | 2 +- ...TaskSimpleCarOpenLockedDoorFromOutside.cpp | 2 +- .../TaskSimpleCarOpenLockedDoorFromOutside.h | 1 + .../Tasks/TaskTypes/TaskSimpleCarShuffle.cpp | 100 ++++++++++++++++++ .../Tasks/TaskTypes/TaskSimpleCarShuffle.h | 51 +++++++++ .../TaskTypes/TaskSimpleCarSlowDragPedOut.cpp | 2 +- .../Tasks/TaskTypes/TaskSimplePickUpBike.cpp | 2 +- source/game_sa/VehicleAnimGroupData.cpp | 49 +++++---- source/game_sa/VehicleAnimGroupData.h | 21 ++-- 17 files changed, 205 insertions(+), 48 deletions(-) create mode 100644 source/game_sa/Tasks/TaskTypes/TaskSimpleCarShuffle.cpp create mode 100644 source/game_sa/Tasks/TaskTypes/TaskSimpleCarShuffle.h diff --git a/source/InjectHooksMain.cpp b/source/InjectHooksMain.cpp index 466617af76..8a096c77e1 100644 --- a/source/InjectHooksMain.cpp +++ b/source/InjectHooksMain.cpp @@ -263,6 +263,7 @@ #include "TaskComplexPassObject.h" #include "TaskComplexEnterCarAsPassenger.h" #include "TaskComplexEnterCarAsDriver.h" +#include "TaskSimpleCarShuffle.h" #include "TaskComplexReactToGunAimedAt.h" #include "TaskSimpleNone.h" #include "TaskComplexKillPedOnFoot.h" @@ -950,7 +951,7 @@ void InjectHooksMain() { CTaskSimpleCarOpenLockedDoorFromOutside::InjectHooks(); // CTaskSimpleCarSetPedSlowDraggedOut::InjectHooks(); CTaskSimpleCarSetTempAction::InjectHooks(); - // CTaskSimpleCarShuffle::InjectHooks(); + CTaskSimpleCarShuffle::InjectHooks(); // CTaskSimpleCarSlowBeDraggedOut::InjectHooks(); CTaskSimpleCarWaitToSlowDown::InjectHooks(); CTaskSimpleCarWaitForDoorNotToBeInUse::InjectHooks(); diff --git a/source/game_sa/Animation/AnimBlendAssociation.h b/source/game_sa/Animation/AnimBlendAssociation.h index 88fa48b5bd..e965d826d9 100644 --- a/source/game_sa/Animation/AnimBlendAssociation.h +++ b/source/game_sa/Animation/AnimBlendAssociation.h @@ -87,8 +87,9 @@ struct SClumpAnimAssoc { int16 m_nAnimId; uint16 m_nFlags; // TODO: use bitfield - float GetTimeProgress() const; - float GetBlendAmount(float weight) const { return IsPartial() ? m_fBlendAmount : m_fBlendAmount * weight; } + float GetTimeProgress() const; + float GetBlendAmount(float weight = 1.f) const { return IsPartial() ? m_fBlendAmount : m_fBlendAmount * weight; } + [[nodiscard]] bool IsRunning() const { return (m_nFlags & ANIMATION_STARTED) != 0; } [[nodiscard]] bool IsRepeating() const { return (m_nFlags & ANIMATION_LOOPED) != 0; } [[nodiscard]] bool IsPartial() const { return (m_nFlags & ANIMATION_PARTIAL) != 0; } @@ -120,6 +121,7 @@ class NOTSA_EXPORT_VTABLE CAnimBlendAssociation : public SClumpAnimAssoc { void Init(CAnimBlendStaticAssociation& source); void ReferenceAnimBlock(); + void SetBlendDelta(float value) { m_fBlendDelta = value; } void SetBlend(float blendAmount, float blendDelta); void SetBlendTo(float blendAmount, float blendDelta); void SetCurrentTime(float currentTime); diff --git a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarAlign.cpp b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarAlign.cpp index 6e16b6bebf..b48f648f87 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarAlign.cpp +++ b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarAlign.cpp @@ -92,7 +92,7 @@ void CTaskSimpleCarAlign::StartAnim(CPed* ped) { }(); m_anim = CAnimManager::BlendAnimation( ped->m_pRwClump, - (AssocGroupId)m_veh->GetAnimGroup().GetGroup(animId), + m_veh->GetAnimGroup().GetGroup(animId), animId, 4.f ); diff --git a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarCloseDoorFromInside.cpp b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarCloseDoorFromInside.cpp index 1b503854ca..de57bdfd6f 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarCloseDoorFromInside.cpp +++ b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarCloseDoorFromInside.cpp @@ -71,7 +71,7 @@ void CTaskSimpleCarCloseDoorFromInside::ComputeAnimID(AssocGroupId& outGroup, An default: NOTSA_UNREACHABLE(); } }(); - outGroup = (AssocGroupId)m_veh->GetAnimGroup().GetGroup(outAnimId); + outGroup = m_veh->GetAnimGroup().GetGroup(outAnimId); } // NOTSA @@ -141,7 +141,7 @@ bool CTaskSimpleCarCloseDoorFromInside::ProcessPed(CPed* ped) { } const auto animId = (AnimationId)m_anim->m_nAnimId; - m_veh->ProcessOpenDoor(ped, m_door, (AssocGroupId)m_veh->GetAnimGroup().GetGroup(animId), animId, m_anim->m_fCurrentTime); + m_veh->ProcessOpenDoor(ped, m_door, m_veh->GetAnimGroup().GetGroup(animId), animId, m_anim->m_fCurrentTime); return false; } diff --git a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarCloseDoorFromOutside.cpp b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarCloseDoorFromOutside.cpp index 36cad32ab4..7379492fba 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarCloseDoorFromOutside.cpp +++ b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarCloseDoorFromOutside.cpp @@ -64,7 +64,7 @@ void CTaskSimpleCarCloseDoorFromOutside::ComputeAnimID(AssocGroupId& outGroup, A default: NOTSA_UNREACHABLE(); } }(); - outGroup = (AssocGroupId)m_veh->GetAnimGroup().GetGroup(outAnimId); + outGroup = m_veh->GetAnimGroup().GetGroup(outAnimId); } // NOTSA diff --git a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarGetIn.cpp b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarGetIn.cpp index b4193ac9a0..644efc01d2 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarGetIn.cpp +++ b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarGetIn.cpp @@ -65,7 +65,7 @@ void CTaskSimpleCarGetIn::StartAnim(CPed const* ped) { }(); const auto grpId = [this, animId]{ - const auto grpId = (AssocGroupId)m_veh->GetAnimGroup().GetGroup(animId); + const auto grpId = m_veh->GetAnimGroup().GetGroup(animId); if (grpId == AssocGroupId::ANIM_GROUP_CONVCARANIMS) { if (m_door == TARGET_DOOR_DRIVER) { if (m_veh->IsDoorMissing(TARGET_DOOR_DRIVER) || !m_veh->IsDoorClosed(TARGET_DOOR_DRIVER)) { diff --git a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarGetOut.cpp b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarGetOut.cpp index 5c67ef1a24..c8f69573f0 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarGetOut.cpp +++ b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarGetOut.cpp @@ -111,7 +111,7 @@ auto CTaskSimpleCarGetOut::ComputeAnimID() -> std::pairGetAnimGroup().GetGroup(animId), animId }; + return { m_veh->GetAnimGroup().GetGroup(animId), animId }; } // 0x64BDE0 diff --git a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarJumpOut.cpp b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarJumpOut.cpp index c1681b49ed..54f5ff3a1c 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarJumpOut.cpp +++ b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarJumpOut.cpp @@ -75,7 +75,7 @@ auto CTaskSimpleCarJumpOut::ComputeAnimID() -> std::pairGetAnimGroup().GetGroup(animId), animId }; + return { m_veh->GetAnimGroup().GetGroup(animId), animId }; } // 0x647510 diff --git a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarOpenDoorFromOutside.cpp b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarOpenDoorFromOutside.cpp index c6c2af3b1a..3cd77b848a 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarOpenDoorFromOutside.cpp +++ b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarOpenDoorFromOutside.cpp @@ -77,7 +77,7 @@ auto CTaskSimpleCarOpenDoorFromOutside::ComputeAnimID() -> std::pairGetAnimGroup().GetGroup(animId), animId }; + return { m_veh->GetAnimGroup().GetGroup(animId), animId }; } // 0x645FA0 diff --git a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarOpenLockedDoorFromOutside.cpp b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarOpenLockedDoorFromOutside.cpp index c7b2b2cd15..a1122ea5b5 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarOpenLockedDoorFromOutside.cpp +++ b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarOpenLockedDoorFromOutside.cpp @@ -59,7 +59,7 @@ void CTaskSimpleCarOpenLockedDoorFromOutside::StartAnim(CPed* ped) { return ANIM_ID_CAR_DOORLOCKED_RHS; } }(); - m_anim = CAnimManager::BlendAnimation(ped->m_pRwClump, (AssocGroupId)m_veh->GetAnimGroup().GetGroup(animationId), animationId, 4.f); + m_anim = CAnimManager::BlendAnimation(ped->m_pRwClump, m_veh->GetAnimGroup().GetGroup(animationId), animationId, 4.f); m_anim->SetFinishCallback(FinishAnimCarOpenLockedDoorFromOutsideCB, this); } diff --git a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarOpenLockedDoorFromOutside.h b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarOpenLockedDoorFromOutside.h index 41978e621b..15a2d4e4a7 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarOpenLockedDoorFromOutside.h +++ b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarOpenLockedDoorFromOutside.h @@ -41,6 +41,7 @@ class NOTSA_EXPORT_VTABLE CTaskSimpleCarOpenLockedDoorFromOutside : public CTask this->CTaskSimpleCarOpenLockedDoorFromOutside::CTaskSimpleCarOpenLockedDoorFromOutside(veh, door, lineUpTask); return this; } + // 0x6460F0 CTaskSimpleCarOpenLockedDoorFromOutside* Destructor() { this->CTaskSimpleCarOpenLockedDoorFromOutside::~CTaskSimpleCarOpenLockedDoorFromOutside(); diff --git a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarShuffle.cpp b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarShuffle.cpp new file mode 100644 index 0000000000..f14fc83f55 --- /dev/null +++ b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarShuffle.cpp @@ -0,0 +1,100 @@ +#include "StdInc.h" + +#include "TaskSimpleCarShuffle.h" +#include "TaskUtilityLineUpPedWithCar.h" + +void CTaskSimpleCarShuffle::InjectHooks() { + RH_ScopedVirtualClass(CTaskSimpleCarShuffle, 0x86ed74, 9); + RH_ScopedCategory("Tasks/TaskTypes"); + + RH_ScopedInstall(Constructor, 0x646810); + RH_ScopedInstall(Destructor, 0x646890); + + RH_ScopedInstall(FinishAnimCarShuffleCB, 0x646970); + RH_ScopedInstall(StartAnim, 0x64B3E0); + + RH_ScopedVMTInstall(Clone, 0x649C40); + RH_ScopedVMTInstall(GetTaskType, 0x646880); + RH_ScopedVMTInstall(MakeAbortable, 0x646900); + RH_ScopedVMTInstall(ProcessPed, 0x64DC40); + RH_ScopedVMTInstall(SetPedPosition, 0x646920); +} + +// 0x646810 +CTaskSimpleCarShuffle::CTaskSimpleCarShuffle(CVehicle* car, int32 targetDoor, CTaskUtilityLineUpPedWithCar* lineUpTask) : + m_Car{ car }, + m_TargetDoor{ targetDoor }, + m_LineUpUtility{ lineUpTask } +{ + CEntity::SafeRegisterRef(m_Car); +} + +// 0x649C40 +CTaskSimpleCarShuffle::CTaskSimpleCarShuffle(const CTaskSimpleCarShuffle&) : + CTaskSimpleCarShuffle{ m_Car, m_TargetDoor, m_LineUpUtility } +{ +} + +// 0x646890 +CTaskSimpleCarShuffle::~CTaskSimpleCarShuffle() { + CEntity::SafeCleanUpRef(m_Car); + if (m_Anim) { + m_Anim->SetDefaultFinishCallback(); + } +} + +// 0x646970 +void CTaskSimpleCarShuffle::FinishAnimCarShuffleCB(CAnimBlendAssociation* assoc, void* data) { + const auto self = static_cast(data); + + assert(self->m_Anim); + + self->m_Anim->SetBlendDelta(-1000.f); + self->m_Anim = nullptr; + + self->m_bFinished = true; +} + +// 0x64B3E0 +void CTaskSimpleCarShuffle::StartAnim(const CPed* a2) { + assert(!m_Anim); + m_Anim = CAnimManager::BlendAnimation( + m_Car->m_pRwClump, + m_Car->GetAnimGroup().GetGroup(ANIM_ID_CAR_SHUFFLE_RHS_1), + ANIM_ID_CAR_SHUFFLE_RHS_1, + 1000.f + ); + m_Anim->SetFinishCallback(FinishAnimCarShuffleCB, this); +} + +// 0x646900 +bool CTaskSimpleCarShuffle::MakeAbortable(CPed* ped, eAbortPriority priority, const CEvent* event) { + if (priority != ABORT_PRIORITY_IMMEDIATE) { + return false; + } + if (m_Anim) { + m_Anim->SetBlendDelta(-1000.f); + } + return true; +} + +// 0x64DC40 +bool CTaskSimpleCarShuffle::ProcessPed(CPed* ped) { + if (m_bFinished || !m_Car) { + return true; + } + if (!m_Anim) { + StartAnim(ped); + } + return false; +} + +// 0x646920 +bool CTaskSimpleCarShuffle::SetPedPosition(CPed* ped) { + if (!ped->bInVehicle || m_Anim && m_Anim->GetBlendAmount() >= 0.9f) { + m_LineUpUtility->ProcessPed(ped, m_Car, m_Anim); + } else { + ped->SetPedPositionInCar(); + } + return true; +} diff --git a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarShuffle.h b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarShuffle.h new file mode 100644 index 0000000000..2c30d38a73 --- /dev/null +++ b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarShuffle.h @@ -0,0 +1,51 @@ +#pragma once + +#include "TaskSimple.h" + +class CVehicle; +class CAnimBlendAssociation; +class CEvent; +class CPed; +class CTaskUtilityLineUpPedWithCar; + +class NOTSA_EXPORT_VTABLE CTaskSimpleCarShuffle final : public CTaskSimple { +public: + static constexpr auto Type = eTaskType::TASK_SIMPLE_CAR_SHUFFLE; + + static void InjectHooks(); + + CTaskSimpleCarShuffle(CVehicle* car, int32 targetDoor, CTaskUtilityLineUpPedWithCar* lineUpTask); + CTaskSimpleCarShuffle(const CTaskSimpleCarShuffle&); + ~CTaskSimpleCarShuffle(); + + void StartAnim(const CPed* a2); + + CTask* Clone() const override { return new CTaskSimpleCarShuffle{ *this }; } + eTaskType GetTaskType() const override { return Type; } + bool MakeAbortable(CPed* ped, eAbortPriority priority = ABORT_PRIORITY_URGENT, CEvent const* event = nullptr) override; + bool ProcessPed(CPed* ped) override; + bool SetPedPosition(CPed * ped) override; + +private: + static void FinishAnimCarShuffleCB(CAnimBlendAssociation* assoc, void* task); + +protected: + bool m_bFinished{}; + CAnimBlendAssociation* m_Anim{}; + CVehicle* m_Car{}; + int32 m_TargetDoor{}; + CTaskUtilityLineUpPedWithCar* m_LineUpUtility{}; + +private: // Wrappers for hooks + // 0x646810 + CTaskSimpleCarShuffle* Constructor(CVehicle* vehicle, int32 unknown, CTaskUtilityLineUpPedWithCar* task) { + this->CTaskSimpleCarShuffle::CTaskSimpleCarShuffle(vehicle, unknown, task); + return this; + } + + // 0x646890 + CTaskSimpleCarShuffle* Destructor() { + this->CTaskSimpleCarShuffle::~CTaskSimpleCarShuffle(); + return this; + } +}; diff --git a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarSlowDragPedOut.cpp b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarSlowDragPedOut.cpp index fcf4ffd67b..d936e3850d 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskSimpleCarSlowDragPedOut.cpp +++ b/source/game_sa/Tasks/TaskTypes/TaskSimpleCarSlowDragPedOut.cpp @@ -82,7 +82,7 @@ std::pair CTaskSimpleCarSlowDragPedOut::ComputeAnimID return ANIM_ID_UNDEFINED; } }(); - return { (AssocGroupId)m_Vehicle->GetAnimGroup().GetGroup(animationId), animationId}; + return { m_Vehicle->GetAnimGroup().GetGroup(animationId), animationId}; } // 0x64C010 diff --git a/source/game_sa/Tasks/TaskTypes/TaskSimplePickUpBike.cpp b/source/game_sa/Tasks/TaskTypes/TaskSimplePickUpBike.cpp index 48f09751aa..d7cf8f7136 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskSimplePickUpBike.cpp +++ b/source/game_sa/Tasks/TaskTypes/TaskSimplePickUpBike.cpp @@ -60,7 +60,7 @@ void CTaskSimplePickUpBike::StartAnim(CPed const* ped) { return rightZ >= 0.f ? ANIM_ID_CAR_ALIGNHI_RHS : ANIM_ID_CAR_ALIGN_RHS; } }(); - m_anim = CAnimManager::BlendAnimation(ped->m_pRwClump, (AssocGroupId)m_veh->GetAnimGroup().GetGroup(animationId), animationId); + m_anim = CAnimManager::BlendAnimation(ped->m_pRwClump, m_veh->GetAnimGroup().GetGroup(animationId), animationId); m_anim->SetFinishCallback(FinishAnimPickUpBikeCB, this); } diff --git a/source/game_sa/VehicleAnimGroupData.cpp b/source/game_sa/VehicleAnimGroupData.cpp index ff1901e1a6..a6756e90e8 100644 --- a/source/game_sa/VehicleAnimGroupData.cpp +++ b/source/game_sa/VehicleAnimGroupData.cpp @@ -52,87 +52,86 @@ void CVehicleAnimGroup::CopyAnimGroup(CVehicleAnimGroup* src) { GetInOutTiming(eInOutTiming::TIMING_END) = src->GetInOutTiming(eInOutTiming::TIMING_END); } -uint32 CVehicleAnimGroup::GetGroup(AnimationId animId) { // TODO: Return `AssocGroupId` - switch (animId) - { +AssocGroupId CVehicleAnimGroup::GetGroup(AnimationId animId) const { + switch (animId) { case ANIM_ID_CAR_ALIGN_LHS: case ANIM_ID_CAR_ALIGN_RHS: case ANIM_ID_CAR_ALIGNHI_LHS: case ANIM_ID_CAR_ALIGNHI_RHS: - return m_animFlags.bAlign ? m_ucSecondGroup : m_ucFirstGroup; + return m_animFlags.bAlign ? GetSecondGroup() : GetFirstGroup(); case ANIM_ID_CAR_OPEN_LHS: case ANIM_ID_CAR_OPEN_RHS: - return m_animFlags.bOpenFrontDoorsOnExit ? m_ucSecondGroup : m_ucFirstGroup; + return m_animFlags.bOpenFrontDoorsOnExit ? GetSecondGroup() : GetFirstGroup(); case ANIM_ID_CAR_OPEN_LHS_1: case ANIM_ID_CAR_OPEN_RHS_1: - return m_animFlags.bOpenRearDoorsOnExit ? m_ucSecondGroup : m_ucFirstGroup; + return m_animFlags.bOpenRearDoorsOnExit ? GetSecondGroup() : GetFirstGroup(); case ANIM_ID_CAR_GETIN_LHS_0: case ANIM_ID_CAR_GETIN_RHS_0: case ANIM_ID_CAR_GETIN_BIKE_FRONT: - return m_animFlags.bCanEnterFrontDoors ? m_ucSecondGroup : m_ucFirstGroup; + return m_animFlags.bCanEnterFrontDoors ? GetSecondGroup() : GetFirstGroup(); case ANIM_ID_CAR_GETIN_LHS_1: case ANIM_ID_CAR_GETIN_RHS_1: - return m_animFlags.bCanEnterRearDoors ? m_ucSecondGroup : m_ucFirstGroup; + return m_animFlags.bCanEnterRearDoors ? GetSecondGroup() : GetFirstGroup(); case ANIM_ID_CAR_PULLOUT_LHS: case ANIM_ID_CAR_PULLOUT_RHS: case ANIM_ID_UNKNOWN_15: - return m_animFlags.bCanPulloutPed ? m_ucSecondGroup : m_ucFirstGroup; + return m_animFlags.bCanPulloutPed ? GetSecondGroup() : GetFirstGroup(); case ANIM_ID_CAR_CLOSEDOOR_LHS_0: case ANIM_ID_CAR_CLOSEDOOR_RHS_0: - return m_animFlags.bCloseFrontDoorWhenInside ? m_ucSecondGroup : m_ucFirstGroup; + return m_animFlags.bCloseFrontDoorWhenInside ? GetSecondGroup() : GetFirstGroup(); case ANIM_ID_CAR_CLOSEDOOR_LHS_1: case ANIM_ID_CAR_CLOSEDOOR_RHS_1: - return m_animFlags.bCloseRearDoorWhenInside ? m_ucSecondGroup : m_ucFirstGroup; + return m_animFlags.bCloseRearDoorWhenInside ? GetSecondGroup() : GetFirstGroup(); case ANIM_ID_CAR_SHUFFLE_RHS_0: case ANIM_ID_CAR_SHUFFLE_RHS_1: - return m_animFlags.bShuffle ? m_ucSecondGroup : m_ucFirstGroup; + return m_animFlags.bShuffle ? GetSecondGroup() : GetFirstGroup(); case ANIM_ID_CAR_GETOUT_LHS_0: case ANIM_ID_CAR_GETOUT_RHS_0: - return m_animFlags.bCanExitFrontDoors ? m_ucSecondGroup : m_ucFirstGroup; + return m_animFlags.bCanExitFrontDoors ? GetSecondGroup() : GetFirstGroup(); case ANIM_ID_CAR_GETOUT_LHS_1: case ANIM_ID_CAR_GETOUT_RHS_1: - return m_animFlags.bCanExitRearDoors ? m_ucSecondGroup : m_ucFirstGroup; + return m_animFlags.bCanExitRearDoors ? GetSecondGroup() : GetFirstGroup(); case ANIM_ID_CAR_JACKEDLHS: case ANIM_ID_CAR_JACKEDRHS: - return m_animFlags.bPlayerCanBeJacked ? m_ucSecondGroup : m_ucFirstGroup; + return m_animFlags.bPlayerCanBeJacked ? GetSecondGroup() : GetFirstGroup(); case ANIM_ID_CAR_CLOSE_LHS_0: case ANIM_ID_CAR_CLOSE_RHS_0: - return m_animFlags.bCloseFrontDoorWhenOutside ? m_ucSecondGroup : m_ucFirstGroup; + return m_animFlags.bCloseFrontDoorWhenOutside ? GetSecondGroup() : GetFirstGroup(); case ANIM_ID_CAR_CLOSE_LHS_1: case ANIM_ID_CAR_CLOSE_RHS_1: - return m_animFlags.bCloseRearDoorWhenOutside ? m_ucSecondGroup : m_ucFirstGroup; + return m_animFlags.bCloseRearDoorWhenOutside ? GetSecondGroup() : GetFirstGroup(); case ANIM_ID_CAR_ROLLOUT_LHS: case ANIM_ID_CAR_ROLLOUT_RHS: - return m_animFlags.bCanJumpOutOfVehicle ? m_ucSecondGroup : m_ucFirstGroup; + return m_animFlags.bCanJumpOutOfVehicle ? GetSecondGroup() : GetFirstGroup(); case ANIM_ID_CAR_ROLLDOOR: - return m_animFlags.bRollDownWindowOnDoorClose ? m_ucSecondGroup : m_ucFirstGroup; + return m_animFlags.bRollDownWindowOnDoorClose ? GetSecondGroup() : GetFirstGroup(); case ANIM_ID_CAR_FALLOUT_LHS: case ANIM_ID_CAR_FALLOUT_RHS: - return m_animFlags.bPlayerCanFallOut ? m_ucSecondGroup : m_ucFirstGroup; + return m_animFlags.bPlayerCanFallOut ? GetSecondGroup() : GetFirstGroup(); case ANIM_ID_CAR_DOORLOCKED_LHS: case ANIM_ID_CAR_DOORLOCKED_RHS: - return m_animFlags.bDoorLocked ? m_ucSecondGroup : m_ucFirstGroup; + return m_animFlags.bDoorLocked ? GetSecondGroup() : GetFirstGroup(); } - assert(false); // Shouldn't ever get to this point - return (m_animFlags.intValue & (1 << animId)) != 0 ? m_ucSecondGroup : m_ucFirstGroup; + NOTSA_UNREACHABLE(); // Shouldn't ever get to this point + //return (m_animFlags.intValue & (1 << animId)) != 0 ? GetSecondGroup() : GetFirstGroup(); } float CVehicleAnimGroup::ComputeCriticalBlendTime(AnimationId animId) { @@ -196,7 +195,7 @@ CVector CVehicleAnimGroup::ComputeAnimDoorOffsets(eVehAnimDoorOffset doorId) { } }(); - const auto groupId = (AssocGroupId)CVehicleAnimGroup::GetGroup(animId); + const auto groupId = CVehicleAnimGroup::GetGroup(animId); auto* animAssoc = CAnimManager::GetAnimAssociation(groupId, animId); auto* sequences = animAssoc->m_pHierarchy->m_pSequences; CAnimManager::UncompressAnimation(animAssoc->m_pHierarchy); @@ -301,7 +300,7 @@ void CVehicleAnimGroupData::GetInOutTimings(AssocGroupId groupId, eInOutTimingMo } // 0x639FC0 -int32 CVehicleAnimGroupData::GetGroupForAnim(AssocGroupId groupId, AnimationId animId) { +AssocGroupId CVehicleAnimGroupData::GetGroupForAnim(AssocGroupId groupId, AnimationId animId) { return CVehicleAnimGroupData::GetVehicleAnimGroup(groupId).GetGroup(animId); } diff --git a/source/game_sa/VehicleAnimGroupData.h b/source/game_sa/VehicleAnimGroupData.h index 03581ac369..9f315ba0f6 100644 --- a/source/game_sa/VehicleAnimGroupData.h +++ b/source/game_sa/VehicleAnimGroupData.h @@ -112,6 +112,9 @@ class CVehicleAnimGroup { uint8 m_ucSecondGroup; // see AssocGroupId char _pad[2]; + AssocGroupId GetFirstGroup() const { return (AssocGroupId)m_ucFirstGroup; } + AssocGroupId GetSecondGroup() const { return (AssocGroupId)m_ucSecondGroup; } + public: sVehicleAnimDataGroupFlags m_animFlags; sVehicleAnimDataSpecialFlags m_specialFlags; @@ -122,11 +125,11 @@ class CVehicleAnimGroup { public: static void InjectHooks(); - void InitAnimGroup(uint8 firstGroup, uint8 secondGroup, int32 animFlags, int32 animSpecialFlags, sVehAnimGroupGeneralTiming* generalTiming, sVehAnimGroupInOutTiming* startTiming, sVehAnimGroupInOutTiming* endTiming); - void CopyAnimGroup(CVehicleAnimGroup* src); - uint32 GetGroup(AnimationId animId); - float ComputeCriticalBlendTime(AnimationId animId); - CVector ComputeAnimDoorOffsets(eVehAnimDoorOffset doorId); + void InitAnimGroup(uint8 firstGroup, uint8 secondGroup, int32 animFlags, int32 animSpecialFlags, sVehAnimGroupGeneralTiming* generalTiming, sVehAnimGroupInOutTiming* startTiming, sVehAnimGroupInOutTiming* endTiming); + void CopyAnimGroup(CVehicleAnimGroup* src); + AssocGroupId GetGroup(AnimationId animId) const; + float ComputeCriticalBlendTime(AnimationId animId); + CVector ComputeAnimDoorOffsets(eVehAnimDoorOffset doorId); /// NOTSA: Helper of `CVehicleAnimGroupData::InitAGroupFromData` int32 InitFromData(const char* line); @@ -145,10 +148,10 @@ class CVehicleAnimGroupData { public: static void InjectHooks(); - static void GetInOutTimings(AssocGroupId groupId, eInOutTimingMode mode, float* pfAnimStart, float* pfAnimEnd); - static int32 GetGroupForAnim(AssocGroupId groupId, AnimationId animId); - static CVector GetAnimDoorOffset(AssocGroupId groupId, eVehAnimDoorOffset doorId); - static float ComputeCriticalBlendTime(AssocGroupId groupId, AnimationId animId); + static void GetInOutTimings(AssocGroupId groupId, eInOutTimingMode mode, float* pfAnimStart, float* pfAnimEnd); + static AssocGroupId GetGroupForAnim(AssocGroupId groupId, AnimationId animId); + static CVector GetAnimDoorOffset(AssocGroupId groupId, eVehAnimDoorOffset doorId); + static float ComputeCriticalBlendTime(AssocGroupId groupId, AnimationId animId); static bool UsesTruckDrivingAnims(AssocGroupId groupId); static bool UsesKartDrivingAnims(AssocGroupId groupId); From a3e423efac6d2b995bc15c1d14e81a63df1f20a3 Mon Sep 17 00:00:00 2001 From: Pirulax Date: Thu, 5 Oct 2023 19:46:53 +0200 Subject: [PATCH 5/9] `CTaskComplexGetOnBoatSeat` (#626) --- .../TaskTypes/TaskComplexGetOnBoatSeat.cpp | 32 ++++++++++++------- .../TaskTypes/TaskComplexGetOnBoatSeat.h | 21 ++++++------ 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/source/game_sa/Tasks/TaskTypes/TaskComplexGetOnBoatSeat.cpp b/source/game_sa/Tasks/TaskTypes/TaskComplexGetOnBoatSeat.cpp index 345ca54445..9c80d34002 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskComplexGetOnBoatSeat.cpp +++ b/source/game_sa/Tasks/TaskTypes/TaskComplexGetOnBoatSeat.cpp @@ -1,23 +1,36 @@ #include "StdInc.h" #include "TaskComplexGetOnBoatSeat.h" +#include "TaskSimpleRunAnim.h" void CTaskComplexGetOnBoatSeat::InjectHooks() { - RH_ScopedClass(CTaskComplexGetOnBoatSeat); + RH_ScopedVirtualClass(CTaskComplexGetOnBoatSeat, 0x86f044, 11); RH_ScopedCategory("Tasks/TaskTypes"); RH_ScopedInstall(Constructor, 0x649210); RH_ScopedInstall(Destructor, 0x649280); - RH_ScopedInstall(Clone, 0x64A3B0, { .reversed = false }); - RH_ScopedInstall(CreateFirstSubTask, 0x649310, { .reversed = false }); + + RH_ScopedVMTInstall(Clone, 0x64A3B0); + RH_ScopedVMTInstall(GetTaskType, 0x649270); + RH_ScopedVMTInstall(MakeAbortable, 0x6492E0); + RH_ScopedVMTInstall(CreateNextSubTask, 0x649300); + RH_ScopedVMTInstall(CreateFirstSubTask, 0x649310); + RH_ScopedVMTInstall(ControlSubTask, 0x6493D0); } // 0x649210 -CTaskComplexGetOnBoatSeat::CTaskComplexGetOnBoatSeat(CVehicle* vehicle) { - m_Vehicle = vehicle; +CTaskComplexGetOnBoatSeat::CTaskComplexGetOnBoatSeat(CVehicle* vehicle) : + m_Vehicle{ vehicle } +{ CEntity::SafeRegisterRef(m_Vehicle); } +// 0x64A3B0 +CTaskComplexGetOnBoatSeat::CTaskComplexGetOnBoatSeat(const CTaskComplexGetOnBoatSeat& o) : + CTaskComplexGetOnBoatSeat{ o.m_Vehicle } +{ +} + // 0x649280 CTaskComplexGetOnBoatSeat::~CTaskComplexGetOnBoatSeat() { CEntity::SafeCleanUpRef(m_Vehicle); @@ -25,17 +38,12 @@ CTaskComplexGetOnBoatSeat::~CTaskComplexGetOnBoatSeat() { // 0x6492E0 bool CTaskComplexGetOnBoatSeat::MakeAbortable(CPed* ped, eAbortPriority priority, const CEvent* event) { - return priority == ABORT_PRIORITY_IMMEDIATE && m_pSubTask->MakeAbortable(ped, ABORT_PRIORITY_IMMEDIATE, event); -} - -// 0x649300 -CTask* CTaskComplexGetOnBoatSeat::CreateNextSubTask(CPed* ped) { - return nullptr; + return priority == ABORT_PRIORITY_IMMEDIATE && m_pSubTask->MakeAbortable(ped, priority, event); } // 0x649310 CTask* CTaskComplexGetOnBoatSeat::CreateFirstSubTask(CPed* ped) { - return plugin::CallMethodAndReturn(this, ped); + return new CTaskSimpleRunAnim{ ANIM_GROUP_DEFAULT, m_Vehicle->m_pHandlingData->m_bSitInBoat ? ANIM_ID_CAR_SIT : ANIM_ID_DRIVE_BOAT, 1.f }; } // 0x6493D0 diff --git a/source/game_sa/Tasks/TaskTypes/TaskComplexGetOnBoatSeat.h b/source/game_sa/Tasks/TaskTypes/TaskComplexGetOnBoatSeat.h index 020ccea669..81d70e7940 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskComplexGetOnBoatSeat.h +++ b/source/game_sa/Tasks/TaskTypes/TaskComplexGetOnBoatSeat.h @@ -3,22 +3,23 @@ #include "TaskComplex.h" class CVehicle; -class CTaskComplexGetOnBoatSeat : CTaskComplex { -public: - CVehicle* m_Vehicle; - +class NOTSA_EXPORT_VTABLE CTaskComplexGetOnBoatSeat final : public CTaskComplex { public: static constexpr auto Type = TASK_COMPLEX_GET_ON_BOAT_SEAT; - explicit CTaskComplexGetOnBoatSeat(CVehicle* vehicle); + CTaskComplexGetOnBoatSeat(CVehicle* vehicle); + CTaskComplexGetOnBoatSeat(const CTaskComplexGetOnBoatSeat&); ~CTaskComplexGetOnBoatSeat() override; eTaskType GetTaskType() const override { return Type; } - CTask* Clone() const override { return new CTaskComplexGetOnBoatSeat(m_Vehicle); } // 0x64A3B0 - bool MakeAbortable(CPed* ped, eAbortPriority priority = ABORT_PRIORITY_URGENT, const CEvent* event = nullptr) override; - CTask* CreateNextSubTask(CPed* ped) override; - CTask* CreateFirstSubTask(CPed* ped) override; - CTask* ControlSubTask(CPed* ped) override; + CTask* Clone() const override { return new CTaskComplexGetOnBoatSeat(m_Vehicle); } // 0x64A3B0 + bool MakeAbortable(CPed* ped, eAbortPriority priority = ABORT_PRIORITY_URGENT, const CEvent* event = nullptr) override; + CTask* CreateNextSubTask(CPed* ped) override { return nullptr; } + CTask* CreateFirstSubTask(CPed* ped) override; + CTask* ControlSubTask(CPed* ped) override; + +protected: + CVehicle* m_Vehicle; private: friend void InjectHooksMain(); From baa8c41058471fb916732f318bfe818624e9e41b Mon Sep 17 00:00:00 2001 From: Pirulax Date: Thu, 5 Oct 2023 20:47:54 +0200 Subject: [PATCH 6/9] `CTaskComplexEnterBoatAsDriver` (#625) --- source/InjectHooksMain.cpp | 2 +- .../Audio/entities/AECollisionAudioEntity.cpp | 3 +- .../TaskComplexEnterBoatAsDriver.cpp | 82 +++++++++++++++++++ .../TaskTypes/TaskComplexEnterBoatAsDriver.h | 49 +++++++---- .../TaskComplexGoToBoatSteeringWheel.cpp | 2 +- .../TaskComplexGoToBoatSteeringWheel.h | 3 +- 6 files changed, 118 insertions(+), 23 deletions(-) diff --git a/source/InjectHooksMain.cpp b/source/InjectHooksMain.cpp index 8a096c77e1..634a2779cb 100644 --- a/source/InjectHooksMain.cpp +++ b/source/InjectHooksMain.cpp @@ -1119,7 +1119,7 @@ void InjectHooksMain() { CTaskSimpleIKPointArm::InjectHooks(); CTaskSimpleIKLookAt::InjectHooks(); CTaskComplexDie::InjectHooks(); - // CTaskComplexEnterBoatAsDriver::InjectHooks(); + CTaskComplexEnterBoatAsDriver::InjectHooks(); CTaskSimpleFight::InjectHooks(); CTaskComplexUseWaterCannon::InjectHooks(); // CTaskComplexDriveToPoint::InjectHooks(); diff --git a/source/game_sa/Audio/entities/AECollisionAudioEntity.cpp b/source/game_sa/Audio/entities/AECollisionAudioEntity.cpp index 610f9c562c..bd216be862 100644 --- a/source/game_sa/Audio/entities/AECollisionAudioEntity.cpp +++ b/source/game_sa/Audio/entities/AECollisionAudioEntity.cpp @@ -62,8 +62,7 @@ void CAECollisionAudioEntity::AddCollisionSoundToList(CEntity* entity1, CEntity* }); if (newEntry == m_Entries.end()) { - // Game tries to access m_Entries[300] in this case. - NOTSA_UNREACHABLE(); + return; } // ? check diff --git a/source/game_sa/Tasks/TaskTypes/TaskComplexEnterBoatAsDriver.cpp b/source/game_sa/Tasks/TaskTypes/TaskComplexEnterBoatAsDriver.cpp index 5c71a3abd0..c43fa4bff9 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskComplexEnterBoatAsDriver.cpp +++ b/source/game_sa/Tasks/TaskTypes/TaskComplexEnterBoatAsDriver.cpp @@ -1,3 +1,85 @@ #include "StdInc.h" #include "TaskComplexEnterBoatAsDriver.h" +#include "TaskComplexGetOnBoatSeat.h" +#include "TaskSimpleCarSetPedInAsDriver.h" +#include "TaskComplexGoToBoatSteeringWheel.h" +#include "TaskSimpleCarSlowDragPedOut.h" + +void CTaskComplexEnterBoatAsDriver::InjectHooks() { + RH_ScopedVirtualClass(CTaskComplexEnterBoatAsDriver, 0x86e7d0, 11); + RH_ScopedCategory("Tasks/TaskTypes"); + + RH_ScopedInstall(Constructor, 0x63B5E0); + RH_ScopedInstall(Destructor, 0x63B650); + + RH_ScopedInstall(CreateSubTask, 0x63B6C0); + + RH_ScopedVMTInstall(Clone, 0x63D920); + RH_ScopedVMTInstall(GetTaskType, 0x63B640); + RH_ScopedVMTInstall(CreateNextSubTask, 0x640E60); + RH_ScopedVMTInstall(CreateFirstSubTask, 0x640ED0); + RH_ScopedVMTInstall(ControlSubTask, 0x63B6B0); +} + +// 0x63B5E0 +CTaskComplexEnterBoatAsDriver::CTaskComplexEnterBoatAsDriver(CVehicle* target) : + m_EnterInto{target} +{ + CEntity::SafeRegisterRef(m_EnterInto); +} + +// 0x63D920 +CTaskComplexEnterBoatAsDriver::CTaskComplexEnterBoatAsDriver(const CTaskComplexEnterBoatAsDriver& o) : + CTaskComplexEnterBoatAsDriver{ o.m_EnterInto } +{ +} + +// 0x63B650 +CTaskComplexEnterBoatAsDriver::~CTaskComplexEnterBoatAsDriver() { + CEntity::SafeCleanUpRef(m_EnterInto); +} + +// 0x63B6C0 +CTask* CTaskComplexEnterBoatAsDriver::CreateSubTask(eTaskType tt) { + switch (tt) { + case TASK_COMPLEX_GET_ON_BOAT_SEAT: + return new CTaskComplexGetOnBoatSeat{ m_EnterInto }; + case TASK_SIMPLE_CAR_SET_PED_IN_AS_DRIVER: + return new CTaskSimpleCarSetPedInAsDriver{ m_EnterInto }; + case TASK_COMPLEX_GO_TO_BOAT_STEERING_WHEEL: + return new CTaskComplexGoToBoatSteeringWheel{ m_EnterInto }; + case TASK_FINISHED: + return nullptr; + default: + NOTSA_UNREACHABLE(); + } +} + +// 0x640E60 +CTask* CTaskComplexEnterBoatAsDriver::CreateNextSubTask(CPed* ped) { + return CreateSubTask([this, ped] { + switch (m_pSubTask->GetTaskType()) { + case TASK_COMPLEX_GO_TO_BOAT_STEERING_WHEEL: { + return CTask::Cast(m_pSubTask)->HasAchievedPoint() + ? TASK_COMPLEX_GET_ON_BOAT_SEAT + : TASK_FINISHED; + } + case TASK_COMPLEX_GET_ON_BOAT_SEAT: + return TASK_SIMPLE_CAR_SET_PED_IN_AS_DRIVER; + case TASK_SIMPLE_CAR_SET_PED_IN_AS_DRIVER: + return TASK_FINISHED; + default: + NOTSA_UNREACHABLE(); + } + }()); +} + +// 0x640ED0 +CTask* CTaskComplexEnterBoatAsDriver::CreateFirstSubTask(CPed* ped) { + return CreateSubTask( + ped->m_pContactEntity == m_EnterInto || ped->m_standingOnEntity == m_EnterInto + ? TASK_COMPLEX_GO_TO_BOAT_STEERING_WHEEL + : TASK_FINISHED + ); +} diff --git a/source/game_sa/Tasks/TaskTypes/TaskComplexEnterBoatAsDriver.h b/source/game_sa/Tasks/TaskTypes/TaskComplexEnterBoatAsDriver.h index 00fc46877b..320134fd61 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskComplexEnterBoatAsDriver.h +++ b/source/game_sa/Tasks/TaskTypes/TaskComplexEnterBoatAsDriver.h @@ -1,28 +1,41 @@ -/* - Plugin-SDK file - Authors: GTA Community. See more here - https://github.com/DK22Pac/plugin-sdk - Do not delete this comment block. Respect others' work! -*/ #pragma once #include "TaskComplex.h" -#include "Vehicle.h" -class CTaskComplexEnterBoatAsDriver : public CTaskComplex { -public: - CVehicle* m_pTargetVehicle; +class CVehicle; +class CPed; +class NOTSA_EXPORT_VTABLE CTaskComplexEnterBoatAsDriver final : public CTaskComplex { public: - static constexpr auto Type = TASK_COMPLEX_ENTER_BOAT_AS_DRIVER; - - CTaskComplexEnterBoatAsDriver(CVehicle* targetVehicle); + static constexpr auto Type = eTaskType::TASK_COMPLEX_ENTER_BOAT_AS_DRIVER; -private: - friend void InjectHooksMain(); static void InjectHooks(); + CTaskComplexEnterBoatAsDriver(CVehicle*); + CTaskComplexEnterBoatAsDriver(const CTaskComplexEnterBoatAsDriver&); + ~CTaskComplexEnterBoatAsDriver(); + + CTask* Clone() const override { return new CTaskComplexEnterBoatAsDriver{ *this }; } + eTaskType GetTaskType() const override { return Type; } + CTask* CreateNextSubTask(CPed* ped) override; + CTask* CreateFirstSubTask(CPed* ped) override; + CTask* ControlSubTask(CPed* ped) override { return m_pSubTask; } + + CTask* CreateSubTask(eTaskType tt); + +protected: + CVehicle* m_EnterInto = {}; + +private: // Wrappers for hooks + // 0x63B5E0 + CTaskComplexEnterBoatAsDriver* Constructor(CVehicle* target) { + this->CTaskComplexEnterBoatAsDriver::CTaskComplexEnterBoatAsDriver(target); + return this; + } + + // 0x63B650 + CTaskComplexEnterBoatAsDriver* Destructor() { + this->CTaskComplexEnterBoatAsDriver::~CTaskComplexEnterBoatAsDriver(); + return this; + } }; - -VALIDATE_SIZE(CTaskComplexEnterBoatAsDriver, 0x10); - diff --git a/source/game_sa/Tasks/TaskTypes/TaskComplexGoToBoatSteeringWheel.cpp b/source/game_sa/Tasks/TaskTypes/TaskComplexGoToBoatSteeringWheel.cpp index 8f2911f4cb..59f1ed220d 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskComplexGoToBoatSteeringWheel.cpp +++ b/source/game_sa/Tasks/TaskTypes/TaskComplexGoToBoatSteeringWheel.cpp @@ -35,7 +35,7 @@ CTask* CTaskComplexGoToBoatSteeringWheel::CreateNextSubTask(CPed* ped) { case TASK_SIMPLE_STAND_STILL: return CreateSubTask(TASK_FINISHED); case TASK_COMPLEX_GO_TO_POINT_AND_STAND_STILL: - m_unused = true; + m_bAchievedPoint = true; return CreateSubTask(TASK_FINISHED); default: NOTSA_UNREACHABLE(); diff --git a/source/game_sa/Tasks/TaskTypes/TaskComplexGoToBoatSteeringWheel.h b/source/game_sa/Tasks/TaskTypes/TaskComplexGoToBoatSteeringWheel.h index 17855b4f21..46f432399f 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskComplexGoToBoatSteeringWheel.h +++ b/source/game_sa/Tasks/TaskTypes/TaskComplexGoToBoatSteeringWheel.h @@ -7,7 +7,7 @@ class NOTSA_EXPORT_VTABLE CTaskComplexGoToBoatSteeringWheel : public CTaskComple public: CVector m_TargetPos{}; CVehicle* m_Vehicle{}; - bool m_unused{}; + bool m_bAchievedPoint{}; uint32 m_FirstSubTaskStartTime{}; public: @@ -18,6 +18,7 @@ class NOTSA_EXPORT_VTABLE CTaskComplexGoToBoatSteeringWheel : public CTaskComple CTask* CreateSubTask(eTaskType taskType); void ComputeTargetPos(); + bool HasAchievedPoint() const { return m_bAchievedPoint; } eTaskType GetTaskType() const override { return Type; } CTask* Clone() const override { return new CTaskComplexGoToBoatSteeringWheel(m_Vehicle); } // 0x64A350 From 9d018b5c830e5be4d3c40065d02dc09ff9677b58 Mon Sep 17 00:00:00 2001 From: Pirulax Date: Sat, 7 Oct 2023 18:35:25 +0200 Subject: [PATCH 7/9] `CTaskComplexCarDrive` (#623) Co-authored-by: yukani --- .../TaskTypes/TaskComplexAvoidEntity.cpp | 4 + .../Tasks/TaskTypes/TaskComplexCarDrive.cpp | 223 ++++++++++-------- .../Tasks/TaskTypes/TaskComplexCarDrive.h | 53 ++--- .../TaskTypes/TaskComplexCarDriveMission.cpp | 14 +- .../TaskTypes/TaskComplexCarDriveMission.h | 6 +- .../TaskTypes/TaskComplexDriveFireTruck.cpp | 2 +- .../TaskTypes/TaskComplexDrivePointRoute.cpp | 2 +- .../TaskTypes/TaskComplexDrivePointRoute.h | 7 +- .../TaskTypes/TaskComplexDriveToPoint.cpp | 42 ++-- .../Tasks/TaskTypes/TaskComplexDriveToPoint.h | 4 +- .../TaskTypes/TaskComplexDriveWander.cpp | 32 +-- .../Tasks/TaskTypes/TaskComplexDriveWander.h | 2 +- .../TaskComplexEnterCarAsPassenger.h | 2 +- .../TaskComplexMedicTreatInjuredPed.cpp | 2 +- 14 files changed, 204 insertions(+), 191 deletions(-) diff --git a/source/game_sa/Tasks/TaskTypes/TaskComplexAvoidEntity.cpp b/source/game_sa/Tasks/TaskTypes/TaskComplexAvoidEntity.cpp index 61cb062eb9..80a96a6db2 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskComplexAvoidEntity.cpp +++ b/source/game_sa/Tasks/TaskTypes/TaskComplexAvoidEntity.cpp @@ -4,6 +4,10 @@ #include "IKChainManager_c.h" #include "TaskSimpleGoToPoint.h" +// !!!!!!!!!!!!!!!! +// UNUSED TASK +// !!!!!!!!!!!!!!!! + void CTaskComplexAvoidEntity::InjectHooks() { RH_ScopedClass(CTaskComplexAvoidEntity); RH_ScopedCategory("Tasks/TaskTypes"); diff --git a/source/game_sa/Tasks/TaskTypes/TaskComplexCarDrive.cpp b/source/game_sa/Tasks/TaskTypes/TaskComplexCarDrive.cpp index 198297b53a..fbc5ae01cd 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskComplexCarDrive.cpp +++ b/source/game_sa/Tasks/TaskTypes/TaskComplexCarDrive.cpp @@ -5,111 +5,149 @@ #include "TaskComplexEnterCarAsDriver.h" #include "TaskSimpleCarDrive.h" #include "TaskComplexWander.h" +#include "TaskComplexEnterAnyCarAsDriver.h" +#include "TaskComplexLeaveAnyCar.h" +#include "TaskSimpleCreateCarAndGetIn.h" void CTaskComplexCarDrive::InjectHooks() { RH_ScopedVirtualClass(CTaskComplexCarDrive, 0x86E934, 14); RH_ScopedCategory("Tasks/TaskTypes"); - RH_ScopedInstall(Constructor_0, 0x63C9D0, { .enabled = false}); - RH_ScopedInstall(Constructor_1, 0x63C940, { .enabled = false}); + RH_ScopedInstall(Constructor_0, 0x63C9D0); + RH_ScopedInstall(Constructor_1, 0x63C940); RH_ScopedInstall(Destructor, 0x63CA40); - RH_ScopedInstall(CreateSubTask, 0x642FA0, { .enabled = false, .locked = true }); + RH_ScopedInstall(CreateSubTask, 0x642FA0); - RH_ScopedVMTInstall(CreateSubTaskCannotGetInCar, 0x643200, { .enabled = false}); - RH_ScopedVMTInstall(SetUpCar, 0x63CAE0, { .enabled = false}); - RH_ScopedVMTInstall(Drive, 0x63CAD0, { .enabled = false}); - RH_ScopedVMTInstall(Clone, 0x63DC90, { .enabled = false}); - RH_ScopedVMTInstall(CreateNextSubTask, 0x644E20, { .enabled = false, .locked = true }); - RH_ScopedVMTInstall(CreateFirstSubTask, 0x645100, { .enabled = false, .locked = true}); - RH_ScopedVMTInstall(ControlSubTask, 0x645240, { .enabled = false}); + RH_ScopedVMTInstall(CreateSubTaskCannotGetInCar, 0x643200); + RH_ScopedVMTInstall(SetUpCar, 0x63CAE0); + RH_ScopedVMTInstall(Drive, 0x63CAD0); + RH_ScopedVMTInstall(Clone, 0x63DC90); + RH_ScopedVMTInstall(CreateNextSubTask, 0x644E20); + RH_ScopedVMTInstall(CreateFirstSubTask, 0x645100); + RH_ScopedVMTInstall(ControlSubTask, 0x645240); } // 0x63C9D0 // asDriver stuff is NOTSA CTaskComplexCarDrive::CTaskComplexCarDrive(CVehicle* vehicle, bool asDriver) : - m_asDriver{asDriver} + m_bAsDriver{asDriver}, + m_Veh{vehicle} { - m_pVehicle = vehicle; - m_fSpeed = 0.0f; - m_carModelIndexToCreate = -1; - m_nCarDrivingStyle = DRIVING_STYLE_STOP_FOR_CARS; - m_bSavedVehicleBehavior = false; - CEntity::SafeRegisterRef(m_pVehicle); + CEntity::SafeRegisterRef(m_Veh); } // 0x63C940 -CTaskComplexCarDrive::CTaskComplexCarDrive(CVehicle* vehicle, float speed, int32 carModelIndexToCreate, eCarDrivingStyle carDrivingStyle) : CTaskComplex() { - m_fSpeed = speed; - m_carModelIndexToCreate = carModelIndexToCreate; - m_pVehicle = vehicle; - m_nCarDrivingStyle = carDrivingStyle; - m_bSavedVehicleBehavior = false; - CEntity::SafeRegisterRef(m_pVehicle); +CTaskComplexCarDrive::CTaskComplexCarDrive(CVehicle* vehicle, float speed, eModelID carModelIndexToCreate, eCarDrivingStyle carDrivingStyle) : + m_CruiseSpeed{speed}, + m_DesiredCarModel{carModelIndexToCreate}, + m_Veh{vehicle}, + m_CarDrivingStyle{static_cast(carDrivingStyle)} +{ + CEntity::SafeRegisterRef(m_Veh); +} + +CTaskComplexCarDrive::CTaskComplexCarDrive(const CTaskComplexCarDrive& o) : + CTaskComplexCarDrive{ m_Veh, m_CruiseSpeed, m_DesiredCarModel, static_cast(m_CarDrivingStyle) } +{ + m_bAsDriver = o.m_bAsDriver; } // 0x63CA40 CTaskComplexCarDrive::~CTaskComplexCarDrive() { - if (m_pVehicle) { - if (m_bSavedVehicleBehavior) { - m_pVehicle->m_autoPilot.m_nCarDrivingStyle = static_cast(m_nOldCarDrivingStyle); - m_pVehicle->m_autoPilot.m_nCarMission = static_cast(m_nCarMission); - m_pVehicle->m_autoPilot.m_nCruiseSpeed = m_nSpeed; + if (m_Veh) { + if (m_bIsCarSetUp) { + m_Veh->m_autoPilot.m_nCarDrivingStyle = static_cast(m_OriginalDrivingStyle); + m_Veh->m_autoPilot.m_nCarMission = static_cast(m_OriginalMission); + m_Veh->m_autoPilot.m_nCruiseSpeed = m_OriginalSpeed; } - CEntity::SafeCleanUpRef(m_pVehicle); + CEntity::SafeCleanUpRef(m_Veh); } } -// 0x63DC90 -CTask* CTaskComplexCarDrive::Clone() const { - auto* task = new CTaskComplexCarDrive(m_pVehicle, m_fSpeed, m_carModelIndexToCreate, static_cast(m_nCarDrivingStyle)); - task->m_asDriver = m_asDriver; - return task; -} - // 0x644E20 CTask* CTaskComplexCarDrive::CreateNextSubTask(CPed* ped) { - return plugin::CallMethodAndReturn(this, ped); + const auto Create = [this, ped](eTaskType tt) { + return CreateSubTask(tt, ped); + }; + switch (m_pSubTask->GetTaskType()) { + case TASK_COMPLEX_ENTER_CAR_AS_PASSENGER: // 0x644E93 + return Create(ped->IsInVehicle() ? TASK_SIMPLE_CAR_DRIVE : TASK_FINISHED); + case TASK_COMPLEX_ENTER_CAR_AS_DRIVER: // 0x644E65 + return Create(ped->IsInVehicle() ? TASK_SIMPLE_CAR_DRIVE : TASK_COMPLEX_ENTER_ANY_CAR_AS_DRIVER); + case TASK_SIMPLE_CAR_DRIVE: // 0x644E56 + return CreateFirstSubTask(ped); + case TASK_COMPLEX_LEAVE_ANY_CAR: { // 0x644EC8 + if (m_Veh) { + return m_bAsDriver + ? Create(TASK_COMPLEX_ENTER_CAR_AS_DRIVER) + : Create(TASK_COMPLEX_ENTER_CAR_AS_PASSENGER); + } else { + return m_bAsDriver + ? Create(TASK_COMPLEX_ENTER_ANY_CAR_AS_DRIVER) + : Create(TASK_FINISHED); + } + } + case TASK_COMPLEX_ENTER_ANY_CAR_AS_DRIVER: { // 0x644F39 + if (ped->IsInVehicle()) { + CEntity::ChangeEntityReference(m_Veh, ped->m_pVehicle); + return Create(TASK_SIMPLE_CAR_DRIVE); + } + return m_DesiredCarModel == MODEL_INVALID + ? CreateSubTaskCannotGetInCar(ped) + : Create(TASK_SIMPLE_CREATE_CAR_AND_GET_IN); + } + case TASK_SIMPLE_CREATE_CAR_AND_GET_IN: { // 0x644FA3 + if (ped->IsInVehicle()) { + CEntity::ChangeEntityReference(m_Veh, ped->m_pVehicle); + return Create(TASK_SIMPLE_CAR_DRIVE); + } + return CreateSubTaskCannotGetInCar(ped); + } + default: + NOTSA_UNREACHABLE(); + } } // 0x645100 CTask* CTaskComplexCarDrive::CreateFirstSubTask(CPed* ped) { - if (!m_pVehicle) { - if (ped->m_pVehicle && ped->bInVehicle) { - m_pVehicle = ped->m_pVehicle; - m_pVehicle->RegisterReference(reinterpret_cast(m_pVehicle)); - return CreateSubTask(TASK_SIMPLE_CAR_DRIVE, ped); + return CreateSubTask([this, ped] { + if (!m_Veh) { + if (ped->IsInVehicle()) { + CEntity::ChangeEntityReference(m_Veh, ped->m_pVehicle); + return TASK_SIMPLE_CAR_DRIVE; + } + return m_bAsDriver + ? TASK_COMPLEX_ENTER_ANY_CAR_AS_DRIVER + : TASK_FINISHED; } - return m_asDriver ? CreateSubTask(TASK_COMPLEX_ENTER_ANY_CAR_AS_DRIVER, ped) : nullptr; - } - - if (ped->m_pVehicle && ped->bInVehicle) { - if (ped->m_pVehicle == m_pVehicle) - return CreateSubTask(TASK_SIMPLE_CAR_DRIVE, ped); - else - return CreateSubTask(TASK_COMPLEX_LEAVE_ANY_CAR, ped); - } else { - if (!m_pVehicle->IsBike()) { - CUpsideDownCarCheck carCheck; - if (carCheck.IsCarUpsideDown(m_pVehicle) == 0) { - return CreateSubTask(m_asDriver ? TASK_COMPLEX_ENTER_CAR_AS_DRIVER : TASK_COMPLEX_ENTER_CAR_AS_PASSENGER, ped); + if (ped->IsInVehicle()) { + return ped->m_pVehicle == m_Veh + ? TASK_SIMPLE_CAR_DRIVE + : TASK_COMPLEX_LEAVE_ANY_CAR; + } + if (!m_Veh->IsBike()) { + if (CUpsideDownCarCheck{}.IsCarUpsideDown(m_Veh)) { + return m_bAsDriver + ? TASK_COMPLEX_ENTER_ANY_CAR_AS_DRIVER + : TASK_FINISHED; } - return m_asDriver ? CreateSubTask(TASK_COMPLEX_ENTER_ANY_CAR_AS_DRIVER, ped) : nullptr; } - return CreateSubTask(m_asDriver ? TASK_COMPLEX_ENTER_CAR_AS_DRIVER : TASK_COMPLEX_ENTER_CAR_AS_PASSENGER, ped); - } + return m_bAsDriver + ? TASK_COMPLEX_ENTER_CAR_AS_DRIVER + : TASK_COMPLEX_ENTER_CAR_AS_PASSENGER; + }(), ped); } // 0x645240 CTask* CTaskComplexCarDrive::ControlSubTask(CPed* ped) { - if (ped->m_pVehicle && ped->bInVehicle) { + if (ped->IsInVehicle()) { switch (m_pSubTask->GetTaskType()) { case TASK_SIMPLE_CAR_DRIVE: return Drive(ped); case TASK_COMPLEX_GO_TO_POINT_ANY_MEANS: - if (ped->m_pVehicle && ped->bInVehicle) { - m_pVehicle = ped->m_pVehicle; - m_pVehicle->RegisterReference(reinterpret_cast(m_pVehicle)); + if (ped->IsInVehicle()) { + CEntity::ChangeEntityReference(m_Veh, ped->m_pVehicle); return CreateSubTask(TASK_SIMPLE_CAR_DRIVE, ped); } } @@ -119,56 +157,33 @@ CTask* CTaskComplexCarDrive::ControlSubTask(CPed* ped) { // 0x63CAE0 void CTaskComplexCarDrive::SetUpCar() { - m_nOldCarDrivingStyle = m_pVehicle->m_autoPilot.m_nCarDrivingStyle; - m_nCarMission = m_pVehicle->m_autoPilot.m_nCarMission; - m_nSpeed = m_pVehicle->m_autoPilot.m_nCruiseSpeed; - m_bSavedVehicleBehavior = true; -} - -// 0x643200 -CTask* CTaskComplexCarDrive::CreateSubTaskCannotGetInCar(CPed* ped) { - return CreateSubTask(TASK_FINISHED, ped); -} - -// 0x63CAD0 -CTask* CTaskComplexCarDrive::Drive(CPed* ped) { - return m_pSubTask; + m_OriginalDrivingStyle = m_Veh->m_autoPilot.m_nCarDrivingStyle; + m_OriginalMission = m_Veh->m_autoPilot.m_nCarMission; + m_OriginalSpeed = m_Veh->m_autoPilot.m_nCruiseSpeed; + m_bIsCarSetUp = true; } // 0x642FA0 CTask* CTaskComplexCarDrive::CreateSubTask(eTaskType taskType, CPed* ped) { - return plugin::CallMethodAndReturn(this, taskType, ped); - - /* - if (taskType <= TASK_COMPLEX_ENTER_ANY_CAR_AS_DRIVER) { - if (taskType != TASK_COMPLEX_ENTER_ANY_CAR_AS_DRIVER) { - switch (taskType) { - case TASK_COMPLEX_ENTER_CAR_AS_PASSENGER: - return new CTaskComplexEnterCarAsPassenger(m_pVehicle, 0, false); - case TASK_COMPLEX_ENTER_CAR_AS_DRIVER: - return new CTaskComplexEnterCarAsDriver(m_pVehicle); - case TASK_SIMPLE_CAR_DRIVE: - SetUpCar(); - return new CTaskSimpleCarDrive(m_pVehicle, nullptr, false); - case TASK_COMPLEX_LEAVE_ANY_CAR: - return new CTaskComplexLeaveAnyCar(0, true, false); // todo: - default: - return nullptr; - } - return nullptr; - } - return new CTaskComplexEnterAnyCarAsDriver(); // todo: - } - return nullptr; - switch (taskType) { + case TASK_COMPLEX_ENTER_CAR_AS_PASSENGER: + return new CTaskComplexEnterCarAsPassenger{ m_Veh }; + case TASK_COMPLEX_ENTER_CAR_AS_DRIVER: + return new CTaskComplexEnterCarAsDriver{ m_Veh }; + case TASK_SIMPLE_CAR_DRIVE: + SetUpCar(); + return new CTaskSimpleCarDrive{ m_Veh }; + case TASK_COMPLEX_LEAVE_ANY_CAR: + return new CTaskComplexLeaveAnyCar{ 0, true, false }; + case TASK_COMPLEX_ENTER_ANY_CAR_AS_DRIVER: + return new CTaskComplexEnterAnyCarAsDriver{}; case TASK_SIMPLE_CREATE_CAR_AND_GET_IN: - return new CTaskSimpleCreateCarAndGetIn(&ped->GetPosition(), m_carModelIndexToCreate); // todo: + return new CTaskSimpleCreateCarAndGetIn{ ped->GetPosition(), m_DesiredCarModel }; case TASK_COMPLEX_WANDER: return CTaskComplexWander::GetWanderTaskByPedType(ped); case TASK_FINISHED: return nullptr; + default: + NOTSA_UNREACHABLE(); } - return nullptr; - */ } diff --git a/source/game_sa/Tasks/TaskTypes/TaskComplexCarDrive.h b/source/game_sa/Tasks/TaskTypes/TaskComplexCarDrive.h index b389a4423b..b3980cd46f 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskComplexCarDrive.h +++ b/source/game_sa/Tasks/TaskTypes/TaskComplexCarDrive.h @@ -7,50 +7,43 @@ class CVehicle; class NOTSA_EXPORT_VTABLE CTaskComplexCarDrive : public CTaskComplex { -public: - CVehicle* m_pVehicle; - float m_fSpeed; - int32 m_carModelIndexToCreate; - eCarDrivingStyle m_nCarDrivingStyle; - uint8 _align[3]{}; // Must have this, as originally an 32bit int was used for the driving style - bool m_asDriver; - int8 m_nOldCarDrivingStyle; - int8 m_nCarMission; - uint8 m_nSpeed; - bool m_bSavedVehicleBehavior; - public: static constexpr auto Type = TASK_COMPLEX_CAR_DRIVE; CTaskComplexCarDrive(CVehicle* vehicle, bool asDriver = true); - CTaskComplexCarDrive(CVehicle* vehicle, float speed, int32 carModelIndexToCreate, eCarDrivingStyle carDrivingStyle); + CTaskComplexCarDrive(CVehicle* vehicle, float speed, eModelID carModelIndexToCreate = MODEL_INVALID, eCarDrivingStyle carDrivingStyle = DRIVING_STYLE_STOP_FOR_CARS); + CTaskComplexCarDrive(const CTaskComplexCarDrive&); ~CTaskComplexCarDrive() override; - CTask* Clone() const override; + CTask* Clone() const override { return new CTaskComplexCarDrive{ *this }; } eTaskType GetTaskType() const override { return Type; } - - CTask* CreateNextSubTask(CPed* ped) override; - CTask* CreateFirstSubTask(CPed* ped) override; - CTask* ControlSubTask(CPed* ped) override; - CTask* CreateSubTask(eTaskType taskType, CPed* ped); + CTask* CreateNextSubTask(CPed* ped) override; + CTask* CreateFirstSubTask(CPed* ped) override; + CTask* ControlSubTask(CPed* ped) override; virtual void SetUpCar(); - virtual CTask* CreateSubTaskCannotGetInCar(CPed* ped); - virtual CTask* Drive(CPed* ped); + virtual CTask* CreateSubTaskCannotGetInCar(CPed* ped) { return CreateSubTask(TASK_FINISHED, ped); } + virtual CTask* Drive(CPed* ped) { return m_pSubTask; } + + CTask* CreateSubTask(eTaskType taskType, CPed* ped); private: friend void InjectHooksMain(); static void InjectHooks(); + CTaskComplexCarDrive* Constructor_0(CVehicle* vehicle) { this->CTaskComplexCarDrive::CTaskComplexCarDrive(vehicle); return this; } - CTaskComplexCarDrive* Constructor_1(CVehicle* vehicle, float speed, int32 carModelIndexToCreate, eCarDrivingStyle carDrivingStyle) { this->CTaskComplexCarDrive::CTaskComplexCarDrive(vehicle, speed, carModelIndexToCreate, carDrivingStyle); return this; } + CTaskComplexCarDrive* Constructor_1(CVehicle* vehicle, float speed, eModelID carModelIndexToCreate, eCarDrivingStyle carDrivingStyle) { this->CTaskComplexCarDrive::CTaskComplexCarDrive(vehicle, speed, carModelIndexToCreate, carDrivingStyle); return this; } CTaskComplexCarDrive* Destructor() { this->CTaskComplexCarDrive::~CTaskComplexCarDrive(); return this; } - CTask* Clone_Reversed() { return CTaskComplexCarDrive::Clone(); } - CTask* CreateNextSubTask_Reversed(CPed* ped) { return CTaskComplexCarDrive::CreateNextSubTask(ped); } - CTask* CreateFirstSubTask_Reversed(CPed* ped) { return CTaskComplexCarDrive::CreateFirstSubTask(ped); } - CTask* ControlSubTask_Reversed(CPed* ped) { return CTaskComplexCarDrive::ControlSubTask(ped); } - CTask* CreateSubTask_Reversed(eTaskType taskType, CPed* ped) { return CTaskComplexCarDrive::CreateSubTask(taskType, ped); } - void SetUpCar_Reversed() { CTaskComplexCarDrive::SetUpCar(); } - CTask* CreateSubTaskCannotGetInCar_Reversed(CPed* ped) { return CTaskComplexCarDrive::CreateSubTaskCannotGetInCar(ped); } - CTask* Drive_Reversed(CPed* ped) { return CTaskComplexCarDrive::Drive(ped); } + +public: + CVehicle* m_Veh{}; + float m_CruiseSpeed{}; + eModelID m_DesiredCarModel{MODEL_INVALID}; + uint32 m_CarDrivingStyle{DRIVING_STYLE_STOP_FOR_CARS}; + bool m_bAsDriver{}; + int8 m_OriginalDrivingStyle{}; + int8 m_OriginalMission{}; + uint8 m_OriginalSpeed{}; + bool m_bIsCarSetUp{}; }; VALIDATE_SIZE(CTaskComplexCarDrive, 0x24); diff --git a/source/game_sa/Tasks/TaskTypes/TaskComplexCarDriveMission.cpp b/source/game_sa/Tasks/TaskTypes/TaskComplexCarDriveMission.cpp index 85e9409584..50eaf4f9d6 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskComplexCarDriveMission.cpp +++ b/source/game_sa/Tasks/TaskTypes/TaskComplexCarDriveMission.cpp @@ -15,7 +15,7 @@ void CTaskComplexCarDriveMission::InjectHooks() { // 0x63CC30 CTaskComplexCarDriveMission::CTaskComplexCarDriveMission(CVehicle* vehicle, CEntity* targetVehicle, eCarMission carDriveMission, eCarDrivingStyle carDrivingStyle, float fSpeed) : - CTaskComplexCarDrive{ vehicle, fSpeed, -1, carDrivingStyle } + CTaskComplexCarDrive{ vehicle, fSpeed, MODEL_INVALID, carDrivingStyle } { // assert(targetVehicle->IsVehicle()); m_pTargetVehicle = static_cast(targetVehicle); @@ -32,18 +32,18 @@ CTaskComplexCarDriveMission::~CTaskComplexCarDriveMission() { void CTaskComplexCarDriveMission::SetUpCar() { CTaskComplexCarDrive::SetUpCar(); - CCarCtrl::JoinCarWithRoadSystem(m_pVehicle); - m_pVehicle->m_nStatus = STATUS_PHYSICS; + CCarCtrl::JoinCarWithRoadSystem(m_Veh); + m_Veh->m_nStatus = STATUS_PHYSICS; - auto& autopilot = m_pVehicle->m_autoPilot; + auto& autopilot = m_Veh->m_autoPilot; autopilot.m_nCarMission = m_nCarMission; - autopilot.m_nCruiseSpeed = (uint32)m_fSpeed; + autopilot.m_nCruiseSpeed = (uint32)m_CruiseSpeed; autopilot.m_speed = (float)autopilot.m_nCruiseSpeed; - autopilot.m_nCarDrivingStyle = (eCarDrivingStyle)m_nCarDrivingStyle; + autopilot.m_nCarDrivingStyle = (eCarDrivingStyle)m_CarDrivingStyle; autopilot.m_pTargetCar = m_pTargetVehicle; autopilot.m_nTimeToStartMission = CTimer::GetTimeInMS(); CEntity::SafeRegisterRef(autopilot.m_pTargetCar); - m_pVehicle->vehicleFlags.bEngineOn = m_pVehicle->vehicleFlags.bEngineBroken ? false : true; + m_Veh->vehicleFlags.bEngineOn = m_Veh->vehicleFlags.bEngineBroken ? false : true; } diff --git a/source/game_sa/Tasks/TaskTypes/TaskComplexCarDriveMission.h b/source/game_sa/Tasks/TaskTypes/TaskComplexCarDriveMission.h index 8d57b43e41..dfdc11683c 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskComplexCarDriveMission.h +++ b/source/game_sa/Tasks/TaskTypes/TaskComplexCarDriveMission.h @@ -17,7 +17,7 @@ class CTaskComplexCarDriveMission : public CTaskComplexCarDrive { CTaskComplexCarDriveMission(CVehicle* vehicle, CEntity* targetVehicle, eCarMission carDriveMission, eCarDrivingStyle carDrivingStyle, float fSpeed); ~CTaskComplexCarDriveMission() override; - CTask* Clone() const override { return new CTaskComplexCarDriveMission(m_pVehicle, m_pTargetVehicle, m_nCarMission, (eCarDrivingStyle)m_nCarDrivingStyle, m_fSpeed); } + CTask* Clone() const override { return new CTaskComplexCarDriveMission(m_Veh, m_pTargetVehicle, m_nCarMission, (eCarDrivingStyle)m_CarDrivingStyle, m_CruiseSpeed); } eTaskType GetTaskType() const override { return Type; } void SetUpCar() override; @@ -41,7 +41,7 @@ class CTaskComplexCarDriveMissionFleeScene : public CTaskComplexCarDriveMission static constexpr auto Type = TASK_COMPLEX_CAR_DRIVE_MISSION_FLEE_SCENE; eTaskType GetTaskType() const override { return Type; } // 0x4B89C0 - CTask* Clone() const override { return new CTaskComplexCarDriveMissionFleeScene(m_pVehicle); } // 0x4B8950 + CTask* Clone() const override { return new CTaskComplexCarDriveMissionFleeScene(m_Veh); } // 0x4B8950 }; class CTaskComplexCarDriveMissionKillPed : public CTaskComplexCarDriveMission { @@ -51,5 +51,5 @@ class CTaskComplexCarDriveMissionKillPed : public CTaskComplexCarDriveMission { static constexpr auto Type = TASK_COMPLEX_CAR_DRIVE_MISSION_KILL_PED; eTaskType GetTaskType() const override { return Type; } // 0x4B8AA0 - CTask* Clone() const override { return new CTaskComplexCarDriveMissionKillPed(m_pVehicle, m_pTargetVehicle); } // 0x4B8A30 + CTask* Clone() const override { return new CTaskComplexCarDriveMissionKillPed(m_Veh, m_pTargetVehicle); } // 0x4B8A30 }; diff --git a/source/game_sa/Tasks/TaskTypes/TaskComplexDriveFireTruck.cpp b/source/game_sa/Tasks/TaskTypes/TaskComplexDriveFireTruck.cpp index 22a7893497..411532f748 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskComplexDriveFireTruck.cpp +++ b/source/game_sa/Tasks/TaskTypes/TaskComplexDriveFireTruck.cpp @@ -128,7 +128,7 @@ CTask* CTaskComplexDriveFireTruck::CreateSubTask(eTaskType taskType, CPed* ped) case TASK_COMPLEX_CAR_DRIVE_WANDER: return new CTaskComplexCarDriveWander(m_pVehicle, DRIVING_STYLE_STOP_FOR_CARS, 10.0F); case TASK_COMPLEX_CAR_DRIVE_TO_POINT: - return new CTaskComplexDriveToPoint(m_pVehicle, m_pFire->m_vecPosition, 30.0F, 0, -1, 25.0F, DRIVING_STYLE_AVOID_CARS); + return new CTaskComplexDriveToPoint(m_pVehicle, m_pFire->m_vecPosition, 30.0F, 0, MODEL_INVALID, 25.0F, DRIVING_STYLE_AVOID_CARS); case TASK_COMPLEX_USE_WATER_CANNON: return new CTaskComplexUseWaterCannon(m_pFire); case TASK_SIMPLE_CAR_DRIVE: diff --git a/source/game_sa/Tasks/TaskTypes/TaskComplexDrivePointRoute.cpp b/source/game_sa/Tasks/TaskTypes/TaskComplexDrivePointRoute.cpp index bae5d3541f..b09dcc5c1d 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskComplexDrivePointRoute.cpp +++ b/source/game_sa/Tasks/TaskTypes/TaskComplexDrivePointRoute.cpp @@ -17,7 +17,7 @@ void CTaskComplexDrivePointRoute::InjectHooks() { } // 0x6433E0 -CTaskComplexDrivePointRoute::CTaskComplexDrivePointRoute(CVehicle* vehicle, CPointRoute const& route, float cruiseSpeed, uint32 mode, int32 carModelIdx, float targetRadius, eCarDrivingStyle drivingStyle) : +CTaskComplexDrivePointRoute::CTaskComplexDrivePointRoute(CVehicle* vehicle, CPointRoute const& route, float cruiseSpeed, uint32 mode, eModelID carModelIdx, float targetRadius, eCarDrivingStyle drivingStyle) : m_mode{mode}, m_veh{vehicle}, m_route{new CPointRoute{route}}, diff --git a/source/game_sa/Tasks/TaskTypes/TaskComplexDrivePointRoute.h b/source/game_sa/Tasks/TaskTypes/TaskComplexDrivePointRoute.h index 0886fac268..11ead93529 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskComplexDrivePointRoute.h +++ b/source/game_sa/Tasks/TaskTypes/TaskComplexDrivePointRoute.h @@ -14,7 +14,7 @@ class NOTSA_EXPORT_VTABLE CTaskComplexDrivePointRoute : public CTaskComplex { CPointRoute* m_route{}; float m_cruiseSpeed{}; uint32 m_mode{}; - int32 m_desiredCarModel{}; + eModelID m_desiredCarModel{}; float m_targetRadius{}; eCarDrivingStyle m_drivingStyle{}; uint8 m_zeropad[3]{}; /// Important padding, as originally `m_drivingStyle` was 4 bytes wide (now it's 1) @@ -25,7 +25,7 @@ class NOTSA_EXPORT_VTABLE CTaskComplexDrivePointRoute : public CTaskComplex { static constexpr auto Type = eTaskType::TASK_COMPLEX_CAR_DRIVE_POINT_ROUTE; - CTaskComplexDrivePointRoute(CVehicle* vehicle, CPointRoute const& route, float cruiseSpeed, uint32 mode, int32 carModelIdx, float targetRadius, eCarDrivingStyle drivingStyle); + CTaskComplexDrivePointRoute(CVehicle* vehicle, CPointRoute const& route, float cruiseSpeed, uint32 mode, eModelID carModelIdx, float targetRadius, eCarDrivingStyle drivingStyle); CTaskComplexDrivePointRoute(const CTaskComplexDrivePointRoute&); ~CTaskComplexDrivePointRoute(); @@ -41,10 +41,11 @@ class NOTSA_EXPORT_VTABLE CTaskComplexDrivePointRoute : public CTaskComplex { private: // Wrappers for hooks // 0x6433E0 - auto Constructor(CVehicle* vehicle, CPointRoute const& route, float cruiseSpeed, uint32 mode, int32 carModelIdx, float targetRadius, eCarDrivingStyle drivingStyle) { + auto Constructor(CVehicle* vehicle, CPointRoute const& route, float cruiseSpeed, uint32 mode, eModelID carModelIdx, float targetRadius, eCarDrivingStyle drivingStyle) { this->CTaskComplexDrivePointRoute::CTaskComplexDrivePointRoute(vehicle, route, cruiseSpeed, mode, carModelIdx, targetRadius, drivingStyle); return this; } + // 0x643490 auto Destructor() { this->CTaskComplexDrivePointRoute::~CTaskComplexDrivePointRoute(); diff --git a/source/game_sa/Tasks/TaskTypes/TaskComplexDriveToPoint.cpp b/source/game_sa/Tasks/TaskTypes/TaskComplexDriveToPoint.cpp index 810b0d0b58..7fb943066d 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskComplexDriveToPoint.cpp +++ b/source/game_sa/Tasks/TaskTypes/TaskComplexDriveToPoint.cpp @@ -4,7 +4,7 @@ #include "TaskComplexGoToPointAnyMeans.h" // 0x63CE00 -CTaskComplexDriveToPoint::CTaskComplexDriveToPoint(CVehicle* vehicle, const CVector& point, float speed, int32 arg4, int32 carModelIndexToCreate, float radius, eCarDrivingStyle drivingStyle) : +CTaskComplexDriveToPoint::CTaskComplexDriveToPoint(CVehicle* vehicle, const CVector& point, float speed, int32 arg4, eModelID carModelIndexToCreate, float radius, eCarDrivingStyle drivingStyle) : CTaskComplexCarDrive(vehicle, speed, carModelIndexToCreate, drivingStyle), m_Point{ point }, field_30{ arg4 }, @@ -16,40 +16,40 @@ CTaskComplexDriveToPoint::CTaskComplexDriveToPoint(CVehicle* vehicle, const CVec // 0x63CE80 CTask* CTaskComplexDriveToPoint::CreateSubTaskCannotGetInCar(CPed* ped) { - return new CTaskComplexGoToPointAnyMeans(PEDMOVE_RUN, m_Point, 0.5f, m_carModelIndexToCreate); + return new CTaskComplexGoToPointAnyMeans(PEDMOVE_RUN, m_Point, 0.5f, m_DesiredCarModel); } // 0x63CF00 void CTaskComplexDriveToPoint::SetUpCar() { - m_nOldCarDrivingStyle = m_pVehicle->m_autoPilot.m_nCarDrivingStyle; - m_nCarMission = m_pVehicle->m_autoPilot.m_nCarMission; - m_nSpeed = m_pVehicle->m_autoPilot.m_nCruiseSpeed; + m_OriginalDrivingStyle = m_Veh->m_autoPilot.m_nCarDrivingStyle; + m_OriginalMission = m_Veh->m_autoPilot.m_nCarMission; + m_OriginalSpeed = m_Veh->m_autoPilot.m_nCruiseSpeed; - m_bSavedVehicleBehavior = true; + m_bIsCarSetUp = true; - if (m_fSpeed > 0.0f) { - assert(m_fSpeed < 255.0f); - m_pVehicle->m_autoPilot.m_nCruiseSpeed = (uint8)m_fSpeed; + if (m_CruiseSpeed > 0.0f) { + assert(m_CruiseSpeed < 255.0f); + m_Veh->m_autoPilot.m_nCruiseSpeed = (uint8)m_CruiseSpeed; } - m_pVehicle->m_autoPilot.m_nCarDrivingStyle = m_nCarDrivingStyle; - m_pVehicle->m_autoPilot.m_nTimeToStartMission = CTimer::GetTimeInMS(); + m_Veh->m_autoPilot.m_nCarDrivingStyle = static_cast(m_CarDrivingStyle); + m_Veh->m_autoPilot.m_nTimeToStartMission = CTimer::GetTimeInMS(); } // 0x645420 CTask* CTaskComplexDriveToPoint::Drive(CPed* ped) { return plugin::CallMethodAndReturn(this, ped); // untested - auto dist = DistanceBetweenPoints(m_pVehicle->GetPosition(), m_Point); + auto dist = DistanceBetweenPoints(m_Veh->GetPosition(), m_Point); if (dist < m_Radius) { - m_pVehicle->m_autoPilot.m_nCarMission = MISSION_NONE; + m_Veh->m_autoPilot.m_nCarMission = MISSION_NONE; field_38 = true; return CTaskComplexCarDrive::CreateSubTask(TASK_FINISHED, ped); } - if (dist >= 3.0f || m_pVehicle->m_autoPilot.m_nCarMission) { - if (!m_pVehicle->m_autoPilot.m_nCruiseSpeed) { - assert(m_fSpeed < 255.0f); - m_pVehicle->m_autoPilot.m_nCruiseSpeed = (uint8)m_fSpeed; + if (dist >= 3.0f || m_Veh->m_autoPilot.m_nCarMission) { + if (!m_Veh->m_autoPilot.m_nCruiseSpeed) { + assert(m_CruiseSpeed < 255.0f); + m_Veh->m_autoPilot.m_nCruiseSpeed = (uint8)m_CruiseSpeed; } if (IsTargetBlocked(ped)) { @@ -59,16 +59,16 @@ CTask* CTaskComplexDriveToPoint::Drive(CPed* ped) { switch (field_30) { case field_30_enum::DEFAULT: - CCarAI::GetCarToGoToCoors(m_pVehicle, &m_Point, m_nCarDrivingStyle, false); + CCarAI::GetCarToGoToCoors(m_Veh, &m_Point, m_CarDrivingStyle, false); return m_pSubTask; case field_30_enum::ACCURATE: - CCarAI::GetCarToGoToCoorsAccurate(m_pVehicle, &m_Point, m_nCarDrivingStyle, false); + CCarAI::GetCarToGoToCoorsAccurate(m_Veh, &m_Point, m_CarDrivingStyle, false); return m_pSubTask; case field_30_enum::STRAIGHT_LINE: - CCarAI::GetCarToGoToCoorsStraightLine(m_pVehicle, &m_Point, m_nCarDrivingStyle, false); + CCarAI::GetCarToGoToCoorsStraightLine(m_Veh, &m_Point, m_CarDrivingStyle, false); return m_pSubTask; case field_30_enum::RACING: - CCarAI::GetCarToGoToCoorsRacing(m_pVehicle, &m_Point, m_nCarDrivingStyle, false); + CCarAI::GetCarToGoToCoorsRacing(m_Veh, &m_Point, m_CarDrivingStyle, false); return m_pSubTask; default: return m_pSubTask; diff --git a/source/game_sa/Tasks/TaskTypes/TaskComplexDriveToPoint.h b/source/game_sa/Tasks/TaskTypes/TaskComplexDriveToPoint.h index f8e7f0fad4..8980f2c332 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskComplexDriveToPoint.h +++ b/source/game_sa/Tasks/TaskTypes/TaskComplexDriveToPoint.h @@ -20,11 +20,11 @@ class CTaskComplexDriveToPoint : public CTaskComplexCarDrive { public: static constexpr auto Type = TASK_COMPLEX_CAR_DRIVE_TO_POINT; - CTaskComplexDriveToPoint(CVehicle* vehicle, const CVector& point, float speed, int32 arg4, int32 carModelIndexToCreate, float radius, eCarDrivingStyle drivingStyle); + CTaskComplexDriveToPoint(CVehicle* vehicle, const CVector& point, float speed, int32 arg4, eModelID carModelIndexToCreate, float radius, eCarDrivingStyle drivingStyle); ~CTaskComplexDriveToPoint() override = default; eTaskType GetTaskType() const override { return Type;} - CTask* Clone() const override { return new CTaskComplexDriveToPoint(m_pVehicle, m_Point, m_fSpeed, field_30, m_carModelIndexToCreate, m_Radius, m_nCarDrivingStyle); } + CTask* Clone() const override { return new CTaskComplexDriveToPoint(m_Veh, m_Point, m_CruiseSpeed, field_30, m_DesiredCarModel, m_Radius, static_cast(m_CarDrivingStyle)); } void SetUpCar() override; CTask* CreateSubTaskCannotGetInCar(CPed* ped) override; diff --git a/source/game_sa/Tasks/TaskTypes/TaskComplexDriveWander.cpp b/source/game_sa/Tasks/TaskTypes/TaskComplexDriveWander.cpp index 7490124f59..d45845486f 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskComplexDriveWander.cpp +++ b/source/game_sa/Tasks/TaskTypes/TaskComplexDriveWander.cpp @@ -5,32 +5,32 @@ // 0x63CB10 CTaskComplexCarDriveWander::CTaskComplexCarDriveWander(CVehicle* vehicle, eCarDrivingStyle carDrivingStyle, float fSpeed) - : CTaskComplexCarDrive(vehicle, fSpeed, -1, carDrivingStyle) + : CTaskComplexCarDrive(vehicle, fSpeed, MODEL_INVALID, carDrivingStyle) { // NOP } // 0x63CB60 void CTaskComplexCarDriveWander::SetUpCar() { - m_nOldCarDrivingStyle = m_pVehicle->m_autoPilot.m_nCarDrivingStyle; - m_nCarMission = m_pVehicle->m_autoPilot.m_nCarMission; - m_nSpeed = m_pVehicle->m_autoPilot.m_nCruiseSpeed; - m_bSavedVehicleBehavior = true; + m_OriginalDrivingStyle = m_Veh->m_autoPilot.m_nCarDrivingStyle; + m_OriginalMission = m_Veh->m_autoPilot.m_nCarMission; + m_OriginalSpeed = m_Veh->m_autoPilot.m_nCruiseSpeed; + m_bIsCarSetUp = true; if (!CCarCtrl::bCarIsBeingCreated) { - CCarCtrl::JoinCarWithRoadSystem(m_pVehicle); - m_pVehicle->m_nStatus = STATUS_PHYSICS; - m_pVehicle->m_autoPilot.m_nCarMission = MISSION_CRUISE; - m_pVehicle->m_autoPilot.m_nCruiseSpeed = (uint8)m_fSpeed; - m_pVehicle->m_autoPilot.m_speed = m_pVehicle->m_autoPilot.m_nCruiseSpeed; - m_pVehicle->m_autoPilot.m_nCarDrivingStyle = static_cast(m_nCarDrivingStyle); + CCarCtrl::JoinCarWithRoadSystem(m_Veh); + m_Veh->m_nStatus = STATUS_PHYSICS; + m_Veh->m_autoPilot.m_nCarMission = MISSION_CRUISE; + m_Veh->m_autoPilot.m_nCruiseSpeed = (uint8)m_CruiseSpeed; + m_Veh->m_autoPilot.m_speed = m_Veh->m_autoPilot.m_nCruiseSpeed; + m_Veh->m_autoPilot.m_nCarDrivingStyle = static_cast(m_CarDrivingStyle); } - if (m_pVehicle->vehicleFlags.bEngineBroken) { - m_pVehicle->vehicleFlags.bEngineOn = false; - m_pVehicle->vehicleFlags.bIsLawEnforcer = false; + if (m_Veh->vehicleFlags.bEngineBroken) { + m_Veh->vehicleFlags.bEngineOn = false; + m_Veh->vehicleFlags.bIsLawEnforcer = false; } else { - m_pVehicle->vehicleFlags.bEngineOn = true; + m_Veh->vehicleFlags.bEngineOn = true; } - m_pVehicle->m_autoPilot.m_nTimeToStartMission = CTimer::GetTimeInMS(); + m_Veh->m_autoPilot.m_nTimeToStartMission = CTimer::GetTimeInMS(); } // 0x643240 diff --git a/source/game_sa/Tasks/TaskTypes/TaskComplexDriveWander.h b/source/game_sa/Tasks/TaskTypes/TaskComplexDriveWander.h index ae484b4364..f2cf245657 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskComplexDriveWander.h +++ b/source/game_sa/Tasks/TaskTypes/TaskComplexDriveWander.h @@ -11,7 +11,7 @@ class CTaskComplexCarDriveWander : public CTaskComplexCarDrive { CTaskComplexCarDriveWander(CVehicle* vehicle, eCarDrivingStyle carDrivingStyle, float fSpeed); ~CTaskComplexCarDriveWander() override = default; - CTask* Clone() const override { return new CTaskComplexCarDrive(m_pVehicle, m_fSpeed, -1, static_cast(m_nCarDrivingStyle)); }; + CTask* Clone() const override { return new CTaskComplexCarDrive(m_Veh, m_CruiseSpeed, MODEL_INVALID, static_cast(m_CarDrivingStyle)); }; eTaskType GetTaskType() const override { return Type; } void SetUpCar() override; CTask* CreateSubTaskCannotGetInCar(CPed* ped) override; diff --git a/source/game_sa/Tasks/TaskTypes/TaskComplexEnterCarAsPassenger.h b/source/game_sa/Tasks/TaskTypes/TaskComplexEnterCarAsPassenger.h index d3e102e847..1dad9253f4 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskComplexEnterCarAsPassenger.h +++ b/source/game_sa/Tasks/TaskTypes/TaskComplexEnterCarAsPassenger.h @@ -12,7 +12,7 @@ class CTaskComplexEnterCarAsPassenger : public CTaskComplexEnterCar { public: static constexpr auto Type = TASK_COMPLEX_ENTER_CAR_AS_PASSENGER; - CTaskComplexEnterCarAsPassenger(CVehicle* targetVehicle, int32 nTargetSeat, bool bCarryOnAfterFallingOff); + CTaskComplexEnterCarAsPassenger(CVehicle* targetVehicle, int32 nTargetSeat = 0, bool bCarryOnAfterFallingOff = false); CTaskComplexEnterCarAsPassenger(const CTaskComplexEnterCarAsPassenger&); ~CTaskComplexEnterCarAsPassenger() override = default; diff --git a/source/game_sa/Tasks/TaskTypes/TaskComplexMedicTreatInjuredPed.cpp b/source/game_sa/Tasks/TaskTypes/TaskComplexMedicTreatInjuredPed.cpp index 1dd3954ce4..1202d265c4 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskComplexMedicTreatInjuredPed.cpp +++ b/source/game_sa/Tasks/TaskTypes/TaskComplexMedicTreatInjuredPed.cpp @@ -71,7 +71,7 @@ CTask* CTaskComplexMedicTreatInjuredPed::CreateSubTask(eTaskType taskType) { case TASK_SIMPLE_CAR_DRIVE: return new CTaskSimpleCarDrive(m_pVehicle, nullptr, false); case TASK_COMPLEX_CAR_DRIVE_TO_POINT: - return new CTaskComplexDriveToPoint(m_pVehicle, m_vecAccidentPosition, 30.0F, 0, -1, -1.0F, DRIVING_STYLE_AVOID_CARS); + return new CTaskComplexDriveToPoint(m_pVehicle, m_vecAccidentPosition, 30.0F, 0, MODEL_INVALID, -1.0F, DRIVING_STYLE_AVOID_CARS); case TASK_COMPLEX_CAR_DRIVE_WANDER: return new CTaskComplexCarDriveWander(m_pVehicle, DRIVING_STYLE_AVOID_CARS, 30.0F); case TASK_COMPLEX_GO_TO_POINT_AND_STAND_STILL: From af19807607c271b936154bb1d0c5be197a3922f8 Mon Sep 17 00:00:00 2001 From: Pirulax Date: Tue, 10 Oct 2023 21:26:12 +0200 Subject: [PATCH 8/9] `CTaskSimpleThrowProjectile` (#629) * Fix assert in `CCollisionData::GetNumFaceGroups` --- source/game_sa/Collision/CollisionData.cpp | 12 +- source/game_sa/Events/EventDamage.h | 2 + .../TaskTypes/TaskSimpleThrowProjectile.cpp | 174 ++++++++++++++---- .../TaskTypes/TaskSimpleThrowProjectile.h | 50 +++-- 4 files changed, 178 insertions(+), 60 deletions(-) diff --git a/source/game_sa/Collision/CollisionData.cpp b/source/game_sa/Collision/CollisionData.cpp index 2245e53ecd..7b2d02337f 100644 --- a/source/game_sa/Collision/CollisionData.cpp +++ b/source/game_sa/Collision/CollisionData.cpp @@ -228,11 +228,11 @@ CLink* CCollisionData::GetLinkPtr() { } auto CCollisionData::GetNumFaceGroups() const -> uint32 { - // See `CCollisionData` header for explanation :) - assert(!bHasFaceGroups || m_pTriangles); - return bHasFaceGroups - ? *reinterpret_cast(reinterpret_cast(m_pTriangles) - sizeof(uint32)) - : 0u; + if (bHasFaceGroups) { + assert(m_pTriangles); + return *reinterpret_cast(reinterpret_cast(m_pTriangles) - sizeof(uint32)); // See `CCollisionData` header for explanation :) + } + return 0; } auto CCollisionData::GetFaceGroups() const -> std::span { @@ -249,7 +249,7 @@ auto CCollisionData::GetFaceGroups() const -> std::span auto CCollisionData::GetTriVertices(const CColTriangle& tri) const->std::array { std::array verts; - for (const auto [i, j] : notsa::enumerate(tri.m_vertIndices)) { + for (auto&& [i, j] : notsa::enumerate(tri.m_vertIndices)) { verts[i] = UncompressVector(m_pVertices[j]); } return verts; diff --git a/source/game_sa/Events/EventDamage.h b/source/game_sa/Events/EventDamage.h index 6669a4f131..54a7412fcc 100644 --- a/source/game_sa/Events/EventDamage.h +++ b/source/game_sa/Events/EventDamage.h @@ -35,6 +35,8 @@ class NOTSA_EXPORT_VTABLE CEventDamage : public CEventEditableResponse { CPedDamageResponse m_damageResponse; public: + static constexpr auto Type = eEventType::EVENT_DAMAGE; + CEventDamage(const CEventDamage& event); CEventDamage(CEntity* source, uint32 startTime, eWeaponType weaponType, ePedPieceTypes pieceHit, uint8 direction, bool a7, bool bPedInVehicle); ~CEventDamage() override; diff --git a/source/game_sa/Tasks/TaskTypes/TaskSimpleThrowProjectile.cpp b/source/game_sa/Tasks/TaskTypes/TaskSimpleThrowProjectile.cpp index aa77ce4f5a..45b1cc939a 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskSimpleThrowProjectile.cpp +++ b/source/game_sa/Tasks/TaskTypes/TaskSimpleThrowProjectile.cpp @@ -2,46 +2,119 @@ #include "TaskSimpleThrowProjectile.h" +void CTaskSimpleThrowProjectile::InjectHooks() { + RH_ScopedVirtualClass(CTaskSimpleThrowProjectile, 0x86d790, 9); + RH_ScopedCategory("Tasks/TaskTypes"); + + RH_ScopedInstall(Constructor, 0x61F660); + RH_ScopedInstall(Destructor, 0x61F700); + + RH_ScopedInstall(ControlThrow, 0x61F810); + RH_ScopedInstall(StartAnim, 0x6259E0); + RH_ScopedInstall(FinishAnimThrowProjectileCB, 0x61F890); + + RH_ScopedVMTInstall(Clone, 0x623030); + RH_ScopedVMTInstall(GetTaskType, 0x61F6F0); + RH_ScopedVMTInstall(MakeAbortable, 0x61F780); + RH_ScopedVMTInstall(ProcessPed, 0x62AF50); +} + // 0x61F660 -CTaskSimpleThrowProjectile::CTaskSimpleThrowProjectile(CEntity* target, CVector posn) : CTaskSimple() { - plugin::CallMethod<0x61F660, CTaskSimpleThrowProjectile*, CEntity*, CVector>(this, target, posn); +CTaskSimpleThrowProjectile::CTaskSimpleThrowProjectile(CEntity* targetEntity, CVector targetPos) : + m_TargetPos{ targetPos }, + m_TargetEntity{ targetEntity }, + m_ButtonCounter{ CTimer::GetTimeInMS() } +{ + CEntity::SafeRegisterRef(m_TargetEntity); +} + +// 0x623030 +CTaskSimpleThrowProjectile::CTaskSimpleThrowProjectile(const CTaskSimpleThrowProjectile& o) : + CTaskSimpleThrowProjectile{ o.m_TargetEntity, o.m_TargetPos } +{ } +// 0x61F700 CTaskSimpleThrowProjectile::~CTaskSimpleThrowProjectile() { - if (m_pAnim) { - m_pAnim->SetFinishCallback(CDefaultAnimCallback::DefaultAnimCB, nullptr); - m_pAnim = nullptr; + if (m_Anim) { + m_Anim->SetDefaultFinishCallback(); + m_Anim = nullptr; } - CEntity::SafeCleanUpRef(m_pTarget); + CEntity::SafeCleanUpRef(m_TargetEntity); } - // 0x61F810 -bool CTaskSimpleThrowProjectile::ControlThrow(bool bUpdateStartTime, CEntity* entity, CVector* entity2) { - return plugin::CallMethodAndReturn(this, bUpdateStartTime, entity, entity2); +bool CTaskSimpleThrowProjectile::ControlThrow(bool bButtonReleased, CEntity* targetEntity, const CVector* targetPos) { + if (m_bIsFinished) { + return true; + } + + if (bButtonReleased && !m_bButtonReleased) { + m_ButtonCounter = CTimer::GetTimeInMS() - m_ButtonCounter; + m_bButtonReleased = true; + } + + if (targetEntity && m_TargetEntity != targetEntity) { + CEntity::ChangeEntityReference(m_TargetEntity, targetEntity); + } + + if (targetPos) { + m_TargetPos = targetPos; + } + + return false; +} + +// 0x61F890 +void CTaskSimpleThrowProjectile::FinishAnimThrowProjectileCB(CAnimBlendAssociation* anim, void* data) { + const auto self = static_cast(data); + + self->m_Anim = nullptr; + if (self->m_bStartThrowFinished) { + self->m_bIsFinished = true; + } else { + self->m_bStartThrowFinished = true; + } +} + +// 0x6259E0 +void CTaskSimpleThrowProjectile::StartAnim(CPed* ped) { + const auto StartAnim = [&, this](AnimationId animId, float blendDelta) { + VERIFY(m_Anim = CAnimManager::BlendAnimation(ped->m_pRwClump, ped->GetActiveWeapon().GetWeaponInfo().m_eAnimGroup, animId, blendDelta)); + m_Anim->SetFinishCallback(FinishAnimThrowProjectileCB, this); + }; + + if (!m_bStartThrowFinished) { + StartAnim(ANIM_ID_GRENADE_WEAPON_START_THROW, 16.f); + } else { + const auto IsPtCloseToPed = [ped](CVector pos) { return (pos - ped->GetPosition()).SquaredMagnitude() <= sq(10.f); }; + if ( (!m_TargetEntity || IsPtCloseToPed(m_TargetEntity->GetPosition())) + || (m_TargetPos.IsZero() || IsPtCloseToPed(m_TargetPos)) + || (m_bButtonReleased || ped->GetActiveWeapon().GetType() == WEAPON_REMOTE_SATCHEL_CHARGE) + ) { + StartAnim(ANIM_ID_GRENADE_WEAPON_THROW, 1000.f); + } else { + StartAnim(ANIM_ID_GRENADE_WEAPON_THROWU, 1000.f); // "U" as in "UP? + } + } } // 0x61F780 bool CTaskSimpleThrowProjectile::MakeAbortable(CPed* ped, eAbortPriority priority, const CEvent* event) { - return plugin::CallMethodAndReturn(this, ped, priority, event); - - // untested - if (priority == ABORT_PRIORITY_URGENT) { - if (m_pAnim) { - m_pAnim->SetFinishCallback(CDefaultAnimCallback::DefaultAnimCB, nullptr); - m_pAnim->m_fBlendDelta = -1000.0f; - m_pAnim = nullptr; - return true; + if (priority == ABORT_PRIORITY_IMMEDIATE) { + if (m_Anim) { + m_Anim->SetDefaultFinishCallback(); + m_Anim->m_fBlendDelta = -1000.0f; + m_Anim = nullptr; } - } else if (event && event->GetEventType() == EVENT_DAMAGE) { - const auto* eventDamage = static_cast(event); - if (eventDamage->m_damageResponse.m_bHealthZero && eventDamage->m_bAddToEventGroup || eventDamage->m_bKnockOffPed) { - if (m_pAnim) { - m_pAnim->SetFinishCallback(CDefaultAnimCallback::DefaultAnimCB, nullptr); - m_pAnim->m_fBlendDelta = -4.0f; - m_pAnim = nullptr; + } else if (const auto eDmg = CEvent::DynCast(event)) { + if (eDmg->m_damageResponse.m_bHealthZero && eDmg->m_bAddToEventGroup || eDmg->m_bKnockOffPed) { + if (m_Anim) { + m_Anim->SetDefaultFinishCallback(); + m_Anim->m_fBlendDelta = -4.0f; + m_Anim = nullptr; } - m_bIsAborting = true; + m_bIsFinished = true; } } return true; @@ -49,16 +122,45 @@ bool CTaskSimpleThrowProjectile::MakeAbortable(CPed* ped, eAbortPriority priorit // 0x62AF50 bool CTaskSimpleThrowProjectile::ProcessPed(CPed* ped) { - return plugin::CallMethodAndReturn(this, ped); -} + if (m_bIsFinished) { + return true; + } -void CTaskSimpleThrowProjectile::InjectHooks() { - RH_ScopedClass(CTaskSimpleThrowProjectile); - RH_ScopedCategory("Tasks/TaskTypes"); - using namespace ReversibleHooks; -} + const auto wi = &ped->GetActiveWeapon().GetWeaponInfo(ped); -// 0x61F660 -CTaskSimpleThrowProjectile* CTaskSimpleThrowProjectile::Constructor(CEntity* pTarget, CVector Posn) { - return plugin::CallMethodAndReturn(this, pTarget, Posn); + if (!wi->flags.bThrow) { + return true; + } + + if (!m_Anim) { + StartAnim(ped); + return false; + } + + switch (m_Anim->m_nAnimId) { + case ANIM_ID_GRENADE_WEAPON_THROW: + case ANIM_ID_GRENADE_WEAPON_THROWU: + const auto animFireTime = m_Anim->m_nAnimId == ANIM_ID_GRENADE_WEAPON_THROW + ? wi->m_fAnimLoop2Fire + : wi->m_fAnimLoopFire; + if (animFireTime < m_Anim->m_fCurrentTime && (m_Anim->m_fCurrentTime - m_Anim->m_fTimeStep) <= animFireTime && m_Anim->IsRunning()) { + if (ped->IsPlayer()) { + if (!m_bButtonReleased) { + m_ButtonCounter = CTimer::GetTimeInMS() - m_ButtonCounter; + } + m_ButtonCounter = std::min(m_ButtonCounter, 533u); + ped->m_pPlayerData->m_fAttackButtonCounter = (float)m_ButtonCounter / 20.f; + } + + if (m_TargetEntity) { + m_TargetPos = m_TargetEntity->GetPosition(); + } + + CVector firePos; + RwV3dTransformPoint(&firePos, &wi->m_vecFireOffset, &ped->GetBoneMatrix((ePedBones)ped->m_apBones[PED_NODE_RIGHT_HAND]->m_nNodeId)); + ped->GetActiveWeapon().Fire(ped, &firePos, &firePos, nullptr, m_TargetPos.IsZero() ? nullptr : &m_TargetPos, nullptr); + } + } + + return false; } diff --git a/source/game_sa/Tasks/TaskTypes/TaskSimpleThrowProjectile.h b/source/game_sa/Tasks/TaskTypes/TaskSimpleThrowProjectile.h index 60d74188e8..97bb2ec7a5 100644 --- a/source/game_sa/Tasks/TaskTypes/TaskSimpleThrowProjectile.h +++ b/source/game_sa/Tasks/TaskTypes/TaskSimpleThrowProjectile.h @@ -11,31 +11,45 @@ class CAnimBlendAssociation; class CEntity; class NOTSA_EXPORT_VTABLE CTaskSimpleThrowProjectile : public CTaskSimple { -public: - bool m_bIsAborting; - bool m_bFinished; - bool m_bStarted; - CAnimBlendAssociation* m_pAnim; - CEntity* m_pTarget; - CVector m_vecPosition; - uint32 m_nStartTime; - public: static constexpr auto Type = TASK_SIMPLE_THROW_PROJECTILE; + static void InjectHooks(); + CTaskSimpleThrowProjectile(CEntity* target, CVector posn); + CTaskSimpleThrowProjectile(const CTaskSimpleThrowProjectile&); ~CTaskSimpleThrowProjectile() override; - eTaskType GetTaskType() const override { return Type; } // 0x61F6F0 - CTask* Clone() const override { return new CTaskSimpleThrowProjectile(m_pTarget, m_vecPosition); } // 0x623030 - bool MakeAbortable(CPed* ped, eAbortPriority priority = ABORT_PRIORITY_URGENT, const CEvent* event = nullptr) override; - bool ProcessPed(CPed* ped) override; + eTaskType GetTaskType() const override { return Type; } // 0x61F6F0 + CTask* Clone() const override { return new CTaskSimpleThrowProjectile{ *this }; } // 0x623030 + bool MakeAbortable(CPed* ped, eAbortPriority priority = ABORT_PRIORITY_URGENT, const CEvent* event = nullptr) override; + bool ProcessPed(CPed* ped) override; - bool ControlThrow(bool bUpdateStartTime, CEntity* entity, CVector* posn); - void FinishAnimThrowProjectileCB(CAnimBlendAssociation* anim, void* data); - void StartAnim(CPed* ped); + bool ControlThrow(bool bButtonReleased, CEntity* entity, const CVector* pos); - static void InjectHooks(); - CTaskSimpleThrowProjectile* Constructor(CEntity* target, CVector posn); + static void FinishAnimThrowProjectileCB(CAnimBlendAssociation* anim, void* data); + void StartAnim(CPed* ped); + +public: + bool m_bIsFinished{}; + bool m_bStartThrowFinished{}; + bool m_bButtonReleased{}; + CAnimBlendAssociation* m_Anim{}; + CEntity* m_TargetEntity{}; + CVector m_TargetPos{}; + uint32 m_ButtonCounter{}; + +private: + // 0x61F660 + CTaskSimpleThrowProjectile* Constructor(CEntity * pEntity, CVector firingPoint) { + this->CTaskSimpleThrowProjectile::CTaskSimpleThrowProjectile(pEntity, firingPoint); + return this; + } + + // 0x61F700 + CTaskSimpleThrowProjectile* Destructor() { + this->CTaskSimpleThrowProjectile::~CTaskSimpleThrowProjectile(); + return this; + } }; VALIDATE_SIZE(CTaskSimpleThrowProjectile, 0x24); From a8ea950ec432115d965e749ff486a77abd97521b Mon Sep 17 00:00:00 2001 From: plakapenka Date: Sun, 15 Oct 2023 18:56:16 +0300 Subject: [PATCH 9/9] use existing variable (#636) --- source/game_sa/PathFind.cpp | 2 +- source/game_sa/PathFind.h | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/source/game_sa/PathFind.cpp b/source/game_sa/PathFind.cpp index 734e6f16ae..d971415d13 100644 --- a/source/game_sa/PathFind.cpp +++ b/source/game_sa/PathFind.cpp @@ -118,7 +118,7 @@ void CPathFind::Init() { m_nNumForbiddenAreas = 0; m_loadAreaRequestPending = false; - for (auto i = 0u; i < NUM_PATH_MAP_AREAS + NUM_PATH_INTERIOR_AREAS; ++i) { + for (auto i = 0u; i < NUM_TOTAL_PATH_NODE_AREAS; ++i) { m_pPathNodes[i] = nullptr; m_pNaviNodes[i] = nullptr; m_pNodeLinks[i] = nullptr; diff --git a/source/game_sa/PathFind.h b/source/game_sa/PathFind.h index f1c81fc745..538135fa78 100644 --- a/source/game_sa/PathFind.h +++ b/source/game_sa/PathFind.h @@ -193,21 +193,21 @@ class CPathFind { * The first part of the array has the vehicle nodes (count: `m_anNumVehicleNodes`) * the remaining part has ped nodes (count: `m_anNumPedNodes`) */ - CPathNode* m_pPathNodes[NUM_PATH_MAP_AREAS + NUM_PATH_INTERIOR_AREAS]; // 0x804 + CPathNode* m_pPathNodes[NUM_TOTAL_PATH_NODE_AREAS]; // 0x804 // Use CPathFind::GetCarPathLink to access - CCarPathLink* m_pNaviNodes[NUM_PATH_MAP_AREAS + NUM_PATH_INTERIOR_AREAS]; // 0x924 - CNodeAddress* m_pNodeLinks[NUM_PATH_MAP_AREAS + NUM_PATH_INTERIOR_AREAS]; // 0xA44 - uint8* m_pLinkLengths[NUM_PATH_MAP_AREAS + NUM_PATH_INTERIOR_AREAS]; // 0xB64 - CPathIntersectionInfo* m_pPathIntersections[NUM_PATH_MAP_AREAS + NUM_PATH_INTERIOR_AREAS]; // 0xC84 + CCarPathLink* m_pNaviNodes[NUM_TOTAL_PATH_NODE_AREAS]; // 0x924 + CNodeAddress* m_pNodeLinks[NUM_TOTAL_PATH_NODE_AREAS]; // 0xA44 + uint8* m_pLinkLengths[NUM_TOTAL_PATH_NODE_AREAS]; // 0xB64 + CPathIntersectionInfo* m_pPathIntersections[NUM_TOTAL_PATH_NODE_AREAS]; // 0xC84 CCarPathLinkAddress* m_pNaviLinks[NUM_PATH_MAP_AREAS]; // 0xDA4 void* m_aUnused[22]; // 0xEA4 uint32 m_aUnk[NUM_PATH_MAP_AREAS - 22]; // 0xEFC - uint32 m_anNumNodes[NUM_PATH_MAP_AREAS + NUM_PATH_INTERIOR_AREAS]; // 0xFA4 - uint32 m_anNumVehicleNodes[NUM_PATH_MAP_AREAS + NUM_PATH_INTERIOR_AREAS]; // 0x10C4 - uint32 m_anNumPedNodes[NUM_PATH_MAP_AREAS + NUM_PATH_INTERIOR_AREAS]; // 0x11E4 - uint32 m_anNumCarPathLinks[NUM_PATH_MAP_AREAS + NUM_PATH_INTERIOR_AREAS]; - uint32 m_anNumAddresses[NUM_PATH_MAP_AREAS + NUM_PATH_INTERIOR_AREAS]; + uint32 m_anNumNodes[NUM_TOTAL_PATH_NODE_AREAS]; // 0xFA4 + uint32 m_anNumVehicleNodes[NUM_TOTAL_PATH_NODE_AREAS]; // 0x10C4 + uint32 m_anNumPedNodes[NUM_TOTAL_PATH_NODE_AREAS]; // 0x11E4 + uint32 m_anNumCarPathLinks[NUM_TOTAL_PATH_NODE_AREAS]; + uint32 m_anNumAddresses[NUM_TOTAL_PATH_NODE_AREAS]; int32 m_aDynamicLinksBaseIds[NUM_PATH_MAP_AREAS][NUM_DYNAMIC_LINKS_PER_AREA]; int32 m_aDynamicLinksIds[NUM_PATH_MAP_AREAS][NUM_DYNAMIC_LINKS_PER_AREA]; uint32 m_totalNumNodesInPathFindHashTable; // Number of items in total in all buckets of `m_pathFindHashTable` @@ -460,7 +460,7 @@ class CPathFind { CPathNode* GetPathNode(CNodeAddress address); inline CCarPathLink& GetCarPathLink(const CCarPathLinkAddress& address) { - assert(address.m_wAreaId < NUM_PATH_MAP_AREAS + NUM_PATH_INTERIOR_AREAS); + assert(address.m_wAreaId < NUM_TOTAL_PATH_NODE_AREAS); return m_pNaviNodes[address.m_wAreaId][address.m_wCarPathLinkId]; }