diff --git a/common/tasks.h b/common/tasks.h index f5f09e4ca..82eb48ce0 100644 --- a/common/tasks.h +++ b/common/tasks.h @@ -5,7 +5,6 @@ #include #include -#define MAXTASKS 10000 #define MAXTASKSETS 1000 #define MAXACTIVEQUESTS 19 // The Client has a hard cap of 19 active quests, 29 in SoD+ #define MAXCHOOSERENTRIES 40 // The Max Chooser (Task Selector entries) is capped at 40 in the Titanium Client. @@ -223,8 +222,8 @@ struct TaskInformation { int reward_points; AltCurrencyType reward_point_type; int activity_count{}; - short min_level{}; - short max_level{}; + uint8_t min_level{}; + uint8_t max_level{}; int level_spread; int min_players; int max_players; diff --git a/zone/gm_commands/findtask.cpp b/zone/gm_commands/findtask.cpp index 95421b1a2..15c66b800 100755 --- a/zone/gm_commands/findtask.cpp +++ b/zone/gm_commands/findtask.cpp @@ -35,8 +35,8 @@ void command_findtask(Client *c, const Seperator *sep) std::string search_criteria = Strings::ToLower(sep->argplus[1]); if (!search_criteria.empty()) { int found_count = 0; - for (uint32 task_id = 1; task_id <= MAXTASKS; task_id++) { - auto task_name = task_manager->GetTaskName(task_id); + for (const auto& task : task_manager->GetTaskData()) { + auto task_name = task.second.title; std::string task_name_lower = Strings::ToLower(task_name); if (task_name_lower.find(search_criteria) == std::string::npos) { continue; @@ -46,7 +46,7 @@ void command_findtask(Client *c, const Seperator *sep) Chat::White, fmt::format( "Task {}: {}", - task_id, + task.first, task_name ).c_str() ); diff --git a/zone/gm_commands/task.cpp b/zone/gm_commands/task.cpp index f84057d54..cc436939b 100755 --- a/zone/gm_commands/task.cpp +++ b/zone/gm_commands/task.cpp @@ -162,7 +162,7 @@ void command_task(Client *c, const Seperator *sep) if (is_assign) { auto task_id = std::strtoul(sep->arg[2], nullptr, 10); - if (task_id && task_id < MAXTASKS) { + if (task_id) { target->AssignTask(task_id, 0, false); c->Message( Chat::Yellow, @@ -203,7 +203,7 @@ void command_task(Client *c, const Seperator *sep) return; } else if (!strcasecmp(sep->arg[2], "task") && arguments == 3) { int task_id = std::strtoul(sep->arg[3], nullptr, 10); - if (task_id && task_id < MAXTASKS) { + if (task_id) { c->Message( Chat::Yellow, fmt::format( @@ -252,7 +252,7 @@ void command_task(Client *c, const Seperator *sep) } else if (is_uncomplete) { if (sep->IsNumber(2)) { auto task_id = std::stoul(sep->arg[2]); - if (!task_id || task_id > MAXTASKS) { + if (!task_id) { c->Message(Chat::White, "Invalid task ID specified."); return; } diff --git a/zone/task_client_state.cpp b/zone/task_client_state.cpp index 1a68c3824..b984e772f 100644 --- a/zone/task_client_state.cpp +++ b/zone/task_client_state.cpp @@ -58,13 +58,12 @@ void ClientTaskState::SendTaskHistory(Client *client, int task_index) } int task_id = m_completed_tasks[adjusted_task_index].task_id; - if ((task_id < 0) || (task_id > MAXTASKS)) { + if (task_id < 0) { return; } - TaskInformation *p_task_data = task_manager->m_task_data[task_id]; - - if (p_task_data == nullptr) { + const auto task_data = task_manager->GetTaskData(task_id); + if (!task_data) { return; } @@ -77,14 +76,14 @@ void ClientTaskState::SendTaskHistory(Client *client, int task_index) int completed_activity_count = 0; int packet_length = sizeof(TaskHistoryReplyHeader_Struct); - for (int i = 0; i < p_task_data->activity_count; i++) { + for (int i = 0; i < task_data->activity_count; i++) { if (m_completed_tasks[adjusted_task_index].activity_done[i]) { completed_activity_count++; packet_length = packet_length + sizeof(TaskHistoryReplyData1_Struct) + - p_task_data->activity_information[i].target_name.size() + 1 + - p_task_data->activity_information[i].item_list.size() + 1 + + task_data->activity_information[i].target_name.size() + 1 + + task_data->activity_information[i].item_list.size() + 1 + sizeof(TaskHistoryReplyData2_Struct) + - p_task_data->activity_information[i].description_override.size() + 1; + task_data->activity_information[i].description_override.size() + 1; } } @@ -98,22 +97,22 @@ void ClientTaskState::SendTaskHistory(Client *client, int task_index) reply = (char *) task_history_reply + sizeof(TaskHistoryReplyHeader_Struct); - for (int i = 0; i < p_task_data->activity_count; i++) { + for (int i = 0; i < task_data->activity_count; i++) { if (m_completed_tasks[adjusted_task_index].activity_done[i]) { task_history_reply_data_1 = (TaskHistoryReplyData1_Struct *) reply; - task_history_reply_data_1->ActivityType = static_cast(p_task_data->activity_information[i].activity_type); + task_history_reply_data_1->ActivityType = static_cast(task_data->activity_information[i].activity_type); reply = (char *) task_history_reply_data_1 + sizeof(TaskHistoryReplyData1_Struct); - VARSTRUCT_ENCODE_STRING(reply, p_task_data->activity_information[i].target_name.c_str()); - VARSTRUCT_ENCODE_STRING(reply, p_task_data->activity_information[i].item_list.c_str()); + VARSTRUCT_ENCODE_STRING(reply, task_data->activity_information[i].target_name.c_str()); + VARSTRUCT_ENCODE_STRING(reply, task_data->activity_information[i].item_list.c_str()); task_history_reply_data_2 = (TaskHistoryReplyData2_Struct *) reply; - task_history_reply_data_2->GoalCount = p_task_data->activity_information[i].goal_count; + task_history_reply_data_2->GoalCount = task_data->activity_information[i].goal_count; task_history_reply_data_2->unknown04 = 0xffffffff; task_history_reply_data_2->unknown08 = 0xffffffff; - task_history_reply_data_2->ZoneID = p_task_data->activity_information[i].zone_ids.empty() ? 0 - : p_task_data->activity_information[i].zone_ids.front(); + task_history_reply_data_2->ZoneID = task_data->activity_information[i].zone_ids.empty() ? 0 + : task_data->activity_information[i].zone_ids.front(); task_history_reply_data_2->unknown16 = 0x00000000; reply = (char *) task_history_reply_data_2 + sizeof(TaskHistoryReplyData2_Struct); - VARSTRUCT_ENCODE_STRING(reply, p_task_data->activity_information[i].description_override.c_str()); + VARSTRUCT_ENCODE_STRING(reply, task_data->activity_information[i].description_override.c_str()); } } @@ -320,7 +319,7 @@ int ClientTaskState::CompletedTasksInSet(int task_set_id) return completed_tasks_count; } -bool ClientTaskState::HasSlotForTask(TaskInformation *task) +bool ClientTaskState::HasSlotForTask(const TaskInformation* task) { if (task == nullptr) { return false; @@ -375,7 +374,7 @@ bool ClientTaskState::UnlockActivities(Client* client, ClientTaskInformation& ta task_info.updated ); - const TaskInformation* task = task_manager->m_task_data[task_info.task_id]; + const auto task = task_manager->GetTaskData(task_info.task_id); if (!task) { return true; @@ -466,7 +465,7 @@ const TaskInformation* ClientTaskState::GetTaskData(const ClientTaskInformation& return nullptr; } - return task_manager->m_task_data[client_task.task_id]; + return task_manager->GetTaskData(client_task.task_id); } bool ClientTaskState::CanUpdate(Client* client, const TaskUpdateFilter& filter, int task_id, @@ -569,7 +568,7 @@ int ClientTaskState::UpdateTasks(Client* client, const TaskUpdateFilter& filter, for (const auto& client_task : m_active_tasks) { - const TaskInformation* task = GetTaskData(client_task); + const auto task = GetTaskData(client_task); if (!task) { continue; @@ -610,7 +609,7 @@ std::pair ClientTaskState::FindTask(Client* client, const TaskUpdateFi for (const auto& client_task : m_active_tasks) { - const TaskInformation* task = GetTaskData(client_task); + const auto task = GetTaskData(client_task); if (!task || (filter.task_id != 0 && client_task.task_id != filter.task_id)) { continue; @@ -674,7 +673,7 @@ int ClientTaskState::ActiveSpeakActivity(Client* client, NPC* npc, int task_id) // This method is to be used from Perl quests only and returns the activity_id of the first // active activity_information found in the specified task which is to SpeakWith this NPC. - if (task_id <= 0 || task_id >= MAXTASKS) + if (task_id <= 0) { return -1; } @@ -793,14 +792,14 @@ void ClientTaskState::UpdateTasksOnKill(Client* client, Client* exp_client, NPC* int ClientTaskState::IncrementDoneCount( Client *client, - const TaskInformation* task_information, + const TaskInformation* task_data, int task_index, int activity_id, int count, bool ignore_quest_update ) { - auto info = GetClientTaskInfo(task_information->type, task_index); + auto info = GetClientTaskInfo(task_data->type, task_index); if (info == nullptr) { return 0; } @@ -813,12 +812,12 @@ int ClientTaskState::IncrementDoneCount( count ); - int remaining = task_information->activity_information[activity_id].goal_count - info->activity[activity_id].done_count; + int remaining = task_data->activity_information[activity_id].goal_count - info->activity[activity_id].done_count; count = std::min(count, remaining); // shared task shim // intercept and pass to world first before processing normally - if (!client->m_shared_task_update && task_information->type == TaskType::Shared) { + if (!client->m_shared_task_update && task_data->type == TaskType::Shared) { // struct auto pack = new ServerPacket(ServerOP_SharedTaskUpdate, sizeof(ServerSharedTaskActivityUpdate_Struct)); @@ -842,7 +841,7 @@ int ClientTaskState::IncrementDoneCount( SyncSharedTaskZoneClientDoneCountState( client, - task_information->type, + task_data->type, task_index, activity_id, r->done_count @@ -867,21 +866,21 @@ int ClientTaskState::IncrementDoneCount( parse->EventPlayer(EVENT_TASK_UPDATE, client, export_string, 0); } - if (task_information->type != TaskType::Shared) { + if (task_data->type != TaskType::Shared) { // live messages for each increment of non-shared tasks - auto activity_type = task_information->activity_information[activity_id].activity_type; + auto activity_type = task_data->activity_information[activity_id].activity_type; int msg_count = activity_type == TaskActivityType::GiveCash ? 1 : count; for (int i = 0; i < msg_count; ++i) { - client->MessageString(Chat::DefaultText, TASK_UPDATED, task_information->title.c_str()); + client->MessageString(Chat::DefaultText, TASK_UPDATED, task_data->title.c_str()); } } info->activity[activity_id].updated = true; // Have we reached the goal count for this activity_information ? - if (info->activity[activity_id].done_count >= task_information->activity_information[activity_id].goal_count) { + if (info->activity[activity_id].done_count >= task_data->activity_information[activity_id].goal_count) { LogTasks("[IncrementDoneCount] done_count [{}] goal_count [{}] activity_id [{}]", info->activity[activity_id].done_count, - task_information->activity_information[activity_id].goal_count, + task_data->activity_information[activity_id].goal_count, activity_id ); @@ -891,11 +890,11 @@ int ClientTaskState::IncrementDoneCount( bool task_complete = UnlockActivities(client, *info); LogTasks("[IncrementDoneCount] task_complete is [{}]", task_complete); // shared tasks only send update messages on activity completion - if (task_information->type == TaskType::Shared) { - client->MessageString(Chat::DefaultText, TASK_UPDATED, task_information->title.c_str()); + if (task_data->type == TaskType::Shared) { + client->MessageString(Chat::DefaultText, TASK_UPDATED, task_data->title.c_str()); } // and by the 'Task Stage Completed' message - client->SendTaskActivityComplete(info->task_id, activity_id, task_index, task_information->type); + client->SendTaskActivityComplete(info->task_id, activity_id, task_index, task_data->type); // Send the updated task/activity_information list to the client task_manager->SendSingleActiveTaskToClient(client, *info, task_complete, false); @@ -924,8 +923,8 @@ int ClientTaskState::IncrementDoneCount( // client. This is the same sequence the packets are sent on live. if (task_complete) { // world adds timers for shared tasks - if (task_information->type != TaskType::Shared) { - AddReplayTimer(client, *info, *task_information); + if (task_data->type != TaskType::Shared) { + AddReplayTimer(client, *info, *task_data); } DispatchEventTaskComplete(client, *info, activity_id); @@ -942,17 +941,17 @@ int ClientTaskState::IncrementDoneCount( QServ->PlayerLogEvent(Player_Log_Task_Updates, client->CharacterID(), event_desc); } - client->SendTaskActivityComplete(info->task_id, 0, task_index, task_information->type, 0); + client->SendTaskActivityComplete(info->task_id, 0, task_index, task_data->type, 0); // If Experience and/or cash rewards are set, reward them from the task even if reward_method is METHODQUEST - RewardTask(client, task_information, *info); + RewardTask(client, task_data, *info); //RemoveTask(c, TaskIndex); // shared tasks linger at the completion step and do not get removed from the task window unlike quests/task - if (task_information->type != TaskType::Shared) { + if (task_data->type != TaskType::Shared) { task_manager->SendCompletedTasksToClient(client, this); - client->CancelTask(task_index, task_information->type); + client->CancelTask(task_index, task_data->type); } } } @@ -1191,15 +1190,13 @@ bool ClientTaskState::IsTaskActivityActive(int task_id, int activity_id) return false; } - TaskInformation *p_task_data = task_manager->m_task_data[info->task_id]; - - // The task is invalid - if (p_task_data == nullptr) { + const auto task_data = task_manager->GetTaskData(info->task_id); + if (!task_data) { return false; } // The activity_id is out of range - if (activity_id >= p_task_data->activity_count) { + if (activity_id >= task_data->activity_count) { return false; } @@ -1264,15 +1261,13 @@ void ClientTaskState::UpdateTaskActivity( return; } - TaskInformation *p_task_data = task_manager->m_task_data[info->task_id]; - - // The task is invalid - if (p_task_data == nullptr) { + const auto task_data = task_manager->GetTaskData(info->task_id); + if (!task_data) { return; } // The activity_id is out of range - if (activity_id >= p_task_data->activity_count) { + if (activity_id >= task_data->activity_count) { return; } @@ -1288,7 +1283,7 @@ void ClientTaskState::UpdateTaskActivity( count ); - IncrementDoneCount(client, p_task_data, active_task_index, activity_id, count, ignore_quest_update); + IncrementDoneCount(client, task_data, active_task_index, activity_id, count, ignore_quest_update); } void ClientTaskState::ResetTaskActivity(Client *client, int task_id, int activity_id) @@ -1336,13 +1331,13 @@ void ClientTaskState::ResetTaskActivity(Client *client, int task_id, int activit return; } - TaskInformation *p_task_data = task_manager->m_task_data[info->task_id]; - if (p_task_data == nullptr) { + const auto task_data = task_manager->GetTaskData(info->task_id); + if (!task_data) { return; } // The activity_id is out of range - if (activity_id >= p_task_data->activity_count) { + if (activity_id >= task_data->activity_count) { return; } @@ -1360,7 +1355,7 @@ void ClientTaskState::ResetTaskActivity(Client *client, int task_id, int activit IncrementDoneCount( client, - p_task_data, + task_data, active_task_index, activity_id, (info->activity[activity_id].done_count * -1), @@ -1370,7 +1365,7 @@ void ClientTaskState::ResetTaskActivity(Client *client, int task_id, int activit void ClientTaskState::ShowClientTaskInfoMessage(ClientTaskInformation *task, Client *c) { - auto task_data = task_manager->m_task_data[task->task_id]; + const auto task_data = task_manager->GetTaskData(task->task_id); c->Message(Chat::White, "------------------------------------------------"); c->Message( @@ -1463,16 +1458,16 @@ int ClientTaskState::TaskTimeLeft(int task_id) if (m_active_task.task_id == task_id) { int time_now = time(nullptr); - TaskInformation *p_task_data = task_manager->m_task_data[task_id]; - if (p_task_data == nullptr) { + const auto task_data = task_manager->GetTaskData(task_id); + if (!task_data) { return -1; } - if (!p_task_data->duration) { + if (!task_data->duration) { return -1; } - int time_left = (m_active_task.accepted_time + p_task_data->duration - time_now); + int time_left = (m_active_task.accepted_time + task_data->duration - time_now); return (time_left > 0 ? time_left : 0); } @@ -1481,16 +1476,16 @@ int ClientTaskState::TaskTimeLeft(int task_id) if (m_active_shared_task.task_id == task_id) { int time_now = time(nullptr); - TaskInformation *p_task_data = task_manager->m_task_data[task_id]; - if (p_task_data == nullptr) { + const auto task_data = task_manager->GetTaskData(task_id); + if (!task_data) { return -1; } - if (!p_task_data->duration) { + if (!task_data->duration) { return -1; } - int time_left = (m_active_shared_task.accepted_time + p_task_data->duration - time_now); + int time_left = (m_active_shared_task.accepted_time + task_data->duration - time_now); return (time_left > 0 ? time_left : 0); } @@ -1506,16 +1501,16 @@ int ClientTaskState::TaskTimeLeft(int task_id) int time_now = time(nullptr); - TaskInformation *p_task_data = task_manager->m_task_data[active_quest.task_id]; - if (p_task_data == nullptr) { + const auto task_data = task_manager->GetTaskData(active_quest.task_id); + if (!task_data) { return -1; } - if (!p_task_data->duration) { + if (!task_data->duration) { return -1; } - int time_left = (active_quest.accepted_time + p_task_data->duration - time_now); + int time_left = (active_quest.accepted_time + task_data->duration - time_now); // If Timeleft is negative, return 0, else return the number of seconds left @@ -1555,13 +1550,13 @@ bool ClientTaskState::TaskOutOfTime(TaskType task_type, int index) } // make sure the task_id is at least maybe in our array - if (info->task_id <= 0 || info->task_id >= MAXTASKS) { + if (info->task_id <= 0) { return false; } - int time_now = time(nullptr); - TaskInformation *task_data = task_manager->m_task_data[info->task_id]; - if (task_data == nullptr) { + int time_now = time(nullptr); + const auto task_data = task_manager->GetTaskData(info->task_id); + if (!task_data) { return false; } @@ -1930,13 +1925,13 @@ void ClientTaskState::AcceptNewTask( bool enforce_level_requirement ) { - if (!task_manager || task_id < 0 || task_id >= MAXTASKS) { + if (!task_manager || task_id < 0) { client->Message(Chat::Red, "Task system not functioning, or task_id %i out of range.", task_id); return; } - auto task = task_manager->m_task_data[task_id]; - if (task == nullptr) { + const auto task = task_manager->GetTaskData(task_id); + if (!task) { client->Message(Chat::Red, "Invalid task_id %i", task_id); return; } @@ -2098,7 +2093,7 @@ void ClientTaskState::AcceptNewTask( active_slot->updated = true; active_slot->was_rewarded = false; - for (int activity_id = 0; activity_id < task_manager->m_task_data[task_id]->activity_count; activity_id++) { + for (int activity_id = 0; activity_id < task->activity_count; activity_id++) { active_slot->activity[activity_id].activity_id = activity_id; active_slot->activity[activity_id].done_count = 0; active_slot->activity[activity_id].activity_state = ActivityHidden; @@ -2179,7 +2174,7 @@ void ClientTaskState::SharedTaskIncrementDoneCount( bool ignore_quest_update ) { - TaskInformation *t = task_manager->m_task_data[task_id]; + const auto t = task_manager->GetTaskData(task_id); auto info = GetClientTaskInfo(t->type, TASKSLOTSHAREDTASK); if (info == nullptr) { @@ -2218,7 +2213,7 @@ bool ClientTaskState::HasActiveSharedTask() void ClientTaskState::CreateTaskDynamicZone(Client* client, int task_id, DynamicZone& dz_request) { - auto task = task_manager->m_task_data[task_id]; + const auto task = task_manager->GetTaskData(task_id); if (!task) { return; @@ -2294,7 +2289,7 @@ void ClientTaskState::ListTaskTimers(Client* client) for (const auto& task_timer : character_task_timers) { - auto task = task_manager->m_task_data[task_timer.task_id]; + const auto task = task_manager->GetTaskData(task_timer.task_id); if (task) { auto timer_type = static_cast(task_timer.timer_type); diff --git a/zone/task_client_state.h b/zone/task_client_state.h index 7509de366..374c233eb 100644 --- a/zone/task_client_state.h +++ b/zone/task_client_state.h @@ -74,7 +74,7 @@ public: int ActiveSpeakActivity(Client* client, NPC* npc, int task_id); int ActiveTasksInSet(int task_set_id); int CompletedTasksInSet(int task_set_id); - bool HasSlotForTask(TaskInformation *task); + bool HasSlotForTask(const TaskInformation* task); void CreateTaskDynamicZone(Client* client, int task_id, DynamicZone& dz); void ListTaskTimers(Client* client); void KickPlayersSharedTask(Client* client); @@ -114,7 +114,7 @@ private: int IncrementDoneCount( Client *client, - const TaskInformation* task_information, + const TaskInformation* task_data, int task_index, int activity_id, int count = 1, diff --git a/zone/task_manager.cpp b/zone/task_manager.cpp index beaa4985f..ae38b666b 100644 --- a/zone/task_manager.cpp +++ b/zone/task_manager.cpp @@ -17,22 +17,6 @@ extern WorldServer worldserver; -TaskManager::TaskManager() -{ - for (auto &task : m_task_data) { - task = nullptr; - } -} - -TaskManager::~TaskManager() -{ - for (auto &task : m_task_data) { - if (task != nullptr) { - safe_delete(task); - } - } -} - bool TaskManager::LoadTaskSets() { // Clear all task sets in memory. Done so we can reload them on the fly if required by just calling @@ -44,9 +28,8 @@ bool TaskManager::LoadTaskSets() auto rows = TasksetsRepository::GetWhere( content_db, fmt::format( - "`id` > 0 AND `id` < {} AND `taskid` >= 0 AND `taskid` < {} ORDER BY `id`, `taskid` ASC", - MAXTASKSETS, - MAXTASKS + "`id` > 0 AND `id` < {} AND `taskid` >= 0 ORDER BY `id`, `taskid` ASC", + MAXTASKSETS ) ); @@ -78,48 +61,51 @@ bool TaskManager::LoadTasks(int single_task) LogTasks("[TaskManager::LoadTasks] LoadTaskSets failed"); } - task_query_filter = fmt::format("id < {}", MAXTASKS); + task_query_filter = fmt::format("id > 0"); } // load task level data auto repo_tasks = TasksRepository::GetWhere(content_db, task_query_filter); + m_task_data.reserve(repo_tasks.size()); for (auto &task: repo_tasks) { int task_id = task.id; - if ((task_id <= 0) || (task_id >= MAXTASKS)) { + if (task_id <= 0) { // This shouldn't happen, as the SELECT is bounded by MAXTASKS LogError("[TASKS]Task ID [{}] out of range while loading tasks from database", task_id); continue; } // load task data - m_task_data[task_id] = new TaskInformation(); - m_task_data[task_id]->type = static_cast(task.type); - m_task_data[task_id]->duration = task.duration; - m_task_data[task_id]->duration_code = static_cast(task.duration_code); - m_task_data[task_id]->title = task.title; - m_task_data[task_id]->description = task.description; - m_task_data[task_id]->reward = task.reward; - m_task_data[task_id]->reward_id = task.rewardid; - m_task_data[task_id]->cash_reward = task.cashreward; - m_task_data[task_id]->experience_reward = task.xpreward; - m_task_data[task_id]->reward_method = (TaskMethodType) task.rewardmethod; - m_task_data[task_id]->reward_points = task.reward_points; - m_task_data[task_id]->reward_point_type = static_cast(task.reward_point_type); - m_task_data[task_id]->faction_reward = task.faction_reward; - m_task_data[task_id]->min_level = task.minlevel; - m_task_data[task_id]->max_level = task.maxlevel; - m_task_data[task_id]->level_spread = task.level_spread; - m_task_data[task_id]->min_players = task.min_players; - m_task_data[task_id]->max_players = task.max_players; - m_task_data[task_id]->repeatable = task.repeatable; - m_task_data[task_id]->completion_emote = task.completion_emote; - m_task_data[task_id]->replay_timer_group = task.replay_timer_group; - m_task_data[task_id]->replay_timer_seconds = task.replay_timer_seconds; - m_task_data[task_id]->request_timer_group = task.request_timer_group; - m_task_data[task_id]->request_timer_seconds = task.request_timer_seconds; - m_task_data[task_id]->activity_count = 0; + TaskInformation task_data{}; + task_data.type = static_cast(task.type); + task_data.duration = task.duration; + task_data.duration_code = static_cast(task.duration_code); + task_data.title = task.title; + task_data.description = task.description; + task_data.reward = task.reward; + task_data.reward_id = task.rewardid; + task_data.cash_reward = task.cashreward; + task_data.experience_reward = task.xpreward; + task_data.reward_method = (TaskMethodType) task.rewardmethod; + task_data.reward_points = task.reward_points; + task_data.reward_point_type = static_cast(task.reward_point_type); + task_data.faction_reward = task.faction_reward; + task_data.min_level = task.minlevel; + task_data.max_level = task.maxlevel; + task_data.level_spread = task.level_spread; + task_data.min_players = task.min_players; + task_data.max_players = task.max_players; + task_data.repeatable = task.repeatable; + task_data.completion_emote = task.completion_emote; + task_data.replay_timer_group = task.replay_timer_group; + task_data.replay_timer_seconds = task.replay_timer_seconds; + task_data.request_timer_group = task.request_timer_group; + task_data.request_timer_seconds = task.request_timer_seconds; + task_data.activity_count = 0; + + m_task_data.try_emplace(task_id, std::move(task_data)); LogTasksDetail( "[LoadTasks] (Task) task_id [{}] type [{}] () duration [{}] duration_code [{}] title [{}] description [{}] " @@ -163,8 +149,7 @@ bool TaskManager::LoadTasks(int single_task) // if loading only a single task if (single_task == 0) { activities_query_filter = fmt::format( - "taskid < {} and activityid < {} ORDER BY taskid, activityid ASC", - MAXTASKS, + "activityid < {} ORDER BY taskid, activityid ASC", MAXACTIVITIESPERTASK ); } @@ -176,7 +161,7 @@ bool TaskManager::LoadTasks(int single_task) int step = task_activity.step; int activity_id = task_activity.activityid; - if ((task_id <= 0) || (task_id >= MAXTASKS) || (activity_id < 0) || (activity_id >= MAXACTIVITIESPERTASK)) { + if (task_id <= 0 || activity_id < 0 || activity_id >= MAXACTIVITIESPERTASK) { // This shouldn't happen, as the SELECT is bounded by MAXTASKS LogTasks( @@ -187,7 +172,8 @@ bool TaskManager::LoadTasks(int single_task) continue; } - if (m_task_data[task_id] == nullptr) { + auto task_data = GetTaskData(task_id); + if (!task_data) { LogTasks( "[LoadTasks] Error: activity_information for non-existent task ([{}], [{}]) while loading activities from database", task_id, @@ -197,20 +183,20 @@ bool TaskManager::LoadTasks(int single_task) } // create pointer to activity data since declarations get unruly long - int activity_index = m_task_data[task_id]->activity_count; - ActivityInformation *activity_data = &m_task_data[task_id]->activity_information[activity_index]; + int activity_index = task_data->activity_count; + ActivityInformation *activity_data = &task_data->activity_information[activity_index]; // Task Activities MUST be numbered sequentially from 0. If not, log an error // and set the task to nullptr. Subsequent activities for this task will raise // ERR_NOTASK errors. // Change to (activityID != (Tasks[taskID]->activity_count + 1)) to index from 1 - if (activity_id != m_task_data[task_id]->activity_count) { + if (activity_id != task_data->activity_count) { LogTasks( "[LoadTasks] Error: Activities for Task [{}] (activity_id [{}]) are not sequential starting at 0. Not loading task ", task_id, activity_id ); - m_task_data[task_id] = nullptr; + m_task_data.erase(task_id); continue; } @@ -268,7 +254,7 @@ bool TaskManager::LoadTasks(int single_task) " target_name [{}] item_list [{}] skill_list [{}] spell_list [{}] description_override [{}]", task_id, activity_id, - m_task_data[task_id]->activity_count, + task_data->activity_count, static_cast(activity_data->activity_type), activity_data->goal_method, activity_data->goal_count, @@ -280,7 +266,7 @@ bool TaskManager::LoadTasks(int single_task) activity_data->description_override.c_str() ); - m_task_data[task_id]->activity_count++; + task_data->activity_count++; } LogTasks("Loaded [{}] Task Activities", task_activities.size()); @@ -313,6 +299,8 @@ bool TaskManager::SaveClientState(Client *client, ClientTaskState *client_task_s continue; } + const auto task_data = GetTaskData(task_id); + int slot = active_task.slot; if (active_task.updated) { @@ -329,7 +317,7 @@ bool TaskManager::SaveClientState(Client *client, ClientTaskState *client_task_s character_id, task_id, slot, - static_cast(m_task_data[task_id]->type), + static_cast(task_data->type), active_task.accepted_time, active_task.was_rewarded ); @@ -349,7 +337,7 @@ bool TaskManager::SaveClientState(Client *client, ClientTaskState *client_task_s int updated_activity_count = 0; - for (int activity_index = 0; activity_index < m_task_data[task_id]->activity_count; ++activity_index) { + for (int activity_index = 0; activity_index < task_data->activity_count; ++activity_index) { if (!active_task.activity[activity_index].updated) { continue; } @@ -396,7 +384,7 @@ bool TaskManager::SaveClientState(Client *client, ClientTaskState *client_task_s } active_task.updated = false; - for (int activity_index = 0; activity_index < m_task_data[task_id]->activity_count; ++activity_index) { + for (int activity_index = 0; activity_index < task_data->activity_count; ++activity_index) { active_task.activity[activity_index].updated = false; } } @@ -417,12 +405,13 @@ bool TaskManager::SaveClientState(Client *client, ClientTaskState *client_task_s int task_id = client_task_state->m_completed_tasks[task_index].task_id; - if ((task_id <= 0) || (task_id >= MAXTASKS) || (m_task_data[task_id] == nullptr)) { + const auto task_data = GetTaskData(task_id); + if (!task_data) { continue; } // we don't record completed shared tasks in the task quest log - if (m_task_data[task_id]->type == TaskType::Shared) { + if (task_data->type == TaskType::Shared) { break; } @@ -450,8 +439,8 @@ bool TaskManager::SaveClientState(Client *client, ClientTaskState *client_task_s } // Insert one record for each completed optional task. - for (int activity_id = 0; activity_id < m_task_data[task_id]->activity_count; activity_id++) { - if (!m_task_data[task_id]->activity_information[activity_id].optional || + for (int activity_id = 0; activity_id < task_data->activity_count; activity_id++) { + if (!task_data->activity_information[activity_id].optional || !client_task_state->m_completed_tasks[task_index].activity_done[activity_id]) { continue; } @@ -529,15 +518,16 @@ int TaskManager::NextTaskInSet(int task_set, int task_id) bool TaskManager::ValidateLevel(int task_id, int player_level) { - if (m_task_data[task_id] == nullptr) { + const auto task_data = GetTaskData(task_id); + if (!task_data) { return false; } - if (m_task_data[task_id]->min_level && (player_level < m_task_data[task_id]->min_level)) { + if (task_data->min_level && (player_level < task_data->min_level)) { return false; } - if (m_task_data[task_id]->max_level && (player_level > m_task_data[task_id]->max_level)) { + if (task_data->max_level && (player_level > task_data->max_level)) { return false; } @@ -546,9 +536,10 @@ bool TaskManager::ValidateLevel(int task_id, int player_level) std::string TaskManager::GetTaskName(uint32 task_id) { - if (task_id > 0 && task_id < MAXTASKS) { - if (m_task_data[task_id] != nullptr) { - return m_task_data[task_id]->title; + if (task_id > 0) { + const auto task_data = GetTaskData(task_id); + if (task_data) { + return task_data->title; } } @@ -557,9 +548,10 @@ std::string TaskManager::GetTaskName(uint32 task_id) TaskType TaskManager::GetTaskType(uint32 task_id) { - if (task_id > 0 && task_id < MAXTASKS) { - if (m_task_data[task_id] != nullptr) { - return m_task_data[task_id]->type; + if (task_id > 0) { + const auto task_data = GetTaskData(task_id); + if (task_data) { + return task_data->type; } } return TaskType::Task; @@ -584,7 +576,8 @@ void TaskManager::TaskSetSelector(Client *client, ClientTaskState *client_task_s // forward to shared task selector validation if set contains a shared task for (const auto& task_id : m_task_sets[task_set_id]) { - if (m_task_data[task_id] && m_task_data[task_id]->type == TaskType::Shared) { + const auto task_data = GetTaskData(task_id); + if (task_data && task_data->type == TaskType::Shared) { SharedTaskSelector(client, mob, m_task_sets[task_set_id].size(), m_task_sets[task_set_id].data()); return; } @@ -615,10 +608,12 @@ void TaskManager::TaskSetSelector(Client *client, ClientTaskState *client_task_s while (iterator != m_task_sets[task_set_id].end() && task_list_index < MAXCHOOSERENTRIES) { auto task = *iterator; + const auto task_data = GetTaskData(task); + // verify level, we're not currently on it, repeatable status, if it's a (shared) task // we aren't currently on another, and if it's enabled if not all_enabled if ((all_enabled || client_task_state->IsTaskEnabled(task)) && ValidateLevel(task, player_level) && - !client_task_state->IsTaskActive(task) && client_task_state->HasSlotForTask(m_task_data[task]) && + !client_task_state->IsTaskActive(task) && client_task_state->HasSlotForTask(task_data) && // this slot checking is a bit silly, but we allow mixing of task types ... (IsTaskRepeatable(task) || !client_task_state->IsTaskCompleted(task))) { task_list[task_list_index++] = task; @@ -660,7 +655,8 @@ void TaskManager::TaskQuestSetSelector( // forward this to shared task validation and non-shared tasks will be dropped for (int i = 0; i < count; ++i) { auto task = tasks[i]; - if (m_task_data[task] && m_task_data[task]->type == TaskType::Shared) { + const auto task_data = GetTaskData(task); + if (task_data && task_data->type == TaskType::Shared) { SharedTaskSelector(client, mob, count, tasks); return; } @@ -673,10 +669,11 @@ void TaskManager::TaskQuestSetSelector( for (int i = 0; i < count; ++i) { auto task = tasks[i]; + const auto task_data = GetTaskData(task); // verify level, we're not currently on it, repeatable status, if it's a (shared) task // we aren't currently on another, and if it's enabled if not all_enabled if (ValidateLevel(task, player_level) && !client_task_state->IsTaskActive(task) && - client_task_state->HasSlotForTask(m_task_data[task]) && + client_task_state->HasSlotForTask(task_data) && // this slot checking is a bit silly, but we allow mixing of task types ... (IsTaskRepeatable(task) || !client_task_state->IsTaskCompleted(task))) { task_list[task_list_index++] = task; @@ -744,10 +741,12 @@ void TaskManager::SharedTaskSelector(Client *client, Mob *mob, int count, const for (int i = 0; i < count && task_list_index < MAXCHOOSERENTRIES; ++i) { // todo: are there non repeatable shared tasks? (would need to check all group/raid members) auto task = tasks[i]; - if (m_task_data[task] && - m_task_data[task]->type == TaskType::Shared && - request.lowest_level >= m_task_data[task]->min_level && - (m_task_data[task]->max_level == 0 || request.highest_level <= m_task_data[task]->max_level)) { + const auto task_data = GetTaskData(task); + if (task_data && + task_data->type == TaskType::Shared && + request.lowest_level >= task_data->min_level && + (task_data->max_level == 0 || request.highest_level <= task_data->max_level)) + { task_list[task_list_index++] = task; } } @@ -769,13 +768,6 @@ void TaskManager::SendTaskSelector(Client *client, Mob *mob, int task_count, int int player_level = client->GetLevel(); client->GetTaskState()->ClearLastOffers(); - // Check if any of the tasks exist - for (int i = 0; i < task_count; i++) { - if (m_task_data[task_list[i]] != nullptr) { - break; - } - } - int valid_tasks_count = 0; for (int task_index = 0; task_index < task_count; task_index++) { if (!ValidateLevel(task_list[task_index], player_level)) { @@ -815,7 +807,7 @@ void TaskManager::SendTaskSelector(Client *client, Mob *mob, int task_count, int } buf.WriteUInt32(task_list[i]); // task_id - m_task_data[task_list[i]]->SerializeSelector(buf, client->ClientVersion()); + m_task_data[task_list[i]].SerializeSelector(buf, client->ClientVersion()); client->GetTaskState()->AddOffer(task_list[i], mob->GetID()); } @@ -841,7 +833,7 @@ void TaskManager::SendSharedTaskSelector(Client *client, Mob *mob, int task_coun for (int i = 0; i < task_count; ++i) { int task_id = task_list[i]; buf.WriteUInt32(task_id); - m_task_data[task_id]->SerializeSelector(buf, client->ClientVersion()); + m_task_data[task_id].SerializeSelector(buf, client->ClientVersion()); client->GetTaskState()->AddOffer(task_id, mob->GetID()); } @@ -851,8 +843,11 @@ void TaskManager::SendSharedTaskSelector(Client *client, Mob *mob, int task_coun int TaskManager::GetActivityCount(int task_id) { - if ((task_id > 0) && (task_id < MAXTASKS)) { - if (m_task_data[task_id]) { return m_task_data[task_id]->activity_count; } + if (task_id > 0) { + const auto task_data = GetTaskData(task_id); + if (task_data) { + return task_data->activity_count; + } } return 0; @@ -860,12 +855,8 @@ int TaskManager::GetActivityCount(int task_id) bool TaskManager::IsTaskRepeatable(int task_id) { - if ((task_id <= 0) || (task_id >= MAXTASKS)) { - return false; - } - - TaskInformation *task_data = task_manager->m_task_data[task_id]; - if (task_data == nullptr) { + const auto task_data = GetTaskData(task_id); + if (!task_data) { return false; } @@ -900,9 +891,10 @@ void TaskManager::SendCompletedTasksToClient(Client *c, ClientTaskState *client_ } */ for (int i = first_task_to_send; i < last_task_to_send; i++) { - int TaskID = client_task_state->m_completed_tasks[i].task_id; - if (m_task_data[TaskID] == nullptr) { continue; } - packet_length = packet_length + 8 + m_task_data[TaskID]->title.size() + 1; + int task_id = client_task_state->m_completed_tasks[i].task_id; + const auto task_data = GetTaskData(task_id); + if (!task_data) { continue; } + packet_length = packet_length + 8 + task_data->title.size() + 1; } auto outapp = new EQApplicationPacket(OP_CompletedTasks, packet_length); @@ -915,11 +907,12 @@ void TaskManager::SendCompletedTasksToClient(Client *c, ClientTaskState *client_ // int task_id = (*iterator).task_id; for (int i = first_task_to_send; i < last_task_to_send; i++) { int task_id = client_task_state->m_completed_tasks[i].task_id; - if (m_task_data[task_id] == nullptr) { continue; } + const auto task_data = GetTaskData(task_id); + if (!task_data) { continue; } *(uint32 *) buf = task_id; buf = buf + 4; - sprintf(buf, "%s", m_task_data[task_id]->title.c_str()); + sprintf(buf, "%s", task_data->title.c_str()); buf = buf + strlen(buf) + 1; //*(uint32 *)buf = (*iterator).CompletedTime; *(uint32 *) buf = client_task_state->m_completed_tasks[i].completed_time; @@ -934,14 +927,16 @@ void TaskManager::SendTaskActivityShort(Client *client, int task_id, int activit { // This activity_information Packet is sent for activities that have not yet been unlocked and appear as ??? // in the client. + const auto task_data = GetTaskData(task_id); + auto outapp = std::make_unique(OP_TaskActivity, 25); outapp->WriteUInt32(client_task_index); - outapp->WriteUInt32(static_cast(m_task_data[task_id]->type)); + outapp->WriteUInt32(static_cast(task_data->type)); outapp->WriteUInt32(task_id); outapp->WriteUInt32(activity_id); outapp->WriteUInt32(0); outapp->WriteUInt32(0xffffffff); - outapp->WriteUInt8(m_task_data[task_id]->activity_information[activity_id].optional ? 1 : 0); + outapp->WriteUInt8(task_data->activity_information[activity_id].optional ? 1 : 0); client->QueuePacket(outapp.get()); } @@ -953,16 +948,18 @@ void TaskManager::SendTaskActivityLong( bool task_complete ) { + const auto task_data = GetTaskData(task_id); + SerializeBuffer buf(100); buf.WriteUInt32(client_task_index); // TaskSequenceNumber - buf.WriteUInt32(static_cast(m_task_data[task_id]->type)); // task type + buf.WriteUInt32(static_cast(task_data->type)); // task type buf.WriteUInt32(task_id); buf.WriteUInt32(activity_id); buf.WriteUInt32(0); // unknown3 - const auto &activity = m_task_data[task_id]->activity_information[activity_id]; - int done_count = client->GetTaskActivityDoneCount(m_task_data[task_id]->type, client_task_index, activity_id); + const auto& activity = task_data->activity_information[activity_id]; + int done_count = client->GetTaskActivityDoneCount(task_data->type, client_task_index, activity_id); activity.SerializeObjective(buf, client->ClientVersion(), done_count); @@ -982,10 +979,12 @@ void TaskManager::SendActiveTaskToClient( return; } + const auto task_data = GetTaskData(task->task_id); + int start_time = task->accepted_time; int task_id = task->task_id; - auto task_type = m_task_data[task_id]->type; - auto task_duration = m_task_data[task_id]->duration; + auto task_type = task_data->type; + auto task_duration = task_data->duration; SendActiveTaskDescription( client, @@ -1066,12 +1065,13 @@ void TaskManager::SendActiveTasksToClient(Client *client, bool task_complete) // quests for (int task_index = 0; task_index < MAXACTIVEQUESTS; task_index++) { int task_id = state->m_active_quests[task_index].task_id; - if ((task_id == 0) || (m_task_data[task_id] == nullptr)) { + const auto task_data = GetTaskData(task_id); + if (!task_data) { continue; } LogTasksDetail("--"); - LogTasksDetail("[SendActiveTasksToClient] Task [{}]", m_task_data[task_id]->title); + LogTasksDetail("[SendActiveTasksToClient] Task [{}]", task_data->title); SendActiveTaskToClient(&state->m_active_quests[task_index], client, task_index, task_complete); } @@ -1083,7 +1083,8 @@ void TaskManager::SendSingleActiveTaskToClient( ) { int task_id = task_info.task_id; - if (task_id == 0 || m_task_data[task_id] == nullptr) { + const auto task_data = GetTaskData(task_id); + if (!task_data) { return; } @@ -1093,7 +1094,7 @@ void TaskManager::SendSingleActiveTaskToClient( task_id, task_info, start_time, - m_task_data[task_id]->duration, + task_data->duration, bring_up_task_journal ); Log(Logs::General, @@ -1131,25 +1132,26 @@ void TaskManager::SendActiveTaskDescription( bool bring_up_task_journal ) { - if ((task_id < 1) || (task_id >= MAXTASKS) || !m_task_data[task_id]) { + auto task_data = GetTaskData(task_id); + if (!task_data) { return; } - int packet_length = sizeof(TaskDescriptionHeader_Struct) + m_task_data[task_id]->title.length() + 1 - + sizeof(TaskDescriptionData1_Struct) + m_task_data[task_id]->description.length() + 1 + int packet_length = sizeof(TaskDescriptionHeader_Struct) + task_data->title.length() + 1 + + sizeof(TaskDescriptionData1_Struct) + task_data->description.length() + 1 + sizeof(TaskDescriptionData2_Struct) + 1 + sizeof(TaskDescriptionTrailer_Struct); // If there is an item make the reward text into a link to the item (only the first item if a list // is specified). I have been unable to get multiple item links to work. // - if (m_task_data[task_id]->reward_id && m_task_data[task_id]->item_link.empty()) { + if (task_data->reward_id && task_data->item_link.empty()) { int item_id = 0; // If the reward is a list of items, and the first entry on the list is valid - if (m_task_data[task_id]->reward_method == METHODSINGLEID) { - item_id = m_task_data[task_id]->reward_id; + if (task_data->reward_method == METHODSINGLEID) { + item_id = task_data->reward_id; } - else if (m_task_data[task_id]->reward_method == METHODLIST) { - item_id = m_goal_list_manager.GetFirstEntry(m_task_data[task_id]->reward_id); + else if (task_data->reward_method == METHODLIST) { + item_id = m_goal_list_manager.GetFirstEntry(task_data->reward_id); if (item_id < 0) { item_id = 0; } @@ -1162,11 +1164,11 @@ void TaskManager::SendActiveTaskDescription( linker.SetLinkType(EQ::saylink::SayLinkItemData); linker.SetItemData(reward_item); linker.SetTaskUse(); - m_task_data[task_id]->item_link = linker.GenerateLink(); + task_data->item_link = linker.GenerateLink(); } } - packet_length += m_task_data[task_id]->reward.length() + 1 + m_task_data[task_id]->item_link.length() + 1; + packet_length += task_data->reward.length() + 1 + task_data->item_link.length() + 1; char *Ptr; TaskDescriptionHeader_Struct *task_description_header; @@ -1181,26 +1183,26 @@ void TaskManager::SendActiveTaskDescription( task_description_header->SequenceNumber = task_info.slot; task_description_header->TaskID = task_id; task_description_header->open_window = bring_up_task_journal; - task_description_header->task_type = static_cast(m_task_data[task_id]->type); + task_description_header->task_type = static_cast(task_data->type); - task_description_header->reward_type = static_cast(m_task_data[task_id]->reward_point_type); + task_description_header->reward_type = static_cast(task_data->reward_point_type); Ptr = (char *) task_description_header + sizeof(TaskDescriptionHeader_Struct); - sprintf(Ptr, "%s", m_task_data[task_id]->title.c_str()); - Ptr += m_task_data[task_id]->title.length() + 1; + sprintf(Ptr, "%s", task_data->title.c_str()); + Ptr += task_data->title.length() + 1; tdd1 = (TaskDescriptionData1_Struct *) Ptr; tdd1->Duration = duration; - tdd1->dur_code = static_cast(m_task_data[task_id]->duration_code); + tdd1->dur_code = static_cast(task_data->duration_code); tdd1->StartTime = start_time; Ptr = (char *) tdd1 + sizeof(TaskDescriptionData1_Struct); - sprintf(Ptr, "%s", m_task_data[task_id]->description.c_str()); - Ptr += m_task_data[task_id]->description.length() + 1; + sprintf(Ptr, "%s", task_data->description.c_str()); + Ptr += task_data->description.length() + 1; tdd2 = (TaskDescriptionData2_Struct *) Ptr; @@ -1209,24 +1211,24 @@ void TaskManager::SendActiveTaskDescription( // "has_reward_selection" is after this bool! Smaller packet when this is 0 tdd2->has_rewards = 1; - tdd2->coin_reward = m_task_data[task_id]->cash_reward; - tdd2->xp_reward = m_task_data[task_id]->experience_reward ? 1 : 0; // just booled - tdd2->faction_reward = m_task_data[task_id]->faction_reward ? 1 : 0; // faction booled + tdd2->coin_reward = task_data->cash_reward; + tdd2->xp_reward = task_data->experience_reward ? 1 : 0; // just booled + tdd2->faction_reward = task_data->faction_reward ? 1 : 0; // faction booled Ptr = (char *) tdd2 + sizeof(TaskDescriptionData2_Struct); // we actually have 2 strings here. One is max length 96 and not parsed for item links // We actually skipped past that string incorrectly before, so TODO: fix item link string - sprintf(Ptr, "%s", m_task_data[task_id]->reward.c_str()); - Ptr += m_task_data[task_id]->reward.length() + 1; + sprintf(Ptr, "%s", task_data->reward.c_str()); + Ptr += task_data->reward.length() + 1; // second string is parsed for item links - sprintf(Ptr, "%s", m_task_data[task_id]->item_link.c_str()); - Ptr += m_task_data[task_id]->item_link.length() + 1; + sprintf(Ptr, "%s", task_data->item_link.c_str()); + Ptr += task_data->item_link.length() + 1; tdt = (TaskDescriptionTrailer_Struct *) Ptr; // shared tasks show radiant/ebon crystal reward, non-shared tasks show generic points - tdt->Points = m_task_data[task_id]->reward_points; + tdt->Points = task_data->reward_points; tdt->has_reward_selection = 0; // TODO: new rewards window @@ -1265,7 +1267,7 @@ bool TaskManager::LoadClientState(Client *client, ClientTaskState *client_task_s // this should just load from the tasks table auto type = task_manager->GetTaskType(character_task.taskid); - if ((task_id < 0) || (task_id >= MAXTASKS)) { + if (task_id < 0) { LogTasks( "[LoadClientState] Error: task_id [{}] out of range while loading character tasks from database", task_id @@ -1324,7 +1326,7 @@ bool TaskManager::LoadClientState(Client *client, ClientTaskState *client_task_s for (auto &character_activity: character_activities) { int task_id = character_activity.taskid; - if ((task_id < 0) || (task_id >= MAXTASKS)) { + if (task_id < 0) { LogTasks( "[LoadClientState] Error: task_id [{}] out of range while loading character activities from database character_id [{}]", task_id, @@ -1415,7 +1417,7 @@ bool TaskManager::LoadClientState(Client *client, ClientTaskState *client_task_s for (auto &character_completed_task: character_completed_tasks) { int task_id = character_completed_task.taskid; - if ((task_id <= 0) || (task_id >= MAXTASKS)) { + if (task_id <= 0) { LogError("[TASKS]Task ID [{}] out of range while loading completed tasks from database", task_id); continue; } @@ -1445,13 +1447,13 @@ bool TaskManager::LoadClientState(Client *client, ClientTaskState *client_task_s // If activity_id is -1, Mark all the non-optional tasks as completed. if (activity_id < 0) { - TaskInformation *task = m_task_data[task_id]; - if (task == nullptr) { + const auto task_data = GetTaskData(task_id); + if (!task_data) { continue; } - for (int i = 0; i < task->activity_count; i++) { - if (!task->activity_information[i].optional) { + for (int i = 0; i < task_data->activity_count; i++) { + if (!task_data->activity_information[i].optional) { completed_task_information.activity_done[i] = true; } } @@ -1470,9 +1472,9 @@ bool TaskManager::LoadClientState(Client *client, ClientTaskState *client_task_s std::string query = StringFormat( "SELECT `taskid` FROM character_enabledtasks " - "WHERE `charid` = %i AND `taskid` >0 AND `taskid` < %i " + "WHERE `charid` = %i AND `taskid` > 0 " "ORDER BY `taskid` ASC", - character_id, MAXTASKS + character_id ); auto results = database.QueryDatabase(query); @@ -1492,7 +1494,8 @@ bool TaskManager::LoadClientState(Client *client, ClientTaskState *client_task_s if (task_id == TASKSLOTEMPTY) { continue; } - if (!m_task_data[task_id]) { + const auto task_data = GetTaskData(task_id); + if (!task_data) { client->Message( Chat::Red, "Active Task Slot %i, references a task (%i), that does not exist. " @@ -1505,13 +1508,13 @@ bool TaskManager::LoadClientState(Client *client, ClientTaskState *client_task_s client_task_state->m_active_tasks[task_index].task_id = TASKSLOTEMPTY; continue; } - for (int activity_index = 0; activity_index < m_task_data[task_id]->activity_count; activity_index++) { + for (int activity_index = 0; activity_index < task_data->activity_count; activity_index++) { if (client_task_state->m_active_tasks[task_index].activity[activity_index].activity_id != activity_index) { client->Message( Chat::Red, "Active Task %i, %s. activity_information count does not match expected value." "Removing from memory. Contact a GM to resolve this.", - task_id, m_task_data[task_id]->title.c_str() + task_id, task_data->title.c_str() ); LogTasks( @@ -1544,9 +1547,9 @@ bool TaskManager::LoadClientState(Client *client, ClientTaskState *client_task_s client_task_state->m_active_task.updated ); - TaskInformation *p_task_data = task_manager->m_task_data[client_task_state->m_active_task.task_id]; - if (p_task_data != nullptr) { - for (int i = 0; i < p_task_data->activity_count; i++) { + const auto task_data = GetTaskData(client_task_state->m_active_task.task_id); + if (task_data) { + for (int i = 0; i < task_data->activity_count; i++) { if (client_task_state->m_active_task.activity[i].activity_id >= 0) { LogTasksDetail( "[LoadClientState] -- character_id [{}] task [{}] activity_id [{}] done_count [{}] activity_state [{}] updated [{}]", @@ -1667,10 +1670,10 @@ void TaskManager::SyncClientSharedTaskWithPersistedState(Client *c, ClientTaskSt if (!shared_task->was_rewarded && IsActiveTaskComplete(*shared_task)) { LogTasksDetail("[LoadClientState] Syncing shared task completion for client [{}]", c->GetName()); - auto task_info = task_manager->m_task_data[shared_task->task_id]; - cts->AddReplayTimer(c, *shared_task, *task_info); // live updates a fresh timer - cts->DispatchEventTaskComplete(c, *shared_task, task_info->activity_count - 1); - cts->RewardTask(c, task_info, *shared_task); + const auto task_data = GetTaskData(shared_task->task_id); + cts->AddReplayTimer(c, *shared_task, *task_data); // live updates a fresh timer + cts->DispatchEventTaskComplete(c, *shared_task, task_data->activity_count - 1); + cts->RewardTask(c, task_data, *shared_task); } SaveClientState(c, cts); @@ -1712,7 +1715,7 @@ void TaskManager::SyncClientSharedTaskRemoveLocalIfNotExists(Client *c, ClientTa CharacterActivitiesRepository::DeleteWhere(database, delete_where); c->MessageString(Chat::Yellow, TaskStr::NO_LONGER_MEMBER_TITLE, - m_task_data[cts->m_active_shared_task.task_id]->title.c_str()); + m_task_data[cts->m_active_shared_task.task_id].title.c_str()); // remove as active task if doesn't exist cts->m_active_shared_task = {}; @@ -1813,11 +1816,16 @@ void TaskManager::HandleUpdateTasksOnKill(Client* client, NPC* npc) bool TaskManager::IsActiveTaskComplete(ClientTaskInformation& client_task) { - auto task_info = task_manager->m_task_data[client_task.task_id]; - for (int i = 0; i < task_info->activity_count; ++i) + const auto task_data = GetTaskData(client_task.task_id); + if (!task_data) + { + return false; + } + + for (int i = 0; i < task_data->activity_count; ++i) { if (client_task.activity[i].activity_state != ActivityCompleted && - !task_info->activity_information[i].optional) + !task_data->activity_information[i].optional) { return false; } diff --git a/zone/task_manager.h b/zone/task_manager.h index 949be9f0a..cbf723b5d 100644 --- a/zone/task_manager.h +++ b/zone/task_manager.h @@ -18,8 +18,6 @@ class Mob; class TaskManager { public: - TaskManager(); - ~TaskManager(); int GetActivityCount(int task_id); bool LoadTasks(int single_task = 0); void ReloadGoalLists(); @@ -69,10 +67,17 @@ public: void HandleUpdateTasksOnKill(Client* client, NPC* npc); + const std::unordered_map& GetTaskData() const { return m_task_data; } + TaskInformation* GetTaskData(int task_id) + { + auto it = m_task_data.find(task_id); + return it != m_task_data.end() ? &it->second : nullptr; + } + private: TaskGoalListManager m_goal_list_manager; - TaskInformation *m_task_data[MAXTASKS]{}; std::vector m_task_sets[MAXTASKSETS]; + std::unordered_map m_task_data; void SendActiveTaskDescription( Client *client, int task_id,