mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-26 06:51:28 +00:00
Shared Task WIP
This commit is contained in:
parent
d4e0e8aea2
commit
39544b4723
@ -6,6 +6,7 @@ N(OP_0x0347),
|
||||
N(OP_AAAction),
|
||||
N(OP_AAExpUpdate),
|
||||
N(OP_AcceptNewTask),
|
||||
N(OP_AcceptNewSharedTask),
|
||||
N(OP_AckPacket),
|
||||
N(OP_Action),
|
||||
N(OP_Action2),
|
||||
|
||||
@ -3788,6 +3788,14 @@ struct AcceptNewTask_Struct {
|
||||
uint32 task_master_id; //entity ID
|
||||
};
|
||||
|
||||
struct AcceptNewSharedTask_Struct {
|
||||
uint32 unknown00;
|
||||
uint32 unknown04;
|
||||
uint32 task_master_id;
|
||||
uint32 task_id;
|
||||
float unknown16;
|
||||
};
|
||||
|
||||
//was all 0's from client, server replied with same op, all 0's
|
||||
struct CancelTask_Struct {
|
||||
uint32 SequenceNumber;
|
||||
|
||||
@ -187,6 +187,7 @@ public:
|
||||
const unsigned char *buffer() const { return m_buffer; }
|
||||
|
||||
friend class BasePacket;
|
||||
friend class ServerPacket;
|
||||
|
||||
private:
|
||||
void Grow(size_t new_size);
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include "../common/types.h"
|
||||
#include "../common/packet_functions.h"
|
||||
#include "../common/eq_packet_structs.h"
|
||||
#include "../common/serialize_buffer.h"
|
||||
#include "../net/packet.h"
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <cereal/types/string.hpp>
|
||||
@ -151,6 +152,12 @@
|
||||
#define ServerOP_LSRemoteAddr 0x1009
|
||||
#define ServerOP_LSAccountUpdate 0x100A
|
||||
|
||||
#define ServerOP_TaskRequest 0x0300
|
||||
#define ServerOP_TaskGrant 0x0301
|
||||
#define ServerOP_TaskReject 0x0302
|
||||
#define ServerOP_TaskAddPlayer 0x0303
|
||||
#define ServerOP_TaskRemovePlayer 0x0304
|
||||
|
||||
#define ServerOP_EncapPacket 0x2007 // Packet within a packet
|
||||
#define ServerOP_WorldListUpdate 0x2008
|
||||
#define ServerOP_WorldListRemove 0x2009
|
||||
@ -246,6 +253,19 @@ public:
|
||||
_rpos = 0;
|
||||
}
|
||||
|
||||
ServerPacket(uint16 in_opcode, SerializeBuffer &buf)
|
||||
{
|
||||
compressed = false;
|
||||
size = buf.m_pos;
|
||||
buf.m_pos = 0;
|
||||
opcode = in_opcode;
|
||||
pBuffer = buf.m_buffer;
|
||||
buf.m_buffer = 0;
|
||||
buf.m_capacity = 0;
|
||||
_wpos = 0;
|
||||
_rpos = 0;
|
||||
}
|
||||
|
||||
ServerPacket* Copy() {
|
||||
if (this == 0) {
|
||||
return 0;
|
||||
|
||||
@ -563,6 +563,7 @@ OP_TaskHistoryRequest=0x6cf6
|
||||
OP_TaskHistoryReply=0x25eb
|
||||
OP_DeclineAllTasks=0x0000
|
||||
OP_TaskRequestTimer=0x4b76
|
||||
OP_AcceptNewSharedTask=0x3e5e
|
||||
|
||||
# Title opcodes
|
||||
OP_NewTitlesAvailable=0x45d1
|
||||
|
||||
@ -568,6 +568,7 @@ OP_TaskHistoryRequest=0x5f1c
|
||||
OP_TaskHistoryReply=0x3d05
|
||||
OP_DeclineAllTasks=0x0000
|
||||
OP_TaskRequestTimer=0x7a48
|
||||
OP_AcceptNewSharedTask=0x6646
|
||||
|
||||
# Title opcodes
|
||||
OP_NewTitlesAvailable=0x0d32
|
||||
|
||||
@ -534,6 +534,7 @@ OP_TaskHistoryReply=0x3d2a # C
|
||||
OP_CancelTask=0x726b # C
|
||||
OP_DeclineAllTasks=0x0000 #
|
||||
OP_TaskRequestTimer=0x2e70
|
||||
OP_AcceptNewSharedTask=0x4751
|
||||
|
||||
|
||||
OP_Shroud=0x6d1f
|
||||
|
||||
@ -510,6 +510,7 @@ OP_TaskRemovePlayer=0x516f
|
||||
OP_TaskPlayerList=0x0ad6
|
||||
OP_TaskQuit=0x2c8c
|
||||
OP_TaskRequestTimer=0x0b08
|
||||
OP_AcceptNewSharedTask=0x5bed
|
||||
|
||||
#Title opcodes
|
||||
OP_NewTitlesAvailable=0x179c #
|
||||
|
||||
@ -475,6 +475,7 @@ OP_TaskRemovePlayer=0x37b9
|
||||
OP_TaskPlayerList=0x3961
|
||||
OP_TaskQuit=0x35dd
|
||||
OP_TaskRequestTimer=0x6a1d
|
||||
OP_AcceptNewSharedTask=0x194d
|
||||
#task complete related: 0x0000 (24 bytes), 0x0000 (8 bytes), 0x0000 (4 bytes)
|
||||
|
||||
|
||||
|
||||
@ -557,6 +557,7 @@ OP_TaskHistoryReply=0x4524 # C
|
||||
OP_CancelTask=0x3bf5 # C
|
||||
OP_DeclineAllTasks=0x0000 #
|
||||
OP_TaskRequestTimer=0x719e
|
||||
OP_AcceptNewSharedTask=0x6ded
|
||||
|
||||
# Title opcodes
|
||||
OP_NewTitlesAvailable=0x4b49 # C
|
||||
|
||||
22
utils/sql/git/required/sharedtasks.sql
Normal file
22
utils/sql/git/required/sharedtasks.sql
Normal file
@ -0,0 +1,22 @@
|
||||
ALTER TABLE `tasks` ADD `reward_points` INT NOT NULL DEFAULT '0' AFTER `rewardmethod`;
|
||||
ALTER TABLE `tasks` ADD `reward_type` INT NOT NULL DEFAULT '0' AFTER `reward_points`;
|
||||
ALTER TABLE `tasks` ADD `replay_group` INT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `min_players` INT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `max_players` INT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `task_lock_step` INT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `instance_zone_id` INT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `zone_version` INT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `zone_in_zone_id` INT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `zone_in_x` FLOAT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `zone_in_y` FLOAT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `zone_in_object_id` TINYINT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `dest_x` FLOAT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `dest_y` FLOAT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `dest_z` FLOAT NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `tasks` ADD `dest_h` FLOAT NOT NULL DEFAULT '0';
|
||||
CREATE TABLE `task_replay_groups` (
|
||||
`id` INT NOT NULL,
|
||||
`duration` INT NOT NULL,
|
||||
`name` VARCHAR(128) NOT NULL DEFAULT '',
|
||||
PRIMARY KEY(`id`)
|
||||
);
|
||||
@ -229,6 +229,14 @@ struct ClientReward
|
||||
uint32 amount;
|
||||
};
|
||||
|
||||
#define PENDING_TASK_TIMEOUT 60000
|
||||
struct PendingSharedTask {
|
||||
int id;
|
||||
int task_master_id;
|
||||
Timer timeout; // so if we take a very long time to get messages back from world, we time out and fail
|
||||
PendingSharedTask() : id(0), task_master_id(0) {}
|
||||
};
|
||||
|
||||
class ClientFactory {
|
||||
public:
|
||||
Client *MakeClient(std::shared_ptr<EQStreamInterface> ieqs);
|
||||
@ -1020,8 +1028,8 @@ public:
|
||||
inline void UpdateTasksOnExplore(int ExploreID) { if(taskstate) taskstate->UpdateTasksOnExplore(this, ExploreID); }
|
||||
inline bool UpdateTasksOnSpeakWith(int NPCTypeID) { if(taskstate) return taskstate->UpdateTasksOnSpeakWith(this, NPCTypeID); else return false; }
|
||||
inline bool UpdateTasksOnDeliver(std::list<EQEmu::ItemInstance*>& Items, int Cash, int NPCTypeID) { if (taskstate) return taskstate->UpdateTasksOnDeliver(this, Items, Cash, NPCTypeID); else return false; }
|
||||
inline void TaskSetSelector(Mob *mob, int TaskSetID) { if(taskmanager) taskmanager->TaskSetSelector(this, taskstate, mob, TaskSetID); }
|
||||
inline void TaskQuestSetSelector(Mob *mob, int count, int *tasks) { if(taskmanager) taskmanager->TaskQuestSetSelector(this, taskstate, mob, count, tasks); }
|
||||
inline void TaskSetSelector(Mob *mob, int TaskSetID, bool shared = false) { if(taskmanager) taskmanager->TaskSetSelector(this, taskstate, mob, TaskSetID, shared); }
|
||||
inline void TaskQuestSetSelector(Mob *mob, int count, int *tasks, bool shared = false) { if(taskmanager) taskmanager->TaskQuestSetSelector(this, taskstate, mob, count, tasks, shared); }
|
||||
inline void EnableTask(int TaskCount, int *TaskList) { if(taskstate) taskstate->EnableTask(CharacterID(), TaskCount, TaskList); }
|
||||
inline void DisableTask(int TaskCount, int *TaskList) { if(taskstate) taskstate->DisableTask(CharacterID(), TaskCount, TaskList); }
|
||||
inline bool IsTaskEnabled(int TaskID) { return (taskstate ? taskstate->IsTaskEnabled(TaskID) : false); }
|
||||
@ -1043,6 +1051,13 @@ public:
|
||||
inline int GetTaskActivityDoneCountFromTaskID(int TaskID, int ActivityID) { return (taskstate ? taskstate->GetTaskActivityDoneCountFromTaskID(TaskID, ActivityID) :0); }
|
||||
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 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; }
|
||||
inline int GetPendingTaskID() const { return pending_task.id; }
|
||||
inline int GetPendingTaskMasterID() const { return pending_task.task_master_id; }
|
||||
inline void StartPendingTimer() { pending_task.timeout.Start(PENDING_TASK_TIMEOUT); }
|
||||
|
||||
inline const EQEmu::versions::ClientVersion ClientVersion() const { return m_ClientVersion; }
|
||||
inline const uint32 ClientVersionBit() const { return m_ClientVersionBit; }
|
||||
@ -1569,6 +1584,7 @@ private:
|
||||
std::set<uint32> zone_flags;
|
||||
|
||||
ClientTaskState *taskstate;
|
||||
PendingSharedTask pending_task;
|
||||
int TotalSecondsPlayed;
|
||||
|
||||
//Anti Spam Stuff
|
||||
|
||||
@ -114,6 +114,7 @@ void MapOpcodes()
|
||||
ConnectedOpcodes[OP_0x0193] = &Client::Handle_0x0193;
|
||||
ConnectedOpcodes[OP_AAAction] = &Client::Handle_OP_AAAction;
|
||||
ConnectedOpcodes[OP_AcceptNewTask] = &Client::Handle_OP_AcceptNewTask;
|
||||
ConnectedOpcodes[OP_AcceptNewSharedTask] = &Client::Handle_OP_AcceptNewSharedTask;
|
||||
ConnectedOpcodes[OP_AdventureInfoRequest] = &Client::Handle_OP_AdventureInfoRequest;
|
||||
ConnectedOpcodes[OP_AdventureLeaderboardRequest] = &Client::Handle_OP_AdventureLeaderboardRequest;
|
||||
ConnectedOpcodes[OP_AdventureMerchantPurchase] = &Client::Handle_OP_AdventureMerchantPurchase;
|
||||
@ -1840,6 +1841,20 @@ void Client::Handle_OP_AcceptNewTask(const EQApplicationPacket *app)
|
||||
taskstate->AcceptNewTask(this, ant->task_id, ant->task_master_id);
|
||||
}
|
||||
|
||||
void Client::Handle_OP_AcceptNewSharedTask(const EQApplicationPacket *app)
|
||||
{
|
||||
if (app->size != sizeof(AcceptNewSharedTask_Struct)) {
|
||||
Log(Logs::General, Logs::None, "Size mismatch in OP_AcceptNewSharedTask expected %i got %i",
|
||||
sizeof(AcceptNewSharedTask_Struct), app->size);
|
||||
DumpPacket(app);
|
||||
return;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
void Client::Handle_OP_AdventureInfoRequest(const EQApplicationPacket *app)
|
||||
{
|
||||
if (app->size < sizeof(EntityId_Struct))
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
void Handle_0x01e7(const EQApplicationPacket *app);
|
||||
void Handle_OP_AAAction(const EQApplicationPacket *app);
|
||||
void Handle_OP_AcceptNewTask(const EQApplicationPacket *app);
|
||||
void Handle_OP_AcceptNewSharedTask(const EQApplicationPacket *app);
|
||||
void Handle_OP_AdventureInfoRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_AdventureLeaderboardRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_AdventureMerchantPurchase(const EQApplicationPacket *app);
|
||||
|
||||
@ -159,6 +159,12 @@ bool Client::Process() {
|
||||
if (TaskPeriodic_Timer.Check() && taskstate)
|
||||
taskstate->TaskPeriodicChecks(this);
|
||||
|
||||
if (pending_task.timeout.Check(false)) {
|
||||
Message(13, "Shared task timed out.");
|
||||
pending_task.id = 0;
|
||||
pending_task.task_master_id = 0;
|
||||
}
|
||||
|
||||
if (linkdead_timer.Check()) {
|
||||
LeaveGroup();
|
||||
Save();
|
||||
|
||||
@ -2048,6 +2048,23 @@ XS(XS__taskselector) {
|
||||
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__sharedtaskselector);
|
||||
XS(XS__sharedtaskselector) {
|
||||
dXSARGS;
|
||||
if ((items >= 1) && (items <= MAXCHOOSERENTRIES)) {
|
||||
int tasks[MAXCHOOSERENTRIES];
|
||||
for (int i = 0; i < items; i++) {
|
||||
tasks[i] = (int) SvIV(ST(i));
|
||||
}
|
||||
quest_manager.taskselector(items, tasks, true);
|
||||
} else {
|
||||
Perl_croak(aTHX_ "Usage: quest::sharedtaskselector(int task_id, 2, 3, 4, 5 [up to 40])");
|
||||
}
|
||||
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__task_setselector);
|
||||
XS(XS__task_setselector) {
|
||||
dXSARGS;
|
||||
@ -3770,6 +3787,7 @@ EXTERN_C XS(boot_quest) {
|
||||
newXS(strcpy(buf, "targlobal"), XS__targlobal, file);
|
||||
newXS(strcpy(buf, "taskexploredarea"), XS__taskexploredarea, file);
|
||||
newXS(strcpy(buf, "taskselector"), XS__taskselector, file);
|
||||
newXS(strcpy(buf, "sharedtaskselector"), XS__sharedtaskselector, file);
|
||||
newXS(strcpy(buf, "task_setselector"), XS__task_setselector, file);
|
||||
newXS(strcpy(buf, "tasktimeleft"), XS__tasktimeleft, file);
|
||||
newXS(strcpy(buf, "toggle_spawn_event"), XS__toggle_spawn_event, file);
|
||||
|
||||
@ -581,6 +581,32 @@ void lua_task_selector(luabind::adl::object table) {
|
||||
quest_manager.taskselector(count, tasks);
|
||||
}
|
||||
|
||||
void lua_task_selector(luabind::adl::object table, bool shared) {
|
||||
if(luabind::type(table) != LUA_TTABLE) {
|
||||
return;
|
||||
}
|
||||
|
||||
int tasks[MAXCHOOSERENTRIES] = { 0 };
|
||||
int count = 0;
|
||||
|
||||
for(int i = 1; i <= MAXCHOOSERENTRIES; ++i) {
|
||||
auto cur = table[i];
|
||||
int cur_value = 0;
|
||||
if(luabind::type(cur) != LUA_TNIL) {
|
||||
try {
|
||||
cur_value = luabind::object_cast<int>(cur);
|
||||
} catch(luabind::cast_failed) {
|
||||
}
|
||||
} else {
|
||||
count = i - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
tasks[i - 1] = cur_value;
|
||||
}
|
||||
quest_manager.taskselector(count, tasks, shared);
|
||||
}
|
||||
|
||||
void lua_task_set_selector(int task_set) {
|
||||
quest_manager.tasksetselector(task_set);
|
||||
}
|
||||
@ -1630,7 +1656,8 @@ luabind::scope lua_register_general() {
|
||||
luabind::def("summon_all_player_corpses", &lua_summon_all_player_corpses),
|
||||
luabind::def("get_player_buried_corpse_count", &lua_get_player_buried_corpse_count),
|
||||
luabind::def("bury_player_corpse", &lua_bury_player_corpse),
|
||||
luabind::def("task_selector", &lua_task_selector),
|
||||
luabind::def("task_selector", (void(*)(luabind::adl::object))&lua_task_selector),
|
||||
luabind::def("task_selector", (void(*)(luabind::adl::object,bool))&lua_task_selector),
|
||||
luabind::def("task_set_selector", &lua_task_set_selector),
|
||||
luabind::def("enable_task", &lua_enable_task),
|
||||
luabind::def("disable_task", &lua_disable_task),
|
||||
|
||||
@ -2146,10 +2146,10 @@ bool QuestManager::createBot(const char *name, const char *lastname, uint8 level
|
||||
|
||||
#endif //BOTS
|
||||
|
||||
void QuestManager::taskselector(int taskcount, int *tasks) {
|
||||
void QuestManager::taskselector(int taskcount, int *tasks, bool shared) {
|
||||
QuestManagerCurrentQuestVars();
|
||||
if(RuleB(TaskSystem, EnableTaskSystem) && initiator && owner && taskmanager)
|
||||
initiator->TaskQuestSetSelector(owner, taskcount, tasks);
|
||||
initiator->TaskQuestSetSelector(owner, taskcount, tasks, shared);
|
||||
}
|
||||
void QuestManager::enabletask(int taskcount, int *tasks) {
|
||||
QuestManagerCurrentQuestVars();
|
||||
@ -2174,11 +2174,11 @@ bool QuestManager::istaskenabled(int taskid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void QuestManager::tasksetselector(int tasksetid) {
|
||||
void QuestManager::tasksetselector(int tasksetid, bool shared) {
|
||||
QuestManagerCurrentQuestVars();
|
||||
Log(Logs::General, Logs::Tasks, "[UPDATE] TaskSetSelector called for task set %i", tasksetid);
|
||||
if(RuleB(TaskSystem, EnableTaskSystem) && initiator && owner && taskmanager)
|
||||
initiator->TaskSetSelector(owner, tasksetid);
|
||||
initiator->TaskSetSelector(owner, tasksetid, shared);
|
||||
}
|
||||
|
||||
bool QuestManager::istaskactive(int task) {
|
||||
|
||||
@ -188,8 +188,8 @@ public:
|
||||
void playerfeature(char *feature, int setting);
|
||||
void npcfeature(char *feature, int setting);
|
||||
void popup(const char *title, const char *text, uint32 popupid, uint32 buttons, uint32 Duration);
|
||||
void taskselector(int taskcount, int *tasks);
|
||||
void tasksetselector(int tasksettid);
|
||||
void taskselector(int taskcount, int *tasks, bool shared = false);
|
||||
void tasksetselector(int tasksettid, bool shared = false);
|
||||
void enabletask(int taskcount, int *tasks);
|
||||
void disabletask(int taskcount, int *tasks);
|
||||
bool istaskenabled(int taskid);
|
||||
|
||||
@ -359,6 +359,7 @@
|
||||
#define LDON_NO_LOCKPICK 7564 //You must have a lock pick in your inventory to do this.
|
||||
#define LDON_WAS_NOT_LOCKED 7565 //%1 was not locked.
|
||||
#define LDON_WAS_NOT_TRAPPED 7566 //%1 was not trapped
|
||||
#define TASK_REJECT_LOCKEDOUT_ME 8017 //This task can not be assigned to you because you must wait %1d:%2h:%3m before you can do another task of this type.
|
||||
#define GAIN_GROUP_LEADERSHIP_POINT 8585 //
|
||||
#define GAIN_RAID_LEADERSHIP_POINT 8589 //
|
||||
#define MAX_GROUP_LEADERSHIP_POINTS 8584 //
|
||||
@ -369,6 +370,15 @@
|
||||
#define GAIN_GROUP_LEADERSHIP_EXP 8788 //
|
||||
#define GAIN_RAID_LEADERSHIP_EXP 8789 //
|
||||
#define BUFF_MINUTES_REMAINING 8799 //%1 (%2 minutes remaining)
|
||||
#define TASK_REJECT_MAX_COUNT 8891 //You can not be assigned this shared task because your party exceeds the maximum allowed number of players.
|
||||
#define TASK_REJECT_LEADER_REQ 8892 //You can not be assigned this shared task because the leader does not meet the shared task requirements.
|
||||
#define TASK_REJECT_MIN_COUNT 8895 //You can not be assigned this shared task because your party does not contain the minimum required number of players.
|
||||
#define TASK_REJECT_HAVE_ONE 8935 //You may not request a shared task because you already have one.
|
||||
#define TASK_REJECT_RAID_HAVE_ONE 8936 //You may not request a shared task because someone in your raid, %1, already has one.
|
||||
#define TASK_REJECT_GROUP_HAVE_ONE 8937 //You may not request a shared task because someone in your group, %1, already has one.
|
||||
#define TASK_REJECT_LOCKEDOUT 8946 //You may not request this shared task because you must wait %1d:%2h:%3m before you can do another task of this type.
|
||||
#define TASK_REJECT_LOCKEDOUT_OTHER 8947 //You may not request this shared task because %1 must wait %2d:%3h:%4m before they can do another task of this type.
|
||||
#define SHARED_TASK_LOCK 8961 //Your shared task is now locked. You may no longer add or remove players.
|
||||
#define NO_MORE_TRAPS 9002 //You have already placed your maximum number of traps.
|
||||
#define FEAR_TOO_HIGH 9035 //Your target is too high of a level for your fear spell.
|
||||
#define SLOW_MOSTLY_SUCCESSFUL 9029 //Your spell was mostly successful.
|
||||
|
||||
280
zone/tasks.cpp
280
zone/tasks.cpp
@ -30,16 +30,19 @@ Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net)
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/say_link.h"
|
||||
#include "../common/data_verification.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "entity.h"
|
||||
#include "mob.h"
|
||||
#include "string_ids.h"
|
||||
#include "worldserver.h"
|
||||
|
||||
#include "queryserv.h"
|
||||
#include "quest_parser_collection.h"
|
||||
|
||||
extern QueryServ* QServ;
|
||||
extern WorldServer worldserver;
|
||||
|
||||
TaskManager::TaskManager() {
|
||||
for(int i=0; i<MAXTASKS; i++)
|
||||
@ -116,15 +119,26 @@ bool TaskManager::LoadTasks(int singleTask)
|
||||
if (!LoadTaskSets())
|
||||
Log(Logs::Detail, Logs::Tasks, "TaskManager::LoadTasks LoadTaskSets failed");
|
||||
|
||||
query = StringFormat("SELECT `id`, `type`, `duration`, `duration_code`, `title`, `description`, "
|
||||
"`reward`, `rewardid`, `cashreward`, `xpreward`, `rewardmethod`, `faction_reward`,"
|
||||
"`minlevel`, `maxlevel`, `repeatable`, `completion_emote` FROM `tasks` WHERE `id` < %i",
|
||||
MAXTASKS);
|
||||
if (!LoadReplayGroups())
|
||||
Log(Logs::Detail, Logs::Tasks, "TaskManager::LoadTasks LoadReplayGroups failed");
|
||||
|
||||
query =
|
||||
StringFormat("SELECT `id`, `type`, `duration`, `duration_code`, `title`, `description`, `reward`, "
|
||||
"`rewardid`, `cashreward`, `xpreward`, `rewardmethod`, `faction_reward`, `minlevel`, "
|
||||
"`maxlevel`, `repeatable`, `completion_emote`, `reward_points`, `reward_type`, "
|
||||
"`replay_group`, `min_players`, `max_players`, `task_lock_step`, `instance_zone_id`, "
|
||||
"`zone_version`, `zone_in_zone_id`, `zone_in_x`, `zone_in_y`, `zone_in_object_id`, "
|
||||
"`dest_x`, `dest_y`, `dest_z`, `dest_h` FROM `tasks` WHERE `id` < %i",
|
||||
MAXTASKS);
|
||||
} else
|
||||
query = StringFormat("SELECT `id`, `type`, `duration`, `duration_code`, `title`, `description`, "
|
||||
"`reward`, `rewardid`, `cashreward`, `xpreward`, `rewardmethod`, `faction_reward`,"
|
||||
"`minlevel`, `maxlevel`, `repeatable`, `completion_emote` FROM `tasks` WHERE `id` = %i",
|
||||
singleTask);
|
||||
query =
|
||||
StringFormat("SELECT `id`, `type`, `duration`, `duration_code`, `title`, `description`, `reward`, "
|
||||
"`rewardid`, `cashreward`, `xpreward`, `rewardmethod`, `faction_reward`, `minlevel`, "
|
||||
"`maxlevel`, `repeatable`, `completion_emote`, `reward_points`, `reward_type`, "
|
||||
"`replay_group`, `min_players`, `max_players`, `task_lock_step`, `instance_zone_id`, "
|
||||
"`zone_version`, `zone_in_zone_id`, `zone_in_x`, `zone_in_y`, `zone_in_object_id`, "
|
||||
"`dest_x`, `dest_y`, `dest_z`, `dest_h` FROM `tasks` WHERE `id` = %i",
|
||||
singleTask);
|
||||
|
||||
const char *ERR_MYSQLERROR = "[TASKS]Error in TaskManager::LoadTasks: %s";
|
||||
|
||||
@ -160,6 +174,22 @@ bool TaskManager::LoadTasks(int singleTask)
|
||||
Tasks[taskID]->MaxLevel = atoi(row[13]);
|
||||
Tasks[taskID]->Repeatable = atoi(row[14]);
|
||||
Tasks[taskID]->completion_emote = row[15];
|
||||
Tasks[taskID]->reward_points = atoi(row[16]);
|
||||
Tasks[taskID]->reward_type = static_cast<PointType>(atoi(row[17]));
|
||||
Tasks[taskID]->replay_group = atoi(row[18]);
|
||||
Tasks[taskID]->min_players = atoi(row[19]);
|
||||
Tasks[taskID]->max_players = atoi(row[20]);
|
||||
Tasks[taskID]->task_lock_step = atoi(row[21]);
|
||||
Tasks[taskID]->instance_zone_id = atoi(row[22]);
|
||||
Tasks[taskID]->zone_version = atoi(row[23]);
|
||||
Tasks[taskID]->zone_in_zone_id = atoi(row[24]);
|
||||
Tasks[taskID]->zone_in_x = atof(row[25]);
|
||||
Tasks[taskID]->zone_in_y = atof(row[26]);
|
||||
Tasks[taskID]->zone_in_object_id = atoi(row[27]);
|
||||
Tasks[taskID]->dest_x = atof(row[28]);
|
||||
Tasks[taskID]->dest_y = atof(row[29]);
|
||||
Tasks[taskID]->dest_z = atof(row[30]);
|
||||
Tasks[taskID]->dest_h = atof(row[31]);
|
||||
Tasks[taskID]->ActivityCount = 0;
|
||||
Tasks[taskID]->SequenceMode = ActivitiesSequential;
|
||||
Tasks[taskID]->LastStep = 0;
|
||||
@ -281,6 +311,22 @@ bool TaskManager::LoadTasks(int singleTask)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TaskManager::LoadReplayGroups()
|
||||
{
|
||||
replay_groups.clear();
|
||||
std::string query = "SELECT `id`, `name`, `duration` FROM `task_replay_groups` WHERE `id` > 0 ORDER BY `id` ASC";
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
return false;
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
replay_groups[atoi(row[0])] = {row[1], atoi(row[2])};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TaskManager::SaveClientState(Client *c, ClientTaskState *state)
|
||||
{
|
||||
// I am saving the slot in the ActiveTasks table, because unless a Task is cancelled/completed, the client
|
||||
@ -905,7 +951,7 @@ bool ClientTaskState::HasSlotForTask(TaskInformation *task)
|
||||
case TaskType::Task:
|
||||
return ActiveTask.TaskID == TASKSLOTEMPTY;
|
||||
case TaskType::Shared:
|
||||
return false; // todo
|
||||
return ActiveSharedTask == nullptr; // todo
|
||||
case TaskType::Quest:
|
||||
for (int i = 0; i < MAXACTIVEQUESTS; ++i)
|
||||
if (ActiveQuests[i].TaskID == TASKSLOTEMPTY)
|
||||
@ -988,7 +1034,7 @@ int TaskManager::GetTaskMaxLevel(int TaskID)
|
||||
return -1;
|
||||
}
|
||||
|
||||
void TaskManager::TaskSetSelector(Client *c, ClientTaskState *state, Mob *mob, int TaskSetID)
|
||||
void TaskManager::TaskSetSelector(Client *c, ClientTaskState *state, Mob *mob, int TaskSetID, bool shared)
|
||||
{
|
||||
int TaskList[MAXCHOOSERENTRIES];
|
||||
int TaskListIndex = 0;
|
||||
@ -1024,14 +1070,14 @@ void TaskManager::TaskSetSelector(Client *c, ClientTaskState *state, Mob *mob, i
|
||||
// we aren't currently on another, and if it's enabled if not all_enabled
|
||||
if ((all_enabled || state->IsTaskEnabled(task)) && AppropriateLevel(task, PlayerLevel) &&
|
||||
!state->IsTaskActive(task) && state->HasSlotForTask(Tasks[task]) && // this slot checking is a bit silly, but we allow mixing of task types ...
|
||||
(IsTaskRepeatable(task) || !state->IsTaskCompleted(task)))
|
||||
(IsTaskRepeatable(task) || !state->IsTaskCompleted(task)) && (shared == (Tasks[task]->type == TaskType::Shared)))
|
||||
TaskList[TaskListIndex++] = task;
|
||||
|
||||
++Iterator;
|
||||
}
|
||||
|
||||
if (TaskListIndex > 0) {
|
||||
SendTaskSelector(c, mob, TaskListIndex, TaskList);
|
||||
SendTaskSelector(c, mob, TaskListIndex, TaskList, shared);
|
||||
} else {
|
||||
mob->SayTo_StringID(c, CC_Yellow, MAX_ACTIVE_TASKS, c->GetName()); // check color, I think this might be only for (Shared) Tasks, w/e -- think should be yellow
|
||||
}
|
||||
@ -1041,7 +1087,7 @@ void TaskManager::TaskSetSelector(Client *c, ClientTaskState *state, Mob *mob, i
|
||||
|
||||
// unlike the non-Quest version of this function, it does not check enabled, that is assumed the responsibility of the quest to handle
|
||||
// we do however still want it to check the other stuff like level, active, room, etc
|
||||
void TaskManager::TaskQuestSetSelector(Client *c, ClientTaskState *state, Mob *mob, int count, int *tasks)
|
||||
void TaskManager::TaskQuestSetSelector(Client *c, ClientTaskState *state, Mob *mob, int count, int *tasks, bool shared)
|
||||
{
|
||||
int TaskList[MAXCHOOSERENTRIES];
|
||||
int TaskListIndex = 0;
|
||||
@ -1058,12 +1104,12 @@ void TaskManager::TaskQuestSetSelector(Client *c, ClientTaskState *state, Mob *m
|
||||
// we aren't currently on another, and if it's enabled if not all_enabled
|
||||
if (AppropriateLevel(task, PlayerLevel) &&
|
||||
!state->IsTaskActive(task) && state->HasSlotForTask(Tasks[task]) && // this slot checking is a bit silly, but we allow mixing of task types ...
|
||||
(IsTaskRepeatable(task) || !state->IsTaskCompleted(task)))
|
||||
(IsTaskRepeatable(task) || !state->IsTaskCompleted(task)) && (shared == (Tasks[task]->type == TaskType::Shared)))
|
||||
TaskList[TaskListIndex++] = task;
|
||||
}
|
||||
|
||||
if (TaskListIndex > 0) {
|
||||
SendTaskSelector(c, mob, TaskListIndex, TaskList);
|
||||
SendTaskSelector(c, mob, TaskListIndex, TaskList, shared);
|
||||
} else {
|
||||
mob->SayTo_StringID(c, CC_Yellow, MAX_ACTIVE_TASKS, c->GetName()); // check color, I think this might be only for (Shared) Tasks, w/e -- think should be yellow
|
||||
}
|
||||
@ -1071,11 +1117,11 @@ void TaskManager::TaskQuestSetSelector(Client *c, ClientTaskState *state, Mob *m
|
||||
return;
|
||||
}
|
||||
|
||||
void TaskManager::SendTaskSelector(Client *c, Mob *mob, int TaskCount, int *TaskList) {
|
||||
void TaskManager::SendTaskSelector(Client *c, Mob *mob, int TaskCount, int *TaskList, bool shared) {
|
||||
|
||||
if (c->ClientVersion() >= EQEmu::versions::ClientVersion::RoF)
|
||||
{
|
||||
SendTaskSelectorNew(c, mob, TaskCount, TaskList);
|
||||
SendTaskSelectorNew(c, mob, TaskCount, TaskList, shared);
|
||||
return;
|
||||
}
|
||||
// Titanium OpCode: 0x5e7c
|
||||
@ -1108,7 +1154,7 @@ void TaskManager::SendTaskSelector(Client *c, Mob *mob, int TaskCount, int *Task
|
||||
|
||||
|
||||
buf.WriteUInt32(ValidTasks);
|
||||
buf.WriteUInt32(2); // task type, live doesn't let you send more than one type, but we do?
|
||||
buf.WriteUInt32(shared ? static_cast<uint32>(TaskType::Shared) : static_cast<uint32>(TaskType::Quest)); // hack, we need to send only shared tasks when doing shared tasks since they use different reply ops
|
||||
buf.WriteUInt32(mob->GetID());
|
||||
|
||||
for (int i = 0; i < TaskCount; i++) {
|
||||
@ -1158,7 +1204,7 @@ void TaskManager::SendTaskSelector(Client *c, Mob *mob, int TaskCount, int *Task
|
||||
|
||||
}
|
||||
|
||||
void TaskManager::SendTaskSelectorNew(Client *c, Mob *mob, int TaskCount, int *TaskList)
|
||||
void TaskManager::SendTaskSelectorNew(Client *c, Mob *mob, int TaskCount, int *TaskList, bool shared)
|
||||
{
|
||||
Log(Logs::General, Logs::Tasks, "[UPDATE] TaskSelector for %i Tasks", TaskCount);
|
||||
|
||||
@ -1188,9 +1234,7 @@ void TaskManager::SendTaskSelectorNew(Client *c, Mob *mob, int TaskCount, int *T
|
||||
SerializeBuffer buf(50 * ValidTasks);
|
||||
|
||||
buf.WriteUInt32(ValidTasks); // TaskCount
|
||||
buf.WriteUInt32(2); // Type, valid values: 0-3. 0 = Task, 1 = Shared Task, 2 = Quest, 3 = ??? -- should fix maybe some day, but we let more than 1 type through :P
|
||||
// so I guess an NPC can only offer one type of quests or we can only open a selection with one type :P (so quest call can tell us I guess)
|
||||
// this is also sent in OP_TaskDescription
|
||||
buf.WriteUInt32(shared ? static_cast<uint32>(TaskType::Shared) : static_cast<uint32>(TaskType::Quest)); // hack, we need to send only shared tasks when doing shared tasks since they use different reply ops
|
||||
buf.WriteUInt32(mob->GetID()); // TaskGiver
|
||||
|
||||
for (int i = 0; i < TaskCount; i++) { // max 40
|
||||
@ -1304,7 +1348,8 @@ ClientTaskState::ClientTaskState() {
|
||||
|
||||
ActiveTask.slot = 0;
|
||||
ActiveTask.TaskID = TASKSLOTEMPTY;
|
||||
// TODO: shared task
|
||||
|
||||
ActiveSharedTask = nullptr;
|
||||
}
|
||||
|
||||
ClientTaskState::~ClientTaskState() {
|
||||
@ -3324,6 +3369,164 @@ 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)
|
||||
{
|
||||
if (!taskmanager || TaskID < 0 || TaskID >= MAXTASKS) {
|
||||
c->Message(13, "Task system not functioning, or TaskID %i out of range.", TaskID);
|
||||
return;
|
||||
}
|
||||
|
||||
auto task = taskmanager->Tasks[TaskID];
|
||||
|
||||
if (task == nullptr) {
|
||||
c->Message(13, "Invalid TaskID %i", TaskID);
|
||||
return;
|
||||
}
|
||||
|
||||
if (task->type != TaskType::Shared) {
|
||||
c->Message(13, "Trying to shared task a non shared task %i", TaskID);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ActiveSharedTask != nullptr) {
|
||||
c->Message_StringID(13, TASK_REJECT_HAVE_ONE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (enforce_level_requirement && !taskmanager->AppropriateLevel(TaskID, c->GetLevel())) {
|
||||
c->Message(13, "You are outside the level range of this task.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!taskmanager->IsTaskRepeatable(TaskID) && IsTaskCompleted(TaskID))
|
||||
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);
|
||||
c->Message_StringID(13, TASK_REJECT_LOCKEDOUT, days.c_str(), hours.c_str(), minutes.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Now we need to verify we meet min_player and max_players for raid/group
|
||||
Group *group = nullptr;
|
||||
Raid *raid = nullptr;
|
||||
int player_count = 1; // 1 is just us!
|
||||
if (c->IsGrouped()) {
|
||||
group = c->GetGroup();
|
||||
player_count = group->GroupCount();
|
||||
} else if (c->IsRaidGrouped()) {
|
||||
raid = c->GetRaid();
|
||||
player_count = raid->RaidCount();
|
||||
}
|
||||
|
||||
// TODO: check task lockouts I guess it's simpler to require everyone to be in zone so we can verify lockouts ...
|
||||
|
||||
if (!EQEmu::ValueWithin(player_count, task->min_players, task->max_players)) {
|
||||
if (player_count < task->min_players)
|
||||
c->Message_StringID(13, TASK_REJECT_MIN_COUNT);
|
||||
else
|
||||
c->Message_StringID(13, TASK_REJECT_MAX_COUNT);
|
||||
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] && 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());
|
||||
} else {
|
||||
if (task->replay_group) {
|
||||
auto expires = client->GetTaskLockoutExpire(task->replay_group);
|
||||
if (expires) {
|
||||
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);
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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) {
|
||||
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());
|
||||
} else {
|
||||
if (task->replay_group) {
|
||||
auto expires = client->GetTaskLockoutExpire(task->replay_group);
|
||||
if (expires) {
|
||||
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);
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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
|
||||
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
|
||||
|
||||
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::ProcessTaskProximities(Client *c, float X, float Y, float Z) {
|
||||
|
||||
float LastX = c->ProximityX();
|
||||
@ -3537,3 +3740,34 @@ int TaskProximityManager::CheckProximities(float X, float Y, float Z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SharedTaskState::LockTask()
|
||||
{
|
||||
SetLocked(true);
|
||||
|
||||
for (auto & m : members)
|
||||
if (m.entity != nullptr)
|
||||
m.entity->Message_StringID(CC_Yellow, SHARED_TASK_LOCK);
|
||||
}
|
||||
|
||||
void SharedTaskState::MemberZoned(Mob *player)
|
||||
{
|
||||
auto it = std::find_if(members.begin(), members.end(),
|
||||
[&player](const SharedTaskMember &a) { return a.name == player->GetName(); });
|
||||
|
||||
if (it == members.end()) // guess they weren't in this group, w/e
|
||||
return;
|
||||
|
||||
it->entity = nullptr;
|
||||
}
|
||||
|
||||
void SharedTaskState::MemberEnterZone(Mob *player)
|
||||
{
|
||||
auto it = std::find_if(members.begin(), members.end(),
|
||||
[&player](const SharedTaskMember &a) { return a.name == player->GetName(); });
|
||||
|
||||
if (it == members.end()) // guess they weren't in this group, w/e
|
||||
return;
|
||||
|
||||
it->entity = player;
|
||||
}
|
||||
|
||||
|
||||
87
zone/tasks.h
87
zone/tasks.h
@ -26,6 +26,8 @@ Copyright (C) 2001-2004 EQEMu Development Team (http://eqemulator.net)
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
|
||||
#define MAXTASKS 10000
|
||||
#define MAXTASKSETS 1000
|
||||
@ -141,6 +143,13 @@ enum class DurationCode {
|
||||
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;
|
||||
@ -155,12 +164,33 @@ struct TaskInformation {
|
||||
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];
|
||||
};
|
||||
|
||||
@ -193,6 +223,35 @@ struct CompletedTaskInformation {
|
||||
bool ActivityDone[MAXACTIVITIESPERTASK];
|
||||
};
|
||||
|
||||
struct SharedTaskMember {
|
||||
std::string name;
|
||||
Mob *entity; // needs to be managed
|
||||
bool leader;
|
||||
SharedTaskMember() : entity(nullptr), leader(false) {}
|
||||
};
|
||||
|
||||
class SharedTaskState {
|
||||
public:
|
||||
SharedTaskState() : locked(false) {}
|
||||
// ~SharedTaskState();
|
||||
|
||||
inline const bool IsLocked() const { return locked; }
|
||||
inline void SetLocked(bool v) { locked = v; }
|
||||
void LockTask(); // notified clients (if they are etc)
|
||||
|
||||
void MemberZoned(Mob *player); // player left zone, update their pointer
|
||||
void MemberEnterZone(Mob *player); // player entered zone, update their pointer
|
||||
|
||||
ClientTaskInformation *GetActivity() { return &activity; }
|
||||
|
||||
friend class TaskManager;
|
||||
|
||||
private:
|
||||
std::vector<SharedTaskMember> members;
|
||||
ClientTaskInformation activity;
|
||||
bool locked;
|
||||
};
|
||||
|
||||
class ClientTaskState {
|
||||
|
||||
public:
|
||||
@ -206,6 +265,8 @@ 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, bool enforce_level_requirement = false);
|
||||
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);
|
||||
@ -255,6 +316,8 @@ private:
|
||||
info = &ActiveTask;
|
||||
break;
|
||||
case TaskType::Shared:
|
||||
if (index == 0 && ActiveSharedTask)
|
||||
info = ActiveSharedTask->GetActivity();
|
||||
break;
|
||||
case TaskType::Quest:
|
||||
if (index < MAXACTIVEQUESTS)
|
||||
@ -273,6 +336,7 @@ private:
|
||||
};
|
||||
ClientTaskInformation ActiveTasks[MAXACTIVEQUESTS + 1];
|
||||
};
|
||||
SharedTaskState *ActiveSharedTask; // pointer to our shared task managed by TaskManager
|
||||
// Shared tasks should be limited to 1 as well
|
||||
std::vector<int> EnabledTasks;
|
||||
std::vector<CompletedTaskInformation> CompletedTasks;
|
||||
@ -280,6 +344,17 @@ 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;
|
||||
};
|
||||
|
||||
class TaskManager {
|
||||
|
||||
@ -289,18 +364,19 @@ public:
|
||||
int GetActivityCount(int TaskID);
|
||||
bool LoadSingleTask(int TaskID);
|
||||
bool LoadTasks(int SingleTask=0);
|
||||
bool LoadReplayGroups();
|
||||
void ReloadGoalLists();
|
||||
inline void LoadProximities(int ZoneID) { ProximityManager.LoadProximities(ZoneID); }
|
||||
bool LoadTaskSets();
|
||||
bool LoadClientState(Client *c, ClientTaskState *state);
|
||||
bool SaveClientState(Client *c, ClientTaskState *state);
|
||||
void SendTaskSelector(Client *c, Mob *mob, int TaskCount, int *TaskList);
|
||||
void SendTaskSelectorNew(Client *c, Mob *mob, int TaskCount, int *TaskList);
|
||||
void SendTaskSelector(Client *c, Mob *mob, int TaskCount, int *TaskList, bool shared = false); // dumb hack cuz we do dumb things
|
||||
void SendTaskSelectorNew(Client *c, Mob *mob, int TaskCount, int *TaskList, bool shared = false);
|
||||
bool AppropriateLevel(int TaskID, int PlayerLevel);
|
||||
int GetTaskMinLevel(int TaskID);
|
||||
int GetTaskMaxLevel(int TaskID);
|
||||
void TaskSetSelector(Client *c, ClientTaskState *state, Mob *mob, int TaskSetID);
|
||||
void TaskQuestSetSelector(Client *c, ClientTaskState *state, Mob *mob, int count, int *tasks); // task list provided by QuestManager (perl/lua)
|
||||
void TaskSetSelector(Client *c, ClientTaskState *state, Mob *mob, int TaskSetID, bool shared = false);
|
||||
void TaskQuestSetSelector(Client *c, ClientTaskState *state, Mob *mob, int count, int *tasks, bool shared = false); // task list provided by QuestManager (perl/lua)
|
||||
void SendActiveTasksToClient(Client *c, bool TaskComplete=false);
|
||||
void SendSingleActiveTaskToClient(Client *c, ClientTaskInformation &task_info, bool TaskComplete, bool BringUpTaskJournal = false);
|
||||
void SendTaskActivityShort(Client *c, int TaskID, int ActivityID, int ClientTaskIndex);
|
||||
@ -316,6 +392,7 @@ public:
|
||||
bool IsTaskRepeatable(int TaskID);
|
||||
friend class ClientTaskState;
|
||||
|
||||
void LoadSharedTask(int id); // loads the shared task state
|
||||
|
||||
private:
|
||||
TaskGoalListManager GoalListManager;
|
||||
@ -323,6 +400,8 @@ private:
|
||||
TaskInformation* Tasks[MAXTASKS];
|
||||
std::vector<int> TaskSets[MAXTASKSETS];
|
||||
void SendActiveTaskDescription(Client *c, int TaskID, ClientTaskInformation &task_info, int StartTime, int Duration, bool BringUpTaskJournal=false);
|
||||
std::unordered_map<int, SharedTaskState> SharedTasks;
|
||||
std::map<int, TaskReplayGroups> replay_groups;
|
||||
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user