#include "MissionPrerequisites.h" #include #include #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& 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->GetMissionState() == static_cast(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& 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& missions) { const auto& index = expressions.find(missionId); if (index != expressions.end()) { return index->second->Execute(missions); } auto* missionsTable = CDClientManager::Instance().GetTable(); const auto missionEntries = missionsTable->Query([=](const CDMissions& entry) { return entry.id == static_cast(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 MissionPrerequisites::expressions = {};