diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index 6240222d4..e9ac04939 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -3897,11 +3897,11 @@ struct TaskActivityShort_Struct { struct TaskActivityComplete_Struct { uint32 TaskIndex; - uint32 unknown2; // 0x00000002 - uint32 unknown3; + uint32 TaskType; // task, shared task, quest + uint32 TaskID; // must match uint32 ActivityID; - uint32 unknown4; // 0x00000001 - uint32 unknown5; // 0x00000001 + uint32 task_completed; // Broadcasts "Task '%1' Completed" it not 0 and "Task '%1' Failed." if 0 + uint32 stage_complete; // Broadcasts "Task Stage Completed" }; #if 0 diff --git a/zone/client.h b/zone/client.h index 989edf7dd..cb4dbb1ba 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1001,8 +1001,8 @@ public: // Task System Methods void LoadClientTaskState(); void RemoveClientTaskState(); - void SendTaskActivityComplete(int TaskID, int ActivityID, int TaskIndex, int TaskIncomplete=1); - void SendTaskFailed(int TaskID, int TaskIndex); + void SendTaskActivityComplete(int TaskID, int ActivityID, int TaskIndex, TaskType type, int TaskIncomplete=1); + void SendTaskFailed(int TaskID, int TaskIndex, TaskType type); void SendTaskComplete(int TaskIndex); inline ClientTaskState *GetTaskState() const { return taskstate; } diff --git a/zone/tasks.cpp b/zone/tasks.cpp index 79542510c..b77d8c911 100644 --- a/zone/tasks.cpp +++ b/zone/tasks.cpp @@ -1468,43 +1468,53 @@ bool ClientTaskState::UpdateTasksByNPC(Client *c, int ActivityType, int NPCTypeI // If the client has no tasks, there is nothing further to check. - if(!taskmanager || ActiveTaskCount == 0) return false; + if (!taskmanager || (ActiveTaskCount == 0 && ActiveTask.TaskID == TASKSLOTEMPTY)) // could be better ... + return false; - for(int i=0; iTaskID == TASKSLOTEMPTY) + continue; // Check if there are any active kill activities for this task - TaskInformation* Task = taskmanager->Tasks[ActiveQuests[i].TaskID]; + auto Task = taskmanager->Tasks[cur_task->TaskID]; - if(Task == nullptr) return false; + if (Task == nullptr) + return false; - for(int j=0; jActivityCount; j++) { + for (int j = 0; j < Task->ActivityCount; j++) { // We are not interested in completed or hidden activities - if(ActiveQuests[i].Activity[j].State != ActivityActive) continue; + if (cur_task->Activity[j].State != ActivityActive) + continue; // We are only interested in Kill activities - if(Task->Activity[j].Type != ActivityType) continue; + if (Task->Activity[j].Type != ActivityType) + continue; // Is there a zone restriction on the activity ? - if((Task->Activity[j].ZoneID >0) && (Task->Activity[j].ZoneID != (int)zone->GetZoneID())) { - Log(Logs::General, Logs::Tasks, "[UPDATE] Char: %s Task: %i, Activity %i, Activity type %i for NPC %i failed zone check", - c->GetName(), ActiveQuests[i].TaskID, j, ActivityType, NPCTypeID); + if ((Task->Activity[j].ZoneID > 0) && (Task->Activity[j].ZoneID != (int)zone->GetZoneID())) { + Log(Logs::General, Logs::Tasks, + "[UPDATE] Char: %s Task: %i, Activity %i, Activity type %i for NPC %i failed zone " + "check", + c->GetName(), cur_task->TaskID, j, ActivityType, NPCTypeID); continue; } // Is the activity to kill this type of NPC ? - switch(Task->Activity[j].GoalMethod) { + switch (Task->Activity[j].GoalMethod) { - case METHODSINGLEID: - if(Task->Activity[j].GoalID != NPCTypeID) continue; - break; - - case METHODLIST: - if(!taskmanager->GoalListManager.IsInList(Task->Activity[j].GoalID, - NPCTypeID)) continue; - break; - - default: - // If METHODQUEST, don't update the activity here + case METHODSINGLEID: + if (Task->Activity[j].GoalID != NPCTypeID) continue; + break; + + case METHODLIST: + if (!taskmanager->GoalListManager.IsInList(Task->Activity[j].GoalID, NPCTypeID)) + continue; + break; + + default: + // If METHODQUEST, don't update the activity here + continue; } // We found an active task to kill this type of NPC, so increment the done count Log(Logs::General, Logs::Tasks, "[UPDATE] Calling increment done count ByNPC"); @@ -1521,26 +1531,32 @@ int ClientTaskState::ActiveSpeakTask(int NPCTypeID) { // This method is to be used from Perl quests only and returns the TaskID of the first // active task found which has an active SpeakWith activity for this NPC. - if(!taskmanager || ActiveTaskCount == 0) return 0; + if (!taskmanager || (ActiveTaskCount == 0 && ActiveTask.TaskID == TASKSLOTEMPTY)) // could be better ... + return 0; - for(int i=0; iTaskID == TASKSLOTEMPTY) + continue; - TaskInformation* Task = taskmanager->Tasks[ActiveQuests[i].TaskID]; + TaskInformation* Task = taskmanager->Tasks[cur_task->TaskID]; - if(Task == nullptr) continue; + if (Task == nullptr) + continue; - for(int j=0; jActivityCount; j++) { + for (int j = 0; j < Task->ActivityCount; j++) { // We are not interested in completed or hidden activities - if(ActiveQuests[i].Activity[j].State != ActivityActive) continue; - if(Task->Activity[j].Type != ActivitySpeakWith) continue; - // Is there a zone restriction on the activity ? - if((Task->Activity[j].ZoneID >0) && (Task->Activity[j].ZoneID != (int)zone->GetZoneID())) { + if (cur_task->Activity[j].State != ActivityActive) + continue; + if (Task->Activity[j].Type != ActivitySpeakWith) + continue; + // Is there a zone restriction on the activity ? + if (Task->Activity[j].ZoneID > 0 && Task->Activity[j].ZoneID != (int)zone->GetZoneID()) continue; - } // Is the activity to speak with this type of NPC ? - if((Task->Activity[j].GoalMethod == METHODQUEST) && - (Task->Activity[j].GoalID == NPCTypeID)) return ActiveQuests[i].TaskID; + if (Task->Activity[j].GoalMethod == METHODQUEST && Task->Activity[j].GoalID == NPCTypeID) + return cur_task->TaskID; } } return 0; @@ -1551,27 +1567,34 @@ int ClientTaskState::ActiveSpeakActivity(int NPCTypeID, int TaskID) { // This method is to be used from Perl quests only and returns the ActivityID of the first // active activity found in the specified task which is to SpeakWith this NPC. - if(!taskmanager || ActiveTaskCount == 0) return -1; - if((TaskID<=0) || (TaskID>=MAXTASKS)) return -1; + if (!taskmanager || (ActiveTaskCount == 0 && ActiveTask.TaskID == TASKSLOTEMPTY)) // could be better ... + return -1; + if (TaskID <= 0 || TaskID >= MAXTASKS) + return -1; - for(int i=0; iTaskID != TaskID) + continue; - TaskInformation* Task = taskmanager->Tasks[ActiveQuests[i].TaskID]; + TaskInformation* Task = taskmanager->Tasks[cur_task->TaskID]; - if(Task == nullptr) continue; + if (Task == nullptr) + continue; - for(int j=0; jActivityCount; j++) { + for (int j = 0; j < Task->ActivityCount; j++) { // We are not interested in completed or hidden activities - if(ActiveQuests[i].Activity[j].State != ActivityActive) continue; - if(Task->Activity[j].Type != ActivitySpeakWith) continue; - // Is there a zone restriction on the activity ? - if((Task->Activity[j].ZoneID >0) && (Task->Activity[j].ZoneID != (int)zone->GetZoneID())) { + if (cur_task->Activity[j].State != ActivityActive) + continue; + if (Task->Activity[j].Type != ActivitySpeakWith) + continue; + // Is there a zone restriction on the activity ? + if (Task->Activity[j].ZoneID > 0 && Task->Activity[j].ZoneID != (int)zone->GetZoneID()) continue; - } // Is the activity to speak with this type of NPC ? - if((Task->Activity[j].GoalMethod == METHODQUEST) && - (Task->Activity[j].GoalID == NPCTypeID)) return j; + if (Task->Activity[j].GoalMethod == METHODQUEST && Task->Activity[j].GoalID == NPCTypeID) + return j; } return 0; } @@ -1588,24 +1611,31 @@ void ClientTaskState::UpdateTasksForItem(Client *c, ActivityType Type, int ItemI Log(Logs::General, Logs::Tasks, "[UPDATE] ClientTaskState::UpdateTasksForItem(%d,%d)", Type, ItemID); - if(ActiveTaskCount == 0) return; + if (!taskmanager || (ActiveTaskCount == 0 && ActiveTask.TaskID == TASKSLOTEMPTY)) // could be better ... + return; - for(int i=0; iTaskID == TASKSLOTEMPTY) + continue; // Check if there are any active loot activities for this task - TaskInformation* Task = taskmanager->Tasks[ActiveQuests[i].TaskID]; + TaskInformation* Task = taskmanager->Tasks[cur_task->TaskID]; - if(Task == nullptr) return; + if (Task == nullptr) + return; - for(int j=0; jActivityCount; j++) { + for (int j = 0; j < Task->ActivityCount; j++) { // We are not interested in completed or hidden activities - if(ActiveQuests[i].Activity[j].State != ActivityActive) continue; + if (cur_task->Activity[j].State != ActivityActive) + continue; // We are only interested in the ActivityType we were called with - if(Task->Activity[j].Type != (int)Type) continue; + if (Task->Activity[j].Type != (int)Type) + continue; // Is there a zone restriction on the activity ? - if((Task->Activity[j].ZoneID >0) && (Task->Activity[j].ZoneID != (int)zone->GetZoneID())) { + if (Task->Activity[j].ZoneID > 0 && Task->Activity[j].ZoneID != (int)zone->GetZoneID()) { Log(Logs::General, Logs::Tasks, "[UPDATE] Char: %s Activity type %i for Item %i failed zone check", c->GetName(), Type, ItemID); continue; @@ -1635,114 +1665,133 @@ void ClientTaskState::UpdateTasksForItem(Client *c, ActivityType Type, int ItemI return; } -void ClientTaskState::UpdateTasksOnExplore(Client *c, int ExploreID) { +void ClientTaskState::UpdateTasksOnExplore(Client *c, int ExploreID) +{ // If the client has no tasks, there is nothing further to check. Log(Logs::General, Logs::Tasks, "[UPDATE] ClientTaskState::UpdateTasksOnExplore(%i)", ExploreID); - if(ActiveTaskCount == 0) return; + if (!taskmanager || (ActiveTaskCount == 0 && ActiveTask.TaskID == TASKSLOTEMPTY)) // could be better ... + return; - for(int i=0; iTaskID == TASKSLOTEMPTY) + continue; // Check if there are any active explore activities for this task - TaskInformation* Task = taskmanager->Tasks[ActiveQuests[i].TaskID]; + TaskInformation *Task = taskmanager->Tasks[cur_task->TaskID]; - if(Task == nullptr) return; + if (Task == nullptr) + return; - for(int j=0; jActivityCount; j++) { + for (int j = 0; j < Task->ActivityCount; j++) { // We are not interested in completed or hidden activities - if(ActiveQuests[i].Activity[j].State != ActivityActive) continue; + if (cur_task->Activity[j].State != ActivityActive) + continue; // We are only interested in explore activities - if(Task->Activity[j].Type != ActivityExplore) continue; - if((Task->Activity[j].ZoneID >0) && (Task->Activity[j].ZoneID != (int)zone->GetZoneID())) { - Log(Logs::General, Logs::Tasks, "[UPDATE] Char: %s Explore exploreid %i failed zone check", - c->GetName(), ExploreID); + if (Task->Activity[j].Type != ActivityExplore) + continue; + if (Task->Activity[j].ZoneID > 0 && Task->Activity[j].ZoneID != (int)zone->GetZoneID()) { + Log(Logs::General, Logs::Tasks, + "[UPDATE] Char: %s Explore exploreid %i failed zone check", c->GetName(), + ExploreID); continue; } // Is the activity to explore this area id ? - switch(Task->Activity[j].GoalMethod) { + switch (Task->Activity[j].GoalMethod) { - case METHODSINGLEID: - if(Task->Activity[j].GoalID != ExploreID) continue; - break; - - case METHODLIST: - if(!taskmanager->GoalListManager.IsInList(Task->Activity[j].GoalID, - ExploreID)) continue; - break; - - default: - // If METHODQUEST, don't update the activity here + case METHODSINGLEID: + if (Task->Activity[j].GoalID != ExploreID) continue; + break; + + case METHODLIST: + if (!taskmanager->GoalListManager.IsInList(Task->Activity[j].GoalID, ExploreID)) + continue; + break; + + default: + // If METHODQUEST, don't update the activity here + continue; } // We found an active task to explore this area, so set done count to goal count // (Only a goal count of 1 makes sense for explore activities?) Log(Logs::General, Logs::Tasks, "[UPDATE] Increment on explore"); IncrementDoneCount(c, Task, i, j, - Task->Activity[j].GoalCount - ActiveQuests[i].Activity[j].DoneCount); - + Task->Activity[j].GoalCount - cur_task->Activity[j].DoneCount); } } return; } -bool ClientTaskState::UpdateTasksOnDeliver(Client *c, std::list& Items, int Cash, int NPCTypeID) { - +bool ClientTaskState::UpdateTasksOnDeliver(Client *c, std::list &Items, int Cash, int NPCTypeID) +{ bool Ret = false; Log(Logs::General, Logs::Tasks, "[UPDATE] ClientTaskState::UpdateTasksForOnDeliver(%d)", NPCTypeID); - if(ActiveTaskCount == 0) return false; + if (!taskmanager || (ActiveTaskCount == 0 && ActiveTask.TaskID == TASKSLOTEMPTY)) // could be better ... + return false; - for(int i=0; iTaskID == TASKSLOTEMPTY) + continue; // Check if there are any active deliver activities for this task - TaskInformation* Task = taskmanager->Tasks[ActiveQuests[i].TaskID]; + TaskInformation *Task = taskmanager->Tasks[cur_task->TaskID]; - if(Task == nullptr) return false; + if (Task == nullptr) + return false; - for(int j=0; jActivityCount; j++) { + for (int j = 0; j < Task->ActivityCount; j++) { // We are not interested in completed or hidden activities - if(ActiveQuests[i].Activity[j].State != ActivityActive) continue; + if (cur_task->Activity[j].State != ActivityActive) + continue; // We are only interested in Deliver activities - if((Task->Activity[j].Type != ActivityDeliver) && - (Task->Activity[j].Type != ActivityGiveCash)) continue; + if (Task->Activity[j].Type != ActivityDeliver && Task->Activity[j].Type != ActivityGiveCash) + continue; // Is there a zone restriction on the activity ? - if((Task->Activity[j].ZoneID >0) && (Task->Activity[j].ZoneID != (int)zone->GetZoneID())) { - Log(Logs::General, Logs::Tasks, "[UPDATE] Char: %s Deliver activity failed zone check (current zone %i, need zone %i", - c->GetName(), zone->GetZoneID(), Task->Activity[j].ZoneID); + if (Task->Activity[j].ZoneID > 0 && Task->Activity[j].ZoneID != (int)zone->GetZoneID()) { + Log(Logs::General, Logs::Tasks, + "[UPDATE] Char: %s Deliver activity failed zone check (current zone %i, need zone " + "%i", + c->GetName(), zone->GetZoneID(), Task->Activity[j].ZoneID); continue; } // Is the activity to deliver to this NPCTypeID ? - if(Task->Activity[j].DeliverToNPC != NPCTypeID) continue; + if (Task->Activity[j].DeliverToNPC != NPCTypeID) + continue; // Is the activity related to these items ? // - if((Task->Activity[j].Type == ActivityGiveCash) && Cash) { + if ((Task->Activity[j].Type == ActivityGiveCash) && Cash) { Log(Logs::General, Logs::Tasks, "[UPDATE] Increment on GiveCash"); IncrementDoneCount(c, Task, i, j, Cash); Ret = true; - } - else { - for(auto& k : Items) { - switch(Task->Activity[j].GoalMethod) { + } else { + for (auto &k : Items) { + switch (Task->Activity[j].GoalMethod) { - case METHODSINGLEID: - if(Task->Activity[j].GoalID != k->GetID()) continue; - break; - - case METHODLIST: - if (!taskmanager->GoalListManager.IsInList(Task->Activity[j].GoalID, k->GetID())) - continue; - break; - - default: - // If METHODQUEST, don't update the activity here + case METHODSINGLEID: + if (Task->Activity[j].GoalID != k->GetID()) continue; + break; + + case METHODLIST: + if (!taskmanager->GoalListManager.IsInList(Task->Activity[j].GoalID, + k->GetID())) + continue; + break; + + default: + // If METHODQUEST, don't update the activity here + continue; } // We found an active task related to this item, so increment the done count Log(Logs::General, Logs::Tasks, "[UPDATE] Increment on GiveItem"); @@ -1756,74 +1805,89 @@ bool ClientTaskState::UpdateTasksOnDeliver(Client *c, std::listTaskID == TASKSLOTEMPTY) + continue; // Check if there are any active explore activities for this task - TaskInformation* Task = taskmanager->Tasks[ActiveQuests[i].TaskID]; + TaskInformation *Task = taskmanager->Tasks[cur_task->TaskID]; - if(Task == nullptr) return; + if (Task == nullptr) + return; - for(int j=0; jActivityCount; j++) { + for (int j = 0; j < Task->ActivityCount; j++) { // We are not interested in completed or hidden activities - if(ActiveQuests[i].Activity[j].State != ActivityActive) continue; + if (cur_task->Activity[j].State != ActivityActive) + continue; // We are only interested in touch activities - if(Task->Activity[j].Type != ActivityTouch) continue; - if(Task->Activity[j].GoalMethod != METHODSINGLEID) continue; - if(Task->Activity[j].ZoneID != ZoneID) { + if (Task->Activity[j].Type != ActivityTouch) + continue; + if (Task->Activity[j].GoalMethod != METHODSINGLEID) + continue; + if (Task->Activity[j].ZoneID != ZoneID) { Log(Logs::General, Logs::Tasks, "[UPDATE] Char: %s Touch activity failed zone check", - c->GetName()); + c->GetName()); continue; } // We found an active task to zone into this zone, so set done count to goal count // (Only a goal count of 1 makes sense for touch activities?) Log(Logs::General, Logs::Tasks, "[UPDATE] Increment on Touch"); IncrementDoneCount(c, Task, i, j, - Task->Activity[j].GoalCount - ActiveQuests[i].Activity[j].DoneCount); + Task->Activity[j].GoalCount - cur_task->Activity[j].DoneCount); } } return; } -void ClientTaskState::IncrementDoneCount(Client *c, TaskInformation* Task, int TaskIndex, int ActivityID, int Count, bool ignore_quest_update) { +void ClientTaskState::IncrementDoneCount(Client *c, TaskInformation *Task, int TaskIndex, int ActivityID, int Count, + bool ignore_quest_update) +{ Log(Logs::General, Logs::Tasks, "[UPDATE] IncrementDoneCount"); - ActiveQuests[TaskIndex].Activity[ActivityID].DoneCount += Count; + auto info = GetClientTaskInfo(Task->type, TaskIndex); - if(ActiveQuests[TaskIndex].Activity[ActivityID].DoneCount > Task->Activity[ActivityID].GoalCount) - ActiveQuests[TaskIndex].Activity[ActivityID].DoneCount = Task->Activity[ActivityID].GoalCount; + if (info == nullptr) + return; + + info->Activity[ActivityID].DoneCount += Count; + + if(info->Activity[ActivityID].DoneCount > Task->Activity[ActivityID].GoalCount) + info->Activity[ActivityID].DoneCount = Task->Activity[ActivityID].GoalCount; if (!ignore_quest_update){ char buf[24]; - snprintf(buf, 23, "%d %d %d", ActiveQuests[TaskIndex].Activity[ActivityID].DoneCount, ActiveQuests[TaskIndex].Activity[ActivityID].ActivityID, ActiveQuests[TaskIndex].TaskID); + snprintf(buf, 23, "%d %d %d", info->Activity[ActivityID].DoneCount, info->Activity[ActivityID].ActivityID, info->TaskID); buf[23] = '\0'; parse->EventPlayer(EVENT_TASK_UPDATE, c, buf, 0); } - ActiveQuests[TaskIndex].Activity[ActivityID].Updated=true; + info->Activity[ActivityID].Updated=true; // Have we reached the goal count for this activity ? - if(ActiveQuests[TaskIndex].Activity[ActivityID].DoneCount >= Task->Activity[ActivityID].GoalCount) { + if(info->Activity[ActivityID].DoneCount >= Task->Activity[ActivityID].GoalCount) { Log(Logs::General, Logs::Tasks, "[UPDATE] Done (%i) = Goal (%i) for Activity %i", - ActiveQuests[TaskIndex].Activity[ActivityID].DoneCount, + info->Activity[ActivityID].DoneCount, Task->Activity[ActivityID].GoalCount, ActivityID); // Flag the activity as complete - ActiveQuests[TaskIndex].Activity[ActivityID].State = ActivityCompleted; + info->Activity[ActivityID].State = ActivityCompleted; // Unlock subsequent activities for this task - bool TaskComplete = UnlockActivities(c->CharacterID(), ActiveQuests[TaskIndex]); // TODO: fix this function + bool TaskComplete = UnlockActivities(c->CharacterID(), *info); Log(Logs::General, Logs::Tasks, "[UPDATE] TaskCompleted is %i", TaskComplete); // and by the 'Task Stage Completed' message - c->SendTaskActivityComplete(ActiveQuests[TaskIndex].TaskID, ActivityID, TaskIndex); + c->SendTaskActivityComplete(info->TaskID, ActivityID, TaskIndex, Task->type); // Send the updated task/activity list to the client taskmanager->SendSingleActiveTaskToClient(c, ActiveQuests[TaskIndex], TaskComplete, false); // Inform the client the task has been updated, both by a chat message @@ -1832,13 +1896,13 @@ void ClientTaskState::IncrementDoneCount(Client *c, TaskInformation* Task, int T if(Task->Activity[ActivityID].GoalMethod != METHODQUEST) { if (!ignore_quest_update){ char buf[24]; - snprintf(buf, 23, "%d %d", ActiveQuests[TaskIndex].TaskID, ActiveQuests[TaskIndex].Activity[ActivityID].ActivityID); + snprintf(buf, 23, "%d %d", info->TaskID, info->Activity[ActivityID].ActivityID); buf[23] = '\0'; parse->EventPlayer(EVENT_TASK_STAGE_COMPLETE, c, buf, 0); } /* QS: PlayerLogTaskUpdates :: Update */ if (RuleB(QueryServ, PlayerLogTaskUpdates)){ - std::string event_desc = StringFormat("Task Stage Complete :: taskid:%i activityid:%i donecount:%i in zoneid:%i instid:%i", ActiveQuests[TaskIndex].TaskID, ActiveQuests[TaskIndex].Activity[ActivityID].ActivityID, ActiveQuests[TaskIndex].Activity[ActivityID].DoneCount, c->GetZoneID(), c->GetInstanceID()); + std::string event_desc = StringFormat("Task Stage Complete :: taskid:%i activityid:%i donecount:%i in zoneid:%i instid:%i", info->TaskID, info->Activity[ActivityID].ActivityID, info->Activity[ActivityID].DoneCount, c->GetZoneID(), c->GetInstanceID()); QServ->PlayerLogEvent(Player_Log_Task_Updates, c->CharacterID(), event_desc); } } @@ -1848,21 +1912,21 @@ void ClientTaskState::IncrementDoneCount(Client *c, TaskInformation* Task, int T // client. This is the same sequence the packets are sent on live. if(TaskComplete) { char buf[24]; - snprintf(buf, 23, "%d %d %d", ActiveQuests[TaskIndex].Activity[ActivityID].DoneCount, ActiveQuests[TaskIndex].Activity[ActivityID].ActivityID, ActiveQuests[TaskIndex].TaskID); + snprintf(buf, 23, "%d %d %d", info->Activity[ActivityID].DoneCount, info->Activity[ActivityID].ActivityID, info->TaskID); buf[23] = '\0'; parse->EventPlayer(EVENT_TASK_COMPLETE, c, buf, 0); /* QS: PlayerLogTaskUpdates :: Complete */ if (RuleB(QueryServ, PlayerLogTaskUpdates)){ - std::string event_desc = StringFormat("Task Complete :: taskid:%i activityid:%i donecount:%i in zoneid:%i instid:%i", ActiveQuests[TaskIndex].TaskID, ActiveQuests[TaskIndex].Activity[ActivityID].ActivityID, ActiveQuests[TaskIndex].Activity[ActivityID].DoneCount, c->GetZoneID(), c->GetInstanceID()); + std::string event_desc = StringFormat("Task Complete :: taskid:%i activityid:%i donecount:%i in zoneid:%i instid:%i", info->TaskID, info->Activity[ActivityID].ActivityID, info->Activity[ActivityID].DoneCount, c->GetZoneID(), c->GetInstanceID()); QServ->PlayerLogEvent(Player_Log_Task_Updates, c->CharacterID(), event_desc); } taskmanager->SendCompletedTasksToClient(c, this); - c->SendTaskActivityComplete(ActiveQuests[TaskIndex].TaskID, 0, TaskIndex, false); + c->SendTaskActivityComplete(info->TaskID, 0, TaskIndex, Task->type, 0); taskmanager->SaveClientState(c, this); //c->SendTaskComplete(TaskIndex); - c->CancelTask(TaskIndex, TaskType::Quest); // TODO: fix + c->CancelTask(TaskIndex, Task->type); //if(Task->RewardMethod != METHODQUEST) RewardTask(c, Task); // If Experience and/or cash rewards are set, reward them from the task even if RewardMethod is METHODQUEST RewardTask(c, Task); @@ -2007,7 +2071,7 @@ void ClientTaskState::FailTask(Client *c, int TaskID) { for(int i=0; iSendTaskFailed(ActiveQuests[i].TaskID, i); + c->SendTaskFailed(ActiveQuests[i].TaskID, i, TaskType::Quest); // TODO: fix // Remove the task from the client c->CancelTask(i, TaskType::Quest); // TODO: fix return; @@ -2231,7 +2295,7 @@ void ClientTaskState::TaskPeriodicChecks(Client *c) { if(TaskOutOfTime(i)) { // Send Red Task Failed Message - c->SendTaskFailed(ActiveQuests[i].TaskID, i); + c->SendTaskFailed(ActiveQuests[i].TaskID, i, TaskType::Quest); // TODO: fix // Remove the task from the client c->CancelTask(i, TaskType::Quest); // TODO: Fix // It is a conscious decision to only fail one task per call to this method, @@ -2362,8 +2426,8 @@ void ClientTaskState::SendTaskHistory(Client *c, int TaskIndex) { } -void Client::SendTaskActivityComplete(int TaskID, int ActivityID, int TaskIndex, int TaskIncomplete) { - +void Client::SendTaskActivityComplete(int TaskID, int ActivityID, int TaskIndex, TaskType type, int TaskIncomplete) +{ // 0x54eb TaskActivityComplete_Struct* tac; @@ -2372,15 +2436,12 @@ void Client::SendTaskActivityComplete(int TaskID, int ActivityID, int TaskIndex, tac = (TaskActivityComplete_Struct*)outapp->pBuffer; - //tac->unknown1 = 0x00000000; tac->TaskIndex = TaskIndex; - tac->unknown2 = 0x00000002; - //tac->unknown3 = 0x00000000; - tac->unknown3 = TaskID; // Correct ? + tac->TaskType = static_cast(type); + tac->TaskID = TaskID; tac->ActivityID = ActivityID; - tac->unknown4 = 0x00000001; - //tac->unknown5 = 0x00000001; - tac->unknown5 = TaskIncomplete; + tac->task_completed = 0x00000001; + tac->stage_complete = TaskIncomplete; QueuePacket(outapp); @@ -2388,8 +2449,8 @@ void Client::SendTaskActivityComplete(int TaskID, int ActivityID, int TaskIndex, } -void Client::SendTaskFailed(int TaskID, int TaskIndex) { - +void Client::SendTaskFailed(int TaskID, int TaskIndex, TaskType type) +{ // 0x54eb char buf[24]; snprintf(buf, 23, "%d", TaskID); @@ -2402,15 +2463,12 @@ void Client::SendTaskFailed(int TaskID, int TaskIndex) { tac = (TaskActivityComplete_Struct*)outapp->pBuffer; - //tac->unknown1 = 0x00000000; tac->TaskIndex = TaskIndex; - tac->unknown2 = 0x00000002; - //tac->unknown3 = 0x00000000; - tac->unknown3 = TaskID; // Correct ? + tac->TaskType = static_cast(type); + tac->TaskID = TaskID; tac->ActivityID = 0; - tac->unknown4 = 0x00000000; //Fail - //tac->unknown5 = 0x00000001; - tac->unknown5 = 0; // 0 for task complete or failed. + tac->task_completed = 0; //Fail + tac->stage_complete = 0; // 0 for task complete or failed. Log(Logs::General, Logs::Tasks, "[UPDATE] TaskFailed"); diff --git a/zone/tasks.h b/zone/tasks.h index 01c08f4a1..91a264f67 100644 --- a/zone/tasks.h +++ b/zone/tasks.h @@ -241,9 +241,33 @@ public: private: bool UnlockActivities(int CharID, ClientTaskInformation &task_info); void IncrementDoneCount(Client *c, TaskInformation *Task, int TaskIndex, int ActivityID, int Count = 1, bool ignore_quest_update = false); + inline ClientTaskInformation *GetClientTaskInfo(TaskType type, int index) + { + ClientTaskInformation *info = nullptr; + switch (type) { + case TaskType::Task: + if (index == 0) + info = &ActiveTask; + break; + case TaskType::Shared: + break; + case TaskType::Quest: + if (index < MAXACTIVEQUESTS) + info = &ActiveQuests[index]; + break; + default: + break; + } + return info; + } int ActiveTaskCount; - ClientTaskInformation ActiveTask; // only one - ClientTaskInformation ActiveQuests[MAXACTIVEQUESTS]; + union { // easier to loop over + struct { + ClientTaskInformation ActiveTask; // only one + ClientTaskInformation ActiveQuests[MAXACTIVEQUESTS]; + }; + ClientTaskInformation ActiveTasks[MAXACTIVEQUESTS + 1]; + }; // Shared tasks should be limited to 1 as well std::vector EnabledTasks; std::vector CompletedTasks;