The requestor should at least be able to see the new shared task and get

a member list

There are still a few issues that need to be solved this way.
We could try searching for the members in zone (by name ...) or we could
just fire off to world and world will have to send a special full
serialization so the new zone could load the state. Or at this point we
could just assume that we have saved the state to the DB (which hasn't
been coded yet) and any out of zone members will have to depend on
loading it up from the DB.
This commit is contained in:
Michael Cook (mackal) 2019-05-26 00:38:28 -04:00
parent 977c3ca3dc
commit c5bf71f221
11 changed files with 116 additions and 101 deletions

View File

@ -462,6 +462,7 @@ N(OP_SetServerFilter),
N(OP_SetStartCity),
N(OP_SetTitle),
N(OP_SetTitleReply),
N(OP_SharedTaskMemberList),
N(OP_Shielding),
N(OP_ShopDelItem),
N(OP_ShopEnd),

View File

@ -3698,6 +3698,7 @@ struct TaskMemberList_Struct {
/*12*/ char list_pointer[0];
/* list is of the form:
char member_name[1] //null terminated string
uint32 monster_mission; // class chosen
uint8 task_leader //boolean flag
*/
};

View File

@ -564,6 +564,7 @@ OP_TaskHistoryReply=0x25eb
OP_DeclineAllTasks=0x0000
OP_TaskRequestTimer=0x4b76
OP_AcceptNewSharedTask=0x3e5e
OP_SharedTaskMemberList=0x4ddb
# Title opcodes
OP_NewTitlesAvailable=0x45d1

View File

@ -569,6 +569,7 @@ OP_TaskHistoryReply=0x3d05
OP_DeclineAllTasks=0x0000
OP_TaskRequestTimer=0x7a48
OP_AcceptNewSharedTask=0x6646
OP_SharedTaskMemberList=0x1e7d
# Title opcodes
OP_NewTitlesAvailable=0x0d32

View File

@ -535,6 +535,7 @@ OP_CancelTask=0x726b # C
OP_DeclineAllTasks=0x0000 #
OP_TaskRequestTimer=0x2e70
OP_AcceptNewSharedTask=0x4751
OP_SharedTaskMemberList=0x55f4
OP_Shroud=0x6d1f

View File

@ -500,7 +500,7 @@ OP_TaskHistoryRequest=0x3035 #
OP_TaskHistoryReply=0x3A60 #
OP_CancelTask=0x4db6 #Xinu or 0x2c8c or 0x4db6
OP_DeclineAllTasks=0x0000 #not sure, 12 bytes
OP_TaskMemberList=0x3713
#OP_TaskMemberList=0x3713
OP_TaskMemberInvite=0x3cde
OP_TaskMemberInviteResponse=0x6cab
OP_TaskMemberChange=0x354a
@ -511,6 +511,7 @@ OP_TaskPlayerList=0x0ad6
OP_TaskQuit=0x2c8c
OP_TaskRequestTimer=0x0b08
OP_AcceptNewSharedTask=0x5bed
OP_SharedTaskMemberList=0x3713
#Title opcodes
OP_NewTitlesAvailable=0x179c #

View File

@ -458,7 +458,7 @@ OP_TaskActivityComplete=0x54eb
OP_CompletedTasks=0x76a2 # ShowEQ 10/27/05
OP_TaskDescription=0x5ef7 # ShowEQ 10/27/05
OP_TaskActivity=0x682d # ShowEQ 10/27/05
OP_TaskMemberList=0x722f #not sure
#OP_TaskMemberList=0x722f #not sure
OP_OpenNewTasksWindow=0x5e7c #combined with OP_AvaliableTask I think
OP_AvaliableTask=0x0000
OP_AcceptNewTask=0x207f
@ -476,6 +476,7 @@ OP_TaskPlayerList=0x3961
OP_TaskQuit=0x35dd
OP_TaskRequestTimer=0x6a1d
OP_AcceptNewSharedTask=0x194d
OP_SharedTaskMemberList=0x722f
#task complete related: 0x0000 (24 bytes), 0x0000 (8 bytes), 0x0000 (4 bytes)

View File

@ -558,6 +558,7 @@ OP_CancelTask=0x3bf5 # C
OP_DeclineAllTasks=0x0000 #
OP_TaskRequestTimer=0x719e
OP_AcceptNewSharedTask=0x6ded
OP_SharedTaskMemberList=0x584e
# Title opcodes
OP_NewTitlesAvailable=0x4b49 # C

