mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-11-25 06:57:28 +00:00
94b9731a2b
Tested that the cooking mission with johnny umami now no longer allows you to lose progress by deleting items.
467 lines
10 KiB
C++
467 lines
10 KiB
C++
#include <sstream>
|
|
|
|
#include "MissionTask.h"
|
|
|
|
#include "Game.h"
|
|
#include "Logger.h"
|
|
#include "Mission.h"
|
|
#include "Character.h"
|
|
#include "dServer.h"
|
|
#include "EntityManager.h"
|
|
#include "ScriptedActivityComponent.h"
|
|
#include "GameMessages.h"
|
|
#include "dZoneManager.h"
|
|
#include "InventoryComponent.h"
|
|
#include "MissionComponent.h"
|
|
#include "eMissionTaskType.h"
|
|
#include "eReplicaComponentType.h"
|
|
|
|
MissionTask::MissionTask(Mission* mission, CDMissionTasks* info, uint32_t mask) {
|
|
this->info = info;
|
|
this->mission = mission;
|
|
this->mask = mask;
|
|
|
|
progress = 0;
|
|
|
|
std::istringstream stream(info->taskParam1);
|
|
std::string token;
|
|
|
|
while (std::getline(stream, token, ',')) {
|
|
const auto parameter = GeneralUtils::TryParse<uint32_t>(token);
|
|
if (parameter) parameters.push_back(parameter.value());
|
|
}
|
|
|
|
stream = std::istringstream(info->targetGroup);
|
|
|
|
while (std::getline(stream, token, ',')) {
|
|
const auto parameter = GeneralUtils::TryParse<uint32_t>(token);
|
|
if (parameter) targets.push_back(parameter.value());
|
|
}
|
|
}
|
|
|
|
|
|
eMissionTaskType MissionTask::GetType() const {
|
|
return static_cast<eMissionTaskType>(info->taskType);
|
|
}
|
|
|
|
|
|
uint32_t MissionTask::GetProgress() const {
|
|
return progress;
|
|
}
|
|
|
|
|
|
void MissionTask::SetProgress(const uint32_t value, const bool echo) {
|
|
if (progress == value) {
|
|
return;
|
|
}
|
|
|
|
progress = value;
|
|
|
|
if (!echo) {
|
|
return;
|
|
}
|
|
|
|
auto* entity = mission->GetAssociate();
|
|
|
|
if (entity == nullptr) {
|
|
return;
|
|
}
|
|
|
|
std::vector<float> updates;
|
|
updates.push_back(static_cast<float>(progress));
|
|
GameMessages::SendNotifyMissionTask(entity, entity->GetSystemAddress(), static_cast<int>(info->id), static_cast<int>(1 << (mask + 1)), updates);
|
|
}
|
|
|
|
|
|
void MissionTask::SetUnique(const std::vector<uint32_t>& value) {
|
|
unique = value;
|
|
}
|
|
|
|
|
|
void MissionTask::AddProgress(int32_t value) {
|
|
value += progress;
|
|
|
|
if (value > info->targetValue) {
|
|
value = info->targetValue;
|
|
}
|
|
|
|
if (value < 0) {
|
|
value = 0;
|
|
}
|
|
|
|
SetProgress(value);
|
|
}
|
|
|
|
|
|
Mission* MissionTask::GetMission() const {
|
|
return mission;
|
|
}
|
|
|
|
|
|
uint32_t MissionTask::GetTarget() const {
|
|
return info->target;
|
|
}
|
|
|
|
|
|
const CDMissionTasks& MissionTask::GetClientInfo() const {
|
|
return *info;
|
|
}
|
|
|
|
|
|
uint32_t MissionTask::GetMask() const {
|
|
return mask;
|
|
}
|
|
|
|
|
|
const std::vector<uint32_t>& MissionTask::GetUnique() const {
|
|
return unique;
|
|
}
|
|
|
|
|
|
const std::vector<uint32_t>& MissionTask::GetTargets() const {
|
|
return targets;
|
|
}
|
|
|
|
|
|
const std::vector<uint32_t>& MissionTask::GetParameters() const {
|
|
return parameters;
|
|
}
|
|
|
|
|
|
std::vector<uint32_t> MissionTask::GetAllTargets() const {
|
|
auto targets = GetTargets();
|
|
|
|
targets.push_back(GetTarget());
|
|
|
|
return targets;
|
|
}
|
|
|
|
|
|
bool MissionTask::InTargets(const uint32_t value) const {
|
|
auto targets = GetTargets();
|
|
|
|
return std::find(targets.begin(), targets.end(), value) != targets.end();
|
|
}
|
|
|
|
|
|
bool MissionTask::InAllTargets(const uint32_t value) const {
|
|
auto targets = GetAllTargets();
|
|
|
|
return std::find(targets.begin(), targets.end(), value) != targets.end();
|
|
}
|
|
|
|
bool MissionTask::InParameters(const uint32_t value) const {
|
|
auto parameters = GetParameters();
|
|
|
|
return std::find(parameters.begin(), parameters.end(), value) != parameters.end();
|
|
}
|
|
|
|
|
|
bool MissionTask::IsComplete() const {
|
|
// Mission 668 has task uid 984 which is a bit mask. Its completion value is 3.
|
|
if (info->uid == 984) {
|
|
return progress >= 3;
|
|
} else {
|
|
return progress >= info->targetValue;
|
|
}
|
|
}
|
|
|
|
|
|
void MissionTask::Complete() {
|
|
SetProgress(info->targetValue);
|
|
}
|
|
|
|
|
|
void MissionTask::CheckCompletion() const {
|
|
if (IsComplete()) {
|
|
mission->CheckCompletion();
|
|
}
|
|
}
|
|
|
|
|
|
void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& targets, int32_t count) {
|
|
if (IsComplete() && count > 0) return;
|
|
|
|
const auto type = GetType();
|
|
|
|
if (count < 0) {
|
|
if (mission->IsMission() && type == eMissionTaskType::GATHER && InAllTargets(value)) {
|
|
if (parameters.size() > 0 && (parameters[0] & 4) != 0) {
|
|
return;
|
|
}
|
|
|
|
auto* inventoryComponent = mission->GetAssociate()->GetComponent<InventoryComponent>();
|
|
|
|
if (inventoryComponent != nullptr) {
|
|
int32_t itemCount = inventoryComponent->GetLotCountNonTransfer(value);
|
|
|
|
if (itemCount < info->targetValue) {
|
|
SetProgress(itemCount);
|
|
|
|
if (mission->IsReadyToComplete()) {
|
|
mission->MakeActive();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
Entity* entity;
|
|
ScriptedActivityComponent* activity;
|
|
uint32_t activityId;
|
|
uint32_t lot;
|
|
uint32_t collectionId;
|
|
std::vector<LDFBaseData*> settings;
|
|
|
|
switch (type) {
|
|
case eMissionTaskType::UNKNOWN:
|
|
break;
|
|
|
|
case eMissionTaskType::ACTIVITY:
|
|
{
|
|
if (InAllTargets(value)) {
|
|
AddProgress(count);
|
|
break;
|
|
}
|
|
|
|
entity = Game::entityManager->GetEntity(associate);
|
|
if (entity == nullptr) {
|
|
if (associate != LWOOBJID_EMPTY) {
|
|
LOG("Failed to find associated entity (%llu)!", associate);
|
|
}
|
|
break;
|
|
}
|
|
|
|
activity = static_cast<ScriptedActivityComponent*>(entity->GetComponent(eReplicaComponentType::QUICK_BUILD));
|
|
if (activity == nullptr) {
|
|
break;
|
|
}
|
|
|
|
activityId = activity->GetActivityID();
|
|
|
|
const auto activityIdOverride = entity->GetVar<int32_t>(u"activityID");
|
|
|
|
if (activityIdOverride != 0) {
|
|
activityId = activityIdOverride;
|
|
}
|
|
|
|
if (!InAllTargets(activityId)) break;
|
|
|
|
AddProgress(count);
|
|
|
|
break;
|
|
}
|
|
|
|
case eMissionTaskType::USE_ITEM:
|
|
case eMissionTaskType::TALK_TO_NPC:
|
|
{
|
|
if (GetTarget() != value) break;
|
|
|
|
AddProgress(count);
|
|
|
|
break;
|
|
}
|
|
|
|
case eMissionTaskType::EMOTE:
|
|
{
|
|
if (!InParameters(value)) break;
|
|
|
|
entity = Game::entityManager->GetEntity(associate);
|
|
|
|
if (entity == nullptr) {
|
|
LOG("Failed to find associated entity (%llu)!", associate);
|
|
|
|
break;
|
|
}
|
|
|
|
lot = static_cast<uint32_t>(entity->GetLOT());
|
|
|
|
if (GetTarget() != lot) break;
|
|
|
|
AddProgress(count);
|
|
|
|
break;
|
|
}
|
|
|
|
case eMissionTaskType::USE_SKILL:
|
|
{
|
|
// This is a complicated check because for some missions we need to check for the associate being in the parameters instead of the value being in the parameters.
|
|
if (associate == LWOOBJID_EMPTY && GetAllTargets().size() == 1 && GetAllTargets()[0] == -1) {
|
|
if (InParameters(value)) AddProgress(count);
|
|
} else {
|
|
if (InParameters(associate) && InAllTargets(value)) AddProgress(count);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case eMissionTaskType::PERFORM_ACTIVITY:
|
|
{
|
|
auto* minigameManager = Game::entityManager->GetEntity(associate);
|
|
if (minigameManager == nullptr)
|
|
break;
|
|
|
|
int32_t gameID = minigameManager->GetLOT();
|
|
|
|
auto* sac = minigameManager->GetComponent<ScriptedActivityComponent>();
|
|
if (sac != nullptr) {
|
|
gameID = sac->GetActivityID();
|
|
}
|
|
|
|
if (info->target != gameID) {
|
|
break;
|
|
}
|
|
// This special case is for shooting gallery missions that want their
|
|
// progress value set to 1 instead of being set to the target value.
|
|
if (info->targetGroup == targets && value >= info->targetValue && GetMission()->IsMission() && info->target == 1864 && info->targetGroup == "performact_score") {
|
|
SetProgress(1);
|
|
break;
|
|
}
|
|
if (info->targetGroup == targets && value >= info->targetValue) {
|
|
SetProgress(info->targetValue);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case eMissionTaskType::VISIT_PROPERTY:
|
|
{
|
|
if (!InAllTargets(value)) break;
|
|
|
|
if (std::find(unique.begin(), unique.end(), static_cast<uint32_t>(associate)) != unique.end()) break;
|
|
|
|
AddProgress(count);
|
|
|
|
unique.push_back(associate);
|
|
|
|
break;
|
|
}
|
|
|
|
case eMissionTaskType::COLLECTION:
|
|
{
|
|
if (!InAllTargets(value)) break;
|
|
|
|
entity = Game::entityManager->GetEntity(associate);
|
|
|
|
if (entity == nullptr) {
|
|
LOG("Failed to find associated entity (%llu)!", associate);
|
|
|
|
break;
|
|
}
|
|
|
|
collectionId = entity->GetCollectibleID();
|
|
|
|
collectionId = static_cast<uint32_t>(collectionId) + static_cast<uint32_t>(Game::server->GetZoneID() << 8);
|
|
|
|
if (std::find(unique.begin(), unique.end(), collectionId) != unique.end()) break;
|
|
|
|
unique.push_back(collectionId);
|
|
|
|
SetProgress(unique.size());
|
|
|
|
auto* entity = mission->GetAssociate();
|
|
|
|
if (entity == nullptr) break;
|
|
|
|
auto* missionComponent = entity->GetComponent<MissionComponent>();
|
|
|
|
if (missionComponent == nullptr) break;
|
|
|
|
missionComponent->AddCollectible(collectionId);
|
|
|
|
break;
|
|
}
|
|
|
|
case eMissionTaskType::EXPLORE:
|
|
{
|
|
if (info->targetGroup != targets) break;
|
|
|
|
AddProgress(count);
|
|
|
|
break;
|
|
}
|
|
|
|
case eMissionTaskType::RACING:
|
|
{
|
|
// The meaning of associate can be found in eRacingTaskParam.h
|
|
if (parameters.empty()) break;
|
|
|
|
if (!InAllTargets(Game::zoneManager->GetZone()->GetWorldID()) && !(parameters[0] == 4 || parameters[0] == 5) && !InAllTargets(value)) break;
|
|
|
|
if (parameters[0] != associate) break;
|
|
|
|
if (associate == 1 || associate == 2 || associate == 3) {
|
|
if (value > info->targetValue) break;
|
|
|
|
AddProgress(info->targetValue);
|
|
}
|
|
// task 15 is a bit mask!
|
|
else if (associate == 15) {
|
|
if (!InAllTargets(value)) break;
|
|
|
|
auto tempProgress = GetProgress();
|
|
// If we won at Nimbus Station, set bit 0
|
|
if (value == 1203) SetProgress(tempProgress |= 1 << 0);
|
|
// If we won at Gnarled Forest, set bit 1
|
|
else if (value == 1303) SetProgress(tempProgress |= 1 << 1);
|
|
// If both bits are set, then the client sees the mission as complete.
|
|
} else if (associate == 10) {
|
|
// If the player did not crash during the race, progress this task by count.
|
|
if (value != 0) break;
|
|
|
|
AddProgress(count);
|
|
} else if (associate == 4 || associate == 5 || associate == 14) {
|
|
if (!InAllTargets(value)) break;
|
|
AddProgress(count);
|
|
} else if (associate == 17) {
|
|
if (!InAllTargets(value)) break;
|
|
AddProgress(count);
|
|
} else {
|
|
AddProgress(count);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case eMissionTaskType::PET_TAMING:
|
|
case eMissionTaskType::SCRIPT:
|
|
case eMissionTaskType::INTERACT:
|
|
case eMissionTaskType::META:
|
|
case eMissionTaskType::POWERUP:
|
|
case eMissionTaskType::SMASH:
|
|
case eMissionTaskType::GATHER:
|
|
case eMissionTaskType::PLAYER_FLAG:
|
|
case eMissionTaskType::EARN_REPUTATION:
|
|
{
|
|
if (!InAllTargets(value)) break;
|
|
|
|
AddProgress(count);
|
|
|
|
break;
|
|
}
|
|
case eMissionTaskType::PLACE_MODEL:
|
|
{
|
|
AddProgress(count);
|
|
break;
|
|
}
|
|
case eMissionTaskType::DONATION:
|
|
AddProgress(count);
|
|
break;
|
|
default:
|
|
LOG("Invalid mission task type (%i)!", static_cast<int>(type));
|
|
return;
|
|
}
|
|
|
|
CheckCompletion();
|
|
}
|
|
|
|
|
|
MissionTask::~MissionTask() {
|
|
targets.clear();
|
|
|
|
parameters.clear();
|
|
|
|
unique.clear();
|
|
}
|