mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-08-06 10:44:08 +00:00
Public release of the DLU server code!
Have fun!
This commit is contained in:
185
dGame/dMission/MissionPrerequisites.cpp
Normal file
185
dGame/dMission/MissionPrerequisites.cpp
Normal file
@@ -0,0 +1,185 @@
|
||||
#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 = {};
|
Reference in New Issue
Block a user