View File

@ -433,6 +433,7 @@ void SharedTask::MemberLeftGame(ClientListEntry *cle)
* Serializes Members into the SerializeBuffer
* Starts with count then followed by names null-termed
* In the future this will include monster mission shit
* This should probably send the SharedMember struct or something more like it, fine for now
*/
void SharedTask::SerializeMembers(SerializeBuffer &buf, bool include_leader) const
{

View File

@ -2451,6 +2451,15 @@ bool TaskManager::IsTaskRepeatable(int TaskID) {
return Task->Repeatable;
}
SharedTaskState *TaskManager::CreateSharedTask(int id, int task_id)
{
auto ret = SharedTasks.insert({id, {id, task_id}});
if (!ret.second) // hmm was already created
return nullptr;
return &(ret.first->second);
}
bool ClientTaskState::TaskOutOfTime(TaskType type, int Index)
{
// Returns true if the Task in the specified slot has a time limit that has been exceeded.
@ -3267,10 +3276,8 @@ void ClientTaskState::AcceptNewTask(Client *c, int TaskID, int NPCID, bool enfor
if (ActiveTask.TaskID != TASKSLOTEMPTY)
max_tasks = true;
break;
case TaskType::Shared: // TODO: shared tasks
// if (something)
max_tasks = true;
break;
case TaskType::Shared: // shared tasks shouldn't call this function. should we log?
return;
case TaskType::Quest:
if (ActiveTaskCount == MAXACTIVEQUESTS)
max_tasks = true;
@ -3312,9 +3319,8 @@ void ClientTaskState::AcceptNewTask(Client *c, int TaskID, int NPCID, bool enfor
case TaskType::Task:
active_slot = &ActiveTask;
break;
case TaskType::Shared: // TODO: shared
active_slot = nullptr;
break;
case TaskType::Shared: // shared aren't done here, should have returned already :P
return;
case TaskType::Quest:
for (int i = 0; i < MAXACTIVEQUESTS; i++) {
Log(Logs::General, Logs::Tasks,
@ -3467,103 +3473,66 @@ void ClientTaskState::PendSharedTask(Client *c, int TaskID, int NPCID, bool enfo
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) {
for (int i = 0; i < MAX_GROUP_MEMBERS; ++i) {
if (group->members[i] == c)
continue;
c->PendingTaskAddMember(group->membername[i]);
if (group->members[i] && group->members[i]->IsClient()) {
auto *client = group->members[i]->CastToClient();
auto *task_state = client->GetTaskState();
if (!task_state->HasSlotForTask(task)) {
task_failed = true;
c->Message_StringID(13, TASK_REJECT_GROUP_HAVE_ONE, c->GetName());
break;
} else {
if (task->replay_group) {
auto expires = client->GetTaskLockoutTimeLeft(task->replay_group);
if (expires > 0) {
task_failed = true;
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());
client->Message_StringID(13, TASK_REJECT_LOCKEDOUT_ME,
days.c_str(), hours.c_str(),
minutes.c_str());
break;
}
}
}
} else if (group->members[i] == nullptr) { // out of zone
missing_players.push_back(group->membername[i]);
}
}
} else if (raid) {
for (int i = 0; i < MAX_RAID_MEMBERS; ++i) {
if (raid->members[i].member == c)
continue;
c->PendingTaskAddMember(raid->members[i].membername);
if (raid->members[i].member) {
auto *client = raid->members[i].member;
auto *task_state = client->GetTaskState();
if (!task_state->HasSlotForTask(task)) {
task_failed = true;
c->Message_StringID(13, TASK_REJECT_RAID_HAVE_ONE, c->GetName());
break;
} else {
if (task->replay_group) {
auto expires = client->GetTaskLockoutTimeLeft(task->replay_group);
if (expires > 0) {
task_failed = true;
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());
client->Message_StringID(13, TASK_REJECT_LOCKEDOUT_ME,
days.c_str(), hours.c_str(),
minutes.c_str());
break;
}
}
}
} else if (raid->members[i].membername[0] != '\0') { // out of zone
missing_players.push_back(raid->members[i].membername);
}
}
}
if (task_failed) { // we already yelled at them
c->ResetPendingTask();
return;
}
// 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
*/
}
void ClientTaskState::AcceptNewSharedTask(Client *c, int TaskID, int NPCID, int id, std::vector<std::string> &members)
{
// all of this data should have been verified already
// first we need to create the new SharedTaskState
auto task_state = taskmanager->CreateSharedTask(id, TaskID);
if (!task_state) {
// TODO: something failed, tell world
return;
}
// we need to init the activity now
auto task_activity = task_state->GetActivity();
task_activity->TaskID = TaskID;
task_activity->AcceptedTime = time(nullptr);
task_activity->Updated = true;
task_activity->CurrentStep = -1;
for (int i = 0; i < taskmanager->Tasks[TaskID]->ActivityCount; i++) {
task_activity->Activity[i].ActivityID = i;
task_activity->Activity[i].DoneCount = 0;
task_activity->Activity[i].State = ActivityHidden;
task_activity->Activity[i].Updated = true;
}
// TODO: figure out packet order
// unsure if we unlock now packet wise, just copying normal tasks for now
UnlockActivities(c->CharacterID(), *task_activity);
taskmanager->SendSingleActiveTaskToClient(c, *task_activity, false, true);
c->Message(0, "You have been assigned the task '%s'.", taskmanager->Tasks[TaskID]->Title.c_str());
// send member list of just leader
task_state->AddMember(c->GetName(), c, true);
task_state->SendMembersList(c);
// send compass shit
// add everyone else and send that
// we could try to find these members so they could know about it ... but ahh not sure :P
for (auto &m : members)
task_state->AddMember(m);
task_state->SendMembersList(c);
std::string buf = std::to_string(TaskID);
NPC *npc = entity_list.GetID(NPCID)->CastToNPC();
if(!npc) {
c->Message(clientMessageYellow, "Task Giver ID is %i", NPCID);
c->Message(clientMessageError, "Unable to find NPC to send EVENT_TASKACCEPTED to. Report this bug.");
// TODO: ahh do we wanna do this? clean up world at least
return;
}
// TODO: save state
parse->EventNPC(EVENT_TASK_ACCEPTED, npc, c, buf.c_str(), 0);
// TODO: We need to tell world we are successful so we can tell all the other clients
// there are a few issues we need to solve with this
}
void ClientTaskState::ProcessTaskProximities(Client *c, float X, float Y, float Z) {
@ -3810,3 +3779,25 @@ void SharedTaskState::MemberEnterZone(Mob *player)
it->entity = player;
}
void SharedTaskState::SendMembersList(Client *to) const
{
if (!to)
return;
SerializeBuffer buf(sizeof(TaskMemberList_Struct) + 15 * members.size());
buf.WriteInt32(0); // unknown ids
buf.WriteInt32(0);
buf.WriteInt32(members.size());
for (auto &&m : members) {
buf.WriteString(m.name);
buf.WriteInt32(0); // monster mission shit
buf.WriteInt8(m.leader);
}
auto outapp = new EQApplicationPacket(OP_SharedTaskMemberList, buf);
to->QueuePacket(outapp);
safe_delete(outapp);
}

View File

@ -95,11 +95,13 @@ struct SharedTaskMember {
Mob *entity; // needs to be managed
bool leader;
SharedTaskMember() : entity(nullptr), leader(false) {}
SharedTaskMember(std::string name, Mob *entity, bool leader) : name(name), entity(entity), leader(leader) {}
};
class SharedTaskState {
public:
SharedTaskState() : locked(false) {}
SharedTaskState(int id, int task_id) : id(id), task_id(task_id), locked(false) { }
// ~SharedTaskState();
inline const bool IsLocked() const { return locked; }
@ -109,12 +111,24 @@ public:
void MemberZoned(Mob *player); // player left zone, update their pointer
void MemberEnterZone(Mob *player); // player entered zone, update their pointer
void AddMember(std::string name, Mob *entity = nullptr, bool leader = false)
{
members.push_back({name, entity, leader});
if (leader)
leader_name = name;
}
void SendMembersList(Client *to) const;
ClientTaskInformation *GetActivity() { return &activity; }
friend class TaskManager;
private:
int id;
int task_id;
std::vector<SharedTaskMember> members;
std::string leader_name;
ClientTaskInformation activity;
bool locked;
};
@ -253,6 +267,7 @@ public:
friend class ClientTaskState;
void LoadSharedTask(int id); // loads the shared task state
SharedTaskState *CreateSharedTask(int id, int task_id);
private:
TaskGoalListManager GoalListManager;