mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
[Tasks] Change zone task data container (#2410)
This allows removal of the task id limit (MAXTASKS) There's some suspect places task data isn't verified but left unchanged If memory use becomes too high once more live data is added tasks can be stored in shared memory instead
This commit is contained in:
parent
ec857cefae
commit
efe1879115
@ -5,7 +5,6 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
|
||||
#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;
|
||||
|
||||
@ -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()
|
||||
);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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<uint32_t>(p_task_data->activity_information[i].activity_type);
|
||||
task_history_reply_data_1->ActivityType = static_cast<uint32_t>(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<int, int> 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<TaskTimerType>(task_timer.timer_type);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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<TaskType>(task.type);
|
||||
m_task_data[task_id]->duration = task.duration;
|
||||
m_task_data[task_id]->duration_code = static_cast<DurationCode>(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<AltCurrencyType>(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<TaskType>(task.type);
|
||||
task_data.duration = task.duration;
|
||||
task_data.duration_code = static_cast<DurationCode>(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<AltCurrencyType>(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<int32_t>(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<int>(m_task_data[task_id]->type),
|
||||
static_cast<int>(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<EQApplicationPacket>(OP_TaskActivity, 25);
|
||||
outapp->WriteUInt32(client_task_index);
|
||||
outapp->WriteUInt32(static_cast<uint32>(m_task_data[task_id]->type));
|
||||
outapp->WriteUInt32(static_cast<uint32>(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<uint32>(m_task_data[task_id]->type)); // task type
|
||||
buf.WriteUInt32(static_cast<uint32>(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<uint32>(m_task_data[task_id]->type);
|
||||
task_description_header->task_type = static_cast<uint32>(task_data->type);
|
||||
|
||||
task_description_header->reward_type = static_cast<int>(m_task_data[task_id]->reward_point_type);
|
||||
task_description_header->reward_type = static_cast<int>(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<uint32>(m_task_data[task_id]->duration_code);
|
||||
tdd1->dur_code = static_cast<uint32>(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;
|
||||
}
|
||||
|
||||
@ -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<uint32_t, TaskInformation>& 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<int> m_task_sets[MAXTASKSETS];
|
||||
std::unordered_map<uint32_t, TaskInformation> m_task_data;
|
||||
void SendActiveTaskDescription(
|
||||
Client *client,
|
||||
int task_id,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user