DarkflameServer/dGame/dMission/MissionTask.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

468 lines
10 KiB
C++
Raw Normal View History

#include <sstream>
#include "MissionTask.h"
#include "Game.h"
#include "dLogger.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, ',')) {
uint32_t parameter;
if (GeneralUtils::TryParse(token, parameter)) {
parameters.push_back(parameter);
}
}
stream = std::istringstream(info->targetGroup);
while (std::getline(stream, token, ',')) {
uint32_t parameter;
if (GeneralUtils::TryParse(token, parameter)) {
targets.push_back(parameter);
}
}
}
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));
2022-02-21 04:01:55 +00:00
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() {
2022-02-10 00:42:17 +00:00
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] & 1) != 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) {
Game::logger->Log("MissionTask", "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) {
Game::logger->Log("MissionTask", "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;
}
2022-02-21 04:00:56 +00:00
// 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) {
2022-02-10 00:42:17 +00:00
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) {
Game::logger->Log("MissionTask", "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:
{
2022-02-06 22:28:27 +00:00
// 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) {
Implementing and Fixing All Racing Achievements (#366) * Grammatical changes in comments * Grammatical fixes in comments Small grammatical fixes found in comments throughout the code. * Added descriptions to functions Added descriptions to functions that didn't have them to keep the code well documented * Created RacingTaskParam.h Created RacingTaskParam so eliminate magic numbers in the original implementation of completing racing missions. * Updated magic numbers in Mission.cpp Updated magic numbers in Mission.cpp to a meaningful name. * Implemented racing smashable task progression Previously, races did not progress tasks for smashing Entities. Now all achievements tracking smashables track them correctly. This has been implemented in the three Entities that can be smashed in a race (imagination boxes, track specific smashables, Forbidden Valley dragon eggs). * Updated race imagination task progression Race imagination now no longer uses a magic number when passed to missionComponent. Instead we use a number defined in an enum located in RacingTaskParam.h * Updated Race task checks Racing tasks for completing races without smashing now no longer auto complete the whole chain of missions. Tasks that track placing on tracks and races overall now properly complete. Tasks that count how many missions in a zone are completed now function. Tasks that track race completions in multiple areas now function. * Updated RacingControlComponent.cpp Fixed any tasks that required 3 players to now require 3 or more players in a race to progress. This restriction is ignored if the world config opted in for solo racing to allow progression in solo worlds. Updated magic numbers sent into missionComponent->Progress to an enum created in this PR. Fixed some indentation. * Fixed a grammatical error in variable name Fixed a grammatical error in the enum for task params
2022-02-05 11:28:17 +00:00
// If the player did not crash during the race, progress this task by count.
if (value != 0) break;
Implementing and Fixing All Racing Achievements (#366) * Grammatical changes in comments * Grammatical fixes in comments Small grammatical fixes found in comments throughout the code. * Added descriptions to functions Added descriptions to functions that didn't have them to keep the code well documented * Created RacingTaskParam.h Created RacingTaskParam so eliminate magic numbers in the original implementation of completing racing missions. * Updated magic numbers in Mission.cpp Updated magic numbers in Mission.cpp to a meaningful name. * Implemented racing smashable task progression Previously, races did not progress tasks for smashing Entities. Now all achievements tracking smashables track them correctly. This has been implemented in the three Entities that can be smashed in a race (imagination boxes, track specific smashables, Forbidden Valley dragon eggs). * Updated race imagination task progression Race imagination now no longer uses a magic number when passed to missionComponent. Instead we use a number defined in an enum located in RacingTaskParam.h * Updated Race task checks Racing tasks for completing races without smashing now no longer auto complete the whole chain of missions. Tasks that track placing on tracks and races overall now properly complete. Tasks that count how many missions in a zone are completed now function. Tasks that track race completions in multiple areas now function. * Updated RacingControlComponent.cpp Fixed any tasks that required 3 players to now require 3 or more players in a race to progress. This restriction is ignored if the world config opted in for solo racing to allow progression in solo worlds. Updated magic numbers sent into missionComponent->Progress to an enum created in this PR. Fixed some indentation. * Fixed a grammatical error in variable name Fixed a grammatical error in the enum for task params
2022-02-05 11:28:17 +00:00
AddProgress(count);
} else if (associate == 4 || associate == 5 || associate == 14) {
if (!InAllTargets(value)) break;
AddProgress(count);
2022-02-06 22:28:27 +00:00
} 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;
}
default:
Game::logger->Log("MissionTask", "Invalid mission task type (%i)!", static_cast<int>(type));
return;
}
CheckCompletion();
}
MissionTask::~MissionTask() {
targets.clear();
parameters.clear();
unique.clear();
}