#ifndef EQEMU_TASK_CLIENT_STATE_H #define EQEMU_TASK_CLIENT_STATE_H #include "tasks.h" #include "../common/types.h" #include #include #include #include constexpr float MAX_TASK_SELECT_DISTANCE = 60.0f; // client closes window at this distance struct TaskOffer { int task_id; 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 Mob* mob = 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: ClientTaskState(); ~ClientTaskState(); void ShowClientTasks(Client* who, Client *to); inline int GetActiveTaskCount() { return m_active_task_count; } int GetActiveTaskID(int index); bool IsTaskActivityCompleted(TaskType task_type, int index, int activity_id); int GetTaskActivityDoneCount(TaskType task_type, int index, int activity_id); int GetTaskActivityDoneCountFromTaskID(int task_id, int activity_id); int GetTaskStartTime(TaskType task_type, int index); void AcceptNewTask(Client *client, int task_id, int npc_type_id, time_t accept_time, bool enforce_level_requirement = false); void FailTask(Client *client, int task_id); int TaskTimeLeft(int task_id); int IsTaskCompleted(int task_id); bool IsTaskActive(int task_id); bool IsTaskActivityActive(int task_id, int activity_id); ActivityState GetTaskActivityState(TaskType task_type, int index, int activity_id); void UpdateTaskActivity(Client *client, int task_id, int activity_id, int count, bool ignore_quest_update = false); void ResetTaskActivity(Client *client, int task_id, int activity_id); void CancelTask(Client *c, int sequence_number, TaskType task_type, bool remove_from_db = true); 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 type, NPC* npc); void UpdateTasksForItem(Client* client, TaskActivityType type, int item_id, int count = 1); void UpdateTasksOnLoot(Client* client, Corpse* corpse, 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::vector& items, Trade& trade, 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* c, const TaskInformation* ti, 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(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(const TaskInformation* task); void CreateTaskDynamicZone(Client* client, int task_id, DynamicZone& dz); void ListTaskTimers(Client* client); void KickPlayersSharedTask(Client* client); 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; void EndSharedTask(Client* client, bool send_fail); inline bool HasFreeTaskSlot() { return m_active_task.task_id == TASKSLOTEMPTY; } friend class TaskManager; // wrapper to call internal IncrementDoneCount void SharedTaskIncrementDoneCount( Client *client, int task_id, int activity_id, int done_count, bool ignore_quest_update = false ); const ClientTaskInformation &GetActiveSharedTask() const; bool HasActiveSharedTask(); private: 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; int DispatchEventTaskComplete(Client* client, ClientTaskInformation& client_task, int activity_id); std::pair 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); int UpdateTasks(Client* client, const TaskUpdateFilter& filter, int count = 1); int IncrementDoneCount( Client *client, const TaskInformation* task_data, int task_index, int activity_id, int count = 1, bool ignore_quest_update = false ); bool UnlockActivities(Client* client, ClientTaskInformation& task_info); inline ClientTaskInformation *GetClientTaskInfo(TaskType task_type, int index) { ClientTaskInformation *info = nullptr; switch (task_type) { case TaskType::Task: if (index == TASKSLOTTASK) { info = &m_active_task; } break; case TaskType::Shared: if (index == TASKSLOTSHAREDTASK) { info = &m_active_shared_task; } break; case TaskType::Quest: if (index < MAXACTIVEQUESTS) { info = &m_active_quests[index]; } break; default: break; } return info; } union { // easier to loop over struct { ClientTaskInformation m_active_task; // only one // acts as a read-only "view" of data that is managed by world and the internal task // system largely behaves like other tasks but shims logic to world where necessary ClientTaskInformation m_active_shared_task; // only one ClientTaskInformation m_active_quests[MAXACTIVEQUESTS]; }; ClientTaskInformation m_active_tasks[MAXACTIVEQUESTS + 2] = {}; }; // Shared tasks should be limited to 1 as well int m_active_task_count; std::vector m_enabled_tasks; std::vector m_completed_tasks; int m_last_completed_task_loaded; std::vector m_last_offers; bool m_has_explore_task = false; static void ShowClientTaskInfoMessage(ClientTaskInformation *task, Client *c); void SyncSharedTaskZoneClientDoneCountState( Client *p_client, TaskType type, int task_index, int activity_id, uint32 done_count ); bool HasActiveTasks(); }; #endif //EQEMU_TASK_CLIENT_STATE_H