diff --git a/dGame/dComponents/MissionOfferComponent.cpp b/dGame/dComponents/MissionOfferComponent.cpp index 774de1c7..7dbaecdc 100644 --- a/dGame/dComponents/MissionOfferComponent.cpp +++ b/dGame/dComponents/MissionOfferComponent.cpp @@ -1,6 +1,6 @@ /* * Darkflame Universe - * Copyright 2019 + * Copyright 2023 */ #include @@ -18,61 +18,26 @@ #include "CDComponentsRegistryTable.h" -OfferedMission::OfferedMission(const uint32_t missionId, const bool offersMission, const bool acceptsMission) { - this->missionId = missionId; - this->offersMission = offersMission; - this->acceptsMission = acceptsMission; +MissionOfferComponent::MissionOfferComponent(Entity* parent, const int32_t componentId) : Component(parent) { + m_ComponentId = componentId; } +void MissionOfferComponent::LoadTemplateData() { + if (m_ComponentId == -1) return; + // Now lookup the missions in the MissionNPCComponent table + auto* missionNpcComponentTable = CDClientManager::Instance().GetTable(); -uint32_t OfferedMission::GetMissionId() const { - return this->missionId; -} + auto missions = missionNpcComponentTable->Query([=](const CDMissionNPCComponent& entry) { + return entry.id == static_cast(m_ComponentId); + }); -bool OfferedMission::GetOfferMission() const { - return this->offersMission; -} - -bool OfferedMission::GetAcceptMission() const { - return this->acceptsMission; -} - -//------------------------ MissionOfferComponent below ------------------------ - -MissionOfferComponent::MissionOfferComponent(Entity* parent, const LOT parentLot) : Component(parent) { - auto* compRegistryTable = CDClientManager::Instance().GetTable(); - - auto value = compRegistryTable->GetByIDAndType(parentLot, eReplicaComponentType::MISSION_OFFER, -1); - - if (value != -1) { - const uint32_t componentId = value; - - // Now lookup the missions in the MissionNPCComponent table - auto* missionNpcComponentTable = CDClientManager::Instance().GetTable(); - - auto missions = missionNpcComponentTable->Query([=](const CDMissionNPCComponent& entry) { - return entry.id == static_cast(componentId); - }); - - for (auto& mission : missions) { - auto* offeredMission = new OfferedMission(mission.missionID, mission.offersMission, mission.acceptsMission); - this->offeredMissions.push_back(offeredMission); - } + for (const auto& mission : missions) { + this->offeredMissions.emplace_back( + std::make_unique(mission.missionID, mission.offersMission, mission.acceptsMission) + ); } } - -MissionOfferComponent::~MissionOfferComponent() { - for (auto* mission : this->offeredMissions) { - if (mission) { - delete mission; - mission = nullptr; - } - } - - offeredMissions.clear(); -} - void MissionOfferComponent::OnUse(Entity* originator) { OfferMissions(originator); } @@ -88,17 +53,15 @@ void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifi std::vector offered{}; - CDMissions info{}; + CDMissions missionInfo{}; - if (specifiedMissionId > 0 && !Mission::IsValidMission(specifiedMissionId, info)) { + if (specifiedMissionId > 0 && !Mission::IsValidMission(specifiedMissionId, missionInfo)) { return; } - for (auto* offeredMission : this->offeredMissions) { - if (specifiedMissionId > 0) { - if (offeredMission->GetMissionId() != specifiedMissionId && !info.isRandom) { - continue; - } + for (const auto& offeredMission : offeredMissions) { + if (specifiedMissionId > 0 && (offeredMission->GetMissionId() != specifiedMissionId && !missionInfo.isRandom)) { + continue; } // First, check if we already have the mission @@ -106,10 +69,13 @@ void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifi auto* mission = missionComponent->GetMission(missionId); - if (mission != nullptr) { + if (mission) { if (specifiedMissionId <= 0) { // Handles the odd case where the offer object should not display the mission again - if (!mission->IsComplete() && mission->GetClientInfo().offer_objectID == m_ParentEntity->GetLOT() && mission->GetClientInfo().target_objectID != m_ParentEntity->GetLOT() && mission->IsFetchMission()) { + if (!mission->IsComplete() && + mission->GetClientInfo().offer_objectID == m_ParentEntity->GetLOT() && + mission->GetClientInfo().target_objectID != m_ParentEntity->GetLOT() && + mission->IsFetchMission()) { continue; } } @@ -127,50 +93,30 @@ void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifi const auto canAccept = MissionPrerequisites::CanAccept(missionId, missionComponent->GetMissions()); // Mission has not yet been accepted - check the prereqs - if (!canAccept) - continue; + if (!canAccept || !Mission::IsValidMission(missionId, missionInfo)) continue; - if (!Mission::IsValidMission(missionId, info)) { - continue; - } + // This means the mission is part of a random pool of missions. + if (missionInfo.isRandom && missionInfo.randomPool.empty()) continue; - const auto& randomPool = info.randomPool; - const auto isRandom = info.isRandom; + if (missionInfo.isRandom && !missionInfo.randomPool.empty()) { + auto randomMissionPoolStr = GeneralUtils::SplitString(missionInfo.randomPool, ','); - if (isRandom && randomPool.empty()) // This means the mission is part of a random pool of missions. - { - continue; - } - - if (isRandom && !randomPool.empty()) { - std::istringstream stream(randomPool); - std::string token; - - std::vector randomMissionPool; - - while (std::getline(stream, token, ',')) { - try { - const auto value = std::stoul(token); - - randomMissionPool.push_back(value); - } catch (std::invalid_argument& exception) { - Game::logger->Log("MissionOfferComponent", "Failed to parse value (%s): (%s)!", token.c_str(), exception.what()); - } + std::vector randomMissions; + for (const auto& randomMissionStr : randomMissionPoolStr) { + uint32_t randomMission; + if (GeneralUtils::TryParse(randomMissionStr, randomMission)) randomMissions.push_back(randomMission); } if (specifiedMissionId > 0) { - const auto& iter = std::find(randomMissionPool.begin(), randomMissionPool.end(), specifiedMissionId); - - if (iter != randomMissionPool.end() && MissionPrerequisites::CanAccept(specifiedMissionId, missionComponent->GetMissions())) { + if (std::find(randomMissions.begin(), randomMissions.end(), specifiedMissionId) != randomMissions.end() && + MissionPrerequisites::CanAccept(specifiedMissionId, missionComponent->GetMissions())) { GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), specifiedMissionId, m_ParentEntity->GetObjectID()); - return; } } std::vector canAcceptPool; - - for (const auto sample : randomMissionPool) { + for (const auto& sample : randomMissions) { const auto state = missionComponent->GetMissionState(sample); if (state == eMissionState::ACTIVE || @@ -180,9 +126,7 @@ void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifi sample == specifiedMissionId) { mission = missionComponent->GetMission(sample); - if (mission == nullptr || mission->IsAchievement()) { - continue; - } + if (!mission || mission->IsAchievement()) continue; GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), sample, m_ParentEntity->GetObjectID()); @@ -191,16 +135,16 @@ void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifi break; } - if (std::find(offered.begin(), offered.end(), sample) == offered.end() && MissionPrerequisites::CanAccept(sample, missionComponent->GetMissions())) { + if (std::find(offered.begin(), offered.end(), sample) == offered.end() && + MissionPrerequisites::CanAccept(sample, missionComponent->GetMissions())) { canAcceptPool.push_back(sample); } } // If the mission is already active or we already completed one of them today - if (canAcceptPool.empty()) - continue; + if (canAcceptPool.empty()) continue; - const auto selected = canAcceptPool[GeneralUtils::GenerateRandomNumber(0, canAcceptPool.size() - 1)]; + const auto selected = canAcceptPool[GeneralUtils::GenerateRandomNumber(0, canAcceptPool.size() - 1)]; GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), selected, m_ParentEntity->GetObjectID()); } else if (std::find(offered.begin(), offered.end(), missionId) == offered.end() && offeredMission->GetOfferMission()) { diff --git a/dGame/dComponents/MissionOfferComponent.h b/dGame/dComponents/MissionOfferComponent.h index ad5f83bc..78da8fd9 100644 --- a/dGame/dComponents/MissionOfferComponent.h +++ b/dGame/dComponents/MissionOfferComponent.h @@ -1,15 +1,18 @@ /* * Darkflame Universe - * Copyright 2019 + * Copyright 2023 */ -#ifndef MISSIONOFFERCOMPONENT_H -#define MISSIONOFFERCOMPONENT_H +#ifndef __MISSIONOFFERCOMPONENT_H__ +#define __MISSIONOFFERCOMPONENT_H__ +#pragma once + +#include +#include +#include #include "dCommonVars.h" #include "Component.h" -#include -#include #include "eReplicaComponentType.h" class Entity; @@ -18,25 +21,29 @@ class Entity; * Light wrapper around missions that may be offered by an entity */ struct OfferedMission { - OfferedMission(uint32_t missionId, bool offersMission, bool acceptsMission); + OfferedMission(const uint32_t missionId, const bool offersMission, const bool acceptsMission) { + this->missionId = missionId; + this->offersMission = offersMission; + this->acceptsMission = acceptsMission; + }; /** * Returns the ID of the mission * @return the ID of the mission */ - uint32_t GetMissionId() const; + uint32_t GetMissionId() const { return missionId; }; /** * Returns if this mission is offered by the entity * @return true if this mission is offered by the entity, false otherwise */ - bool GetOfferMission() const; + bool GetOfferMission() const { return offersMission; }; /** * Returns if this mission may be accepted by the entity (currently unused) * @return true if this mission may be accepted by the entity, false otherwise */ - bool GetAcceptMission() const; + bool GetAcceptMission() const { return acceptsMission; }; private: @@ -63,8 +70,9 @@ class MissionOfferComponent : public Component { public: inline static const eReplicaComponentType ComponentType = eReplicaComponentType::MISSION_OFFER; - MissionOfferComponent(Entity* parent, LOT parentLot); - ~MissionOfferComponent() override; + MissionOfferComponent(Entity* parent, const int32_t componentId = -1); + + void LoadTemplateData() override; /** * Handles the OnUse event triggered by some entity, determines which missions to show based on what they may @@ -85,7 +93,9 @@ private: /** * The missions this entity has to offer */ - std::vector offeredMissions; + std::vector> offeredMissions; + + int32_t m_ComponentId; }; -#endif // MISSIONOFFERCOMPONENT_H +#endif // __MISSIONOFFERCOMPONENT_H__ diff --git a/dGame/dEntity/Entity.cpp b/dGame/dEntity/Entity.cpp index c6553f72..6b977135 100644 --- a/dGame/dEntity/Entity.cpp +++ b/dGame/dEntity/Entity.cpp @@ -517,7 +517,7 @@ void Entity::Initialize() { m_IsGhostingCandidate = false; break; case eReplicaComponentType::MISSION_OFFER: - AddComponent(GetLOT()); + AddComponent(componentId); break; case eReplicaComponentType::RACING_STATS: AddComponent();