World should verify the full task to simplify things

This commit is contained in:
Michael Cook (mackal) 2019-05-18 17:26:09 -04:00
parent 358ce2ca94
commit e1bb3301a5
12 changed files with 349 additions and 343 deletions

View File

@ -151,6 +151,7 @@ SET(common_headers
fixed_memory_hash_set.h
fixed_memory_variable_hash_set.h
global_define.h
global_tasks.h
guild_base.h
guilds.h
inventory_profile.h

155
common/global_tasks.h Normal file
View File

@ -0,0 +1,155 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef GLOBAL_TASKS_H
#define GLOBAL_TASKS_H
#include <string>
#include <vector>
#include <algorithm>
#include "types.h"
/* This file contains what is needed for both zone and world managers
*/
#define MAXTASKS 10000
#define MAXTASKSETS 1000
// The Client has a hard cap of 19 active quests, 29 in SoD+
#define MAXACTIVEQUESTS 19
// The Max Chooser (Task Selector entries) is capped at 40 in the Titanium Client.
#define MAXCHOOSERENTRIES 40
// The Client has a hard cap of 20 activities per task.
#define MAXACTIVITIESPERTASK 20
// This is used to determine if a client's active task slot is empty.
#define TASKSLOTEMPTY 0
// Command Codes for worldserver ServerOP_ReloadTasks
#define RELOADTASKS 0
#define RELOADTASKGOALLISTS 1
#define RELOADTASKPROXIMITIES 2
#define RELOADTASKSETS 3
// used for timer lockouts and /tasktimers
struct TaskTimer {
int ID; // ID used in task timer (replay group)
int original_id; // original ID of the task (book keeping)
int expires; // UNIX timestamp of when it expires, what happens with DLS? Fuck it.
};
typedef enum { METHODSINGLEID = 0, METHODLIST = 1, METHODQUEST = 2 } TaskMethodType;
struct ActivityInformation {
int StepNumber;
int Type;
std::string target_name; // name mob, location -- default empty
std::string item_list; // likely defaults to empty
std::string skill_list; // IDs ; separated -- default -1
std::string spell_list; // IDs ; separated -- default 0
std::string desc_override; // overrides auto generated description -- default empty
int skill_id; // older clients, first id from above
int spell_id; // older clients, first id from above
int GoalID;
TaskMethodType GoalMethod;
int GoalCount;
int DeliverToNPC;
std::vector<int> ZoneIDs;
std::string zones; // IDs ; searated, ZoneID is the first in this list for older clients -- default empty string
bool Optional;
inline bool CheckZone(int zone_id) {
if (ZoneIDs.empty())
return true;
return std::find(ZoneIDs.begin(), ZoneIDs.end(), zone_id) != ZoneIDs.end();
}
};
typedef enum { ActivitiesSequential = 0, ActivitiesStepped = 1 } SequenceType;
enum class TaskType {
Task = 0, // can have at max 1
Shared = 1, // can have at max 1
Quest = 2, // can have at max 19 or 29 depending on client
E = 3 // can have at max 19 or 29 depending on client, not present in live anymore
};
enum class DurationCode {
None = 0,
Short = 1,
Medium = 2,
Long = 3
};
// need to capture more, shared are just Radiant/Ebon though
enum class PointType {
None = 0,
Radiant = 4,
Ebon = 5,
};
struct TaskInformation {
TaskType type;
int Duration;
DurationCode dur_code; // description for time investment for when Duration == 0
std::string Title; // max length 64
std::string Description; // max length 4000, 2048 on Tit
std::string Reward;
std::string item_link; // max length 128 older clients, item link gets own string
std::string completion_emote; // emote after completing task, yellow. Maybe should make more generic ... but yellow for now!
int RewardID;
int CashReward; // Expressed in copper
int XPReward;
int faction_reward; // just a npc_faction_id
TaskMethodType RewardMethod;
int reward_points; // DoN crystals for shared. Generic "points" for non-shared
PointType reward_type; // 4 for Radiant Crystals else Ebon crystals when shared task
int ActivityCount;
SequenceType SequenceMode;
int LastStep;
short MinLevel;
short MaxLevel;
bool Repeatable;
int replay_group; // ID of our replay timer group (0 means none)
int min_players; // shared tasks
int max_players;
int task_lock_step; // task locks after this step is completed
uint32 instance_zone_id; // instance shit
uint32 zone_version;
uint16 zone_in_zone_id;
float zone_in_x;
float zone_in_y;
uint16 zone_in_object_id;
float dest_x;
float dest_y;
float dest_z;
float dest_h;
/* int graveyard_zone_id;
float graveyard_x;
float graveyard_y;
float graveyard_z;
float graveyard_radius; */
ActivityInformation Activity[MAXACTIVITIESPERTASK];
};
typedef enum { ActivityHidden = 0, ActivityActive = 1, ActivityCompleted = 2 } ActivityState;
typedef enum { ActivityDeliver = 1, ActivityKill = 2, ActivityLoot = 3, ActivitySpeakWith = 4, ActivityExplore = 5,
ActivityTradeSkill = 6, ActivityFish = 7, ActivityForage = 8, ActivityCastOn = 9, ActivitySkillOn = 10,
ActivityTouch = 11, ActivityCollect = 13, ActivityGiveCash = 100 } ActivityType;
#endif /* !GLOBAL_TASKS_H */

View File

@ -157,7 +157,6 @@
#define ServerOP_TaskReject 0x0302
#define ServerOP_TaskAddPlayer 0x0303
#define ServerOP_TaskRemovePlayer 0x0304
#define ServerOP_TaskRequestReply 0x0305
#define ServerOP_EncapPacket 0x2007 // Packet within a packet
#define ServerOP_WorldListUpdate 0x2008

View File

@ -25,6 +25,9 @@
#include "world_config.h"
#include "../common/guilds.h"
#include "../common/string_util.h"
#include "shared_tasks.h"
#include <algorithm>
extern uint32 numplayers;
extern LoginServerList loginserverlist;
@ -50,6 +53,8 @@ ClientListEntry::ClientListEntry(uint32 in_id, uint32 iLSID, const char* iLoginN
pLFGToLevel = 0;
pLFGMatchFilter = false;
memset(pLFGComments, 0, 64);
shared_task_id = 0;
m_shared_task = nullptr;
}
ClientListEntry::ClientListEntry(uint32 in_id, uint32 iAccID, const char* iAccName, MD5& iMD5Pass, int16 iAdmin)
@ -71,6 +76,8 @@ ClientListEntry::ClientListEntry(uint32 in_id, uint32 iAccID, const char* iAccNa
pLFGToLevel = 0;
pLFGMatchFilter = false;
memset(pLFGComments, 0, 64);
shared_task_id = 0;
m_shared_task = nullptr;
}
ClientListEntry::ClientListEntry(uint32 in_id, ZoneServer* iZS, ServerClientList_Struct* scl, int8 iOnline)
@ -93,6 +100,8 @@ ClientListEntry::ClientListEntry(uint32 in_id, ZoneServer* iZS, ServerClientList
pLFGToLevel = 0;
pLFGMatchFilter = false;
memset(pLFGComments, 0, 64);
shared_task_id = 0;
m_shared_task = nullptr;
if (iOnline >= CLE_Status_Zoning)
Update(iZS, scl, iOnline);
@ -105,6 +114,8 @@ ClientListEntry::~ClientListEntry() {
Camp(); // updates zoneserver's numplayers
client_list.RemoveCLEReferances(this);
}
if (m_shared_task != nullptr)
m_shared_task->MemberLeftGame(this);
for (auto &elem : tell_queue)
safe_delete_array(elem);
tell_queue.clear();
@ -248,6 +259,10 @@ void ClientListEntry::ClearVars(bool iAll) {
pLFG = 0;
gm = 0;
pClientVersion = 0;
shared_task_id = 0;
if (m_shared_task != nullptr)
m_shared_task->MemberLeftGame(this);
m_shared_task = nullptr;
for (auto &elem : tell_queue)
safe_delete_array(elem);
tell_queue.clear();
@ -331,3 +346,34 @@ void ClientListEntry::ProcessTellQueue()
return;
}
/*
* returns expire timestamp
*/
int ClientListEntry::GetTaskLockoutExpire(int id) const
{
auto it = std::find_if(m_task_replay_timers.begin(), m_task_replay_timers.end(),
[id](const TaskTimer &a) { return a.ID == id; });
if (it != m_task_replay_timers.end())
return it->expires;
return 0;
}
/*
* returns seconds until expires
* returns <= 0 if expired
*/
int ClientListEntry::GetTaskLockoutTimeLeft(int id) const
{
auto it = std::find_if(m_task_replay_timers.begin(), m_task_replay_timers.end(),
[id](const TaskTimer &a) { return a.ID == id; });
if (it != m_task_replay_timers.end())
return it->expires - Timer::GetCurrentTime();
return 0;
}

View File

@ -6,6 +6,7 @@
//#include "../common/eq_packet_structs.h"
#include "../common/servertalk.h"
#include "../common/rulesys.h"
#include "../common/global_tasks.h"
#include <vector>
@ -18,6 +19,7 @@
class ZoneServer;
struct ServerClientList_Struct;
class SharedTask;
class ClientListEntry {
public:
@ -88,6 +90,12 @@ public:
inline void PushToTellQueue(ServerChannelMessage_Struct *scm) { tell_queue.push_back(scm); }
void ProcessTellQueue();
// shared task stuff
int GetTaskLockoutExpire(int id) const;
int GetTaskLockoutTimeLeft(int id) const;
inline int GetCurrentSharedTaskID() const { return shared_task_id; }
inline void SetCurrentSharedTaskID(int in) { shared_task_id = in; }
private:
void ClearVars(bool iAll = false);
@ -129,6 +137,13 @@ private:
bool pLFGMatchFilter;
char pLFGComments[64];
// shared task stuff
// stub for now
int shared_task_id; // ID in the TaskManager
SharedTask *m_shared_task; // just for quick reference so we can tell it to clean up our pointer
std::vector<TaskTimer> m_task_replay_timers;
// Tell Queue -- really a vector :D
std::vector<ServerChannelMessage_Struct *> tell_queue;
};

View File

@ -3,6 +3,8 @@
#include "cliententry.h"
#include "zonelist.h"
#include <algorithm>
extern ClientList client_list;
extern ZSList zoneserver_list;
@ -15,11 +17,25 @@ void SharedTaskManager::HandleTaskRequest(ServerPacket *pack)
int task_id = pack->ReadUInt32();
pack->ReadString(tmp_str);
std::string leader_name = tmp_str;
int missing_count = pack->ReadUInt32();
std::vector<std::string> missing_players;
for (int i = 0; i < missing_count; ++i) {
int player_count = pack->ReadUInt32();
std::vector<std::string> players;
for (int i = 0; i < player_count; ++i) {
pack->ReadString(tmp_str);
missing_players.push_back(tmp_str);
players.push_back(tmp_str);
}
// check if the task exist, we only load shared tasks in world, so we know the type is correct if found
auto it = task_information.find(task_id);
if (it == task_information.end()) { // not loaded! bad id or not shared task
auto pc = client_list.FindCharacter(leader_name.c_str());
if (pc) {
auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 4);
pack->WriteUInt32(0); // string ID or just generic fail message
pack->WriteString(leader_name.c_str());
zoneserver_list.SendPacket(pc->zone(), pc->instance(), pack);
safe_delete(pack);
} // oh well
return;
}
int id = GetNextID();
@ -33,85 +49,46 @@ void SharedTaskManager::HandleTaskRequest(ServerPacket *pack)
zoneserver_list.SendPacket(pc->zone(), pc->instance(), pack);
safe_delete(pack);
} // oh well
return;
}
auto cle = client_list.FindCharacter(leader_name.c_str());
if (cle == nullptr) {// something went wrong
tasks.erase(ret.first);
return;
}
auto &task = ret.first->second;
task.AddMember(leader_name, true);
task.AddMember(leader_name, cle, true);
if (missing_players.empty()) {
if (players.empty()) {
// send instant success to leader
auto pc = client_list.FindCharacter(leader_name.c_str());
if (pc) {
SerializeBuffer buf(10);
buf.WriteInt32(id); // task's ID
buf.WriteString(leader_name); // leader's name
auto pack = new ServerPacket(ServerOP_TaskGrant, buf);
zoneserver_list.SendPacket(pc->zone(), pc->instance(), pack);
zoneserver_list.SendPacket(cle->zone(), cle->instance(), pack);
safe_delete(pack);
} else { // well fuck
tasks.erase(ret.first);
}
return;
}
task.SetMissingCount(missing_count);
for (auto &&name : missing_players) {
for (auto &&name : players) {
// look up CLEs by name, tell them we need to know if they can be added
auto pc = client_list.FindCharacter(name.c_str());
if (pc) {
SerializeBuffer buf(10);
buf.WriteInt32(id);
buf.WriteInt32(task_id);
buf.WriteString(name);
cle = client_list.FindCharacter(name.c_str());
if (cle) {
// make sure we don't have a shared task already
auto pack = new ServerPacket(ServerOP_TaskRequest, buf);
zoneserver_list.SendPacket(pc->zone(), pc->instance(), pack);
safe_delete(pack);
} else { // asked for a toon we couldn't find ABORT!
auto pc = client_list.FindCharacter(leader_name.c_str());
if (pc) {
auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 4);
pack->WriteUInt32(0); // string ID or just generic fail message
pack->WriteString(leader_name.c_str());
zoneserver_list.SendPacket(pc->zone(), pc->instance(), pack);
safe_delete(pack);
} // oh well
tasks.erase(ret.first);
break;
// make sure our level is right
// check our lock out timer
// we're good, add to task
task.AddMember(name, cle);
}
}
}
void SharedTaskManager::HandleTaskRequestReply(ServerPacket *pack)
{
if (!pack)
return;
int id = pack->ReadUInt32();
char name[64] = { 0 };
pack->ReadString(name);
int status = pack->ReadUInt32();
auto it = tasks.find(id);
if (it == tasks.end()) {
// task already errored and no longer existed, we can ignore
return;
}
auto &task = it->second;
if (status != TASKJOINOOZ_CAN) {
// TODO: forward to leader
return;
}
if (!task.DecrementMissingCount())
tasks.erase(it);
}
/*
* This is called once during boot of world
* We need to load next_id, clean up expired tasks (?), and populate the map
@ -138,23 +115,19 @@ int SharedTaskManager::GetNextID()
return next_id;
}
bool SharedTask::DecrementMissingCount()
{
--missing_count;
if (missing_count == 0) {
auto pc = client_list.FindCharacter(leader_name.c_str());
if (pc) {
SerializeBuffer buf(10);
buf.WriteInt32(id); // task's ID
buf.WriteString(leader_name); // leader's name
/*
* When a player leaves world they will tell us to clean up their pointer
* This is NOT leaving the shared task, just crashed or something
*/
auto pack = new ServerPacket(ServerOP_TaskGrant, buf);
zoneserver_list.SendPacket(pc->zone(), pc->instance(), pack);
safe_delete(pack);
} else {
return false; // error, please clean us up
}
}
return true;
void SharedTask::MemberLeftGame(ClientListEntry *cle)
{
auto it = std::find_if(members.begin(), members.end(), [cle](SharedTaskMember &m) { return m.cle == cle; });
// ahh okay ...
if (it == members.end())
return;
it->cle = nullptr;
}

