mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-11-24 22:47:25 +00:00
c1e8546d48
add final missing scripts for nt also fix the turnin for the breadcrumb missions not showing the completion window. Fix another missing script Add another script fix include guards Fix dirt clouds not appearing on mission accept
214 lines
6.5 KiB
C++
214 lines
6.5 KiB
C++
/*
|
|
* Darkflame Universe
|
|
* Copyright 2019
|
|
*/
|
|
|
|
#include <sstream>
|
|
#include "MissionOfferComponent.h"
|
|
#include "CDClientManager.h"
|
|
#include "CDMissionsTable.h"
|
|
#include "CDMissionNPCComponentTable.h"
|
|
#include "GameMessages.h"
|
|
#include "Entity.h"
|
|
#include "MissionComponent.h"
|
|
#include "Logger.h"
|
|
#include "Game.h"
|
|
#include "MissionPrerequisites.h"
|
|
#include "eMissionState.h"
|
|
|
|
#include "CDComponentsRegistryTable.h"
|
|
|
|
OfferedMission::OfferedMission(const uint32_t missionId, const bool offersMission, const bool acceptsMission) {
|
|
this->missionId = missionId;
|
|
this->offersMission = offersMission;
|
|
this->acceptsMission = acceptsMission;
|
|
}
|
|
|
|
|
|
uint32_t OfferedMission::GetMissionId() const {
|
|
return this->missionId;
|
|
}
|
|
|
|
bool OfferedMission::GetOffersMission() const {
|
|
return this->offersMission;
|
|
}
|
|
|
|
bool OfferedMission::GetAcceptsMission() 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) {
|
|
OfferMissions(originator);
|
|
}
|
|
|
|
void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifiedMissionId) {
|
|
// First, get the entity's MissionComponent. If there is not one, then we cannot offer missions to this entity.
|
|
auto* missionComponent = static_cast<MissionComponent*>(entity->GetComponent(eReplicaComponentType::MISSION));
|
|
|
|
if (!missionComponent) {
|
|
LOG("Unable to get mission component for Entity %llu", entity->GetObjectID());
|
|
return;
|
|
}
|
|
|
|
std::vector<uint32_t> offered{};
|
|
|
|
CDMissions info{};
|
|
|
|
if (specifiedMissionId > 0 && !Mission::IsValidMission(specifiedMissionId, info)) {
|
|
return;
|
|
}
|
|
|
|
for (auto* offeredMission : this->offeredMissions) {
|
|
if (specifiedMissionId > 0) {
|
|
if (offeredMission->GetMissionId() != specifiedMissionId && !info.isRandom) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// First, check if we already have the mission
|
|
const auto missionId = offeredMission->GetMissionId();
|
|
|
|
auto* mission = missionComponent->GetMission(missionId);
|
|
|
|
if (mission != nullptr) {
|
|
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_Parent->GetLOT() && mission->GetClientInfo().target_objectID != m_Parent->GetLOT() && mission->IsFetchMission()) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// We have the mission, if it is not complete, offer it
|
|
if (mission->IsActive() || mission->IsReadyToComplete()) {
|
|
GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), missionId, m_Parent->GetObjectID());
|
|
|
|
offered.push_back(missionId);
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
const auto canAccept = MissionPrerequisites::CanAccept(missionId, missionComponent->GetMissions());
|
|
|
|
// Mission has not yet been accepted - check the prereqs
|
|
if (!canAccept)
|
|
continue;
|
|
|
|
if (!Mission::IsValidMission(missionId, info)) {
|
|
continue;
|
|
}
|
|
|
|
const auto& randomPool = info.randomPool;
|
|
const auto isRandom = info.isRandom;
|
|
|
|
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<uint32_t> randomMissionPool;
|
|
|
|
while (std::getline(stream, token, ',')) {
|
|
try {
|
|
const auto value = std::stoul(token);
|
|
|
|
randomMissionPool.push_back(value);
|
|
} catch (std::invalid_argument& exception) {
|
|
LOG("Failed to parse value (%s): (%s)!", token.c_str(), exception.what());
|
|
}
|
|
}
|
|
|
|
if (specifiedMissionId > 0) {
|
|
const auto& iter = std::find(randomMissionPool.begin(), randomMissionPool.end(), specifiedMissionId);
|
|
|
|
if (iter != randomMissionPool.end() && MissionPrerequisites::CanAccept(specifiedMissionId, missionComponent->GetMissions())) {
|
|
GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), specifiedMissionId, m_Parent->GetObjectID());
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
std::vector<uint32_t> canAcceptPool;
|
|
|
|
for (const auto sample : randomMissionPool) {
|
|
const auto state = missionComponent->GetMissionState(sample);
|
|
|
|
if (state == eMissionState::ACTIVE ||
|
|
state == eMissionState::COMPLETE_ACTIVE ||
|
|
state == eMissionState::READY_TO_COMPLETE ||
|
|
state == eMissionState::COMPLETE_READY_TO_COMPLETE ||
|
|
sample == specifiedMissionId) {
|
|
mission = missionComponent->GetMission(sample);
|
|
|
|
if (mission == nullptr || mission->IsAchievement()) {
|
|
continue;
|
|
}
|
|
|
|
GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), sample, m_Parent->GetObjectID());
|
|
|
|
canAcceptPool.clear();
|
|
|
|
break;
|
|
}
|
|
|
|
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;
|
|
|
|
const auto selected = canAcceptPool[GeneralUtils::GenerateRandomNumber<int>(0, canAcceptPool.size() - 1)];
|
|
|
|
GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), selected, m_Parent->GetObjectID());
|
|
} else if (
|
|
std::find(offered.begin(), offered.end(), missionId) == offered.end()
|
|
&&
|
|
(offeredMission->GetOffersMission() || offeredMission->GetAcceptsMission())) {
|
|
GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), missionId, m_Parent->GetObjectID());
|
|
}
|
|
}
|
|
}
|