Merge branch 'shared_tasks' of github.com:EQEmu/Server into shared_tasks_service

This commit is contained in:
KimLS 2019-06-10 21:53:41 -07:00
commit 0b26c80d8f
25 changed files with 237 additions and 41 deletions

View File

@ -1393,11 +1393,13 @@ sub fetch_latest_windows_binaries {
}
sub fetch_latest_windows_binaries_bots {
print "[Update] Fetching Latest Windows Binaries with Bots...\n";
get_remote_file($install_repository_request_url . "master_windows_build_bots.zip", "updates_staged/master_windows_build_bots.zip", 1);
print "[Update] Fetching Latest Windows Binaries (unstable) with Bots...\n";
get_remote_file("https://ci.appveyor.com/api/projects/KimLS/server/artifacts/eqemu-x86-bots.zip", "updates_staged/eqemu-x86-bots.zip", 1);
#::: old repository kept for reference until no issues reported
#::: get_remote_file($install_repository_request_url . "master_windows_build_bots.zip", "updates_staged/master_windows_build_bots.zip", 1);
print "[Update] Fetched Latest Windows Binaries with Bots...\n";
print "[Update] Extracting...\n";
unzip('updates_staged/master_windows_build_bots.zip', 'updates_staged/binaries/');
unzip('updates_staged/eqemu-x86-bots.zip', 'updates_staged/binaries/');
my @files;
my $start_dir = "updates_staged/binaries";
find(

View File

@ -21,30 +21,30 @@ CREATE TABLE `task_replay_groups` (
PRIMARY KEY(`id`)
);
CREATE TABLE `character_task_lockouts` (
`charid` INT NOT NULL,
`character_id` INT NOT NULL,
`replay_group` INT NOT NULL,
`original_id` INT NOT NULL,
`timestamp` INT NOT NULL,
PRIMARY KEY(`charid`, `replay_group`)
PRIMARY KEY(`character_id`, `replay_group`)
);
CREATE TABLE `shared_task_state` (
`id` INT NOT NULL,
`taskid` INT NOT NULL,
`acceptedtime` INT NOT NULL,
`locked` TINYINT NOT NULL DEFAULT '0',
`task_id` INT NOT NULL,
`accepted_time` INT NOT NULL,
`is_locked` TINYINT NOT NULL DEFAULT '0',
PRIMARY KEY(`id`)
);
CREATE TABLE `shared_task_activities` (
`shared_id` INT NOT NULL,
`shared_task_id` INT NOT NULL,
`activity_id` INT NOT NULL,
`done_count` INT NOT NULL,
`completed` TINYINT,
PRIMARY KEY(`shared_id`, `activity_id`)
PRIMARY KEY(`shared_task_id`, `activity_id`)
);
CREATE TABLE `shared_task_members` (
`shared_id` INT NOT NULL,
`charid` INT NOT NULL,
`name` VARCHAR(64) NOT NULL,
`leader` TINYINT,
PRIMARY KEY(`charid`)
`shared_task_id` INT NOT NULL,
`character_id` INT NOT NULL,
`character_name` VARCHAR(64) NOT NULL,
`is_leader` TINYINT DEFAULT 0,
PRIMARY KEY(shared_task_id, character_id)
);

View File

@ -23,6 +23,7 @@ data_buckets
db_str
doors
eqtime
faction_base_data
faction_list
faction_list_mod
fear_hints

View File

@ -373,7 +373,7 @@ int ClientListEntry::GetTaskLockoutTimeLeft(int id) const
[id](const TaskTimer &a) { return a.ID == id; });
if (it != m_task_replay_timers.end())
return it->expires - Timer::GetCurrentTime();
return it->expires - time(nullptr);
return 0;
}
@ -384,7 +384,7 @@ int ClientListEntry::GetTaskLockoutTimeLeft(int id) const
bool ClientListEntry::CleanExpiredTaskLockouts() const
{
std::string query =
StringFormat("DELETE FROM `character_task_lockouts` WHERE `charid` = %i AND `timestamp` > %i", pcharid,
StringFormat("DELETE FROM `character_task_lockouts` WHERE `character_id` = %i AND `timestamp` > %i", pcharid,
Timer::GetCurrentTime());
auto results = database.QueryDatabase(query);
return results.Success();
@ -397,7 +397,7 @@ bool ClientListEntry::LoadTaskLockouts()
{
CleanExpiredTaskLockouts();
std::string query = StringFormat(
"SELECT `replay_group`, `original_id`, `timestamp` FROM `character_task_lockouts` WHERE `charid` = %i",
"SELECT `replay_group`, `original_id`, `timestamp` FROM `character_task_lockouts` WHERE `character_id` = %i",
pcharid);
auto results = database.QueryDatabase(query);
if (!results.Success())

View File

@ -82,7 +82,7 @@ void SharedTaskManager::HandleTaskRequest(ServerPacket *pack)
}
auto &task = ret.first->second;
task.AddMember(leader_name, cle_leader, true);
task.AddMember(leader_name, cle_leader, cle_leader->CharID(), true);
if (players.empty()) {
// send instant success to leader
@ -133,7 +133,7 @@ void SharedTaskManager::HandleTaskRequest(ServerPacket *pack)
// check our lock out timer
int expires = cle->GetTaskLockoutExpire(task_id);
if ((expires - Timer::GetCurrentTime()) >= 0) {
if ((expires - time(nullptr)) >= 0) {
// failure TODO: appropriate message, we need to send the timestamp here
auto pack = new ServerPacket(ServerOP_TaskReject, leader_name.size() + 1 + 8);
pack->WriteUInt32(0); // string ID or just generic fail message
@ -146,7 +146,7 @@ void SharedTaskManager::HandleTaskRequest(ServerPacket *pack)
}
// we're good, add to task
task.AddMember(name, cle);
task.AddMember(name, cle, cle->CharID());
}
}
@ -374,7 +374,7 @@ bool SharedTaskManager::LoadSharedTaskState()
{
// one may think we should clean up expired tasks, but we don't just in case world is booting back up after a crash
// we will clean them up in the normal process loop so zones get told to clean up
std::string query = "SELECT `id`, `taskid`, `acceptedtime`, `locked` FROM `shared_task_state`";
std::string query = "SELECT `id`, `task_id`, `accepted_time`, `is_locked` FROM `shared_task_state`";
auto results = database.QueryDatabase(query);
if (results.Success() && results.RowCount() > 0) {
@ -389,14 +389,14 @@ bool SharedTaskManager::LoadSharedTaskState()
}
}
query = "SELECT `shared_id`, `charid`, `name`, `leader` FROM `shared_task_members` ORDER BY shared_id ASC";
query = "SELECT `shared_task_id`, `character_id`, `character_name`, `is_leader` FROM `shared_task_members` ORDER BY shared_task_id ASC";
results = database.QueryDatabase(query);
if (results.Success() && results.RowCount() > 0) {
for (auto row = results.begin(); row != results.end(); ++row) {
int task_id = atoi(row[0]);
// hmm not sure best way to do this, fine for now
if (tasks.count(task_id) == 1)
tasks[task_id].AddMember(row[2], nullptr, atoi(row[3]) != 0);
tasks[task_id].AddMember(row[2], nullptr, atoi(row[1]), atoi(row[3]) != 0);
}
}
@ -404,7 +404,7 @@ bool SharedTaskManager::LoadSharedTaskState()
// But the crash case may actually dictate we should :P
// set next_id to highest used ID
query = "SELECT MAX(id) FROM shared_task_state";
query = "SELECT IFNULL(MAX(id), 0) FROM shared_task_state";
results = database.QueryDatabase(query);
if (results.Success() && results.RowCount() == 1) {
auto row = results.begin();

View File

@ -6,16 +6,21 @@
#include "../common/servertalk.h"
#include "../common/global_tasks.h"
#include "cliententry.h"
class ClientListEntry;
struct SharedTaskMember {
std::string name;
ClientListEntry *cle;
int char_id;
bool leader;
// TODO: monster mission stuff
SharedTaskMember() : cle(nullptr), leader(false) {}
SharedTaskMember(std::string name, ClientListEntry *cle, bool leader) : name(name), cle(cle), leader(leader) {}
SharedTaskMember() : cle(nullptr), char_id(0), leader(false) {}
SharedTaskMember(std::string name, ClientListEntry *cle, int char_id, bool leader)
: name(name), cle(cle), char_id(char_id), leader(leader)
{
}
};
class SharedTask {
@ -24,11 +29,16 @@ public:
SharedTask(int id, int task_id) : id(id), task_id(task_id), locked(false) {}
~SharedTask() {}
void AddMember(std::string name, ClientListEntry *cle = nullptr, bool leader = false)
void AddMember(std::string name, ClientListEntry *cle = nullptr, int char_id = 0, bool leader = false)
{
members.push_back({name, cle, leader});
members.push_back({name, cle, char_id, leader});
if (leader)
leader_name = name;
if (char_id == 0)
return;
auto it = std::find(char_ids.begin(), char_ids.end(), char_id);
if (it == char_ids.end())
char_ids.push_back(char_id);
}
void MemberLeftGame(ClientListEntry *cle);
inline const std::string &GetLeaderName() const { return leader_name; }
@ -59,6 +69,7 @@ private:
bool locked;
std::string leader_name;
std::vector<SharedTaskMember> members;
std::vector<int> char_ids; // every char id of someone to be locked out, different in case they leave/removed
ClientTaskInformation task_state; // book keeping
friend class SharedTaskManager;

View File

@ -1877,6 +1877,10 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQEmu::skills::Sk
if (r)
r->MemberZoned(this);
auto shared_task = GetSharedTask();
if (shared_task)
shared_task->MemberZoned(this);
dead_timer.Start(5000, true);
m_pp.zone_id = m_pp.binds[0].zoneId;
m_pp.zoneInstance = m_pp.binds[0].instance_id;

View File

@ -439,6 +439,7 @@ NPCType *Bot::FillNPCTypeStruct(uint32 botSpellsID, std::string botName, std::st
bot_npc_type->skip_global_loot = true;
//bot_npc_type->rare_spawn = false;
bot_npc_type->stuck_behavior = Ground;
bot_npc_type->skip_auto_scale = true;
return bot_npc_type;
}

View File

@ -3396,6 +3396,11 @@ void Client::LinkDead()
if(raid){
raid->MemberZoned(this);
}
auto shared_task = GetSharedTask();
if (shared_task)
shared_task->MemberZoned(this);
// save_timer.Start(2500);
linkdead_timer.Start(RuleI(Zone,ClientLinkdeadMS));
SendAppearancePacket(AT_Linkdead, 1);

View File

@ -791,7 +791,9 @@ public:
uint32 GetCharMaxLevelFromQGlobal();
uint32 GetCharMaxLevelFromBucket();
inline bool IsStanding() const {return (playeraction == 0);}
inline bool IsSitting() const {return (playeraction == 1);}
inline bool IsCrouching() const {return (playeraction == 2);}
inline bool IsBecomeNPC() const { return npcflag; }
inline uint8 GetBecomeNPCLevel() const { return npclevel; }
inline void SetBecomeNPC(bool flag) { npcflag = flag; }
@ -1027,6 +1029,7 @@ 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, int accepted_time, std::vector<std::string> &members) { if (taskstate) taskstate->AcceptNewSharedTask(this, TaskID, NPCID, id, accepted_time, members); }
inline void AddToSharedTask(int TaskID) { if (taskstate) taskstate->AddToSharedTask(this, TaskID); }
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); }
@ -1045,6 +1048,7 @@ public:
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 SharedTaskState *GetSharedTask() { return taskstate ? taskstate->GetSharedTask() : nullptr; }
inline const EQEmu::versions::ClientVersion ClientVersion() const { return m_ClientVersion; }
inline const uint32 ClientVersionBit() const { return m_ClientVersionBit; }

View File

@ -1799,7 +1799,7 @@ void Client::Handle_OP_AcceptNewSharedTask(const EQApplicationPacket *app)
auto *ant = (AcceptNewSharedTask_Struct*)app->pBuffer;
if (ant->task_id > 0 && RuleB(TaskSystem, EnableTaskSystem) && taskstate)
taskstate->PendSharedTask(this, ant->task_id, ant->task_master_id);
taskstate->RequestSharedTask(this, ant->task_id, ant->task_master_id);
}
void Client::Handle_OP_AdventureInfoRequest(const EQApplicationPacket *app)

