[Tasks] Replace task goals with explicit fields (#2402)

The task goal system made implementing tasks a little confusing since
the goal could be ambiguous depending on type. This also didn't support
filtering on multiple goals (e.g. looting items from matching npc names
inside an area). Deliver types could specify an npc id in `delivertonpc`
but the database may have multiple npcs with the same name or a task
might want to match partial npc names.

This replaces goalids with explicit fields for npcs, items, proximity
areas, and touch switch ids. These changes make managing task data
easier without needing to update multiple tables and allows filtering
task updates by multiple criteria. To mitigate any performance impact
from merging task proximities, only clients with explore tasks in the
current zone are checked during client movement updates.

Items and npcs still support goallists but it would be possible to
denormalize entries into delimited strings to combine with the match
lists. This would also decouple task goals from reward lists.

The client task update functions were refactored to run through a single
filtering function which significantly reduces duplicated code from the
legacy task system. This will also make it easier to later implement
any unhandled types.

Since the new fields will handle filtering single entries and lists
based on having values set, `goalmethod` now only distinguishes quest
controlled from source controlled.

This is a breaking api change, `taskexploredarea` has been removed
since explore ids no longer exist.
This commit is contained in:
hg
2022-09-01 20:18:21 -04:00
committed by GitHub
parent 8851b410d2
commit 7482cfc066
30 changed files with 659 additions and 1344 deletions
+36 -14
View File
@@ -16,6 +16,20 @@ struct TaskOffer
uint16_t npc_entity_id;
};
struct TaskUpdateFilter
{
int task_id = 0;
int dz_switch_id = 0;
uint32_t item_id = 0;
glm::vec4 pos;
bool use_pos = false; // if true uses pos instead of client position for area filters
bool ignore_area = false; // if true, area check is disabled
NPC* npc = nullptr;
Client* exp_client = nullptr; // used by Kill tasks to filter shared task updates
TaskActivityType type = TaskActivityType::None;
TaskMethodType method = TaskMethodType::METHODSINGLEID;
};
class ClientTaskState {
public:
@@ -41,23 +55,23 @@ public:
void CancelAllTasks(Client *client);
void RemoveTask(Client *client, int sequence_number, TaskType task_type);
void RemoveTaskByTaskID(Client *client, uint32 task_id);
bool UpdateTasksByNPC(Client *client, TaskActivityType activity_type, int npc_type_id);
void UpdateTasksForItem(Client *client, TaskActivityType activity_type, int item_id, int count = 1);
void UpdateTasksOnExplore(Client *client, int explore_id);
bool UpdateTasksOnSpeakWith(Client *client, int npc_type_id);
bool UpdateTasksOnDeliver(Client *client, std::list<EQ::ItemInstance *> &items, int cash, int npc_type_id);
bool UpdateTasksByNPC(Client* client, TaskActivityType type, NPC* npc);
void UpdateTasksForItem(Client* client, TaskActivityType type, NPC* npc, int item_id, int count = 1);
void UpdateTasksOnExplore(Client* client, const glm::vec4& loc);
bool UpdateTasksOnSpeakWith(Client* client, NPC* npc);
bool UpdateTasksOnDeliver(Client* client, std::list<EQ::ItemInstance*>& items, int cash, NPC* npc);
void UpdateTasksOnTouch(Client *client, int dz_switch_id);
void ProcessTaskProximities(Client *client, float x, float y, float z);
bool TaskOutOfTime(TaskType task_type, int index);
void TaskPeriodicChecks(Client *client);
void SendTaskHistory(Client *client, int task_index);
void RewardTask(Client *client, TaskInformation *task_information, ClientTaskInformation& client_task);
void RewardTask(Client* client, const TaskInformation* task_information, ClientTaskInformation& client_task);
void EnableTask(int character_id, int task_count, int *task_list);
void DisableTask(int character_id, int task_count, int *task_list);
bool IsTaskEnabled(int task_id);
int EnabledTaskCount(int task_set_id);
int ActiveSpeakTask(int npc_type_id);
int ActiveSpeakActivity(int npc_type_id, int task_id);
int ActiveSpeakTask(Client* client, NPC* npc);
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);
@@ -67,6 +81,7 @@ public:
void LockSharedTask(Client* client, bool lock);
void ClearLastOffers() { m_last_offers.clear(); }
bool CanAcceptNewTask(Client* client, int task_id, int npc_entity_id) const;
bool HasExploreTask(Client* client) const;
inline bool HasFreeTaskSlot() { return m_active_task.task_id == TASKSLOTEMPTY; }
@@ -85,21 +100,28 @@ public:
bool HasActiveSharedTask();
private:
void AddReplayTimer(Client *client, ClientTaskInformation& client_task, TaskInformation& task);
void DispatchEventTaskComplete(Client* client, ClientTaskInformation& client_task, int activity_id);
const TaskInformation* GetTaskData(const ClientTaskInformation& client_task) const;
void AddOffer(int task_id, uint16_t npc_entity_id) { m_last_offers.push_back({task_id, npc_entity_id}); };
void AddReplayTimer(Client *client, ClientTaskInformation& client_task, const TaskInformation& task);
bool CanUpdate(Client* client, const TaskUpdateFilter& filter, int task_id,
const ActivityInformation& activity, const ClientActivityInformation& client_activity) const;
void DispatchEventTaskComplete(Client* client, ClientTaskInformation& client_task, int activity_id);
std::pair<int, int> FindTask(Client* client, const TaskUpdateFilter& filter) const;
void RecordCompletedTask(uint32_t character_id, const TaskInformation& task, const ClientTaskInformation& client_task);
void UpdateTasksOnKill(Client* client, Client* exp_client, NPC* npc);
bool UpdateTasks(Client* client, const TaskUpdateFilter& filter, int count = 1);
void IncrementDoneCount(
Client *client,
TaskInformation *task_information,
const TaskInformation* task_information,
int task_index,
int activity_id,
int count = 1,
bool ignore_quest_update = false
);
bool UnlockActivities(int character_id, ClientTaskInformation &task_info);
bool UnlockActivities(Client* client, ClientTaskInformation& task_info);
inline ClientTaskInformation *GetClientTaskInfo(TaskType task_type, int index)
{
@@ -143,12 +165,13 @@ private:
std::vector<CompletedTaskInformation> m_completed_tasks;
int m_last_completed_task_loaded;
std::vector<TaskOffer> m_last_offers;
bool m_has_explore_task = false;
static void ShowClientTaskInfoMessage(ClientTaskInformation *task, Client *c);
void SyncSharedTaskZoneClientDoneCountState(
Client *p_client,
TaskInformation *p_information,
TaskType type,
int task_index,
int activity_id,
uint32 done_count
@@ -156,5 +179,4 @@ private:
bool HasActiveTasks();
};
#endif //EQEMU_TASK_CLIENT_STATE_H