MissionOfferComponent pass

This commit is contained in:
EmosewaMC 2023-07-05 20:30:52 -07:00
parent 950a1fe423
commit 001f6a75eb
3 changed files with 65 additions and 111 deletions

View File

@ -1,6 +1,6 @@
/* /*
* Darkflame Universe * Darkflame Universe
* Copyright 2019 * Copyright 2023
*/ */
#include <sstream> #include <sstream>
@ -18,61 +18,26 @@
#include "CDComponentsRegistryTable.h" #include "CDComponentsRegistryTable.h"
OfferedMission::OfferedMission(const uint32_t missionId, const bool offersMission, const bool acceptsMission) { MissionOfferComponent::MissionOfferComponent(Entity* parent, const int32_t componentId) : Component(parent) {
this->missionId = missionId; m_ComponentId = componentId;
this->offersMission = offersMission;
this->acceptsMission = acceptsMission;
} }
void MissionOfferComponent::LoadTemplateData() {
if (m_ComponentId == -1) return;
// Now lookup the missions in the MissionNPCComponent table
auto* missionNpcComponentTable = CDClientManager::Instance().GetTable<CDMissionNPCComponentTable>();
uint32_t OfferedMission::GetMissionId() const { auto missions = missionNpcComponentTable->Query([=](const CDMissionNPCComponent& entry) {
return this->missionId; return entry.id == static_cast<int32_t>(m_ComponentId);
} });
bool OfferedMission::GetOfferMission() const { for (const auto& mission : missions) {
return this->offersMission; this->offeredMissions.emplace_back(
} std::make_unique<OfferedMission>(mission.missionID, mission.offersMission, mission.acceptsMission)
);
bool OfferedMission::GetAcceptMission() const {
return this->acceptsMission;
}
//------------------------ MissionOfferComponent below ------------------------
MissionOfferComponent::MissionOfferComponent(Entity* parent, const LOT parentLot) : Component(parent) {
auto* compRegistryTable = CDClientManager::Instance().GetTable<CDComponentsRegistryTable>();
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<CDMissionNPCComponentTable>();
auto missions = missionNpcComponentTable->Query([=](const CDMissionNPCComponent& entry) {
return entry.id == static_cast<unsigned>(componentId);
});
for (auto& mission : missions) {
auto* offeredMission = new OfferedMission(mission.missionID, mission.offersMission, mission.acceptsMission);
this->offeredMissions.push_back(offeredMission);
}
} }
} }
MissionOfferComponent::~MissionOfferComponent() {
for (auto* mission : this->offeredMissions) {
if (mission) {
delete mission;
mission = nullptr;
}
}
offeredMissions.clear();
}
void MissionOfferComponent::OnUse(Entity* originator) { void MissionOfferComponent::OnUse(Entity* originator) {
OfferMissions(originator); OfferMissions(originator);
} }
@ -88,17 +53,15 @@ void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifi
std::vector<uint32_t> offered{}; std::vector<uint32_t> offered{};
CDMissions info{}; CDMissions missionInfo{};
if (specifiedMissionId > 0 && !Mission::IsValidMission(specifiedMissionId, info)) { if (specifiedMissionId > 0 && !Mission::IsValidMission(specifiedMissionId, missionInfo)) {
return; return;
} }
for (auto* offeredMission : this->offeredMissions) { for (const auto& offeredMission : offeredMissions) {
if (specifiedMissionId > 0) { if (specifiedMissionId > 0 && (offeredMission->GetMissionId() != specifiedMissionId && !missionInfo.isRandom)) {
if (offeredMission->GetMissionId() != specifiedMissionId && !info.isRandom) { continue;
continue;
}
} }
// First, check if we already have the mission // 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); auto* mission = missionComponent->GetMission(missionId);
if (mission != nullptr) { if (mission) {
if (specifiedMissionId <= 0) { if (specifiedMissionId <= 0) {
// Handles the odd case where the offer object should not display the mission again // 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; continue;
} }
} }
@ -127,50 +93,30 @@ void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifi
const auto canAccept = MissionPrerequisites::CanAccept(missionId, missionComponent->GetMissions()); const auto canAccept = MissionPrerequisites::CanAccept(missionId, missionComponent->GetMissions());
// Mission has not yet been accepted - check the prereqs // Mission has not yet been accepted - check the prereqs
if (!canAccept) if (!canAccept || !Mission::IsValidMission(missionId, missionInfo)) continue;
continue;
if (!Mission::IsValidMission(missionId, info)) { // This means the mission is part of a random pool of missions.
continue; if (missionInfo.isRandom && missionInfo.randomPool.empty()) continue;
}
const auto& randomPool = info.randomPool; if (missionInfo.isRandom && !missionInfo.randomPool.empty()) {
const auto isRandom = info.isRandom; auto randomMissionPoolStr = GeneralUtils::SplitString(missionInfo.randomPool, ',');
if (isRandom && randomPool.empty()) // This means the mission is part of a random pool of missions. std::vector<uint32_t> randomMissions;
{ for (const auto& randomMissionStr : randomMissionPoolStr) {
continue; uint32_t randomMission;
} if (GeneralUtils::TryParse(randomMissionStr, randomMission)) randomMissions.push_back(randomMission);
if (isRandom && !randomPool.empty()) {
std::istringstream stream(randomPool);
std::string token;
std::vector<uint32_t> 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());
}
} }
if (specifiedMissionId > 0) { if (specifiedMissionId > 0) {
const auto& iter = std::find(randomMissionPool.begin(), randomMissionPool.end(), specifiedMissionId); if (std::find(randomMissions.begin(), randomMissions.end(), specifiedMissionId) != randomMissions.end() &&
MissionPrerequisites::CanAccept(specifiedMissionId, missionComponent->GetMissions())) {
if (iter != randomMissionPool.end() && MissionPrerequisites::CanAccept(specifiedMissionId, missionComponent->GetMissions())) {
GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), specifiedMissionId, m_ParentEntity->GetObjectID()); GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), specifiedMissionId, m_ParentEntity->GetObjectID());
return; return;
} }
} }
std::vector<uint32_t> canAcceptPool; std::vector<uint32_t> canAcceptPool;
for (const auto& sample : randomMissions) {
for (const auto sample : randomMissionPool) {
const auto state = missionComponent->GetMissionState(sample); const auto state = missionComponent->GetMissionState(sample);
if (state == eMissionState::ACTIVE || if (state == eMissionState::ACTIVE ||
@ -180,9 +126,7 @@ void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifi
sample == specifiedMissionId) { sample == specifiedMissionId) {
mission = missionComponent->GetMission(sample); mission = missionComponent->GetMission(sample);
if (mission == nullptr || mission->IsAchievement()) { if (!mission || mission->IsAchievement()) continue;
continue;
}
GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), sample, m_ParentEntity->GetObjectID()); GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), sample, m_ParentEntity->GetObjectID());
@ -191,16 +135,16 @@ void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifi
break; 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); canAcceptPool.push_back(sample);
} }
} }
// If the mission is already active or we already completed one of them today // If the mission is already active or we already completed one of them today
if (canAcceptPool.empty()) if (canAcceptPool.empty()) continue;
continue;
const auto selected = canAcceptPool[GeneralUtils::GenerateRandomNumber<int>(0, canAcceptPool.size() - 1)]; const auto selected = canAcceptPool[GeneralUtils::GenerateRandomNumber<int32_t>(0, canAcceptPool.size() - 1)];
GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), selected, m_ParentEntity->GetObjectID()); GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), selected, m_ParentEntity->GetObjectID());
} else if (std::find(offered.begin(), offered.end(), missionId) == offered.end() && offeredMission->GetOfferMission()) { } else if (std::find(offered.begin(), offered.end(), missionId) == offered.end() && offeredMission->GetOfferMission()) {

View File

@ -1,15 +1,18 @@
/* /*
* Darkflame Universe * Darkflame Universe
* Copyright 2019 * Copyright 2023
*/ */
#ifndef MISSIONOFFERCOMPONENT_H #ifndef __MISSIONOFFERCOMPONENT_H__
#define MISSIONOFFERCOMPONENT_H #define __MISSIONOFFERCOMPONENT_H__
#pragma once
#include <memory>
#include <vector>
#include <stdint.h>
#include "dCommonVars.h" #include "dCommonVars.h"
#include "Component.h" #include "Component.h"
#include <vector>
#include <stdint.h>
#include "eReplicaComponentType.h" #include "eReplicaComponentType.h"
class Entity; class Entity;
@ -18,25 +21,29 @@ class Entity;
* Light wrapper around missions that may be offered by an entity * Light wrapper around missions that may be offered by an entity
*/ */
struct OfferedMission { 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 * Returns the ID of the mission
* @return 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 * Returns if this mission is offered by the entity
* @return true if this mission is offered by the entity, false otherwise * @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) * 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 * @return true if this mission may be accepted by the entity, false otherwise
*/ */
bool GetAcceptMission() const; bool GetAcceptMission() const { return acceptsMission; };
private: private:
@ -63,8 +70,9 @@ class MissionOfferComponent : public Component {
public: public:
inline static const eReplicaComponentType ComponentType = eReplicaComponentType::MISSION_OFFER; inline static const eReplicaComponentType ComponentType = eReplicaComponentType::MISSION_OFFER;
MissionOfferComponent(Entity* parent, LOT parentLot); MissionOfferComponent(Entity* parent, const int32_t componentId = -1);
~MissionOfferComponent() override;
void LoadTemplateData() override;
/** /**
* Handles the OnUse event triggered by some entity, determines which missions to show based on what they may * 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 * The missions this entity has to offer
*/ */
std::vector<OfferedMission*> offeredMissions; std::vector<std::unique_ptr<OfferedMission>> offeredMissions;
int32_t m_ComponentId;
}; };
#endif // MISSIONOFFERCOMPONENT_H #endif // __MISSIONOFFERCOMPONENT_H__

View File

@ -517,7 +517,7 @@ void Entity::Initialize() {
m_IsGhostingCandidate = false; m_IsGhostingCandidate = false;
break; break;
case eReplicaComponentType::MISSION_OFFER: case eReplicaComponentType::MISSION_OFFER:
AddComponent<MissionOfferComponent>(GetLOT()); AddComponent<MissionOfferComponent>(componentId);
break; break;
case eReplicaComponentType::RACING_STATS: case eReplicaComponentType::RACING_STATS:
AddComponent<RacingStatsComponent>(); AddComponent<RacingStatsComponent>();