View File

@ -149,6 +149,9 @@ bool Client::Process() {
{
myraid->MemberZoned(this);
}
auto shared_task = GetSharedTask();
if (shared_task)
shared_task->MemberZoned(this);
return(false);
}
@ -171,6 +174,9 @@ bool Client::Process() {
if (myraid) {
myraid->MemberZoned(this);
}
auto shared_task = GetSharedTask();
if (shared_task)
shared_task->MemberZoned(this);
return false; //delete client
}
@ -653,6 +659,9 @@ bool Client::Process() {
myraid->MemberZoned(this);
}
}
auto shared_task = GetSharedTask();
if (shared_task)
shared_task->MemberZoned(this);
OnDisconnect(false);
return false;
}
@ -694,6 +703,10 @@ void Client::OnDisconnect(bool hard_disconnect) {
if (MyRaid)
MyRaid->MemberZoned(this);
auto shared_task = GetSharedTask();
if (shared_task)
shared_task->MemberZoned(this);
parse->EventPlayer(EVENT_DISCONNECT, this, "", 0);
/* QS: PlayerLogConnectDisconnect */
@ -2101,6 +2114,10 @@ void Client::HandleRespawnFromHover(uint32 Option)
if(r)
r->MemberZoned(this);
auto shared_task = GetSharedTask();
if (shared_task)
shared_task->MemberZoned(this);
m_pp.zone_id = chosen->zone_id;
m_pp.zoneInstance = chosen->instance_id;
database.MoveCharacterToZone(CharacterID(), database.GetZoneName(chosen->zone_id));

View File

@ -537,6 +537,9 @@ void EntityList::MobProcess()
Log(Logs::General, Logs::Error, "About to delete a client still in a raid.");
r->MemberZoned(mob->CastToClient());
}
auto shared_task = mob->CastToClient()->GetSharedTask();
if (shared_task)
shared_task->MemberZoned(mob);
entity_list.RemoveClient(id);
}

