mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-11-14 07:47:13 +00:00
fix(mission): GetMissionState answers the client's state bit mask
LWOMissionComponent::getMissionState (0x00cd7400) returns a mask: COMPLETE once the mission was completed, ORed with the state of the mission in progress; a mission not in progress gets AVAILABLE when it was never completed or is repeatable and its prerequisites are met, else 0. DLU's handler answered UNKNOWN (-1, every bit set) for a mission that cannot be taken and COMPLETE for a completed repeatable one, and ignored cooldownInfoRequested. With cooldown info requested (0x00cd7770) the client only checks the cooldown of a repeat in progress (state 9 or 10): fewer whole minutes since the last completion than Missions.cooldownTime. MissionComponent::GetMissionState, used across the server, is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,8 @@
|
||||
* Copyright 2019
|
||||
*/
|
||||
|
||||
#include <ctime>
|
||||
#include <limits>
|
||||
#include <ranges>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
@@ -73,6 +75,38 @@ eMissionState MissionComponent::GetMissionState(const uint32_t missionId) const
|
||||
}
|
||||
|
||||
|
||||
int32_t MissionComponent::GetClientMissionState(const uint32_t missionId) const {
|
||||
// A mission ID below 1 is no mission
|
||||
if (missionId == 0 || missionId > static_cast<uint32_t>(std::numeric_limits<int32_t>::max())) return 0;
|
||||
|
||||
const auto* const mission = GetMission(missionId);
|
||||
const bool done = mission && (mission->GetCompletions() > 0 || mission->IsComplete());
|
||||
int32_t state = done ? static_cast<int32_t>(eMissionState::COMPLETE) : 0;
|
||||
|
||||
// In progress: its own state
|
||||
if (mission && !mission->IsComplete()) return state | static_cast<int32_t>(mission->GetMissionState());
|
||||
|
||||
CDMissions info{};
|
||||
if (!Mission::IsValidMission(missionId, info)) return 0;
|
||||
|
||||
if ((!done || info.repeatable) && MissionPrerequisites::CheckPrerequisites(missionId, m_Missions)) {
|
||||
state |= static_cast<int32_t>(eMissionState::AVAILABLE);
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
bool MissionComponent::IsCooldownRunning(const int64_t completedAt, const int64_t cooldownMinutes, const int64_t now) {
|
||||
return cooldownMinutes > 0 && (now - completedAt) / 60 < cooldownMinutes;
|
||||
}
|
||||
|
||||
bool MissionComponent::IsCooldownRunning(const uint32_t missionId) const {
|
||||
const auto* const mission = GetMission(missionId);
|
||||
if (!mission || (mission->GetCompletions() == 0 && !mission->IsComplete())) return false;
|
||||
|
||||
return IsCooldownRunning(mission->GetTimestamp(), mission->GetClientInfo().cooldownTime, std::time(nullptr));
|
||||
}
|
||||
|
||||
const std::unordered_map<uint32_t, Mission*>& MissionComponent::GetMissions() const {
|
||||
return m_Missions;
|
||||
}
|
||||
@@ -720,8 +754,19 @@ bool MissionComponent::OnGetObjectReportInfo(GameMessages::GetObjectReportInfo&
|
||||
return true;
|
||||
}
|
||||
|
||||
// LWOMissionComponent::msgGetMissionState (0x00d176e0): the client's mission state bit mask; with cooldown info
|
||||
// requested (0x00cd7770), the cooldown is only checked for a repeat in progress (state 9 or 10) and otherwise finished
|
||||
bool MissionComponent::OnGetMissionState(GameMessages::GetMissionState& getMissionState) {
|
||||
getMissionState.missionState = GetMissionState(getMissionState.missionID);
|
||||
const auto missionID = static_cast<uint32_t>(getMissionState.missionID);
|
||||
const auto state = getMissionState.missionID < 1 ? 0 : GetClientMissionState(missionID);
|
||||
getMissionState.missionState = static_cast<eMissionState>(state);
|
||||
|
||||
if (getMissionState.cooldownInfoRequested) {
|
||||
const auto* const mission = GetMission(missionID);
|
||||
const bool inProgress = mission && !mission->IsComplete();
|
||||
const bool repeat = state == static_cast<int32_t>(eMissionState::COMPLETE_AVAILABLE) || state == static_cast<int32_t>(eMissionState::COMPLETE_ACTIVE);
|
||||
getMissionState.cooldownFinished = !(inProgress && repeat && IsCooldownRunning(missionID));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -56,6 +56,22 @@ public:
|
||||
*/
|
||||
eMissionState GetMissionState(uint32_t missionId) const;
|
||||
|
||||
/**
|
||||
* The mission state as the client works it out (LWOMissionComponent::getMissionState 0x00cd7400): a bit mask,
|
||||
* COMPLETE (8) once the mission was ever completed, ORed with the state of the mission in progress; a mission not in
|
||||
* progress gets AVAILABLE (1) when it was never completed or is repeatable and its prerequisites are met. 0 for an
|
||||
* unknown mission.
|
||||
*/
|
||||
int32_t GetClientMissionState(uint32_t missionId) const;
|
||||
|
||||
/**
|
||||
* Whether the cooldown (Missions.cooldownTime, minutes) of a completed mission is still running, as the client
|
||||
* checks it: only for a mission completed before, a cooldown above 0, and while fewer whole minutes than the
|
||||
* cooldown have passed since the last completion.
|
||||
*/
|
||||
bool IsCooldownRunning(uint32_t missionId) const;
|
||||
static bool IsCooldownRunning(int64_t completedAt, int64_t cooldownMinutes, int64_t now);
|
||||
|
||||
/**
|
||||
* Checks if the entity has all the requirements for accepting the mission specified by the ID.
|
||||
* @param missionId the mission ID to check for if the character may accept it
|
||||
|
||||
@@ -41,6 +41,14 @@ public:
|
||||
* @return whether or not the mission identified by the specified ID can be accepted
|
||||
*/
|
||||
static bool CanAccept(uint32_t missionId, const std::unordered_map<uint32_t, Mission*>& missions);
|
||||
|
||||
/**
|
||||
* Checks the prerequisites for a mission
|
||||
* @param missionId the mission ID to check prerequisites for
|
||||
* @param missions the mission inventory to check the prerequisites against
|
||||
* @return whether or not the prerequisites of the mission identified by the specified ID are met
|
||||
*/
|
||||
static bool CheckPrerequisites(uint32_t missionId, const std::unordered_map<uint32_t, Mission*>& missions);
|
||||
private:
|
||||
|
||||
/**
|
||||
@@ -48,11 +56,4 @@ private:
|
||||
*/
|
||||
static std::unordered_map<uint32_t, PrerequisiteExpression*> expressions;
|
||||
|
||||
/**
|
||||
* Checks the prerequisites for a mission
|
||||
* @param missionId the mission ID to check prerequisites for
|
||||
* @param missions the mission inventory to check the prerequisites against
|
||||
* @return whether or not the mission identified by the specified ID can be accepted
|
||||
*/
|
||||
static bool CheckPrerequisites(uint32_t missionId, const std::unordered_map<uint32_t, Mission*>& missions);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user