View File

@ -5,29 +5,36 @@
#include <string>
#include "../common/servertalk.h"
#include "../common/global_tasks.h"
class ClientListEntry;
struct SharedTaskMember {
std::string name;
ClientListEntry *cle;
bool leader;
SharedTaskMember() : leader(false) {}
SharedTaskMember(std::string name, bool leader) : name(name), leader(leader) {}
SharedTaskMember() : leader(false), cle(nullptr) {}
SharedTaskMember(std::string name, ClientListEntry *cle, bool leader) : name(name), cle(cle), leader(leader) {}
};
class SharedTask {
public:
SharedTask() : id(0), task_id(0), missing_count(0) {}
SharedTask(int id, int task_id) : id(id), task_id(task_id), missing_count(0) {}
SharedTask() : id(0), task_id(0) {}
SharedTask(int id, int task_id) : id(id), task_id(task_id) {}
~SharedTask() {}
void AddMember(std::string name, bool leader = false) { members.push_back({name, leader}); if (leader) leader_name = name; }
inline void SetMissingCount(int in) { missing_count = in; }
bool DecrementMissingCount(); // if we failed, tell who called us to clean us up basically
void AddMember(std::string name, ClientListEntry *cle = nullptr, bool leader = false)
{
members.push_back({name, cle, leader});
if (leader)
leader_name = name;
}
void MemberLeftGame(ClientListEntry *cle);
const std::string &GetLeaderName() const { return leader_name; }
private:
int id; // id we have in our map
int task_id; // ID of the task we're on
int missing_count; // other toons waiting to verify (out of zone, etc)
std::string leader_name;
std::vector<SharedTaskMember> members;
};
@ -38,15 +45,16 @@ public:
~SharedTaskManager() {}
bool LoadSharedTaskState();
bool LoadSharedTasks();
// IPC packet processing
void HandleTaskRequest(ServerPacket *pack);
void HandleTaskRequestReply(ServerPacket *pack);
private:
int GetNextID();
int next_id;
std::unordered_map<int, SharedTask> tasks;
std::unordered_map<int, SharedTask> tasks; // current active shared task states
std::unordered_map<int, TaskInformation> task_information; // task info shit
};
#endif /* !SHARED_TASKS_H */