View File

@ -972,8 +972,8 @@ void Client::DeleteItemInInventory(int16 slot_id, int8 quantity, bool client_upd
safe_delete(outapp);
}
else {
outapp = new EQApplicationPacket(OP_MoveItem, sizeof(MoveItem_Struct));
MoveItem_Struct* delitem = (MoveItem_Struct*)outapp->pBuffer;
outapp = new EQApplicationPacket(OP_DeleteItem, sizeof(DeleteItem_Struct));
DeleteItem_Struct* delitem = (DeleteItem_Struct*)outapp->pBuffer;
delitem->from_slot = slot_id;
delitem->to_slot = 0xFFFFFFFF;
delitem->number_in_stack = 0xFFFFFFFF;

View File

@ -615,11 +615,21 @@ void Lua_Client::UntrainDiscAll(bool update_client) {
self->UntrainDiscAll(update_client);
}
bool Lua_Client::IsStanding() {
Lua_Safe_Call_Bool();
return self->IsStanding();
}
bool Lua_Client::IsSitting() {
Lua_Safe_Call_Bool();
return self->IsSitting();
}
bool Lua_Client::IsCrouching() {
Lua_Safe_Call_Bool();
return self->IsCrouching();
}
void Lua_Client::SetFeigned(bool v) {
Lua_Safe_Call_Void();
self->SetFeigned(v);
@ -1621,7 +1631,9 @@ luabind::scope lua_register_client() {
.def("UntrainDisc", (void(Lua_Client::*)(int,bool))&Lua_Client::UntrainDisc)
.def("UntrainDiscAll", (void(Lua_Client::*)(void))&Lua_Client::UntrainDiscAll)
.def("UntrainDiscAll", (void(Lua_Client::*)(bool))&Lua_Client::UntrainDiscAll)
.def("IsStanding", (bool(Lua_Client::*)(void))&Lua_Client::IsStanding)
.def("IsSitting", (bool(Lua_Client::*)(void))&Lua_Client::IsSitting)
.def("IsCrouching", (bool(Lua_Client::*)(void))&Lua_Client::IsCrouching)
.def("SetFeigned", (void(Lua_Client::*)(bool))&Lua_Client::SetFeigned)
.def("GetFeigned", (bool(Lua_Client::*)(void))&Lua_Client::GetFeigned)
.def("AutoSplitEnabled", (bool(Lua_Client::*)(void))&Lua_Client::AutoSplitEnabled)

View File

@ -148,7 +148,9 @@ public:
void UntrainDisc(int slot, bool update_client);
void UntrainDiscAll();
void UntrainDiscAll(bool update_client);
bool IsStanding();
bool IsSitting();
bool IsCrouching();
void SetFeigned(bool v);
bool GetFeigned();
bool AutoSplitEnabled();

View File

@ -239,6 +239,7 @@ NPC::NPC(const NPCType *npc_type_data, Spawn2 *in_respawn, const glm::vec4 &posi
p_depop = false;
loottable_id = npc_type_data->loottable_id;
skip_global_loot = npc_type_data->skip_global_loot;
skip_auto_scale = npc_type_data->skip_auto_scale;
rare_spawn = npc_type_data->rare_spawn;
no_target_hotkey = npc_type_data->no_target_hotkey;
primary_faction = 0;

View File

@ -468,6 +468,7 @@ public:
virtual int GetStuckBehavior() const { return NPCTypedata_ours ? NPCTypedata_ours->stuck_behavior : NPCTypedata->stuck_behavior; }
inline bool IsSkipAutoScale() const { return skip_auto_scale; }
protected:
@ -612,6 +613,7 @@ protected:
private:
uint32 loottable_id;
bool skip_global_loot;
bool skip_auto_scale;
bool p_depop;
};

View File

@ -26,6 +26,9 @@
*/
void NpcScaleManager::ScaleNPC(NPC * npc)
{
if (npc->IsSkipAutoScale())
return;
int8 npc_type = GetNPCScalingType(npc);
int npc_level = npc->GetLevel();
bool is_auto_scaled = IsAutoScaled(npc);
@ -621,4 +624,4 @@ bool NpcScaleManager::ApplyGlobalBaseScalingToNPCDynamically(NPC *&npc)
auto results = database.QueryDatabase(query);
return results.Success();
}
}

View File

@ -2596,6 +2596,32 @@ XS(XS_Client_UntrainDiscAll) {
XSRETURN_EMPTY;
}
XS(XS_Client_IsStanding); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_IsStanding)
{
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Client::IsStanding(THIS)");
{
Client * THIS;
bool RETVAL;
if (sv_derived_from(ST(0), "Client")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Client *,tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Client");
if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->IsStanding();
ST(0) = boolSV(RETVAL);
sv_2mortal(ST(0));
}
XSRETURN(1);
}
XS(XS_Client_IsSitting); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_IsSitting) {
dXSARGS;
@ -2620,6 +2646,32 @@ XS(XS_Client_IsSitting) {
XSRETURN(1);
}
XS(XS_Client_IsCrouching); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_IsCrouching)
{
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Client::IsCrouching(THIS)");
{
Client * THIS;
bool RETVAL;
if (sv_derived_from(ST(0), "Client")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Client *,tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Client");
if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->IsCrouching();
ST(0) = boolSV(RETVAL);
sv_2mortal(ST(0));
}
XSRETURN(1);
}
XS(XS_Client_IsBecomeNPC); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_IsBecomeNPC) {
dXSARGS;
@ -6338,7 +6390,9 @@ XS(boot_Client) {
newXSproto(strcpy(buf, "IsLD"), XS_Client_IsLD, file, "$");
newXSproto(strcpy(buf, "IsMedding"), XS_Client_IsMedding, file, "$");
newXSproto(strcpy(buf, "IsRaidGrouped"), XS_Client_IsRaidGrouped, file, "$");
newXSproto(strcpy(buf, "IsStanding"), XS_Client_IsStanding, file, "$");
newXSproto(strcpy(buf, "IsSitting"), XS_Client_IsSitting, file, "$");
newXSproto(strcpy(buf, "IsCrouching"), XS_Client_IsCrouching, file, "$");
newXSproto(strcpy(buf, "IsTaskActive"), XS_Client_IsTaskActive, file, "$$");
newXSproto(strcpy(buf, "IsTaskActivityActive"), XS_Client_IsTaskActivityActive, file, "$$$");
newXSproto(strcpy(buf, "IsTaskCompleted"), XS_Client_IsTaskCompleted, file, "$$");

View File

@ -3084,6 +3084,21 @@ void TaskManager::SendActiveTaskDescription(Client *c, int TaskID, ClientTaskInf
safe_delete(outapp);
}
// TODO: stub
SharedTaskState *TaskManager::LoadSharedTask(int id)
{
return nullptr;
}
SharedTaskState *TaskManager::GetSharedTask(int id)
{
auto it = SharedTasks.find(id);
if (it == SharedTasks.end())
return nullptr;
return &(it->second);
}
bool ClientTaskState::IsTaskActivityCompleted(TaskType type, int index, int ActivityID)
{
switch (type) {
@ -3387,10 +3402,13 @@ void ClientTaskState::AcceptNewTask(Client *c, int TaskID, int NPCID, bool enfor
parse->EventNPC(EVENT_TASK_ACCEPTED, npc, c, buf.c_str(), 0);
}
// This function will do a bunch of verification, then set up a pending state which will then send a request
// to world and send off requests to out of group zones to ask if they can join the task
// Once the we get all of the replies that pass, we will then assign the task
void ClientTaskState::PendSharedTask(Client *c, int TaskID, int NPCID, bool enforce_level_requirement)
/*
* This function is a proxy for OP_AccetNewSharedTask since it has to fire to
* world. We do a handful of checks on the leader, then build a packet with a
* list of all the members in our group/raid if applicable. The verification for
* the other members is done in world.
*/
void ClientTaskState::RequestSharedTask(Client *c, int TaskID, int NPCID, bool enforce_level_requirement)
{
if (!taskmanager || TaskID < 0 || TaskID >= MAXTASKS) {
c->Message(13, "Task system not functioning, or TaskID %i out of range.", TaskID);
@ -3550,11 +3568,47 @@ void ClientTaskState::AcceptNewSharedTask(Client *c, int TaskID, int NPCID, int
worldserver.SendPacket(pack);
delete pack;
ActiveSharedTask = task_state;
return;
// there are a few issues we need to solve with this
}
/*
* This function is called when world sends ServerOP_TaskZoneCreated to trigger
* members to join. If the task doesn't already exist, we need to load it from
* the DB.
*
* This is also called in LoadClientTaskState() when they notice they have a
* shared task they need to join. (Called from first OP_ZoneEntry)
*/
void ClientTaskState::AddToSharedTask(Client *c, int TaskID)
{
auto task = taskmanager->GetSharedTask(TaskID);
if (!task)
task = taskmanager->LoadSharedTask(TaskID);
if (!task) {// FUCK
return;
}
task->MemberEnterZone(c);
// send packets
auto task_activity = task->GetActivity();
taskmanager->SendSingleActiveTaskToClient(c, *task_activity, false, true);
task->SendMembersList(c);
// So normally getting a task we would send EVENT_TASK_ACCEPTED here, but
// this isn't an accept step. I guess we should add another event in case
// they need the same thing TODO
ActiveSharedTask = task;
return;
}
void ClientTaskState::ProcessTaskProximities(Client *c, float X, float Y, float Z) {
float LastX = c->ProximityX();
@ -3780,7 +3834,7 @@ void SharedTaskState::LockTask()
void SharedTaskState::MemberZoned(Mob *player)
{
auto it = std::find_if(members.begin(), members.end(),
[&player](const SharedTaskMember &a) { return a.name == player->GetName(); });
[&player](const SharedTaskMember &a) { return a.entity == player; });
if (it == members.end()) // guess they weren't in this group, w/e
return;

View File

@ -146,8 +146,6 @@ public:
int GetTaskActivityDoneCountFromTaskID(int TaskID, int ActivityID);
int GetTaskStartTime(TaskType type, int index);
void AcceptNewTask(Client *c, int TaskID, int NPCID, bool enforce_level_requirement = false);
void AcceptNewSharedTask(Client *c, int TaskID, int NPCID, int id, int accepted_time, std::vector<std::string> &members);
void PendSharedTask(Client *c, int TaskID, int NPCID, bool enforce_level_requirement = false);
void FailTask(Client *c, int TaskID);
int TaskTimeLeft(int TaskID);
int IsTaskCompleted(int TaskID);
@ -180,9 +178,15 @@ public:
int ActiveTasksInSet(int TaskSetID);
int CompletedTasksInSet(int TaskSetID);
bool HasSlotForTask(TaskInformation *task);
// shared task related functions
void AcceptNewSharedTask(Client *c, int TaskID, int NPCID, int id, int accepted_time, std::vector<std::string> &members);
void AddToSharedTask(Client *c, int TaskID);
void RequestSharedTask(Client *c, int TaskID, int NPCID, bool enforce_level_requirement = false);
inline bool HasFreeTaskSlot() { return ActiveTask.TaskID == TASKSLOTEMPTY; }
inline SharedTaskState *GetSharedTask() { return ActiveSharedTask ; }
friend class TaskManager;
private:
@ -266,8 +270,9 @@ public:
bool IsTaskRepeatable(int TaskID);
friend class ClientTaskState;
void LoadSharedTask(int id); // loads the shared task state
SharedTaskState *LoadSharedTask(int id); // loads the shared task state
SharedTaskState *CreateSharedTask(int id, int task_id);
SharedTaskState *GetSharedTask(int id);
private:
TaskGoalListManager GoalListManager;

View File

@ -1991,6 +1991,17 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
}
break;
}
case ServerOP_TaskZoneCreated:
{
int task_id = pack->ReadUInt32();
char name[64] = { 0 };
pack->ReadString(name);
auto client = entity_list.GetClientByName(name);
if (client)
client->AddToSharedTask(task_id);
break;
}
default: {
std::cout << " Unknown ZSopcode:" << (int)pack->opcode;
std::cout << " size:" << pack->size << std::endl;

View File

@ -2675,6 +2675,7 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
temp_npctype_data->rare_spawn = atoi(row[108]) != 0;
temp_npctype_data->stuck_behavior = atoi(row[109]);
temp_npctype_data->use_model = atoi(row[110]);
temp_npctype_data->skip_auto_scale = false; // hardcoded here for now
// If NPC with duplicate NPC id already in table,
// free item we attempted to add.
@ -2877,6 +2878,8 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client
tmpNPCType->scalerate = atoi(row[43]);
tmpNPCType->spellscale = atoi(row[44]);
tmpNPCType->healscale = atoi(row[45]);
tmpNPCType->skip_global_loot = true;
tmpNPCType->skip_auto_scale = true;
// If Merc with duplicate NPC id already in table,
// free item we attempted to add.

View File

@ -143,6 +143,7 @@ struct NPCType
bool untargetable;
bool skip_global_loot;
bool rare_spawn;
bool skip_auto_scale; // just so it doesn't mess up bots or mercs, probably should add to DB too just in case
int8 stuck_behavior;
uint16 use_model;
};