mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-12-23 22:13:35 +00:00
181 lines
3.8 KiB
C++
181 lines
3.8 KiB
C++
|
#include "MissionPrerequisites.h"
|
||
|
|
||
|
#include <sstream>
|
||
|
#include <ctime>
|
||
|
|
||
|
#include "CDClientManager.h"
|
||
|
#include "dLogger.h"
|
||
|
|
||
|
|
||
|
PrerequisiteExpression::PrerequisiteExpression(const std::string& str) {
|
||
|
std::stringstream a;
|
||
|
std::stringstream b;
|
||
|
std::stringstream s;
|
||
|
|
||
|
auto bor = false;
|
||
|
|
||
|
auto sub = false;
|
||
|
|
||
|
auto done = false;
|
||
|
|
||
|
for (auto i = 0u; i < str.size(); ++i) {
|
||
|
if (done) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
const auto character = str[i];
|
||
|
|
||
|
switch (character) {
|
||
|
case '|':
|
||
|
bor = true;
|
||
|
b << str.substr(i + 1);
|
||
|
done = true;
|
||
|
break;
|
||
|
case ' ':
|
||
|
case ')':
|
||
|
break;
|
||
|
case ',':
|
||
|
case '&':
|
||
|
case '(':
|
||
|
b << str.substr(i + 1);
|
||
|
done = true;
|
||
|
break;
|
||
|
case '0':
|
||
|
case '1':
|
||
|
case '2':
|
||
|
case '3':
|
||
|
case '4':
|
||
|
case '5':
|
||
|
case '6':
|
||
|
case '7':
|
||
|
case '8':
|
||
|
case '9':
|
||
|
if (sub) {
|
||
|
s << character;
|
||
|
} else {
|
||
|
a << character;
|
||
|
}
|
||
|
break;
|
||
|
case ':':
|
||
|
sub = true;
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this->m_or = bor;
|
||
|
|
||
|
const auto aString = a.str();
|
||
|
|
||
|
if (!aString.empty()) {
|
||
|
this->a = std::stoul(a.str());
|
||
|
} else {
|
||
|
this->a = 0;
|
||
|
}
|
||
|
|
||
|
const auto subString = s.str();
|
||
|
|
||
|
if (!subString.empty()) {
|
||
|
this->sub = std::stoul(s.str());
|
||
|
} else {
|
||
|
this->sub = 0;
|
||
|
}
|
||
|
|
||
|
const auto bString = b.str();
|
||
|
|
||
|
if (!bString.empty()) {
|
||
|
this->b = new PrerequisiteExpression(bString);
|
||
|
} else {
|
||
|
this->b = nullptr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
bool PrerequisiteExpression::Execute(const std::unordered_map<uint32_t, Mission*>& missions) const {
|
||
|
auto a = this->a == 0;
|
||
|
|
||
|
auto b = this->b == nullptr;
|
||
|
|
||
|
if (!a) {
|
||
|
const auto index = missions.find(this->a);
|
||
|
|
||
|
if (index != missions.end()) {
|
||
|
const auto* mission = index->second;
|
||
|
|
||
|
if (this->sub != 0) {
|
||
|
// Special case for one Wisp Lee repeatable mission.
|
||
|
a = mission->GetClientInfo().id == 1883 ?
|
||
|
mission->GetMissionState() == static_cast<MissionState>(this->sub) :
|
||
|
mission->GetMissionState() >= static_cast<MissionState>(this->sub);
|
||
|
} else if (mission->IsComplete()) {
|
||
|
a = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!b) {
|
||
|
b = this->b->Execute(missions);
|
||
|
}
|
||
|
|
||
|
if (this->m_or) {
|
||
|
return a || b;
|
||
|
}
|
||
|
|
||
|
return a && b;
|
||
|
}
|
||
|
|
||
|
|
||
|
PrerequisiteExpression::~PrerequisiteExpression() {
|
||
|
delete b;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool MissionPrerequisites::CanAccept(const uint32_t missionId, const std::unordered_map<uint32_t, Mission*>& missions) {
|
||
|
const auto& missionIndex = missions.find(missionId);
|
||
|
|
||
|
if (missionIndex != missions.end()) {
|
||
|
auto* mission = missionIndex->second;
|
||
|
const auto& info = mission->GetClientInfo();
|
||
|
|
||
|
if (info.repeatable) {
|
||
|
const auto prerequisitesMet = CheckPrerequisites(missionId, missions);
|
||
|
|
||
|
// Checked by client
|
||
|
const time_t time = std::time(nullptr);
|
||
|
const time_t lock = mission->GetTimestamp() + info.cooldownTime * 60;
|
||
|
|
||
|
// If there's no time limit, just check the prerequisites, otherwise make sure both conditions are met
|
||
|
return (info.cooldownTime == -1 ? prerequisitesMet : (lock - time < 0)) && prerequisitesMet;
|
||
|
}
|
||
|
|
||
|
// Mission is already accepted and cannot be repeatedly accepted
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Mission is not yet accepted, check the prerequisites
|
||
|
return CheckPrerequisites(missionId, missions);
|
||
|
}
|
||
|
|
||
|
bool MissionPrerequisites::CheckPrerequisites(uint32_t missionId, const std::unordered_map<uint32_t, Mission*>& missions) {
|
||
|
const auto& index = expressions.find(missionId);
|
||
|
if (index != expressions.end()) {
|
||
|
return index->second->Execute(missions);
|
||
|
}
|
||
|
|
||
|
auto* missionsTable = CDClientManager::Instance()->GetTable<CDMissionsTable>("Missions");
|
||
|
const auto missionEntries = missionsTable->Query([=](const CDMissions& entry) {
|
||
|
return entry.id == static_cast<int>(missionId);
|
||
|
});
|
||
|
|
||
|
if (missionEntries.empty())
|
||
|
return false;
|
||
|
|
||
|
auto* expression = new PrerequisiteExpression(missionEntries[0].prereqMissionID);
|
||
|
expressions.insert_or_assign(missionId, expression);
|
||
|
|
||
|
return expression->Execute(missions);
|
||
|
}
|
||
|
|
||
|
std::unordered_map<uint32_t, PrerequisiteExpression*> MissionPrerequisites::expressions = {};
|