View File

@ -1356,11 +1356,6 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
shared_tasks.HandleTaskRequest(pack);
break;
}
case ServerOP_TaskRequestReply:
{
shared_tasks.HandleTaskRequestReply(pack);
break;
}
default:
{
Log(Logs::Detail, Logs::World_Server, "Unknown ServerOPcode from zone 0x%04x, size %d", pack->opcode, pack->size);

View File

@ -1036,7 +1036,6 @@ public:
inline void ProcessTaskProximities(float X, float Y, float Z) { if(taskstate) taskstate->ProcessTaskProximities(this, X, Y, Z); }
inline void AssignTask(int TaskID, int NPCID, bool enforce_level_requirement = false) { if (taskstate) taskstate->AcceptNewTask(this, TaskID, NPCID, enforce_level_requirement); }
inline void AssignSharedTask(int TaskID, int NPCID, int id) { if (taskstate) taskstate->AcceptNewSharedTask(this, TaskID, NPCID, id); }
inline void HandleCanJoinSharedTask(int TaskID, int id) { if (taskstate) taskstate->HandleCanJoinSharedTask(this, TaskID, id); }
inline int ActiveSpeakTask(int NPCID) { if(taskstate) return taskstate->ActiveSpeakTask(NPCID); else return 0; }
inline int ActiveSpeakActivity(int NPCID, int TaskID) { if(taskstate) return taskstate->ActiveSpeakActivity(NPCID, TaskID); else return 0; }
inline void FailTask(int TaskID) { if(taskstate) taskstate->FailTask(this, TaskID); }
@ -1054,6 +1053,7 @@ public:
inline int ActiveTasksInSet(int TaskSet) { return (taskstate ? taskstate->ActiveTasksInSet(TaskSet) :0); }
inline int CompletedTasksInSet(int TaskSet) { return (taskstate ? taskstate->CompletedTasksInSet(TaskSet) :0); }
inline int GetTaskLockoutExpire(int id) { return 0; } // stub
inline int GetTaskLockoutTimeLeft(int id) { return 0; } // stub
inline void SetPendingTask(int id, int task_master_id) { pending_task.id = id; pending_task.task_master_id = task_master_id; }
inline bool HasPendingTask() const { return pending_task.id != 0; }

View File

@ -3405,14 +3405,13 @@ void ClientTaskState::PendSharedTask(Client *c, int TaskID, int NPCID, bool enfo
return;
if (task->replay_group) {
auto expires = c->GetTaskLockoutExpire(task->replay_group);
if (expires) {
auto diff = expires - Timer::GetCurrentTime();
std::string days = std::to_string(diff / 86400);
diff = diff % 86400;
std::string hours = std::to_string(diff / 3600);
diff = diff % 3600;
std::string minutes = std::to_string(diff / 60);
auto expires = c->GetTaskLockoutTimeLeft(task->replay_group);
if (expires > 0) {
std::string days = std::to_string(expires / 86400);
expires = expires % 86400;
std::string hours = std::to_string(expires / 3600);
expires = expires % 3600;
std::string minutes = std::to_string(expires / 60);
c->Message_StringID(13, TASK_REJECT_LOCKEDOUT, days.c_str(), hours.c_str(), minutes.c_str());
return;
}
@ -3440,6 +3439,37 @@ void ClientTaskState::PendSharedTask(Client *c, int TaskID, int NPCID, bool enfo
return;
}
// okay, we verified a few things on the requestor, now we need to fire off to world to do the rest
SerializeBuffer buf(25 + 10 * player_count);
buf.WriteInt32(TaskID); // Task ID
buf.WriteString(c->GetName()); // leader name
buf.WriteInt32(player_count - 1); // count, not leader
if (group) {
for (int i = 0; i < MAX_GROUP_MEMBERS; ++i) {
if (group->members[i] == c) // skipping requestor
continue;
// TODO: mercs/bots
if (group->members[i] != nullptr && group->members[i]->IsClient())
buf.WriteString(group->membername[i]);
}
} else if (raid) {
for (int i = 0; i < MAX_RAID_MEMBERS; ++i) {
if (raid->members[i].member == c) // skipping requestor
continue;
// TODO: bots if they ever can live in a raid
if (raid->members[i].membername[0] != '\0')
buf.WriteString(raid->members[i].membername);
}
}
auto pack = new ServerPacket(ServerOP_TaskRequest, buf);
worldserver.SendPacket(pack);
delete pack;
return;
/*
std::vector<std::string> missing_players; // names of players not in this zone so we can put the checks off to world
bool task_failed = false;
if (group) {
@ -3458,15 +3488,14 @@ void ClientTaskState::PendSharedTask(Client *c, int TaskID, int NPCID, bool enfo
break;
} else {
if (task->replay_group) {
auto expires = client->GetTaskLockoutExpire(task->replay_group);
if (expires) {
auto expires = client->GetTaskLockoutTimeLeft(task->replay_group);
if (expires > 0) {
task_failed = true;
auto diff = expires - Timer::GetCurrentTime();
std::string days = std::to_string(diff / 86400);
diff = diff % 86400;
std::string hours = std::to_string(diff / 3600);
diff = diff % 3600;
std::string minutes = std::to_string(diff / 60);
std::string days = std::to_string(expires / 86400);
expires = expires % 86400;
std::string hours = std::to_string(expires / 3600);
expires = expires % 3600;
std::string minutes = std::to_string(expires / 60);
c->Message_StringID(13, TASK_REJECT_LOCKEDOUT_OTHER,
client->GetName(), days.c_str(),
hours.c_str(), minutes.c_str());
@ -3497,15 +3526,14 @@ void ClientTaskState::PendSharedTask(Client *c, int TaskID, int NPCID, bool enfo
break;
} else {
if (task->replay_group) {
auto expires = client->GetTaskLockoutExpire(task->replay_group);
if (expires) {
auto expires = client->GetTaskLockoutTimeLeft(task->replay_group);
if (expires > 0) {
task_failed = true;
auto diff = expires - Timer::GetCurrentTime();
std::string days = std::to_string(diff / 86400);
diff = diff % 86400;
std::string hours = std::to_string(diff / 3600);
diff = diff % 3600;
std::string minutes = std::to_string(diff / 60);
std::string days = std::to_string(expires / 86400);
expires = expires % 86400;
std::string hours = std::to_string(expires / 3600);
expires = expires % 3600;
std::string minutes = std::to_string(expires / 60);
c->Message_StringID(13, TASK_REJECT_LOCKEDOUT_OTHER,
client->GetName(), days.c_str(),
hours.c_str(), minutes.c_str());
@ -3530,17 +3558,8 @@ void ClientTaskState::PendSharedTask(Client *c, int TaskID, int NPCID, bool enfo
// so we've verified all the clients we can and didn't fail, time to pend and yell at world
c->SetPendingTask(TaskID, NPCID);
c->StartPendingTimer(); // in case something goes wrong and takes ages, we time out
*/
SerializeBuffer buf(25 + 10 * missing_players.size());
buf.WriteInt32(TaskID); // Task ID
buf.WriteString(c->GetName()); // leader name
buf.WriteInt32(missing_players.size()); // count
for (auto && name : missing_players)
buf.WriteString(name);
auto pack = new ServerPacket(ServerOP_TaskRequest, buf);
worldserver.SendPacket(pack);
delete pack;
}
void ClientTaskState::AcceptNewSharedTask(Client *c, int TaskID, int NPCID, int id)
@ -3548,75 +3567,6 @@ void ClientTaskState::AcceptNewSharedTask(Client *c, int TaskID, int NPCID, int
}
void ClientTaskState::HandleCanJoinSharedTask(Client *c, int TaskID, int id)
{
if (!c)
return;
SerializeBuffer buf(15);
buf.WriteInt32(id);
buf.WriteString(c->GetName());
if (!taskmanager || TaskID < 0 || TaskID >= MAXTASKS) {
buf.WriteInt32(TASKJOINOOZ_NOTASK);
auto pack = new ServerPacket(ServerOP_TaskRequestReply, buf);
worldserver.SendPacket(pack);
delete pack;
return;
}
auto task = taskmanager->Tasks[TaskID];
if (task == nullptr) {
buf.WriteInt32(TASKJOINOOZ_NOTASK);
auto pack = new ServerPacket(ServerOP_TaskRequestReply, buf);
worldserver.SendPacket(pack);
delete pack;
return;
}
if (task->type != TaskType::Shared) {
buf.WriteInt32(TASKJOINOOZ_NOTASK);
auto pack = new ServerPacket(ServerOP_TaskRequestReply, buf);
worldserver.SendPacket(pack);
delete pack;
return;
}
if (ActiveSharedTask != nullptr) {
buf.WriteInt32(TASKJOINOOZ_HAVEONE);
auto pack = new ServerPacket(ServerOP_TaskRequestReply, buf);
worldserver.SendPacket(pack);
delete pack;
return;
}
if (!taskmanager->AppropriateLevel(TaskID, c->GetLevel())) {
buf.WriteInt32(TASKJOINOOZ_LEVEL);
auto pack = new ServerPacket(ServerOP_TaskRequestReply, buf);
worldserver.SendPacket(pack);
delete pack;
return;
}
if (task->replay_group) {
auto expires = c->GetTaskLockoutExpire(task->replay_group);
if (expires) {
buf.WriteInt32(TASKJOINOOZ_TIMER);
buf.WriteInt32(expires);
auto pack = new ServerPacket(ServerOP_TaskRequestReply, buf);
worldserver.SendPacket(pack);
delete pack;
return;
}
}
buf.WriteInt32(TASKJOINOOZ_CAN);
auto pack = new ServerPacket(ServerOP_TaskRequestReply, buf);
worldserver.SendPacket(pack);
delete pack;
}
void ClientTaskState::ProcessTaskProximities(Client *c, float X, float Y, float Z) {
float LastX = c->ProximityX();

View File

@ -21,6 +21,7 @@ Copyright (C) 2001-2004 EQEMu Development Team (http://eqemulator.net)
#define TASKS_H
#include "../common/types.h"
#include "../common/global_tasks.h"
#include <list>
#include <vector>
@ -29,24 +30,6 @@ Copyright (C) 2001-2004 EQEMu Development Team (http://eqemulator.net)
#include <unordered_map>
#include <map>
#define MAXTASKS 10000
#define MAXTASKSETS 1000
// The Client has a hard cap of 19 active quests, 29 in SoD+
#define MAXACTIVEQUESTS 19
// The Max Chooser (Task Selector entries) is capped at 40 in the Titanium Client.
#define MAXCHOOSERENTRIES 40
// The Client has a hard cap of 20 activities per task.
#define MAXACTIVITIESPERTASK 20
// This is used to determine if a client's active task slot is empty.
#define TASKSLOTEMPTY 0
// Command Codes for worldserver ServerOP_ReloadTasks
//
#define RELOADTASKS 0
#define RELOADTASKGOALLISTS 1
#define RELOADTASKPROXIMITIES 2
#define RELOADTASKSETS 3
class Client;
class Mob;
@ -100,106 +83,6 @@ private:
std::vector<TaskProximity> TaskProximities;
};
typedef enum { METHODSINGLEID = 0, METHODLIST = 1, METHODQUEST = 2 } TaskMethodType;
struct ActivityInformation {
int StepNumber;
int Type;
std::string target_name; // name mob, location -- default empty
std::string item_list; // likely defaults to empty
std::string skill_list; // IDs ; separated -- default -1
std::string spell_list; // IDs ; separated -- default 0
std::string desc_override; // overrides auto generated description -- default empty
int skill_id; // older clients, first id from above
int spell_id; // older clients, first id from above
int GoalID;
TaskMethodType GoalMethod;
int GoalCount;
int DeliverToNPC;
std::vector<int> ZoneIDs;
std::string zones; // IDs ; searated, ZoneID is the first in this list for older clients -- default empty string
bool Optional;
inline bool CheckZone(int zone_id) {
if (ZoneIDs.empty())
return true;
return std::find(ZoneIDs.begin(), ZoneIDs.end(), zone_id) != ZoneIDs.end();
}
};
typedef enum { ActivitiesSequential = 0, ActivitiesStepped = 1 } SequenceType;
enum class TaskType {
Task = 0, // can have at max 1
Shared = 1, // can have at max 1
Quest = 2, // can have at max 19 or 29 depending on client
E = 3 // can have at max 19 or 29 depending on client, not present in live anymore
};
enum class DurationCode {
None = 0,
Short = 1,
Medium = 2,
Long = 3
};
// need to capture more, shared are just Radiant/Ebon though
enum class PointType {
None = 0,
Radiant = 4,
Ebon = 5,
};
struct TaskInformation {
TaskType type;
int Duration;
DurationCode dur_code; // description for time investment for when Duration == 0
std::string Title; // max length 64
std::string Description; // max length 4000, 2048 on Tit
std::string Reward;
std::string item_link; // max length 128 older clients, item link gets own string
std::string completion_emote; // emote after completing task, yellow. Maybe should make more generic ... but yellow for now!
int RewardID;
int CashReward; // Expressed in copper
int XPReward;
int faction_reward; // just a npc_faction_id
TaskMethodType RewardMethod;
int reward_points; // DoN crystals for shared. Generic "points" for non-shared
PointType reward_type; // 4 for Radiant Crystals else Ebon crystals when shared task
int ActivityCount;
SequenceType SequenceMode;
int LastStep;
short MinLevel;
short MaxLevel;
bool Repeatable;
int replay_group; // ID of our replay timer group (0 means none)
int min_players; // shared tasks
int max_players;
int task_lock_step; // task locks after this step is completed
uint32 instance_zone_id; // instance shit
uint32 zone_version;
uint16 zone_in_zone_id;
float zone_in_x;
float zone_in_y;
uint16 zone_in_object_id;
float dest_x;
float dest_y;
float dest_z;
float dest_h;
/* int graveyard_zone_id;
float graveyard_x;
float graveyard_y;
float graveyard_z;
float graveyard_radius; */
ActivityInformation Activity[MAXACTIVITIESPERTASK];
};
typedef enum { ActivityHidden = 0, ActivityActive = 1, ActivityCompleted = 2 } ActivityState;
typedef enum { ActivityDeliver = 1, ActivityKill = 2, ActivityLoot = 3, ActivitySpeakWith = 4, ActivityExplore = 5,
ActivityTradeSkill = 6, ActivityFish = 7, ActivityForage = 8, ActivityCastOn = 9, ActivitySkillOn = 10,
ActivityTouch = 11, ActivityCollect = 13, ActivityGiveCash = 100 } ActivityType;
struct ClientActivityInformation {
int ActivityID;
@ -267,7 +150,6 @@ public:
void AcceptNewTask(Client *c, int TaskID, int NPCID, bool enforce_level_requirement = false);
void AcceptNewSharedTask(Client *c, int TaskID, int NPCID, int id);
void PendSharedTask(Client *c, int TaskID, int NPCID, bool enforce_level_requirement = false);
void HandleCanJoinSharedTask(Client *c, int TaskID, int id);
void FailTask(Client *c, int TaskID);
int TaskTimeLeft(int TaskID);
int IsTaskCompleted(int TaskID);
@ -345,13 +227,6 @@ private:
bool CheckedTouchActivities;
};
// used for timer lockouts and /tasktimers
struct TaskTimer {
int ID; // ID used in task timer
int original_id; // original ID of the task
int expires; // UNIX timestamp of when it expires, what happens with DLS? Fuck it.
};
struct TaskReplayGroups {
std::string name;
int duration;

View File

@ -1954,6 +1954,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
}
case ServerOP_TaskReject:
{
// this will be reworked to not use the pend shit, we will depend on hoping successive requests just get thrown out
int message = pack->ReadUInt32();
char name[64] = { 0 };
pack->ReadString(name);
@ -1968,18 +1969,6 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
}
break;
}
case ServerOP_TaskRequest:
{
int id = pack->ReadUInt32(); // we need the ID when reply to world so we know which shared task we're going to
int task_id = pack->ReadUInt32();
char name[64] = { 0 };
pack->ReadString(name);
auto client = entity_list.GetClientByName(name);
if (client) {
client->HandleCanJoinSharedTask(task_id, id);
}
break;
}
default: {
std::cout << " Unknown ZSopcode:" << (int)pack->opcode;
std::cout << " size:" << pack->size << std::endl;