diff --git a/dCommon/dEnums/eCharacterVersion.h b/dCommon/dEnums/eCharacterVersion.h index 15610c3a..7ba3be8f 100644 --- a/dCommon/dEnums/eCharacterVersion.h +++ b/dCommon/dEnums/eCharacterVersion.h @@ -20,7 +20,8 @@ enum class eCharacterVersion : uint32_t { NJ_JAYMISSIONS, NEXUS_FORCE_EXPLORER, // Fixes pet ids in player inventories PET_IDS, // Fixes pet ids in player inventories - UP_TO_DATE, // will become INVENTORY_PERSISTENT_IDS + INVENTORY_PERSISTENT_IDS, // Fixes racing meta missions + UP_TO_DATE, // will become RACING_META_MISSIONS }; #endif //!__ECHARACTERVERSION__H__ diff --git a/dGame/dComponents/MissionComponent.cpp b/dGame/dComponents/MissionComponent.cpp index b3a503d5..af53c16e 100644 --- a/dGame/dComponents/MissionComponent.cpp +++ b/dGame/dComponents/MissionComponent.cpp @@ -3,6 +3,7 @@ * Copyright 2019 */ +#include #include #include @@ -71,7 +72,7 @@ eMissionState MissionComponent::GetMissionState(const uint32_t missionId) const } -const std::unordered_map& MissionComponent::GetMissions() const { +const std::map& MissionComponent::GetMissions() const { return m_Missions; } @@ -149,7 +150,7 @@ void MissionComponent::Progress(eMissionTaskType type, int32_t value, LWOOBJID a } for (const auto& [id, mission] : m_Missions) { - if (!mission || std::find(acceptedAchievements.begin(), acceptedAchievements.end(), mission->GetMissionId()) != acceptedAchievements.end()) continue; + if (!mission || std::ranges::find(acceptedAchievements, mission->GetMissionId()) != acceptedAchievements.end()) continue; if (mission->IsAchievement() && ignoreAchievements) continue; @@ -747,3 +748,30 @@ bool MissionComponent::OnMissionNeedsLot(GameMessages::GameMsg& msg) { const auto& needMsg = static_cast(msg); return RequiresItem(needMsg.item); } + +void MissionComponent::FixRacingMetaMissions() { + for (const auto mission : m_Missions | std::views::values) { + if (!mission || mission->IsComplete()) continue; + + for (const auto task : mission->GetTasks()) { + if (!task) continue; + + // has to be a racing meta mission and have a taskparam1 of 4 + if (task->GetType() != eMissionTaskType::RACING || !task->GetClientInfo().taskParam1.starts_with("4")) continue; + + // Each target is racing mission that needs to be completed. + // If its completed, progress the meta task by 1. + uint32_t progress = 0; + for (const auto& target : task->GetAllTargets()) { + if (target == 0) continue; + auto* racingMission = GetMission(target); + if (racingMission && racingMission->IsComplete()) { + progress++; + } + } + task->SetProgress(progress); + } + // in case the mission is actually complete, give them the rewards + mission->CheckCompletion(); + } +} diff --git a/dGame/dComponents/MissionComponent.h b/dGame/dComponents/MissionComponent.h index a5cd058a..d8b0d84e 100644 --- a/dGame/dComponents/MissionComponent.h +++ b/dGame/dComponents/MissionComponent.h @@ -38,7 +38,7 @@ public: * Returns all the missions for this entity, mapped by mission ID * @return the missions for this entity, mapped by mission ID */ - const std::unordered_map& GetMissions() const; + const std::map& GetMissions() const; /** * Returns the mission for the given mission ID, if it exists @@ -170,6 +170,8 @@ public: bool HasMission(uint32_t missionId); void ResetMission(const int32_t missionId); + + void FixRacingMetaMissions(); private: bool OnGetObjectReportInfo(GameMessages::GameMsg& msg); bool OnGetMissionState(GameMessages::GameMsg& msg); @@ -177,7 +179,7 @@ private: /** * All the missions owned by this entity, mapped by mission ID */ - std::unordered_map m_Missions; + std::map m_Missions; /** * All the collectibles currently collected by the entity diff --git a/dGame/dMission/Mission.cpp b/dGame/dMission/Mission.cpp index 3d46cde8..e13cc411 100644 --- a/dGame/dMission/Mission.cpp +++ b/dGame/dMission/Mission.cpp @@ -407,9 +407,7 @@ void Mission::Catchup() { task->Progress(target); } } - } - - if (type == eMissionTaskType::PLAYER_FLAG) { + } else if (type == eMissionTaskType::PLAYER_FLAG) { for (int32_t target : task->GetAllTargets()) { const auto flag = GetCharacter()->GetPlayerFlag(target); @@ -423,6 +421,24 @@ void Mission::Catchup() { break; } } + } else if (type == eMissionTaskType::RACING) { + // check if its a racing meta task ("4") and then set its progress to the current completed missions in all tasks + const auto& clientInfo = task->GetClientInfo(); + if (clientInfo.taskParam1.starts_with("4")) { + // Each target is racing mission that needs to be completed. + // If its completed, progress the meta task by 1. + // at the end set the task progress to avoid sending excess msgs across the wire + uint32_t progress = 0; + for (const auto& target : task->GetAllTargets()) { + if (target == 0) continue; + + auto* racingMission = m_MissionComponent->GetMission(target); + if (racingMission != nullptr && racingMission->IsComplete()) { + progress++; + } + } + task->SetProgress(progress); + } } } } diff --git a/dGame/dMission/MissionPrerequisites.cpp b/dGame/dMission/MissionPrerequisites.cpp index b5b81160..97dcfe9e 100644 --- a/dGame/dMission/MissionPrerequisites.cpp +++ b/dGame/dMission/MissionPrerequisites.cpp @@ -92,7 +92,7 @@ PrerequisiteExpression::PrerequisiteExpression(const std::string& str) { } -bool PrerequisiteExpression::Execute(const std::unordered_map& missions) const { +bool PrerequisiteExpression::Execute(const std::map& missions) const { auto a = this->a == 0; auto b = this->b == nullptr; @@ -129,7 +129,7 @@ PrerequisiteExpression::~PrerequisiteExpression() { } -bool MissionPrerequisites::CanAccept(const uint32_t missionId, const std::unordered_map& missions) { +bool MissionPrerequisites::CanAccept(const uint32_t missionId, const std::map& missions) { const auto& missionIndex = missions.find(missionId); if (missionIndex != missions.end()) { @@ -155,7 +155,7 @@ bool MissionPrerequisites::CanAccept(const uint32_t missionId, const std::unorde return CheckPrerequisites(missionId, missions); } -bool MissionPrerequisites::CheckPrerequisites(uint32_t missionId, const std::unordered_map& missions) { +bool MissionPrerequisites::CheckPrerequisites(uint32_t missionId, const std::map& missions) { const auto& index = expressions.find(missionId); if (index != expressions.end()) { return index->second->Execute(missions); diff --git a/dGame/dMission/MissionPrerequisites.h b/dGame/dMission/MissionPrerequisites.h index 13b8e903..d1a1ab19 100644 --- a/dGame/dMission/MissionPrerequisites.h +++ b/dGame/dMission/MissionPrerequisites.h @@ -21,7 +21,7 @@ public: * @param missions the list of missions to check the prerequisites against (f.e. whether they're completed) * @return whether or not all the prerequisites are met */ - bool Execute(const std::unordered_map& missions) const; + bool Execute(const std::map& missions) const; explicit PrerequisiteExpression(const std::string& str); ~PrerequisiteExpression(); @@ -40,7 +40,7 @@ public: * @param missions the mission inventory to check the prerequisites against * @return whether or not the mission identified by the specified ID can be accepted */ - static bool CanAccept(uint32_t missionId, const std::unordered_map& missions); + static bool CanAccept(uint32_t missionId, const std::map& missions); private: /** @@ -54,5 +54,5 @@ private: * @param missions the mission inventory to check the prerequisites against * @return whether or not the mission identified by the specified ID can be accepted */ - static bool CheckPrerequisites(uint32_t missionId, const std::unordered_map& missions); + static bool CheckPrerequisites(uint32_t missionId, const std::map& missions); }; diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index ad570534..18d5b4f2 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -1118,6 +1118,11 @@ void HandlePacket(Packet* packet) { levelComponent->SetCharacterVersion(eCharacterVersion::UP_TO_DATE); [[fallthrough]]; } + case eCharacterVersion::INVENTORY_PERSISTENT_IDS: { + LOG("Fixing racing meta missions"); + missionComponent->FixRacingMetaMissions(); + [[fallthrough]]; + } case eCharacterVersion::UP_TO_DATE: break; }