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..6480e74d 100644 --- a/dGame/dComponents/MissionComponent.cpp +++ b/dGame/dComponents/MissionComponent.cpp @@ -3,6 +3,7 @@ * Copyright 2019 */ +#include #include #include @@ -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 (auto* const mission : m_Missions | std::views::values) { + if (!mission || mission->IsComplete()) continue; + + for (auto* const 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..7ac4b108 100644 --- a/dGame/dComponents/MissionComponent.h +++ b/dGame/dComponents/MissionComponent.h @@ -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); 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/MissionTask.cpp b/dGame/dMission/MissionTask.cpp index c8f2f9c0..872796a8 100644 --- a/dGame/dMission/MissionTask.cpp +++ b/dGame/dMission/MissionTask.cpp @@ -418,7 +418,24 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& AddProgress(count); } else if (associate == 4 || associate == 5 || associate == 14) { if (!InAllTargets(value)) break; - AddProgress(count); + if (associate == 4) { + // Recount all completed target missions so this stays idempotent with + // Catchup, which sets the same value on Accept(). AddProgress would + // double-count when LookForAchievements runs Catchup then Progress. + auto* entity = mission->GetAssociate(); + if (entity == nullptr) break; + auto* missionComponent = entity->GetComponent(); + if (missionComponent == nullptr) break; + uint32_t completedCount = 0; + for (const auto& target : GetAllTargets()) { + if (target == 0) continue; + auto* targetMission = missionComponent->GetMission(target); + if (targetMission != nullptr && targetMission->IsComplete()) completedCount++; + } + SetProgress(completedCount); + } else { + AddProgress(count); + } } else if (associate == 17) { if (!InAllTargets(value)) break; AddProgress(count); diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index ad570534..34b485df 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -1115,6 +1115,12 @@ void HandlePacket(Packet* packet) { case eCharacterVersion::PET_IDS: { LOG("Regenerating item ids"); inventoryComponent->RegenerateItemIDs(); + levelComponent->SetCharacterVersion(eCharacterVersion::INVENTORY_PERSISTENT_IDS); + [[fallthrough]]; + } + case eCharacterVersion::INVENTORY_PERSISTENT_IDS: { + LOG("Fixing racing meta missions"); + missionComponent->FixRacingMetaMissions(); levelComponent->SetCharacterVersion(eCharacterVersion::UP_TO_DATE); [[fallthrough]]; }