Skip to content

Commit

Permalink
CTaskSimpleChat and CTaskComplexChat (gta-reversed#592)
Browse files Browse the repository at this point in the history
* Fix `CPedGroupMembership::AppointNewLeader`

* `CTaskComplexChat`
  • Loading branch information
Pirulax authored Aug 1, 2023
1 parent 50579ee commit a076e21
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 54 deletions.
2 changes: 1 addition & 1 deletion source/game_sa/InterestingEvents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ CInterestingEvents::CInterestingEvents() {
};

SetOptions(INTERESTING_EVENT_0, 5, 2000);
SetOptions(INTERESTING_EVENT_1, 1, 5000);
SetOptions(PEDS_CHATTING, 1, 5000);
SetOptions(INTERESTING_EVENT_2, 1, 5000);
SetOptions(INTERESTING_EVENT_3, 1, 5000);
SetOptions(INTERESTING_EVENT_4, 2, 3000);
Expand Down
2 changes: 1 addition & 1 deletion source/game_sa/InterestingEvents.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class CInterestingEvents {
public:
enum EType {
INTERESTING_EVENT_0 = 0, //
INTERESTING_EVENT_1 = 1, // CTaskComplexChat::CreateFirstSubTask
PEDS_CHATTING = 1, // CTaskComplexChat::CreateFirstSubTask
INTERESTING_EVENT_2 = 2, // CTaskComplexSunbathe::CreateNextSubTask
INTERESTING_EVENT_3 = 3, // CTaskComplexUseAttractor::CreateFirstSubTask CTaskComplexUseClosestFreeScriptedAttractor::CreateFirstSubTask
INTERESTING_EVENT_4 = 4, //
Expand Down
9 changes: 6 additions & 3 deletions source/game_sa/PedGroupMembership.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ void CPedGroupMembership::AddFollower(CPed* ped) {

// 0x5F6AE0
void CPedGroupMembership::AddMember(CPed* member, int32 memIdx) {
assert(member);
assert(!m_members[memIdx]);

m_members[memIdx] = member;
CEntity::RegisterReference(m_members[memIdx]);
/* dead code before checking if the member is in the player's group */
Expand All @@ -60,8 +62,9 @@ void CPedGroupMembership::AppointNewLeader() {
return;
}

const auto leader = m_members[memId];
RemoveMember(memId); // Must call as it does some cleanup
AddMember(m_members[memId], LEADER_MEM_ID);
AddMember(leader, LEADER_MEM_ID);
}

// 0x5F6A50
Expand All @@ -79,8 +82,8 @@ int32 CPedGroupMembership::CountMembersExcludingLeader() {

// 0x5FB160
void CPedGroupMembership::Flush() {
for (auto i = 0u; i < m_members.size(); i++) {
if (GetMember(i)) {
for (auto&& [i, mem] : notsa::enumerate(m_members)) {
if (mem) {
RemoveMember(i);
}
}
Expand Down
119 changes: 81 additions & 38 deletions source/game_sa/Tasks/TaskTypes/TaskComplexChat.cpp
Original file line number Diff line number Diff line change
@@ -1,31 +1,49 @@
#include "StdInc.h"

#include "TaskComplexChat.h"

#include "TaskSimpleChat.h"
#include "InterestingEvents.h"
#include "TaskSimpleRunAnim.h"
#include "TaskSimpleStandStill.h"

void CTaskComplexChat::InjectHooks() {
RH_ScopedVirtualClass(CTaskComplexChat, 0x8706A0, 14);
RH_ScopedCategory("Tasks/TaskTypes");

RH_ScopedInstall(Constructor, 0x682CB0);
RH_ScopedInstall(Destructor, 0x682D40);
RH_ScopedVMTInstall(Clone, 0x682DA0);
RH_ScopedVMTInstall(GetTaskType, 0x682D30);
RH_ScopedVMTInstall(CreateNextSubTask, 0x682E10);
RH_ScopedVMTInstall(CreateFirstSubTask, 0x682E20);
RH_ScopedVMTInstall(ControlSubTask, 0x683060);
}

// 0x682CB0
CTaskComplexChat::CTaskComplexChat(bool a2, CPed* ped, int32 updateDirectionCount, int16 conversationId) : CTaskComplex() {
byteC = a2;
m_UpdateDirectionCount = updateDirectionCount;
m_Ped = ped;
m_ConversationId = conversationId;
CEntity::SafeRegisterRef(m_Ped);
byte1A = 0;
dword1C = 0;
CTaskComplexChat::CTaskComplexChat(bool isChatter, CPed* partner, int32 stage, int16 globalSpeechContext) :
m_IsChatter{ isChatter },
m_ChatPartner{partner},
m_Stage{stage},
m_GlobalSpeechContext{ globalSpeechContext }
{
CEntity::SafeRegisterRef(m_ChatPartner);
}

// 0x682D40
CTaskComplexChat::~CTaskComplexChat() {
CEntity::SafeCleanUpRef(m_Ped);
CTaskComplexChat::CTaskComplexChat(const CTaskComplexChat& o) :
CTaskComplexChat{
o.m_IsChatter,
o.m_ChatPartner,
o.m_Stage,
o.m_GlobalSpeechContext
}
{
m_TaskFinished = o.m_TaskFinished;
}

// 0x682DA0
CTask* CTaskComplexChat::Clone() {
auto* task = new CTaskComplexChat(byteC, m_Ped, m_UpdateDirectionCount, m_ConversationId);
task->byte1A = byte1A;
return task;
// 0x682D40
CTaskComplexChat::~CTaskComplexChat() {
CEntity::SafeCleanUpRef(m_ChatPartner);
}

// 0x682E10
Expand All @@ -35,38 +53,63 @@ CTask* CTaskComplexChat::CreateNextSubTask(CPed* ped) {

// 0x682E20
CTask* CTaskComplexChat::CreateFirstSubTask(CPed* ped) {
return plugin::CallMethodAndReturn<CTask*, 0x682E20, CTaskComplexChat*, CPed*>(this, ped);

if (!m_Ped)
if (!m_ChatPartner) {
return nullptr;
}

if (!byteC) {
return new CTaskSimpleStandStill(999999);
if (!m_IsChatter) {
return new CTaskSimpleStandStill(999'999);
}

if (m_ConversationId > -1) {
ped->Say(m_ConversationId);
if (m_GlobalSpeechContext > -1) {
ped->Say(m_GlobalSpeechContext);
}

g_InterestingEvents.Add(CInterestingEvents::INTERESTING_EVENT_1, ped);

if (m_ConversationId == 164 || m_ConversationId > 166 && m_ConversationId <= 168) {
auto RandomNumberInRange = CGeneral::GetRandomNumberInRange(0, 3);
if (RandomNumberInRange) {
if (RandomNumberInRange == 1) {
return new CTaskSimpleRunAnim(ANIM_GROUP_DEFAULT, ANIM_ID_ENDCHAT_02, 4.0f, 0);
} else if (RandomNumberInRange == 2) {
return new CTaskSimpleRunAnim(ANIM_GROUP_DEFAULT, ANIM_ID_ENDCHAT_03, 4.0f, 0);
} else {
// todo: return new CTaskSimpleChat(4000);
}
g_InterestingEvents.Add(CInterestingEvents::PEDS_CHATTING, ped);

if (m_GlobalSpeechContext == 164 || m_GlobalSpeechContext > 166 && m_GlobalSpeechContext <= 168) {
switch (CGeneral::GetRandomNumberInRange(0, notsa::IsFixBugs() ? 3 : 4)) {
case 0: return new CTaskSimpleRunAnim(ANIM_GROUP_DEFAULT, ANIM_ID_ENDCHAT_01, 4.0f, 0);
case 1: return new CTaskSimpleRunAnim(ANIM_GROUP_DEFAULT, ANIM_ID_ENDCHAT_02, 4.0f, 0);
case 2: return new CTaskSimpleRunAnim(ANIM_GROUP_DEFAULT, ANIM_ID_ENDCHAT_03, 4.0f, 0);
case 3: return new CTaskSimpleChat{ 4000 }; // NOTE: (FIXED-BUG) Originally unreachable
}
return new CTaskSimpleRunAnim(ANIM_GROUP_DEFAULT, ANIM_ID_ENDCHAT_01, 4.0f, 0);
}
// todo: return new CTaskSimpleChat(999999);

return new CTaskSimpleChat{ 999'999 };
}

// 0x683060
CTask* CTaskComplexChat::ControlSubTask(CPed* ped) {
return plugin::CallMethodAndReturn<CTask*, 0x683060, CTaskComplexChat*, CPed*>(this, ped);
if (!m_ChatPartner) {
return nullptr;
}

if (m_TaskFinished && m_pSubTask->MakeAbortable(ped, ABORT_PRIORITY_URGENT, nullptr)) {
return nullptr;
}

const auto partnerChatTask = m_ChatPartner->GetTaskManager().Find<CTaskComplexChat>();
if (partnerChatTask) {
if (partnerChatTask->m_Stage < m_Stage || !partnerChatTask->m_TaskFinished && m_IsChatter == partnerChatTask->m_IsChatter) {
m_TaskFinished = true;
}
}

if (m_IsChatter && !ped->GetPedTalking()) {
if (partnerChatTask) {
if (!partnerChatTask->m_TaskFinished && !partnerChatTask->m_IsChatter) {
partnerChatTask->m_TaskFinished = m_TaskFinished = true;
}
}
m_NoChatTimeout++;
if (m_NoChatTimeout > 50) {
m_TaskFinished = true;
if (partnerChatTask) {
partnerChatTask->m_TaskFinished = true;
}
}
}

return m_pSubTask;
}
37 changes: 26 additions & 11 deletions source/game_sa/Tasks/TaskTypes/TaskComplexChat.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,39 @@ class CEntity;

class CTaskComplexChat : public CTaskComplex {
public:
bool byteC;
CPed* m_Ped;
int32 m_UpdateDirectionCount;
int16 m_ConversationId;
int8 byte1A;
int32 dword1C;
bool m_IsChatter{};
CPed* m_ChatPartner{};
int32 m_Stage{};
int16 m_GlobalSpeechContext{};
bool m_TaskFinished{};
int32 m_NoChatTimeout{};

public:
static constexpr auto Type = TASK_COMPLEX_CHAT;

CTaskComplexChat(bool a2, CPed* ped, int32 updateDirectionCount, int16 conversationId);
static void InjectHooks();

CTaskComplexChat(bool isChatter, CPed* partner, int32 stage, int16 globalSpeechContext);
CTaskComplexChat(const CTaskComplexChat&);
~CTaskComplexChat() override;

eTaskType GetTaskType() override { return Type; } // 0x682D30
CTask* Clone() override;
CTask* Clone() override { return new CTaskComplexChat{*this}; }
CTask* ControlSubTask(CPed* ped) override;
CTask* CreateFirstSubTask(CPed* ped) override;
CTask* CreateNextSubTask(CPed* ped) override;

private: // Wrappers for hooks
// 0x682CB0
CTaskComplexChat* Constructor(uint8 a, CPed* b, int32 c, int16 d) {
this->CTaskComplexChat::CTaskComplexChat(a, b, c, d);
return this;
}

CTask* ControlSubTask(CPed* ped) override;
CTask* CreateFirstSubTask(CPed* ped) override;
CTask* CreateNextSubTask(CPed* ped) override;
// 0x682D40
CTaskComplexChat* Destructor() {
this->CTaskComplexChat::~CTaskComplexChat();
return this;
}
};
VALIDATE_SIZE(CTaskComplexChat, 0x20);
38 changes: 38 additions & 0 deletions source/game_sa/Tasks/TaskTypes/TaskSimpleChat.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include "StdInc.h"
#include "TaskSimpleChat.h"


void CTaskSimpleChat::InjectHooks() {
RH_ScopedVirtualClass(CTaskSimpleChat, 0x86C78C, 10);
RH_ScopedCategory("Tasks/TaskTypes");

RH_ScopedInstall(Destructor, 0x5F7FD0);
RH_ScopedVMTInstall(Clone, 0x5F65E0);
RH_ScopedVMTInstall(IsInterruptable, 0x5F6650);
}

// 0x5F65A0
CTaskSimpleChat::CTaskSimpleChat(uint32 duration) :
CTaskSimpleRunTimedAnim{
ANIM_GROUP_DEFAULT,
ANIM_ID_IDLE_CHAT,
4.f,
-4.f,
duration,
TASK_SIMPLE_CHAT,
"Chat",
0
}
{
}

// 0x5F65E0
CTaskSimpleChat::CTaskSimpleChat(const CTaskSimpleChat& o) :
CTaskSimpleChat{ o.m_durationMs }
{
}

// 0x5F7FD0
CTaskSimpleChat::~CTaskSimpleChat() {
assert(false && "Destructor not reversed"); // TODO: Reverse destructor}
}
26 changes: 26 additions & 0 deletions source/game_sa/Tasks/TaskTypes/TaskSimpleChat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

#include "TaskSimpleRunTimedAnim.h"

class CPed;

class CTaskSimpleChat : public CTaskSimpleRunTimedAnim {
public:
static constexpr auto Type = TASK_SIMPLE_CHAT;

static void InjectHooks();

CTaskSimpleChat(uint32 duration);
CTaskSimpleChat(const CTaskSimpleChat& o);
~CTaskSimpleChat();

virtual CTask* Clone() { return new CTaskSimpleChat{ *this }; }
virtual bool IsInterruptable(CPed const* ped) { return false; }

private:
// 0x5F7FD0
CTaskSimpleChat* Destructor() {
this->CTaskSimpleChat::~CTaskSimpleChat();
return this;
}
};

0 comments on commit a076e21

Please sign in to comment.