mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 10:31:29 +00:00
commit
5a94e82db8
16
.drone.yml
Normal file
16
.drone.yml
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: EQEmulator Server Linux CI
|
||||
|
||||
# Limits how many of these builds can run on the drone runner at a time, this isn't about cores
|
||||
concurrency:
|
||||
limit: 1
|
||||
|
||||
steps:
|
||||
- name: server-build
|
||||
# Source build script https://github.com/Akkadius/akk-stack/blob/master/containers/eqemu-server/Dockerfile#L20
|
||||
image: akkadius/eqemu-server:latest
|
||||
commands:
|
||||
- sudo chown eqemu:eqemu /drone/src/ * -R
|
||||
- git submodule init && git submodule update && mkdir -p build && cd build && cmake -DEQEMU_BUILD_LOGIN=ON -DEQEMU_BUILD_BOTS=ON -DEQEMU_BUILD_LUA=ON -G 'Unix Makefiles' .. && make -j$((`nproc`-4))
|
||||
@ -12,7 +12,7 @@ IF(NOT CMAKE_BUILD_TYPE)
|
||||
SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE)
|
||||
ENDIF(NOT CMAKE_BUILD_TYPE)
|
||||
|
||||
SET(CMAKE_CXX_STANDARD 11)
|
||||
SET(CMAKE_CXX_STANDARD 14)
|
||||
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
SET(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
|
||||
@ -80,3 +80,4 @@ forum, although pull requests will be much quicker and easier on all parties.
|
||||
<a href="https://github.com/EQEmu/server/graphs/contributors">
|
||||
<img src="https://contributors-img.firebaseapp.com/image?repo=EQEmu/server" />
|
||||
</a>
|
||||
|
||||
|
||||
@ -378,6 +378,8 @@ const char *GetClassIDName(uint8 class_id, uint8 level)
|
||||
return "Berserker Guildmaster";
|
||||
case MERCHANT:
|
||||
return "Merchant";
|
||||
case DISCORD_MERCHANT:
|
||||
return "Discord Merchant";
|
||||
case ADVENTURERECRUITER:
|
||||
return "Adventure Recruiter";
|
||||
case ADVENTUREMERCHANT:
|
||||
@ -388,6 +390,18 @@ const char *GetClassIDName(uint8 class_id, uint8 level)
|
||||
return "Tribute Master";
|
||||
case GUILD_TRIBUTE_MASTER:
|
||||
return "Guild Tribute Master";
|
||||
case GUILD_BANKER:
|
||||
return "Guild Banker";
|
||||
case NORRATHS_KEEPERS_MERCHANT:
|
||||
return "Radiant Crystal Merchant";
|
||||
case DARK_REIGN_MERCHANT:
|
||||
return "Ebon Crystal Merchant";
|
||||
case FELLOWSHIP_MASTER:
|
||||
return "Fellowship Master";
|
||||
case ALT_CURRENCY_MERCHANT:
|
||||
return "Alternate Currency Merchant";
|
||||
case MERCERNARY_MASTER:
|
||||
return "Mercenary Liaison";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
@ -61,6 +61,7 @@
|
||||
#define CORPSE_CLASS 62 // only seen on Danvi's Corpse in Akheva so far..
|
||||
#define TRIBUTE_MASTER 63
|
||||
#define GUILD_TRIBUTE_MASTER 64 // not sure
|
||||
#define GUILD_BANKER 66
|
||||
#define NORRATHS_KEEPERS_MERCHANT 67
|
||||
#define DARK_REIGN_MERCHANT 68
|
||||
#define FELLOWSHIP_MASTER 69
|
||||
|
||||
@ -300,8 +300,7 @@ void DatabaseDumpService::Dump()
|
||||
config->DatabaseUsername
|
||||
);
|
||||
|
||||
std::string options = "--allow-keywords --extended-insert";
|
||||
|
||||
std::string options = "--allow-keywords --extended-insert --max-allowed-packet=1G --net-buffer-length=32704";
|
||||
if (IsDumpWithNoData()) {
|
||||
options += " --no-data";
|
||||
}
|
||||
|
||||
@ -493,6 +493,9 @@ void Database::DeleteInstance(uint16 instance_id)
|
||||
query = StringFormat("DELETE FROM spawn_condition_values WHERE instance_id=%u", instance_id);
|
||||
QueryDatabase(query);
|
||||
|
||||
query = fmt::format("DELETE FROM dynamic_zones WHERE instance_id={}", instance_id);
|
||||
QueryDatabase(query);
|
||||
|
||||
BuryCorpsesInInstance(instance_id);
|
||||
}
|
||||
|
||||
@ -582,8 +585,7 @@ void Database::PurgeExpiredInstances()
|
||||
QueryDatabase(fmt::format("DELETE FROM respawn_times WHERE instance_id IN ({})", imploded_instance_ids));
|
||||
QueryDatabase(fmt::format("DELETE FROM spawn_condition_values WHERE instance_id IN ({})", imploded_instance_ids));
|
||||
QueryDatabase(fmt::format("UPDATE character_corpses SET is_buried = 1, instance_id = 0 WHERE instance_id IN ({})", imploded_instance_ids));
|
||||
|
||||
|
||||
QueryDatabase(fmt::format("DELETE FROM dynamic_zones WHERE instance_id IN ({})", imploded_instance_ids));
|
||||
}
|
||||
|
||||
void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration)
|
||||
|
||||
@ -50,6 +50,7 @@ namespace DatabaseSchema {
|
||||
{"character_data", "id"},
|
||||
{"character_disciplines", "id"},
|
||||
{"character_enabledtasks", "charid"},
|
||||
{"character_expedition_lockouts", "character_id"},
|
||||
{"character_inspect_messages", "id"},
|
||||
{"character_item_recast", "id"},
|
||||
{"character_languages", "id"},
|
||||
@ -114,6 +115,7 @@ namespace DatabaseSchema {
|
||||
"character_data",
|
||||
"character_disciplines",
|
||||
"character_enabledtasks",
|
||||
"character_expedition_lockouts",
|
||||
"character_inspect_messages",
|
||||
"character_item_recast",
|
||||
"character_languages",
|
||||
@ -305,7 +307,11 @@ namespace DatabaseSchema {
|
||||
"banned_ips",
|
||||
"bug_reports",
|
||||
"bugs",
|
||||
"dynamic_zones",
|
||||
"eventlog",
|
||||
"expedition_lockouts",
|
||||
"expedition_members",
|
||||
"expeditions",
|
||||
"gm_ips",
|
||||
"group_id",
|
||||
"group_leaders",
|
||||
|
||||
@ -136,20 +136,22 @@ N(OP_Dye),
|
||||
N(OP_DynamicWall),
|
||||
N(OP_DzAddPlayer),
|
||||
N(OP_DzChooseZone),
|
||||
N(OP_DzChooseZoneReply),
|
||||
N(OP_DzCompass),
|
||||
N(OP_DzExpeditionEndsWarning),
|
||||
N(OP_DzExpeditionInfo),
|
||||
N(OP_DzExpeditionList),
|
||||
N(OP_DzJoinExpeditionConfirm),
|
||||
N(OP_DzJoinExpeditionReply),
|
||||
N(OP_DzLeaderStatus),
|
||||
N(OP_DzExpeditionInvite),
|
||||
N(OP_DzExpeditionInviteResponse),
|
||||
N(OP_DzExpeditionLockoutTimers),
|
||||
N(OP_DzListTimers),
|
||||
N(OP_DzMakeLeader),
|
||||
N(OP_DzMemberList),
|
||||
N(OP_DzMemberStatus),
|
||||
N(OP_DzMemberListName),
|
||||
N(OP_DzMemberListStatus),
|
||||
N(OP_DzPlayerList),
|
||||
N(OP_DzQuit),
|
||||
N(OP_DzRemovePlayer),
|
||||
N(OP_DzSetLeaderName),
|
||||
N(OP_DzSwapPlayer),
|
||||
N(OP_Emote),
|
||||
N(OP_EndLootRequest),
|
||||
@ -271,6 +273,7 @@ N(OP_ItemVerifyRequest),
|
||||
N(OP_ItemViewUnknown),
|
||||
N(OP_Jump),
|
||||
N(OP_KeyRing),
|
||||
N(OP_KickPlayers),
|
||||
N(OP_KnowledgeBase),
|
||||
N(OP_LDoNButton),
|
||||
N(OP_LDoNDisarmTraps),
|
||||
|
||||
@ -375,13 +375,16 @@ struct NewZone_Struct {
|
||||
/*0686*/ uint16 zone_instance;
|
||||
/*0688*/ uint32 unknown688;
|
||||
/*0692*/ uint8 unknown692[8];
|
||||
// Titanium doesn't have a translator, but we can still safely add stuff under here without issues since client memcpy's only what it knows
|
||||
// Just wastes some bandwidth sending to tit clients /shrug
|
||||
/*0700*/ float fog_density;
|
||||
/*0704*/ uint32 SuspendBuffs;
|
||||
/*0708*/ uint32 FastRegenHP;
|
||||
/*0712*/ uint32 FastRegenMana;
|
||||
/*0716*/ uint32 FastRegenEndurance;
|
||||
/*0720*/ uint32 NPCAggroMaxDist;
|
||||
/*0724*/
|
||||
/*0724*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, if this value is 0, it prevents you from running off edges that would end up underworld
|
||||
/*0728*/
|
||||
};
|
||||
|
||||
/*
|
||||
@ -4832,17 +4835,98 @@ struct BuffIcon_Struct
|
||||
BuffIconEntry_Struct entries[0];
|
||||
};
|
||||
|
||||
struct ExpeditionInfo_Struct
|
||||
struct ExpeditionInvite_Struct
|
||||
{
|
||||
/*000*/ uint32 max_players;
|
||||
/*004*/ char expedition_name[128];
|
||||
/*132*/ char leader_name[64];
|
||||
/*000*/ uint32 client_id; // unique character id
|
||||
/*004*/ uint32 unknown004; // added after titanium
|
||||
/*008*/ char inviter_name[64];
|
||||
/*072*/ char expedition_name[128];
|
||||
/*200*/ uint8 swapping; // 0: adding 1: swapping
|
||||
/*201*/ char swap_name[64]; // if swapping, swap name being removed
|
||||
/*265*/ uint8 padding[3];
|
||||
/*268*/ uint16 dz_zone_id; // dz_id zone/instance pair, sent back in reply
|
||||
/*270*/ uint16 dz_instance_id;
|
||||
};
|
||||
|
||||
struct ExpeditionJoinPrompt_Struct
|
||||
struct ExpeditionInviteResponse_Struct
|
||||
{
|
||||
/*000*/ char player_name[64];
|
||||
/*064*/ char expedition_name[64];
|
||||
/*000*/ uint32 unknown000;
|
||||
/*004*/ uint32 unknown004; // added after titanium
|
||||
/*008*/ uint16 dz_zone_id; // dz_id pair sent in invite
|
||||
/*010*/ uint16 dz_instance_id;
|
||||
/*012*/ uint8 accepted; // 0: declined 1: accepted
|
||||
/*013*/ uint8 swapping; // 0: adding 1: swapping (sent in invite)
|
||||
/*014*/ char swap_name[64]; // swap name sent in invite
|
||||
/*078*/ uint8 unknown078; // padding garbage?
|
||||
/*079*/ uint8 unknown079; // padding garbage?
|
||||
};
|
||||
|
||||
struct ExpeditionInfo_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 unknown004; // added after titanium
|
||||
/*008*/ uint32 assigned; // padded bool, 0: not in expedition (clear data), 1: in expedition
|
||||
/*012*/ uint32 max_players;
|
||||
/*016*/ char expedition_name[128];
|
||||
/*144*/ char leader_name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionMemberEntry_Struct
|
||||
{
|
||||
/*000*/ char name[64]; // variable length, null terminated, max 0x40 (64)
|
||||
/*064*/ uint8 expedition_status; // 0: unknown, 1: Online, 2: Offline, 3: In Dynamic Zone, 4: Link Dead
|
||||
};
|
||||
|
||||
struct ExpeditionMemberList_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 member_count;
|
||||
/*008*/ ExpeditionMemberEntry_Struct members[0]; // variable length
|
||||
};
|
||||
|
||||
struct ExpeditionMemberListName_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ uint32 add_name; // padded bool, 0: remove name, 1: add name with unknown status
|
||||
/*012*/ char name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionLockoutTimerEntry_Struct
|
||||
{
|
||||
/*000*/ char expedition_name[128]; // variable length, null terminated, max 0x80 (128)
|
||||
/*000*/ uint32 seconds_remaining;
|
||||
/*000*/ int32 event_type; // seen -1 (0xffffffff) for replay timers and 1 for event timers
|
||||
/*000*/ char event_name[256]; // variable length, null terminated, max 0x100 (256)
|
||||
};
|
||||
|
||||
struct ExpeditionLockoutTimers_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 count;
|
||||
/*008*/ ExpeditionLockoutTimerEntry_Struct timers[0];
|
||||
};
|
||||
|
||||
struct ExpeditionSetLeaderName_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ char leader_name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionCommand_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ char name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionCommandSwap_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ char add_player_name[64]; // swap to (player must confirm)
|
||||
/*072*/ char rem_player_name[64]; // swap from
|
||||
};
|
||||
|
||||
struct ExpeditionExpireWarning
|
||||
@ -4850,48 +4934,67 @@ struct ExpeditionExpireWarning
|
||||
/*008*/ uint32 minutes_remaining;
|
||||
};
|
||||
|
||||
struct ExpeditionCompassEntry_Struct
|
||||
struct DynamicZoneCompassEntry_Struct
|
||||
{
|
||||
/*000*/ uint32 enabled; //guess
|
||||
/*004*/ float y;
|
||||
/*008*/ float x;
|
||||
/*012*/ float z;
|
||||
/*000*/ uint16 dz_zone_id; // target dz id pair
|
||||
/*002*/ uint16 dz_instance_id;
|
||||
/*004*/ uint32 dz_type; // 1: Expedition, 2: Tutorial (purple), 3: Task, 4: Mission, 5: Quest (green)
|
||||
/*008*/ uint32 unknown008;
|
||||
/*012*/ float y;
|
||||
/*016*/ float x;
|
||||
/*020*/ float z;
|
||||
};
|
||||
|
||||
struct ExpeditionCompass_Struct
|
||||
struct DynamicZoneCompass_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*000*/ uint32 count;
|
||||
/*004*/ ExpeditionCompassEntry_Struct entries[0];
|
||||
/*004*/ DynamicZoneCompassEntry_Struct entries[0];
|
||||
};
|
||||
|
||||
struct ExpeditionMemberEntry_Struct
|
||||
struct DynamicZoneChooseZoneEntry_Struct
|
||||
{
|
||||
char name[64];
|
||||
char status;
|
||||
/*000*/ uint16 dz_zone_id; // dz_id pair
|
||||
/*002*/ uint16 dz_instance_id;
|
||||
/*004*/ uint32 unknown_id1; // seen 28 00 00 00 (40), sent back in reply
|
||||
/*008*/ uint32 dz_type; // 1: Expedition, 2: Tutorial, 3: Task, 4: Mission, 5: Quest -- sent back in reply
|
||||
/*012*/ uint32 unknown_id2; // possibly an id based on dz type, for expeditions this was same as dz_id (zone|instance) but task dz was different
|
||||
/*016*/ char description[128]; // variable length, null terminated
|
||||
/*144*/ char leader_name[64]; // variable length, null terminated
|
||||
};
|
||||
|
||||
struct ExpeditionMemberList_Struct
|
||||
struct DynamicZoneChooseZone_Struct
|
||||
{
|
||||
/*000*/ uint32 count;
|
||||
/*004*/ ExpeditionMemberEntry_Struct entries[0];
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 count;
|
||||
/*008*/ DynamicZoneChooseZoneEntry_Struct choices[0];
|
||||
};
|
||||
|
||||
struct ExpeditionLockoutEntry_Struct
|
||||
struct DynamicZoneChooseZoneReply_Struct
|
||||
{
|
||||
/*000*/ uint32 time_left;
|
||||
/*004*/ char expedition[128];
|
||||
/*132*/ char expedition_event[128];
|
||||
/*000*/ uint32 unknown000; // ff ff ff ff
|
||||
/*004*/ uint32 unknown004; // seen 69 00 00 00
|
||||
/*008*/ uint32 unknown008; // ff ff ff ff
|
||||
/*012*/ uint32 unknown_id1; // from choose zone entry message
|
||||
/*016*/ uint16 dz_zone_id; // dz_id pair
|
||||
/*018*/ uint16 dz_instance_id;
|
||||
/*020*/ uint32 dz_type; // 1: Expedition, 2: Tutorial, 3: Task, 4: Mission, 5: Quest
|
||||
/*024*/ uint32 unknown_id2; // from choose zone entry message
|
||||
/*028*/ uint32 unknown028; // 00 00 00 00
|
||||
/*032*/ uint32 unknown032; // always same as unknown044
|
||||
/*036*/ uint32 unknown036;
|
||||
/*040*/ uint32 unknown040;
|
||||
/*044*/ uint32 unknown044; // always same as unknown032
|
||||
/*048*/ uint32 unknown048; // seen 01 00 00 00 and 02 00 00 00
|
||||
};
|
||||
|
||||
struct ExpeditionLockoutList_Struct
|
||||
struct KickPlayers_Struct
|
||||
{
|
||||
/*000*/ uint32 count;
|
||||
/*004*/ ExpeditionLockoutEntry_Struct entries[0];
|
||||
};
|
||||
|
||||
struct ExpeditionLeaderSet_Struct
|
||||
{
|
||||
/*000*/ char leader_name[64];
|
||||
/*000*/ char char_name[64];
|
||||
/*064*/ uint32 unknown064; // always 0
|
||||
/*068*/ uint8 kick_expedition; // true if /kickplayers exp
|
||||
/*069*/ uint8 kick_task; // true if /kickplayers task
|
||||
/*070*/ uint8 padding[2];
|
||||
};
|
||||
|
||||
struct CorpseDrag_Struct
|
||||
|
||||
@ -118,6 +118,9 @@ namespace Logs {
|
||||
Merchants,
|
||||
ZonePoints,
|
||||
Loot,
|
||||
Expeditions,
|
||||
DynamicZones,
|
||||
Group,
|
||||
MaxCategoryID /* Don't Remove this */
|
||||
};
|
||||
|
||||
@ -194,7 +197,10 @@ namespace Logs {
|
||||
"HotReload",
|
||||
"Merchants",
|
||||
"ZonePoints",
|
||||
"Loot"
|
||||
"Loot",
|
||||
"Expeditions",
|
||||
"DynamicZones",
|
||||
"Group",
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -161,6 +161,16 @@
|
||||
OutF(LogSys, Logs::Detail, Logs::Doors, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogGroup(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Group].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Group, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogGroupDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Group].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Group, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogGuilds(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Guilds].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Guilds, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
@ -601,6 +611,31 @@
|
||||
OutF(LogSys, Logs::Detail, Logs::Loot, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogExpeditions(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Expeditions].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Expeditions, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogExpeditionsModerate(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Expeditions].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Moderate, Logs::Expeditions, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogExpeditionsDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Expeditions].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::Expeditions, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogDynamicZones(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::DynamicZones].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::DynamicZones, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogDynamicZonesDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::DynamicZones].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::DynamicZones, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define Log(debug_level, log_category, message, ...) do {\
|
||||
if (LogSys.log_settings[log_category].is_category_enabled == 1)\
|
||||
LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
@ -694,6 +729,12 @@
|
||||
#define LogDoorsDetail(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogGroup(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogGroupDetail(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogGuilds(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
@ -952,6 +993,21 @@
|
||||
#define LogZonePointsDetail(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogExpeditions(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogExpeditionsModerate(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogExpeditionsDetail(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogDynamicZones(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogDynamicZonesDetail(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define Log(debug_level, log_category, message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
|
||||
@ -710,15 +710,48 @@ namespace RoF
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzChooseZone)
|
||||
{
|
||||
SETUP_VAR_ENCODE(DynamicZoneChooseZone_Struct);
|
||||
|
||||
SerializeBuffer buf;
|
||||
buf.WriteUInt32(emu->client_id);
|
||||
buf.WriteUInt32(emu->count);
|
||||
|
||||
for (uint32 i = 0; i < emu->count; ++i)
|
||||
{
|
||||
buf.WriteUInt16(emu->choices[i].dz_zone_id);
|
||||
buf.WriteUInt16(emu->choices[i].dz_instance_id);
|
||||
buf.WriteUInt32(emu->choices[i].unknown_id1);
|
||||
buf.WriteUInt32(emu->choices[i].dz_type);
|
||||
buf.WriteUInt32(emu->choices[i].unknown_id2);
|
||||
buf.WriteString(emu->choices[i].description);
|
||||
buf.WriteString(emu->choices[i].leader_name);
|
||||
}
|
||||
|
||||
__packet->size = buf.size();
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
memcpy(__packet->pBuffer, buf.buffer(), __packet->size);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzCompass)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionCompass_Struct);
|
||||
ALLOC_VAR_ENCODE(structs::ExpeditionCompass_Struct, sizeof(structs::ExpeditionInfo_Struct) + sizeof(structs::ExpeditionCompassEntry_Struct) * emu->count);
|
||||
SETUP_VAR_ENCODE(DynamicZoneCompass_Struct);
|
||||
ALLOC_VAR_ENCODE(structs::DynamicZoneCompass_Struct,
|
||||
sizeof(structs::DynamicZoneCompass_Struct) +
|
||||
sizeof(structs::DynamicZoneCompassEntry_Struct) * emu->count
|
||||
);
|
||||
|
||||
OUT(client_id);
|
||||
OUT(count);
|
||||
|
||||
for (uint32 i = 0; i < emu->count; ++i)
|
||||
{
|
||||
OUT(entries[i].dz_zone_id);
|
||||
OUT(entries[i].dz_instance_id);
|
||||
OUT(entries[i].dz_type);
|
||||
OUT(entries[i].x);
|
||||
OUT(entries[i].y);
|
||||
OUT(entries[i].z);
|
||||
@ -742,81 +775,60 @@ namespace RoF
|
||||
ENCODE_LENGTH_EXACT(ExpeditionInfo_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionInfo_Struct, structs::ExpeditionInfo_Struct);
|
||||
|
||||
OUT(client_id);
|
||||
OUT(assigned);
|
||||
OUT(max_players);
|
||||
eq->unknown004 = 785316192;
|
||||
eq->unknown008 = 435601;
|
||||
strncpy(eq->expedition_name, emu->expedition_name, sizeof(eq->expedition_name));
|
||||
strncpy(eq->leader_name, emu->leader_name, sizeof(eq->leader_name));
|
||||
strn0cpy(eq->expedition_name, emu->expedition_name, sizeof(eq->expedition_name));
|
||||
strn0cpy(eq->leader_name, emu->leader_name, sizeof(eq->leader_name));
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzExpeditionList)
|
||||
ENCODE(OP_DzExpeditionInvite)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionLockoutList_Struct);
|
||||
ENCODE_LENGTH_EXACT(ExpeditionInvite_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionInvite_Struct, structs::ExpeditionInvite_Struct);
|
||||
|
||||
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
||||
uint32 client_id = 0;
|
||||
uint8 null_term = 0;
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&emu->count, sizeof(uint32));
|
||||
OUT(client_id);
|
||||
strn0cpy(eq->inviter_name, emu->inviter_name, sizeof(eq->inviter_name));
|
||||
strn0cpy(eq->expedition_name, emu->expedition_name, sizeof(eq->expedition_name));
|
||||
OUT(swapping);
|
||||
strn0cpy(eq->swap_name, emu->swap_name, sizeof(eq->swap_name));
|
||||
OUT(dz_zone_id);
|
||||
OUT(dz_instance_id);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzExpeditionLockoutTimers)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionLockoutTimers_Struct);
|
||||
|
||||
SerializeBuffer buf;
|
||||
buf.WriteUInt32(emu->client_id);
|
||||
buf.WriteUInt32(emu->count);
|
||||
for (uint32 i = 0; i < emu->count; ++i)
|
||||
{
|
||||
ss.write(emu->entries[i].expedition, strlen(emu->entries[i].expedition));
|
||||
ss.write((const char*)&null_term, sizeof(char));
|
||||
ss.write((const char*)&emu->entries[i].time_left, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write(emu->entries[i].expedition_event, strlen(emu->entries[i].expedition_event));
|
||||
ss.write((const char*)&null_term, sizeof(char));
|
||||
buf.WriteString(emu->timers[i].expedition_name);
|
||||
buf.WriteUInt32(emu->timers[i].seconds_remaining);
|
||||
buf.WriteInt32(emu->timers[i].event_type);
|
||||
buf.WriteString(emu->timers[i].event_name);
|
||||
}
|
||||
|
||||
__packet->size = ss.str().length();
|
||||
__packet->size = buf.size();
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size);
|
||||
memcpy(__packet->pBuffer, buf.buffer(), __packet->size);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzJoinExpeditionConfirm)
|
||||
ENCODE(OP_DzSetLeaderName)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(ExpeditionJoinPrompt_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionJoinPrompt_Struct, structs::ExpeditionJoinPrompt_Struct);
|
||||
ENCODE_LENGTH_EXACT(ExpeditionSetLeaderName_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionSetLeaderName_Struct, structs::ExpeditionSetLeaderName_Struct);
|
||||
|
||||
strncpy(eq->expedition_name, emu->expedition_name, sizeof(eq->expedition_name));
|
||||
strncpy(eq->player_name, emu->player_name, sizeof(eq->player_name));
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzLeaderStatus)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionLeaderSet_Struct);
|
||||
|
||||
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
||||
uint32 client_id = 0;
|
||||
uint8 null_term = 0;
|
||||
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write(emu->leader_name, strlen(emu->leader_name));
|
||||
ss.write((const char*)&null_term, sizeof(char));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));//0xffffffff
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));//1
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
|
||||
__packet->size = ss.str().length();
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size);
|
||||
OUT(client_id);
|
||||
strn0cpy(eq->leader_name, emu->leader_name, sizeof(eq->leader_name));
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
@ -825,26 +837,43 @@ namespace RoF
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionMemberList_Struct);
|
||||
|
||||
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
||||
|
||||
uint32 client_id = 0;
|
||||
uint8 null_term = 0;
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&emu->count, sizeof(uint32));
|
||||
for (uint32 i = 0; i < emu->count; ++i)
|
||||
SerializeBuffer buf;
|
||||
buf.WriteUInt32(emu->client_id);
|
||||
buf.WriteUInt32(emu->member_count);
|
||||
for (uint32 i = 0; i < emu->member_count; ++i)
|
||||
{
|
||||
ss.write(emu->entries[i].name, strlen(emu->entries[i].name));
|
||||
ss.write((const char*)&null_term, sizeof(char));
|
||||
ss.write((const char*)&emu->entries[i].status, sizeof(char));
|
||||
buf.WriteString(emu->members[i].name);
|
||||
buf.WriteUInt8(emu->members[i].expedition_status);
|
||||
}
|
||||
|
||||
__packet->size = ss.str().length();
|
||||
__packet->size = buf.size();
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size);
|
||||
memcpy(__packet->pBuffer, buf.buffer(), __packet->size);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzMemberListName)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(ExpeditionMemberListName_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionMemberListName_Struct, structs::ExpeditionMemberListName_Struct);
|
||||
|
||||
OUT(client_id);
|
||||
OUT(add_name);
|
||||
strn0cpy(eq->name, emu->name, sizeof(eq->name));
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzMemberListStatus)
|
||||
{
|
||||
auto emu = reinterpret_cast<ExpeditionMemberList_Struct*>((*p)->pBuffer);
|
||||
if (emu->member_count == 1)
|
||||
{
|
||||
ENCODE_FORWARD(OP_DzMemberList);
|
||||
}
|
||||
}
|
||||
|
||||
ENCODE(OP_Emote)
|
||||
{
|
||||
EQApplicationPacket *in = *p;
|
||||
@ -1827,6 +1856,7 @@ namespace RoF
|
||||
OUT(FastRegenHP);
|
||||
OUT(FastRegenMana);
|
||||
OUT(FastRegenEndurance);
|
||||
OUT(underworld_teleport_index);
|
||||
|
||||
eq->FogDensity = emu->fog_density;
|
||||
|
||||
@ -4387,6 +4417,84 @@ namespace RoF
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzAddPlayer)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionCommand_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionCommand_Struct, structs::ExpeditionCommand_Struct);
|
||||
|
||||
strn0cpy(emu->name, eq->name, sizeof(emu->name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzChooseZoneReply)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::DynamicZoneChooseZoneReply_Struct);
|
||||
SETUP_DIRECT_DECODE(DynamicZoneChooseZoneReply_Struct, structs::DynamicZoneChooseZoneReply_Struct);
|
||||
|
||||
IN(unknown000);
|
||||
IN(unknown004);
|
||||
IN(unknown008);
|
||||
IN(unknown_id1);
|
||||
IN(dz_zone_id);
|
||||
IN(dz_instance_id);
|
||||
IN(dz_type);
|
||||
IN(unknown_id2);
|
||||
IN(unknown028);
|
||||
IN(unknown032);
|
||||
IN(unknown036);
|
||||
IN(unknown040);
|
||||
IN(unknown044);
|
||||
IN(unknown048);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzExpeditionInviteResponse)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionInviteResponse_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionInviteResponse_Struct, structs::ExpeditionInviteResponse_Struct);
|
||||
|
||||
IN(dz_zone_id);
|
||||
IN(dz_instance_id);
|
||||
IN(accepted);
|
||||
IN(swapping);
|
||||
strn0cpy(emu->swap_name, eq->swap_name, sizeof(emu->swap_name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzMakeLeader)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionCommand_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionCommand_Struct, structs::ExpeditionCommand_Struct);
|
||||
|
||||
strn0cpy(emu->name, eq->name, sizeof(emu->name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzRemovePlayer)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionCommand_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionCommand_Struct, structs::ExpeditionCommand_Struct);
|
||||
|
||||
strn0cpy(emu->name, eq->name, sizeof(emu->name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzSwapPlayer)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionCommandSwap_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionCommandSwap_Struct, structs::ExpeditionCommandSwap_Struct);
|
||||
|
||||
strn0cpy(emu->add_player_name, eq->add_player_name, sizeof(emu->add_player_name));
|
||||
strn0cpy(emu->rem_player_name, eq->rem_player_name, sizeof(emu->rem_player_name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_Emote)
|
||||
{
|
||||
unsigned char *__eq_buffer = __packet->pBuffer;
|
||||
|
||||
@ -759,15 +759,48 @@ namespace RoF2
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzChooseZone)
|
||||
{
|
||||
SETUP_VAR_ENCODE(DynamicZoneChooseZone_Struct);
|
||||
|
||||
SerializeBuffer buf;
|
||||
buf.WriteUInt32(emu->client_id);
|
||||
buf.WriteUInt32(emu->count);
|
||||
|
||||
for (uint32 i = 0; i < emu->count; ++i)
|
||||
{
|
||||
buf.WriteUInt16(emu->choices[i].dz_zone_id);
|
||||
buf.WriteUInt16(emu->choices[i].dz_instance_id);
|
||||
buf.WriteUInt32(emu->choices[i].unknown_id1);
|
||||
buf.WriteUInt32(emu->choices[i].dz_type);
|
||||
buf.WriteUInt32(emu->choices[i].unknown_id2);
|
||||
buf.WriteString(emu->choices[i].description);
|
||||
buf.WriteString(emu->choices[i].leader_name);
|
||||
}
|
||||
|
||||
__packet->size = buf.size();
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
memcpy(__packet->pBuffer, buf.buffer(), __packet->size);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzCompass)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionCompass_Struct);
|
||||
ALLOC_VAR_ENCODE(structs::ExpeditionCompass_Struct, sizeof(structs::ExpeditionInfo_Struct) + sizeof(structs::ExpeditionCompassEntry_Struct) * emu->count);
|
||||
SETUP_VAR_ENCODE(DynamicZoneCompass_Struct);
|
||||
ALLOC_VAR_ENCODE(structs::DynamicZoneCompass_Struct,
|
||||
sizeof(structs::DynamicZoneCompass_Struct) +
|
||||
sizeof(structs::DynamicZoneCompassEntry_Struct) * emu->count
|
||||
);
|
||||
|
||||
OUT(client_id);
|
||||
OUT(count);
|
||||
|
||||
for (uint32 i = 0; i < emu->count; ++i)
|
||||
{
|
||||
OUT(entries[i].dz_zone_id);
|
||||
OUT(entries[i].dz_instance_id);
|
||||
OUT(entries[i].dz_type);
|
||||
OUT(entries[i].x);
|
||||
OUT(entries[i].y);
|
||||
OUT(entries[i].z);
|
||||
@ -791,81 +824,60 @@ namespace RoF2
|
||||
ENCODE_LENGTH_EXACT(ExpeditionInfo_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionInfo_Struct, structs::ExpeditionInfo_Struct);
|
||||
|
||||
OUT(client_id);
|
||||
OUT(assigned);
|
||||
OUT(max_players);
|
||||
eq->unknown004 = 785316192;
|
||||
eq->unknown008 = 435601;
|
||||
strncpy(eq->expedition_name, emu->expedition_name, sizeof(eq->expedition_name));
|
||||
strncpy(eq->leader_name, emu->leader_name, sizeof(eq->leader_name));
|
||||
strn0cpy(eq->expedition_name, emu->expedition_name, sizeof(eq->expedition_name));
|
||||
strn0cpy(eq->leader_name, emu->leader_name, sizeof(eq->leader_name));
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzExpeditionList)
|
||||
ENCODE(OP_DzExpeditionInvite)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionLockoutList_Struct);
|
||||
ENCODE_LENGTH_EXACT(ExpeditionInvite_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionInvite_Struct, structs::ExpeditionInvite_Struct);
|
||||
|
||||
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
||||
uint32 client_id = 0;
|
||||
uint8 null_term = 0;
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&emu->count, sizeof(uint32));
|
||||
OUT(client_id);
|
||||
strn0cpy(eq->inviter_name, emu->inviter_name, sizeof(eq->inviter_name));
|
||||
strn0cpy(eq->expedition_name, emu->expedition_name, sizeof(eq->expedition_name));
|
||||
OUT(swapping);
|
||||
strn0cpy(eq->swap_name, emu->swap_name, sizeof(eq->swap_name));
|
||||
OUT(dz_zone_id);
|
||||
OUT(dz_instance_id);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzExpeditionLockoutTimers)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionLockoutTimers_Struct);
|
||||
|
||||
SerializeBuffer buf;
|
||||
buf.WriteUInt32(emu->client_id);
|
||||
buf.WriteUInt32(emu->count);
|
||||
for (uint32 i = 0; i < emu->count; ++i)
|
||||
{
|
||||
ss.write(emu->entries[i].expedition, strlen(emu->entries[i].expedition));
|
||||
ss.write((const char*)&null_term, sizeof(char));
|
||||
ss.write((const char*)&emu->entries[i].time_left, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write(emu->entries[i].expedition_event, strlen(emu->entries[i].expedition_event));
|
||||
ss.write((const char*)&null_term, sizeof(char));
|
||||
buf.WriteString(emu->timers[i].expedition_name);
|
||||
buf.WriteUInt32(emu->timers[i].seconds_remaining);
|
||||
buf.WriteInt32(emu->timers[i].event_type);
|
||||
buf.WriteString(emu->timers[i].event_name);
|
||||
}
|
||||
|
||||
__packet->size = ss.str().length();
|
||||
__packet->size = buf.size();
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size);
|
||||
memcpy(__packet->pBuffer, buf.buffer(), __packet->size);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzJoinExpeditionConfirm)
|
||||
ENCODE(OP_DzSetLeaderName)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(ExpeditionJoinPrompt_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionJoinPrompt_Struct, structs::ExpeditionJoinPrompt_Struct);
|
||||
ENCODE_LENGTH_EXACT(ExpeditionSetLeaderName_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionSetLeaderName_Struct, structs::ExpeditionSetLeaderName_Struct);
|
||||
|
||||
strncpy(eq->expedition_name, emu->expedition_name, sizeof(eq->expedition_name));
|
||||
strncpy(eq->player_name, emu->player_name, sizeof(eq->player_name));
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzLeaderStatus)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionLeaderSet_Struct);
|
||||
|
||||
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
||||
uint32 client_id = 0;
|
||||
uint8 null_term = 0;
|
||||
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write(emu->leader_name, strlen(emu->leader_name));
|
||||
ss.write((const char*)&null_term, sizeof(char));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));//0xffffffff
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));//1
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
|
||||
__packet->size = ss.str().length();
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size);
|
||||
OUT(client_id);
|
||||
strn0cpy(eq->leader_name, emu->leader_name, sizeof(eq->leader_name));
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
@ -874,26 +886,43 @@ namespace RoF2
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionMemberList_Struct);
|
||||
|
||||
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
||||
|
||||
uint32 client_id = 0;
|
||||
uint8 null_term = 0;
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&emu->count, sizeof(uint32));
|
||||
for (uint32 i = 0; i < emu->count; ++i)
|
||||
SerializeBuffer buf;
|
||||
buf.WriteUInt32(emu->client_id);
|
||||
buf.WriteUInt32(emu->member_count);
|
||||
for (uint32 i = 0; i < emu->member_count; ++i)
|
||||
{
|
||||
ss.write(emu->entries[i].name, strlen(emu->entries[i].name));
|
||||
ss.write((const char*)&null_term, sizeof(char));
|
||||
ss.write((const char*)&emu->entries[i].status, sizeof(char));
|
||||
buf.WriteString(emu->members[i].name);
|
||||
buf.WriteUInt8(emu->members[i].expedition_status);
|
||||
}
|
||||
|
||||
__packet->size = ss.str().length();
|
||||
__packet->size = buf.size();
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size);
|
||||
memcpy(__packet->pBuffer, buf.buffer(), __packet->size);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzMemberListName)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(ExpeditionMemberListName_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionMemberListName_Struct, structs::ExpeditionMemberListName_Struct);
|
||||
|
||||
OUT(client_id);
|
||||
OUT(add_name);
|
||||
strn0cpy(eq->name, emu->name, sizeof(eq->name));
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzMemberListStatus)
|
||||
{
|
||||
auto emu = reinterpret_cast<ExpeditionMemberList_Struct*>((*p)->pBuffer);
|
||||
if (emu->member_count == 1)
|
||||
{
|
||||
ENCODE_FORWARD(OP_DzMemberList);
|
||||
}
|
||||
}
|
||||
|
||||
ENCODE(OP_Emote)
|
||||
{
|
||||
EQApplicationPacket *in = *p;
|
||||
@ -1876,6 +1905,7 @@ namespace RoF2
|
||||
OUT(FastRegenHP);
|
||||
OUT(FastRegenMana);
|
||||
OUT(FastRegenEndurance);
|
||||
OUT(underworld_teleport_index);
|
||||
|
||||
eq->FogDensity = emu->fog_density;
|
||||
|
||||
@ -4584,6 +4614,84 @@ namespace RoF2
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzAddPlayer)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionCommand_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionCommand_Struct, structs::ExpeditionCommand_Struct);
|
||||
|
||||
strn0cpy(emu->name, eq->name, sizeof(emu->name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzChooseZoneReply)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::DynamicZoneChooseZoneReply_Struct);
|
||||
SETUP_DIRECT_DECODE(DynamicZoneChooseZoneReply_Struct, structs::DynamicZoneChooseZoneReply_Struct);
|
||||
|
||||
IN(unknown000);
|
||||
IN(unknown004);
|
||||
IN(unknown008);
|
||||
IN(unknown_id1);
|
||||
IN(dz_zone_id);
|
||||
IN(dz_instance_id);
|
||||
IN(dz_type);
|
||||
IN(unknown_id2);
|
||||
IN(unknown028);
|
||||
IN(unknown032);
|
||||
IN(unknown036);
|
||||
IN(unknown040);
|
||||
IN(unknown044);
|
||||
IN(unknown048);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzExpeditionInviteResponse)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionInviteResponse_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionInviteResponse_Struct, structs::ExpeditionInviteResponse_Struct);
|
||||
|
||||
IN(dz_zone_id);
|
||||
IN(dz_instance_id);
|
||||
IN(accepted);
|
||||
IN(swapping);
|
||||
strn0cpy(emu->swap_name, eq->swap_name, sizeof(emu->swap_name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzMakeLeader)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionCommand_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionCommand_Struct, structs::ExpeditionCommand_Struct);
|
||||
|
||||
strn0cpy(emu->name, eq->name, sizeof(emu->name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzRemovePlayer)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionCommand_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionCommand_Struct, structs::ExpeditionCommand_Struct);
|
||||
|
||||
strn0cpy(emu->name, eq->name, sizeof(emu->name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzSwapPlayer)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionCommandSwap_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionCommandSwap_Struct, structs::ExpeditionCommandSwap_Struct);
|
||||
|
||||
strn0cpy(emu->add_player_name, eq->add_player_name, sizeof(emu->add_player_name));
|
||||
strn0cpy(emu->rem_player_name, eq->rem_player_name, sizeof(emu->rem_player_name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_Emote)
|
||||
{
|
||||
unsigned char *__eq_buffer = __packet->pBuffer;
|
||||
|
||||
@ -58,13 +58,16 @@ E(OP_DeleteCharge)
|
||||
E(OP_DeleteItem)
|
||||
E(OP_DeleteSpawn)
|
||||
E(OP_DisciplineUpdate)
|
||||
E(OP_DzChooseZone)
|
||||
E(OP_DzCompass)
|
||||
E(OP_DzExpeditionEndsWarning)
|
||||
E(OP_DzExpeditionInfo)
|
||||
E(OP_DzExpeditionList)
|
||||
E(OP_DzJoinExpeditionConfirm)
|
||||
E(OP_DzLeaderStatus)
|
||||
E(OP_DzExpeditionInvite)
|
||||
E(OP_DzExpeditionLockoutTimers)
|
||||
E(OP_DzMemberList)
|
||||
E(OP_DzMemberListName)
|
||||
E(OP_DzMemberListStatus)
|
||||
E(OP_DzSetLeaderName)
|
||||
E(OP_Emote)
|
||||
E(OP_ExpansionInfo)
|
||||
E(OP_FormattedMessage)
|
||||
@ -159,6 +162,12 @@ D(OP_ConsiderCorpse)
|
||||
D(OP_Consume)
|
||||
D(OP_Damage)
|
||||
D(OP_DeleteItem)
|
||||
D(OP_DzAddPlayer)
|
||||
D(OP_DzChooseZoneReply)
|
||||
D(OP_DzExpeditionInviteResponse)
|
||||
D(OP_DzMakeLeader)
|
||||
D(OP_DzRemovePlayer)
|
||||
D(OP_DzSwapPlayer)
|
||||
D(OP_Emote)
|
||||
D(OP_EnvDamage)
|
||||
D(OP_FaceChange)
|
||||
|
||||
@ -628,7 +628,7 @@ struct NewZone_Struct {
|
||||
/*0856*/ uint32 scriptNPCReceivedanItem;
|
||||
/*0860*/ uint32 bCheck; // padded bool
|
||||
/*0864*/ uint32 scriptIDSomething;
|
||||
/*0868*/ uint32 scriptIDSomething2;
|
||||
/*0868*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, -1 affects some collisions
|
||||
/*0872*/ uint32 scriptIDSomething3;
|
||||
/*0876*/ uint32 SuspendBuffs; // padded bool
|
||||
/*0880*/ uint32 LavaDamage; // LavaDamage value
|
||||
@ -4882,52 +4882,169 @@ struct VeteranClaim
|
||||
/*076*/ uint32 action;
|
||||
};
|
||||
|
||||
struct ExpeditionEntryHeader_Struct
|
||||
struct ExpeditionInvite_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id; // unique character id
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ char inviter_name[64];
|
||||
/*072*/ char expedition_name[128];
|
||||
/*200*/ uint8 swapping; // 0: adding 1: swapping
|
||||
/*201*/ char swap_name[64]; // if swapping, swap name being removed
|
||||
/*265*/ uint8 padding[3];
|
||||
/*268*/ uint16 dz_zone_id; // dz_id zone/instance pair, sent back in reply
|
||||
/*270*/ uint16 dz_instance_id;
|
||||
};
|
||||
|
||||
struct ExpeditionInviteResponse_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000;
|
||||
/*000*/ uint32 number_of_entries;
|
||||
};
|
||||
|
||||
struct ExpeditionJoinPrompt_Struct
|
||||
{
|
||||
/*000*/ uint32 clientid;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ char player_name[64];
|
||||
/*072*/ char expedition_name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionExpireWarning
|
||||
{
|
||||
/*000*/ uint32 clientid;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ uint32 minutes_remaining;
|
||||
/*008*/ uint16 dz_zone_id; // dz_id pair sent in invite
|
||||
/*010*/ uint16 dz_instance_id;
|
||||
/*012*/ uint8 accepted; // 0: declined 1: accepted
|
||||
/*013*/ uint8 swapping; // 0: adding 1: swapping (sent in invite)
|
||||
/*014*/ char swap_name[64]; // swap name sent in invite
|
||||
/*078*/ uint8 unknown078; // padding garbage?
|
||||
/*079*/ uint8 unknown079; // padding garbage?
|
||||
};
|
||||
|
||||
struct ExpeditionInfo_Struct
|
||||
{
|
||||
/*000*/ uint32 clientid;
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ uint32 unknown008;
|
||||
/*008*/ uint32 assigned; // padded bool, 0: not in expedition (clear data), 1: in expedition
|
||||
/*012*/ uint32 max_players;
|
||||
/*016*/ char expedition_name[128];
|
||||
/*142*/ char leader_name[64];
|
||||
/*016*/ char expedition_name[128];
|
||||
/*144*/ char leader_name[64];
|
||||
//*208*/ uint32 unknown208; // live sends 01 00 00 00 here but client doesn't read it
|
||||
};
|
||||
|
||||
struct ExpeditionCompassEntry_Struct
|
||||
struct ExpeditionMemberEntry_Struct
|
||||
{
|
||||
/*000*/ float unknown000; //seen *((uint32*)) = 1584791871
|
||||
/*004*/ uint32 enabled; //guess
|
||||
/*008*/ uint32 unknown008; //seen 1019
|
||||
/*000*/ char name[1]; // variable length, null terminated, max 0x40 (64)
|
||||
/*000*/ uint8 expedition_status; // 0: unknown 1: Online, 2: Offline, 3: In Dynamic Zone, 4: Link Dead
|
||||
};
|
||||
|
||||
struct ExpeditionMemberList_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 member_count; // number of players in window
|
||||
/*008*/ ExpeditionMemberEntry_Struct members[0]; // variable length
|
||||
};
|
||||
|
||||
struct ExpeditionMemberListName_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ uint32 add_name; // padded bool, 0: remove name, 1: add name with unknown status
|
||||
/*012*/ char name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionLockoutTimerEntry_Struct
|
||||
{
|
||||
/*000*/ char expedition_name[1]; // variable length, null terminated, max 0x80 (128)
|
||||
/*000*/ uint32 seconds_remaining;
|
||||
/*000*/ int32 event_type; // seen -1 (0xffffffff) for replay timers and 1 for event timers
|
||||
/*000*/ char event_name[1]; // variable length, null terminated, max 0x100 (256)
|
||||
};
|
||||
|
||||
struct ExpeditionLockoutTimers_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 count;
|
||||
/*008*/ ExpeditionLockoutTimerEntry_Struct timers[0];
|
||||
};
|
||||
|
||||
struct ExpeditionSetLeaderName_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ char leader_name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionCommand_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ char name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionCommandSwap_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ char add_player_name[64]; // swap to (player must confirm)
|
||||
/*072*/ char rem_player_name[64]; // swap from
|
||||
};
|
||||
|
||||
struct ExpeditionExpireWarning
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ uint32 minutes_remaining;
|
||||
};
|
||||
|
||||
struct DynamicZoneCompassEntry_Struct
|
||||
{
|
||||
/*000*/ uint16 dz_zone_id; // target dz id pair
|
||||
/*002*/ uint16 dz_instance_id;
|
||||
/*004*/ uint32 dz_type; // 1: Expedition, 2: Tutorial (purple), 3: Task, 4: Mission, 5: Quest (green)
|
||||
/*008*/ uint32 unknown008;
|
||||
/*012*/ float y;
|
||||
/*016*/ float x;
|
||||
/*020*/ float z;
|
||||
};
|
||||
|
||||
struct ExpeditionCompass_Struct
|
||||
struct DynamicZoneCompass_Struct
|
||||
{
|
||||
/*000*/ uint32 clientid;
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 count;
|
||||
/*008*/ ExpeditionCompassEntry_Struct entries[0];
|
||||
/*008*/ DynamicZoneCompassEntry_Struct entries[0];
|
||||
};
|
||||
|
||||
struct DynamicZoneChooseZoneEntry_Struct
|
||||
{
|
||||
/*000*/ uint16 dz_zone_id; // dz_id pair
|
||||
/*002*/ uint16 dz_instance_id;
|
||||
/*004*/ uint32 unknown_id1; // seen 28 00 00 00 (40), sent back in reply
|
||||
/*008*/ uint32 dz_type; // 1: Expedition, 2: Tutorial, 3: Task, 4: Mission, 5: Quest -- sent back in reply
|
||||
/*012*/ uint32 unknown_id2; // possibly an id based on dz type, for expeditions this was same as dz_id (zone|instance) but task dz was different
|
||||
/*016*/ char description[1]; // variable length, null terminated, max 0x80 (128)
|
||||
/*000*/ char leader_name[1]; // variable length, null terminated, max 0x40 (64)
|
||||
};
|
||||
|
||||
struct DynamicZoneChooseZone_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 count;
|
||||
/*008*/ DynamicZoneChooseZoneEntry_Struct choices[0];
|
||||
};
|
||||
|
||||
struct DynamicZoneChooseZoneReply_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000; // ff ff ff ff
|
||||
/*004*/ uint32 unknown004; // seen 69 00 00 00
|
||||
/*008*/ uint32 unknown008; // ff ff ff ff
|
||||
/*012*/ uint32 unknown_id1; // from choose zone entry message
|
||||
/*016*/ uint16 dz_zone_id; // dz_id pair
|
||||
/*018*/ uint16 dz_instance_id;
|
||||
/*020*/ uint32 dz_type; // 1: Expedition, 2: Tutorial, 3: Task, 4: Mission, 5: Quest
|
||||
/*024*/ uint32 unknown_id2; // from choose zone entry message
|
||||
/*028*/ uint32 unknown028; // 00 00 00 00
|
||||
/*032*/ uint32 unknown032; // always same as unknown044
|
||||
/*036*/ uint32 unknown036;
|
||||
/*040*/ uint32 unknown040;
|
||||
/*044*/ uint32 unknown044; // always same as unknown032
|
||||
/*048*/ uint32 unknown048; // seen 01 00 00 00 and 02 00 00 00
|
||||
};
|
||||
|
||||
struct KickPlayers_Struct
|
||||
{
|
||||
/*000*/ char char_name[64];
|
||||
/*064*/ uint32 unknown064; // always 0
|
||||
/*068*/ uint8 kick_expedition; // true if /kickplayers exp
|
||||
/*069*/ uint8 kick_task; // true if /kickplayers task
|
||||
/*070*/ uint8 padding[2];
|
||||
};
|
||||
|
||||
struct MaxCharacters_Struct
|
||||
|
||||
@ -44,13 +44,16 @@ E(OP_DeleteCharge)
|
||||
E(OP_DeleteItem)
|
||||
E(OP_DeleteSpawn)
|
||||
E(OP_DisciplineUpdate)
|
||||
E(OP_DzChooseZone)
|
||||
E(OP_DzCompass)
|
||||
E(OP_DzExpeditionEndsWarning)
|
||||
E(OP_DzExpeditionInfo)
|
||||
E(OP_DzExpeditionList)
|
||||
E(OP_DzJoinExpeditionConfirm)
|
||||
E(OP_DzLeaderStatus)
|
||||
E(OP_DzExpeditionInvite)
|
||||
E(OP_DzExpeditionLockoutTimers)
|
||||
E(OP_DzMemberList)
|
||||
E(OP_DzMemberListName)
|
||||
E(OP_DzMemberListStatus)
|
||||
E(OP_DzSetLeaderName)
|
||||
E(OP_Emote)
|
||||
E(OP_ExpansionInfo)
|
||||
E(OP_FormattedMessage)
|
||||
@ -145,6 +148,12 @@ D(OP_ConsiderCorpse)
|
||||
D(OP_Consume)
|
||||
D(OP_Damage)
|
||||
D(OP_DeleteItem)
|
||||
D(OP_DzAddPlayer)
|
||||
D(OP_DzChooseZoneReply)
|
||||
D(OP_DzExpeditionInviteResponse)
|
||||
D(OP_DzMakeLeader)
|
||||
D(OP_DzRemovePlayer)
|
||||
D(OP_DzSwapPlayer)
|
||||
D(OP_Emote)
|
||||
D(OP_EnvDamage)
|
||||
D(OP_FaceChange)
|
||||
|
||||
@ -575,7 +575,11 @@ struct NewZone_Struct {
|
||||
/*0848*/ int32 unknown848;
|
||||
/*0852*/ uint16 zone_id;
|
||||
/*0854*/ uint16 zone_instance;
|
||||
/*0856*/ char unknown856[20];
|
||||
/*0856*/ uint32 scriptNPCReceivedanItem;
|
||||
/*0860*/ uint32 bCheck; // padded bool
|
||||
/*0864*/ uint32 scriptIDSomething;
|
||||
/*0868*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, -1 affects some collisions
|
||||
/*0872*/ uint32 scriptIDSomething3;
|
||||
/*0876*/ uint32 SuspendBuffs;
|
||||
/*0880*/ uint32 unknown880; // Seen 50
|
||||
/*0884*/ uint32 unknown884; // Seen 10
|
||||
@ -4811,52 +4815,159 @@ struct VeteranClaim
|
||||
/*076*/ uint32 action;
|
||||
};
|
||||
|
||||
struct ExpeditionEntryHeader_Struct
|
||||
struct ExpeditionInvite_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id; // unique character id
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ char inviter_name[64];
|
||||
/*072*/ char expedition_name[128];
|
||||
/*200*/ uint8 swapping; // 0: adding 1: swapping
|
||||
/*201*/ char swap_name[64]; // if swapping, swap name being removed
|
||||
/*265*/ uint8 padding[3];
|
||||
/*268*/ uint16 dz_zone_id; // dz_id zone/instance pair, sent back in reply
|
||||
/*270*/ uint16 dz_instance_id;
|
||||
};
|
||||
|
||||
struct ExpeditionInviteResponse_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000;
|
||||
/*000*/ uint32 number_of_entries;
|
||||
};
|
||||
|
||||
struct ExpeditionJoinPrompt_Struct
|
||||
{
|
||||
/*000*/ uint32 clientid;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ char player_name[64];
|
||||
/*072*/ char expedition_name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionExpireWarning
|
||||
{
|
||||
/*000*/ uint32 clientid;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ uint32 minutes_remaining;
|
||||
/*008*/ uint16 dz_zone_id; // dz_id pair sent in invite
|
||||
/*010*/ uint16 dz_instance_id;
|
||||
/*012*/ uint8 accepted; // 0: declined 1: accepted
|
||||
/*013*/ uint8 swapping; // 0: adding 1: swapping (sent in invite)
|
||||
/*014*/ char swap_name[64]; // swap name sent in invite
|
||||
/*078*/ uint8 unknown078; // padding garbage?
|
||||
/*079*/ uint8 unknown079; // padding garbage?
|
||||
};
|
||||
|
||||
struct ExpeditionInfo_Struct
|
||||
{
|
||||
/*000*/ uint32 clientid;
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ uint32 unknown008;
|
||||
/*008*/ uint32 assigned; // padded bool
|
||||
/*012*/ uint32 max_players;
|
||||
/*016*/ char expedition_name[128];
|
||||
/*142*/ char leader_name[64];
|
||||
/*016*/ char expedition_name[128];
|
||||
/*144*/ char leader_name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionCompassEntry_Struct
|
||||
struct ExpeditionMemberEntry_Struct
|
||||
{
|
||||
/*000*/ float unknown000; //seen *((uint32*)) = 1584791871
|
||||
/*004*/ uint32 enabled; //guess
|
||||
/*008*/ uint32 unknown008; //seen 1019
|
||||
/*000*/ char name[1]; // variable length, null terminated, max 0x40 (64)
|
||||
/*000*/ uint8 expedition_status; // 0: unknown 1: Online, 2: Offline, 3: In Dynamic Zone, 4: Link Dead
|
||||
};
|
||||
|
||||
struct ExpeditionMemberList_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 member_count; // number of players in window
|
||||
/*008*/ ExpeditionMemberEntry_Struct members[0]; // variable length
|
||||
};
|
||||
|
||||
struct ExpeditionMemberListName_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ uint32 add_name; // padded bool, 0: remove name, 1: add name with unknown status
|
||||
/*012*/ char name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionLockoutTimerEntry_Struct
|
||||
{
|
||||
/*000*/ char expedition_name[1]; // variable length, null terminated, max 0x80 (128)
|
||||
/*000*/ uint32 seconds_remaining;
|
||||
/*000*/ int32 event_type; // seen -1 (0xffffffff) for replay timers and 1 for event timers
|
||||
/*000*/ char event_name[1]; // variable length, null terminated, max 0x100 (256)
|
||||
};
|
||||
|
||||
struct ExpeditionLockoutTimers_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 count;
|
||||
/*008*/ ExpeditionLockoutTimerEntry_Struct timers[0];
|
||||
};
|
||||
|
||||
struct ExpeditionSetLeaderName_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ char leader_name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionCommand_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ char name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionCommandSwap_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ char add_player_name[64]; // swap to (player must confirm)
|
||||
/*072*/ char rem_player_name[64]; // swap from
|
||||
};
|
||||
|
||||
struct ExpeditionExpireWarning
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ uint32 minutes_remaining;
|
||||
};
|
||||
|
||||
struct DynamicZoneCompassEntry_Struct
|
||||
{
|
||||
/*000*/ uint16 dz_zone_id; // target dz id pair
|
||||
/*002*/ uint16 dz_instance_id;
|
||||
/*004*/ uint32 dz_type; // 1: Expedition, 2: Tutorial (purple), 3: Task, 4: Mission, 5: Quest (green)
|
||||
/*008*/ uint32 unknown008;
|
||||
/*012*/ float y;
|
||||
/*016*/ float x;
|
||||
/*020*/ float z;
|
||||
};
|
||||
|
||||
struct ExpeditionCompass_Struct
|
||||
struct DynamicZoneCompass_Struct
|
||||
{
|
||||
/*000*/ uint32 clientid;
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 count;
|
||||
/*008*/ ExpeditionCompassEntry_Struct entries[0];
|
||||
/*008*/ DynamicZoneCompassEntry_Struct entries[0];
|
||||
};
|
||||
|
||||
struct DynamicZoneChooseZoneEntry_Struct
|
||||
{
|
||||
/*000*/ uint16 dz_zone_id; // dz_id pair
|
||||
/*002*/ uint16 dz_instance_id;
|
||||
/*004*/ uint32 unknown_id1; // sent back in reply
|
||||
/*008*/ uint32 dz_type; // 1: Expedition, 2: Tutorial, 3: Task, 4: Mission, 5: Quest -- sent back in reply
|
||||
/*012*/ uint32 unknown_id2; // possibly an id based on dz type, for expeditions this was same as dz_id (zone|instance) but task dz was different
|
||||
/*016*/ char description[1]; // variable length, null terminated, max 0x80 (128)
|
||||
/*000*/ char leader_name[1]; // variable length, null terminated, max 0x40 (64)
|
||||
};
|
||||
|
||||
struct DynamicZoneChooseZone_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 count;
|
||||
/*008*/ DynamicZoneChooseZoneEntry_Struct choices[0];
|
||||
};
|
||||
|
||||
struct DynamicZoneChooseZoneReply_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000; // ff ff ff ff
|
||||
/*004*/ uint32 unknown004; // seen 69 00 00 00
|
||||
/*008*/ uint32 unknown008; // ff ff ff ff
|
||||
/*012*/ uint32 unknown_id1; // from choose zone entry message
|
||||
/*016*/ uint16 dz_zone_id; // dz_id pair
|
||||
/*018*/ uint16 dz_instance_id;
|
||||
/*020*/ uint32 dz_type; // 1: Expedition, 2: Tutorial, 3: Task, 4: Mission, 5: Quest
|
||||
/*024*/ uint32 unknown_id2; // from choose zone entry message
|
||||
/*028*/ uint32 unknown028; // 00 00 00 00
|
||||
/*032*/ uint32 unknown032; // always same as unknown044
|
||||
/*036*/ uint32 unknown036;
|
||||
/*040*/ uint32 unknown040;
|
||||
/*044*/ uint32 unknown044; // always same as unknown032
|
||||
/*048*/ uint32 unknown048; // seen 01 00 00 00 and 02 00 00 00
|
||||
};
|
||||
|
||||
struct MaxCharacters_Struct
|
||||
|
||||
@ -483,15 +483,48 @@ namespace SoD
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzChooseZone)
|
||||
{
|
||||
SETUP_VAR_ENCODE(DynamicZoneChooseZone_Struct);
|
||||
|
||||
SerializeBuffer buf;
|
||||
buf.WriteUInt32(emu->client_id);
|
||||
buf.WriteUInt32(emu->count);
|
||||
|
||||
for (uint32 i = 0; i < emu->count; ++i)
|
||||
{
|
||||
buf.WriteUInt16(emu->choices[i].dz_zone_id);
|
||||
buf.WriteUInt16(emu->choices[i].dz_instance_id);
|
||||
buf.WriteUInt32(emu->choices[i].unknown_id1);
|
||||
buf.WriteUInt32(emu->choices[i].dz_type);
|
||||
buf.WriteUInt32(emu->choices[i].unknown_id2);
|
||||
buf.WriteString(emu->choices[i].description);
|
||||
buf.WriteString(emu->choices[i].leader_name);
|
||||
}
|
||||
|
||||
__packet->size = buf.size();
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
memcpy(__packet->pBuffer, buf.buffer(), __packet->size);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzCompass)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionCompass_Struct);
|
||||
ALLOC_VAR_ENCODE(structs::ExpeditionCompass_Struct, sizeof(structs::ExpeditionInfo_Struct) + sizeof(structs::ExpeditionCompassEntry_Struct) * emu->count);
|
||||
SETUP_VAR_ENCODE(DynamicZoneCompass_Struct);
|
||||
ALLOC_VAR_ENCODE(structs::DynamicZoneCompass_Struct,
|
||||
sizeof(structs::DynamicZoneCompass_Struct) +
|
||||
sizeof(structs::DynamicZoneCompassEntry_Struct) * emu->count
|
||||
);
|
||||
|
||||
OUT(client_id);
|
||||
OUT(count);
|
||||
|
||||
for (uint32 i = 0; i < emu->count; ++i)
|
||||
{
|
||||
OUT(entries[i].dz_zone_id);
|
||||
OUT(entries[i].dz_instance_id);
|
||||
OUT(entries[i].dz_type);
|
||||
OUT(entries[i].x);
|
||||
OUT(entries[i].y);
|
||||
OUT(entries[i].z);
|
||||
@ -515,81 +548,60 @@ namespace SoD
|
||||
ENCODE_LENGTH_EXACT(ExpeditionInfo_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionInfo_Struct, structs::ExpeditionInfo_Struct);
|
||||
|
||||
OUT(client_id);
|
||||
OUT(assigned);
|
||||
OUT(max_players);
|
||||
eq->unknown004 = 785316192;
|
||||
eq->unknown008 = 435601;
|
||||
strcpy(eq->expedition_name, emu->expedition_name);
|
||||
strcpy(eq->leader_name, emu->leader_name);
|
||||
strn0cpy(eq->expedition_name, emu->expedition_name, sizeof(eq->expedition_name));
|
||||
strn0cpy(eq->leader_name, emu->leader_name, sizeof(eq->leader_name));
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzExpeditionList)
|
||||
ENCODE(OP_DzExpeditionInvite)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionLockoutList_Struct);
|
||||
ENCODE_LENGTH_EXACT(ExpeditionInvite_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionInvite_Struct, structs::ExpeditionInvite_Struct);
|
||||
|
||||
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
||||
uint32 client_id = 0;
|
||||
uint8 null_term = 0;
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&emu->count, sizeof(uint32));
|
||||
OUT(client_id);
|
||||
strn0cpy(eq->inviter_name, emu->inviter_name, sizeof(eq->inviter_name));
|
||||
strn0cpy(eq->expedition_name, emu->expedition_name, sizeof(eq->expedition_name));
|
||||
OUT(swapping);
|
||||
strn0cpy(eq->swap_name, emu->swap_name, sizeof(eq->swap_name));
|
||||
OUT(dz_zone_id);
|
||||
OUT(dz_instance_id);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzExpeditionLockoutTimers)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionLockoutTimers_Struct);
|
||||
|
||||
SerializeBuffer buf;
|
||||
buf.WriteUInt32(emu->client_id);
|
||||
buf.WriteUInt32(emu->count);
|
||||
for (uint32 i = 0; i < emu->count; ++i)
|
||||
{
|
||||
ss.write(emu->entries[i].expedition, strlen(emu->entries[i].expedition));
|
||||
ss.write((const char*)&null_term, sizeof(char));
|
||||
ss.write((const char*)&emu->entries[i].time_left, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write(emu->entries[i].expedition_event, strlen(emu->entries[i].expedition_event));
|
||||
ss.write((const char*)&null_term, sizeof(char));
|
||||
buf.WriteString(emu->timers[i].expedition_name);
|
||||
buf.WriteUInt32(emu->timers[i].seconds_remaining);
|
||||
buf.WriteInt32(emu->timers[i].event_type);
|
||||
buf.WriteString(emu->timers[i].event_name);
|
||||
}
|
||||
|
||||
__packet->size = ss.str().length();
|
||||
__packet->size = buf.size();
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size);
|
||||
memcpy(__packet->pBuffer, buf.buffer(), __packet->size);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzJoinExpeditionConfirm)
|
||||
ENCODE(OP_DzSetLeaderName)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(ExpeditionJoinPrompt_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionJoinPrompt_Struct, structs::ExpeditionJoinPrompt_Struct);
|
||||
ENCODE_LENGTH_EXACT(ExpeditionSetLeaderName_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionSetLeaderName_Struct, structs::ExpeditionSetLeaderName_Struct);
|
||||
|
||||
strcpy(eq->expedition_name, emu->expedition_name);
|
||||
strcpy(eq->player_name, emu->player_name);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzLeaderStatus)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionLeaderSet_Struct);
|
||||
|
||||
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
||||
uint32 client_id = 0;
|
||||
uint8 null_term = 0;
|
||||
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write(emu->leader_name, strlen(emu->leader_name));
|
||||
ss.write((const char*)&null_term, sizeof(char));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));//0xffffffff
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));//1
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
|
||||
__packet->size = ss.str().length();
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size);
|
||||
OUT(client_id);
|
||||
strn0cpy(eq->leader_name, emu->leader_name, sizeof(eq->leader_name));
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
@ -598,26 +610,44 @@ namespace SoD
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionMemberList_Struct);
|
||||
|
||||
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
||||
|
||||
uint32 client_id = 0;
|
||||
uint8 null_term = 0;
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&emu->count, sizeof(uint32));
|
||||
for (uint32 i = 0; i < emu->count; ++i)
|
||||
SerializeBuffer buf;
|
||||
buf.WriteUInt32(emu->client_id);
|
||||
buf.WriteUInt32(emu->member_count);
|
||||
for (uint32 i = 0; i < emu->member_count; ++i)
|
||||
{
|
||||
ss.write(emu->entries[i].name, strlen(emu->entries[i].name));
|
||||
ss.write((const char*)&null_term, sizeof(char));
|
||||
ss.write((const char*)&emu->entries[i].status, sizeof(char));
|
||||
buf.WriteString(emu->members[i].name);
|
||||
buf.WriteUInt8(emu->members[i].expedition_status);
|
||||
}
|
||||
|
||||
__packet->size = ss.str().length();
|
||||
__packet->size = buf.size();
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size);
|
||||
memcpy(__packet->pBuffer, buf.buffer(), __packet->size);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzMemberListName)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(ExpeditionMemberListName_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionMemberListName_Struct, structs::ExpeditionMemberListName_Struct);
|
||||
|
||||
OUT(client_id);
|
||||
OUT(add_name);
|
||||
strn0cpy(eq->name, emu->name, sizeof(eq->name));
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzMemberListStatus)
|
||||
{
|
||||
auto emu = reinterpret_cast<ExpeditionMemberList_Struct*>((*p)->pBuffer);
|
||||
if (emu->member_count == 1)
|
||||
{
|
||||
ENCODE_FORWARD(OP_DzMemberList);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ENCODE(OP_Emote)
|
||||
{
|
||||
EQApplicationPacket *in = *p;
|
||||
@ -1353,6 +1383,7 @@ namespace SoD
|
||||
OUT(FastRegenHP);
|
||||
OUT(FastRegenMana);
|
||||
OUT(FastRegenEndurance);
|
||||
OUT(underworld_teleport_index);
|
||||
|
||||
/*fill in some unknowns with observed values, hopefully it will help */
|
||||
eq->unknown800 = -1;
|
||||
@ -2973,6 +3004,84 @@ namespace SoD
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzAddPlayer)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionCommand_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionCommand_Struct, structs::ExpeditionCommand_Struct);
|
||||
|
||||
strn0cpy(emu->name, eq->name, sizeof(emu->name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzChooseZoneReply)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::DynamicZoneChooseZoneReply_Struct);
|
||||
SETUP_DIRECT_DECODE(DynamicZoneChooseZoneReply_Struct, structs::DynamicZoneChooseZoneReply_Struct);
|
||||
|
||||
IN(unknown000);
|
||||
IN(unknown004);
|
||||
IN(unknown008);
|
||||
IN(unknown_id1);
|
||||
IN(dz_zone_id);
|
||||
IN(dz_instance_id);
|
||||
IN(dz_type);
|
||||
IN(unknown_id2);
|
||||
IN(unknown028);
|
||||
IN(unknown032);
|
||||
IN(unknown036);
|
||||
IN(unknown040);
|
||||
IN(unknown044);
|
||||
IN(unknown048);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzExpeditionInviteResponse)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionInviteResponse_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionInviteResponse_Struct, structs::ExpeditionInviteResponse_Struct);
|
||||
|
||||
IN(dz_zone_id);
|
||||
IN(dz_instance_id);
|
||||
IN(accepted);
|
||||
IN(swapping);
|
||||
strn0cpy(emu->swap_name, eq->swap_name, sizeof(emu->swap_name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzMakeLeader)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionCommand_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionCommand_Struct, structs::ExpeditionCommand_Struct);
|
||||
|
||||
strn0cpy(emu->name, eq->name, sizeof(emu->name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzRemovePlayer)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionCommand_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionCommand_Struct, structs::ExpeditionCommand_Struct);
|
||||
|
||||
strn0cpy(emu->name, eq->name, sizeof(emu->name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzSwapPlayer)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionCommandSwap_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionCommandSwap_Struct, structs::ExpeditionCommandSwap_Struct);
|
||||
|
||||
strn0cpy(emu->add_player_name, eq->add_player_name, sizeof(emu->add_player_name));
|
||||
strn0cpy(emu->rem_player_name, eq->rem_player_name, sizeof(emu->rem_player_name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_Emote)
|
||||
{
|
||||
unsigned char *__eq_buffer = __packet->pBuffer;
|
||||
|
||||
@ -35,13 +35,16 @@ E(OP_Consider)
|
||||
E(OP_Damage)
|
||||
E(OP_DeleteCharge)
|
||||
E(OP_DeleteItem)
|
||||
E(OP_DzChooseZone)
|
||||
E(OP_DzCompass)
|
||||
E(OP_DzExpeditionEndsWarning)
|
||||
E(OP_DzExpeditionInfo)
|
||||
E(OP_DzExpeditionList)
|
||||
E(OP_DzJoinExpeditionConfirm)
|
||||
E(OP_DzLeaderStatus)
|
||||
E(OP_DzExpeditionInvite)
|
||||
E(OP_DzExpeditionLockoutTimers)
|
||||
E(OP_DzMemberList)
|
||||
E(OP_DzMemberListName)
|
||||
E(OP_DzMemberListStatus)
|
||||
E(OP_DzSetLeaderName)
|
||||
E(OP_Emote)
|
||||
E(OP_ExpansionInfo)
|
||||
E(OP_FormattedMessage)
|
||||
@ -111,6 +114,12 @@ D(OP_Consider)
|
||||
D(OP_ConsiderCorpse)
|
||||
D(OP_Consume)
|
||||
D(OP_DeleteItem)
|
||||
D(OP_DzAddPlayer)
|
||||
D(OP_DzChooseZoneReply)
|
||||
D(OP_DzExpeditionInviteResponse)
|
||||
D(OP_DzMakeLeader)
|
||||
D(OP_DzRemovePlayer)
|
||||
D(OP_DzSwapPlayer)
|
||||
D(OP_Emote)
|
||||
D(OP_FaceChange)
|
||||
D(OP_FindPersonRequest)
|
||||
|
||||
@ -444,7 +444,11 @@ struct NewZone_Struct {
|
||||
/*0848*/ int32 unknown848;
|
||||
/*0852*/ uint16 zone_id;
|
||||
/*0854*/ uint16 zone_instance;
|
||||
/*0856*/ char unknown856[20];
|
||||
/*0856*/ uint32 scriptNPCReceivedanItem;
|
||||
/*0860*/ uint32 bCheck; // padded bool
|
||||
/*0864*/ uint32 scriptIDSomething;
|
||||
/*0868*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, -1 affects some collisions
|
||||
/*0872*/ uint32 scriptIDSomething3;
|
||||
/*0876*/ uint32 SuspendBuffs;
|
||||
/*0880*/ uint32 unknown880; //seen 50
|
||||
/*0884*/ uint32 unknown884; //seen 10
|
||||
@ -4165,52 +4169,160 @@ struct VeteranReward
|
||||
/*012*/ VeteranRewardItem items[8];
|
||||
};
|
||||
|
||||
struct ExpeditionEntryHeader_Struct
|
||||
|
||||
struct ExpeditionInvite_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id; // unique character id
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ char inviter_name[64];
|
||||
/*072*/ char expedition_name[128];
|
||||
/*200*/ uint8 swapping; // 0: adding 1: swapping
|
||||
/*201*/ char swap_name[64]; // if swapping, swap name being removed
|
||||
/*265*/ uint8 padding[3];
|
||||
/*268*/ uint16 dz_zone_id; // dz_id zone/instance pair, sent back in reply
|
||||
/*270*/ uint16 dz_instance_id;
|
||||
};
|
||||
|
||||
struct ExpeditionInviteResponse_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000;
|
||||
/*000*/ uint32 number_of_entries;
|
||||
};
|
||||
|
||||
struct ExpeditionJoinPrompt_Struct
|
||||
{
|
||||
/*000*/ uint32 clientid;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ char player_name[64];
|
||||
/*072*/ char expedition_name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionExpireWarning
|
||||
{
|
||||
/*000*/ uint32 clientid;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ uint32 minutes_remaining;
|
||||
/*008*/ uint16 dz_zone_id; // dz_id pair sent in invite
|
||||
/*010*/ uint16 dz_instance_id;
|
||||
/*012*/ uint8 accepted; // 0: declined 1: accepted
|
||||
/*013*/ uint8 swapping; // 0: adding 1: swapping (sent in invite)
|
||||
/*014*/ char swap_name[64]; // swap name sent in invite
|
||||
/*078*/ uint8 unknown078; // padding garbage?
|
||||
/*079*/ uint8 unknown079; // padding garbage?
|
||||
};
|
||||
|
||||
struct ExpeditionInfo_Struct
|
||||
{
|
||||
/*000*/ uint32 clientid;
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ uint32 unknown008;
|
||||
/*008*/ uint32 assigned; // padded bool
|
||||
/*012*/ uint32 max_players;
|
||||
/*016*/ char expedition_name[128];
|
||||
/*142*/ char leader_name[64];
|
||||
/*016*/ char expedition_name[128];
|
||||
/*144*/ char leader_name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionCompassEntry_Struct
|
||||
struct ExpeditionMemberEntry_Struct
|
||||
{
|
||||
/*000*/ float unknown000; //seen *((uint32*)) = 1584791871
|
||||
/*004*/ uint32 enabled; //guess
|
||||
/*008*/ uint32 unknown008; //seen 1019
|
||||
/*000*/ char name[1]; // variable length, null terminated, max 0x40 (64)
|
||||
/*000*/ uint8 expedition_status; // 0: unknown 1: Online, 2: Offline, 3: In Dynamic Zone, 4: Link Dead
|
||||
};
|
||||
|
||||
struct ExpeditionMemberList_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 member_count; // number of players in window
|
||||
/*008*/ ExpeditionMemberEntry_Struct members[0]; // variable length
|
||||
};
|
||||
|
||||
struct ExpeditionMemberListName_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ uint32 add_name; // padded bool, 0: remove name, 1: add name with unknown status
|
||||
/*012*/ char name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionLockoutTimerEntry_Struct
|
||||
{
|
||||
/*000*/ char expedition_name[1]; // variable length, null terminated, max 0x80 (128)
|
||||
/*000*/ uint32 seconds_remaining;
|
||||
/*000*/ int32 event_type; // seen -1 (0xffffffff) for replay timers and 1 for event timers
|
||||
/*000*/ char event_name[1]; // variable length, null terminated, max 0x100 (256)
|
||||
};
|
||||
|
||||
struct ExpeditionLockoutTimers_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 count;
|
||||
/*008*/ ExpeditionLockoutTimerEntry_Struct timers[0];
|
||||
};
|
||||
|
||||
struct ExpeditionSetLeaderName_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ char leader_name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionCommand_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ char name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionCommandSwap_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ char add_player_name[64]; // swap to (player must confirm)
|
||||
/*072*/ char rem_player_name[64]; // swap from
|
||||
};
|
||||
|
||||
struct ExpeditionExpireWarning
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ uint32 minutes_remaining;
|
||||
};
|
||||
|
||||
struct DynamicZoneCompassEntry_Struct
|
||||
{
|
||||
/*000*/ uint16 dz_zone_id; // target dz id pair
|
||||
/*002*/ uint16 dz_instance_id;
|
||||
/*004*/ uint32 dz_type; // 1: Expedition, 2: Tutorial (purple), 3: Task, 4: Mission, 5: Quest (green)
|
||||
/*008*/ uint32 unknown008;
|
||||
/*012*/ float y;
|
||||
/*016*/ float x;
|
||||
/*020*/ float z;
|
||||
};
|
||||
|
||||
struct ExpeditionCompass_Struct
|
||||
struct DynamicZoneCompass_Struct
|
||||
{
|
||||
/*000*/ uint32 clientid;
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 count;
|
||||
/*008*/ ExpeditionCompassEntry_Struct entries[0];
|
||||
/*008*/ DynamicZoneCompassEntry_Struct entries[0];
|
||||
};
|
||||
|
||||
struct DynamicZoneChooseZoneEntry_Struct
|
||||
{
|
||||
/*000*/ uint16 dz_zone_id; // dz_id pair
|
||||
/*002*/ uint16 dz_instance_id;
|
||||
/*004*/ uint32 unknown_id1; // sent back in reply
|
||||
/*008*/ uint32 dz_type; // 1: Expedition, 2: Tutorial, 3: Task, 4: Mission, 5: Quest -- sent back in reply
|
||||
/*012*/ uint32 unknown_id2; // possibly an id based on dz type, for expeditions this was same as dz_id (zone|instance) but task dz was different
|
||||
/*016*/ char description[1]; // variable length, null terminated, max 0x80 (128)
|
||||
/*000*/ char leader_name[1]; // variable length, null terminated, max 0x40 (64)
|
||||
};
|
||||
|
||||
struct DynamicZoneChooseZone_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 count;
|
||||
/*008*/ DynamicZoneChooseZoneEntry_Struct choices[0];
|
||||
};
|
||||
|
||||
struct DynamicZoneChooseZoneReply_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000; // ff ff ff ff
|
||||
/*004*/ uint32 unknown004; // seen 69 00 00 00
|
||||
/*008*/ uint32 unknown008; // ff ff ff ff
|
||||
/*012*/ uint32 unknown_id1; // from choose zone entry message
|
||||
/*016*/ uint16 dz_zone_id; // dz_id pair
|
||||
/*018*/ uint16 dz_instance_id;
|
||||
/*020*/ uint32 dz_type; // 1: Expedition, 2: Tutorial, 3: Task, 4: Mission, 5: Quest
|
||||
/*024*/ uint32 unknown_id2; // from choose zone entry message
|
||||
/*028*/ uint32 unknown028; // 00 00 00 00
|
||||
/*032*/ uint32 unknown032; // always same as unknown044
|
||||
/*036*/ uint32 unknown036;
|
||||
/*040*/ uint32 unknown040;
|
||||
/*044*/ uint32 unknown044; // always same as unknown032
|
||||
/*048*/ uint32 unknown048; // seen 01 00 00 00 and 02 00 00 00
|
||||
};
|
||||
|
||||
struct AltCurrencySelectItem_Struct {
|
||||
|
||||
@ -471,14 +471,48 @@ namespace SoF
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzChooseZone)
|
||||
{
|
||||
SETUP_VAR_ENCODE(DynamicZoneChooseZone_Struct);
|
||||
|
||||
SerializeBuffer buf;
|
||||
buf.WriteUInt32(emu->client_id);
|
||||
buf.WriteUInt32(emu->count);
|
||||
|
||||
for (uint32 i = 0; i < emu->count; ++i)
|
||||
{
|
||||
buf.WriteUInt16(emu->choices[i].dz_zone_id);
|
||||
buf.WriteUInt16(emu->choices[i].dz_instance_id);
|
||||
buf.WriteUInt32(emu->choices[i].unknown_id1);
|
||||
buf.WriteUInt32(emu->choices[i].dz_type);
|
||||
buf.WriteUInt32(emu->choices[i].unknown_id2);
|
||||
buf.WriteString(emu->choices[i].description);
|
||||
buf.WriteString(emu->choices[i].leader_name);
|
||||
}
|
||||
|
||||
__packet->size = buf.size();
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
memcpy(__packet->pBuffer, buf.buffer(), __packet->size);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzCompass)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionCompass_Struct);
|
||||
ALLOC_VAR_ENCODE(structs::ExpeditionCompass_Struct, sizeof(structs::ExpeditionInfo_Struct) + sizeof(structs::ExpeditionCompassEntry_Struct) * emu->count);
|
||||
SETUP_VAR_ENCODE(DynamicZoneCompass_Struct);
|
||||
ALLOC_VAR_ENCODE(structs::DynamicZoneCompass_Struct,
|
||||
sizeof(structs::DynamicZoneCompass_Struct) +
|
||||
sizeof(structs::DynamicZoneCompassEntry_Struct) * emu->count
|
||||
);
|
||||
|
||||
OUT(client_id);
|
||||
OUT(count);
|
||||
|
||||
for (uint32 i = 0; i < emu->count; ++i)
|
||||
{
|
||||
OUT(entries[i].dz_zone_id);
|
||||
OUT(entries[i].dz_instance_id);
|
||||
OUT(entries[i].dz_type);
|
||||
OUT(entries[i].x);
|
||||
OUT(entries[i].y);
|
||||
OUT(entries[i].z);
|
||||
@ -502,80 +536,60 @@ namespace SoF
|
||||
ENCODE_LENGTH_EXACT(ExpeditionInfo_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionInfo_Struct, structs::ExpeditionInfo_Struct);
|
||||
|
||||
OUT(client_id);
|
||||
OUT(assigned);
|
||||
OUT(max_players);
|
||||
eq->enabled_max = 1;
|
||||
strcpy(eq->expedition_name, emu->expedition_name);
|
||||
strcpy(eq->leader_name, emu->leader_name);
|
||||
strn0cpy(eq->expedition_name, emu->expedition_name, sizeof(eq->expedition_name));
|
||||
strn0cpy(eq->leader_name, emu->leader_name, sizeof(eq->leader_name));
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzExpeditionList)
|
||||
ENCODE(OP_DzExpeditionInvite)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionLockoutList_Struct);
|
||||
ENCODE_LENGTH_EXACT(ExpeditionInvite_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionInvite_Struct, structs::ExpeditionInvite_Struct);
|
||||
|
||||
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
||||
uint32 client_id = 0;
|
||||
uint8 null_term = 0;
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&emu->count, sizeof(uint32));
|
||||
for (int i = 0; i < emu->count; ++i)
|
||||
OUT(client_id);
|
||||
strn0cpy(eq->inviter_name, emu->inviter_name, sizeof(eq->inviter_name));
|
||||
strn0cpy(eq->expedition_name, emu->expedition_name, sizeof(eq->expedition_name));
|
||||
OUT(swapping);
|
||||
strn0cpy(eq->swap_name, emu->swap_name, sizeof(eq->swap_name));
|
||||
OUT(dz_zone_id);
|
||||
OUT(dz_instance_id);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzExpeditionLockoutTimers)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionLockoutTimers_Struct);
|
||||
|
||||
SerializeBuffer buf;
|
||||
buf.WriteUInt32(emu->client_id);
|
||||
buf.WriteUInt32(emu->count);
|
||||
for (uint32 i = 0; i < emu->count; ++i)
|
||||
{
|
||||
ss.write(emu->entries[i].expedition, strlen(emu->entries[i].expedition));
|
||||
ss.write((const char*)&null_term, sizeof(char));
|
||||
ss.write((const char*)&emu->entries[i].time_left, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write(emu->entries[i].expedition_event, strlen(emu->entries[i].expedition_event));
|
||||
ss.write((const char*)&null_term, sizeof(char));
|
||||
buf.WriteString(emu->timers[i].expedition_name);
|
||||
buf.WriteUInt32(emu->timers[i].seconds_remaining);
|
||||
buf.WriteInt32(emu->timers[i].event_type);
|
||||
buf.WriteString(emu->timers[i].event_name);
|
||||
}
|
||||
|
||||
__packet->size = ss.str().length();
|
||||
__packet->size = buf.size();
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size);
|
||||
memcpy(__packet->pBuffer, buf.buffer(), __packet->size);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzJoinExpeditionConfirm)
|
||||
ENCODE(OP_DzSetLeaderName)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(ExpeditionJoinPrompt_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionJoinPrompt_Struct, structs::ExpeditionJoinPrompt_Struct);
|
||||
ENCODE_LENGTH_EXACT(ExpeditionSetLeaderName_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionSetLeaderName_Struct, structs::ExpeditionSetLeaderName_Struct);
|
||||
|
||||
strcpy(eq->expedition_name, emu->expedition_name);
|
||||
strcpy(eq->player_name, emu->player_name);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzLeaderStatus)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionLeaderSet_Struct);
|
||||
|
||||
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
||||
uint32 client_id = 0;
|
||||
uint8 null_term = 0;
|
||||
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
//ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write(emu->leader_name, strlen(emu->leader_name));
|
||||
ss.write((const char*)&null_term, sizeof(char));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));//0xffffffff
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));//1
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
|
||||
__packet->size = ss.str().length();
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size);
|
||||
OUT(client_id);
|
||||
strn0cpy(eq->leader_name, emu->leader_name, sizeof(eq->leader_name));
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
@ -584,26 +598,43 @@ namespace SoF
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionMemberList_Struct);
|
||||
|
||||
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
||||
|
||||
uint32 client_id = 0;
|
||||
uint8 null_term = 0;
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&emu->count, sizeof(uint32));
|
||||
for (uint32 i = 0; i < emu->count; ++i)
|
||||
SerializeBuffer buf;
|
||||
buf.WriteUInt32(emu->client_id);
|
||||
buf.WriteUInt32(emu->member_count);
|
||||
for (uint32 i = 0; i < emu->member_count; ++i)
|
||||
{
|
||||
ss.write(emu->entries[i].name, strlen(emu->entries[i].name));
|
||||
ss.write((const char*)&null_term, sizeof(char));
|
||||
ss.write((const char*)&emu->entries[i].status, sizeof(char));
|
||||
buf.WriteString(emu->members[i].name);
|
||||
buf.WriteUInt8(emu->members[i].expedition_status);
|
||||
}
|
||||
|
||||
__packet->size = ss.str().length();
|
||||
__packet->size = buf.size();
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size);
|
||||
memcpy(__packet->pBuffer, buf.buffer(), __packet->size);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzMemberListName)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(ExpeditionMemberListName_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionMemberListName_Struct, structs::ExpeditionMemberListName_Struct);
|
||||
|
||||
OUT(client_id);
|
||||
OUT(add_name);
|
||||
strn0cpy(eq->name, emu->name, sizeof(eq->name));
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzMemberListStatus)
|
||||
{
|
||||
auto emu = reinterpret_cast<ExpeditionMemberList_Struct*>((*p)->pBuffer);
|
||||
if (emu->member_count == 1)
|
||||
{
|
||||
ENCODE_FORWARD(OP_DzMemberList);
|
||||
}
|
||||
}
|
||||
|
||||
ENCODE(OP_Emote)
|
||||
{
|
||||
EQApplicationPacket *in = *p;
|
||||
@ -1030,6 +1061,7 @@ namespace SoF
|
||||
OUT(FastRegenHP);
|
||||
OUT(FastRegenMana);
|
||||
OUT(FastRegenEndurance);
|
||||
OUT(underworld_teleport_index);
|
||||
|
||||
/*fill in some unknowns with observed values, hopefully it will help */
|
||||
eq->unknown796 = -1;
|
||||
@ -2434,6 +2466,83 @@ namespace SoF
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzAddPlayer)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionCommand_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionCommand_Struct, structs::ExpeditionCommand_Struct);
|
||||
|
||||
strn0cpy(emu->name, eq->name, sizeof(emu->name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzChooseZoneReply)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::DynamicZoneChooseZoneReply_Struct);
|
||||
SETUP_DIRECT_DECODE(DynamicZoneChooseZoneReply_Struct, structs::DynamicZoneChooseZoneReply_Struct);
|
||||
|
||||
emu->unknown000 = eq->unknown000;
|
||||
emu->unknown008 = eq->unknown004;
|
||||
IN(unknown_id1);
|
||||
IN(dz_zone_id);
|
||||
IN(dz_instance_id);
|
||||
IN(dz_type);
|
||||
IN(unknown_id2);
|
||||
emu->unknown028 = eq->unknown024;
|
||||
emu->unknown032 = eq->unknown028;
|
||||
emu->unknown036 = eq->unknown032;
|
||||
emu->unknown040 = eq->unknown036;
|
||||
emu->unknown044 = eq->unknown040;
|
||||
emu->unknown048 = eq->unknown044;
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzExpeditionInviteResponse)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionInviteResponse_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionInviteResponse_Struct, structs::ExpeditionInviteResponse_Struct);
|
||||
|
||||
IN(dz_zone_id);
|
||||
IN(dz_instance_id);
|
||||
IN(accepted);
|
||||
IN(swapping);
|
||||
strn0cpy(emu->swap_name, eq->swap_name, sizeof(emu->swap_name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzMakeLeader)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionCommand_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionCommand_Struct, structs::ExpeditionCommand_Struct);
|
||||
|
||||
strn0cpy(emu->name, eq->name, sizeof(emu->name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzRemovePlayer)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionCommand_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionCommand_Struct, structs::ExpeditionCommand_Struct);
|
||||
|
||||
strn0cpy(emu->name, eq->name, sizeof(emu->name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzSwapPlayer)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionCommandSwap_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionCommandSwap_Struct, structs::ExpeditionCommandSwap_Struct);
|
||||
|
||||
strn0cpy(emu->add_player_name, eq->add_player_name, sizeof(emu->add_player_name));
|
||||
strn0cpy(emu->rem_player_name, eq->rem_player_name, sizeof(emu->rem_player_name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_Emote)
|
||||
{
|
||||
unsigned char *__eq_buffer = __packet->pBuffer;
|
||||
|
||||
@ -36,13 +36,16 @@ E(OP_Damage)
|
||||
E(OP_DeleteCharge)
|
||||
E(OP_DeleteItem)
|
||||
E(OP_DeleteSpawn)
|
||||
E(OP_DzChooseZone)
|
||||
E(OP_DzCompass)
|
||||
E(OP_DzExpeditionEndsWarning)
|
||||
E(OP_DzExpeditionInfo)
|
||||
E(OP_DzExpeditionList)
|
||||
E(OP_DzJoinExpeditionConfirm)
|
||||
E(OP_DzLeaderStatus)
|
||||
E(OP_DzExpeditionInvite)
|
||||
E(OP_DzExpeditionLockoutTimers)
|
||||
E(OP_DzMemberList)
|
||||
E(OP_DzMemberListName)
|
||||
E(OP_DzMemberListStatus)
|
||||
E(OP_DzSetLeaderName)
|
||||
E(OP_Emote)
|
||||
E(OP_ExpansionInfo)
|
||||
E(OP_FormattedMessage)
|
||||
@ -103,6 +106,12 @@ D(OP_Consider)
|
||||
D(OP_ConsiderCorpse)
|
||||
D(OP_Consume)
|
||||
D(OP_DeleteItem)
|
||||
D(OP_DzAddPlayer)
|
||||
D(OP_DzChooseZoneReply)
|
||||
D(OP_DzExpeditionInviteResponse)
|
||||
D(OP_DzMakeLeader)
|
||||
D(OP_DzRemovePlayer)
|
||||
D(OP_DzSwapPlayer)
|
||||
D(OP_Emote)
|
||||
D(OP_FaceChange)
|
||||
D(OP_FindPersonRequest)
|
||||
|
||||
@ -448,7 +448,11 @@ struct NewZone_Struct {
|
||||
/*0844*/ int32 unknown844;
|
||||
/*0848*/ uint16 zone_id;
|
||||
/*0850*/ uint16 zone_instance;
|
||||
/*0852*/ char unknown852[20];
|
||||
/*0852*/ uint32 scriptNPCReceivedanItem;
|
||||
/*0856*/ uint32 bCheck; // padded bool
|
||||
/*0860*/ uint32 scriptIDSomething;
|
||||
/*0864*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, -1 affects some collisions
|
||||
/*0868*/ uint32 scriptIDSomething3;
|
||||
/*0872*/ uint32 SuspendBuffs;
|
||||
/*0876*/ uint32 unknown876; //seen 50
|
||||
/*0880*/ uint32 unknown880; //seen 10
|
||||
@ -4084,43 +4088,150 @@ struct VeteranReward
|
||||
/*012*/ VeteranRewardItem items[8];
|
||||
};
|
||||
|
||||
struct ExpeditionExpireWarning
|
||||
struct ExpeditionInvite_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ char inviter_name[64];
|
||||
/*068*/ char expedition_name[128];
|
||||
/*196*/ uint8 swapping; // 0: adding 1: swapping
|
||||
/*197*/ char swap_name[64]; // if swapping, swap name being removed
|
||||
/*261*/ uint8 padding[3];
|
||||
/*264*/ uint16 dz_zone_id; // dz_id zone/instance pair, sent back in reply
|
||||
/*268*/ uint16 dz_instance_id;
|
||||
};
|
||||
|
||||
struct ExpeditionInviteResponse_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000;
|
||||
/*004*/ uint32 minutes_remaining;
|
||||
/*004*/ uint16 dz_zone_id; // dz_id pair sent in invite
|
||||
/*006*/ uint16 dz_instance_id;
|
||||
/*008*/ uint8 accepted; // 0: declined 1: accepted
|
||||
/*009*/ uint8 swapping; // 0: adding 1: swapping (sent in invite)
|
||||
/*010*/ char swap_name[64]; // swap name sent in invite
|
||||
/*074*/ uint8 unknown078; // padding/garbage?
|
||||
/*075*/ uint8 unknown079; // padding/garbage?
|
||||
};
|
||||
|
||||
struct ExpeditionInfo_Struct
|
||||
{
|
||||
/*000*/ uint32 clientid;
|
||||
/*004*/ uint32 enabled_max;
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 assigned; // padded bool
|
||||
/*008*/ uint32 max_players;
|
||||
/*012*/ char expedition_name[128];
|
||||
/*142*/ char leader_name[64];
|
||||
/*012*/ char expedition_name[128];
|
||||
/*140*/ char leader_name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionCompassEntry_Struct
|
||||
struct ExpeditionMemberEntry_Struct
|
||||
{
|
||||
/*000*/ float unknown000; //seen *((uint32*)) = 1584791871
|
||||
/*004*/ uint32 enabled; //guess
|
||||
/*008*/ uint32 unknown008; //seen 1019
|
||||
/*000*/ char name[1]; // variable length, null terminated, max 0x40 (64)
|
||||
/*000*/ uint8 expedition_status; // 0: unknown 1: Online, 2: Offline, 3: In Dynamic Zone, 4: Link Dead
|
||||
};
|
||||
|
||||
struct ExpeditionMemberList_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 member_count;
|
||||
/*008*/ ExpeditionMemberEntry_Struct members[0]; // variable length
|
||||
};
|
||||
|
||||
struct ExpeditionMemberListName_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 add_name; // padded bool, 0: remove name, 1: add name with unknown status
|
||||
/*008*/ char name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionLockoutTimerEntry_Struct
|
||||
{
|
||||
/*000*/ char expedition_name[1]; // variable length, null terminated, max 0x80 (128)
|
||||
/*000*/ uint32 seconds_remaining;
|
||||
/*000*/ int32 event_type; // seen -1 (0xffffffff) for replay timers and 1 for event timers
|
||||
/*000*/ char event_name[1]; // variable length, null terminated, max 0x100 (256)
|
||||
};
|
||||
|
||||
struct ExpeditionLockoutTimers_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 count;
|
||||
/*008*/ ExpeditionLockoutTimerEntry_Struct timers[0];
|
||||
};
|
||||
|
||||
struct ExpeditionSetLeaderName_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ char leader_name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionCommand_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000;
|
||||
/*004*/ char name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionCommandSwap_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000;
|
||||
/*004*/ char add_player_name[64]; // swap to (player must confirm)
|
||||
/*068*/ char rem_player_name[64]; // swap from
|
||||
};
|
||||
|
||||
struct ExpeditionExpireWarning
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 minutes_remaining;
|
||||
};
|
||||
|
||||
struct DynamicZoneCompassEntry_Struct
|
||||
{
|
||||
/*000*/ uint16 dz_zone_id; // target dz id pair
|
||||
/*002*/ uint16 dz_instance_id;
|
||||
/*004*/ uint32 dz_type; // 1: Expedition, 2: Tutorial (purple), 3: Task, 4: Mission, 5: Quest (green)
|
||||
/*008*/ uint32 unknown008;
|
||||
/*012*/ float y;
|
||||
/*016*/ float x;
|
||||
/*020*/ float z;
|
||||
};
|
||||
|
||||
struct ExpeditionCompass_Struct
|
||||
struct DynamicZoneCompass_Struct
|
||||
{
|
||||
/*000*/ uint32 clientid;
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 count;
|
||||
/*008*/ ExpeditionCompassEntry_Struct entries[0];
|
||||
/*008*/ DynamicZoneCompassEntry_Struct entries[0];
|
||||
};
|
||||
|
||||
struct ExpeditionJoinPrompt_Struct
|
||||
struct DynamicZoneChooseZoneEntry_Struct
|
||||
{
|
||||
/*000*/ uint32 clientid;
|
||||
/*004*/ char player_name[64];
|
||||
/*068*/ char expedition_name[64];
|
||||
/*000*/ uint16 dz_zone_id; // dz_id pair
|
||||
/*002*/ uint16 dz_instance_id;
|
||||
/*004*/ uint32 unknown_id1; // sent back in reply
|
||||
/*008*/ uint32 dz_type; // 1: Expedition, 2: Tutorial, 3: Task, 4: Mission, 5: Quest -- sent back in reply
|
||||
/*012*/ uint32 unknown_id2; // possibly an id based on dz type, for expeditions this was same as dz_id (zone|instance) but task dz was different
|
||||
/*016*/ char description[1]; // variable length, null terminated, max 0x80 (128)
|
||||
/*000*/ char leader_name[1]; // variable length, null terminated, max 0x40 (64)
|
||||
};
|
||||
|
||||
struct DynamicZoneChooseZone_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 count;
|
||||
/*008*/ DynamicZoneChooseZoneEntry_Struct choices[0];
|
||||
};
|
||||
|
||||
struct DynamicZoneChooseZoneReply_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ uint32 unknown_id1;
|
||||
/*012*/ uint16 dz_zone_id;
|
||||
/*014*/ uint16 dz_instance_id;
|
||||
/*016*/ uint32 dz_type; // 1: Expedition, 2: Tutorial, 3: Task, 4: Mission, 5: Quest
|
||||
/*020*/ uint32 unknown_id2;
|
||||
/*024*/ uint32 unknown024;
|
||||
/*028*/ uint32 unknown028; // always same as unknown040
|
||||
/*032*/ uint32 unknown032;
|
||||
/*036*/ uint32 unknown036;
|
||||
/*040*/ uint32 unknown040; // always same as unknown028
|
||||
/*044*/ uint32 unknown044;
|
||||
};
|
||||
|
||||
struct AltCurrencySelectItem_Struct {
|
||||
|
||||
@ -414,15 +414,48 @@ namespace Titanium
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzChooseZone)
|
||||
{
|
||||
SETUP_VAR_ENCODE(DynamicZoneChooseZone_Struct);
|
||||
|
||||
SerializeBuffer buf;
|
||||
buf.WriteUInt32(emu->client_id);
|
||||
buf.WriteUInt32(emu->count);
|
||||
|
||||
for (uint32 i = 0; i < emu->count; ++i)
|
||||
{
|
||||
buf.WriteUInt16(emu->choices[i].dz_zone_id);
|
||||
buf.WriteUInt16(emu->choices[i].dz_instance_id);
|
||||
buf.WriteUInt32(emu->choices[i].unknown_id1);
|
||||
buf.WriteUInt32(emu->choices[i].dz_type);
|
||||
buf.WriteUInt32(emu->choices[i].unknown_id2);
|
||||
buf.WriteString(emu->choices[i].description);
|
||||
buf.WriteString(emu->choices[i].leader_name);
|
||||
}
|
||||
|
||||
__packet->size = buf.size();
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
memcpy(__packet->pBuffer, buf.buffer(), __packet->size);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzCompass)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionCompass_Struct);
|
||||
ALLOC_VAR_ENCODE(structs::ExpeditionCompass_Struct, sizeof(structs::ExpeditionInfo_Struct) + sizeof(structs::ExpeditionCompassEntry_Struct) * emu->count);
|
||||
SETUP_VAR_ENCODE(DynamicZoneCompass_Struct);
|
||||
ALLOC_VAR_ENCODE(structs::DynamicZoneCompass_Struct,
|
||||
sizeof(structs::DynamicZoneCompass_Struct) +
|
||||
sizeof(structs::DynamicZoneCompassEntry_Struct) * emu->count
|
||||
);
|
||||
|
||||
OUT(client_id);
|
||||
OUT(count);
|
||||
|
||||
for (uint32 i = 0; i < emu->count; ++i)
|
||||
{
|
||||
OUT(entries[i].dz_zone_id);
|
||||
OUT(entries[i].dz_instance_id);
|
||||
OUT(entries[i].dz_type);
|
||||
OUT(entries[i].x);
|
||||
OUT(entries[i].y);
|
||||
OUT(entries[i].z);
|
||||
@ -446,80 +479,60 @@ namespace Titanium
|
||||
ENCODE_LENGTH_EXACT(ExpeditionInfo_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionInfo_Struct, structs::ExpeditionInfo_Struct);
|
||||
|
||||
OUT(client_id);
|
||||
OUT(assigned);
|
||||
OUT(max_players);
|
||||
eq->enabled_max = 1;
|
||||
strcpy(eq->expedition_name, emu->expedition_name);
|
||||
strcpy(eq->leader_name, emu->leader_name);
|
||||
strn0cpy(eq->expedition_name, emu->expedition_name, sizeof(eq->expedition_name));
|
||||
strn0cpy(eq->leader_name, emu->leader_name, sizeof(eq->leader_name));
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzExpeditionList)
|
||||
ENCODE(OP_DzExpeditionInvite)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionLockoutList_Struct);
|
||||
ENCODE_LENGTH_EXACT(ExpeditionInvite_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionInvite_Struct, structs::ExpeditionInvite_Struct);
|
||||
|
||||
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
||||
uint32 client_id = 0;
|
||||
uint8 null_term = 0;
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&emu->count, sizeof(uint32));
|
||||
OUT(client_id);
|
||||
strn0cpy(eq->inviter_name, emu->inviter_name, sizeof(eq->inviter_name));
|
||||
strn0cpy(eq->expedition_name, emu->expedition_name, sizeof(eq->expedition_name));
|
||||
OUT(swapping);
|
||||
strn0cpy(eq->swap_name, emu->swap_name, sizeof(eq->swap_name));
|
||||
OUT(dz_zone_id);
|
||||
OUT(dz_instance_id);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzExpeditionLockoutTimers)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionLockoutTimers_Struct);
|
||||
|
||||
SerializeBuffer buf;
|
||||
buf.WriteUInt32(emu->client_id);
|
||||
buf.WriteUInt32(emu->count);
|
||||
for (uint32 i = 0; i < emu->count; ++i)
|
||||
{
|
||||
ss.write(emu->entries[i].expedition, strlen(emu->entries[i].expedition));
|
||||
ss.write((const char*)&null_term, sizeof(char));
|
||||
ss.write((const char*)&emu->entries[i].time_left, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write(emu->entries[i].expedition_event, strlen(emu->entries[i].expedition_event));
|
||||
ss.write((const char*)&null_term, sizeof(char));
|
||||
buf.WriteString(emu->timers[i].expedition_name);
|
||||
buf.WriteUInt32(emu->timers[i].seconds_remaining);
|
||||
buf.WriteInt32(emu->timers[i].event_type);
|
||||
buf.WriteString(emu->timers[i].event_name);
|
||||
}
|
||||
|
||||
__packet->size = ss.str().length();
|
||||
__packet->size = buf.size();
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size);
|
||||
memcpy(__packet->pBuffer, buf.buffer(), __packet->size);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzJoinExpeditionConfirm)
|
||||
ENCODE(OP_DzSetLeaderName)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(ExpeditionJoinPrompt_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionJoinPrompt_Struct, structs::ExpeditionJoinPrompt_Struct);
|
||||
ENCODE_LENGTH_EXACT(ExpeditionSetLeaderName_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionSetLeaderName_Struct, structs::ExpeditionSetLeaderName_Struct);
|
||||
|
||||
strcpy(eq->expedition_name, emu->expedition_name);
|
||||
strcpy(eq->player_name, emu->player_name);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzLeaderStatus)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionLeaderSet_Struct);
|
||||
|
||||
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
||||
uint32 client_id = 0;
|
||||
uint8 null_term = 0;
|
||||
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
//ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write(emu->leader_name, strlen(emu->leader_name));
|
||||
ss.write((const char*)&null_term, sizeof(char));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));//0xffffffff
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));//1
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
|
||||
__packet->size = ss.str().length();
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size);
|
||||
OUT(client_id);
|
||||
strn0cpy(eq->leader_name, emu->leader_name, sizeof(eq->leader_name));
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
@ -528,26 +541,43 @@ namespace Titanium
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionMemberList_Struct);
|
||||
|
||||
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
||||
|
||||
uint32 client_id = 0;
|
||||
uint8 null_term = 0;
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&emu->count, sizeof(uint32));
|
||||
for (uint32 i = 0; i < emu->count; ++i)
|
||||
SerializeBuffer buf;
|
||||
buf.WriteUInt32(emu->client_id);
|
||||
buf.WriteUInt32(emu->member_count);
|
||||
for (uint32 i = 0; i < emu->member_count; ++i)
|
||||
{
|
||||
ss.write(emu->entries[i].name, strlen(emu->entries[i].name));
|
||||
ss.write((const char*)&null_term, sizeof(char));
|
||||
ss.write((const char*)&emu->entries[i].status, sizeof(char));
|
||||
buf.WriteString(emu->members[i].name);
|
||||
buf.WriteUInt8(emu->members[i].expedition_status);
|
||||
}
|
||||
|
||||
__packet->size = ss.str().length();
|
||||
__packet->size = buf.size();
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size);
|
||||
memcpy(__packet->pBuffer, buf.buffer(), __packet->size);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzMemberListName)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(ExpeditionMemberListName_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionMemberListName_Struct, structs::ExpeditionMemberListName_Struct);
|
||||
|
||||
OUT(client_id);
|
||||
OUT(add_name);
|
||||
strn0cpy(eq->name, emu->name, sizeof(eq->name));
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzMemberListStatus)
|
||||
{
|
||||
auto emu = reinterpret_cast<ExpeditionMemberList_Struct*>((*p)->pBuffer);
|
||||
if (emu->member_count == 1)
|
||||
{
|
||||
ENCODE_FORWARD(OP_DzMemberList);
|
||||
}
|
||||
}
|
||||
|
||||
ENCODE(OP_Emote)
|
||||
{
|
||||
EQApplicationPacket *in = *p;
|
||||
@ -1943,6 +1973,83 @@ namespace Titanium
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzAddPlayer)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionCommand_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionCommand_Struct, structs::ExpeditionCommand_Struct);
|
||||
|
||||
strn0cpy(emu->name, eq->name, sizeof(emu->name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzChooseZoneReply)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::DynamicZoneChooseZoneReply_Struct);
|
||||
SETUP_DIRECT_DECODE(DynamicZoneChooseZoneReply_Struct, structs::DynamicZoneChooseZoneReply_Struct);
|
||||
|
||||
emu->unknown000 = eq->unknown000;
|
||||
emu->unknown008 = eq->unknown004;
|
||||
IN(unknown_id1);
|
||||
IN(dz_zone_id);
|
||||
IN(dz_instance_id);
|
||||
IN(dz_type);
|
||||
IN(unknown_id2);
|
||||
emu->unknown028 = eq->unknown024;
|
||||
emu->unknown032 = eq->unknown028;
|
||||
emu->unknown036 = eq->unknown032;
|
||||
emu->unknown040 = eq->unknown036;
|
||||
emu->unknown044 = eq->unknown040;
|
||||
emu->unknown048 = eq->unknown044;
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzExpeditionInviteResponse)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionInviteResponse_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionInviteResponse_Struct, structs::ExpeditionInviteResponse_Struct);
|
||||
|
||||
IN(dz_zone_id);
|
||||
IN(dz_instance_id);
|
||||
IN(accepted);
|
||||
IN(swapping);
|
||||
strn0cpy(emu->swap_name, eq->swap_name, sizeof(emu->swap_name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzMakeLeader)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionCommand_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionCommand_Struct, structs::ExpeditionCommand_Struct);
|
||||
|
||||
strn0cpy(emu->name, eq->name, sizeof(emu->name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzRemovePlayer)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionCommand_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionCommand_Struct, structs::ExpeditionCommand_Struct);
|
||||
|
||||
strn0cpy(emu->name, eq->name, sizeof(emu->name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzSwapPlayer)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionCommandSwap_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionCommandSwap_Struct, structs::ExpeditionCommandSwap_Struct);
|
||||
|
||||
strn0cpy(emu->add_player_name, eq->add_player_name, sizeof(emu->add_player_name));
|
||||
strn0cpy(emu->rem_player_name, eq->rem_player_name, sizeof(emu->rem_player_name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_Emote)
|
||||
{
|
||||
unsigned char *__eq_buffer = __packet->pBuffer;
|
||||
|
||||
@ -32,13 +32,16 @@ E(OP_Damage)
|
||||
E(OP_DeleteCharge)
|
||||
E(OP_DeleteItem)
|
||||
E(OP_DeleteSpawn)
|
||||
E(OP_DzChooseZone)
|
||||
E(OP_DzCompass)
|
||||
E(OP_DzExpeditionEndsWarning)
|
||||
E(OP_DzExpeditionInfo)
|
||||
E(OP_DzExpeditionList)
|
||||
E(OP_DzJoinExpeditionConfirm)
|
||||
E(OP_DzLeaderStatus)
|
||||
E(OP_DzExpeditionInvite)
|
||||
E(OP_DzExpeditionLockoutTimers)
|
||||
E(OP_DzMemberList)
|
||||
E(OP_DzMemberListName)
|
||||
E(OP_DzMemberListStatus)
|
||||
E(OP_DzSetLeaderName)
|
||||
E(OP_Emote)
|
||||
E(OP_FormattedMessage)
|
||||
E(OP_GroundSpawn)
|
||||
@ -86,6 +89,12 @@ D(OP_CharacterCreate)
|
||||
D(OP_ClientUpdate)
|
||||
D(OP_Consume)
|
||||
D(OP_DeleteItem)
|
||||
D(OP_DzAddPlayer)
|
||||
D(OP_DzChooseZoneReply)
|
||||
D(OP_DzExpeditionInviteResponse)
|
||||
D(OP_DzMakeLeader)
|
||||
D(OP_DzRemovePlayer)
|
||||
D(OP_DzSwapPlayer)
|
||||
D(OP_Emote)
|
||||
D(OP_FaceChange)
|
||||
D(OP_InspectAnswer)
|
||||
|
||||
@ -3299,43 +3299,150 @@ struct VeteranReward
|
||||
/*004*/ VeteranRewardItem item;
|
||||
};
|
||||
|
||||
struct ExpeditionExpireWarning
|
||||
struct ExpeditionInvite_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ char inviter_name[64];
|
||||
/*068*/ char expedition_name[128];
|
||||
/*196*/ uint8 swapping; // 0: adding 1: swapping
|
||||
/*197*/ char swap_name[64]; // if swapping, swap name being removed
|
||||
/*261*/ uint8 padding[3];
|
||||
/*264*/ uint16 dz_zone_id; // dz_id zone/instance pair, sent back in reply
|
||||
/*268*/ uint16 dz_instance_id;
|
||||
};
|
||||
|
||||
struct ExpeditionInviteResponse_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000;
|
||||
/*004*/ uint32 minutes_remaining;
|
||||
/*004*/ uint16 dz_zone_id; // dz_id pair sent in invite
|
||||
/*006*/ uint16 dz_instance_id;
|
||||
/*008*/ uint8 accepted; // 0: declined 1: accepted
|
||||
/*009*/ uint8 swapping; // 0: adding 1: swapping (sent in invite)
|
||||
/*010*/ char swap_name[64]; // swap name sent in invite
|
||||
/*074*/ uint8 unknown078; // padding/garbage?
|
||||
/*075*/ uint8 unknown079; // padding/garbage?
|
||||
};
|
||||
|
||||
struct ExpeditionInfo_Struct
|
||||
{
|
||||
/*000*/ uint32 clientid;
|
||||
/*004*/ uint32 enabled_max;
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 assigned; // padded bool
|
||||
/*008*/ uint32 max_players;
|
||||
/*012*/ char expedition_name[128];
|
||||
/*142*/ char leader_name[64];
|
||||
/*012*/ char expedition_name[128];
|
||||
/*140*/ char leader_name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionCompassEntry_Struct
|
||||
struct ExpeditionMemberEntry_Struct
|
||||
{
|
||||
/*000*/ float unknown000; //seen *((uint32*)) = 1584791871
|
||||
/*004*/ uint32 enabled; //guess
|
||||
/*008*/ uint32 unknown008; //seen 1019
|
||||
/*000*/ char name[1]; // variable length, null terminated, max 0x40 (64)
|
||||
/*000*/ uint8 expedition_status; // 0: unknown 1: Online, 2: Offline, 3: In Dynamic Zone, 4: Link Dead
|
||||
};
|
||||
|
||||
struct ExpeditionMemberList_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 member_count;
|
||||
/*008*/ ExpeditionMemberEntry_Struct members[0]; // variable length
|
||||
};
|
||||
|
||||
struct ExpeditionMemberListName_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 add_name; // padded bool, 0: remove name, 1: add name with unknown status
|
||||
/*008*/ char name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionLockoutTimerEntry_Struct
|
||||
{
|
||||
/*000*/ char expedition_name[1]; // variable length, null terminated, max 0x80 (128)
|
||||
/*000*/ uint32 seconds_remaining;
|
||||
/*000*/ int32 event_type; // seen -1 (0xffffffff) for replay timers and 1 for event timers
|
||||
/*000*/ char event_name[1]; // variable length, null terminated, max 0x100 (256)
|
||||
};
|
||||
|
||||
struct ExpeditionLockoutTimers_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 count;
|
||||
/*008*/ ExpeditionLockoutTimerEntry_Struct timers[0];
|
||||
};
|
||||
|
||||
struct ExpeditionSetLeaderName_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ char leader_name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionCommand_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000;
|
||||
/*004*/ char name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionCommandSwap_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000;
|
||||
/*004*/ char add_player_name[64]; // swap to (player must confirm)
|
||||
/*068*/ char rem_player_name[64]; // swap from
|
||||
};
|
||||
|
||||
struct ExpeditionExpireWarning
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 minutes_remaining;
|
||||
};
|
||||
|
||||
struct DynamicZoneCompassEntry_Struct
|
||||
{
|
||||
/*000*/ uint16 dz_zone_id; // target dz id pair
|
||||
/*002*/ uint16 dz_instance_id;
|
||||
/*004*/ uint32 dz_type; // 1: Expedition, 2: Tutorial (purple), 3: Task, 4: Mission, 5: Quest (green)
|
||||
/*008*/ uint32 unknown008;
|
||||
/*012*/ float y;
|
||||
/*016*/ float x;
|
||||
/*020*/ float z;
|
||||
};
|
||||
|
||||
struct ExpeditionCompass_Struct
|
||||
struct DynamicZoneCompass_Struct
|
||||
{
|
||||
/*000*/ uint32 clientid;
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 count;
|
||||
/*008*/ ExpeditionCompassEntry_Struct entries[0];
|
||||
/*008*/ DynamicZoneCompassEntry_Struct entries[0];
|
||||
};
|
||||
|
||||
struct ExpeditionJoinPrompt_Struct
|
||||
struct DynamicZoneChooseZoneEntry_Struct
|
||||
{
|
||||
/*000*/ uint32 clientid;
|
||||
/*004*/ char player_name[64];
|
||||
/*068*/ char expedition_name[64];
|
||||
/*000*/ uint16 dz_zone_id; // dz_id pair
|
||||
/*002*/ uint16 dz_instance_id;
|
||||
/*004*/ uint32 unknown_id1; // sent back in reply
|
||||
/*008*/ uint32 dz_type; // 1: Expedition, 2: Tutorial, 3: Task, 4: Mission, 5: Quest -- sent back in reply
|
||||
/*012*/ uint32 unknown_id2; // possibly an id based on dz type, for expeditions this was same as dz_id (zone|instance) but task dz was different
|
||||
/*016*/ char description[1]; // variable length, null terminated, max 0x80 (128)
|
||||
/*000*/ char leader_name[1]; // variable length, null terminated, max 0x40 (64)
|
||||
};
|
||||
|
||||
struct DynamicZoneChooseZone_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 count;
|
||||
/*008*/ DynamicZoneChooseZoneEntry_Struct choices[0];
|
||||
};
|
||||
|
||||
struct DynamicZoneChooseZoneReply_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ uint32 unknown_id1;
|
||||
/*012*/ uint16 dz_zone_id;
|
||||
/*014*/ uint16 dz_instance_id;
|
||||
/*016*/ uint32 dz_type; // 1: Expedition, 2: Tutorial, 3: Task, 4: Mission, 5: Quest
|
||||
/*020*/ uint32 unknown_id2;
|
||||
/*024*/ uint32 unknown024;
|
||||
/*028*/ uint32 unknown028; // always same as unknown040
|
||||
/*032*/ uint32 unknown032;
|
||||
/*036*/ uint32 unknown036;
|
||||
/*040*/ uint32 unknown040; // always same as unknown028
|
||||
/*044*/ uint32 unknown044;
|
||||
};
|
||||
|
||||
struct LFGuild_SearchPlayer_Struct
|
||||
|
||||
@ -613,14 +613,48 @@ namespace UF
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzChooseZone)
|
||||
{
|
||||
SETUP_VAR_ENCODE(DynamicZoneChooseZone_Struct);
|
||||
|
||||
SerializeBuffer buf;
|
||||
buf.WriteUInt32(emu->client_id);
|
||||
buf.WriteUInt32(emu->count);
|
||||
|
||||
for (uint32 i = 0; i < emu->count; ++i)
|
||||
{
|
||||
buf.WriteUInt16(emu->choices[i].dz_zone_id);
|
||||
buf.WriteUInt16(emu->choices[i].dz_instance_id);
|
||||
buf.WriteUInt32(emu->choices[i].unknown_id1);
|
||||
buf.WriteUInt32(emu->choices[i].dz_type);
|
||||
buf.WriteUInt32(emu->choices[i].unknown_id2);
|
||||
buf.WriteString(emu->choices[i].description);
|
||||
buf.WriteString(emu->choices[i].leader_name);
|
||||
}
|
||||
|
||||
__packet->size = buf.size();
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
memcpy(__packet->pBuffer, buf.buffer(), __packet->size);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzCompass)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionCompass_Struct);
|
||||
ALLOC_VAR_ENCODE(structs::ExpeditionCompass_Struct, sizeof(structs::ExpeditionInfo_Struct) + sizeof(structs::ExpeditionCompassEntry_Struct) * emu->count);
|
||||
SETUP_VAR_ENCODE(DynamicZoneCompass_Struct);
|
||||
ALLOC_VAR_ENCODE(structs::DynamicZoneCompass_Struct,
|
||||
sizeof(structs::DynamicZoneCompass_Struct) +
|
||||
sizeof(structs::DynamicZoneCompassEntry_Struct) * emu->count
|
||||
);
|
||||
|
||||
OUT(client_id);
|
||||
OUT(count);
|
||||
|
||||
for (uint32 i = 0; i < emu->count; ++i)
|
||||
{
|
||||
OUT(entries[i].dz_zone_id);
|
||||
OUT(entries[i].dz_instance_id);
|
||||
OUT(entries[i].dz_type);
|
||||
OUT(entries[i].x);
|
||||
OUT(entries[i].y);
|
||||
OUT(entries[i].z);
|
||||
@ -644,81 +678,60 @@ namespace UF
|
||||
ENCODE_LENGTH_EXACT(ExpeditionInfo_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionInfo_Struct, structs::ExpeditionInfo_Struct);
|
||||
|
||||
OUT(client_id);
|
||||
OUT(assigned);
|
||||
OUT(max_players);
|
||||
eq->unknown004 = 785316192;
|
||||
eq->unknown008 = 435601;
|
||||
strcpy(eq->expedition_name, emu->expedition_name);
|
||||
strcpy(eq->leader_name, emu->leader_name);
|
||||
strn0cpy(eq->expedition_name, emu->expedition_name, sizeof(eq->expedition_name));
|
||||
strn0cpy(eq->leader_name, emu->leader_name, sizeof(eq->leader_name));
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzExpeditionList)
|
||||
ENCODE(OP_DzExpeditionInvite)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionLockoutList_Struct);
|
||||
ENCODE_LENGTH_EXACT(ExpeditionInvite_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionInvite_Struct, structs::ExpeditionInvite_Struct);
|
||||
|
||||
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
||||
uint32 client_id = 0;
|
||||
uint8 null_term = 0;
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&emu->count, sizeof(uint32));
|
||||
OUT(client_id);
|
||||
strn0cpy(eq->inviter_name, emu->inviter_name, sizeof(eq->inviter_name));
|
||||
strn0cpy(eq->expedition_name, emu->expedition_name, sizeof(eq->expedition_name));
|
||||
OUT(swapping);
|
||||
strn0cpy(eq->swap_name, emu->swap_name, sizeof(eq->swap_name));
|
||||
OUT(dz_zone_id);
|
||||
OUT(dz_instance_id);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzExpeditionLockoutTimers)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionLockoutTimers_Struct);
|
||||
|
||||
SerializeBuffer buf;
|
||||
buf.WriteUInt32(emu->client_id);
|
||||
buf.WriteUInt32(emu->count);
|
||||
for (uint32 i = 0; i < emu->count; ++i)
|
||||
{
|
||||
ss.write(emu->entries[i].expedition, strlen(emu->entries[i].expedition));
|
||||
ss.write((const char*)&null_term, sizeof(char));
|
||||
ss.write((const char*)&emu->entries[i].time_left, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write(emu->entries[i].expedition_event, strlen(emu->entries[i].expedition_event));
|
||||
ss.write((const char*)&null_term, sizeof(char));
|
||||
buf.WriteString(emu->timers[i].expedition_name);
|
||||
buf.WriteUInt32(emu->timers[i].seconds_remaining);
|
||||
buf.WriteInt32(emu->timers[i].event_type);
|
||||
buf.WriteString(emu->timers[i].event_name);
|
||||
}
|
||||
|
||||
__packet->size = ss.str().length();
|
||||
__packet->size = buf.size();
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size);
|
||||
memcpy(__packet->pBuffer, buf.buffer(), __packet->size);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzJoinExpeditionConfirm)
|
||||
ENCODE(OP_DzSetLeaderName)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(ExpeditionJoinPrompt_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionJoinPrompt_Struct, structs::ExpeditionJoinPrompt_Struct);
|
||||
ENCODE_LENGTH_EXACT(ExpeditionSetLeaderName_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionSetLeaderName_Struct, structs::ExpeditionSetLeaderName_Struct);
|
||||
|
||||
strcpy(eq->expedition_name, emu->expedition_name);
|
||||
strcpy(eq->player_name, emu->player_name);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzLeaderStatus)
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionLeaderSet_Struct);
|
||||
|
||||
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
||||
uint32 client_id = 0;
|
||||
uint8 null_term = 0;
|
||||
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write(emu->leader_name, strlen(emu->leader_name));
|
||||
ss.write((const char*)&null_term, sizeof(char));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));//0xffffffff
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&client_id, sizeof(uint32));//1
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
|
||||
__packet->size = ss.str().length();
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size);
|
||||
OUT(client_id);
|
||||
strn0cpy(eq->leader_name, emu->leader_name, sizeof(eq->leader_name));
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
@ -727,26 +740,43 @@ namespace UF
|
||||
{
|
||||
SETUP_VAR_ENCODE(ExpeditionMemberList_Struct);
|
||||
|
||||
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
||||
|
||||
uint32 client_id = 0;
|
||||
uint8 null_term = 0;
|
||||
ss.write((const char*)&client_id, sizeof(uint32));
|
||||
ss.write((const char*)&emu->count, sizeof(uint32));
|
||||
for (uint32 i = 0; i < emu->count; ++i)
|
||||
SerializeBuffer buf;
|
||||
buf.WriteUInt32(emu->client_id);
|
||||
buf.WriteUInt32(emu->member_count);
|
||||
for (uint32 i = 0; i < emu->member_count; ++i)
|
||||
{
|
||||
ss.write(emu->entries[i].name, strlen(emu->entries[i].name));
|
||||
ss.write((const char*)&null_term, sizeof(char));
|
||||
ss.write((const char*)&emu->entries[i].status, sizeof(char));
|
||||
buf.WriteString(emu->members[i].name);
|
||||
buf.WriteUInt8(emu->members[i].expedition_status);
|
||||
}
|
||||
|
||||
__packet->size = ss.str().length();
|
||||
__packet->size = buf.size();
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size);
|
||||
memcpy(__packet->pBuffer, buf.buffer(), __packet->size);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzMemberListName)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(ExpeditionMemberListName_Struct);
|
||||
SETUP_DIRECT_ENCODE(ExpeditionMemberListName_Struct, structs::ExpeditionMemberListName_Struct);
|
||||
|
||||
OUT(client_id);
|
||||
OUT(add_name);
|
||||
strn0cpy(eq->name, emu->name, sizeof(eq->name));
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DzMemberListStatus)
|
||||
{
|
||||
auto emu = reinterpret_cast<ExpeditionMemberList_Struct*>((*p)->pBuffer);
|
||||
if (emu->member_count == 1)
|
||||
{
|
||||
ENCODE_FORWARD(OP_DzMemberList);
|
||||
}
|
||||
}
|
||||
|
||||
ENCODE(OP_Emote)
|
||||
{
|
||||
EQApplicationPacket *in = *p;
|
||||
@ -1577,6 +1607,7 @@ namespace UF
|
||||
OUT(FastRegenHP);
|
||||
OUT(FastRegenMana);
|
||||
OUT(FastRegenEndurance);
|
||||
OUT(underworld_teleport_index);
|
||||
|
||||
eq->FogDensity = emu->fog_density;
|
||||
|
||||
@ -3314,6 +3345,84 @@ namespace UF
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzAddPlayer)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionCommand_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionCommand_Struct, structs::ExpeditionCommand_Struct);
|
||||
|
||||
strn0cpy(emu->name, eq->name, sizeof(emu->name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzChooseZoneReply)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::DynamicZoneChooseZoneReply_Struct);
|
||||
SETUP_DIRECT_DECODE(DynamicZoneChooseZoneReply_Struct, structs::DynamicZoneChooseZoneReply_Struct);
|
||||
|
||||
IN(unknown000);
|
||||
IN(unknown004);
|
||||
IN(unknown008);
|
||||
IN(unknown_id1);
|
||||
IN(dz_zone_id);
|
||||
IN(dz_instance_id);
|
||||
IN(dz_type);
|
||||
IN(unknown_id2);
|
||||
IN(unknown028);
|
||||
IN(unknown032);
|
||||
IN(unknown036);
|
||||
IN(unknown040);
|
||||
IN(unknown044);
|
||||
IN(unknown048);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzExpeditionInviteResponse)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionInviteResponse_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionInviteResponse_Struct, structs::ExpeditionInviteResponse_Struct);
|
||||
|
||||
IN(dz_zone_id);
|
||||
IN(dz_instance_id);
|
||||
IN(accepted);
|
||||
IN(swapping);
|
||||
strn0cpy(emu->swap_name, eq->swap_name, sizeof(emu->swap_name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzMakeLeader)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionCommand_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionCommand_Struct, structs::ExpeditionCommand_Struct);
|
||||
|
||||
strn0cpy(emu->name, eq->name, sizeof(emu->name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzRemovePlayer)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionCommand_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionCommand_Struct, structs::ExpeditionCommand_Struct);
|
||||
|
||||
strn0cpy(emu->name, eq->name, sizeof(emu->name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_DzSwapPlayer)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::ExpeditionCommandSwap_Struct);
|
||||
SETUP_DIRECT_DECODE(ExpeditionCommandSwap_Struct, structs::ExpeditionCommandSwap_Struct);
|
||||
|
||||
strn0cpy(emu->add_player_name, eq->add_player_name, sizeof(emu->add_player_name));
|
||||
strn0cpy(emu->rem_player_name, eq->rem_player_name, sizeof(emu->rem_player_name));
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_Emote)
|
||||
{
|
||||
unsigned char *__eq_buffer = __packet->pBuffer;
|
||||
|
||||
@ -38,13 +38,16 @@ E(OP_Damage)
|
||||
E(OP_DeleteCharge)
|
||||
E(OP_DeleteItem)
|
||||
E(OP_DisciplineUpdate)
|
||||
E(OP_DzChooseZone)
|
||||
E(OP_DzCompass)
|
||||
E(OP_DzExpeditionEndsWarning)
|
||||
E(OP_DzExpeditionInfo)
|
||||
E(OP_DzExpeditionList)
|
||||
E(OP_DzJoinExpeditionConfirm)
|
||||
E(OP_DzLeaderStatus)
|
||||
E(OP_DzExpeditionInvite)
|
||||
E(OP_DzExpeditionLockoutTimers)
|
||||
E(OP_DzMemberList)
|
||||
E(OP_DzMemberListName)
|
||||
E(OP_DzMemberListStatus)
|
||||
E(OP_DzSetLeaderName)
|
||||
E(OP_Emote)
|
||||
E(OP_ExpansionInfo)
|
||||
E(OP_FormattedMessage)
|
||||
@ -120,6 +123,12 @@ D(OP_ConsiderCorpse)
|
||||
D(OP_Consume)
|
||||
D(OP_Damage)
|
||||
D(OP_DeleteItem)
|
||||
D(OP_DzAddPlayer)
|
||||
D(OP_DzChooseZoneReply)
|
||||
D(OP_DzExpeditionInviteResponse)
|
||||
D(OP_DzMakeLeader)
|
||||
D(OP_DzRemovePlayer)
|
||||
D(OP_DzSwapPlayer)
|
||||
D(OP_Emote)
|
||||
D(OP_EnvDamage)
|
||||
D(OP_FaceChange)
|
||||
|
||||
@ -444,7 +444,11 @@ struct NewZone_Struct {
|
||||
/*0848*/ int32 unknown848;
|
||||
/*0852*/ uint16 zone_id;
|
||||
/*0854*/ uint16 zone_instance;
|
||||
/*0856*/ char unknown856[20];
|
||||
/*0856*/ uint32 scriptNPCReceivedanItem;
|
||||
/*0860*/ uint32 bCheck; // padded bool
|
||||
/*0864*/ uint32 scriptIDSomething;
|
||||
/*0868*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, -1 affects some collisions
|
||||
/*0872*/ uint32 scriptIDSomething3;
|
||||
/*0876*/ uint32 SuspendBuffs;
|
||||
/*0880*/ uint32 unknown880; //seen 50
|
||||
/*0884*/ uint32 unknown884; //seen 10
|
||||
@ -4246,52 +4250,160 @@ struct VeteranReward
|
||||
/*012*/ VeteranRewardItem items[8];
|
||||
};
|
||||
|
||||
struct ExpeditionEntryHeader_Struct
|
||||
|
||||
struct ExpeditionInvite_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id; // unique character id
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ char inviter_name[64];
|
||||
/*072*/ char expedition_name[128];
|
||||
/*200*/ uint8 swapping; // 0: adding 1: swapping
|
||||
/*201*/ char swap_name[64]; // if swapping, swap name being removed
|
||||
/*265*/ uint8 padding[3];
|
||||
/*268*/ uint16 dz_zone_id; // dz_id zone/instance pair, sent back in reply
|
||||
/*270*/ uint16 dz_instance_id;
|
||||
};
|
||||
|
||||
struct ExpeditionInviteResponse_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000;
|
||||
/*000*/ uint32 number_of_entries;
|
||||
};
|
||||
|
||||
struct ExpeditionJoinPrompt_Struct
|
||||
{
|
||||
/*000*/ uint32 clientid;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ char player_name[64];
|
||||
/*072*/ char expedition_name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionExpireWarning
|
||||
{
|
||||
/*000*/ uint32 clientid;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ uint32 minutes_remaining;
|
||||
/*008*/ uint16 dz_zone_id; // dz_id pair sent in invite
|
||||
/*010*/ uint16 dz_instance_id;
|
||||
/*012*/ uint8 accepted; // 0: declined 1: accepted
|
||||
/*013*/ uint8 swapping; // 0: adding 1: swapping (sent in invite)
|
||||
/*014*/ char swap_name[64]; // swap name sent in invite
|
||||
/*078*/ uint8 unknown078; // padding garbage?
|
||||
/*079*/ uint8 unknown079; // padding garbage?
|
||||
};
|
||||
|
||||
struct ExpeditionInfo_Struct
|
||||
{
|
||||
/*000*/ uint32 clientid;
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ uint32 unknown008;
|
||||
/*008*/ uint32 assigned; // padded bool
|
||||
/*012*/ uint32 max_players;
|
||||
/*016*/ char expedition_name[128];
|
||||
/*142*/ char leader_name[64];
|
||||
/*016*/ char expedition_name[128];
|
||||
/*144*/ char leader_name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionCompassEntry_Struct
|
||||
struct ExpeditionMemberEntry_Struct
|
||||
{
|
||||
/*000*/ float unknown000; //seen *((uint32*)) = 1584791871
|
||||
/*004*/ uint32 enabled; //guess
|
||||
/*008*/ uint32 unknown008; //seen 1019
|
||||
/*000*/ char name[1]; // variable length, null terminated, max 0x40 (64)
|
||||
/*000*/ uint8 expedition_status; // 0: unknown 1: Online, 2: Offline, 3: In Dynamic Zone, 4: Link Dead
|
||||
};
|
||||
|
||||
struct ExpeditionMemberList_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 member_count; // number of players in window
|
||||
/*008*/ ExpeditionMemberEntry_Struct members[0]; // variable length
|
||||
};
|
||||
|
||||
struct ExpeditionMemberListName_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ uint32 add_name; // padded bool, 0: remove name, 1: add name with unknown status
|
||||
/*012*/ char name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionLockoutTimerEntry_Struct
|
||||
{
|
||||
/*000*/ char expedition_name[1]; // variable length, null terminated, max 0x80 (128)
|
||||
/*000*/ uint32 seconds_remaining;
|
||||
/*000*/ int32 event_type; // seen -1 (0xffffffff) for replay timers and 1 for event timers
|
||||
/*000*/ char event_name[1]; // variable length, null terminated, max 0x100 (256)
|
||||
};
|
||||
|
||||
struct ExpeditionLockoutTimers_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 count;
|
||||
/*008*/ ExpeditionLockoutTimerEntry_Struct timers[0];
|
||||
};
|
||||
|
||||
struct ExpeditionSetLeaderName_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ char leader_name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionCommand_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ char name[64];
|
||||
};
|
||||
|
||||
struct ExpeditionCommandSwap_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ char add_player_name[64]; // swap to (player must confirm)
|
||||
/*072*/ char rem_player_name[64]; // swap from
|
||||
};
|
||||
|
||||
struct ExpeditionExpireWarning
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 unknown004;
|
||||
/*008*/ uint32 minutes_remaining;
|
||||
};
|
||||
|
||||
struct DynamicZoneCompassEntry_Struct
|
||||
{
|
||||
/*000*/ uint16 dz_zone_id; // target dz id pair
|
||||
/*002*/ uint16 dz_instance_id;
|
||||
/*004*/ uint32 dz_type; // 1: Expedition, 2: Tutorial (purple), 3: Task, 4: Mission, 5: Quest (green)
|
||||
/*008*/ uint32 unknown008;
|
||||
/*012*/ float y;
|
||||
/*016*/ float x;
|
||||
/*020*/ float z;
|
||||
};
|
||||
|
||||
struct ExpeditionCompass_Struct
|
||||
struct DynamicZoneCompass_Struct
|
||||
{
|
||||
/*000*/ uint32 clientid;
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 count;
|
||||
/*008*/ ExpeditionCompassEntry_Struct entries[0];
|
||||
/*008*/ DynamicZoneCompassEntry_Struct entries[0];
|
||||
};
|
||||
|
||||
struct DynamicZoneChooseZoneEntry_Struct
|
||||
{
|
||||
/*000*/ uint16 dz_zone_id; // dz_id pair
|
||||
/*002*/ uint16 dz_instance_id;
|
||||
/*004*/ uint32 unknown_id1; // sent back in reply
|
||||
/*008*/ uint32 dz_type; // 1: Expedition, 2: Tutorial, 3: Task, 4: Mission, 5: Quest -- sent back in reply
|
||||
/*012*/ uint32 unknown_id2; // possibly an id based on dz type, for expeditions this was same as dz_id (zone|instance) but task dz was different
|
||||
/*016*/ char description[1]; // variable length, null terminated, max 0x80 (128)
|
||||
/*000*/ char leader_name[1]; // variable length, null terminated, max 0x40 (64)
|
||||
};
|
||||
|
||||
struct DynamicZoneChooseZone_Struct
|
||||
{
|
||||
/*000*/ uint32 client_id;
|
||||
/*004*/ uint32 count;
|
||||
/*008*/ DynamicZoneChooseZoneEntry_Struct choices[0];
|
||||
};
|
||||
|
||||
struct DynamicZoneChooseZoneReply_Struct
|
||||
{
|
||||
/*000*/ uint32 unknown000; // ff ff ff ff
|
||||
/*004*/ uint32 unknown004; // seen 69 00 00 00
|
||||
/*008*/ uint32 unknown008; // ff ff ff ff
|
||||
/*012*/ uint32 unknown_id1; // from choose zone entry message
|
||||
/*016*/ uint16 dz_zone_id; // dz_id pair
|
||||
/*018*/ uint16 dz_instance_id;
|
||||
/*020*/ uint32 dz_type; // 1: Expedition, 2: Tutorial, 3: Task, 4: Mission, 5: Quest
|
||||
/*024*/ uint32 unknown_id2; // from choose zone entry message
|
||||
/*028*/ uint32 unknown028; // 00 00 00 00
|
||||
/*032*/ uint32 unknown032; // always same as unknown044
|
||||
/*036*/ uint32 unknown036;
|
||||
/*040*/ uint32 unknown040;
|
||||
/*044*/ uint32 unknown044; // always same as unknown032
|
||||
/*048*/ uint32 unknown048; // seen 01 00 00 00 and 02 00 00 00
|
||||
};
|
||||
|
||||
struct AltCurrencySelectItem_Struct {
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
|
||||
|
||||
RULE_CATEGORY(Character)
|
||||
RULE_INT(Character, MaxLevel, 65, "Sets the highest level attainable by experience for players")
|
||||
RULE_INT(Character, MaxLevel, 65, "Sets the highest level for players that can be reached through experience")
|
||||
RULE_BOOL(Character, PerCharacterQglobalMaxLevel, false, "Check for qglobal 'CharMaxLevel' character qglobal (Type 5, \"\"), if player tries to level beyond that point, it will not go beyond that level")
|
||||
RULE_BOOL(Character, PerCharacterBucketMaxLevel, false, "Check for data bucket 'CharMaxLevel', if player tries to level beyond that point, it will not go beyond that level")
|
||||
RULE_INT(Character, MaxExpLevel, 0, "Defines the maximum level that can be reached through experience")
|
||||
@ -57,8 +57,8 @@ RULE_REAL(Character, ExpMultiplier, 0.5, "If greater than 0, the experience gain
|
||||
RULE_REAL(Character, AAExpMultiplier, 0.5, "If greater than 0, the AA experience gained is multiplied by this value. ")
|
||||
RULE_REAL(Character, GroupExpMultiplier, 0.5, "The experience in a group is multiplied by this value in addition to the group multiplier. The group multiplier is: 2 members=x 1.2, 3=x1.4, 4=x1.6, 5=x1.8, 6=x2.16")
|
||||
RULE_REAL(Character, RaidExpMultiplier, 0.2, "The experience gained in raids is multiplied by (1-RaidExpMultiplier) ")
|
||||
RULE_BOOL(Character, UseXPConScaling, true, "When activated, the experience is modified depending on the difference between player level and NPC level. The settings Green/LightBlue/Blue//White/Yellow and RedModifier are used")
|
||||
RULE_INT(Character, ShowExpValues, 0, "Show expirience values. 0=normal, 1=show raw experience values, 2=show raw experience values and percent")
|
||||
RULE_BOOL(Character, UseXPConScaling, true, "When activated, the experience is modified depending on the difference between player level and NPC level. The values from the rules GreenModifier to RedModifier are used")
|
||||
RULE_INT(Character, ShowExpValues, 0, "Show experience values. 0=normal, 1=show raw experience values, 2=show raw experience values and percent")
|
||||
RULE_INT(Character, GreenModifier, 20, "The experience obtained for green con mobs is multiplied by value/100")
|
||||
RULE_INT(Character, LightBlueModifier, 40, "The experience obtained for light-blue con mobs is multiplied by value/100")
|
||||
RULE_INT(Character, BlueModifier, 90, "The experience obtained for blue con mobs is multiplied by value/100")
|
||||
@ -80,7 +80,7 @@ RULE_INT(Character, ItemAccuracyCap, 150, "Limit on accuracy granted by items")
|
||||
RULE_INT(Character, ItemAvoidanceCap, 100, "Limit on avoidance granted by items")
|
||||
RULE_INT(Character, ItemCombatEffectsCap, 100, "Limit on combat effects granted by items")
|
||||
RULE_INT(Character, ItemShieldingCap, 35, "Limit on shielding granted by items")
|
||||
RULE_INT(Character, ItemSpellShieldingCap, 35, "Limit on spell shieldung granted by items")
|
||||
RULE_INT(Character, ItemSpellShieldingCap, 35, "Limit on spell shielding granted by items")
|
||||
RULE_INT(Character, ItemDoTShieldingCap, 35, "Limit on DoT shielding granted by items")
|
||||
RULE_INT(Character, ItemStunResistCap, 35, "Limit on resistance granted by items")
|
||||
RULE_INT(Character, ItemStrikethroughCap, 35, "Limit on strikethrough granted by items")
|
||||
@ -91,7 +91,7 @@ RULE_INT(Character, ItemClairvoyanceCap, 250, "Limit on clairvoyance granted by
|
||||
RULE_INT(Character, ItemDSMitigationCap, 50, "Limit on damageshield mitigation granted by items")
|
||||
RULE_INT(Character, ItemEnduranceRegenCap, 15, "Limit on endurance regeneration granted by items")
|
||||
RULE_INT(Character, ItemExtraDmgCap, 150, "Cap for bonuses to melee skills like Bash, Frenzy, etc.")
|
||||
RULE_INT(Character, HasteCap, 100, "Haste cap for non-v3(overhaste) haste")
|
||||
RULE_INT(Character, HasteCap, 100, "Haste cap for non-v3(over haste) haste")
|
||||
RULE_INT(Character, SkillUpModifier, 100, "The probability for a skill-up is multiplied by value/100")
|
||||
RULE_BOOL(Character, SharedBankPlat, false, "Shared bank platinum. Off by default to prevent duplication")
|
||||
RULE_BOOL(Character, BindAnywhere, false, "Allows players to bind their soul anywhere in the world")
|
||||
@ -112,14 +112,14 @@ RULE_INT(Character, RespawnFromHoverTimer, 300, "Respawn Window countdown timer,
|
||||
RULE_BOOL(Character, UseNewStatsWindow, true, "Setting whether the new Stats window, which displays all information, should be used")
|
||||
RULE_BOOL(Character, ItemCastsUseFocus, false, "If true, this allows item clickies to use focuses that have limited maximum levels on them")
|
||||
RULE_INT(Character, MinStatusForNoDropExemptions, 80, "This allows status x and higher to trade no drop items")
|
||||
RULE_INT(Character, SkillCapMaxLevel, 75, "Sets the Maximum Level used for Skill Caps (from skill_caps table). -1 makes it use MaxLevel rule value. It is set to 75 because PEQ only has skillcaps up to that level, and grabbing the players' skill past 75 will return 0, breaking all skills past that level. This helps servers with obsurd level caps (75+ level cap) function without any modifications")
|
||||
RULE_INT(Character, SkillCapMaxLevel, 75, "Sets the Maximum Level used for Skill Caps (from skill_caps table). -1 makes it use MaxLevel rule value. It is set to 75 because PEQ only has skill caps up to that level, and grabbing the players' skill past 75 will return 0, breaking all skills past that level. This helps servers with obsurd level caps (75+ level cap) function without any modifications")
|
||||
RULE_INT(Character, StatCap, 0, "If StatCap > 0 then this value is used. If it is 0, the value of the following code is used: If Level < 61: 255. If Level >= 61 and the client SoF or newer: 255 + 5 x (level -60). If the client is older than SoF and the level < 71 then: 255 + x (level-60). In all other cases: 330.")
|
||||
RULE_BOOL(Character, CheckCursorEmptyWhenLooting, true, "If true, a player cannot loot a corpse (player or NPC) with an item on their cursor")
|
||||
RULE_BOOL(Character, MaintainIntoxicationAcrossZones, true, "If true, alcohol effects are maintained across zoning and logging out/in")
|
||||
RULE_BOOL(Character, EnableDiscoveredItems, true, "If enabled, it enables EVENT_DISCOVER_ITEM and also saves character names and timestamps for the first time an item is discovered")
|
||||
RULE_BOOL(Character, EnableXTargetting, true, "Enable Extended Targeting Window, for users with UF and later clients")
|
||||
RULE_BOOL(Character, EnableAggroMeter, true, "Enable Aggro Meter, for users with RoF and later clients")
|
||||
RULE_BOOL(Character, KeepLevelOverMax, false, "Don't delevel a character that has somehow gone over the level cap")
|
||||
RULE_BOOL(Character, KeepLevelOverMax, false, "Don't de-level a character that has somehow gone over the level cap")
|
||||
RULE_INT(Character, FoodLossPerUpdate, 32, "How much food/water you lose per stamina update")
|
||||
RULE_BOOL(Character, EnableHungerPenalties, false, "Being hungry/thirsty has negative effects -- it does appear normal live servers do not have penalties")
|
||||
RULE_BOOL(Character, EnableFoodRequirement, true, "If disabled, food is no longer required")
|
||||
@ -129,16 +129,16 @@ RULE_INT(Character, BaseRunSpeedCap, 158, "Base Run Speed Cap, on live it's 158%
|
||||
RULE_INT(Character, OrnamentationAugmentType, 20, "Ornamentation Augment Type")
|
||||
RULE_REAL(Character, EnvironmentDamageMulipliter, 1, "Multiplier for environmental damage like fall damage.")
|
||||
RULE_BOOL(Character, UnmemSpellsOnDeath, true, "Setting whether at death all memorized Spells are forgotten")
|
||||
RULE_INT(Character, TradeskillUpAlchemy, 2, "Alchemy skillup rate adjust. Lower is faster")
|
||||
RULE_INT(Character, TradeskillUpBaking, 2, "Baking skillup rate adjust. Lower is faster")
|
||||
RULE_INT(Character, TradeskillUpBlacksmithing, 2, "Blacksmithing skillup rate adjust. Lower is faster")
|
||||
RULE_INT(Character, TradeskillUpBrewing, 3, "Brewing skillup rate adjust. Lower is faster")
|
||||
RULE_INT(Character, TradeskillUpFletching, 2, "Fletching skillup rate adjust. Lower is faster")
|
||||
RULE_INT(Character, TradeskillUpJewelcrafting, 2, "Jewelcrafting skillup rate adjust. Lower is faster")
|
||||
RULE_INT(Character, TradeskillUpMakePoison, 2, "Make Poison skillup rate adjust. Lower is faster")
|
||||
RULE_INT(Character, TradeskillUpPottery, 4, "Pottery skillup rate adjust. Lower is faster")
|
||||
RULE_INT(Character, TradeskillUpResearch, 1, "Research skillup rate adjust. Lower is faster")
|
||||
RULE_INT(Character, TradeskillUpTinkering, 2, "Tinkering skillup rate adjust. Lower is faster")
|
||||
RULE_INT(Character, TradeskillUpAlchemy, 2, "Alchemy skillup rate adjustment. Lower is faster")
|
||||
RULE_INT(Character, TradeskillUpBaking, 2, "Baking skillup rate adjustment. Lower is faster")
|
||||
RULE_INT(Character, TradeskillUpBlacksmithing, 2, "Blacksmithing skillup rate adjustment. Lower is faster")
|
||||
RULE_INT(Character, TradeskillUpBrewing, 3, "Brewing skillup rate adjustment. Lower is faster")
|
||||
RULE_INT(Character, TradeskillUpFletching, 2, "Fletching skillup rate adjustment. Lower is faster")
|
||||
RULE_INT(Character, TradeskillUpJewelcrafting, 2, "Jewelcrafting skillup rate adjustment. Lower is faster")
|
||||
RULE_INT(Character, TradeskillUpMakePoison, 2, "Make Poison skillup rate adjustment. Lower is faster")
|
||||
RULE_INT(Character, TradeskillUpPottery, 4, "Pottery skillup rate adjustment. Lower is faster")
|
||||
RULE_INT(Character, TradeskillUpResearch, 1, "Research skillup rate adjustment. Lower is faster")
|
||||
RULE_INT(Character, TradeskillUpTinkering, 2, "Tinkering skillup rate adjustment. Lower is faster")
|
||||
RULE_BOOL(Character, MarqueeHPUpdates, false, "Will show health percentage in center of screen if health lesser than 100%")
|
||||
RULE_INT(Character, IksarCommonTongue, 95, "Starting value for Common Tongue for Iksars")
|
||||
RULE_INT(Character, OgreCommonTongue, 95, "Starting value for Common Tongue for Ogres")
|
||||
@ -147,7 +147,7 @@ RULE_BOOL(Character, ActiveInvSnapshots, false, "Takes a periodic snapshot of in
|
||||
RULE_INT(Character, InvSnapshotMinIntervalM, 180, "Minimum time between inventory snapshots (minutes)")
|
||||
RULE_INT(Character, InvSnapshotMinRetryM, 30, "Time to re-attempt an inventory snapshot after a failure (minutes)")
|
||||
RULE_INT(Character, InvSnapshotHistoryD, 30, "Time to keep snapshot entries (days)")
|
||||
RULE_BOOL(Character, RestrictSpellScribing, false, "Setting whether to testricts spell scribing to allowable races/classes of spell scroll")
|
||||
RULE_BOOL(Character, RestrictSpellScribing, false, "Setting whether to restrict spell scribing to allowable races/classes of spell scroll")
|
||||
RULE_BOOL(Character, UseStackablePickPocketing, true, "Allows stackable pickpocketed items to stack instead of only being allowed in empty inventory slots")
|
||||
RULE_BOOL(Character, EnableAvoidanceCap, false, "Setting whether the avoidance cap should be activated")
|
||||
RULE_INT(Character, AvoidanceCap, 750, "750 Is a pretty good value, seen people dodge all attacks beyond 1,000 Avoidance")
|
||||
@ -197,7 +197,7 @@ RULE_INT(Skills, MaxTrainSpecializations, 50, "Maximum level a GM trainer will t
|
||||
RULE_INT(Skills, SwimmingStartValue, 100, "Start value of swimming skill")
|
||||
RULE_BOOL(Skills, TrainSenseHeading, false, "Switch whether SenseHeading is trained by use")
|
||||
RULE_INT(Skills, SenseHeadingStartValue, 200, "Start value of sense heading skill")
|
||||
RULE_BOOL(Skills, SelfLanguageLearning, true, "Enabling self learning of languages")
|
||||
RULE_BOOL(Skills, SelfLanguageLearning, true, "Enabling self-learning of languages")
|
||||
RULE_BOOL(Skills, RequireTomeHandin, false, "Disable click-to-learn and force hand in to Guild Master")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
@ -246,6 +246,7 @@ RULE_BOOL(World, MaxClientsSimplifiedLogic, false, "New logic that only uses Exe
|
||||
RULE_INT (World, TellQueueSize, 20, "Maximum tell queue size")
|
||||
RULE_BOOL(World, StartZoneSameAsBindOnCreation, true, "Should the start zone always be the same location as your bind?")
|
||||
RULE_BOOL(World, EnforceCharacterLimitAtLogin, false, "Enforce the limit for characters that are online at login")
|
||||
RULE_BOOL(World, EnableDevTools, true, "Enable or Disable the Developer Tools globally (Most of the time you want this enabled)")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Zone)
|
||||
@ -339,7 +340,7 @@ RULE_BOOL(Spells, ReflectMessagesClose, true, "True (Live functionality) is for
|
||||
RULE_INT(Spells, VirusSpreadDistance, 30, "The distance a viral spell will jump to its next victim")
|
||||
RULE_BOOL(Spells, LiveLikeFocusEffects, true, "Determines whether specific healing, dmg and mana reduction focuses are randomized")
|
||||
RULE_INT(Spells, BaseImmunityLevel, 55, "The level that targets start to be immune to stun, fear and mez spells with a maximum level of 0")
|
||||
RULE_BOOL(Spells, NPCIgnoreBaseImmunity, true, "Whether or not NPCget to ignore the BaseImmunityLevel for their spells")
|
||||
RULE_BOOL(Spells, NPCIgnoreBaseImmunity, true, "Whether or not NPC get to ignore the BaseImmunityLevel for their spells")
|
||||
RULE_REAL(Spells, AvgSpellProcsPerMinute, 6.0, "Adjust rate for sympathetic spell procs")
|
||||
RULE_INT(Spells, ResistFalloff, 67, "Maximum that level that will adjust our resist chance based on level modifiers")
|
||||
RULE_INT(Spells, CharismaEffectiveness, 10, "Determines how much resist modification charisma applies to charm/pacify checks. Default 10 CHA = -1 resist mod")
|
||||
@ -397,7 +398,7 @@ RULE_INT(Combat, PetBaseCritChance, 0, "Pet base crit chance")
|
||||
RULE_INT(Combat, NPCBashKickLevel, 6, "The level that NPCcan KICK/BASH")
|
||||
RULE_INT(Combat, NPCBashKickStunChance, 15, "Percent chance that a bash/kick will stun")
|
||||
RULE_INT(Combat, MeleeCritDifficulty, 8900, "Value against which is rolled to check if a melee crit is triggered. Lower is easier")
|
||||
RULE_INT(Combat, ArcheryCritDifficulty, 3400, "Value against which is rolled to check if a archery crit is triggered. Lower is easier")
|
||||
RULE_INT(Combat, ArcheryCritDifficulty, 3400, "Value against which is rolled to check if an archery crit is triggered. Lower is easier")
|
||||
RULE_INT(Combat, ThrowingCritDifficulty, 1100, "Value against which is rolled to check if a throwing crit is triggered. Lower is easier")
|
||||
RULE_BOOL(Combat, NPCCanCrit, false, "Setting whether an NPC can land critical hits")
|
||||
RULE_BOOL(Combat, UseIntervalAC, true, "Switch whether bonuses, armour class, multipliers, classes and caps should be considered in the calculation of damage values")
|
||||
@ -416,7 +417,7 @@ RULE_REAL(Combat, BaseProcChance, 0.035, "Base chance for procs")
|
||||
RULE_REAL(Combat, ProcDexDivideBy, 11000, "Divisor for the probability of a proc increased by dexterity")
|
||||
RULE_BOOL(Combat, AdjustSpecialProcPerMinute, true, "Set PPM for special abilities like HeadShot (Live does this as of 4-14)")
|
||||
RULE_REAL(Combat, AvgSpecialProcsPerMinute, 2.0, "Unclear what best value is atm")
|
||||
RULE_REAL(Combat, BaseHitChance, 69.0, "Base chance to hiz")
|
||||
RULE_REAL(Combat, BaseHitChance, 69.0, "Base chance to hit")
|
||||
RULE_REAL(Combat, NPCBonusHitChance, 26.0, "Bonus chance to hit for NPC")
|
||||
RULE_REAL(Combat, HitFalloffMinor, 5.0, "Hit will fall off up to value over the initial level range (percent)")
|
||||
RULE_REAL(Combat, HitFalloffModerate, 7.0, "Hit will fall off up to value over the three levels after the initial level range (percent)")
|
||||
@ -490,14 +491,14 @@ RULE_BOOL(Combat, ProjectileDmgOnImpact, true, "If enabled, projectiles (ie arro
|
||||
RULE_BOOL(Combat, MeleePush, true, "Eenable melee push")
|
||||
RULE_INT(Combat, MeleePushChance, 50, "NPC chance the target will be pushed. Made up, 100 actually isn't that bad")
|
||||
RULE_BOOL(Combat, UseLiveCombatRounds, true, "Turn this false if you don't want to worry about fixing up combat rounds for NPCs")
|
||||
RULE_INT(Combat, NPCAssistCap, 5, "Maxiumium number of NPCthat will assist another NPC at once")
|
||||
RULE_INT(Combat, NPCAssistCap, 5, "Maxiumium number of NPC that will assist another NPC at once")
|
||||
RULE_INT(Combat, NPCAssistCapTimer, 6000, "Time a NPC will take to clear assist aggro cap space (milliseconds)")
|
||||
RULE_BOOL(Combat, UseRevampHandToHand, false, "Use h2h revamped dmg/delays I believe this was implemented during SoF")
|
||||
RULE_BOOL(Combat, ClassicMasterWu, false, "Classic master wu uses a random special, modern doesn't")
|
||||
RULE_BOOL(Combat, ClassicMasterWu, false, "Classic Master Wu uses a random special, modern doesn't")
|
||||
RULE_REAL(Combat, HitBoxMod, 1.00, "Added to test hit boxes.")
|
||||
RULE_INT(Combat, LevelToStopDamageCaps, 0, "Level to stop damage caps. 1 will effectively disable them, 20 should give basically same results as old incorrect system")
|
||||
RULE_INT(Combat, LevelToStopACTwinkControl, 50, "Level to stop armorclass twink control. 1 will effectively disable it, 50 should give basically same results as current system")
|
||||
RULE_BOOL(Combat, ClassicNPCBackstab, false, "True disables npc facestab - NPCget normal attack if not behind")
|
||||
RULE_BOOL(Combat, ClassicNPCBackstab, false, "True disables NPC facestab - NPC get normal attack if not behind")
|
||||
RULE_BOOL(Combat, UseNPCDamageClassLevelMods, true, "Uses GetClassLevelDamageMod calc in npc_scale_manager")
|
||||
RULE_BOOL(Combat, UseExtendedPoisonProcs, false, "Allow old school poisons to last until characrer zones, at a lower proc rate")
|
||||
RULE_CATEGORY_END()
|
||||
@ -508,7 +509,7 @@ RULE_INT(NPC, MajorNPCCorpseDecayTimeMS, 1500000, "NPC corpse decay time, if NPC
|
||||
RULE_INT(NPC, CorpseUnlockTimer, 150000, "Time after which corpses are unlocked for everyone to loot (milliseconds)")
|
||||
RULE_INT(NPC, EmptyNPCCorpseDecayTimeMS, 0, "NPC corpse decay time, if no items are left on the corpse (milliseconds)")
|
||||
RULE_BOOL(NPC, UseItemBonusesForNonPets, true, "Switch whether item bonuses should be used for NPCs who are not pets")
|
||||
RULE_BOOL(NPC, UseBaneDamage, false, "If NPCs can't inheriently hit the target we don't add bane/magic dmg which isn't exactly the same as PCs")
|
||||
RULE_BOOL(NPC, UseBaneDamage, false, "If NPCs can't inherently hit the target we don't add bane/magic dmg which isn't exactly the same as PCs")
|
||||
RULE_INT(NPC, SayPauseTimeInSec, 5, "Time span in which an NPC pauses his movement after a Say event without aggro (seconds)")
|
||||
RULE_INT(NPC, OOCRegen, 0, "Enable out-of-combat regeneration for NPC")
|
||||
RULE_BOOL(NPC, BuffFriends, false, "Setting whether NPC should buff other NPC")
|
||||
@ -516,27 +517,27 @@ RULE_BOOL(NPC, EnableNPCQuestJournal, false, "Setting whether the NPC Quest Jour
|
||||
RULE_INT(NPC, LastFightingDelayMovingMin, 10000, "Minimum time before mob goes home after all aggro loss (milliseconds)")
|
||||
RULE_INT(NPC, LastFightingDelayMovingMax, 20000, "Maximum time before mob goes home after all aggro loss (milliseconds)")
|
||||
RULE_BOOL(NPC, SmartLastFightingDelayMoving, true, "When true, mobs that started going home previously will do so again immediately if still on FD hate list")
|
||||
RULE_BOOL(NPC, ReturnNonQuestNoDropItems, false, "Returns NO DROP items on NPCthat don't have an EVENT_TRADE sub in their script")
|
||||
RULE_BOOL(NPC, ReturnNonQuestNoDropItems, false, "Returns NO DROP items on NPC that don't have an EVENT_TRADE sub in their script")
|
||||
RULE_INT(NPC, StartEnrageValue, 9, " Percentage HP that an NPC will begin to enrage")
|
||||
RULE_BOOL(NPC, LiveLikeEnrage, false, "If set to true then only player controlled pets will enrage")
|
||||
RULE_BOOL(NPC, EnableMeritBasedFaction, false, "If set to true, faction will given in the same way as experience (solo/group/raid)")
|
||||
RULE_INT(NPC, NPCToNPCAggroTimerMin, 500, "Minimum time span after which one NPC aggro another NPC (milliseconds)")
|
||||
RULE_INT(NPC, NPCToNPCAggroTimerMax, 6000, "Maximum time span after which one NPC aggro another NPC (milliseconds)")
|
||||
RULE_BOOL(NPC, UseClassAsLastName, true, "Uses class archetype as LastName for NPCwith none")
|
||||
RULE_BOOL(NPC, UseClassAsLastName, true, "Uses class archetype as LastName for NPC with none")
|
||||
RULE_BOOL(NPC, NewLevelScaling, true, "Better level scaling, use old if new formulas would break your server")
|
||||
RULE_INT(NPC, NPCGatePercent, 20, " Percentage at which the NPC Will attempt to gate at")
|
||||
RULE_BOOL(NPC, NPCGateNearBind, false, "Will NPC attempt to gate when near bind location?")
|
||||
RULE_INT(NPC, NPCGateDistanceBind, 75, "Distance from bind before NPC will attempt to gate")
|
||||
RULE_BOOL(NPC, NPCHealOnGate, true, "Will the NPC Heal on Gate")
|
||||
RULE_BOOL(NPC, UseMeditateBasedManaRegen, false, "Based NPC ooc regen on Meditate skill")
|
||||
RULE_REAL(NPC, NPCHealOnGateAmount, 25, "How much the npc will heal on gate if enabled")
|
||||
RULE_REAL(NPC, NPCHealOnGateAmount, 25, "How much the NPC will heal on gate if enabled")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Aggro)
|
||||
RULE_BOOL(Aggro, SmartAggroList, true, "Smart aggro list attempts to choose targets in a much smarter fashion, prefering players to pets, sitting and critically injured players to normal players, and players in melee range to players not")
|
||||
RULE_INT(Aggro, SittingAggroMod, 35, "Aggro increase against sitting targets. 35=35%")
|
||||
RULE_INT(Aggro, MeleeRangeAggroMod, 10, "Aggro increase against targets in melee range. 10=10%")
|
||||
RULE_INT(Aggro, CurrentTargetAggroMod, 0, "Aggro increase against current target. 0% = prefer the current target to any other. Makes it harder for our NPCto switch targets")
|
||||
RULE_INT(Aggro, CurrentTargetAggroMod, 0, "Aggro increase against current target. 0% = prefer the current target to any other. Makes it harder for our NPC to switch targets")
|
||||
RULE_INT(Aggro, CriticallyWoundedAggroMod, 100, "Aggro increase against critical wounded targets")
|
||||
RULE_INT(Aggro, SpellAggroMod, 100, "Aggro increase for spells")
|
||||
RULE_INT(Aggro, SongAggroMod, 33, "Aggro increase for songs")
|
||||
@ -547,7 +548,8 @@ RULE_INT(Aggro, IntAggroThreshold, 75, "Int lesser or equal the value will aggro
|
||||
RULE_BOOL(Aggro, AllowTickPulling, false, "tick pulling is an exploit in an NPC's call for help fixed sometime in 2006 on live")
|
||||
RULE_INT(Aggro, MinAggroLevel, 18, "Minimum level for use with UseLevelAggro")
|
||||
RULE_BOOL(Aggro, UseLevelAggro, true, "MinAggroLevel rule value+ and Undead will aggro regardless of level difference. This will disabled Rule:IntAggroThreshold if set to true")
|
||||
RULE_INT(Aggro, ClientAggroCheckInterval, 6, "Interval in which clients actually check for aggro - in seconds")
|
||||
RULE_INT(Aggro, ClientAggroCheckMovingInterval, 1000, "Interval in which clients actually check for aggro while moving - in milliseconds - this should be lower than ClientAggroCheckIdleInterval")
|
||||
RULE_INT(Aggro, ClientAggroCheckIdleInterval, 6000, "Interval in which clients actually check for aggro while idle - in milliseconds - this should be higher than ClientAggroCheckMovingInterval")
|
||||
RULE_REAL(Aggro, PetAttackRange, 40000.0, "Maximum squared range /pet attack works at default is 200")
|
||||
RULE_BOOL(Aggro, NPCAggroMaxDistanceEnabled, true, "If enabled, NPC's will drop aggro beyond 600 units or what is defined at the zone level")
|
||||
RULE_CATEGORY_END()
|
||||
@ -619,7 +621,7 @@ RULE_BOOL(Chat, EnableVoiceMacros, true, "Enable voice macros")
|
||||
RULE_BOOL(Chat, EnableMailKeyIPVerification, true, "Setting whether the authenticity of the client should be verified via its IP address when accessing the InGame mailbox")
|
||||
RULE_BOOL(Chat, EnableAntiSpam, true, "Enable anti-spam system for chat")
|
||||
RULE_BOOL(Chat, SuppressCommandErrors, false, "Do not suppress command errors by default")
|
||||
RULE_INT(Chat, MinStatusToBypassAntiSpam, 100, "Minimum status to bypass the anti spam system")
|
||||
RULE_INT(Chat, MinStatusToBypassAntiSpam, 100, "Minimum status to bypass the anti-spam system")
|
||||
RULE_INT(Chat, MinimumMessagesPerInterval, 4, "Minimum number of chat messages allowed per interval. The karma value is added to this value")
|
||||
RULE_INT(Chat, MaximumMessagesPerInterval, 12, "Maximum value of chat messages allowed per interval")
|
||||
RULE_INT(Chat, MaxMessagesBeforeKick, 20, "If an attempt is made to send more than the maximum allowed number of chat messages per interval, the client will be disconnected after this absolute number of messages")
|
||||
@ -783,6 +785,20 @@ RULE_BOOL(Instances, RecycleInstanceIds, true, "Setting whether free instance ID
|
||||
RULE_INT(Instances, GuildHallExpirationDays, 90, "Amount of days before a Guild Hall instance expires")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Expedition)
|
||||
RULE_INT(Expedition, MinStatusToBypassPlayerCountRequirements, 80, "Minimum GM status to bypass minimum player requirements for Expedition creation")
|
||||
RULE_BOOL(Expedition, EmptyDzShutdownEnabled, true, "Enable early instance shutdown after last member of expedition removed")
|
||||
RULE_INT(Expedition, EmptyDzShutdownDelaySeconds, 1500, "Seconds to set dynamic zone instance expiration if early shutdown enabled")
|
||||
RULE_INT(Expedition, WorldExpeditionProcessRateMS, 6000, "Timer interval (ms) that world checks expedition states")
|
||||
RULE_BOOL(Expedition, AlwaysNotifyNewLeaderOnChange, false, "Always notify clients when made expedition leader. If false (live-like) new leaders are only notified when made leader via /dzmakeleader")
|
||||
RULE_REAL(Expedition, LockoutDurationMultiplier, 1.0, "Multiplies lockout duration by this value when new lockouts are added")
|
||||
RULE_BOOL(Expedition, EnableInDynamicZoneStatus, false, "Enables the 'In Dynamic Zone' member status in expedition window. If false (live-like) players inside the dz will show as 'Online'")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(DynamicZone)
|
||||
RULE_INT(DynamicZone, ClientRemovalDelayMS, 60000, "Delay (ms) until a client is teleported out of dynamic zone after being removed as member")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
#undef RULE_CATEGORY
|
||||
#undef RULE_INT
|
||||
#undef RULE_REAL
|
||||
|
||||
@ -101,7 +101,7 @@ const std::string &EQ::SayLinkEngine::GenerateLink()
|
||||
m_Error = true;
|
||||
m_Link = "<LINKER ERROR>";
|
||||
LogError("SayLinkEngine::GenerateLink() failed to generate a useable say link");
|
||||
LogError(">> LinkType: {}, Lengths: {link: {}({}), body: {}({}), text: {}({})}",
|
||||
LogError(">> LinkType: {}, Lengths: [link: {}({}), body: {}({}), text: {}({})]",
|
||||
m_LinkType,
|
||||
m_Link.length(),
|
||||
EQ::constants::SAY_LINK_MAXIMUM_SIZE,
|
||||
|
||||
@ -80,6 +80,7 @@
|
||||
#define ServerOP_UpdateSpawn 0x003f
|
||||
#define ServerOP_SpawnStatusChange 0x0040
|
||||
#define ServerOP_DropClient 0x0041 // DropClient
|
||||
#define ServerOP_ChangeGroupLeader 0x0042
|
||||
#define ServerOP_ReloadTasks 0x0060
|
||||
#define ServerOP_DepopAllPlayersCorpses 0x0061
|
||||
#define ServerOP_ReloadTitles 0x0062
|
||||
@ -140,6 +141,35 @@
|
||||
#define ServerOP_LFPUpdate 0x0213
|
||||
#define ServerOP_LFPMatches 0x0214
|
||||
#define ServerOP_ClientVersionSummary 0x0215
|
||||
|
||||
#define ServerOP_ExpeditionCreate 0x0400
|
||||
#define ServerOP_ExpeditionDeleted 0x0401
|
||||
#define ServerOP_ExpeditionLeaderChanged 0x0402
|
||||
#define ServerOP_ExpeditionLockout 0x0403
|
||||
#define ServerOP_ExpeditionMemberChange 0x0404
|
||||
#define ServerOP_ExpeditionMemberSwap 0x0405
|
||||
#define ServerOP_ExpeditionMemberStatus 0x0406
|
||||
#define ServerOP_ExpeditionGetOnlineMembers 0x0407
|
||||
#define ServerOP_ExpeditionDzAddPlayer 0x0408
|
||||
#define ServerOP_ExpeditionDzMakeLeader 0x0409
|
||||
#define ServerOP_ExpeditionDzCompass 0x040a
|
||||
#define ServerOP_ExpeditionDzSafeReturn 0x040b
|
||||
#define ServerOP_ExpeditionDzZoneIn 0x040c
|
||||
#define ServerOP_ExpeditionCharacterLockout 0x040d
|
||||
#define ServerOP_ExpeditionSaveInvite 0x040e
|
||||
#define ServerOP_ExpeditionRequestInvite 0x040f
|
||||
#define ServerOP_ExpeditionReplayOnJoin 0x0410
|
||||
#define ServerOP_ExpeditionLockState 0x0411
|
||||
#define ServerOP_ExpeditionMembersRemoved 0x0412
|
||||
#define ServerOP_ExpeditionDzDuration 0x0413
|
||||
#define ServerOP_ExpeditionLockoutDuration 0x0414
|
||||
#define ServerOP_ExpeditionSecondsRemaining 0x0415
|
||||
#define ServerOP_ExpeditionExpireWarning 0x0416
|
||||
#define ServerOP_ExpeditionChooseNewLeader 0x0417
|
||||
|
||||
#define ServerOP_DzCharacterChange 0x0450
|
||||
#define ServerOP_DzRemoveAllCharacters 0x0451
|
||||
|
||||
#define ServerOP_LSInfo 0x1000
|
||||
#define ServerOP_LSStatus 0x1001
|
||||
#define ServerOP_LSClientAuthLeg 0x1002
|
||||
@ -257,6 +287,7 @@
|
||||
#define ServerOP_CZTaskRemoveGroup 0x4560
|
||||
#define ServerOP_CZTaskRemoveRaid 0x4561
|
||||
#define ServerOP_CZTaskRemoveGuild 0x4562
|
||||
#define ServerOP_CZClientMessageString 0x4563
|
||||
|
||||
#define ServerOP_WWAssignTask 0x4750
|
||||
#define ServerOP_WWCastSpell 0x4751
|
||||
@ -831,6 +862,7 @@ struct ServerGroupLeave_Struct {
|
||||
uint16 instance_id;
|
||||
uint32 gid;
|
||||
char member_name[64]; //kick this member from the group
|
||||
bool checkleader;
|
||||
};
|
||||
|
||||
struct ServerGroupJoin_Struct {
|
||||
@ -840,10 +872,20 @@ struct ServerGroupJoin_Struct {
|
||||
char member_name[64]; //this person is joining the group
|
||||
};
|
||||
|
||||
struct ServerGroupLeader_Struct {
|
||||
uint32 zoneid;
|
||||
uint16 instance_id;
|
||||
uint32 gid;
|
||||
char leader_name[64];
|
||||
char oldleader_name[64];
|
||||
};
|
||||
|
||||
struct ServerForceGroupUpdate_Struct {
|
||||
uint32 origZoneID;
|
||||
uint16 instance_id;
|
||||
uint32 gid;
|
||||
char leader_name[64];
|
||||
char oldleader_name[64];
|
||||
};
|
||||
|
||||
struct ServerGroupChannelMessage_Struct {
|
||||
@ -1433,6 +1475,14 @@ struct CZNPCSignal_Struct {
|
||||
uint32 signal;
|
||||
};
|
||||
|
||||
struct CZClientMessageString_Struct {
|
||||
uint32 string_id;
|
||||
uint16 chat_type;
|
||||
char character_name[64];
|
||||
uint32 args_size;
|
||||
char args[1]; // null delimited
|
||||
};
|
||||
|
||||
struct CZClientSignalByName_Struct {
|
||||
char character_name[64];
|
||||
uint32 signal;
|
||||
@ -1958,6 +2008,146 @@ struct UCSServerStatus_Struct {
|
||||
};
|
||||
};
|
||||
|
||||
struct ServerExpeditionID_Struct {
|
||||
uint32 expedition_id;
|
||||
uint32 sender_zone_id;
|
||||
uint32 sender_instance_id;
|
||||
};
|
||||
|
||||
struct ServerExpeditionLeaderID_Struct {
|
||||
uint32 expedition_id;
|
||||
uint32 leader_id;
|
||||
};
|
||||
|
||||
struct ServerExpeditionMemberChange_Struct {
|
||||
uint32 expedition_id;
|
||||
uint32 sender_zone_id;
|
||||
uint16 sender_instance_id;
|
||||
uint8 removed; // 0: added, 1: removed
|
||||
uint32 char_id;
|
||||
char char_name[64];
|
||||
};
|
||||
|
||||
struct ServerExpeditionMemberSwap_Struct {
|
||||
uint32 expedition_id;
|
||||
uint32 sender_zone_id;
|
||||
uint16 sender_instance_id;
|
||||
uint32 add_char_id;
|
||||
uint32 remove_char_id;
|
||||
char add_char_name[64];
|
||||
char remove_char_name[64];
|
||||
};
|
||||
|
||||
struct ServerExpeditionMemberStatus_Struct {
|
||||
uint32 expedition_id;
|
||||
uint32 sender_zone_id;
|
||||
uint16 sender_instance_id;
|
||||
uint8 status; // 0: unknown 1: Online 2: Offline 3: In Dynamic Zone 4: Link Dead
|
||||
uint32 character_id;
|
||||
};
|
||||
|
||||
struct ServerExpeditionCharacterEntry_Struct {
|
||||
uint32 expedition_id;
|
||||
uint32 character_id;
|
||||
uint32 character_zone_id;
|
||||
uint16 character_instance_id;
|
||||
uint8 character_online; // 0: offline 1: online
|
||||
};
|
||||
|
||||
struct ServerExpeditionCharacters_Struct {
|
||||
uint32 sender_zone_id;
|
||||
uint16 sender_instance_id;
|
||||
uint32 count;
|
||||
ServerExpeditionCharacterEntry_Struct entries[0];
|
||||
};
|
||||
|
||||
struct ServerExpeditionLockout_Struct {
|
||||
uint32 expedition_id;
|
||||
uint64 expire_time;
|
||||
uint32 duration;
|
||||
uint32 sender_zone_id;
|
||||
uint16 sender_instance_id;
|
||||
uint8 remove;
|
||||
uint8 members_only;
|
||||
int seconds_adjust;
|
||||
char event_name[256];
|
||||
};
|
||||
|
||||
struct ServerExpeditionLockState_Struct {
|
||||
uint32 expedition_id;
|
||||
uint32 sender_zone_id;
|
||||
uint16 sender_instance_id;
|
||||
uint8 enabled;
|
||||
uint8 lock_msg; // 0: none, 1: closing 2: trial begin
|
||||
};
|
||||
|
||||
struct ServerExpeditionSetting_Struct {
|
||||
uint32 expedition_id;
|
||||
uint32 sender_zone_id;
|
||||
uint16 sender_instance_id;
|
||||
uint8 enabled;
|
||||
};
|
||||
|
||||
struct ServerExpeditionCharacterLockout_Struct {
|
||||
uint8 remove;
|
||||
uint32 character_id;
|
||||
uint64 expire_time;
|
||||
uint32 duration;
|
||||
char uuid[37];
|
||||
char expedition_name[128];
|
||||
char event_name[256];
|
||||
};
|
||||
|
||||
struct ServerExpeditionCharacterID_Struct {
|
||||
uint32_t character_id;
|
||||
};
|
||||
|
||||
struct ServerExpeditionUpdateDuration_Struct {
|
||||
uint32_t expedition_id;
|
||||
uint32_t new_duration_seconds;
|
||||
};
|
||||
|
||||
struct ServerExpeditionExpireWarning_Struct {
|
||||
uint32_t expedition_id;
|
||||
uint32_t minutes_remaining;
|
||||
};
|
||||
|
||||
struct ServerDzCommand_Struct {
|
||||
uint32 expedition_id;
|
||||
uint8 is_char_online; // 0: target name is offline, 1: online
|
||||
char requester_name[64];
|
||||
char target_name[64];
|
||||
char remove_name[64]; // used for swap command
|
||||
};
|
||||
|
||||
struct ServerDzCommandMakeLeader_Struct {
|
||||
uint32 expedition_id;
|
||||
uint32 requester_id;
|
||||
uint8 is_online; // set by world, 0: new leader name offline, 1: online
|
||||
uint8 is_success; // set by world, 0: makeleader failed, 1: success (is online member)
|
||||
char new_leader_name[64];
|
||||
};
|
||||
|
||||
struct ServerDzLocation_Struct {
|
||||
uint32 owner_id; // system associated with the dz (expedition, shared task, etc)
|
||||
uint16 dz_zone_id;
|
||||
uint16 dz_instance_id;
|
||||
uint32 sender_zone_id;
|
||||
uint16 sender_instance_id;
|
||||
uint32 zone_id; // compass or safereturn zone id
|
||||
float y;
|
||||
float x;
|
||||
float z;
|
||||
float heading;
|
||||
};
|
||||
|
||||
struct ServerDzCharacter_Struct {
|
||||
uint16 zone_id;
|
||||
uint16 instance_id;
|
||||
uint8 remove; // 0: added 1: removed
|
||||
uint32 character_id;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
#endif
|
||||
|
||||
@ -1271,7 +1271,7 @@ bool IsSpellUsableThisZoneType(uint16 spell_id, uint8 zone_type)
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* GetSpellName(int16 spell_id)
|
||||
const char* GetSpellName(uint16 spell_id)
|
||||
{
|
||||
return spells[spell_id].name;
|
||||
}
|
||||
|
||||
@ -981,6 +981,6 @@ uint32 GetNimbusEffect(uint16 spell_id);
|
||||
int32 GetFuriousBash(uint16 spell_id);
|
||||
bool IsShortDurationBuff(uint16 spell_id);
|
||||
bool IsSpellUsableThisZoneType(uint16 spell_id, uint8 zone_type);
|
||||
const char *GetSpellName(int16 spell_id);
|
||||
const char *GetSpellName(uint16 spell_id);
|
||||
|
||||
#endif
|
||||
|
||||
@ -592,3 +592,15 @@ std::string numberToWords(unsigned long long int n)
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// first letter capitalized and rest made lower case
|
||||
std::string FormatName(const std::string& char_name)
|
||||
{
|
||||
std::string formatted(char_name);
|
||||
if (!formatted.empty())
|
||||
{
|
||||
std::transform(formatted.begin(), formatted.end(), formatted.begin(), ::tolower);
|
||||
formatted[0] = ::toupper(formatted[0]);
|
||||
}
|
||||
return formatted;
|
||||
}
|
||||
|
||||
@ -206,6 +206,6 @@ void MakeLowerString(const char *source, char *target);
|
||||
void RemoveApostrophes(std::string &s);
|
||||
std::string convert2digit(int n, std::string suffix);
|
||||
std::string numberToWords(unsigned long long int n);
|
||||
|
||||
std::string FormatName(const std::string& char_name);
|
||||
|
||||
#endif
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||
*/
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9157
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9159
|
||||
|
||||
#ifdef BOTS
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9027
|
||||
|
||||
@ -366,6 +366,7 @@ OP_CancelSneakHide=0x265f
|
||||
OP_AggroMeterLockTarget=0x70b7
|
||||
OP_AggroMeterTargetInfo=0x18fe
|
||||
OP_AggroMeterUpdate=0x75aa
|
||||
OP_UnderWorld=0x44f9 # clients sends up when they detect an underworld issue, might be useful for cheat detection
|
||||
|
||||
OP_DzQuit=0x5fc8
|
||||
OP_DzListTimers=0x67b9
|
||||
@ -374,16 +375,18 @@ OP_DzRemovePlayer=0x0dc1
|
||||
OP_DzSwapPlayer=0x4995
|
||||
OP_DzMakeLeader=0x17b2
|
||||
OP_DzPlayerList=0x1aff
|
||||
OP_DzJoinExpeditionConfirm=0x30df
|
||||
OP_DzJoinExpeditionReply=0x15d4
|
||||
OP_DzExpeditionInvite=0x30df
|
||||
OP_DzExpeditionInviteResponse=0x15d4
|
||||
OP_DzExpeditionInfo=0x3861
|
||||
OP_DzExpeditionList=0x0b3b
|
||||
OP_DzMemberStatus=0x26c2
|
||||
OP_DzLeaderStatus=0x4021
|
||||
OP_DzExpeditionEndsWarning=0x32eb
|
||||
OP_DzExpeditionLockoutTimers=0x0b3b
|
||||
OP_DzMemberList=0x348f
|
||||
OP_DzMemberListName=0x26c2
|
||||
OP_DzMemberListStatus=0x0000
|
||||
OP_DzSetLeaderName=0x4021
|
||||
OP_DzExpeditionEndsWarning=0x32eb
|
||||
OP_DzCompass=0x0e01 # Was 0x4f09
|
||||
OP_DzChooseZone=0x6e5e # Maybe 0x29d6
|
||||
OP_DzChooseZoneReply=0x0000
|
||||
|
||||
# New Opcodes
|
||||
OP_SpawnPositionUpdate=0x0000 # Actually OP_MobUpdate ?
|
||||
|
||||
@ -367,25 +367,29 @@ OP_CancelSneakHide=0x0927
|
||||
OP_AggroMeterLockTarget=0x1643
|
||||
OP_AggroMeterTargetInfo=0x16bc
|
||||
OP_AggroMeterUpdate=0x1781
|
||||
OP_UnderWorld=0x2eb3 # clients sends up when they detect an underworld issue, might be useful for cheat detection
|
||||
OP_KickPlayers=0x6770
|
||||
|
||||
# Expeditions
|
||||
OP_DzQuit=0xb2e3
|
||||
OP_DzListTimers=0x7b68
|
||||
OP_DzAddPlayer=0x4701
|
||||
OP_DzRemovePlayer=0x1abc
|
||||
OP_DzSwapPlayer=0x405b
|
||||
OP_DzMakeLeader=0x543d
|
||||
OP_DzPlayerList=0x14c6
|
||||
OP_DzJoinExpeditionConfirm=0x7f4b
|
||||
OP_DzJoinExpeditionReply=0x1950
|
||||
OP_DzListTimers=0x7b68
|
||||
OP_DzExpeditionInvite=0x7f4b
|
||||
OP_DzExpeditionInviteResponse=0x1950
|
||||
OP_DzExpeditionInfo=0x9119
|
||||
OP_DzExpeditionList=0x205f
|
||||
OP_DzQuit=0xb2e3
|
||||
OP_DzMemberStatus=0x32f0
|
||||
OP_DzLeaderStatus=0x3de9
|
||||
OP_DzExpeditionLockoutTimers=0x205f
|
||||
OP_DzMemberList=0x5ae4
|
||||
OP_DzExpeditionEndsWarning=0x383c
|
||||
OP_DzMemberListName=0x32f0
|
||||
OP_DzMemberListStatus=0x12F5
|
||||
OP_DzSetLeaderName=0x3de9
|
||||
OP_DzExpeditionEndsWarning=0x5189
|
||||
OP_DzCompass=0x3e0e
|
||||
OP_DzChooseZone=0x0b7d
|
||||
OP_DzChooseZoneReply=0x4de1
|
||||
|
||||
# New Opcodes
|
||||
OP_SpawnPositionUpdate=0x0000 # Actually OP_MobUpdate ?
|
||||
|
||||
@ -357,6 +357,7 @@ OP_OpenContainer=0x3278
|
||||
OP_Marquee=0x7dc9
|
||||
OP_Fling=0x2b88
|
||||
OP_CancelSneakHide=0x7705
|
||||
OP_UnderWorld=0x51ae # clients sends up when they detect an underworld issue, might be useful for cheat detection
|
||||
|
||||
# Expedition
|
||||
OP_DzQuit=0x054e
|
||||
@ -366,17 +367,18 @@ OP_DzRemovePlayer=0xa682
|
||||
OP_DzSwapPlayer=0x0d8d
|
||||
OP_DzMakeLeader=0x1caa
|
||||
OP_DzPlayerList=0x74ca
|
||||
OP_DzJoinExpeditionConfirm=0x1772
|
||||
OP_DzJoinExpeditionReply=0x3c13
|
||||
OP_DzExpeditionInvite=0x1772
|
||||
OP_DzExpeditionInviteResponse=0x3c13
|
||||
OP_DzExpeditionInfo=0x128e
|
||||
OP_DzMemberStatus=0x4661
|
||||
OP_DzLeaderStatus=0x226f
|
||||
OP_DzExpeditionEndsWarning=0x1879
|
||||
OP_DzExpeditionList=0x3657
|
||||
OP_DzExpeditionLockoutTimers=0x3657
|
||||
OP_DzMemberList=0x74e4
|
||||
OP_DzMemberListName=0x4661
|
||||
OP_DzMemberListStatus=0x1d99
|
||||
OP_DzSetLeaderName=0x226f
|
||||
OP_DzExpeditionEndsWarning=0x1879
|
||||
OP_DzCompass=0x35d3
|
||||
OP_DzChooseZone=0x0d8a
|
||||
#0x1d99 was grouped with these too but I don't really know it's purpose.
|
||||
OP_DzChooseZoneReply=0x5a67
|
||||
|
||||
# New Opcodes
|
||||
OP_SpawnPositionUpdate=0x4656 #
|
||||
|
||||
@ -338,6 +338,7 @@ OP_OpenContainer=0x10e3
|
||||
OP_Marquee=0x2f75
|
||||
OP_Untargetable=0x3e36
|
||||
OP_CancelSneakHide=0x5335
|
||||
OP_UnderWorld=0x7580 # clients sends up when they detect an underworld issue, might be useful for cheat detection
|
||||
|
||||
#expedition
|
||||
OP_DzQuit=0x20d6
|
||||
@ -347,16 +348,18 @@ OP_DzRemovePlayer=0x2ce8
|
||||
OP_DzSwapPlayer=0x2c3e
|
||||
OP_DzMakeLeader=0x1a75
|
||||
OP_DzPlayerList=0x5116
|
||||
OP_DzJoinExpeditionConfirm=0x1793
|
||||
OP_DzJoinExpeditionReply=0x7a6f
|
||||
OP_DzExpeditionInvite=0x1793
|
||||
OP_DzExpeditionInviteResponse=0x7a6f
|
||||
OP_DzExpeditionInfo=0x60a6
|
||||
OP_DzMemberStatus=0x0516
|
||||
OP_DzLeaderStatus=0x79d3
|
||||
OP_DzExpeditionEndsWarning=0x5153
|
||||
OP_DzExpeditionList=0x02ac
|
||||
OP_DzExpeditionLockoutTimers=0x02ac
|
||||
OP_DzMemberList=0x5e14
|
||||
OP_DzMemberListName=0x0516
|
||||
OP_DzMemberListStatus=0x0000
|
||||
OP_DzSetLeaderName=0x79d3
|
||||
OP_DzExpeditionEndsWarning=0x5153
|
||||
OP_DzCompass=0x531d
|
||||
OP_DzChooseZone=0x3c5b
|
||||
OP_DzChooseZoneReply=0x0000
|
||||
|
||||
#Looting
|
||||
OP_LootRequest=0x36E3 #Trevius 02/16/09
|
||||
|
||||
@ -297,17 +297,18 @@ OP_DzRemovePlayer=0x540b
|
||||
OP_DzSwapPlayer=0x794a
|
||||
OP_DzMakeLeader=0x0ce9
|
||||
OP_DzPlayerList=0xada0
|
||||
OP_DzJoinExpeditionConfirm=0x3817
|
||||
OP_DzJoinExpeditionReply=0x5da9
|
||||
OP_DzExpeditionInvite=0x3817
|
||||
OP_DzExpeditionInviteResponse=0x5da9
|
||||
OP_DzExpeditionInfo=0x98e
|
||||
OP_DzMemberStatus=0x1826
|
||||
OP_DzLeaderStatus=0x7abc
|
||||
OP_DzExpeditionEndsWarning=0x1c3f
|
||||
OP_DzExpeditionList=0x7c12
|
||||
OP_DzExpeditionLockoutTimers=0x7c12
|
||||
OP_DzMemberList=0x9b6
|
||||
OP_DzMemberListName=0x1826
|
||||
OP_DzMemberListStatus=0x330d
|
||||
OP_DzSetLeaderName=0x7abc
|
||||
OP_DzExpeditionEndsWarning=0x1c3f
|
||||
OP_DzCompass=0x28aa
|
||||
OP_DzChooseZone=0x1022
|
||||
#0x330d is something but I'm not sure what yet.
|
||||
OP_DzChooseZoneReply=0x20e7
|
||||
|
||||
#bazaar trader stuff stuff:
|
||||
#become and buy from
|
||||
@ -543,6 +544,7 @@ OP_PlayerStateRemove=0x381d
|
||||
OP_VoiceMacroIn=0x2866 # Client to Server
|
||||
OP_VoiceMacroOut=0x2ec6 # Server to Client
|
||||
OP_CameraEffect=0x0937 # Correct
|
||||
OP_UnderWorld=0x7186 # clients sends up when they detect an underworld issue, might be useful for cheat detection
|
||||
|
||||
#named unknowns, to make looking for real unknown easier
|
||||
OP_AnnoyingZoneUnknown=0x729c
|
||||
|
||||
@ -368,6 +368,7 @@ OP_OpenContainer=0x041a
|
||||
OP_Marquee=0x3675
|
||||
OP_Fling=0x51b1
|
||||
OP_CancelSneakHide=0x7686
|
||||
OP_UnderWorld=0x2d9d # clients sends up when they detect an underworld issue, might be useful for cheat detection
|
||||
|
||||
OP_DzQuit=0x1539
|
||||
OP_DzListTimers=0x21e9
|
||||
@ -376,16 +377,18 @@ OP_DzRemovePlayer=0x054e
|
||||
OP_DzSwapPlayer=0x4661
|
||||
OP_DzMakeLeader=0x226f
|
||||
OP_DzPlayerList=0x74e4
|
||||
OP_DzJoinExpeditionConfirm=0x3c5e
|
||||
OP_DzJoinExpeditionReply=0x1154
|
||||
OP_DzExpeditionInvite=0x3c5e
|
||||
OP_DzExpeditionInviteResponse=0x1154
|
||||
OP_DzExpeditionInfo=0x1150
|
||||
OP_DzMemberStatus=0x2d17
|
||||
OP_DzLeaderStatus=0x2caf
|
||||
OP_DzExpeditionEndsWarning=0x6ac2
|
||||
OP_DzExpeditionList=0x70d8
|
||||
OP_DzExpeditionLockoutTimers=0x70d8
|
||||
OP_DzMemberList=0x15c4
|
||||
OP_DzMemberListName=0x2d17
|
||||
OP_DzMemberListStatus=0x0d98
|
||||
OP_DzSetLeaderName=0x2caf
|
||||
OP_DzExpeditionEndsWarning=0x6ac2
|
||||
OP_DzCompass=0x01cb
|
||||
OP_DzChooseZone=0x65e1
|
||||
OP_DzChooseZoneReply=0xa682
|
||||
|
||||
#shroud
|
||||
OP_ShroudSelectionWindow=0x72ad
|
||||
|
||||
@ -411,6 +411,8 @@
|
||||
9155|2020_08_15_lootdrop_level_filtering.sql|SHOW COLUMNS from `lootdrop_entries` LIKE 'trivial_min_level'|empty|
|
||||
9156|2020_08_16_virtual_zonepoints.sql|SHOW COLUMNS from `zone_points` LIKE 'is_virtual'|empty|
|
||||
9157|2020_09_02_pet_taunting.sql|SHOW COLUMNS from `character_pet_info` LIKE 'taunting'|empty|
|
||||
9158|2020_12_09_underworld.sql|SHOW COLUMNS from `zone` LIKE 'underworld_teleport_index'|empty|
|
||||
9159|2020_12_22_expedition_system.sql|SELECT * FROM db_version WHERE version >= 9159|empty|
|
||||
|
||||
# Upgrade conditions:
|
||||
# This won't be needed after this system is implemented, but it is used database that are not
|
||||
|
||||
6
utils/sql/git/required/2020_12_09_underworld.sql
Normal file
6
utils/sql/git/required/2020_12_09_underworld.sql
Normal file
@ -0,0 +1,6 @@
|
||||
ALTER TABLE `zone` ADD COLUMN `underworld_teleport_index` INT(4) NOT NULL DEFAULT '0';
|
||||
UPDATE `zone` SET `underworld` = '-2030' WHERE `zoneidnumber` = '71';
|
||||
UPDATE `zone` SET `underworld_teleport_index` = '11' WHERE `zoneidnumber` = '71';
|
||||
UPDATE `zone` SET `underworld_teleport_index` = '-1' WHERE `zoneidnumber` = '75';
|
||||
UPDATE `zone` SET `underworld_teleport_index` = '-1' WHERE `zoneidnumber` = '150';
|
||||
|
||||
82
utils/sql/git/required/2020_12_22_expedition_system.sql
Normal file
82
utils/sql/git/required/2020_12_22_expedition_system.sql
Normal file
@ -0,0 +1,82 @@
|
||||
CREATE TABLE `expeditions` (
|
||||
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`uuid` VARCHAR(36) NOT NULL,
|
||||
`dynamic_zone_id` INT(10) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`expedition_name` VARCHAR(128) NOT NULL,
|
||||
`leader_id` INT(10) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`min_players` TINYINT(3) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`max_players` TINYINT(3) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`add_replay_on_join` TINYINT(3) UNSIGNED NOT NULL DEFAULT 1,
|
||||
`is_locked` TINYINT(3) UNSIGNED NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE INDEX `dynamic_zone_id` (`dynamic_zone_id`)
|
||||
)
|
||||
COLLATE='latin1_swedish_ci'
|
||||
ENGINE=InnoDB
|
||||
;
|
||||
|
||||
CREATE TABLE `expedition_lockouts` (
|
||||
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`expedition_id` INT(10) UNSIGNED NOT NULL,
|
||||
`event_name` VARCHAR(256) NOT NULL,
|
||||
`expire_time` DATETIME NOT NULL DEFAULT current_timestamp(),
|
||||
`duration` INT(10) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`from_expedition_uuid` VARCHAR(36) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE INDEX `expedition_id_event_name` (`expedition_id`, `event_name`)
|
||||
)
|
||||
COLLATE='latin1_swedish_ci'
|
||||
ENGINE=InnoDB
|
||||
;
|
||||
|
||||
CREATE TABLE `expedition_members` (
|
||||
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`expedition_id` INT(10) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`character_id` INT(10) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`is_current_member` TINYINT(3) UNSIGNED NOT NULL DEFAULT 1,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE INDEX `expedition_id_character_id` (`expedition_id`, `character_id`)
|
||||
)
|
||||
COLLATE='latin1_swedish_ci'
|
||||
ENGINE=InnoDB
|
||||
;
|
||||
|
||||
CREATE TABLE `character_expedition_lockouts` (
|
||||
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`character_id` INT(10) UNSIGNED NOT NULL,
|
||||
`expedition_name` VARCHAR(128) NOT NULL,
|
||||
`event_name` VARCHAR(256) NOT NULL,
|
||||
`expire_time` DATETIME NOT NULL DEFAULT current_timestamp(),
|
||||
`duration` INT(10) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`from_expedition_uuid` VARCHAR(36) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE INDEX `character_id_expedition_name_event_name` (`character_id`, `expedition_name`, `event_name`)
|
||||
)
|
||||
COLLATE='latin1_swedish_ci'
|
||||
ENGINE=InnoDB
|
||||
;
|
||||
|
||||
CREATE TABLE `dynamic_zones` (
|
||||
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`instance_id` INT(10) NOT NULL DEFAULT 0,
|
||||
`type` TINYINT(3) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`compass_zone_id` INT(10) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`compass_x` FLOAT NOT NULL DEFAULT 0,
|
||||
`compass_y` FLOAT NOT NULL DEFAULT 0,
|
||||
`compass_z` FLOAT NOT NULL DEFAULT 0,
|
||||
`safe_return_zone_id` INT(10) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`safe_return_x` FLOAT NOT NULL DEFAULT 0,
|
||||
`safe_return_y` FLOAT NOT NULL DEFAULT 0,
|
||||
`safe_return_z` FLOAT NOT NULL DEFAULT 0,
|
||||
`safe_return_heading` FLOAT NOT NULL DEFAULT 0,
|
||||
`zone_in_x` FLOAT NOT NULL DEFAULT 0,
|
||||
`zone_in_y` FLOAT NOT NULL DEFAULT 0,
|
||||
`zone_in_z` FLOAT NOT NULL DEFAULT 0,
|
||||
`zone_in_heading` FLOAT NOT NULL DEFAULT 0,
|
||||
`has_zone_in` TINYINT(3) UNSIGNED NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE INDEX `instance_id` (`instance_id`)
|
||||
)
|
||||
COLLATE='utf8mb4_general_ci'
|
||||
ENGINE=InnoDB
|
||||
;
|
||||
@ -9,6 +9,10 @@ SET(world_sources
|
||||
console.cpp
|
||||
eql_config.cpp
|
||||
eqemu_api_world_data_service.cpp
|
||||
expedition.cpp
|
||||
expedition_database.cpp
|
||||
expedition_message.cpp
|
||||
expedition_state.cpp
|
||||
launcher_link.cpp
|
||||
launcher_list.cpp
|
||||
lfplist.cpp
|
||||
@ -39,6 +43,10 @@ SET(world_headers
|
||||
console.h
|
||||
eql_config.h
|
||||
eqemu_api_world_data_service.h
|
||||
expedition.h
|
||||
expedition_database.h
|
||||
expedition_message.h
|
||||
expedition_state.h
|
||||
launcher_link.h
|
||||
launcher_list.h
|
||||
lfplist.h
|
||||
|
||||
@ -127,6 +127,9 @@ public:
|
||||
inline void PushToTellQueue(ServerChannelMessage_Struct *scm) { tell_queue.push_back(scm); }
|
||||
void ProcessTellQueue();
|
||||
|
||||
void SetPendingExpeditionInvite(ServerPacket* pack) { p_pending_expedition_invite.reset(pack->Copy()); };
|
||||
std::unique_ptr<ServerPacket> GetPendingExpeditionInvite() { return std::move(p_pending_expedition_invite); }
|
||||
|
||||
private:
|
||||
void ClearVars(bool iAll = false);
|
||||
|
||||
@ -171,6 +174,8 @@ private:
|
||||
|
||||
// Tell Queue -- really a vector :D
|
||||
std::vector<ServerChannelMessage_Struct *> tell_queue;
|
||||
|
||||
std::unique_ptr<ServerPacket> p_pending_expedition_invite = nullptr;
|
||||
};
|
||||
|
||||
#endif /*CLIENTENTRY_H_*/
|
||||
|
||||
195
world/expedition.cpp
Normal file
195
world/expedition.cpp
Normal file
@ -0,0 +1,195 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "expedition.h"
|
||||
#include "expedition_database.h"
|
||||
#include "cliententry.h"
|
||||
#include "clientlist.h"
|
||||
#include "zonelist.h"
|
||||
#include "zoneserver.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
|
||||
extern ClientList client_list;
|
||||
extern ZSList zoneserver_list;
|
||||
|
||||
Expedition::Expedition(uint32_t expedition_id, uint32_t dz_id, uint32_t dz_instance_id,
|
||||
uint32_t dz_zone_id, uint32_t start_time, uint32_t duration, uint32_t leader_id
|
||||
) :
|
||||
m_expedition_id(expedition_id),
|
||||
m_dz_id(dz_id),
|
||||
m_dz_instance_id(dz_instance_id),
|
||||
m_dz_zone_id(dz_zone_id),
|
||||
m_start_time(std::chrono::system_clock::from_time_t(start_time)),
|
||||
m_duration(duration),
|
||||
m_leader_id(leader_id)
|
||||
{
|
||||
m_expire_time = m_start_time + m_duration;
|
||||
m_warning_cooldown_timer.Enable();
|
||||
}
|
||||
|
||||
void Expedition::AddMember(uint32_t character_id)
|
||||
{
|
||||
auto it = std::find_if(m_member_ids.begin(), m_member_ids.end(),
|
||||
[&](uint32_t member_id) { return member_id == character_id; });
|
||||
|
||||
if (it == m_member_ids.end())
|
||||
{
|
||||
m_member_ids.emplace_back(character_id);
|
||||
}
|
||||
}
|
||||
|
||||
bool Expedition::HasMember(uint32_t character_id)
|
||||
{
|
||||
return std::any_of(m_member_ids.begin(), m_member_ids.end(),
|
||||
[&](uint32_t member_id) { return member_id == character_id; });
|
||||
}
|
||||
|
||||
void Expedition::RemoveMember(uint32_t character_id)
|
||||
{
|
||||
m_member_ids.erase(std::remove_if(m_member_ids.begin(), m_member_ids.end(),
|
||||
[&](uint32_t member_id) { return member_id == character_id; }
|
||||
), m_member_ids.end());
|
||||
|
||||
if (!m_member_ids.empty() && character_id == m_leader_id)
|
||||
{
|
||||
ChooseNewLeader();
|
||||
}
|
||||
}
|
||||
|
||||
void Expedition::ChooseNewLeader()
|
||||
{
|
||||
// we don't track expedition member status in world so may choose a linkdead member
|
||||
// this is fine since it will trigger another change when that member goes offline
|
||||
auto it = std::find_if(m_member_ids.begin(), m_member_ids.end(), [&](uint32_t member_id) {
|
||||
auto member_cle = (member_id != m_leader_id) ? client_list.FindCLEByCharacterID(member_id) : nullptr;
|
||||
return (member_id != m_leader_id && member_cle && member_cle->GetOnline() == CLE_Status::InZone);
|
||||
});
|
||||
|
||||
if (it == m_member_ids.end())
|
||||
{
|
||||
// no online members found, fallback to choosing any member
|
||||
it = std::find_if(m_member_ids.begin(), m_member_ids.end(),
|
||||
[&](uint32_t member_id) { return (member_id != m_leader_id); });
|
||||
}
|
||||
|
||||
if (it != m_member_ids.end())
|
||||
{
|
||||
SetNewLeader(*it);
|
||||
}
|
||||
}
|
||||
|
||||
bool Expedition::SetNewLeader(uint32_t character_id)
|
||||
{
|
||||
if (!HasMember(character_id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
LogExpeditionsModerate("Replacing [{}] leader [{}] with [{}]", m_expedition_id, m_leader_id, character_id);
|
||||
ExpeditionDatabase::UpdateLeaderID(m_expedition_id, character_id);
|
||||
m_leader_id = character_id;
|
||||
SendZonesLeaderChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Expedition::SendZonesExpeditionDeleted()
|
||||
{
|
||||
uint32_t pack_size = sizeof(ServerExpeditionID_Struct);
|
||||
auto pack = std::unique_ptr<ServerPacket>(new ServerPacket(ServerOP_ExpeditionDeleted, pack_size));
|
||||
auto buf = reinterpret_cast<ServerExpeditionID_Struct*>(pack->pBuffer);
|
||||
buf->expedition_id = GetID();
|
||||
zoneserver_list.SendPacket(pack.get());
|
||||
}
|
||||
|
||||
void Expedition::SendZonesDurationUpdate()
|
||||
{
|
||||
uint32_t packsize = sizeof(ServerExpeditionUpdateDuration_Struct);
|
||||
auto pack = std::unique_ptr<ServerPacket>(new ServerPacket(ServerOP_ExpeditionDzDuration, packsize));
|
||||
auto packbuf = reinterpret_cast<ServerExpeditionUpdateDuration_Struct*>(pack->pBuffer);
|
||||
packbuf->expedition_id = GetID();
|
||||
packbuf->new_duration_seconds = static_cast<uint32_t>(m_duration.count());
|
||||
zoneserver_list.SendPacket(pack.get());
|
||||
}
|
||||
|
||||
void Expedition::SendZonesExpireWarning(uint32_t minutes_remaining)
|
||||
{
|
||||
uint32_t pack_size = sizeof(ServerExpeditionExpireWarning_Struct);
|
||||
auto pack = std::unique_ptr<ServerPacket>(new ServerPacket(ServerOP_ExpeditionExpireWarning, pack_size));
|
||||
auto buf = reinterpret_cast<ServerExpeditionExpireWarning_Struct*>(pack->pBuffer);
|
||||
buf->expedition_id = GetID();
|
||||
buf->minutes_remaining = minutes_remaining;
|
||||
zoneserver_list.SendPacket(pack.get());
|
||||
}
|
||||
|
||||
void Expedition::SendZonesLeaderChanged()
|
||||
{
|
||||
uint32_t pack_size = sizeof(ServerExpeditionLeaderID_Struct);
|
||||
auto pack = std::unique_ptr<ServerPacket>(new ServerPacket(ServerOP_ExpeditionLeaderChanged, pack_size));
|
||||
auto buf = reinterpret_cast<ServerExpeditionLeaderID_Struct*>(pack->pBuffer);
|
||||
buf->expedition_id = GetID();
|
||||
buf->leader_id = m_leader_id;
|
||||
zoneserver_list.SendPacket(pack.get());
|
||||
}
|
||||
|
||||
void Expedition::UpdateDzSecondsRemaining(uint32_t seconds_remaining)
|
||||
{
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto update_time = std::chrono::seconds(seconds_remaining);
|
||||
|
||||
auto current_remaining = m_expire_time - now;
|
||||
if (current_remaining > update_time) // reduce only
|
||||
{
|
||||
LogExpeditionsDetail(
|
||||
"Updating expedition [{}] dz instance [{}] seconds remaining to [{}]s",
|
||||
GetID(), GetInstanceID(), seconds_remaining
|
||||
);
|
||||
|
||||
// preserve original start time and adjust duration instead
|
||||
m_expire_time = now + update_time;
|
||||
m_duration = std::chrono::duration_cast<std::chrono::seconds>(m_expire_time - m_start_time);
|
||||
|
||||
ExpeditionDatabase::UpdateDzDuration(GetInstanceID(), static_cast<uint32_t>(m_duration.count()));
|
||||
|
||||
// update zone level caches and update the actual dz instance's timer
|
||||
SendZonesDurationUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
std::chrono::system_clock::duration Expedition::GetRemainingDuration() const
|
||||
{
|
||||
return m_expire_time - std::chrono::system_clock::now();
|
||||
}
|
||||
|
||||
void Expedition::CheckExpireWarning()
|
||||
{
|
||||
if (m_warning_cooldown_timer.Check(false))
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
auto remaining = GetRemainingDuration();
|
||||
if ((remaining > 14min && remaining < 15min) ||
|
||||
(remaining > 4min && remaining < 5min) ||
|
||||
(remaining > 0min && remaining < 1min))
|
||||
{
|
||||
int minutes = std::chrono::duration_cast<std::chrono::minutes>(remaining).count() + 1;
|
||||
SendZonesExpireWarning(minutes);
|
||||
m_warning_cooldown_timer.Start(70000); // 1 minute 10 seconds
|
||||
}
|
||||
}
|
||||
}
|
||||
73
world/expedition.h
Normal file
73
world/expedition.h
Normal file
@ -0,0 +1,73 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* 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 WORLD_EXPEDITION_H
|
||||
#define WORLD_EXPEDITION_H
|
||||
|
||||
#include "../common/timer.h"
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
class Expedition
|
||||
{
|
||||
public:
|
||||
Expedition() = default;
|
||||
Expedition(uint32_t expedition_id, uint32_t dz_id, uint32_t dz_instance_id,
|
||||
uint32_t dz_zone_id, uint32_t expire_time, uint32_t duration, uint32_t leader_id);
|
||||
|
||||
void AddMember(uint32_t character_id);
|
||||
void RemoveMember(uint32_t character_id);
|
||||
void RemoveAllMembers() { m_member_ids.clear(); }
|
||||
void CheckExpireWarning();
|
||||
void ChooseNewLeader();
|
||||
uint32_t GetID() const { return m_expedition_id; }
|
||||
uint16_t GetInstanceID() const { return static_cast<uint16_t>(m_dz_instance_id); }
|
||||
uint16_t GetZoneID() const { return static_cast<uint16_t>(m_dz_zone_id); }
|
||||
bool HasMember(uint32_t character_id);
|
||||
bool IsEmpty() const { return m_member_ids.empty(); }
|
||||
bool IsExpired() const { return m_expire_time < std::chrono::system_clock::now(); }
|
||||
bool IsPendingDelete() const { return m_pending_delete; }
|
||||
bool IsValid() const { return m_expedition_id != 0; }
|
||||
void SendZonesDurationUpdate();
|
||||
void SendZonesExpeditionDeleted();
|
||||
void SendZonesExpireWarning(uint32_t minutes_remaining);
|
||||
bool SetNewLeader(uint32_t new_leader_id);
|
||||
void SetPendingDelete(bool pending) { m_pending_delete = pending; }
|
||||
void UpdateDzSecondsRemaining(uint32_t seconds_remaining);
|
||||
std::chrono::system_clock::duration GetRemainingDuration() const;
|
||||
|
||||
private:
|
||||
void SendZonesLeaderChanged();
|
||||
|
||||
uint32_t m_expedition_id = 0;
|
||||
uint32_t m_dz_id = 0;
|
||||
uint32_t m_dz_instance_id = 0;
|
||||
uint32_t m_dz_zone_id = 0;
|
||||
uint32_t m_leader_id = 0;
|
||||
bool m_pending_delete = false;
|
||||
Timer m_warning_cooldown_timer;
|
||||
std::vector<uint32_t> m_member_ids;
|
||||
std::chrono::seconds m_duration;
|
||||
std::chrono::time_point<std::chrono::system_clock> m_start_time;
|
||||
std::chrono::time_point<std::chrono::system_clock> m_expire_time;
|
||||
};
|
||||
|
||||
#endif
|
||||
215
world/expedition_database.cpp
Normal file
215
world/expedition_database.cpp
Normal file
@ -0,0 +1,215 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "expedition_database.h"
|
||||
#include "expedition.h"
|
||||
#include "worlddb.h"
|
||||
|
||||
void ExpeditionDatabase::PurgeExpiredExpeditions()
|
||||
{
|
||||
std::string query = SQL(
|
||||
SELECT
|
||||
expeditions.id
|
||||
FROM expeditions
|
||||
LEFT JOIN dynamic_zones ON expeditions.dynamic_zone_id = dynamic_zones.id
|
||||
LEFT JOIN instance_list ON dynamic_zones.instance_id = instance_list.id
|
||||
LEFT JOIN
|
||||
(
|
||||
SELECT expedition_id, COUNT(IF(is_current_member = TRUE, 1, NULL)) member_count
|
||||
FROM expedition_members
|
||||
GROUP BY expedition_id
|
||||
) expedition_members
|
||||
ON expedition_members.expedition_id = expeditions.id
|
||||
WHERE
|
||||
instance_list.id IS NULL
|
||||
OR expedition_members.member_count IS NULL
|
||||
OR expedition_members.member_count = 0
|
||||
OR (instance_list.start_time + instance_list.duration) <= UNIX_TIMESTAMP();
|
||||
);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (results.Success())
|
||||
{
|
||||
std::vector<uint32_t> expedition_ids;
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
{
|
||||
expedition_ids.emplace_back(static_cast<uint32_t>(strtoul(row[0], nullptr, 10)));
|
||||
}
|
||||
|
||||
if (!expedition_ids.empty())
|
||||
{
|
||||
ExpeditionDatabase::MoveMembersToSafeReturn(expedition_ids);
|
||||
ExpeditionDatabase::DeleteExpeditions(expedition_ids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExpeditionDatabase::PurgeExpiredCharacterLockouts()
|
||||
{
|
||||
std::string query = SQL(
|
||||
DELETE FROM character_expedition_lockouts
|
||||
WHERE expire_time <= NOW();
|
||||
);
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
|
||||
std::vector<Expedition> ExpeditionDatabase::LoadExpeditions(uint32_t select_expedition_id)
|
||||
{
|
||||
std::vector<Expedition> expeditions;
|
||||
|
||||
std::string query = SQL(
|
||||
SELECT
|
||||
expeditions.id,
|
||||
expeditions.dynamic_zone_id,
|
||||
instance_list.id,
|
||||
instance_list.zone,
|
||||
instance_list.start_time,
|
||||
instance_list.duration,
|
||||
expeditions.leader_id,
|
||||
expedition_members.character_id
|
||||
FROM expeditions
|
||||
INNER JOIN dynamic_zones ON expeditions.dynamic_zone_id = dynamic_zones.id
|
||||
INNER JOIN instance_list ON dynamic_zones.instance_id = instance_list.id
|
||||
INNER JOIN expedition_members ON expedition_members.expedition_id = expeditions.id
|
||||
AND expedition_members.is_current_member = TRUE
|
||||
);
|
||||
|
||||
if (select_expedition_id != 0)
|
||||
{
|
||||
query.append(fmt::format(" WHERE expeditions.id = {};", select_expedition_id));
|
||||
}
|
||||
else
|
||||
{
|
||||
query.append(" ORDER BY expeditions.id;");
|
||||
}
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (results.Success())
|
||||
{
|
||||
uint32_t last_expedition_id = 0;
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
{
|
||||
uint32_t expedition_id = strtoul(row[0], nullptr, 10);
|
||||
|
||||
if (last_expedition_id != expedition_id)
|
||||
{
|
||||
expeditions.emplace_back(
|
||||
static_cast<uint32_t>(strtoul(row[0], nullptr, 10)), // expedition_id
|
||||
static_cast<uint32_t>(strtoul(row[1], nullptr, 10)), // dz_id
|
||||
static_cast<uint32_t>(strtoul(row[2], nullptr, 10)), // dz_instance_id
|
||||
static_cast<uint32_t>(strtoul(row[3], nullptr, 10)), // dz_zone_id
|
||||
static_cast<uint32_t>(strtoul(row[4], nullptr, 10)), // start_time
|
||||
static_cast<uint32_t>(strtoul(row[5], nullptr, 10)), // duration
|
||||
static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) // leader_id
|
||||
);
|
||||
}
|
||||
|
||||
last_expedition_id = expedition_id;
|
||||
|
||||
uint32_t member_id = static_cast<uint32_t>(strtoul(row[7], nullptr, 10));
|
||||
expeditions.back().AddMember(member_id);
|
||||
}
|
||||
}
|
||||
|
||||
return expeditions;
|
||||
}
|
||||
|
||||
Expedition ExpeditionDatabase::LoadExpedition(uint32_t expedition_id)
|
||||
{
|
||||
LogExpeditions("Loading expedition [{}] for world cache", expedition_id);
|
||||
|
||||
Expedition expedition;
|
||||
|
||||
auto expeditions = LoadExpeditions(expedition_id);
|
||||
if (!expeditions.empty())
|
||||
{
|
||||
expedition = expeditions.front();
|
||||
}
|
||||
|
||||
return expedition;
|
||||
}
|
||||
|
||||
void ExpeditionDatabase::DeleteExpeditions(const std::vector<uint32_t>& expedition_ids)
|
||||
{
|
||||
LogExpeditionsDetail("Deleting [{}] expedition(s)", expedition_ids.size());
|
||||
|
||||
std::string expedition_ids_query = fmt::format("{}", fmt::join(expedition_ids, ","));
|
||||
|
||||
if (!expedition_ids_query.empty())
|
||||
{
|
||||
auto query = fmt::format("DELETE FROM expeditions WHERE id IN ({});", expedition_ids_query);
|
||||
database.QueryDatabase(query);
|
||||
|
||||
query = fmt::format("DELETE FROM expedition_members WHERE expedition_id IN ({});", expedition_ids_query);
|
||||
database.QueryDatabase(query);
|
||||
|
||||
query = fmt::format("DELETE FROM expedition_lockouts WHERE expedition_id IN ({});", expedition_ids_query);
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
|
||||
void ExpeditionDatabase::UpdateDzDuration(uint16_t instance_id, uint32_t new_duration)
|
||||
{
|
||||
std::string query = fmt::format(
|
||||
"UPDATE instance_list SET duration = {} WHERE id = {};",
|
||||
new_duration, instance_id
|
||||
);
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
|
||||
void ExpeditionDatabase::UpdateLeaderID(uint32_t expedition_id, uint32_t leader_id)
|
||||
{
|
||||
LogExpeditionsDetail("Updating leader [{}] for expedition [{}]", leader_id, expedition_id);
|
||||
|
||||
auto query = fmt::format(SQL(
|
||||
UPDATE expeditions SET leader_id = {} WHERE id = {};
|
||||
), leader_id, expedition_id);
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
|
||||
void ExpeditionDatabase::MoveMembersToSafeReturn(const std::vector<uint32_t>& expedition_ids)
|
||||
{
|
||||
LogExpeditionsDetail("Moving members from [{}] expedition(s) to safereturn", expedition_ids.size());
|
||||
|
||||
// only offline members still in expired dz zones should be updated here
|
||||
std::string query = fmt::format(SQL(
|
||||
UPDATE character_data
|
||||
INNER JOIN expedition_members ON character_data.id = expedition_members.character_id
|
||||
INNER JOIN expeditions ON expedition_members.expedition_id = expeditions.id
|
||||
INNER JOIN dynamic_zones ON expeditions.dynamic_zone_id = dynamic_zones.id
|
||||
INNER JOIN instance_list ON dynamic_zones.instance_id = instance_list.id
|
||||
AND character_data.zone_instance = instance_list.id
|
||||
AND character_data.zone_id = instance_list.zone
|
||||
SET
|
||||
zone_id = IF(safe_return_zone_id > 0, safe_return_zone_id, zone_id),
|
||||
zone_instance = IF(safe_return_zone_id > 0, 0, zone_instance),
|
||||
x = IF(safe_return_zone_id > 0, safe_return_x, x),
|
||||
y = IF(safe_return_zone_id > 0, safe_return_y, y),
|
||||
z = IF(safe_return_zone_id > 0, safe_return_z, z),
|
||||
heading = IF(safe_return_zone_id > 0, safe_return_heading, heading)
|
||||
WHERE expeditions.id IN ({});
|
||||
), fmt::join(expedition_ids, ","));
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
41
world/expedition_database.h
Normal file
41
world/expedition_database.h
Normal file
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* 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 WORLD_EXPEDITION_DATABASE_H
|
||||
#define WORLD_EXPEDITION_DATABASE_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
class Expedition;
|
||||
|
||||
namespace ExpeditionDatabase
|
||||
{
|
||||
void DeleteExpeditions(const std::vector<uint32_t>& expedition_ids);
|
||||
std::vector<Expedition> LoadExpeditions(uint32_t select_expedition_id = 0);
|
||||
Expedition LoadExpedition(uint32_t expedition_id);
|
||||
void MoveMembersToSafeReturn(const std::vector<uint32_t>& expedition_ids);
|
||||
void PurgeExpiredExpeditions();
|
||||
void PurgeExpiredCharacterLockouts();
|
||||
void UpdateDzDuration(uint16_t instance_id, uint32_t new_duration);
|
||||
void UpdateLeaderID(uint32_t expedition_id, uint32_t leader_id);
|
||||
};
|
||||
|
||||
#endif
|
||||
229
world/expedition_message.cpp
Normal file
229
world/expedition_message.cpp
Normal file
@ -0,0 +1,229 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "expedition.h"
|
||||
#include "expedition_message.h"
|
||||
#include "expedition_state.h"
|
||||
#include "cliententry.h"
|
||||
#include "clientlist.h"
|
||||
#include "zonelist.h"
|
||||
#include "zoneserver.h"
|
||||
#include "../common/servertalk.h"
|
||||
#include <algorithm>
|
||||
|
||||
extern ClientList client_list;
|
||||
extern ZSList zoneserver_list;
|
||||
|
||||
void ExpeditionMessage::HandleZoneMessage(ServerPacket* pack)
|
||||
{
|
||||
switch (pack->opcode)
|
||||
{
|
||||
case ServerOP_ExpeditionChooseNewLeader:
|
||||
{
|
||||
ExpeditionMessage::ChooseNewLeader(pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_ExpeditionCreate:
|
||||
{
|
||||
auto buf = reinterpret_cast<ServerExpeditionID_Struct*>(pack->pBuffer);
|
||||
expedition_state.AddExpedition(buf->expedition_id);
|
||||
zoneserver_list.SendPacket(pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_ExpeditionMemberChange:
|
||||
{
|
||||
auto buf = reinterpret_cast<ServerExpeditionMemberChange_Struct*>(pack->pBuffer);
|
||||
expedition_state.MemberChange(buf->expedition_id, buf->char_id, buf->removed);
|
||||
zoneserver_list.SendPacket(pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_ExpeditionMemberSwap:
|
||||
{
|
||||
auto buf = reinterpret_cast<ServerExpeditionMemberSwap_Struct*>(pack->pBuffer);
|
||||
expedition_state.MemberChange(buf->expedition_id, buf->add_char_id, false);
|
||||
expedition_state.MemberChange(buf->expedition_id, buf->remove_char_id, true);
|
||||
zoneserver_list.SendPacket(pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_ExpeditionMembersRemoved:
|
||||
{
|
||||
auto buf = reinterpret_cast<ServerExpeditionID_Struct*>(pack->pBuffer);
|
||||
expedition_state.RemoveAllMembers(buf->expedition_id);
|
||||
zoneserver_list.SendPacket(pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_ExpeditionGetOnlineMembers:
|
||||
{
|
||||
ExpeditionMessage::GetOnlineMembers(pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_ExpeditionDzAddPlayer:
|
||||
{
|
||||
ExpeditionMessage::AddPlayer(pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_ExpeditionDzMakeLeader:
|
||||
{
|
||||
ExpeditionMessage::MakeLeader(pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_ExpeditionCharacterLockout:
|
||||
{
|
||||
auto buf = reinterpret_cast<ServerExpeditionCharacterLockout_Struct*>(pack->pBuffer);
|
||||
auto cle = client_list.FindCLEByCharacterID(buf->character_id);
|
||||
if (cle && cle->Server())
|
||||
{
|
||||
cle->Server()->SendPacket(pack);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ServerOP_ExpeditionSaveInvite:
|
||||
{
|
||||
ExpeditionMessage::SaveInvite(pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_ExpeditionRequestInvite:
|
||||
{
|
||||
ExpeditionMessage::RequestInvite(pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_ExpeditionSecondsRemaining:
|
||||
{
|
||||
auto buf = reinterpret_cast<ServerExpeditionUpdateDuration_Struct*>(pack->pBuffer);
|
||||
expedition_state.SetSecondsRemaining(buf->expedition_id, buf->new_duration_seconds);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExpeditionMessage::AddPlayer(ServerPacket* pack)
|
||||
{
|
||||
auto buf = reinterpret_cast<ServerDzCommand_Struct*>(pack->pBuffer);
|
||||
|
||||
ClientListEntry* invited_cle = client_list.FindCharacter(buf->target_name);
|
||||
if (invited_cle && invited_cle->Server())
|
||||
{
|
||||
// continue in the add target's zone
|
||||
buf->is_char_online = true;
|
||||
invited_cle->Server()->SendPacket(pack);
|
||||
}
|
||||
else
|
||||
{
|
||||
// add target not online, return to inviter
|
||||
ClientListEntry* inviter_cle = client_list.FindCharacter(buf->requester_name);
|
||||
if (inviter_cle && inviter_cle->Server())
|
||||
{
|
||||
inviter_cle->Server()->SendPacket(pack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExpeditionMessage::MakeLeader(ServerPacket* pack)
|
||||
{
|
||||
auto buf = reinterpret_cast<ServerDzCommandMakeLeader_Struct*>(pack->pBuffer);
|
||||
|
||||
// notify requester (old leader) and new leader of the result
|
||||
ZoneServer* new_leader_zs = nullptr;
|
||||
ClientListEntry* new_leader_cle = client_list.FindCharacter(buf->new_leader_name);
|
||||
if (new_leader_cle && new_leader_cle->Server())
|
||||
{
|
||||
auto expedition = expedition_state.GetExpedition(buf->expedition_id);
|
||||
if (expedition)
|
||||
{
|
||||
buf->is_success = expedition->SetNewLeader(new_leader_cle->CharID());
|
||||
}
|
||||
|
||||
buf->is_online = true;
|
||||
new_leader_zs = new_leader_cle->Server();
|
||||
new_leader_zs->SendPacket(pack);
|
||||
}
|
||||
|
||||
// if old and new leader are in the same zone only send one message
|
||||
ClientListEntry* requester_cle = client_list.FindCLEByCharacterID(buf->requester_id);
|
||||
if (requester_cle && requester_cle->Server() && requester_cle->Server() != new_leader_zs)
|
||||
{
|
||||
requester_cle->Server()->SendPacket(pack);
|
||||
}
|
||||
}
|
||||
|
||||
void ExpeditionMessage::GetOnlineMembers(ServerPacket* pack)
|
||||
{
|
||||
auto buf = reinterpret_cast<ServerExpeditionCharacters_Struct*>(pack->pBuffer);
|
||||
|
||||
// not efficient but only requested during caching
|
||||
char zone_name[64] = {0};
|
||||
std::vector<ClientListEntry*> all_clients;
|
||||
all_clients.reserve(client_list.GetClientCount());
|
||||
client_list.GetClients(zone_name, all_clients);
|
||||
|
||||
for (uint32_t i = 0; i < buf->count; ++i)
|
||||
{
|
||||
auto it = std::find_if(all_clients.begin(), all_clients.end(), [&](const ClientListEntry* cle) {
|
||||
return (cle && cle->CharID() == buf->entries[i].character_id);
|
||||
});
|
||||
|
||||
if (it != all_clients.end())
|
||||
{
|
||||
buf->entries[i].character_zone_id = (*it)->zone();
|
||||
buf->entries[i].character_instance_id = (*it)->instance();
|
||||
buf->entries[i].character_online = true;
|
||||
}
|
||||
}
|
||||
|
||||
zoneserver_list.SendPacket(buf->sender_zone_id, buf->sender_instance_id, pack);
|
||||
}
|
||||
|
||||
void ExpeditionMessage::SaveInvite(ServerPacket* pack)
|
||||
{
|
||||
auto buf = reinterpret_cast<ServerDzCommand_Struct*>(pack->pBuffer);
|
||||
|
||||
ClientListEntry* invited_cle = client_list.FindCharacter(buf->target_name);
|
||||
if (invited_cle)
|
||||
{
|
||||
// store packet on cle and re-send it when client requests it
|
||||
buf->is_char_online = true;
|
||||
pack->opcode = ServerOP_ExpeditionDzAddPlayer;
|
||||
invited_cle->SetPendingExpeditionInvite(pack);
|
||||
}
|
||||
}
|
||||
|
||||
void ExpeditionMessage::RequestInvite(ServerPacket* pack)
|
||||
{
|
||||
auto buf = reinterpret_cast<ServerExpeditionCharacterID_Struct*>(pack->pBuffer);
|
||||
ClientListEntry* cle = client_list.FindCLEByCharacterID(buf->character_id);
|
||||
if (cle)
|
||||
{
|
||||
auto invite_pack = cle->GetPendingExpeditionInvite();
|
||||
if (invite_pack && cle->Server())
|
||||
{
|
||||
cle->Server()->SendPacket(invite_pack.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExpeditionMessage::ChooseNewLeader(ServerPacket* pack)
|
||||
{
|
||||
auto buf = reinterpret_cast<ServerExpeditionID_Struct*>(pack->pBuffer);
|
||||
auto expedition = expedition_state.GetExpedition(buf->expedition_id);
|
||||
if (expedition)
|
||||
{
|
||||
expedition->ChooseNewLeader();
|
||||
}
|
||||
}
|
||||
37
world/expedition_message.h
Normal file
37
world/expedition_message.h
Normal file
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* 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 WORLD_EXPEDITION_MESSAGE_H
|
||||
#define WORLD_EXPEDITION_MESSAGE_H
|
||||
|
||||
class ServerPacket;
|
||||
|
||||
namespace ExpeditionMessage
|
||||
{
|
||||
void AddPlayer(ServerPacket* pack);
|
||||
void ChooseNewLeader(ServerPacket* pack);
|
||||
void GetOnlineMembers(ServerPacket* pack);
|
||||
void HandleZoneMessage(ServerPacket* pack);
|
||||
void MakeLeader(ServerPacket* pack);
|
||||
void RequestInvite(ServerPacket* pack);
|
||||
void SaveInvite(ServerPacket* pack);
|
||||
};
|
||||
|
||||
#endif
|
||||
158
world/expedition_state.cpp
Normal file
158
world/expedition_state.cpp
Normal file
@ -0,0 +1,158 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "expedition_state.h"
|
||||
#include "expedition.h"
|
||||
#include "expedition_database.h"
|
||||
#include "zonelist.h"
|
||||
#include "zoneserver.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include <algorithm>
|
||||
|
||||
extern ZSList zoneserver_list;
|
||||
|
||||
ExpeditionState expedition_state;
|
||||
|
||||
Expedition* ExpeditionState::GetExpedition(uint32_t expedition_id)
|
||||
{
|
||||
auto it = std::find_if(m_expeditions.begin(), m_expeditions.end(),
|
||||
[&](const Expedition& expedition) { return expedition.GetID() == expedition_id; });
|
||||
|
||||
return (it != m_expeditions.end()) ? &(*it) : nullptr;
|
||||
}
|
||||
|
||||
void ExpeditionState::LoadActiveExpeditions()
|
||||
{
|
||||
BenchTimer benchmark;
|
||||
|
||||
m_expeditions = ExpeditionDatabase::LoadExpeditions();
|
||||
|
||||
auto elapsed = benchmark.elapsed();
|
||||
LogExpeditions("World caching [{}] expeditions took [{}s]", m_expeditions.size(), elapsed);
|
||||
}
|
||||
|
||||
void ExpeditionState::AddExpedition(uint32_t expedition_id)
|
||||
{
|
||||
if (expedition_id == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto expedition = ExpeditionDatabase::LoadExpedition(expedition_id);
|
||||
|
||||
if (expedition.IsValid())
|
||||
{
|
||||
auto existing_expedition = GetExpedition(expedition_id);
|
||||
if (!existing_expedition)
|
||||
{
|
||||
m_expeditions.emplace_back(expedition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExpeditionState::RemoveExpedition(uint32_t expedition_id)
|
||||
{
|
||||
m_expeditions.erase(std::remove_if(m_expeditions.begin(), m_expeditions.end(),
|
||||
[&](const Expedition& expedition) {
|
||||
return expedition.GetID() == expedition_id;
|
||||
}
|
||||
), m_expeditions.end());
|
||||
}
|
||||
|
||||
void ExpeditionState::MemberChange(uint32_t expedition_id, uint32_t character_id, bool remove)
|
||||
{
|
||||
auto expedition = GetExpedition(expedition_id);
|
||||
if (expedition)
|
||||
{
|
||||
if (remove) {
|
||||
expedition->RemoveMember(character_id);
|
||||
} else {
|
||||
expedition->AddMember(character_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExpeditionState::RemoveAllMembers(uint32_t expedition_id)
|
||||
{
|
||||
auto expedition = GetExpedition(expedition_id);
|
||||
if (expedition)
|
||||
{
|
||||
expedition->RemoveAllMembers();
|
||||
}
|
||||
}
|
||||
|
||||
void ExpeditionState::SetSecondsRemaining(uint32_t expedition_id, uint32_t seconds_remaining)
|
||||
{
|
||||
auto expedition = GetExpedition(expedition_id);
|
||||
if (expedition)
|
||||
{
|
||||
expedition->UpdateDzSecondsRemaining(seconds_remaining);
|
||||
}
|
||||
}
|
||||
|
||||
void ExpeditionState::Process()
|
||||
{
|
||||
if (!m_process_throttle_timer.Check())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<uint32_t> expedition_ids;
|
||||
|
||||
for (auto it = m_expeditions.begin(); it != m_expeditions.end();)
|
||||
{
|
||||
bool is_deleted = false;
|
||||
|
||||
if (it->IsEmpty() || it->IsExpired())
|
||||
{
|
||||
// don't delete expedition until its dz instance is empty. this prevents
|
||||
// an exploit where all members leave expedition and complete an event
|
||||
// before being kicked from removal timer. the lockout could never be
|
||||
// applied because the zone expedition cache was already invalidated.
|
||||
auto dz_zoneserver = zoneserver_list.FindByInstanceID(it->GetInstanceID());
|
||||
if (!dz_zoneserver || dz_zoneserver->NumPlayers() == 0)
|
||||
{
|
||||
LogExpeditions("Expedition [{}] expired or empty, notifying zones and deleting", it->GetID());
|
||||
expedition_ids.emplace_back(it->GetID());
|
||||
it->SendZonesExpeditionDeleted();
|
||||
is_deleted = true;
|
||||
}
|
||||
|
||||
if (it->IsEmpty() && !it->IsPendingDelete() && RuleB(Expedition, EmptyDzShutdownEnabled))
|
||||
{
|
||||
it->UpdateDzSecondsRemaining(RuleI(Expedition, EmptyDzShutdownDelaySeconds));
|
||||
}
|
||||
|
||||
it->SetPendingDelete(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
it->CheckExpireWarning();
|
||||
}
|
||||
|
||||
it = is_deleted ? m_expeditions.erase(it) : it + 1;
|
||||
}
|
||||
|
||||
if (!expedition_ids.empty())
|
||||
{
|
||||
ExpeditionDatabase::MoveMembersToSafeReturn(expedition_ids);
|
||||
ExpeditionDatabase::DeleteExpeditions(expedition_ids);
|
||||
}
|
||||
}
|
||||
50
world/expedition_state.h
Normal file
50
world/expedition_state.h
Normal file
@ -0,0 +1,50 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* 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 WORLD_EXPEDITION_STATE_H
|
||||
#define WORLD_EXPEDITION_STATE_H
|
||||
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/timer.h"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
extern class ExpeditionState expedition_state;
|
||||
|
||||
class Expedition;
|
||||
|
||||
class ExpeditionState
|
||||
{
|
||||
public:
|
||||
void AddExpedition(uint32_t expedition_id);
|
||||
Expedition* GetExpedition(uint32_t expedition_id);
|
||||
void LoadActiveExpeditions();
|
||||
void MemberChange(uint32_t expedition_id, uint32_t character_id, bool remove);
|
||||
void Process();
|
||||
void RemoveAllMembers(uint32_t expedition_id);
|
||||
void RemoveExpedition(uint32_t expedition_id);
|
||||
void SetSecondsRemaining(uint32_t expedition_id, uint32_t seconds_remaining);
|
||||
|
||||
private:
|
||||
std::vector<Expedition> m_expeditions;
|
||||
Timer m_process_throttle_timer{static_cast<uint32_t>(RuleI(Expedition, WorldExpeditionProcessRateMS))};
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -88,6 +88,8 @@ union semun {
|
||||
#include "queryserv.h"
|
||||
#include "web_interface.h"
|
||||
#include "console.h"
|
||||
#include "expedition_database.h"
|
||||
#include "expedition_state.h"
|
||||
|
||||
#include "../common/net/servertalk_server.h"
|
||||
#include "../zone/data_bucket.h"
|
||||
@ -423,12 +425,19 @@ int main(int argc, char** argv) {
|
||||
|
||||
adventure_manager.LoadLeaderboardInfo();
|
||||
|
||||
LogInfo("Purging expired expeditions");
|
||||
ExpeditionDatabase::PurgeExpiredExpeditions();
|
||||
ExpeditionDatabase::PurgeExpiredCharacterLockouts();
|
||||
|
||||
LogInfo("Purging expired instances");
|
||||
database.PurgeExpiredInstances();
|
||||
|
||||
Timer PurgeInstanceTimer(450000);
|
||||
PurgeInstanceTimer.Start(450000);
|
||||
|
||||
LogInfo("Loading active expeditions");
|
||||
expedition_state.LoadActiveExpeditions();
|
||||
|
||||
LogInfo("Loading char create info");
|
||||
content_db.LoadCharacterCreateAllocations();
|
||||
content_db.LoadCharacterCreateCombos();
|
||||
@ -599,6 +608,7 @@ int main(int argc, char** argv) {
|
||||
if (PurgeInstanceTimer.Check()) {
|
||||
database.PurgeExpiredInstances();
|
||||
database.PurgeAllDeletedDataBuckets();
|
||||
ExpeditionDatabase::PurgeExpiredCharacterLockouts();
|
||||
}
|
||||
|
||||
if (EQTimeTimer.Check()) {
|
||||
@ -614,6 +624,7 @@ int main(int argc, char** argv) {
|
||||
launcher_list.Process();
|
||||
LFPGroupList.Process();
|
||||
adventure_manager.Process();
|
||||
expedition_state.Process();
|
||||
|
||||
if (InterserverTimer.Check()) {
|
||||
InterserverTimer.Start();
|
||||
|
||||
@ -36,6 +36,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "ucs.h"
|
||||
#include "queryserv.h"
|
||||
#include "world_store.h"
|
||||
#include "expedition_message.h"
|
||||
|
||||
extern ClientList client_list;
|
||||
extern GroupLFPList LFPGroupList;
|
||||
@ -276,6 +277,14 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||
break;
|
||||
}
|
||||
|
||||
case ServerOP_ChangeGroupLeader: {
|
||||
if (pack->size != sizeof(ServerGroupLeader_Struct)) {
|
||||
break;
|
||||
}
|
||||
zoneserver_list.SendPacket(pack); //bounce it to all zones
|
||||
break;
|
||||
}
|
||||
|
||||
case ServerOP_RaidAdd: {
|
||||
if (pack->size != sizeof(ServerRaidGeneralAction_Struct))
|
||||
break;
|
||||
@ -1355,6 +1364,52 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||
cle->ProcessTellQueue();
|
||||
break;
|
||||
}
|
||||
case ServerOP_CZClientMessageString:
|
||||
{
|
||||
auto buf = reinterpret_cast<CZClientMessageString_Struct*>(pack->pBuffer);
|
||||
client_list.SendPacket(buf->character_name, pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_ExpeditionLockout:
|
||||
case ServerOP_ExpeditionLockoutDuration:
|
||||
case ServerOP_ExpeditionLockState:
|
||||
case ServerOP_ExpeditionMemberStatus:
|
||||
case ServerOP_ExpeditionReplayOnJoin:
|
||||
case ServerOP_ExpeditionDzCompass:
|
||||
case ServerOP_ExpeditionDzSafeReturn:
|
||||
case ServerOP_ExpeditionDzZoneIn:
|
||||
case ServerOP_ExpeditionExpireWarning:
|
||||
{
|
||||
zoneserver_list.SendPacket(pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_ExpeditionChooseNewLeader:
|
||||
case ServerOP_ExpeditionCreate:
|
||||
case ServerOP_ExpeditionGetOnlineMembers:
|
||||
case ServerOP_ExpeditionMemberChange:
|
||||
case ServerOP_ExpeditionMemberSwap:
|
||||
case ServerOP_ExpeditionMembersRemoved:
|
||||
case ServerOP_ExpeditionDzAddPlayer:
|
||||
case ServerOP_ExpeditionDzMakeLeader:
|
||||
case ServerOP_ExpeditionCharacterLockout:
|
||||
case ServerOP_ExpeditionSaveInvite:
|
||||
case ServerOP_ExpeditionRequestInvite:
|
||||
case ServerOP_ExpeditionSecondsRemaining:
|
||||
{
|
||||
ExpeditionMessage::HandleZoneMessage(pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_DzCharacterChange:
|
||||
case ServerOP_DzRemoveAllCharacters:
|
||||
{
|
||||
auto buf = reinterpret_cast<ServerDzCharacter_Struct*>(pack->pBuffer);
|
||||
ZoneServer* instance_zs = zoneserver_list.FindByInstanceID(buf->instance_id);
|
||||
if (instance_zs)
|
||||
{
|
||||
instance_zs->SendPacket(pack);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
LogInfo("Unknown ServerOPcode from zone {:#04x}, size [{}]", pack->opcode, pack->size);
|
||||
|
||||
@ -22,6 +22,7 @@ SET(zone_sources
|
||||
corpse.cpp
|
||||
data_bucket.cpp
|
||||
doors.cpp
|
||||
dynamiczone.cpp
|
||||
effects.cpp
|
||||
embparser.cpp
|
||||
embparser_api.cpp
|
||||
@ -30,6 +31,10 @@ SET(zone_sources
|
||||
encounter.cpp
|
||||
entity.cpp
|
||||
exp.cpp
|
||||
expedition.cpp
|
||||
expedition_database.cpp
|
||||
expedition_lockout_timer.cpp
|
||||
expedition_request.cpp
|
||||
fastmath.cpp
|
||||
fearpath.cpp
|
||||
forage.cpp
|
||||
@ -48,6 +53,7 @@ SET(zone_sources
|
||||
lua_encounter.cpp
|
||||
lua_entity.cpp
|
||||
lua_entity_list.cpp
|
||||
lua_expedition.cpp
|
||||
lua_general.cpp
|
||||
lua_group.cpp
|
||||
lua_hate_list.cpp
|
||||
@ -100,6 +106,7 @@ SET(zone_sources
|
||||
perl_client.cpp
|
||||
perl_doors.cpp
|
||||
perl_entity.cpp
|
||||
perl_expedition.cpp
|
||||
perl_groups.cpp
|
||||
perl_hateentry.cpp
|
||||
perl_mob.cpp
|
||||
@ -165,6 +172,7 @@ SET(zone_headers
|
||||
corpse.h
|
||||
data_bucket.h
|
||||
doors.h
|
||||
dynamiczone.h
|
||||
embparser.h
|
||||
embperl.h
|
||||
embxs.h
|
||||
@ -172,6 +180,10 @@ SET(zone_headers
|
||||
entity.h
|
||||
errmsg.h
|
||||
event_codes.h
|
||||
expedition.h
|
||||
expedition_database.h
|
||||
expedition_lockout_timer.h
|
||||
expedition_request.h
|
||||
fastmath.h
|
||||
forage.h
|
||||
global_loot_manager.h
|
||||
@ -187,6 +199,7 @@ SET(zone_headers
|
||||
lua_encounter.h
|
||||
lua_entity.h
|
||||
lua_entity_list.h
|
||||
lua_expedition.h
|
||||
lua_general.h
|
||||
lua_group.h
|
||||
lua_hate_list.h
|
||||
|
||||
@ -468,6 +468,12 @@ bool Mob::IsAttackAllowed(Mob *target, bool isSpellAttack)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (target->GetSpecialAbility(IMMUNE_DAMAGE_CLIENT) && IsClient())
|
||||
return false;
|
||||
|
||||
if (target->GetSpecialAbility(IMMUNE_DAMAGE_NPC) && IsNPC())
|
||||
return false;
|
||||
|
||||
// can't damage own pet (applies to everthing)
|
||||
Mob *target_owner = target->GetOwner();
|
||||
Mob *our_owner = GetOwner();
|
||||
|
||||
@ -2247,7 +2247,7 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, EQ::skills::SkillTy
|
||||
d->spawn_id = GetID();
|
||||
d->killer_id = killer_mob ? killer_mob->GetID() : 0;
|
||||
d->bindzoneid = 0;
|
||||
d->spell_id = spell == SPELL_UNKNOWN ? 0xffffffff : spell;
|
||||
d->spell_id = 0xffffffff; // Sending spell was causing extra DoT land msg
|
||||
d->attack_skill = SkillDamageTypes[attack_skill];
|
||||
d->damage = damage;
|
||||
app->priority = 6;
|
||||
@ -2667,6 +2667,12 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
|
||||
if (IsFamiliar() || GetSpecialAbility(IMMUNE_AGGRO))
|
||||
return;
|
||||
|
||||
if (GetSpecialAbility(IMMUNE_AGGRO_NPC) && other->IsNPC())
|
||||
return;
|
||||
|
||||
if (GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && other->IsClient())
|
||||
return;
|
||||
|
||||
if (spell_id != SPELL_UNKNOWN && NoDetrimentalSpellAggro(spell_id))
|
||||
return;
|
||||
|
||||
@ -2758,8 +2764,11 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
|
||||
else {
|
||||
// cb:2007-08-17
|
||||
// owner must get on list, but he's not actually gained any hate yet
|
||||
if (!owner->GetSpecialAbility(IMMUNE_AGGRO))
|
||||
{
|
||||
if (
|
||||
!owner->GetSpecialAbility(IMMUNE_AGGRO) &&
|
||||
!(this->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && owner->IsClient()) &&
|
||||
!(this->GetSpecialAbility(IMMUNE_AGGRO_NPC) && owner->IsNPC())
|
||||
) {
|
||||
if (owner->IsClient() && !CheckAggro(owner))
|
||||
owner->CastToClient()->AddAutoXTarget(this);
|
||||
hate_list.AddEntToHateList(owner, 0, 0, false, !iBuffTic);
|
||||
@ -2768,12 +2777,24 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
|
||||
}
|
||||
|
||||
if (mypet && !mypet->IsHeld() && !mypet->IsPetStop()) { // I have a pet, add other to it
|
||||
if (!mypet->IsFamiliar() && !mypet->GetSpecialAbility(IMMUNE_AGGRO))
|
||||
if (
|
||||
!mypet->IsFamiliar() &&
|
||||
!mypet->GetSpecialAbility(IMMUNE_AGGRO) &&
|
||||
!(mypet->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && this->IsClient()) &&
|
||||
!(mypet->GetSpecialAbility(IMMUNE_AGGRO_NPC) && this->IsNPC())
|
||||
) {
|
||||
mypet->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
|
||||
}
|
||||
}
|
||||
else if (myowner) { // I am a pet, add other to owner if it's NPC/LD
|
||||
if (myowner->IsAIControlled() && !myowner->GetSpecialAbility(IMMUNE_AGGRO))
|
||||
if (
|
||||
myowner->IsAIControlled() &&
|
||||
!myowner->GetSpecialAbility(IMMUNE_AGGRO) &&
|
||||
!(this->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && myowner->IsClient()) &&
|
||||
!(this->GetSpecialAbility(IMMUNE_AGGRO_NPC) && myowner->IsNPC())
|
||||
) {
|
||||
myowner->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
|
||||
}
|
||||
}
|
||||
|
||||
if (other->GetTempPetCount())
|
||||
@ -3467,8 +3488,19 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
|
||||
// pets that have GHold will never automatically add NPCs
|
||||
// pets that have Hold and no Focus will add NPCs if they're engaged
|
||||
// pets that have Hold and Focus will not add NPCs
|
||||
if (pet && !pet->IsFamiliar() && !pet->GetSpecialAbility(IMMUNE_AGGRO) && !pet->IsEngaged() && attacker && attacker != this && !attacker->IsCorpse() && !pet->IsGHeld() && !attacker->IsTrap())
|
||||
{
|
||||
if (
|
||||
pet &&
|
||||
!pet->IsFamiliar() &&
|
||||
!pet->GetSpecialAbility(IMMUNE_AGGRO) &&
|
||||
!pet->IsEngaged() &&
|
||||
attacker &&
|
||||
!(pet->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && attacker->IsClient()) &&
|
||||
!(pet->GetSpecialAbility(IMMUNE_AGGRO_NPC) && attacker->IsNPC()) &&
|
||||
attacker != this &&
|
||||
!attacker->IsCorpse() &&
|
||||
!pet->IsGHeld() &&
|
||||
!attacker->IsTrap()
|
||||
) {
|
||||
if (!pet->IsHeld()) {
|
||||
LogAggro("Sending pet [{}] into battle due to attack", pet->GetName());
|
||||
if (IsClient()) {
|
||||
|
||||
@ -2211,12 +2211,12 @@ bool Bot::Process()
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mob_scan_close.Check()) {
|
||||
if (mob_close_scan_timer.Check()) {
|
||||
LogAIScanClose(
|
||||
"is_moving [{}] bot [{}] timer [{}]",
|
||||
moving ? "true" : "false",
|
||||
GetCleanName(),
|
||||
mob_scan_close.GetDuration()
|
||||
mob_close_scan_timer.GetDuration()
|
||||
);
|
||||
|
||||
entity_list.ScanCloseClientMobs(close_mobs, this);
|
||||
|
||||
766
zone/client.cpp
766
zone/client.cpp
@ -40,6 +40,10 @@ extern volatile bool RunLoops;
|
||||
#include "../common/data_verification.h"
|
||||
#include "../common/profanity_manager.h"
|
||||
#include "data_bucket.h"
|
||||
#include "expedition.h"
|
||||
#include "expedition_database.h"
|
||||
#include "expedition_lockout_timer.h"
|
||||
#include "expedition_request.h"
|
||||
#include "position.h"
|
||||
#include "worldserver.h"
|
||||
#include "zonedb.h"
|
||||
@ -139,7 +143,7 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
endupkeep_timer(1000),
|
||||
forget_timer(0),
|
||||
autosave_timer(RuleI(Character, AutosaveIntervalS) * 1000),
|
||||
client_scan_npc_aggro_timer(RuleI(Aggro, ClientAggroCheckInterval) * 1000),
|
||||
client_scan_npc_aggro_timer(RuleI(Aggro, ClientAggroCheckIdleInterval)),
|
||||
client_zone_wide_full_position_update_timer(5 * 60 * 1000),
|
||||
tribute_timer(Tribute_duration),
|
||||
proximity_timer(ClientProximity_interval),
|
||||
@ -264,6 +268,7 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
InitializeMercInfo();
|
||||
SetMerc(0);
|
||||
if (RuleI(World, PVPMinLevel) > 0 && level >= RuleI(World, PVPMinLevel) && m_pp.pvp == 0) SetPVP(true, false);
|
||||
dynamiczone_removal_timer.Disable();
|
||||
|
||||
//for good measure:
|
||||
memset(&m_pp, 0, sizeof(m_pp));
|
||||
@ -350,8 +355,8 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
/**
|
||||
* GM
|
||||
*/
|
||||
display_mob_info_window = true;
|
||||
dev_tools_window_enabled = true;
|
||||
SetDisplayMobInfoWindow(true);
|
||||
SetDevToolsEnabled(true);
|
||||
|
||||
#ifdef BOTS
|
||||
bot_owner_options[booDeathMarquee] = false;
|
||||
@ -2428,13 +2433,17 @@ bool Client::CheckIncreaseSkill(EQ::skills::SkillType skillid, Mob *against_who,
|
||||
char buffer[24] = { 0 };
|
||||
snprintf(buffer, 23, "%d %d", skillid, skillval);
|
||||
parse->EventPlayer(EVENT_USE_SKILL, this, buffer, 0);
|
||||
if(against_who)
|
||||
{
|
||||
if(against_who->GetSpecialAbility(IMMUNE_AGGRO) || against_who->IsClient() ||
|
||||
GetLevelCon(against_who->GetLevel()) == CON_GRAY)
|
||||
{
|
||||
if (against_who) {
|
||||
if (
|
||||
against_who->GetSpecialAbility(IMMUNE_AGGRO) ||
|
||||
against_who->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) ||
|
||||
against_who->IsClient() ||
|
||||
GetLevelCon(against_who->GetLevel()) == CON_GRAY
|
||||
) {
|
||||
//false by default
|
||||
if( !mod_can_increase_skill(skillid, against_who) ) { return(false); }
|
||||
if (!mod_can_increase_skill(skillid, against_who)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3201,6 +3210,27 @@ void Client::MessageString(uint32 type, uint32 string_id, const char* message1,
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Client::MessageString(const CZClientMessageString_Struct* msg)
|
||||
{
|
||||
if (msg)
|
||||
{
|
||||
if (msg->args_size == 0)
|
||||
{
|
||||
MessageString(msg->chat_type, msg->string_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t outsize = sizeof(FormattedMessage_Struct) + msg->args_size;
|
||||
auto outapp = std::unique_ptr<EQApplicationPacket>(new EQApplicationPacket(OP_FormattedMessage, outsize));
|
||||
auto outbuf = reinterpret_cast<FormattedMessage_Struct*>(outapp->pBuffer);
|
||||
outbuf->string_id = msg->string_id;
|
||||
outbuf->type = msg->chat_type;
|
||||
memcpy(outbuf->message, msg->args, msg->args_size);
|
||||
QueuePacket(outapp.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// helper function, returns true if we should see the message
|
||||
bool Client::FilteredMessageCheck(Mob *sender, eqFilterType filter)
|
||||
{
|
||||
@ -3397,6 +3427,13 @@ void Client::LinkDead()
|
||||
if(raid){
|
||||
raid->MemberZoned(this);
|
||||
}
|
||||
|
||||
Expedition* expedition = GetExpedition();
|
||||
if (expedition)
|
||||
{
|
||||
expedition->SetMemberStatus(this, ExpeditionMemberStatus::LinkDead);
|
||||
}
|
||||
|
||||
// save_timer.Start(2500);
|
||||
linkdead_timer.Start(RuleI(Zone,ClientLinkdeadMS));
|
||||
SendAppearancePacket(AT_Linkdead, 1);
|
||||
@ -4725,6 +4762,12 @@ void Client::IncrementAggroCount(bool raid_target)
|
||||
|
||||
uint32 newtimer = raid_target ? RuleI(Character, RestRegenRaidTimeToActivate) : RuleI(Character, RestRegenTimeToActivate);
|
||||
|
||||
// When our aggro count is 1 here, we are exiting rest state. We need to pause our current timer, if we have time remaining
|
||||
// We should not actually have to do anything to the Timer object since the AggroCount counter blocks it from being checked
|
||||
// and will have it's timer changed when we exit combat so let's not do any extra work
|
||||
if (AggroCount == 1 && rest_timer.GetRemainingTime()) // the Client::rest_timer is never disabled, so don't need to check
|
||||
m_pp.RestTimer = std::max(1u, rest_timer.GetRemainingTime() / 1000); // I guess round up?
|
||||
|
||||
// save the new timer if it's higher
|
||||
m_pp.RestTimer = std::max(m_pp.RestTimer, newtimer);
|
||||
|
||||
@ -4734,10 +4777,6 @@ void Client::IncrementAggroCount(bool raid_target)
|
||||
if(AggroCount > 1)
|
||||
return;
|
||||
|
||||
// Pause the rest timer, it's possible the new timer is a non-raid timer we're currently ticking down on a raid timer
|
||||
if (AggroCount == 1)
|
||||
m_pp.RestTimer = std::max(m_pp.RestTimer, rest_timer.GetRemainingTime() / 1000);
|
||||
|
||||
if (ClientVersion() >= EQ::versions::ClientVersion::SoF) {
|
||||
auto outapp = new EQApplicationPacket(OP_RestState, 1);
|
||||
char *Buffer = (char *)outapp->pBuffer;
|
||||
@ -5743,6 +5782,18 @@ void Client::AddCrystals(uint32 Radiant, uint32 Ebon)
|
||||
SendCrystalCounts();
|
||||
}
|
||||
|
||||
void Client::SetEbonCrystals(uint32 value) {
|
||||
m_pp.currentEbonCrystals = value;
|
||||
SaveCurrency();
|
||||
SendCrystalCounts();
|
||||
}
|
||||
|
||||
void Client::SetRadiantCrystals(uint32 value) {
|
||||
m_pp.currentRadCrystals = value;
|
||||
SaveCurrency();
|
||||
SendCrystalCounts();
|
||||
}
|
||||
|
||||
// Processes a client request to inspect a SoF+ client's equipment.
|
||||
void Client::ProcessInspectRequest(Client* requestee, Client* requester) {
|
||||
if(requestee && requester) {
|
||||
@ -6110,21 +6161,19 @@ void Client::CheckEmoteHail(Mob *target, const char* message)
|
||||
|
||||
void Client::MarkSingleCompassLoc(float in_x, float in_y, float in_z, uint8 count)
|
||||
{
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_DzCompass, sizeof(ExpeditionInfo_Struct) +
|
||||
sizeof(ExpeditionCompassEntry_Struct) * count);
|
||||
ExpeditionCompass_Struct *ecs = (ExpeditionCompass_Struct*)outapp->pBuffer;
|
||||
//ecs->clientid = GetID();
|
||||
ecs->count = count;
|
||||
|
||||
if (count) {
|
||||
ecs->entries[0].x = in_x;
|
||||
ecs->entries[0].y = in_y;
|
||||
ecs->entries[0].z = in_z;
|
||||
if (count == 0)
|
||||
{
|
||||
m_has_quest_compass = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_has_quest_compass = true;
|
||||
m_quest_compass.x = in_x;
|
||||
m_quest_compass.y = in_y;
|
||||
m_quest_compass.z = in_z;
|
||||
}
|
||||
|
||||
FastQueuePacket(&outapp);
|
||||
safe_delete(outapp);
|
||||
SendDzCompassUpdate();
|
||||
}
|
||||
|
||||
void Client::SendZonePoints()
|
||||
@ -8617,7 +8666,7 @@ void Client::QuestReward(Mob* target, uint32 copper, uint32 silver, uint32 gold,
|
||||
AddMoneyToPP(copper, silver, gold, platinum, false);
|
||||
|
||||
if (itemid > 0)
|
||||
SummonItem(itemid, 0, 0, 0, 0, 0, 0, false, EQ::invslot::slotCursor);
|
||||
SummonItem(itemid, -1, 0, 0, 0, 0, 0, false, EQ::invslot::slotCursor);
|
||||
|
||||
if (faction)
|
||||
{
|
||||
@ -9169,17 +9218,14 @@ void Client::SetDisplayMobInfoWindow(bool display_mob_info_window)
|
||||
Client::display_mob_info_window = display_mob_info_window;
|
||||
}
|
||||
|
||||
bool Client::IsDevToolsWindowEnabled() const
|
||||
bool Client::IsDevToolsEnabled() const
|
||||
{
|
||||
return dev_tools_window_enabled;
|
||||
return dev_tools_enabled && RuleB(World, EnableDevTools);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param in_dev_tools_window_enabled
|
||||
*/
|
||||
void Client::SetDevToolsWindowEnabled(bool in_dev_tools_window_enabled)
|
||||
void Client::SetDevToolsEnabled(bool in_dev_tools_enabled)
|
||||
{
|
||||
Client::dev_tools_window_enabled = in_dev_tools_window_enabled;
|
||||
Client::dev_tools_enabled = in_dev_tools_enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -9388,7 +9434,7 @@ void Client::ShowDevToolsMenu()
|
||||
std::string menu_commands_search;
|
||||
std::string menu_commands_show;
|
||||
std::string reload_commands_show;
|
||||
std::string window_toggle_command;
|
||||
std::string devtools_toggle;
|
||||
|
||||
/**
|
||||
* Search entity commands
|
||||
@ -9423,9 +9469,9 @@ void Client::ShowDevToolsMenu()
|
||||
/**
|
||||
* Show window status
|
||||
*/
|
||||
window_toggle_command = "Disabled [" + EQ::SayLinkEngine::GenerateQuestSaylink("#devtools enable_window", false, "Enable") + "] ";
|
||||
if (IsDevToolsWindowEnabled()) {
|
||||
window_toggle_command = "Enabled [" + EQ::SayLinkEngine::GenerateQuestSaylink("#devtools disable_window", false, "Disable") + "] ";
|
||||
devtools_toggle = "Disabled [" + EQ::SayLinkEngine::GenerateQuestSaylink("#devtools enable", false, "Enable") + "] ";
|
||||
if (IsDevToolsEnabled()) {
|
||||
devtools_toggle = "Enabled [" + EQ::SayLinkEngine::GenerateQuestSaylink("#devtools disable", false, "Disable") + "] ";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -9433,8 +9479,8 @@ void Client::ShowDevToolsMenu()
|
||||
*/
|
||||
SendChatLineBreak();
|
||||
Message(
|
||||
Chat::White, "| [Devtools] Window %s Show this menu with %s | Current expansion [%s]",
|
||||
window_toggle_command.c_str(),
|
||||
Chat::White, "| [Devtools] %s Show this menu with %s | Current expansion [%s]",
|
||||
devtools_toggle.c_str(),
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink("#dev", false, "#dev").c_str(),
|
||||
content_service.GetCurrentExpansionName().c_str()
|
||||
);
|
||||
@ -9448,3 +9494,643 @@ void Client::ShowDevToolsMenu()
|
||||
void Client::SendChatLineBreak(uint16 color) {
|
||||
Message(color, "------------------------------------------------");
|
||||
}
|
||||
|
||||
void Client::SendCrossZoneMessage(
|
||||
Client* client, const std::string& character_name, uint16_t chat_type, const std::string& message)
|
||||
{
|
||||
// if client is null, falls back to sending a cross zone message by name
|
||||
if (!client && !character_name.empty())
|
||||
{
|
||||
client = entity_list.GetClientByName(character_name.c_str());
|
||||
}
|
||||
|
||||
if (client)
|
||||
{
|
||||
client->Message(chat_type, message.c_str());
|
||||
}
|
||||
else if (!character_name.empty() && !message.empty())
|
||||
{
|
||||
uint32_t pack_size = sizeof(CZMessagePlayer_Struct);
|
||||
auto pack = std::unique_ptr<ServerPacket>(new ServerPacket(ServerOP_CZMessagePlayer, pack_size));
|
||||
auto buf = reinterpret_cast<CZMessagePlayer_Struct*>(pack->pBuffer);
|
||||
buf->type = chat_type;
|
||||
strn0cpy(buf->character_name, character_name.c_str(), sizeof(buf->character_name));
|
||||
strn0cpy(buf->message, message.c_str(), sizeof(buf->message));
|
||||
|
||||
worldserver.SendPacket(pack.get());
|
||||
}
|
||||
}
|
||||
|
||||
void Client::SendCrossZoneMessageString(
|
||||
Client* client, const std::string& character_name, uint16_t chat_type,
|
||||
uint32_t string_id, const std::initializer_list<std::string>& arguments)
|
||||
{
|
||||
// if client is null, falls back to sending a cross zone message by name
|
||||
if (!client && !character_name.empty()) // double check client isn't in this zone
|
||||
{
|
||||
client = entity_list.GetClientByName(character_name.c_str());
|
||||
}
|
||||
|
||||
if (!client && character_name.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SerializeBuffer argument_buffer;
|
||||
for (const auto& argument : arguments)
|
||||
{
|
||||
argument_buffer.WriteString(argument);
|
||||
}
|
||||
|
||||
uint32_t args_size = static_cast<uint32_t>(argument_buffer.size());
|
||||
uint32_t pack_size = sizeof(CZClientMessageString_Struct) + args_size;
|
||||
auto pack = std::unique_ptr<ServerPacket>(new ServerPacket(ServerOP_CZClientMessageString, pack_size));
|
||||
auto buf = reinterpret_cast<CZClientMessageString_Struct*>(pack->pBuffer);
|
||||
buf->string_id = string_id;
|
||||
buf->chat_type = chat_type;
|
||||
strn0cpy(buf->character_name, character_name.c_str(), sizeof(buf->character_name));
|
||||
buf->args_size = args_size;
|
||||
memcpy(buf->args, argument_buffer.buffer(), argument_buffer.size());
|
||||
|
||||
if (client)
|
||||
{
|
||||
client->MessageString(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
worldserver.SendPacket(pack.get());
|
||||
}
|
||||
}
|
||||
|
||||
void Client::UpdateExpeditionInfoAndLockouts()
|
||||
{
|
||||
// this is processed by client after entering a zone
|
||||
SendDzCompassUpdate();
|
||||
|
||||
m_expedition_lockouts = ExpeditionDatabase::LoadCharacterLockouts(CharacterID());
|
||||
|
||||
auto expedition = GetExpedition();
|
||||
if (expedition)
|
||||
{
|
||||
expedition->SendClientExpeditionInfo(this);
|
||||
|
||||
// live synchronizes lockouts obtained during the active expedition to
|
||||
// members once they zone into the expedition's dynamic zone instance
|
||||
if (expedition->GetDynamicZone().IsCurrentZoneDzInstance())
|
||||
{
|
||||
expedition->SyncCharacterLockouts(CharacterID(), m_expedition_lockouts);
|
||||
expedition->SetMemberStatus(this, ExpeditionMemberStatus::InDynamicZone);
|
||||
}
|
||||
else
|
||||
{
|
||||
expedition->SetMemberStatus(this, ExpeditionMemberStatus::Online);
|
||||
}
|
||||
}
|
||||
|
||||
SendExpeditionLockoutTimers();
|
||||
|
||||
// ask world for any pending invite we saved from a previous zone
|
||||
RequestPendingExpeditionInvite();
|
||||
}
|
||||
|
||||
Expedition* Client::CreateExpedition(DynamicZone& dz_instance, ExpeditionRequest& request)
|
||||
{
|
||||
return Expedition::TryCreate(this, dz_instance, request);
|
||||
}
|
||||
|
||||
Expedition* Client::CreateExpedition(
|
||||
const std::string& zone_name, uint32 version, uint32 duration, const std::string& expedition_name,
|
||||
uint32 min_players, uint32 max_players, bool disable_messages)
|
||||
{
|
||||
DynamicZone dz_instance{ zone_name, version, duration, DynamicZoneType::Expedition };
|
||||
ExpeditionRequest request{ expedition_name, min_players, max_players, disable_messages };
|
||||
return Expedition::TryCreate(this, dz_instance, request);
|
||||
}
|
||||
|
||||
Expedition* Client::GetExpedition() const
|
||||
{
|
||||
if (zone && m_expedition_id)
|
||||
{
|
||||
auto expedition_cache_iter = zone->expedition_cache.find(m_expedition_id);
|
||||
if (expedition_cache_iter != zone->expedition_cache.end())
|
||||
{
|
||||
return expedition_cache_iter->second.get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Client::AddExpeditionLockout(const ExpeditionLockoutTimer& lockout, bool update_db)
|
||||
{
|
||||
// todo: support for account based lockouts like live AoC expeditions
|
||||
|
||||
// if client already has this lockout, we're replacing it with the new one
|
||||
m_expedition_lockouts.erase(std::remove_if(m_expedition_lockouts.begin(), m_expedition_lockouts.end(),
|
||||
[&](const ExpeditionLockoutTimer& existing_lockout) {
|
||||
return existing_lockout.IsSameLockout(lockout);
|
||||
}
|
||||
), m_expedition_lockouts.end());
|
||||
|
||||
m_expedition_lockouts.emplace_back(lockout);
|
||||
|
||||
if (update_db) // for quest api
|
||||
{
|
||||
ExpeditionDatabase::InsertCharacterLockouts(CharacterID(), { lockout });
|
||||
}
|
||||
|
||||
SendExpeditionLockoutTimers();
|
||||
}
|
||||
|
||||
void Client::AddNewExpeditionLockout(
|
||||
const std::string& expedition_name, const std::string& event_name, uint32_t seconds, std::string uuid)
|
||||
{
|
||||
auto lockout = ExpeditionLockoutTimer::CreateLockout(expedition_name, event_name, seconds, uuid);
|
||||
AddExpeditionLockout(lockout, true);
|
||||
}
|
||||
|
||||
void Client::AddExpeditionLockoutDuration(
|
||||
const std::string& expedition_name, const std::string& event_name, int seconds,
|
||||
const std::string& uuid, bool update_db)
|
||||
{
|
||||
auto it = std::find_if(m_expedition_lockouts.begin(), m_expedition_lockouts.end(),
|
||||
[&](const ExpeditionLockoutTimer& lockout) {
|
||||
return lockout.IsSameLockout(expedition_name, event_name);
|
||||
});
|
||||
|
||||
if (it != m_expedition_lockouts.end())
|
||||
{
|
||||
it->AddLockoutTime(seconds);
|
||||
|
||||
if (!uuid.empty())
|
||||
{
|
||||
it->SetUUID(uuid);
|
||||
}
|
||||
|
||||
if (update_db)
|
||||
{
|
||||
ExpeditionDatabase::InsertCharacterLockouts(CharacterID(), { *it });
|
||||
}
|
||||
|
||||
SendExpeditionLockoutTimers();
|
||||
}
|
||||
else if (seconds > 0) // missing lockouts inserted for reductions would be instantly expired
|
||||
{
|
||||
auto lockout = ExpeditionLockoutTimer::CreateLockout(expedition_name, event_name, seconds, uuid);
|
||||
AddExpeditionLockout(lockout, update_db);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::RemoveExpeditionLockout(
|
||||
const std::string& expedition_name, const std::string& event_name, bool update_db)
|
||||
{
|
||||
m_expedition_lockouts.erase(std::remove_if(m_expedition_lockouts.begin(), m_expedition_lockouts.end(),
|
||||
[&](const ExpeditionLockoutTimer& lockout) {
|
||||
return lockout.IsSameLockout(expedition_name, event_name);
|
||||
}
|
||||
), m_expedition_lockouts.end());
|
||||
|
||||
if (update_db) // for quest api
|
||||
{
|
||||
ExpeditionDatabase::DeleteCharacterLockout(CharacterID(), expedition_name, event_name);
|
||||
}
|
||||
|
||||
SendExpeditionLockoutTimers();
|
||||
}
|
||||
|
||||
void Client::RemoveAllExpeditionLockouts(const std::string& expedition_name, bool update_db)
|
||||
{
|
||||
if (expedition_name.empty())
|
||||
{
|
||||
if (update_db)
|
||||
{
|
||||
ExpeditionDatabase::DeleteAllCharacterLockouts(CharacterID());
|
||||
}
|
||||
m_expedition_lockouts.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (update_db)
|
||||
{
|
||||
ExpeditionDatabase::DeleteAllCharacterLockouts(CharacterID(), expedition_name);
|
||||
}
|
||||
|
||||
m_expedition_lockouts.erase(std::remove_if(m_expedition_lockouts.begin(), m_expedition_lockouts.end(),
|
||||
[&](const ExpeditionLockoutTimer& lockout) {
|
||||
return lockout.GetExpeditionName() == expedition_name;
|
||||
}
|
||||
), m_expedition_lockouts.end());
|
||||
}
|
||||
|
||||
SendExpeditionLockoutTimers();
|
||||
}
|
||||
|
||||
const ExpeditionLockoutTimer* Client::GetExpeditionLockout(
|
||||
const std::string& expedition_name, const std::string& event_name, bool include_expired) const
|
||||
{
|
||||
for (const auto& expedition_lockout : m_expedition_lockouts)
|
||||
{
|
||||
if ((include_expired || !expedition_lockout.IsExpired()) &&
|
||||
expedition_lockout.IsSameLockout(expedition_name, event_name))
|
||||
{
|
||||
return &expedition_lockout;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<ExpeditionLockoutTimer> Client::GetExpeditionLockouts(
|
||||
const std::string& expedition_name, bool include_expired)
|
||||
{
|
||||
std::vector<ExpeditionLockoutTimer> lockouts;
|
||||
for (const auto& lockout : m_expedition_lockouts)
|
||||
{
|
||||
if ((include_expired || !lockout.IsExpired()) &&
|
||||
lockout.GetExpeditionName() == expedition_name)
|
||||
{
|
||||
lockouts.emplace_back(lockout);
|
||||
}
|
||||
}
|
||||
return lockouts;
|
||||
}
|
||||
|
||||
bool Client::HasExpeditionLockout(
|
||||
const std::string& expedition_name, const std::string& event_name, bool include_expired)
|
||||
{
|
||||
return (GetExpeditionLockout(expedition_name, event_name, include_expired) != nullptr);
|
||||
}
|
||||
|
||||
void Client::SendExpeditionLockoutTimers()
|
||||
{
|
||||
std::vector<ExpeditionLockoutTimerEntry_Struct> lockout_entries;
|
||||
|
||||
// client displays lockouts rounded down to nearest minute, send lockouts
|
||||
// with 60s offset added to compensate (live does this too)
|
||||
constexpr uint32_t rounding_seconds = 60;
|
||||
|
||||
// erases expired lockouts while building lockout timer list
|
||||
for (auto it = m_expedition_lockouts.begin(); it != m_expedition_lockouts.end();)
|
||||
{
|
||||
uint32_t seconds_remaining = it->GetSecondsRemaining();
|
||||
if (seconds_remaining == 0)
|
||||
{
|
||||
it = m_expedition_lockouts.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExpeditionLockoutTimerEntry_Struct lockout;
|
||||
strn0cpy(lockout.expedition_name, it->GetExpeditionName().c_str(), sizeof(lockout.expedition_name));
|
||||
lockout.seconds_remaining = seconds_remaining + rounding_seconds;
|
||||
lockout.event_type = it->IsReplayTimer() ? Expedition::REPLAY_TIMER_ID : Expedition::EVENT_TIMER_ID;
|
||||
strn0cpy(lockout.event_name, it->GetEventName().c_str(), sizeof(lockout.event_name));
|
||||
|
||||
lockout_entries.emplace_back(lockout);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t lockout_count = static_cast<uint32_t>(lockout_entries.size());
|
||||
uint32_t lockout_entries_size = sizeof(ExpeditionLockoutTimerEntry_Struct) * lockout_count;
|
||||
uint32_t outsize = sizeof(ExpeditionLockoutTimers_Struct) + lockout_entries_size;
|
||||
auto outapp = std::unique_ptr<EQApplicationPacket>(new EQApplicationPacket(OP_DzExpeditionLockoutTimers, outsize));
|
||||
auto outbuf = reinterpret_cast<ExpeditionLockoutTimers_Struct*>(outapp->pBuffer);
|
||||
outbuf->count = lockout_count;
|
||||
if (!lockout_entries.empty())
|
||||
{
|
||||
memcpy(outbuf->timers, lockout_entries.data(), lockout_entries_size);
|
||||
}
|
||||
QueuePacket(outapp.get());
|
||||
}
|
||||
|
||||
void Client::RequestPendingExpeditionInvite()
|
||||
{
|
||||
uint32_t packsize = sizeof(ServerExpeditionCharacterID_Struct);
|
||||
auto pack = std::unique_ptr<ServerPacket>(new ServerPacket(ServerOP_ExpeditionRequestInvite, packsize));
|
||||
auto packbuf = reinterpret_cast<ServerExpeditionCharacterID_Struct*>(pack->pBuffer);
|
||||
packbuf->character_id = CharacterID();
|
||||
worldserver.SendPacket(pack.get());
|
||||
}
|
||||
|
||||
void Client::DzListTimers()
|
||||
{
|
||||
// only lists player's current replay timer lockouts, not all event lockouts
|
||||
bool found = false;
|
||||
for (const auto& lockout : m_expedition_lockouts)
|
||||
{
|
||||
if (lockout.IsReplayTimer())
|
||||
{
|
||||
found = true;
|
||||
auto time_remaining = lockout.GetDaysHoursMinutesRemaining();
|
||||
MessageString(
|
||||
Chat::Yellow, DZLIST_REPLAY_TIMER,
|
||||
time_remaining.days.c_str(),
|
||||
time_remaining.hours.c_str(),
|
||||
time_remaining.mins.c_str(),
|
||||
lockout.GetExpeditionName().c_str()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
MessageString(Chat::Yellow, EXPEDITION_NO_TIMERS);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::SetDzRemovalTimer(bool enable_timer)
|
||||
{
|
||||
uint32_t timer_ms = RuleI(DynamicZone, ClientRemovalDelayMS);
|
||||
|
||||
LogDynamicZones(
|
||||
"Character [{}] instance [{}] removal timer enabled: [{}] delay (ms): [{}]",
|
||||
CharacterID(), zone ? zone->GetInstanceID() : 0, enable_timer, timer_ms
|
||||
);
|
||||
|
||||
if (enable_timer)
|
||||
{
|
||||
dynamiczone_removal_timer.Start(timer_ms);
|
||||
}
|
||||
else
|
||||
{
|
||||
dynamiczone_removal_timer.Disable();
|
||||
}
|
||||
}
|
||||
|
||||
void Client::SendDzCompassUpdate()
|
||||
{
|
||||
// client may be associated with multiple dynamic zone compasses in this zone
|
||||
std::vector<DynamicZoneCompassEntry_Struct> compass_entries;
|
||||
|
||||
for (const auto& client_dz : GetDynamicZones())
|
||||
{
|
||||
auto compass = client_dz.dynamic_zone.GetCompassLocation();
|
||||
if (zone && zone->GetZoneID() == compass.zone_id && zone->GetInstanceID() == 0)
|
||||
{
|
||||
DynamicZoneCompassEntry_Struct entry;
|
||||
entry.dz_zone_id = static_cast<uint16_t>(client_dz.dynamic_zone.GetZoneID());
|
||||
entry.dz_instance_id = static_cast<uint16_t>(client_dz.dynamic_zone.GetInstanceID());
|
||||
entry.dz_type = static_cast<uint32_t>(client_dz.dynamic_zone.GetType());
|
||||
entry.x = compass.x;
|
||||
entry.y = compass.y;
|
||||
entry.z = compass.z;
|
||||
|
||||
compass_entries.emplace_back(entry);
|
||||
}
|
||||
}
|
||||
|
||||
// compass set via MarkSingleCompassLocation()
|
||||
if (m_has_quest_compass)
|
||||
{
|
||||
DynamicZoneCompassEntry_Struct entry;
|
||||
entry.dz_zone_id = 0;
|
||||
entry.dz_instance_id = 0;
|
||||
entry.dz_type = 0;
|
||||
entry.x = m_quest_compass.x;
|
||||
entry.y = m_quest_compass.y;
|
||||
entry.z = m_quest_compass.z;
|
||||
|
||||
compass_entries.emplace_back(entry);
|
||||
}
|
||||
|
||||
uint32 count = static_cast<uint32_t>(compass_entries.size());
|
||||
uint32 entries_size = sizeof(DynamicZoneCompassEntry_Struct) * count;
|
||||
uint32 outsize = sizeof(DynamicZoneCompass_Struct) + entries_size;
|
||||
auto outapp = std::unique_ptr<EQApplicationPacket>(new EQApplicationPacket(OP_DzCompass, outsize));
|
||||
auto outbuf = reinterpret_cast<DynamicZoneCompass_Struct*>(outapp->pBuffer);
|
||||
outbuf->count = count;
|
||||
memcpy(outbuf->entries, compass_entries.data(), entries_size);
|
||||
|
||||
QueuePacket(outapp.get());
|
||||
}
|
||||
|
||||
void Client::GoToDzSafeReturnOrBind(const DynamicZone& dynamic_zone)
|
||||
{
|
||||
auto safereturn = dynamic_zone.GetSafeReturnLocation();
|
||||
LogDynamicZonesDetail(
|
||||
"Sending character [{}] to safereturn zone [{}] or bind", CharacterID(), safereturn.zone_id
|
||||
);
|
||||
|
||||
if (!dynamic_zone.IsValid() || safereturn.zone_id == 0)
|
||||
{
|
||||
GoToBind();
|
||||
}
|
||||
else
|
||||
{
|
||||
MovePC(safereturn.zone_id, 0, safereturn.x, safereturn.y, safereturn.z, safereturn.heading);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<DynamicZoneInfo> Client::GetDynamicZones(uint32_t zone_id, int zone_version)
|
||||
{
|
||||
std::vector<DynamicZoneInfo> client_dzs;
|
||||
|
||||
// check client systems for any associated dynamic zones optionally filtered by zone
|
||||
Expedition* expedition = GetExpedition();
|
||||
if (expedition &&
|
||||
(zone_id == 0 || expedition->GetDynamicZone().GetZoneID() == zone_id) &&
|
||||
(zone_version < 0 || expedition->GetDynamicZone().GetZoneVersion() == zone_version))
|
||||
{
|
||||
client_dzs.emplace_back(expedition->GetName(), expedition->GetLeaderName(), expedition->GetDynamicZone());
|
||||
}
|
||||
|
||||
// todo: tasks, missions (shared tasks), and quests with an associated dz to zone_id
|
||||
|
||||
return client_dzs;
|
||||
}
|
||||
|
||||
void Client::MovePCDynamicZone(uint32 zone_id, int zone_version, bool msg_if_invalid)
|
||||
{
|
||||
if (zone_id == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto client_dzs = GetDynamicZones(zone_id, zone_version);
|
||||
|
||||
if (client_dzs.empty())
|
||||
{
|
||||
if (msg_if_invalid)
|
||||
{
|
||||
MessageString(Chat::Red, DYNAMICZONE_WAY_IS_BLOCKED); // unconfirmed message
|
||||
}
|
||||
}
|
||||
else if (client_dzs.size() == 1)
|
||||
{
|
||||
const DynamicZone& dz = client_dzs[0].dynamic_zone;
|
||||
DynamicZoneLocation zonein = dz.GetZoneInLocation();
|
||||
ZoneMode zone_mode = dz.HasZoneInLocation() ? ZoneMode::ZoneSolicited : ZoneMode::ZoneToSafeCoords;
|
||||
MovePC(zone_id, dz.GetInstanceID(), zonein.x, zonein.y, zonein.z, zonein.heading, 0, zone_mode);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogDynamicZonesDetail(
|
||||
"Sending DzSwitchListWnd to character [{}] associated with [{}] dynamic zone(s)",
|
||||
CharacterID(), client_dzs.size());
|
||||
|
||||
// more than one dynamic zone to this zone, send out the switchlist window
|
||||
// note that this will most likely crash clients if they've reloaded the ui
|
||||
// this occurs on live as well so it may just be a long lasting client bug
|
||||
uint32 count = static_cast<uint32_t>(client_dzs.size());
|
||||
uint32 entries_size = sizeof(DynamicZoneChooseZoneEntry_Struct) * count;
|
||||
uint32 outsize = sizeof(DynamicZoneChooseZone_Struct) + entries_size;
|
||||
auto outapp = std::unique_ptr<EQApplicationPacket>(new EQApplicationPacket(OP_DzChooseZone, outsize));
|
||||
auto outbuf = reinterpret_cast<DynamicZoneChooseZone_Struct*>(outapp->pBuffer);
|
||||
outbuf->count = count;
|
||||
for (int i = 0; i < client_dzs.size(); ++i)
|
||||
{
|
||||
outbuf->choices[i].dz_zone_id = client_dzs[i].dynamic_zone.GetZoneID();
|
||||
outbuf->choices[i].dz_instance_id = client_dzs[i].dynamic_zone.GetInstanceID();
|
||||
outbuf->choices[i].dz_type = static_cast<uint32_t>(client_dzs[i].dynamic_zone.GetType());
|
||||
strn0cpy(outbuf->choices[i].description, client_dzs[i].description.c_str(), sizeof(outbuf->choices[i].description));
|
||||
strn0cpy(outbuf->choices[i].leader_name, client_dzs[i].leader_name.c_str(), sizeof(outbuf->choices[i].leader_name));
|
||||
}
|
||||
QueuePacket(outapp.get());
|
||||
}
|
||||
}
|
||||
|
||||
void Client::MovePCDynamicZone(const std::string& zone_name, int zone_version, bool msg_if_invalid)
|
||||
{
|
||||
auto zone_id = ZoneID(zone_name.c_str());
|
||||
MovePCDynamicZone(zone_id, zone_version, msg_if_invalid);
|
||||
}
|
||||
|
||||
void Client::Fling(float value, float target_x, float target_y, float target_z, bool ignore_los, bool clipping) {
|
||||
BuffFadeByEffect(SE_Levitate);
|
||||
if (CheckLosFN(target_x, target_y, target_z, 6.0f) || ignore_los) {
|
||||
auto outapp_fling = new EQApplicationPacket(OP_Fling, sizeof(fling_struct));
|
||||
fling_struct* flingTo = (fling_struct*)outapp_fling->pBuffer;
|
||||
if(clipping)
|
||||
flingTo->collision = 0;
|
||||
else
|
||||
flingTo->collision = -1;
|
||||
|
||||
flingTo->travel_time = -1;
|
||||
flingTo->unk3 = 1;
|
||||
flingTo->disable_fall_damage = 1;
|
||||
flingTo->speed_z = value;
|
||||
flingTo->new_y = target_y;
|
||||
flingTo->new_x = target_x;
|
||||
flingTo->new_z = target_z;
|
||||
outapp_fling->priority = 6;
|
||||
FastQueuePacket(&outapp_fling);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> Client::GetLearnableDisciplines(uint8 min_level, uint8 max_level) {
|
||||
bool SpellGlobalRule = RuleB(Spells, EnableSpellGlobals);
|
||||
bool SpellBucketRule = RuleB(Spells, EnableSpellBuckets);
|
||||
bool SpellGlobalCheckResult = false;
|
||||
bool SpellBucketCheckResult = false;
|
||||
std::vector<int> learnable_disciplines;
|
||||
for (int spell_id = 0; spell_id < SPDAT_RECORDS; ++spell_id) {
|
||||
bool learnable = false;
|
||||
if (!IsValidSpell(spell_id))
|
||||
continue;
|
||||
if (!IsDiscipline(spell_id))
|
||||
continue;
|
||||
if (spells[spell_id].classes[WARRIOR] == 0)
|
||||
continue;
|
||||
if (max_level > 0 && spells[spell_id].classes[m_pp.class_ - 1] > max_level)
|
||||
continue;
|
||||
if (min_level > 1 && spells[spell_id].classes[m_pp.class_ - 1] < min_level)
|
||||
continue;
|
||||
if (spells[spell_id].skill == 52)
|
||||
continue;
|
||||
if (RuleB(Spells, UseCHAScribeHack) && spells[spell_id].effectid[EFFECT_COUNT - 1] == 10)
|
||||
continue;
|
||||
if (HasDisciplineLearned(spell_id))
|
||||
continue;
|
||||
|
||||
if (SpellGlobalRule) {
|
||||
SpellGlobalCheckResult = SpellGlobalCheck(spell_id, CharacterID());
|
||||
if (SpellGlobalCheckResult) {
|
||||
learnable = true;
|
||||
}
|
||||
} else if (SpellBucketRule) {
|
||||
SpellBucketCheckResult = SpellBucketCheck(spell_id, CharacterID());
|
||||
if (SpellBucketCheckResult) {
|
||||
learnable = true;
|
||||
}
|
||||
} else {
|
||||
learnable = true;
|
||||
}
|
||||
|
||||
if (learnable) {
|
||||
learnable_disciplines.push_back(spell_id);
|
||||
}
|
||||
}
|
||||
return learnable_disciplines;
|
||||
}
|
||||
|
||||
std::vector<int> Client::GetLearnedDisciplines() {
|
||||
std::vector<int> learned_disciplines;
|
||||
for (int index = 0; index < MAX_PP_DISCIPLINES; index++) {
|
||||
if (IsValidSpell(m_pp.disciplines.values[index])) {
|
||||
learned_disciplines.push_back(m_pp.disciplines.values[index]);
|
||||
}
|
||||
}
|
||||
return learned_disciplines;
|
||||
}
|
||||
|
||||
std::vector<int> Client::GetMemmedSpells() {
|
||||
std::vector<int> memmed_spells;
|
||||
for (int index = 0; index < EQ::spells::SPELL_GEM_COUNT; index++) {
|
||||
if (IsValidSpell(m_pp.mem_spells[index])) {
|
||||
memmed_spells.push_back(m_pp.mem_spells[index]);
|
||||
}
|
||||
}
|
||||
return memmed_spells;
|
||||
}
|
||||
|
||||
std::vector<int> Client::GetScribeableSpells(uint8 min_level, uint8 max_level) {
|
||||
bool SpellGlobalRule = RuleB(Spells, EnableSpellGlobals);
|
||||
bool SpellBucketRule = RuleB(Spells, EnableSpellBuckets);
|
||||
bool SpellGlobalCheckResult = false;
|
||||
bool SpellBucketCheckResult = false;
|
||||
std::vector<int> scribeable_spells;
|
||||
for (int spell_id = 0; spell_id < SPDAT_RECORDS; ++spell_id) {
|
||||
bool scribeable = false;
|
||||
if (!IsValidSpell(spell_id))
|
||||
continue;
|
||||
if (spells[spell_id].classes[WARRIOR] == 0)
|
||||
continue;
|
||||
if (max_level > 0 && spells[spell_id].classes[m_pp.class_ - 1] > max_level)
|
||||
continue;
|
||||
if (min_level > 1 && spells[spell_id].classes[m_pp.class_ - 1] < min_level)
|
||||
continue;
|
||||
if (spells[spell_id].skill == 52)
|
||||
continue;
|
||||
if (RuleB(Spells, UseCHAScribeHack) && spells[spell_id].effectid[EFFECT_COUNT - 1] == 10)
|
||||
continue;
|
||||
if (HasSpellScribed(spell_id))
|
||||
continue;
|
||||
|
||||
if (SpellGlobalRule) {
|
||||
SpellGlobalCheckResult = SpellGlobalCheck(spell_id, CharacterID());
|
||||
if (SpellGlobalCheckResult) {
|
||||
scribeable = true;
|
||||
}
|
||||
} else if (SpellBucketRule) {
|
||||
SpellBucketCheckResult = SpellBucketCheck(spell_id, CharacterID());
|
||||
if (SpellBucketCheckResult) {
|
||||
scribeable = true;
|
||||
}
|
||||
} else {
|
||||
scribeable = true;
|
||||
}
|
||||
|
||||
if (scribeable) {
|
||||
scribeable_spells.push_back(spell_id);
|
||||
}
|
||||
}
|
||||
return scribeable_spells;
|
||||
}
|
||||
|
||||
std::vector<int> Client::GetScribedSpells() {
|
||||
std::vector<int> scribed_spells;
|
||||
for(int index = 0; index < EQ::spells::SPELLBOOK_SIZE; index++) {
|
||||
if (IsValidSpell(m_pp.spell_book[index])) {
|
||||
scribed_spells.push_back(m_pp.spell_book[index]);
|
||||
}
|
||||
}
|
||||
return scribed_spells;
|
||||
}
|
||||
|
||||
@ -21,12 +21,18 @@
|
||||
class Client;
|
||||
class EQApplicationPacket;
|
||||
class EQStream;
|
||||
class DynamicZone;
|
||||
class Expedition;
|
||||
class ExpeditionLockoutTimer;
|
||||
class ExpeditionRequest;
|
||||
class Group;
|
||||
class NPC;
|
||||
class Object;
|
||||
class Raid;
|
||||
class Seperator;
|
||||
class ServerPacket;
|
||||
struct DynamicZoneInfo;
|
||||
struct DynamicZoneLocation;
|
||||
enum WaterRegionType : int;
|
||||
|
||||
namespace EQ
|
||||
@ -232,8 +238,8 @@ public:
|
||||
void SetDisplayMobInfoWindow(bool display_mob_info_window);
|
||||
bool GetDisplayMobInfoWindow() const;
|
||||
|
||||
bool IsDevToolsWindowEnabled() const;
|
||||
void SetDevToolsWindowEnabled(bool dev_tools_window_enabled);
|
||||
bool IsDevToolsEnabled() const;
|
||||
void SetDevToolsEnabled(bool in_dev_tools_enabled);
|
||||
|
||||
void SetPrimaryWeaponOrnamentation(uint32 model_id);
|
||||
void SetSecondaryWeaponOrnamentation(uint32 model_id);
|
||||
@ -283,6 +289,7 @@ public:
|
||||
uint8 SlotConvert(uint8 slot,bool bracer=false);
|
||||
void MessageString(uint32 type, uint32 string_id, uint32 distance = 0);
|
||||
void MessageString(uint32 type, uint32 string_id, const char* message,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0, uint32 distance = 0);
|
||||
void MessageString(const CZClientMessageString_Struct* msg);
|
||||
bool FilteredMessageCheck(Mob *sender, eqFilterType filter);
|
||||
void FilteredMessageString(Mob *sender, uint32 type, eqFilterType filter, uint32 string_id);
|
||||
void FilteredMessageString(Mob *sender, uint32 type, eqFilterType filter,
|
||||
@ -594,9 +601,9 @@ public:
|
||||
uint32 GetPVPPoints() { return m_pp.PVPCurrentPoints; }
|
||||
void AddPVPPoints(uint32 Points);
|
||||
uint32 GetRadiantCrystals() { return m_pp.currentRadCrystals; }
|
||||
void SetRadiantCrystals(uint32 Crystals) { m_pp.currentRadCrystals = Crystals; }
|
||||
void SetRadiantCrystals(uint32 value);
|
||||
uint32 GetEbonCrystals() { return m_pp.currentEbonCrystals; }
|
||||
void SetEbonCrystals(uint32 Crystals) { m_pp.currentEbonCrystals = Crystals; }
|
||||
void SetEbonCrystals(uint32 value);
|
||||
void AddCrystals(uint32 Radiant, uint32 Ebon);
|
||||
void SendCrystalCounts();
|
||||
|
||||
@ -777,6 +784,11 @@ public:
|
||||
void UnmemSpellAll(bool update_client = true);
|
||||
uint16 FindMemmedSpellBySlot(int slot);
|
||||
int MemmedCount();
|
||||
std::vector<int> GetLearnableDisciplines(uint8 min_level = 1, uint8 max_level = 0);
|
||||
std::vector<int> GetLearnedDisciplines();
|
||||
std::vector<int> GetMemmedSpells();
|
||||
std::vector<int> GetScribeableSpells(uint8 min_level = 1, uint8 max_level = 0);
|
||||
std::vector<int> GetScribedSpells();
|
||||
void ScribeSpell(uint16 spell_id, int slot, bool update_client = true);
|
||||
void UnscribeSpell(int slot, bool update_client = true);
|
||||
void UnscribeSpellAll(bool update_client = true);
|
||||
@ -787,6 +799,8 @@ public:
|
||||
uint32 GetCharMaxLevelFromQGlobal();
|
||||
uint32 GetCharMaxLevelFromBucket();
|
||||
|
||||
void Fling(float value, float target_x, float target_y, float target_z, bool ignore_los = false, bool clipping = false);
|
||||
|
||||
inline bool IsStanding() const {return (playeraction == 0);}
|
||||
inline bool IsSitting() const {return (playeraction == 1);}
|
||||
inline bool IsCrouching() const {return (playeraction == 2);}
|
||||
@ -966,6 +980,7 @@ public:
|
||||
void SendDisciplineUpdate();
|
||||
void SendDisciplineTimer(uint32 timer_id, uint32 duration);
|
||||
bool UseDiscipline(uint32 spell_id, uint32 target);
|
||||
bool HasDisciplineLearned(uint16 spell_id);
|
||||
|
||||
void SetLinkedSpellReuseTimer(uint32 timer_id, uint32 duration);
|
||||
bool IsLinkedSpellReuseTimerReady(uint32 timer_id);
|
||||
@ -988,6 +1003,7 @@ public:
|
||||
void ProcessInspectRequest(Client* requestee, Client* requester);
|
||||
bool ClientFinishedLoading() { return (conn_state == ClientConnectFinished); }
|
||||
int FindSpellBookSlotBySpellID(uint16 spellid);
|
||||
uint32 GetSpellIDByBookSlot(int book_slot);
|
||||
int GetNextAvailableSpellBookSlot(int starting_slot = 0);
|
||||
inline uint32 GetSpellByBookSlot(int book_slot) { return m_pp.spell_book[book_slot]; }
|
||||
inline bool HasSpellScribed(int spellid) { return (FindSpellBookSlotBySpellID(spellid) != -1 ? true : false); }
|
||||
@ -1103,6 +1119,47 @@ public:
|
||||
|
||||
void MarkSingleCompassLoc(float in_x, float in_y, float in_z, uint8 count=1);
|
||||
|
||||
// cross zone client messaging helpers (null client argument will fallback to messaging by name)
|
||||
static void SendCrossZoneMessage(
|
||||
Client* client, const std::string& client_name, uint16_t chat_type, const std::string& message);
|
||||
static void SendCrossZoneMessageString(
|
||||
Client* client, const std::string& client_name, uint16_t chat_type,
|
||||
uint32_t string_id, const std::initializer_list<std::string>& arguments = {});
|
||||
|
||||
void AddExpeditionLockout(const ExpeditionLockoutTimer& lockout, bool update_db = false);
|
||||
void AddExpeditionLockoutDuration(const std::string& expedition_name,
|
||||
const std::string& event_Name, int seconds, const std::string& uuid = {}, bool update_db = false);
|
||||
void AddNewExpeditionLockout(const std::string& expedition_name,
|
||||
const std::string& event_name, uint32_t duration, std::string uuid = {});
|
||||
Expedition* CreateExpedition(DynamicZone& dz_instance, ExpeditionRequest& request);
|
||||
Expedition* CreateExpedition(
|
||||
const std::string& zone_name, uint32 version, uint32 duration, const std::string& expedition_name,
|
||||
uint32 min_players, uint32 max_players, bool disable_messages = false);
|
||||
Expedition* GetExpedition() const;
|
||||
uint32 GetExpeditionID() const { return m_expedition_id; }
|
||||
const ExpeditionLockoutTimer* GetExpeditionLockout(
|
||||
const std::string& expedition_name, const std::string& event_name, bool include_expired = false) const;
|
||||
const std::vector<ExpeditionLockoutTimer>& GetExpeditionLockouts() const { return m_expedition_lockouts; };
|
||||
std::vector<ExpeditionLockoutTimer> GetExpeditionLockouts(const std::string& expedition_name, bool include_expired = false);
|
||||
uint32 GetPendingExpeditionInviteID() const { return m_pending_expedition_invite.expedition_id; }
|
||||
bool HasExpeditionLockout(const std::string& expedition_name, const std::string& event_name, bool include_expired = false);
|
||||
bool IsInExpedition() const { return m_expedition_id != 0; }
|
||||
void RemoveAllExpeditionLockouts(const std::string& expedition_name, bool update_db = false);
|
||||
void RemoveExpeditionLockout(const std::string& expedition_name,
|
||||
const std::string& event_name, bool update_db = false);
|
||||
void RequestPendingExpeditionInvite();
|
||||
void SendExpeditionLockoutTimers();
|
||||
void SetExpeditionID(uint32 expedition_id) { m_expedition_id = expedition_id; };
|
||||
void SetPendingExpeditionInvite(ExpeditionInvite&& invite) { m_pending_expedition_invite = invite; }
|
||||
void UpdateExpeditionInfoAndLockouts();
|
||||
void DzListTimers();
|
||||
void SetDzRemovalTimer(bool enable_timer);
|
||||
void SendDzCompassUpdate();
|
||||
void GoToDzSafeReturnOrBind(const DynamicZone& dynamic_zone);
|
||||
void MovePCDynamicZone(uint32 zone_id, int zone_version = -1, bool msg_if_invalid = true);
|
||||
void MovePCDynamicZone(const std::string& zone_name, int zone_version = -1, bool msg_if_invalid = true);
|
||||
std::vector<DynamicZoneInfo> GetDynamicZones(uint32_t zone_id = 0, int zone_version = -1);
|
||||
|
||||
void CalcItemScale();
|
||||
bool CalcItemScale(uint32 slot_x, uint32 slot_y); // behavior change: 'slot_y' is now [RANGE]_END and not [RANGE]_END + 1
|
||||
void DoItemEnterZone();
|
||||
@ -1476,7 +1533,7 @@ private:
|
||||
uint32 tmSitting; // time stamp started sitting, used for HP regen bonus added on MAY 5, 2004
|
||||
|
||||
bool display_mob_info_window;
|
||||
bool dev_tools_window_enabled;
|
||||
bool dev_tools_enabled;
|
||||
|
||||
int32 max_end;
|
||||
int32 current_endurance;
|
||||
@ -1556,6 +1613,7 @@ private:
|
||||
Timer hp_other_update_throttle_timer; /* This is to keep clients from DOSing the server with macros that change client targets constantly */
|
||||
Timer position_update_timer; /* Timer used when client hasn't updated within a 10 second window */
|
||||
Timer consent_throttle_timer;
|
||||
Timer dynamiczone_removal_timer;
|
||||
|
||||
glm::vec3 m_Proximity;
|
||||
glm::vec4 last_position_before_bulk_update;
|
||||
@ -1657,6 +1715,12 @@ private:
|
||||
|
||||
int client_max_level;
|
||||
|
||||
uint32 m_expedition_id = 0;
|
||||
ExpeditionInvite m_pending_expedition_invite { 0 };
|
||||
std::vector<ExpeditionLockoutTimer> m_expedition_lockouts;
|
||||
glm::vec3 m_quest_compass;
|
||||
bool m_has_quest_compass = false;
|
||||
|
||||
#ifdef BOTS
|
||||
|
||||
public:
|
||||
|
||||
@ -49,6 +49,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "../common/zone_numbers.h"
|
||||
#include "data_bucket.h"
|
||||
#include "event_codes.h"
|
||||
#include "expedition.h"
|
||||
#include "expedition_database.h"
|
||||
#include "guild_mgr.h"
|
||||
#include "merc.h"
|
||||
#include "petitions.h"
|
||||
@ -191,6 +193,15 @@ void MapOpcodes()
|
||||
ConnectedOpcodes[OP_DuelResponse2] = &Client::Handle_OP_DuelResponse2;
|
||||
ConnectedOpcodes[OP_DumpName] = &Client::Handle_OP_DumpName;
|
||||
ConnectedOpcodes[OP_Dye] = &Client::Handle_OP_Dye;
|
||||
ConnectedOpcodes[OP_DzAddPlayer] = &Client::Handle_OP_DzAddPlayer;
|
||||
ConnectedOpcodes[OP_DzChooseZoneReply] = &Client::Handle_OP_DzChooseZoneReply;
|
||||
ConnectedOpcodes[OP_DzExpeditionInviteResponse] = &Client::Handle_OP_DzExpeditionInviteResponse;
|
||||
ConnectedOpcodes[OP_DzListTimers] = &Client::Handle_OP_DzListTimers;
|
||||
ConnectedOpcodes[OP_DzMakeLeader] = &Client::Handle_OP_DzMakeLeader;
|
||||
ConnectedOpcodes[OP_DzPlayerList] = &Client::Handle_OP_DzPlayerList;
|
||||
ConnectedOpcodes[OP_DzRemovePlayer] = &Client::Handle_OP_DzRemovePlayer;
|
||||
ConnectedOpcodes[OP_DzSwapPlayer] = &Client::Handle_OP_DzSwapPlayer;
|
||||
ConnectedOpcodes[OP_DzQuit] = &Client::Handle_OP_DzQuit;
|
||||
ConnectedOpcodes[OP_Emote] = &Client::Handle_OP_Emote;
|
||||
ConnectedOpcodes[OP_EndLootRequest] = &Client::Handle_OP_EndLootRequest;
|
||||
ConnectedOpcodes[OP_EnvDamage] = &Client::Handle_OP_EnvDamage;
|
||||
@ -266,6 +277,7 @@ void MapOpcodes()
|
||||
ConnectedOpcodes[OP_ItemViewUnknown] = &Client::Handle_OP_Ignore;
|
||||
ConnectedOpcodes[OP_Jump] = &Client::Handle_OP_Jump;
|
||||
ConnectedOpcodes[OP_KeyRing] = &Client::Handle_OP_KeyRing;
|
||||
ConnectedOpcodes[OP_KickPlayers] = &Client::Handle_OP_KickPlayers;
|
||||
ConnectedOpcodes[OP_LDoNButton] = &Client::Handle_OP_LDoNButton;
|
||||
ConnectedOpcodes[OP_LDoNDisarmTraps] = &Client::Handle_OP_LDoNDisarmTraps;
|
||||
ConnectedOpcodes[OP_LDoNInspect] = &Client::Handle_OP_LDoNInspect;
|
||||
@ -885,6 +897,8 @@ void Client::CompleteConnect()
|
||||
guild_mgr.RequestOnlineGuildMembers(this->CharacterID(), this->GuildID());
|
||||
}
|
||||
|
||||
UpdateExpeditionInfoAndLockouts();
|
||||
|
||||
/** Request adventure info **/
|
||||
auto pack = new ServerPacket(ServerOP_AdventureDataRequest, 64);
|
||||
strcpy((char*)pack->pBuffer, GetName());
|
||||
@ -920,7 +934,7 @@ void Client::CompleteConnect()
|
||||
|
||||
entity_list.ScanCloseMobs(close_mobs, this, true);
|
||||
|
||||
if (GetGM()) {
|
||||
if (GetGM() && IsDevToolsEnabled()) {
|
||||
ShowDevToolsMenu();
|
||||
}
|
||||
|
||||
@ -1701,13 +1715,15 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
/* Task Packets */
|
||||
LoadClientTaskState();
|
||||
|
||||
m_expedition_id = ExpeditionDatabase::GetExpeditionIDFromCharacterID(CharacterID());
|
||||
|
||||
/**
|
||||
* DevTools Load Settings
|
||||
*/
|
||||
if (Admin() >= EQ::DevTools::GM_ACCOUNT_STATUS_LEVEL) {
|
||||
std::string dev_tools_window_key = StringFormat("%i-dev-tools-window-disabled", AccountID());
|
||||
std::string dev_tools_window_key = StringFormat("%i-dev-tools-disabled", AccountID());
|
||||
if (DataBucket::GetData(dev_tools_window_key) == "true") {
|
||||
dev_tools_window_enabled = false;
|
||||
dev_tools_enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2025,12 +2041,10 @@ void Client::Handle_OP_AdventureMerchantPurchase(const EQApplicationPacket *app)
|
||||
else if (aps->Type == NorrathsKeepersMerchant)
|
||||
{
|
||||
SetRadiantCrystals(GetRadiantCrystals() - (int32)item->LDoNPrice);
|
||||
SendCrystalCounts();
|
||||
}
|
||||
else if (aps->Type == DarkReignMerchant)
|
||||
{
|
||||
SetEbonCrystals(GetEbonCrystals() - (int32)item->LDoNPrice);
|
||||
SendCrystalCounts();
|
||||
}
|
||||
int16 charges = 1;
|
||||
if (item->MaxCharges != 0)
|
||||
@ -4533,23 +4547,63 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
|
||||
rewind_timer.Start(30000, true);
|
||||
}
|
||||
|
||||
/* Handle client aggro scanning timers NPCs */
|
||||
is_client_moving = (cy == m_Position.y && cx == m_Position.x) ? false : true;
|
||||
|
||||
is_client_moving = !(cy == m_Position.y && cx == m_Position.x);
|
||||
|
||||
|
||||
/**
|
||||
* Client aggro scanning
|
||||
*/
|
||||
const uint16 client_scan_npc_aggro_timer_idle = RuleI(Aggro, ClientAggroCheckIdleInterval);
|
||||
const uint16 client_scan_npc_aggro_timer_moving = RuleI(Aggro, ClientAggroCheckMovingInterval);
|
||||
|
||||
LogAggroDetail(
|
||||
"ClientUpdate [{}] {}moving, scan timer [{}]",
|
||||
GetCleanName(),
|
||||
is_client_moving ? "" : "NOT ",
|
||||
client_scan_npc_aggro_timer.GetRemainingTime()
|
||||
);
|
||||
|
||||
if (is_client_moving) {
|
||||
LogDebug("ClientUpdate: Client is moving - scan timer is: [{}]", client_scan_npc_aggro_timer.GetDuration());
|
||||
if (client_scan_npc_aggro_timer.GetDuration() > 1000) {
|
||||
if (client_scan_npc_aggro_timer.GetRemainingTime() > client_scan_npc_aggro_timer_moving) {
|
||||
LogAggroDetail("Client [{}] Restarting with moving timer", GetCleanName());
|
||||
client_scan_npc_aggro_timer.Disable();
|
||||
client_scan_npc_aggro_timer.Start(500);
|
||||
client_scan_npc_aggro_timer.Start(client_scan_npc_aggro_timer_moving);
|
||||
client_scan_npc_aggro_timer.Trigger();
|
||||
}
|
||||
}
|
||||
else {
|
||||
LogDebug("ClientUpdate: Client is NOT moving - scan timer is: [{}]", client_scan_npc_aggro_timer.GetDuration());
|
||||
if (client_scan_npc_aggro_timer.GetDuration() < 1000) {
|
||||
client_scan_npc_aggro_timer.Disable();
|
||||
client_scan_npc_aggro_timer.Start(3000);
|
||||
else if (client_scan_npc_aggro_timer.GetDuration() == client_scan_npc_aggro_timer_moving) {
|
||||
LogAggroDetail("Client [{}] Restarting with idle timer", GetCleanName());
|
||||
client_scan_npc_aggro_timer.Disable();
|
||||
client_scan_npc_aggro_timer.Start(client_scan_npc_aggro_timer_idle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Client mob close list cache scan timer
|
||||
*/
|
||||
const uint16 client_mob_close_scan_timer_moving = 6000;
|
||||
const uint16 client_mob_close_scan_timer_idle = 60000;
|
||||
|
||||
LogAIScanCloseDetail(
|
||||
"Client [{}] {}moving, scan timer [{}]",
|
||||
GetCleanName(),
|
||||
is_client_moving ? "" : "NOT ",
|
||||
mob_close_scan_timer.GetRemainingTime()
|
||||
);
|
||||
|
||||
if (is_client_moving) {
|
||||
if (mob_close_scan_timer.GetRemainingTime() > client_mob_close_scan_timer_moving) {
|
||||
LogAIScanCloseDetail("Client [{}] Restarting with moving timer", GetCleanName());
|
||||
mob_close_scan_timer.Disable();
|
||||
mob_close_scan_timer.Start(client_mob_close_scan_timer_moving);
|
||||
mob_close_scan_timer.Trigger();
|
||||
}
|
||||
}
|
||||
else if (mob_close_scan_timer.GetDuration() == client_mob_close_scan_timer_moving) {
|
||||
LogAIScanCloseDetail("Client [{}] Restarting with idle timer", GetCleanName());
|
||||
mob_close_scan_timer.Disable();
|
||||
mob_close_scan_timer.Start(client_mob_close_scan_timer_idle);
|
||||
}
|
||||
|
||||
/**
|
||||
* On a normal basis we limit mob movement updates based on distance
|
||||
@ -5566,6 +5620,116 @@ void Client::Handle_OP_Dye(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::Handle_OP_DzAddPlayer(const EQApplicationPacket *app)
|
||||
{
|
||||
auto expedition = GetExpedition();
|
||||
if (expedition)
|
||||
{
|
||||
auto dzcmd = reinterpret_cast<ExpeditionCommand_Struct*>(app->pBuffer);
|
||||
expedition->DzAddPlayer(this, dzcmd->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
// the only /dz command that sends an error message if no active expedition
|
||||
Message(Chat::System, DZ_YOU_NOT_ASSIGNED);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Handle_OP_DzChooseZoneReply(const EQApplicationPacket *app)
|
||||
{
|
||||
auto dzmsg = reinterpret_cast<DynamicZoneChooseZoneReply_Struct*>(app->pBuffer);
|
||||
LogDynamicZones(
|
||||
"Character [{}] chose DynamicZone [{}]:[{}] type: [{}] with system id: [{}]",
|
||||
CharacterID(), dzmsg->dz_zone_id, dzmsg->dz_instance_id, dzmsg->dz_type, dzmsg->unknown_id2
|
||||
);
|
||||
|
||||
if (!dzmsg->dz_instance_id || !database.VerifyInstanceAlive(dzmsg->dz_instance_id, CharacterID()))
|
||||
{
|
||||
// live just no-ops this without a message
|
||||
LogDynamicZones(
|
||||
"Character [{}] chose invalid DynamicZone [{}]:[{}] or is no longer a member",
|
||||
CharacterID(), dzmsg->dz_zone_id, dzmsg->dz_instance_id
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
auto client_dzs = GetDynamicZones();
|
||||
auto it = std::find_if(client_dzs.begin(), client_dzs.end(), [&](const DynamicZoneInfo dz_info) {
|
||||
return dz_info.dynamic_zone.IsSameDz(dzmsg->dz_zone_id, dzmsg->dz_instance_id);
|
||||
});
|
||||
|
||||
if (it != client_dzs.end())
|
||||
{
|
||||
DynamicZoneLocation loc = it->dynamic_zone.GetZoneInLocation();
|
||||
ZoneMode zone_mode = it->dynamic_zone.HasZoneInLocation() ? ZoneMode::ZoneSolicited : ZoneMode::ZoneToSafeCoords;
|
||||
MovePC(dzmsg->dz_zone_id, dzmsg->dz_instance_id, loc.x, loc.y, loc.z, loc.heading, 0, zone_mode);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Handle_OP_DzExpeditionInviteResponse(const EQApplicationPacket *app)
|
||||
{
|
||||
auto expedition = Expedition::FindCachedExpeditionByID(m_pending_expedition_invite.expedition_id);
|
||||
std::string swap_remove_name = m_pending_expedition_invite.swap_remove_name;
|
||||
m_pending_expedition_invite = { 0 }; // clear before re-validating
|
||||
|
||||
if (expedition)
|
||||
{
|
||||
auto dzmsg = reinterpret_cast<ExpeditionInviteResponse_Struct*>(app->pBuffer);
|
||||
expedition->DzInviteResponse(this, dzmsg->accepted, swap_remove_name);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Handle_OP_DzListTimers(const EQApplicationPacket *app)
|
||||
{
|
||||
DzListTimers();
|
||||
}
|
||||
|
||||
void Client::Handle_OP_DzMakeLeader(const EQApplicationPacket *app)
|
||||
{
|
||||
auto expedition = GetExpedition();
|
||||
if (expedition)
|
||||
{
|
||||
auto dzcmd = reinterpret_cast<ExpeditionCommand_Struct*>(app->pBuffer);
|
||||
expedition->DzMakeLeader(this, dzcmd->name);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Handle_OP_DzPlayerList(const EQApplicationPacket *app)
|
||||
{
|
||||
auto expedition = GetExpedition();
|
||||
if (expedition) {
|
||||
expedition->DzPlayerList(this);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Handle_OP_DzRemovePlayer(const EQApplicationPacket *app)
|
||||
{
|
||||
auto expedition = GetExpedition();
|
||||
if (expedition)
|
||||
{
|
||||
auto dzcmd = reinterpret_cast<ExpeditionCommand_Struct*>(app->pBuffer);
|
||||
expedition->DzRemovePlayer(this, dzcmd->name);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Handle_OP_DzSwapPlayer(const EQApplicationPacket *app)
|
||||
{
|
||||
auto expedition = GetExpedition();
|
||||
if (expedition)
|
||||
{
|
||||
auto dzcmd = reinterpret_cast<ExpeditionCommandSwap_Struct*>(app->pBuffer);
|
||||
expedition->DzSwapPlayer(this, dzcmd->rem_player_name, dzcmd->add_player_name);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Handle_OP_DzQuit(const EQApplicationPacket *app)
|
||||
{
|
||||
auto expedition = GetExpedition();
|
||||
if (expedition) {
|
||||
expedition->DzQuit(this);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Handle_OP_Emote(const EQApplicationPacket *app)
|
||||
{
|
||||
if (app->size != sizeof(Emote_Struct)) {
|
||||
@ -8836,6 +9000,23 @@ void Client::Handle_OP_KeyRing(const EQApplicationPacket *app)
|
||||
KeyRingList();
|
||||
}
|
||||
|
||||
void Client::Handle_OP_KickPlayers(const EQApplicationPacket *app)
|
||||
{
|
||||
auto buf = reinterpret_cast<KickPlayers_Struct*>(app->pBuffer);
|
||||
if (buf->kick_expedition)
|
||||
{
|
||||
auto expedition = GetExpedition();
|
||||
if (expedition)
|
||||
{
|
||||
expedition->DzKickPlayers(this);
|
||||
}
|
||||
}
|
||||
else if (buf->kick_task)
|
||||
{
|
||||
// todo: shared tasks
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Handle_OP_LDoNButton(const EQApplicationPacket *app)
|
||||
{
|
||||
if (app->size < sizeof(bool))
|
||||
@ -10872,8 +11053,8 @@ void Client::Handle_OP_PopupResponse(const EQApplicationPacket *app)
|
||||
break;
|
||||
|
||||
case EQ::popupresponse::MOB_INFO_DISMISS:
|
||||
this->SetDisplayMobInfoWindow(false);
|
||||
this->Message(Chat::Yellow, "[DevTools] Window snoozed in this zone...");
|
||||
SetDisplayMobInfoWindow(false);
|
||||
Message(Chat::Yellow, "[DevTools] Window snoozed in this zone...");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@ -101,6 +101,15 @@
|
||||
void Handle_OP_DuelResponse2(const EQApplicationPacket *app);
|
||||
void Handle_OP_DumpName(const EQApplicationPacket *app);
|
||||
void Handle_OP_Dye(const EQApplicationPacket *app);
|
||||
void Handle_OP_DzAddPlayer(const EQApplicationPacket *app);
|
||||
void Handle_OP_DzChooseZoneReply(const EQApplicationPacket *app);
|
||||
void Handle_OP_DzExpeditionInviteResponse(const EQApplicationPacket *app);
|
||||
void Handle_OP_DzListTimers(const EQApplicationPacket *app);
|
||||
void Handle_OP_DzMakeLeader(const EQApplicationPacket *app);
|
||||
void Handle_OP_DzPlayerList(const EQApplicationPacket *app);
|
||||
void Handle_OP_DzRemovePlayer(const EQApplicationPacket *app);
|
||||
void Handle_OP_DzSwapPlayer(const EQApplicationPacket *app);
|
||||
void Handle_OP_DzQuit(const EQApplicationPacket *app);
|
||||
void Handle_OP_Emote(const EQApplicationPacket *app);
|
||||
void Handle_OP_EndLootRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_EnvDamage(const EQApplicationPacket *app);
|
||||
@ -174,6 +183,7 @@
|
||||
void Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_Jump(const EQApplicationPacket *app);
|
||||
void Handle_OP_KeyRing(const EQApplicationPacket *app);
|
||||
void Handle_OP_KickPlayers(const EQApplicationPacket *app);
|
||||
void Handle_OP_LDoNButton(const EQApplicationPacket *app);
|
||||
void Handle_OP_LDoNDisarmTraps(const EQApplicationPacket *app);
|
||||
void Handle_OP_LDoNInspect(const EQApplicationPacket *app);
|
||||
|
||||
@ -44,6 +44,7 @@
|
||||
#include "../common/spdat.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "event_codes.h"
|
||||
#include "expedition.h"
|
||||
#include "guild_mgr.h"
|
||||
#include "map.h"
|
||||
#include "petitions.h"
|
||||
@ -160,6 +161,12 @@ bool Client::Process() {
|
||||
if (TaskPeriodic_Timer.Check() && taskstate)
|
||||
taskstate->TaskPeriodicChecks(this);
|
||||
|
||||
if (dynamiczone_removal_timer.Check() && zone && zone->GetInstanceID() != 0)
|
||||
{
|
||||
dynamiczone_removal_timer.Disable();
|
||||
GoToDzSafeReturnOrBind(zone->GetDynamicZone());
|
||||
}
|
||||
|
||||
if (linkdead_timer.Check()) {
|
||||
LeaveGroup();
|
||||
Save();
|
||||
@ -172,6 +179,13 @@ bool Client::Process() {
|
||||
if (myraid) {
|
||||
myraid->MemberZoned(this);
|
||||
}
|
||||
|
||||
Expedition* expedition = GetExpedition();
|
||||
if (expedition)
|
||||
{
|
||||
expedition->SetMemberStatus(this, ExpeditionMemberStatus::Offline);
|
||||
}
|
||||
|
||||
return false; //delete client
|
||||
}
|
||||
|
||||
@ -257,7 +271,7 @@ bool Client::Process() {
|
||||
* Used in aggro checks
|
||||
*/
|
||||
if (mob_close_scan_timer.Check()) {
|
||||
entity_list.ScanCloseMobs(close_mobs, this, true);
|
||||
entity_list.ScanCloseMobs(close_mobs, this, is_client_moving);
|
||||
}
|
||||
|
||||
bool may_use_attacks = false;
|
||||
@ -560,6 +574,12 @@ bool Client::Process() {
|
||||
client_state = CLIENT_LINKDEAD;
|
||||
AI_Start(CLIENT_LD_TIMEOUT);
|
||||
SendAppearancePacket(AT_Linkdead, 1);
|
||||
|
||||
Expedition* expedition = GetExpedition();
|
||||
if (expedition)
|
||||
{
|
||||
expedition->SetMemberStatus(this, ExpeditionMemberStatus::LinkDead);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -691,6 +711,12 @@ void Client::OnDisconnect(bool hard_disconnect) {
|
||||
}
|
||||
}
|
||||
|
||||
Expedition* expedition = GetExpedition();
|
||||
if (expedition && !bZoning)
|
||||
{
|
||||
expedition->SetMemberStatus(this, ExpeditionMemberStatus::Offline);
|
||||
}
|
||||
|
||||
RemoveAllAuras();
|
||||
|
||||
Mob *Other = trade->With();
|
||||
|
||||
308
zone/command.cpp
308
zone/command.cpp
@ -60,6 +60,7 @@
|
||||
|
||||
#include "data_bucket.h"
|
||||
#include "command.h"
|
||||
#include "expedition.h"
|
||||
#include "guild_mgr.h"
|
||||
#include "map.h"
|
||||
#include "qglobals.h"
|
||||
@ -198,11 +199,14 @@ int command_init(void)
|
||||
command_add("disarmtrap", "Analog for ldon disarm trap for the newer clients since we still don't have it working.", 80, command_disarmtrap) ||
|
||||
command_add("distance", "- Reports the distance between you and your target.", 80, command_distance) ||
|
||||
command_add("doanim", "[animnum] [type] - Send an EmoteAnim for you or your target", 50, command_doanim) ||
|
||||
command_add("dz", "Manage expeditions and dynamic zone instances", 80, command_dz) ||
|
||||
command_add("dzkickplayers", "Removes all players from current expedition. (/kickplayers alternative for pre-RoF clients)", 0, command_dzkickplayers) ||
|
||||
command_add("editmassrespawn", "[name-search] [second-value] - Mass (Zone wide) NPC respawn timer editing command", 100, command_editmassrespawn) ||
|
||||
command_add("emote", "['name'/'world'/'zone'] [type] [message] - Send an emote message", 80, command_emote) ||
|
||||
command_add("emotesearch", "Searches NPC Emotes", 80, command_emotesearch) ||
|
||||
command_add("emoteview", "Lists all NPC Emotes", 80, command_emoteview) ||
|
||||
command_add("enablerecipe", "[recipe_id] - Enables a recipe using the recipe id.", 80, command_enablerecipe) ||
|
||||
command_add("endurance", "Restores you or your target's endurance.", 50, command_endurance) ||
|
||||
command_add("equipitem", "[slotid(0-21)] - Equip the item on your cursor into the specified slot", 50, command_equipitem) ||
|
||||
command_add("face", "- Change the face of your target", 80, command_face) ||
|
||||
command_add("faction", "[Find (criteria | all ) | Review (criteria | all) | Reset (id)] - Resets Player's Faction", 80, command_faction) ||
|
||||
@ -435,6 +439,7 @@ int command_init(void)
|
||||
command_add("wp", "[add/delete] [grid_num] [pause] [wp_num] [-h] - Add/delete a waypoint to/from a wandering grid", 170, command_wp) ||
|
||||
command_add("wpadd", "[pause] [-h] - Add your current location as a waypoint to your NPC target's AI path", 170, command_wpadd) ||
|
||||
command_add("wpinfo", "- Show waypoint info about your NPC target", 170, command_wpinfo) ||
|
||||
command_add("worldwide", "Performs world-wide GM functions such as cast (can be extended for other commands). Use caution", 250, command_worldwide) ||
|
||||
command_add("xtargets", "Show your targets Extended Targets and optionally set how many xtargets they can have.", 250, command_xtargets) ||
|
||||
command_add("zclip", "[min] [max] - modifies and resends zhdr packet", 80, command_zclip) ||
|
||||
command_add("zcolor", "[red] [green] [blue] - Change sky color", 80, command_zcolor) ||
|
||||
@ -734,6 +739,42 @@ void command_logcommand(Client *c, const char *message)
|
||||
/*
|
||||
* commands go below here
|
||||
*/
|
||||
void command_worldwide(Client *c, const Seperator *sep)
|
||||
{
|
||||
std::string sub_command;
|
||||
if (sep->arg[1]) {
|
||||
sub_command = sep->arg[1];
|
||||
}
|
||||
|
||||
if (sub_command == "cast") {
|
||||
if (sep->arg[2][0] && Seperator::IsNumber(sep->arg[2])) {
|
||||
int spell_id = atoi(sep->arg[2]);
|
||||
quest_manager.WorldWideCastSpell(spell_id, 0, 0);
|
||||
worldserver.SendEmoteMessage(0, 0, 15, fmt::format("<SYSTEMWIDE MESSAGE> A GM has cast [{}] world-wide!", GetSpellName(spell_id)).c_str());
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::Yellow, "Usage: #worldwide cast [spellid]");
|
||||
}
|
||||
}
|
||||
|
||||
if (!sep->arg[1]) {
|
||||
c->Message(Chat::White, "This command is used to perform world-wide tasks");
|
||||
c->Message(Chat::White, "Usage: #worldwide cast [spellid]");
|
||||
}
|
||||
}
|
||||
void command_endurance(Client *c, const Seperator *sep)
|
||||
{
|
||||
Mob *t;
|
||||
|
||||
t = c->GetTarget() ? c->GetTarget() : c;
|
||||
|
||||
if (t->IsClient())
|
||||
t->CastToClient()->SetEndurance(t->CastToClient()->GetMaxEndurance());
|
||||
else
|
||||
t->SetEndurance(t->GetMaxEndurance());
|
||||
|
||||
t->Message(Chat::White, "Your endurance has been refilled.");
|
||||
}
|
||||
void command_setstat(Client* c, const Seperator* sep){
|
||||
if(sep->arg[1][0] && sep->arg[2][0] && c->GetTarget()!=0 && c->GetTarget()->IsClient()){
|
||||
c->GetTarget()->CastToClient()->SetStats(atoi(sep->arg[1]),atoi(sep->arg[2]));
|
||||
@ -4837,6 +4878,10 @@ void command_corpse(Client *c, const Seperator *sep)
|
||||
c->Message(Chat::White, "Insufficient status to depop player corpse.");
|
||||
|
||||
}
|
||||
else if (strcasecmp(sep->arg[1], "moveallgraveyard") == 0) {
|
||||
int count = entity_list.MovePlayerCorpsesToGraveyard(true);
|
||||
c->Message(Chat::White, "Moved [%d] player corpse(s) to zone graveyard", count);
|
||||
}
|
||||
else if (sep->arg[1][0] == 0 || strcasecmp(sep->arg[1], "help") == 0) {
|
||||
c->Message(Chat::White, "#Corpse Sub-Commands:");
|
||||
c->Message(Chat::White, " DeleteNPCCorpses");
|
||||
@ -4844,6 +4889,7 @@ void command_corpse(Client *c, const Seperator *sep)
|
||||
c->Message(Chat::White, " ListNPC");
|
||||
c->Message(Chat::White, " ListPlayer");
|
||||
c->Message(Chat::White, " Lock - GM locks the corpse - cannot be looted by non-GM");
|
||||
c->Message(Chat::White, " MoveAllGraveyard - move all player corpses to zone's graveyard or non-instance");
|
||||
c->Message(Chat::White, " UnLock");
|
||||
c->Message(Chat::White, " RemoveCash");
|
||||
c->Message(Chat::White, " InspectLoot");
|
||||
@ -5592,18 +5638,18 @@ void command_depopzone(Client *c, const Seperator *sep)
|
||||
|
||||
void command_devtools(Client *c, const Seperator *sep)
|
||||
{
|
||||
std::string dev_tools_window_key = StringFormat("%i-dev-tools-window-disabled", c->AccountID());
|
||||
std::string dev_tools_key = StringFormat("%i-dev-tools-disabled", c->AccountID());
|
||||
|
||||
/**
|
||||
* Handle window toggle
|
||||
*/
|
||||
if (strcasecmp(sep->arg[1], "disable_window") == 0) {
|
||||
DataBucket::SetData(dev_tools_window_key, "true");
|
||||
c->SetDevToolsWindowEnabled(false);
|
||||
if (strcasecmp(sep->arg[1], "disable") == 0) {
|
||||
DataBucket::SetData(dev_tools_key, "true");
|
||||
c->SetDevToolsEnabled(false);
|
||||
}
|
||||
if (strcasecmp(sep->arg[1], "enable_window") == 0) {
|
||||
DataBucket::DeleteData(dev_tools_window_key);
|
||||
c->SetDevToolsWindowEnabled(true);
|
||||
if (strcasecmp(sep->arg[1], "enable") == 0) {
|
||||
DataBucket::DeleteData(dev_tools_key);
|
||||
c->SetDevToolsEnabled(true);
|
||||
}
|
||||
|
||||
c->ShowDevToolsMenu();
|
||||
@ -6825,6 +6871,210 @@ void command_doanim(Client *c, const Seperator *sep)
|
||||
c->DoAnim(atoi(sep->arg[1]),atoi(sep->arg[2]));
|
||||
}
|
||||
|
||||
void command_dz(Client* c, const Seperator* sep)
|
||||
{
|
||||
if (!c || !zone) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcasecmp(sep->arg[1], "expedition") == 0)
|
||||
{
|
||||
if (strcasecmp(sep->arg[2], "list") == 0)
|
||||
{
|
||||
std::vector<Expedition*> expeditions;
|
||||
for (const auto& expedition : zone->expedition_cache)
|
||||
{
|
||||
expeditions.emplace_back(expedition.second.get());
|
||||
}
|
||||
|
||||
std::sort(expeditions.begin(), expeditions.end(),
|
||||
[](const Expedition* lhs, const Expedition* rhs) {
|
||||
return lhs->GetID() < rhs->GetID();
|
||||
});
|
||||
|
||||
c->Message(Chat::White, fmt::format("Total Active Expeditions: [{}]", expeditions.size()).c_str());
|
||||
for (const auto& expedition : expeditions)
|
||||
{
|
||||
auto leader_saylink = EQ::SayLinkEngine::GenerateQuestSaylink(fmt::format(
|
||||
"#goto {}", expedition->GetLeaderName()), false, expedition->GetLeaderName());
|
||||
auto zone_saylink = EQ::SayLinkEngine::GenerateQuestSaylink(fmt::format(
|
||||
"#zoneinstance {}", expedition->GetInstanceID()), false, "zone");
|
||||
|
||||
auto seconds = expedition->GetDynamicZone().GetSecondsRemaining();
|
||||
|
||||
c->Message(Chat::White, fmt::format(
|
||||
"expedition id: [{}] dz id: [{}] name: [{}] leader: [{}] {}: [{}]:[{}]:[{}]:[{}] members: [{}] remaining: [{:02}:{:02}:{:02}]",
|
||||
expedition->GetID(),
|
||||
expedition->GetDynamicZoneID(),
|
||||
expedition->GetName(),
|
||||
leader_saylink,
|
||||
zone_saylink,
|
||||
ZoneName(expedition->GetDynamicZone().GetZoneID()),
|
||||
expedition->GetDynamicZone().GetZoneID(),
|
||||
expedition->GetInstanceID(),
|
||||
expedition->GetDynamicZone().GetZoneVersion(),
|
||||
expedition->GetMemberCount(),
|
||||
seconds / 3600, // hours
|
||||
(seconds / 60) % 60, // minutes
|
||||
seconds % 60 // seconds
|
||||
).c_str());
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(sep->arg[2], "reload") == 0)
|
||||
{
|
||||
Expedition::CacheAllFromDatabase();
|
||||
c->Message(Chat::White, fmt::format(
|
||||
"Reloaded [{}] expeditions to cache from database.", zone->expedition_cache.size()
|
||||
).c_str());
|
||||
}
|
||||
else if (strcasecmp(sep->arg[2], "destroy") == 0 && sep->IsNumber(3))
|
||||
{
|
||||
auto expedition_id = std::strtoul(sep->arg[3], nullptr, 10);
|
||||
auto expedition = Expedition::FindCachedExpeditionByID(expedition_id);
|
||||
if (expedition)
|
||||
{
|
||||
c->Message(Chat::White, fmt::format("Destroying expedition [{}] ({})",
|
||||
expedition_id, expedition->GetName()).c_str());
|
||||
expedition->RemoveAllMembers();
|
||||
}
|
||||
else
|
||||
{
|
||||
c->Message(Chat::Red, fmt::format("Failed to destroy expedition [{}]", sep->arg[3]).c_str());
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(sep->arg[2], "unlock") == 0 && sep->IsNumber(3))
|
||||
{
|
||||
auto expedition_id = std::strtoul(sep->arg[3], nullptr, 10);
|
||||
auto expedition = Expedition::FindCachedExpeditionByID(expedition_id);
|
||||
if (expedition)
|
||||
{
|
||||
c->Message(Chat::White, fmt::format("Unlocking expedition [{}]", expedition_id).c_str());
|
||||
expedition->SetLocked(false, ExpeditionLockMessage::None, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
c->Message(Chat::Red, fmt::format("Failed to find expedition [{}]", sep->arg[3]).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(sep->arg[1], "list") == 0)
|
||||
{
|
||||
std::string query = SQL(
|
||||
SELECT
|
||||
dynamic_zones.id,
|
||||
dynamic_zones.type,
|
||||
instance_list.id,
|
||||
instance_list.zone,
|
||||
instance_list.version,
|
||||
instance_list.start_time,
|
||||
instance_list.duration,
|
||||
COUNT(instance_list_player.id) member_count
|
||||
FROM dynamic_zones
|
||||
INNER JOIN instance_list ON dynamic_zones.instance_id = instance_list.id
|
||||
LEFT JOIN instance_list_player ON instance_list.id = instance_list_player.id
|
||||
GROUP BY instance_list.id
|
||||
ORDER BY dynamic_zones.id;
|
||||
);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (results.Success())
|
||||
{
|
||||
c->Message(Chat::White, fmt::format("Total Dynamic Zones: [{}]", results.RowCount()).c_str());
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
{
|
||||
auto start_time = strtoul(row[5], nullptr, 10);
|
||||
auto duration = strtoul(row[6], nullptr, 10);
|
||||
auto expire_time = std::chrono::system_clock::from_time_t(start_time + duration);
|
||||
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto remaining = std::chrono::duration_cast<std::chrono::seconds>(expire_time - now);
|
||||
auto seconds = std::max(0, static_cast<int>(remaining.count()));
|
||||
|
||||
bool is_expired = now > expire_time;
|
||||
if (!is_expired || strcasecmp(sep->arg[2], "all") == 0)
|
||||
{
|
||||
uint32_t instance_id = strtoul(row[2], nullptr, 10);
|
||||
auto zone_saylink = is_expired ? "zone" : EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
fmt::format("#zoneinstance {}", instance_id), false, "zone");
|
||||
|
||||
c->Message(Chat::White, fmt::format(
|
||||
"dz id: [{}] type: [{}] {}: [{}]:[{}]:[{}] members: [{}] remaining: [{:02}:{:02}:{:02}]",
|
||||
strtoul(row[0], nullptr, 10), // dynamic_zone_id
|
||||
strtoul(row[1], nullptr, 10), // dynamic_zone_type
|
||||
zone_saylink,
|
||||
strtoul(row[3], nullptr, 10), // instance_zone_id
|
||||
instance_id, // instance_id
|
||||
strtoul(row[4], nullptr, 10), // instance_zone_version
|
||||
strtoul(row[7], nullptr, 10), // instance member_count
|
||||
seconds / 3600, // hours
|
||||
(seconds / 60) % 60, // minutes
|
||||
seconds % 60 // seconds
|
||||
).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(sep->arg[1], "lockouts") == 0)
|
||||
{
|
||||
if (strcasecmp(sep->arg[2], "remove") == 0 && sep->arg[3][0] != '\0')
|
||||
{
|
||||
if (sep->arg[5][0] == '\0')
|
||||
{
|
||||
c->Message(Chat::White, fmt::format(
|
||||
"Removing [{}] lockouts on [{}].", sep->arg[4][0] ? sep->arg[4] : "all", sep->arg[3]
|
||||
).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
c->Message(Chat::White, fmt::format(
|
||||
"Removing [{}]:[{}] lockout on [{}].", sep->arg[4], sep->arg[5], sep->arg[3]
|
||||
).c_str());
|
||||
}
|
||||
Expedition::RemoveLockoutsByCharacterName(sep->arg[3], sep->arg[4], sep->arg[5]);
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(sep->arg[1], "makeleader") == 0 && sep->IsNumber(2) && sep->arg[3][0] != '\0')
|
||||
{
|
||||
auto expedition_id = std::strtoul(sep->arg[2], nullptr, 10);
|
||||
auto expedition = Expedition::FindCachedExpeditionByID(expedition_id);
|
||||
if (expedition)
|
||||
{
|
||||
auto char_name = FormatName(sep->arg[3]);
|
||||
c->Message(Chat::White, fmt::format("Setting expedition [{}] leader to [{}]", expedition_id, char_name).c_str());
|
||||
expedition->SendWorldMakeLeaderRequest(c->CharacterID(), char_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
c->Message(Chat::Red, fmt::format("Failed to find expedition [{}]", expedition_id).c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
c->Message(Chat::White, "#dz usage:");
|
||||
c->Message(Chat::White, "#dz expedition list - list expeditions in current zone cache");
|
||||
c->Message(Chat::White, "#dz expedition reload - reload expedition zone cache from database");
|
||||
c->Message(Chat::White, "#dz expedition destroy <expedition_id> - destroy expedition globally (must be in cache)");
|
||||
c->Message(Chat::White, "#dz expedition unlock <expedition_id> - unlock expedition");
|
||||
c->Message(Chat::White, "#dz list [all] - list dynamic zone instances from database -- 'all' includes expired");
|
||||
c->Message(Chat::White, "#dz lockouts remove <char_name> - delete all of character's expedition lockouts");
|
||||
c->Message(Chat::White, "#dz lockouts remove <char_name> \"<expedition_name>\" - delete lockouts by expedition");
|
||||
c->Message(Chat::White, "#dz lockouts remove <char_name> \"<expedition_name>\" \"<event_name>\" - delete lockout by expedition event");
|
||||
c->Message(Chat::White, "#dz makeleader <expedition_id> <character_name> - set new expedition leader");
|
||||
}
|
||||
}
|
||||
|
||||
void command_dzkickplayers(Client* c, const Seperator* sep)
|
||||
{
|
||||
if (c)
|
||||
{
|
||||
auto expedition = c->GetExpedition();
|
||||
if (expedition)
|
||||
{
|
||||
expedition->DzKickPlayers(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void command_editmassrespawn(Client* c, const Seperator* sep)
|
||||
{
|
||||
if (strcasecmp(sep->arg[1], "usage") == 0) {
|
||||
@ -6879,7 +7129,7 @@ void command_editmassrespawn(Client* c, const Seperator* sep)
|
||||
|
||||
int results_count = 0;
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
auto results = content_db.QueryDatabase(query);
|
||||
if (results.Success() && results.RowCount()) {
|
||||
|
||||
results_count = results.RowCount();
|
||||
@ -6906,7 +7156,7 @@ void command_editmassrespawn(Client* c, const Seperator* sep)
|
||||
|
||||
if (change_apply) {
|
||||
|
||||
results = database.QueryDatabase(
|
||||
results = content_db.QueryDatabase(
|
||||
fmt::format(
|
||||
SQL(
|
||||
UPDATE spawn2
|
||||
@ -7741,13 +7991,6 @@ void command_itemsearch(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> amounts = {
|
||||
"1",
|
||||
"10",
|
||||
"100",
|
||||
"1000"
|
||||
};
|
||||
|
||||
int count = 0;
|
||||
char sName[64];
|
||||
char sCriteria[255];
|
||||
@ -7761,14 +8004,25 @@ void command_itemsearch(Client *c, const Seperator *sep)
|
||||
pdest = strstr(sName, sCriteria);
|
||||
if (pdest != nullptr) {
|
||||
linker.SetItemData(item);
|
||||
|
||||
std::string saylink_commands;
|
||||
for (auto &amount : amounts) {
|
||||
saylink_commands += EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
"#si " + std::to_string(item->ID) + " " + amount,
|
||||
std::string item_id = std::to_string(item->ID);
|
||||
std::string saylink_commands =
|
||||
"[" +
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
"#si " + item_id,
|
||||
false,
|
||||
"[" + amount + "] "
|
||||
);
|
||||
"X"
|
||||
) +
|
||||
"] ";
|
||||
if (item->Stackable && item->StackSize > 1) {
|
||||
std::string stack_size = std::to_string(item->StackSize);
|
||||
saylink_commands +=
|
||||
"[" +
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
"#si " + item_id + " " + stack_size,
|
||||
false,
|
||||
stack_size
|
||||
) +
|
||||
"]";
|
||||
}
|
||||
|
||||
c->Message(
|
||||
@ -7776,8 +8030,8 @@ void command_itemsearch(Client *c, const Seperator *sep)
|
||||
fmt::format(
|
||||
" Summon {} [{}] [{}]",
|
||||
saylink_commands,
|
||||
item->ID,
|
||||
linker.GenerateLink()
|
||||
linker.GenerateLink(),
|
||||
item->ID
|
||||
).c_str()
|
||||
);
|
||||
|
||||
@ -7855,14 +8109,10 @@ void command_setcrystals(Client *c, const Seperator *sep)
|
||||
else if(!strcasecmp(sep->arg[1], "radiant"))
|
||||
{
|
||||
t->SetRadiantCrystals(atoi(sep->arg[2]));
|
||||
t->SendCrystalCounts();
|
||||
t->SaveCurrency();
|
||||
}
|
||||
else if(!strcasecmp(sep->arg[1], "ebon"))
|
||||
{
|
||||
t->SetEbonCrystals(atoi(sep->arg[2]));
|
||||
t->SendCrystalCounts();
|
||||
t->SaveCurrency();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -92,11 +92,14 @@ void command_disablerecipe(Client *c, const Seperator *sep);
|
||||
void command_disarmtrap(Client *c, const Seperator *sep);
|
||||
void command_distance(Client *c, const Seperator *sep);
|
||||
void command_doanim(Client *c, const Seperator *sep);
|
||||
void command_dz(Client *c, const Seperator *sep);
|
||||
void command_dzkickplayers(Client *c, const Seperator *sep);
|
||||
void command_editmassrespawn(Client* c, const Seperator* sep);
|
||||
void command_emote(Client *c, const Seperator *sep);
|
||||
void command_emotesearch(Client* c, const Seperator *sep);
|
||||
void command_emoteview(Client* c, const Seperator *sep);
|
||||
void command_enablerecipe(Client *c, const Seperator *sep);
|
||||
void command_endurance(Client *c, const Seperator *sep);
|
||||
void command_equipitem(Client *c, const Seperator *sep);
|
||||
void command_face(Client *c, const Seperator *sep);
|
||||
void command_faction(Client *c, const Seperator *sep);
|
||||
@ -342,6 +345,7 @@ void command_worldshutdown(Client *c, const Seperator *sep);
|
||||
void command_wp(Client *c, const Seperator *sep);
|
||||
void command_wpadd(Client *c, const Seperator *sep);
|
||||
void command_wpinfo(Client *c, const Seperator *sep);
|
||||
void command_worldwide(Client *c, const Seperator *sep);
|
||||
void command_xtargets(Client *c, const Seperator *sep);
|
||||
void command_zclip(Client *c, const Seperator *sep);
|
||||
void command_zcolor(Client *c, const Seperator *sep);
|
||||
|
||||
@ -195,7 +195,11 @@ enum {
|
||||
COUNTER_AVOID_DAMAGE = 44,
|
||||
PROX_AGGRO = 45,
|
||||
IMMUNE_RANGED_ATTACKS = 46,
|
||||
MAX_SPECIAL_ATTACK = 47
|
||||
IMMUNE_DAMAGE_CLIENT = 47,
|
||||
IMMUNE_DAMAGE_NPC = 48,
|
||||
IMMUNE_AGGRO_CLIENT = 49,
|
||||
IMMUNE_AGGRO_NPC = 50,
|
||||
MAX_SPECIAL_ATTACK = 51
|
||||
};
|
||||
|
||||
typedef enum { //fear states
|
||||
@ -786,5 +790,12 @@ struct DamageHitInfo {
|
||||
EQ::skills::SkillType skill;
|
||||
};
|
||||
|
||||
struct ExpeditionInvite
|
||||
{
|
||||
uint32_t expedition_id;
|
||||
std::string inviter_name;
|
||||
std::string swap_remove_name;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -38,6 +38,7 @@ Child of the Mob class.
|
||||
|
||||
#include "corpse.h"
|
||||
#include "entity.h"
|
||||
#include "expedition.h"
|
||||
#include "groups.h"
|
||||
#include "mob.h"
|
||||
#include "raids.h"
|
||||
@ -825,22 +826,7 @@ bool Corpse::Process() {
|
||||
}
|
||||
|
||||
if (corpse_graveyard_timer.Check()) {
|
||||
if (zone->HasGraveyard()) {
|
||||
Save();
|
||||
player_corpse_depop = true;
|
||||
database.SendCharacterCorpseToGraveyard(corpse_db_id, zone->graveyard_zoneid(),
|
||||
(zone->GetZoneID() == zone->graveyard_zoneid()) ? zone->GetInstanceID() : 0, zone->GetGraveyardPoint());
|
||||
corpse_graveyard_timer.Disable();
|
||||
auto pack = new ServerPacket(ServerOP_SpawnPlayerCorpse, sizeof(SpawnPlayerCorpse_Struct));
|
||||
SpawnPlayerCorpse_Struct* spc = (SpawnPlayerCorpse_Struct*)pack->pBuffer;
|
||||
spc->player_corpse_id = corpse_db_id;
|
||||
spc->zone_id = zone->graveyard_zoneid();
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
LogDebug("Moved [{}] player corpse to the designated graveyard in zone [{}]", this->GetName(), ZoneName(zone->graveyard_zoneid()));
|
||||
corpse_db_id = 0;
|
||||
}
|
||||
|
||||
MovePlayerCorpseToGraveyard();
|
||||
corpse_graveyard_timer.Disable();
|
||||
return false;
|
||||
}
|
||||
@ -1275,6 +1261,20 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
if (zone && zone->GetInstanceID() != 0)
|
||||
{
|
||||
// expeditions may prevent looting based on client's lockouts
|
||||
auto expedition = Expedition::FindCachedExpeditionByZoneInstance(zone->GetZoneID(), zone->GetInstanceID());
|
||||
if (expedition && !expedition->CanClientLootCorpse(client, GetNPCTypeID(), GetID()))
|
||||
{
|
||||
client->MessageString(Chat::Red, LOOT_NOT_ALLOWED, inst->GetItem()->Name);
|
||||
client->QueuePacket(app);
|
||||
SendEndLootErrorPacket(client);
|
||||
ResetLooter();
|
||||
delete inst;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// do we want this to have a fail option too?
|
||||
parse->EventItem(EVENT_LOOT, client, inst, this, buf, 0);
|
||||
@ -1628,3 +1628,53 @@ void Corpse::LoadPlayerCorpseDecayTime(uint32 corpse_db_id){
|
||||
corpse_graveyard_timer.SetTimer(3000);
|
||||
}
|
||||
}
|
||||
|
||||
void Corpse::SendWorldSpawnPlayerCorpseInZone(uint32_t zone_id)
|
||||
{
|
||||
auto pack = std::unique_ptr<ServerPacket>(new ServerPacket(ServerOP_SpawnPlayerCorpse, sizeof(SpawnPlayerCorpse_Struct)));
|
||||
SpawnPlayerCorpse_Struct* spc = reinterpret_cast<SpawnPlayerCorpse_Struct*>(pack->pBuffer);
|
||||
spc->player_corpse_id = corpse_db_id;
|
||||
spc->zone_id = zone_id;
|
||||
worldserver.SendPacket(pack.get());
|
||||
}
|
||||
|
||||
bool Corpse::MovePlayerCorpseToGraveyard()
|
||||
{
|
||||
if (IsPlayerCorpse() && zone && zone->HasGraveyard())
|
||||
{
|
||||
Save();
|
||||
|
||||
uint16_t instance_id = (zone->GetZoneID() == zone->graveyard_zoneid()) ? zone->GetInstanceID() : 0;
|
||||
database.SendCharacterCorpseToGraveyard(corpse_db_id, zone->graveyard_zoneid(), instance_id, zone->GetGraveyardPoint());
|
||||
SendWorldSpawnPlayerCorpseInZone(zone->graveyard_zoneid());
|
||||
|
||||
corpse_db_id = 0;
|
||||
player_corpse_depop = true;
|
||||
corpse_graveyard_timer.Disable();
|
||||
|
||||
LogDebug("Moved [{}] player corpse to the designated graveyard in zone [{}]", GetName(), ZoneName(zone->graveyard_zoneid()));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Corpse::MovePlayerCorpseToNonInstance()
|
||||
{
|
||||
if (IsPlayerCorpse() && zone && zone->GetInstanceID() != 0)
|
||||
{
|
||||
Save();
|
||||
|
||||
database.SendCharacterCorpseToNonInstance(corpse_db_id);
|
||||
SendWorldSpawnPlayerCorpseInZone(zone->GetZoneID());
|
||||
|
||||
corpse_db_id = 0;
|
||||
player_corpse_depop = true;
|
||||
corpse_graveyard_timer.Disable();
|
||||
|
||||
LogDebug("Moved [{}] player corpse to non-instance version of zone [{}]", GetName(), ZoneName(zone->GetZoneID()));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -79,6 +79,9 @@ class Corpse : public Mob {
|
||||
void SetConsentGuildID(uint32 guild_id) { if (IsPlayerCorpse()) { consented_guild_id = guild_id; } }
|
||||
void AddConsentName(std::string consent_player_name);
|
||||
void RemoveConsentName(std::string consent_player_name);
|
||||
void SendWorldSpawnPlayerCorpseInZone(uint32_t zone_id);
|
||||
bool MovePlayerCorpseToGraveyard();
|
||||
bool MovePlayerCorpseToNonInstance();
|
||||
|
||||
void Delete();
|
||||
void Bury();
|
||||
|
||||
@ -207,6 +207,8 @@ void Doors::HandleClick(Client* sender, uint8 trigger) {
|
||||
}
|
||||
}
|
||||
|
||||
// todo: if IsDzDoor() call Client::MovePCDynamicZone(target_zone_id) (for systems that use dzs)
|
||||
|
||||
uint32 required_key_item = GetKeyItem();
|
||||
uint8 disable_add_to_key_ring = GetNoKeyring();
|
||||
uint32 player_has_key = 0;
|
||||
|
||||
544
zone/dynamiczone.cpp
Normal file
544
zone/dynamiczone.cpp
Normal file
@ -0,0 +1,544 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "dynamiczone.h"
|
||||
#include "client.h"
|
||||
#include "worldserver.h"
|
||||
#include "zonedb.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
|
||||
extern WorldServer worldserver;
|
||||
|
||||
DynamicZone::DynamicZone(
|
||||
uint32_t zone_id, uint32_t version, uint32_t duration, DynamicZoneType type
|
||||
) :
|
||||
m_zone_id(zone_id),
|
||||
m_version(version),
|
||||
m_duration(duration),
|
||||
m_type(type)
|
||||
{
|
||||
}
|
||||
|
||||
DynamicZone::DynamicZone(
|
||||
std::string zone_shortname, uint32_t version, uint32_t duration, DynamicZoneType type
|
||||
) :
|
||||
m_version(version),
|
||||
m_duration(duration),
|
||||
m_type(type)
|
||||
{
|
||||
m_zone_id = ZoneID(zone_shortname.c_str());
|
||||
|
||||
if (!m_zone_id)
|
||||
{
|
||||
LogDynamicZones("Failed to get zone id for zone [{}]", zone_shortname);
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_map<uint32_t, DynamicZone> DynamicZone::LoadMultipleDzFromDatabase(
|
||||
const std::vector<uint32_t>& dynamic_zone_ids)
|
||||
{
|
||||
LogDynamicZonesDetail("Loading dynamic zone data for [{}] instances", dynamic_zone_ids.size());
|
||||
|
||||
std::string in_dynamic_zone_ids_query = fmt::format("{}", fmt::join(dynamic_zone_ids, ","));
|
||||
|
||||
std::unordered_map<uint32_t, DynamicZone> dynamic_zones;
|
||||
|
||||
if (!in_dynamic_zone_ids_query.empty())
|
||||
{
|
||||
std::string query = fmt::format(SQL(
|
||||
{} WHERE dynamic_zones.id IN ({});
|
||||
), DynamicZoneSelectQuery(), in_dynamic_zone_ids_query);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (results.Success())
|
||||
{
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
{
|
||||
DynamicZone dz;
|
||||
dz.LoadDatabaseResult(row);
|
||||
dynamic_zones.emplace(dz.GetID(), dz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dynamic_zones;
|
||||
}
|
||||
|
||||
uint32_t DynamicZone::Create()
|
||||
{
|
||||
if (m_id != 0)
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
if (GetInstanceID() == 0)
|
||||
{
|
||||
CreateInstance();
|
||||
}
|
||||
|
||||
m_id = SaveToDatabase();
|
||||
|
||||
return m_id;
|
||||
}
|
||||
|
||||
uint32_t DynamicZone::CreateInstance()
|
||||
{
|
||||
if (m_instance_id)
|
||||
{
|
||||
LogDynamicZones("CreateInstance failed, instance id [{}] already created", m_instance_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!m_zone_id)
|
||||
{
|
||||
LogDynamicZones("CreateInstance failed, invalid zone id [{}]", m_zone_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t instance_id = 0;
|
||||
if (!database.GetUnusedInstanceID(instance_id)) // todo: doesn't this race with insert?
|
||||
{
|
||||
LogDynamicZones("Failed to find unused instance id");
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_start_time = std::chrono::system_clock::now();
|
||||
auto start_time = std::chrono::system_clock::to_time_t(m_start_time);
|
||||
|
||||
std::string query = fmt::format(SQL(
|
||||
INSERT INTO instance_list
|
||||
(id, zone, version, start_time, duration)
|
||||
VALUES
|
||||
({}, {}, {}, {}, {})
|
||||
), instance_id, m_zone_id, m_version, start_time, m_duration.count());
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
{
|
||||
LogDynamicZones("Failed to create instance [{}] for Dynamic Zone [{}]", instance_id, m_zone_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_instance_id = instance_id;
|
||||
m_never_expires = false;
|
||||
m_expire_time = m_start_time + m_duration;
|
||||
|
||||
return m_instance_id;
|
||||
}
|
||||
|
||||
std::string DynamicZone::DynamicZoneSelectQuery()
|
||||
{
|
||||
return std::string(SQL(
|
||||
SELECT
|
||||
instance_list.id,
|
||||
instance_list.zone,
|
||||
instance_list.version,
|
||||
instance_list.start_time,
|
||||
instance_list.duration,
|
||||
instance_list.never_expires,
|
||||
dynamic_zones.id,
|
||||
dynamic_zones.type,
|
||||
dynamic_zones.compass_zone_id,
|
||||
dynamic_zones.compass_x,
|
||||
dynamic_zones.compass_y,
|
||||
dynamic_zones.compass_z,
|
||||
dynamic_zones.safe_return_zone_id,
|
||||
dynamic_zones.safe_return_x,
|
||||
dynamic_zones.safe_return_y,
|
||||
dynamic_zones.safe_return_z,
|
||||
dynamic_zones.safe_return_heading,
|
||||
dynamic_zones.zone_in_x,
|
||||
dynamic_zones.zone_in_y,
|
||||
dynamic_zones.zone_in_z,
|
||||
dynamic_zones.zone_in_heading,
|
||||
dynamic_zones.has_zone_in
|
||||
FROM dynamic_zones
|
||||
INNER JOIN instance_list ON dynamic_zones.instance_id = instance_list.id
|
||||
));
|
||||
}
|
||||
|
||||
void DynamicZone::LoadDatabaseResult(MySQLRequestRow& row)
|
||||
{
|
||||
m_instance_id = strtoul(row[0], nullptr, 10);
|
||||
m_zone_id = strtoul(row[1], nullptr, 10);
|
||||
m_version = strtoul(row[2], nullptr, 10);
|
||||
m_start_time = std::chrono::system_clock::from_time_t(strtoul(row[3], nullptr, 10));
|
||||
m_duration = std::chrono::seconds(strtoul(row[4], nullptr, 10));
|
||||
m_expire_time = m_start_time + m_duration;
|
||||
m_never_expires = (strtoul(row[5], nullptr, 10) != 0);
|
||||
m_id = strtoul(row[6], nullptr, 10);
|
||||
m_type = static_cast<DynamicZoneType>(strtoul(row[7], nullptr, 10));
|
||||
m_compass.zone_id = strtoul(row[8], nullptr, 10);
|
||||
m_compass.x = strtof(row[9], nullptr);
|
||||
m_compass.y = strtof(row[10], nullptr);
|
||||
m_compass.z = strtof(row[11], nullptr);
|
||||
m_safereturn.zone_id = strtoul(row[12], nullptr, 10);
|
||||
m_safereturn.x = strtof(row[13], nullptr);
|
||||
m_safereturn.y = strtof(row[14], nullptr);
|
||||
m_safereturn.z = strtof(row[15], nullptr);
|
||||
m_safereturn.heading = strtof(row[16], nullptr);
|
||||
m_zonein.x = strtof(row[17], nullptr);
|
||||
m_zonein.y = strtof(row[18], nullptr);
|
||||
m_zonein.z = strtof(row[19], nullptr);
|
||||
m_zonein.heading = strtof(row[20], nullptr);
|
||||
m_has_zonein = (strtoul(row[21], nullptr, 10) != 0);
|
||||
}
|
||||
|
||||
uint32_t DynamicZone::SaveToDatabase()
|
||||
{
|
||||
LogDynamicZonesDetail("Saving dz instance [{}] to database", m_instance_id);
|
||||
|
||||
if (m_instance_id != 0)
|
||||
{
|
||||
std::string query = fmt::format(SQL(
|
||||
INSERT INTO dynamic_zones
|
||||
(
|
||||
instance_id,
|
||||
type,
|
||||
compass_zone_id,
|
||||
compass_x,
|
||||
compass_y,
|
||||
compass_z,
|
||||
safe_return_zone_id,
|
||||
safe_return_x,
|
||||
safe_return_y,
|
||||
safe_return_z,
|
||||
safe_return_heading,
|
||||
zone_in_x,
|
||||
zone_in_y,
|
||||
zone_in_z,
|
||||
zone_in_heading,
|
||||
has_zone_in
|
||||
)
|
||||
VALUES
|
||||
({}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {});
|
||||
),
|
||||
m_instance_id,
|
||||
static_cast<uint8_t>(m_type),
|
||||
m_compass.zone_id,
|
||||
m_compass.x,
|
||||
m_compass.y,
|
||||
m_compass.z,
|
||||
m_safereturn.zone_id,
|
||||
m_safereturn.x,
|
||||
m_safereturn.y,
|
||||
m_safereturn.z,
|
||||
m_safereturn.heading,
|
||||
m_zonein.x,
|
||||
m_zonein.y,
|
||||
m_zonein.z,
|
||||
m_zonein.heading,
|
||||
m_has_zonein
|
||||
);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (results.Success())
|
||||
{
|
||||
return results.LastInsertedID();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DynamicZone::SaveCompassToDatabase()
|
||||
{
|
||||
LogDynamicZonesDetail(
|
||||
"Instance [{}] saving compass zone: [{}] xyz: ([{}], [{}], [{}])",
|
||||
m_instance_id, m_compass.zone_id, m_compass.x, m_compass.y, m_compass.z
|
||||
);
|
||||
|
||||
if (m_instance_id != 0)
|
||||
{
|
||||
std::string query = fmt::format(SQL(
|
||||
UPDATE dynamic_zones SET
|
||||
compass_zone_id = {},
|
||||
compass_x = {},
|
||||
compass_y = {},
|
||||
compass_z = {}
|
||||
WHERE instance_id = {};
|
||||
),
|
||||
m_compass.zone_id,
|
||||
m_compass.x,
|
||||
m_compass.y,
|
||||
m_compass.z,
|
||||
m_instance_id
|
||||
);
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZone::SaveSafeReturnToDatabase()
|
||||
{
|
||||
LogDynamicZonesDetail(
|
||||
"Instance [{}] saving safereturn zone: [{}] xyzh: ([{}], [{}], [{}], [{}])",
|
||||
m_instance_id, m_safereturn.zone_id, m_safereturn.x, m_safereturn.y, m_safereturn.z, m_safereturn.heading
|
||||
);
|
||||
|
||||
if (m_instance_id != 0)
|
||||
{
|
||||
std::string query = fmt::format(SQL(
|
||||
UPDATE dynamic_zones SET
|
||||
safe_return_zone_id = {},
|
||||
safe_return_x = {},
|
||||
safe_return_y = {},
|
||||
safe_return_z = {},
|
||||
safe_return_heading = {}
|
||||
WHERE instance_id = {};
|
||||
),
|
||||
m_safereturn.zone_id,
|
||||
m_safereturn.x,
|
||||
m_safereturn.y,
|
||||
m_safereturn.z,
|
||||
m_safereturn.heading,
|
||||
m_instance_id
|
||||
);
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZone::SaveZoneInLocationToDatabase()
|
||||
{
|
||||
LogDynamicZonesDetail(
|
||||
"Instance [{}] saving zonein zone: [{}] xyzh: ([{}], [{}], [{}], [{}]) has: [{}]",
|
||||
m_instance_id, m_zone_id, m_zonein.x, m_zonein.y, m_zonein.z, m_zonein.heading, m_has_zonein
|
||||
);
|
||||
|
||||
if (m_instance_id != 0)
|
||||
{
|
||||
std::string query = fmt::format(SQL(
|
||||
UPDATE dynamic_zones SET
|
||||
zone_in_x = {},
|
||||
zone_in_y = {},
|
||||
zone_in_z = {},
|
||||
zone_in_heading = {},
|
||||
has_zone_in = {}
|
||||
WHERE instance_id = {};
|
||||
),
|
||||
m_zonein.x,
|
||||
m_zonein.y,
|
||||
m_zonein.z,
|
||||
m_zonein.heading,
|
||||
m_has_zonein,
|
||||
m_instance_id
|
||||
);
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZone::AddCharacter(uint32_t character_id)
|
||||
{
|
||||
database.AddClientToInstance(m_instance_id, character_id);
|
||||
SendInstanceCharacterChange(character_id, false); // stops client kick timer
|
||||
}
|
||||
|
||||
void DynamicZone::RemoveCharacter(uint32_t character_id)
|
||||
{
|
||||
database.RemoveClientFromInstance(m_instance_id, character_id);
|
||||
SendInstanceCharacterChange(character_id, true); // start client kick timer
|
||||
}
|
||||
|
||||
void DynamicZone::RemoveAllCharacters(bool enable_removal_timers)
|
||||
{
|
||||
if (GetInstanceID() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable_removal_timers)
|
||||
{
|
||||
// just remove all clients in bulk instead of only characters assigned to the instance
|
||||
if (IsCurrentZoneDzInstance())
|
||||
{
|
||||
for (const auto& client_iter : entity_list.GetClientList())
|
||||
{
|
||||
if (client_iter.second)
|
||||
{
|
||||
client_iter.second->SetDzRemovalTimer(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (GetInstanceID() != 0)
|
||||
{
|
||||
uint32_t packsize = sizeof(ServerDzCharacter_Struct);
|
||||
auto pack = std::unique_ptr<ServerPacket>(new ServerPacket(ServerOP_DzRemoveAllCharacters, packsize));
|
||||
auto packbuf = reinterpret_cast<ServerDzCharacter_Struct*>(pack->pBuffer);
|
||||
packbuf->zone_id = GetZoneID();
|
||||
packbuf->instance_id = GetInstanceID();
|
||||
packbuf->remove = true;
|
||||
packbuf->character_id = 0;
|
||||
worldserver.SendPacket(pack.get());
|
||||
}
|
||||
}
|
||||
|
||||
database.RemoveClientsFromInstance(GetInstanceID());
|
||||
}
|
||||
|
||||
void DynamicZone::SaveInstanceMembersToDatabase(const std::vector<uint32_t>& character_ids)
|
||||
{
|
||||
LogDynamicZonesDetail("Saving [{}] instance members to database", character_ids.size());
|
||||
|
||||
std::string insert_values;
|
||||
for (const auto& character_id : character_ids)
|
||||
{
|
||||
fmt::format_to(std::back_inserter(insert_values), "({}, {}),", m_instance_id, character_id);
|
||||
}
|
||||
|
||||
if (!insert_values.empty())
|
||||
{
|
||||
insert_values.pop_back(); // trailing comma
|
||||
|
||||
std::string query = fmt::format(SQL(
|
||||
REPLACE INTO instance_list_player (id, charid) VALUES {};
|
||||
), insert_values);
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZone::SendInstanceCharacterChange(uint32_t character_id, bool removed)
|
||||
{
|
||||
// if removing, sets removal timer on client inside the instance
|
||||
if (IsCurrentZoneDzInstance())
|
||||
{
|
||||
Client* client = entity_list.GetClientByCharID(character_id);
|
||||
if (client)
|
||||
{
|
||||
client->SetDzRemovalTimer(removed);
|
||||
}
|
||||
}
|
||||
else if (GetInstanceID() != 0)
|
||||
{
|
||||
uint32_t packsize = sizeof(ServerDzCharacter_Struct);
|
||||
auto pack = std::unique_ptr<ServerPacket>(new ServerPacket(ServerOP_DzCharacterChange, packsize));
|
||||
auto packbuf = reinterpret_cast<ServerDzCharacter_Struct*>(pack->pBuffer);
|
||||
packbuf->zone_id = GetZoneID();
|
||||
packbuf->instance_id = GetInstanceID();
|
||||
packbuf->remove = removed;
|
||||
packbuf->character_id = character_id;
|
||||
worldserver.SendPacket(pack.get());
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZone::SetCompass(const DynamicZoneLocation& location, bool update_db)
|
||||
{
|
||||
m_compass = location;
|
||||
|
||||
if (update_db)
|
||||
{
|
||||
SaveCompassToDatabase();
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZone::SetSafeReturn(const DynamicZoneLocation& location, bool update_db)
|
||||
{
|
||||
m_safereturn = location;
|
||||
|
||||
if (update_db)
|
||||
{
|
||||
SaveSafeReturnToDatabase();
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZone::SetZoneInLocation(const DynamicZoneLocation& location, bool update_db)
|
||||
{
|
||||
m_zonein = location;
|
||||
m_has_zonein = true;
|
||||
|
||||
if (update_db)
|
||||
{
|
||||
SaveZoneInLocationToDatabase();
|
||||
}
|
||||
}
|
||||
|
||||
bool DynamicZone::IsCurrentZoneDzInstance() const
|
||||
{
|
||||
return (zone && zone->GetInstanceID() != 0 && zone->GetInstanceID() == GetInstanceID());
|
||||
}
|
||||
|
||||
bool DynamicZone::IsInstanceID(uint32_t instance_id) const
|
||||
{
|
||||
return (GetInstanceID() != 0 && GetInstanceID() == instance_id);
|
||||
}
|
||||
|
||||
bool DynamicZone::IsSameDz(uint32_t zone_id, uint32_t instance_id) const
|
||||
{
|
||||
return zone_id == m_zone_id && instance_id == m_instance_id;
|
||||
}
|
||||
|
||||
uint32_t DynamicZone::GetSecondsRemaining() const
|
||||
{
|
||||
auto now = std::chrono::system_clock::now();
|
||||
if (m_expire_time > now)
|
||||
{
|
||||
auto remaining = m_expire_time - now;
|
||||
return static_cast<uint32_t>(std::chrono::duration_cast<std::chrono::seconds>(remaining).count());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DynamicZone::SetUpdatedDuration(uint32_t new_duration)
|
||||
{
|
||||
// preserves original start time, just modifies duration and expire time
|
||||
m_duration = std::chrono::seconds(new_duration);
|
||||
m_expire_time = m_start_time + m_duration;
|
||||
|
||||
LogDynamicZones("Updated zone [{}]:[{}] seconds remaining: [{}]",
|
||||
m_zone_id, m_instance_id, GetSecondsRemaining());
|
||||
|
||||
if (zone && IsCurrentZoneDzInstance())
|
||||
{
|
||||
zone->SetInstanceTimer(GetSecondsRemaining());
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicZone::HandleWorldMessage(ServerPacket* pack)
|
||||
{
|
||||
switch (pack->opcode)
|
||||
{
|
||||
case ServerOP_DzCharacterChange:
|
||||
{
|
||||
auto buf = reinterpret_cast<ServerDzCharacter_Struct*>(pack->pBuffer);
|
||||
Client* client = entity_list.GetClientByCharID(buf->character_id);
|
||||
if (client)
|
||||
{
|
||||
client->SetDzRemovalTimer(buf->remove); // instance kick timer
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ServerOP_DzRemoveAllCharacters:
|
||||
{
|
||||
auto buf = reinterpret_cast<ServerDzCharacter_Struct*>(pack->pBuffer);
|
||||
if (buf->remove)
|
||||
{
|
||||
for (const auto& client_list_iter : entity_list.GetClientList())
|
||||
{
|
||||
if (client_list_iter.second)
|
||||
{
|
||||
client_list_iter.second->SetDzRemovalTimer(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
132
zone/dynamiczone.h
Normal file
132
zone/dynamiczone.h
Normal file
@ -0,0 +1,132 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* 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 DYNAMICZONE_H
|
||||
#define DYNAMICZONE_H
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
class MySQLRequestRow;
|
||||
class ServerPacket;
|
||||
|
||||
enum class DynamicZoneType : uint8_t
|
||||
{
|
||||
None = 0,
|
||||
Expedition,
|
||||
Tutorial,
|
||||
Task,
|
||||
Mission, // Shared Task
|
||||
Quest
|
||||
};
|
||||
|
||||
struct DynamicZoneLocation
|
||||
{
|
||||
uint32_t zone_id = 0;
|
||||
float x = 0.0f;
|
||||
float y = 0.0f;
|
||||
float z = 0.0f;
|
||||
float heading = 0.0f;
|
||||
|
||||
DynamicZoneLocation() = default;
|
||||
DynamicZoneLocation(uint32_t zone_id_, float x_, float y_, float z_, float heading_)
|
||||
: zone_id(zone_id_), x(x_), y(y_), z(z_), heading(heading_) {}
|
||||
};
|
||||
|
||||
class DynamicZone
|
||||
{
|
||||
public:
|
||||
DynamicZone() = default;
|
||||
DynamicZone(uint32_t zone_id, uint32_t version, uint32_t duration, DynamicZoneType type);
|
||||
DynamicZone(std::string zone_shortname, uint32_t version, uint32_t duration, DynamicZoneType type);
|
||||
DynamicZone(uint32_t dz_id) : m_id(dz_id) {}
|
||||
DynamicZone(DynamicZoneType type) : m_type(type) {}
|
||||
|
||||
static std::unordered_map<uint32_t, DynamicZone> LoadMultipleDzFromDatabase(
|
||||
const std::vector<uint32_t>& dynamic_zone_ids);
|
||||
static void HandleWorldMessage(ServerPacket* pack);
|
||||
|
||||
uint64_t GetExpireTime() const { return std::chrono::system_clock::to_time_t(m_expire_time); }
|
||||
uint32_t GetID() const { return m_id; }
|
||||
uint16_t GetInstanceID() const { return static_cast<uint16_t>(m_instance_id); }
|
||||
uint32_t GetSecondsRemaining() const;
|
||||
uint16_t GetZoneID() const { return static_cast<uint16_t>(m_zone_id); }
|
||||
uint32_t GetZoneIndex() const { return (m_instance_id << 16) | (m_zone_id & 0xffff); }
|
||||
uint32_t GetZoneVersion() const { return m_version; }
|
||||
DynamicZoneType GetType() const { return m_type; }
|
||||
DynamicZoneLocation GetCompassLocation() const { return m_compass; }
|
||||
DynamicZoneLocation GetSafeReturnLocation() const { return m_safereturn; }
|
||||
DynamicZoneLocation GetZoneInLocation() const { return m_zonein; }
|
||||
|
||||
void AddCharacter(uint32_t character_id);
|
||||
uint32_t Create();
|
||||
uint32_t CreateInstance();
|
||||
bool HasZoneInLocation() const { return m_has_zonein; }
|
||||
bool IsCurrentZoneDzInstance() const;
|
||||
bool IsInstanceID(uint32_t instance_id) const;
|
||||
bool IsValid() const { return m_instance_id != 0; }
|
||||
bool IsSameDz(uint32_t zone_id, uint32_t instance_id) const;
|
||||
void RemoveAllCharacters(bool enable_removal_timers = true);
|
||||
void RemoveCharacter(uint32_t character_id);
|
||||
void SaveInstanceMembersToDatabase(const std::vector<uint32_t>& character_ids);
|
||||
void SendInstanceCharacterChange(uint32_t character_id, bool removed);
|
||||
void SetCompass(const DynamicZoneLocation& location, bool update_db = false);
|
||||
void SetSafeReturn(const DynamicZoneLocation& location, bool update_db = false);
|
||||
void SetZoneInLocation(const DynamicZoneLocation& location, bool update_db = false);
|
||||
void SetUpdatedDuration(uint32_t seconds);
|
||||
|
||||
private:
|
||||
static std::string DynamicZoneSelectQuery();
|
||||
void LoadDatabaseResult(MySQLRequestRow& row);
|
||||
void SaveCompassToDatabase();
|
||||
void SaveSafeReturnToDatabase();
|
||||
void SaveZoneInLocationToDatabase();
|
||||
uint32_t SaveToDatabase();
|
||||
|
||||
uint32_t m_id = 0;
|
||||
uint32_t m_zone_id = 0;
|
||||
uint32_t m_instance_id = 0;
|
||||
uint32_t m_version = 0;
|
||||
bool m_never_expires = false;
|
||||
bool m_has_zonein = false;
|
||||
DynamicZoneType m_type = DynamicZoneType::None;
|
||||
DynamicZoneLocation m_compass;
|
||||
DynamicZoneLocation m_safereturn;
|
||||
DynamicZoneLocation m_zonein;
|
||||
std::chrono::seconds m_duration;
|
||||
std::chrono::time_point<std::chrono::system_clock> m_start_time;
|
||||
std::chrono::time_point<std::chrono::system_clock> m_expire_time;
|
||||
};
|
||||
|
||||
struct DynamicZoneInfo
|
||||
{
|
||||
std::string description; // from owning system
|
||||
std::string leader_name;
|
||||
DynamicZone dynamic_zone;
|
||||
|
||||
DynamicZoneInfo() = default;
|
||||
DynamicZoneInfo(std::string desc, std::string leader, const DynamicZone& dz)
|
||||
: description(std::move(desc)), leader_name(std::move(leader)), dynamic_zone(dz) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -678,6 +678,17 @@ void Client::ResetDisciplineTimer(uint32 timer_id) {
|
||||
SendDisciplineTimer(timer_id, 0);
|
||||
}
|
||||
|
||||
bool Client::HasDisciplineLearned(uint16 spell_id) {
|
||||
bool has_learned = false;
|
||||
for (auto index = 0; index < MAX_PP_DISCIPLINES; ++index) {
|
||||
if (GetPP().disciplines.values[index] == spell_id) {
|
||||
has_learned = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return has_learned;
|
||||
}
|
||||
|
||||
void Client::SendDisciplineTimer(uint32 timer_id, uint32 duration)
|
||||
{
|
||||
if (timer_id < MAX_DISCIPLINE_TIMERS)
|
||||
|
||||
@ -971,6 +971,9 @@ void PerlembParser::MapFunctions()
|
||||
"package Doors;"
|
||||
"&boot_Doors;" // load quest Doors XS
|
||||
|
||||
"package Expedition;"
|
||||
"&boot_Expedition;"
|
||||
|
||||
#endif
|
||||
"package main;"
|
||||
"}"
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
#include "embparser.h"
|
||||
#include "embxs.h"
|
||||
#include "entity.h"
|
||||
#include "expedition.h"
|
||||
#include "queryserv.h"
|
||||
#include "questmgr.h"
|
||||
#include "zone.h"
|
||||
@ -2792,6 +2793,29 @@ XS(XS__we) {
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__message);
|
||||
XS(XS__message) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: quest::message(int color, string message)");
|
||||
|
||||
int color = (int) SvIV(ST(0));
|
||||
char *message = (char *) SvPV_nolen(ST(1));
|
||||
quest_manager.message(color, message);
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__whisper);
|
||||
XS(XS__whisper) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: quest::whisper(string message)");
|
||||
|
||||
char *message = (char *) SvPV_nolen(ST(0));
|
||||
quest_manager.whisper(message);
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__getlevel);
|
||||
XS(XS__getlevel) {
|
||||
dXSARGS;
|
||||
@ -2926,6 +2950,22 @@ XS(XS__countitem) {
|
||||
XSRETURN_IV(quantity);
|
||||
}
|
||||
|
||||
XS(XS__removeitem);
|
||||
XS(XS__removeitem) {
|
||||
dXSARGS;
|
||||
if (items < 1 || items > 2)
|
||||
Perl_croak(aTHX_ "Usage: quest::removeitem(int item_id, [int quantity = 1])");
|
||||
|
||||
uint32 item_id = (int) SvIV(ST(0));
|
||||
uint32 quantity = 1;
|
||||
if (items > 1)
|
||||
quantity = (int) SvIV(ST(1));
|
||||
|
||||
quest_manager.removeitem(item_id, quantity);
|
||||
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__getitemname);
|
||||
XS(XS__getitemname) {
|
||||
dXSARGS;
|
||||
@ -3733,10 +3773,11 @@ XS(XS__GetZoneLongName) {
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: quest::GetZoneLongName(string zone)");
|
||||
dXSTARG;
|
||||
char *zone = (char *) SvPV_nolen(ST(0));
|
||||
Const_char *RETVAL = quest_manager.GetZoneLongName(zone);
|
||||
|
||||
sv_setpv(TARG, RETVAL);
|
||||
std::string zone = (std::string) SvPV_nolen(ST(0));
|
||||
std::string RETVAL = quest_manager.GetZoneLongName(zone);
|
||||
|
||||
sv_setpv(TARG, RETVAL.c_str());
|
||||
XSprePUSH;
|
||||
PUSHTARG;
|
||||
XSRETURN(1);
|
||||
@ -3767,7 +3808,7 @@ XS(XS__crosszoneassigntaskbycharid) {
|
||||
|
||||
if (items == 3) {
|
||||
enforce_level_requirement = (bool) SvTRUE(ST(2));
|
||||
}
|
||||
}
|
||||
quest_manager.CrossZoneAssignTaskByCharID(character_id, task_id, enforce_level_requirement);
|
||||
}
|
||||
|
||||
@ -3801,13 +3842,13 @@ XS(XS__crosszoneassigntaskbyraidid) {
|
||||
int raid_id = (int) SvIV(ST(0));
|
||||
uint32 task_id = (uint32) SvIV(ST(1));
|
||||
bool enforce_level_requirement = false;
|
||||
|
||||
|
||||
if (items == 3) {
|
||||
enforce_level_requirement = (bool) SvTRUE(ST(2));
|
||||
}
|
||||
quest_manager.CrossZoneAssignTaskByRaidID(raid_id, task_id, enforce_level_requirement);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszoneassigntaskbyguildid);
|
||||
@ -3825,7 +3866,7 @@ XS(XS__crosszoneassigntaskbyguildid) {
|
||||
}
|
||||
quest_manager.CrossZoneAssignTaskByGuildID(guild_id, task_id, enforce_level_requirement);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszonecastspellbycharid);
|
||||
@ -3838,7 +3879,7 @@ XS(XS__crosszonecastspellbycharid) {
|
||||
uint32 spell_id = (uint32) SvIV(ST(1));
|
||||
quest_manager.CrossZoneCastSpellByCharID(character_id, spell_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszonecastspellbygroupid);
|
||||
@ -3851,7 +3892,7 @@ XS(XS__crosszonecastspellbygroupid) {
|
||||
uint32 spell_id = (uint32) SvIV(ST(1));
|
||||
quest_manager.CrossZoneCastSpellByGroupID(group_id, spell_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszonecastspellbyraidid);
|
||||
@ -3864,7 +3905,7 @@ XS(XS__crosszonecastspellbyraidid) {
|
||||
uint32 spell_id = (uint32) SvIV(ST(1));
|
||||
quest_manager.CrossZoneCastSpellByRaidID(raid_id, spell_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszonecastspellbyguildid);
|
||||
@ -3877,7 +3918,7 @@ XS(XS__crosszonecastspellbyguildid) {
|
||||
uint32 spell_id = (uint32) SvUV(ST(1));
|
||||
quest_manager.CrossZoneCastSpellByGuildID(guild_id, spell_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszonedisabletaskbycharid);
|
||||
@ -3890,7 +3931,7 @@ XS(XS__crosszonedisabletaskbycharid) {
|
||||
uint32 task_id = (uint32) SvUV(ST(1));
|
||||
quest_manager.CrossZoneDisableTaskByCharID(char_id, task_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszonedisabletaskbygroupid);
|
||||
@ -3903,7 +3944,7 @@ XS(XS__crosszonedisabletaskbygroupid) {
|
||||
uint32 task_id = (uint32) SvUV(ST(1));
|
||||
quest_manager.CrossZoneDisableTaskByGroupID(group_id, task_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszonedisabletaskbyraidid);
|
||||
@ -3916,7 +3957,7 @@ XS(XS__crosszonedisabletaskbyraidid) {
|
||||
uint32 task_id = (uint32) SvUV(ST(1));
|
||||
quest_manager.CrossZoneDisableTaskByRaidID(raid_id, task_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszonedisabletaskbyguildid);
|
||||
@ -3929,7 +3970,7 @@ XS(XS__crosszonedisabletaskbyguildid) {
|
||||
uint32 task_id = (uint32) SvUV(ST(1));
|
||||
quest_manager.CrossZoneDisableTaskByGuildID(guild_id, task_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszoneenabletaskbycharid);
|
||||
@ -3942,7 +3983,7 @@ XS(XS__crosszoneenabletaskbycharid) {
|
||||
uint32 task_id = (uint32) SvUV(ST(1));
|
||||
quest_manager.CrossZoneEnableTaskByCharID(char_id, task_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszoneenabletaskbygroupid);
|
||||
@ -3955,7 +3996,7 @@ XS(XS__crosszoneenabletaskbygroupid) {
|
||||
uint32 task_id = (uint32) SvUV(ST(1));
|
||||
quest_manager.CrossZoneEnableTaskByGroupID(group_id, task_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszoneenabletaskbyraidid);
|
||||
@ -3968,7 +4009,7 @@ XS(XS__crosszoneenabletaskbyraidid) {
|
||||
uint32 task_id = (uint32) SvUV(ST(1));
|
||||
quest_manager.CrossZoneEnableTaskByRaidID(raid_id, task_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszoneenabletaskbyguildid);
|
||||
@ -3981,7 +4022,7 @@ XS(XS__crosszoneenabletaskbyguildid) {
|
||||
uint32 task_id = (uint32) SvUV(ST(1));
|
||||
quest_manager.CrossZoneEnableTaskByGuildID(guild_id, task_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszonefailtaskbycharid);
|
||||
@ -3994,7 +4035,7 @@ XS(XS__crosszonefailtaskbycharid) {
|
||||
uint32 task_id = (uint32) SvUV(ST(1));
|
||||
quest_manager.CrossZoneFailTaskByCharID(char_id, task_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszonefailtaskbygroupid);
|
||||
@ -4007,7 +4048,7 @@ XS(XS__crosszonefailtaskbygroupid) {
|
||||
uint32 task_id = (uint32) SvUV(ST(1));
|
||||
quest_manager.CrossZoneFailTaskByGroupID(group_id, task_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszonefailtaskbyraidid);
|
||||
@ -4020,7 +4061,7 @@ XS(XS__crosszonefailtaskbyraidid) {
|
||||
uint32 task_id = (uint32) SvUV(ST(1));
|
||||
quest_manager.CrossZoneFailTaskByRaidID(raid_id, task_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszonefailtaskbyguildid);
|
||||
@ -4033,7 +4074,7 @@ XS(XS__crosszonefailtaskbyguildid) {
|
||||
uint32 task_id = (uint32) SvUV(ST(1));
|
||||
quest_manager.CrossZoneFailTaskByGuildID(guild_id, task_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszonemarqueebycharid);
|
||||
@ -4390,7 +4431,7 @@ XS(XS__crosszoneremovetaskbycharid) {
|
||||
uint32 task_id = (uint32) SvUV(ST(1));
|
||||
quest_manager.CrossZoneRemoveTaskByCharID(char_id, task_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszoneremovetaskbygroupid);
|
||||
@ -4403,7 +4444,7 @@ XS(XS__crosszoneremovetaskbygroupid) {
|
||||
uint32 task_id = (uint32) SvUV(ST(1));
|
||||
quest_manager.CrossZoneRemoveTaskByGroupID(group_id, task_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszoneremovetaskbyraidid);
|
||||
@ -4416,7 +4457,7 @@ XS(XS__crosszoneremovetaskbyraidid) {
|
||||
uint32 task_id = (uint32) SvUV(ST(1));
|
||||
quest_manager.CrossZoneRemoveTaskByRaidID(raid_id, task_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszoneremovetaskbyguildid);
|
||||
@ -4429,7 +4470,7 @@ XS(XS__crosszoneremovetaskbyguildid) {
|
||||
uint32 task_id = (uint32) SvUV(ST(1));
|
||||
quest_manager.CrossZoneRemoveTaskByGuildID(guild_id, task_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszoneresetactivitybycharid);
|
||||
@ -4443,7 +4484,7 @@ XS(XS__crosszoneresetactivitybycharid) {
|
||||
int activity_id = (int) SvIV(ST(2));
|
||||
quest_manager.CrossZoneResetActivityByCharID(char_id, task_id, activity_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszoneresetactivitybygroupid);
|
||||
@ -4457,7 +4498,7 @@ XS(XS__crosszoneresetactivitybygroupid) {
|
||||
int activity_id = (int) SvIV(ST(2));
|
||||
quest_manager.CrossZoneResetActivityByGroupID(group_id, task_id, activity_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszoneresetactivitybyraidid);
|
||||
@ -4471,7 +4512,7 @@ XS(XS__crosszoneresetactivitybyraidid) {
|
||||
int activity_id = (int) SvIV(ST(2));
|
||||
quest_manager.CrossZoneResetActivityByRaidID(raid_id, task_id, activity_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszoneresetactivitybyguildid);
|
||||
@ -4485,7 +4526,7 @@ XS(XS__crosszoneresetactivitybyguildid) {
|
||||
int activity_id = (int) SvIV(ST(2));
|
||||
quest_manager.CrossZoneResetActivityByGuildID(guild_id, task_id, activity_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszonesetentityvariablebynpctypeid);
|
||||
@ -4684,7 +4725,7 @@ XS(XS__crosszoneupdateactivitybycharid) {
|
||||
}
|
||||
quest_manager.CrossZoneUpdateActivityByCharID(char_id, task_id, activity_id, activity_count);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszoneupdateactivitybygroupid);
|
||||
@ -4702,7 +4743,7 @@ XS(XS__crosszoneupdateactivitybygroupid) {
|
||||
}
|
||||
quest_manager.CrossZoneUpdateActivityByGroupID(group_id, task_id, activity_id, activity_count);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszoneupdateactivitybyraidid);
|
||||
@ -4720,7 +4761,7 @@ XS(XS__crosszoneupdateactivitybyraidid) {
|
||||
}
|
||||
quest_manager.CrossZoneUpdateActivityByRaidID(raid_id, task_id, activity_id, activity_count);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszoneupdateactivitybyguildid);
|
||||
@ -4738,7 +4779,7 @@ XS(XS__crosszoneupdateactivitybyguildid) {
|
||||
}
|
||||
quest_manager.CrossZoneUpdateActivityByGuildID(guild_id, task_id, activity_id, activity_count);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__worldwideassigntask);
|
||||
@ -4753,7 +4794,7 @@ XS(XS__worldwideassigntask) {
|
||||
if (items == 2) {
|
||||
min_status = (uint8) SvUV(ST(1));
|
||||
}
|
||||
|
||||
|
||||
if (items == 3) {
|
||||
max_status = (uint8) SvUV(ST(2));
|
||||
}
|
||||
@ -4775,7 +4816,7 @@ XS(XS__worldwidecastspell) {
|
||||
if (items == 2) {
|
||||
min_status = (uint8) SvUV(ST(1));
|
||||
}
|
||||
|
||||
|
||||
if (items == 3) {
|
||||
max_status = (uint8) SvUV(ST(2));
|
||||
}
|
||||
@ -4797,7 +4838,7 @@ XS(XS__worldwidedisabletask) {
|
||||
if (items == 2) {
|
||||
min_status = (uint8) SvUV(ST(1));
|
||||
}
|
||||
|
||||
|
||||
if (items == 3) {
|
||||
max_status = (uint8) SvUV(ST(2));
|
||||
}
|
||||
@ -4819,7 +4860,7 @@ XS(XS__worldwideenabletask) {
|
||||
if (items == 2) {
|
||||
min_status = (uint8) SvUV(ST(1));
|
||||
}
|
||||
|
||||
|
||||
if (items == 3) {
|
||||
max_status = (uint8) SvUV(ST(2));
|
||||
}
|
||||
@ -4841,7 +4882,7 @@ XS(XS__worldwidefailtask) {
|
||||
if (items == 2) {
|
||||
min_status = (uint8) SvUV(ST(1));
|
||||
}
|
||||
|
||||
|
||||
if (items == 3) {
|
||||
max_status = (uint8) SvUV(ST(2));
|
||||
}
|
||||
@ -4868,7 +4909,7 @@ XS(XS__worldwidemarquee) {
|
||||
if (items == 7) {
|
||||
min_status = (uint8) SvUV(ST(6));
|
||||
}
|
||||
|
||||
|
||||
if (items == 8) {
|
||||
max_status = (uint8) SvUV(ST(7));
|
||||
}
|
||||
@ -4891,7 +4932,7 @@ XS(XS__worldwidemessage) {
|
||||
if (items == 3) {
|
||||
min_status = (uint8) SvUV(ST(2));
|
||||
}
|
||||
|
||||
|
||||
if (items == 4) {
|
||||
max_status = (uint8) SvUV(ST(3));
|
||||
}
|
||||
@ -4914,7 +4955,7 @@ XS(XS__worldwidemove) {
|
||||
if (items == 2) {
|
||||
min_status = (uint8) SvUV(ST(1));
|
||||
}
|
||||
|
||||
|
||||
if (items == 3) {
|
||||
max_status = (uint8) SvUV(ST(2));
|
||||
}
|
||||
@ -4936,7 +4977,7 @@ XS(XS__worldwidemoveinstance) {
|
||||
if (items == 2) {
|
||||
min_status = (uint8) SvUV(ST(1));
|
||||
}
|
||||
|
||||
|
||||
if (items == 3) {
|
||||
max_status = (uint8) SvUV(ST(2));
|
||||
}
|
||||
@ -4958,7 +4999,7 @@ XS(XS__worldwideremovespell) {
|
||||
if (items == 2) {
|
||||
min_status = (uint8) SvUV(ST(1));
|
||||
}
|
||||
|
||||
|
||||
if (items == 3) {
|
||||
max_status = (uint8) SvUV(ST(2));
|
||||
}
|
||||
@ -4980,7 +5021,7 @@ XS(XS__worldwideremovetask) {
|
||||
if (items == 2) {
|
||||
min_status = (uint8) SvUV(ST(1));
|
||||
}
|
||||
|
||||
|
||||
if (items == 3) {
|
||||
max_status = (uint8) SvUV(ST(2));
|
||||
}
|
||||
@ -5003,7 +5044,7 @@ XS(XS__worldwideresetactivity) {
|
||||
if (items == 3) {
|
||||
min_status = (uint8) SvUV(ST(2));
|
||||
}
|
||||
|
||||
|
||||
if (items == 4) {
|
||||
max_status = (uint8) SvUV(ST(3));
|
||||
}
|
||||
@ -5026,7 +5067,7 @@ XS(XS__worldwidesetentityvariableclient) {
|
||||
if (items == 3) {
|
||||
min_status = (uint8) SvUV(ST(2));
|
||||
}
|
||||
|
||||
|
||||
if (items == 4) {
|
||||
max_status = (uint8) SvUV(ST(3));
|
||||
}
|
||||
@ -5075,7 +5116,7 @@ XS(XS__worldwidesignalclient) {
|
||||
if (items == 2) {
|
||||
min_status = (uint8) SvUV(ST(1));
|
||||
}
|
||||
|
||||
|
||||
if (items == 3) {
|
||||
max_status = (uint8) SvUV(ST(1));
|
||||
}
|
||||
@ -5102,7 +5143,7 @@ XS(XS__worldwideupdateactivity) {
|
||||
if (items == 4) {
|
||||
min_status = (uint8) SvUV(ST(3));
|
||||
}
|
||||
|
||||
|
||||
if (items == 5) {
|
||||
max_status = (uint8) SvUV(ST(4));
|
||||
}
|
||||
@ -6042,6 +6083,265 @@ XS(XS__SetContentFlag)
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__get_expedition);
|
||||
XS(XS__get_expedition) {
|
||||
dXSARGS;
|
||||
if (items != 0) {
|
||||
Perl_croak(aTHX_ "Usage: quest::get_expedition()");
|
||||
}
|
||||
|
||||
Expedition* RETVAL = nullptr;
|
||||
if (zone && zone->GetInstanceID() != 0)
|
||||
{
|
||||
RETVAL = Expedition::FindCachedExpeditionByZoneInstance(zone->GetZoneID(), zone->GetInstanceID());
|
||||
}
|
||||
|
||||
EXTEND(sp, 1); // grow stack, function had 0 arguments
|
||||
ST(0) = sv_newmortal(); // PUSHs(sv_newmortal());
|
||||
if (RETVAL) {
|
||||
sv_setref_pv(ST(0), "Expedition", (void*)RETVAL);
|
||||
}
|
||||
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS__get_expedition_by_char_id);
|
||||
XS(XS__get_expedition_by_char_id) {
|
||||
dXSARGS;
|
||||
if (items != 1) {
|
||||
Perl_croak(aTHX_ "Usage: quest::get_expedition_by_char_id(uint32 character_id)");
|
||||
}
|
||||
|
||||
uint32 character_id = (int)SvUV(ST(0));
|
||||
|
||||
Expedition* RETVAL = Expedition::FindCachedExpeditionByCharacterID(character_id);
|
||||
|
||||
ST(0) = sv_newmortal();
|
||||
if (RETVAL) {
|
||||
sv_setref_pv(ST(0), "Expedition", (void*)RETVAL);
|
||||
}
|
||||
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS__get_expedition_by_dz_id);
|
||||
XS(XS__get_expedition_by_dz_id) {
|
||||
dXSARGS;
|
||||
if (items != 1) {
|
||||
Perl_croak(aTHX_ "Usage: quest::get_expedition_by_dz_id(uint32 dynamic_zone_id)");
|
||||
}
|
||||
|
||||
uint32 dz_id = (int)SvUV(ST(0));
|
||||
|
||||
Expedition* RETVAL = Expedition::FindCachedExpeditionByDynamicZoneID(dz_id);
|
||||
|
||||
ST(0) = sv_newmortal();
|
||||
if (RETVAL) {
|
||||
sv_setref_pv(ST(0), "Expedition", (void*)RETVAL);
|
||||
}
|
||||
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS__get_expedition_by_zone_instance);
|
||||
XS(XS__get_expedition_by_zone_instance) {
|
||||
dXSARGS;
|
||||
if (items != 2) {
|
||||
Perl_croak(aTHX_ "Usage: quest::GetExpeditionByZoneInstance(uint16 zone_id, uint16 instance_id)");
|
||||
}
|
||||
|
||||
uint16 zone_id = (uint16)SvUV(ST(0));
|
||||
uint16 instance_id = (uint16)SvUV(ST(1));
|
||||
|
||||
Expedition* RETVAL = Expedition::FindCachedExpeditionByZoneInstance(zone_id, instance_id);
|
||||
|
||||
ST(0) = sv_newmortal();
|
||||
if (RETVAL) {
|
||||
sv_setref_pv(ST(0), "Expedition", (void*)RETVAL);
|
||||
}
|
||||
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS__get_expedition_lockout_by_char_id);
|
||||
XS(XS__get_expedition_lockout_by_char_id) {
|
||||
dXSARGS;
|
||||
if (items != 3) {
|
||||
Perl_croak(aTHX_ "Usage: quest::get_expedition_lockout_by_char_id(uint32 character_id, string expedition_name, string event_name)");
|
||||
}
|
||||
|
||||
uint32_t character_id = static_cast<uint32_t>(SvUV(ST(0)));
|
||||
std::string expedition_name = SvPV_nolen(ST(1));
|
||||
std::string event_name = SvPV_nolen(ST(2));
|
||||
|
||||
auto lockouts = Expedition::GetExpeditionLockoutsByCharacterID(character_id);
|
||||
auto it = std::find_if(lockouts.begin(), lockouts.end(), [&](const ExpeditionLockoutTimer& lockout) {
|
||||
return lockout.IsSameLockout(expedition_name, event_name);
|
||||
});
|
||||
|
||||
// mortalize so its refcnt is auto decremented on function exit to avoid leak
|
||||
HV* hash = (HV*)sv_2mortal((SV*)newHV()); // hash refcnt +1 (mortal -1)
|
||||
|
||||
if (it != lockouts.end())
|
||||
{
|
||||
hv_store(hash, "remaining", strlen("remaining"), newSVuv(it->GetSecondsRemaining()), 0);
|
||||
hv_store(hash, "uuid", strlen("uuid"), newSVpv(it->GetExpeditionUUID().c_str(), 0), 0);
|
||||
}
|
||||
|
||||
ST(0) = sv_2mortal(newRV((SV*)hash)); // hash refcnt: 2 (-1 mortal), reference: 1 (-1 mortal)
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS__get_expedition_lockouts_by_char_id);
|
||||
XS(XS__get_expedition_lockouts_by_char_id) {
|
||||
dXSARGS;
|
||||
if (items != 1 && items != 2) {
|
||||
Perl_croak(aTHX_ "Usage: quest::get_expedition_lockouts_by_char_id(uint32 character_id, [string expedition_name])");
|
||||
}
|
||||
|
||||
HV* hash = newHV(); // hash refcnt +1 (non-mortal, newRV_noinc to not inc)
|
||||
SV* hash_ref = nullptr; // for expedition event hash if filtering on expedition
|
||||
|
||||
uint32_t character_id = static_cast<uint32_t>(SvUV(ST(0)));
|
||||
std::string expedition_name;
|
||||
if (items == 2)
|
||||
{
|
||||
expedition_name = SvPV_nolen(ST(1));
|
||||
}
|
||||
|
||||
auto lockouts = Expedition::GetExpeditionLockoutsByCharacterID(character_id);
|
||||
|
||||
for (const auto& lockout : lockouts)
|
||||
{
|
||||
uint32_t name_len = static_cast<uint32_t>(lockout.GetExpeditionName().size());
|
||||
uint32_t event_len = static_cast<uint32_t>(lockout.GetEventName().size());
|
||||
|
||||
// hashes are stored through references inside other hashes/arrays. we need
|
||||
// to wrap newHV in newRV references when inserting nested hash values.
|
||||
// we use newRV_noinc to not increment the hash's ref count; rv will own it
|
||||
|
||||
SV** entry = hv_fetch(hash, lockout.GetExpeditionName().c_str(), name_len, false);
|
||||
if (!entry)
|
||||
{
|
||||
// create expedition entry in hash with its value as ref to event hash
|
||||
SV* event_hash_ref = newRV_noinc((SV*)newHV()); // ref takes ownership
|
||||
if (!expedition_name.empty() && lockout.GetExpeditionName() == expedition_name)
|
||||
{
|
||||
hash_ref = event_hash_ref; // save ref for filtered expedition return
|
||||
}
|
||||
entry = hv_store(hash, lockout.GetExpeditionName().c_str(), name_len, event_hash_ref, 0);
|
||||
}
|
||||
|
||||
// *entry is a reference to expedition's event hash (which it owns). the
|
||||
// event entry in the hash will contain ref to a lockout detail hash
|
||||
if (entry && SvROK(*entry) && SvTYPE(SvRV(*entry)) == SVt_PVHV) // is ref to hash type
|
||||
{
|
||||
HV* details_hash = newHV(); // refcnt +1, reference will take ownership
|
||||
hv_store(details_hash, "remaining", strlen("remaining"), newSVuv(lockout.GetSecondsRemaining()), 0);
|
||||
hv_store(details_hash, "uuid", strlen("uuid"), newSVpv(lockout.GetExpeditionUUID().c_str(), 0), 0);
|
||||
|
||||
HV* event_hash = (HV*)SvRV(*entry);
|
||||
hv_store(event_hash, lockout.GetEventName().c_str(), event_len,
|
||||
(SV*)newRV_noinc((SV*)details_hash), 0);
|
||||
}
|
||||
}
|
||||
|
||||
SV* rv = &PL_sv_undef;
|
||||
|
||||
if (!expedition_name.empty())
|
||||
{
|
||||
rv = hash_ref ? sv_2mortal(hash_ref) : &PL_sv_undef; // ref that owns event hash for expedition
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = sv_2mortal(newRV_noinc((SV*)hash)); // takes ownership of expedition hash
|
||||
}
|
||||
|
||||
ST(0) = rv;
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS__add_expedition_lockout_all_clients);
|
||||
XS(XS__add_expedition_lockout_all_clients) {
|
||||
dXSARGS;
|
||||
if (items != 3 && items != 4) {
|
||||
Perl_croak(aTHX_ "Usage: quest::add_expedition_lockout_all_clients(string expedition_name, string event_name, uint32 seconds, [string uuid])");
|
||||
}
|
||||
|
||||
std::string expedition_name = SvPV_nolen(ST(0));
|
||||
std::string event_name = SvPV_nolen(ST(1));
|
||||
uint32_t seconds = static_cast<uint32_t>(SvUV(ST(2)));
|
||||
std::string uuid;
|
||||
|
||||
if (items == 4)
|
||||
{
|
||||
uuid = SvPV_nolen(ST(3));
|
||||
}
|
||||
|
||||
auto lockout = ExpeditionLockoutTimer::CreateLockout(expedition_name, event_name, seconds, uuid);
|
||||
Expedition::AddLockoutClients(lockout);
|
||||
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__add_expedition_lockout_by_char_id);
|
||||
XS(XS__add_expedition_lockout_by_char_id) {
|
||||
dXSARGS;
|
||||
if (items != 4 && items != 5) {
|
||||
Perl_croak(aTHX_ "Usage: quest::add_expedition_lockout_by_char_id(uint32 character_id, string expedition_name, string event_name, uint32 seconds, [string uuid])");
|
||||
}
|
||||
|
||||
std::string uuid;
|
||||
if (items == 5)
|
||||
{
|
||||
uuid = SvPV_nolen(ST(4));
|
||||
}
|
||||
|
||||
uint32_t character_id = static_cast<uint32_t>(SvUV(ST(0)));
|
||||
std::string expedition_name = SvPV_nolen(ST(1));
|
||||
std::string event_name = SvPV_nolen(ST(2));
|
||||
uint32_t seconds = static_cast<uint32_t>(SvUV(ST(3)));
|
||||
|
||||
Expedition::AddLockoutByCharacterID(character_id, expedition_name, event_name, seconds, uuid);
|
||||
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__remove_expedition_lockout_by_char_id);
|
||||
XS(XS__remove_expedition_lockout_by_char_id) {
|
||||
dXSARGS;
|
||||
if (items != 3) {
|
||||
Perl_croak(aTHX_ "Usage: quest::remove_expedition_lockout_by_char_id(uint32 character_id, string expedition_name, string event_name)");
|
||||
}
|
||||
|
||||
uint32_t character_id = static_cast<uint32_t>(SvUV(ST(0)));
|
||||
std::string expedition_name = SvPV_nolen(ST(1));
|
||||
std::string event_name = SvPV_nolen(ST(2));
|
||||
|
||||
Expedition::RemoveLockoutsByCharacterID(character_id, expedition_name, event_name);
|
||||
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__remove_all_expedition_lockouts_by_char_id);
|
||||
XS(XS__remove_all_expedition_lockouts_by_char_id) {
|
||||
dXSARGS;
|
||||
if (items != 1 && items != 2) {
|
||||
Perl_croak(aTHX_ "Usage: quest::remove_expedition_lockout_by_char_id(uint32 character_id, [string expedition_name])");
|
||||
}
|
||||
|
||||
std::string expedition_name;
|
||||
if (items == 2)
|
||||
{
|
||||
expedition_name = SvPV_nolen(ST(1));
|
||||
}
|
||||
|
||||
uint32_t character_id = static_cast<uint32_t>(SvUV(ST(0)));
|
||||
Expedition::RemoveLockoutsByCharacterID(character_id, expedition_name);
|
||||
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
/*
|
||||
This is the callback perl will look for to setup the
|
||||
quest package's XSUBs
|
||||
@ -6112,6 +6412,8 @@ EXTERN_C XS(boot_quest) {
|
||||
newXS(strcpy(buf, "activespeakactivity"), XS__activespeakactivity, file);
|
||||
newXS(strcpy(buf, "activespeaktask"), XS__activespeaktask, file);
|
||||
newXS(strcpy(buf, "activetasksinset"), XS__activetasksinset, file);
|
||||
newXS(strcpy(buf, "add_expedition_lockout_all_clients"), XS__add_expedition_lockout_all_clients, file);
|
||||
newXS(strcpy(buf, "add_expedition_lockout_by_char_id"), XS__add_expedition_lockout_by_char_id, file);
|
||||
newXS(strcpy(buf, "addldonloss"), XS__addldonpoints, file);
|
||||
newXS(strcpy(buf, "addldonpoints"), XS__addldonpoints, file);
|
||||
newXS(strcpy(buf, "addldonwin"), XS__addldonpoints, file);
|
||||
@ -6171,7 +6473,7 @@ EXTERN_C XS(boot_quest) {
|
||||
newXS(strcpy(buf, "crosszonemoveinstancebycharid"), XS__crosszonemoveinstancebycharid, file);
|
||||
newXS(strcpy(buf, "crosszonemoveinstancebygroupid"), XS__crosszonemoveinstancebygroupid, file);
|
||||
newXS(strcpy(buf, "crosszonemoveinstancebyraidid"), XS__crosszonemoveinstancebyraidid, file);
|
||||
newXS(strcpy(buf, "crosszonemoveinstancebyguildid"), XS__crosszonemoveinstancebyguildid, file);
|
||||
newXS(strcpy(buf, "crosszonemoveinstancebyguildid"), XS__crosszonemoveinstancebyguildid, file);
|
||||
newXS(strcpy(buf, "crosszoneremovespellbycharid"), XS__crosszoneremovespellbycharid, file);
|
||||
newXS(strcpy(buf, "crosszoneremovespellbygroupid"), XS__crosszoneremovespellbygroupid, file);
|
||||
newXS(strcpy(buf, "crosszoneremovespellbyraidid"), XS__crosszoneremovespellbyraidid, file);
|
||||
@ -6246,6 +6548,12 @@ EXTERN_C XS(boot_quest) {
|
||||
newXS(strcpy(buf, "getcharidbyname"), XS__getcharidbyname, file);
|
||||
newXS(strcpy(buf, "getclassname"), XS__getclassname, file);
|
||||
newXS(strcpy(buf, "getcurrencyid"), XS__getcurrencyid, file);
|
||||
newXS(strcpy(buf, "get_expedition"), XS__get_expedition, file);
|
||||
newXS(strcpy(buf, "get_expedition_by_char_id"), XS__get_expedition_by_char_id, file);
|
||||
newXS(strcpy(buf, "get_expedition_by_dz_id"), XS__get_expedition_by_dz_id, file);
|
||||
newXS(strcpy(buf, "get_expedition_by_zone_instance"), XS__get_expedition_by_zone_instance, file);
|
||||
newXS(strcpy(buf, "get_expedition_lockout_by_char_id"), XS__get_expedition_lockout_by_char_id, file);
|
||||
newXS(strcpy(buf, "get_expedition_lockouts_by_char_id"), XS__get_expedition_lockouts_by_char_id, file);
|
||||
newXS(strcpy(buf, "getinventoryslotid"), XS__getinventoryslotid, file);
|
||||
newXS(strcpy(buf, "getitemname"), XS__getitemname, file);
|
||||
newXS(strcpy(buf, "getItemName"), XS_qc_getItemName, file);
|
||||
@ -6284,6 +6592,7 @@ EXTERN_C XS(boot_quest) {
|
||||
newXS(strcpy(buf, "log"), XS__log, file);
|
||||
newXS(strcpy(buf, "log_combat"), XS__log_combat, file);
|
||||
newXS(strcpy(buf, "me"), XS__me, file);
|
||||
newXS(strcpy(buf, "message"), XS__message, file);
|
||||
newXS(strcpy(buf, "modifynpcstat"), XS__ModifyNPCStat, file);
|
||||
newXS(strcpy(buf, "movegrp"), XS__movegrp, file);
|
||||
newXS(strcpy(buf, "movepc"), XS__movepc, file);
|
||||
@ -6311,6 +6620,9 @@ EXTERN_C XS(boot_quest) {
|
||||
newXS(strcpy(buf, "rain"), XS__rain, file);
|
||||
newXS(strcpy(buf, "rebind"), XS__rebind, file);
|
||||
newXS(strcpy(buf, "reloadzonestaticdata"), XS__reloadzonestaticdata, file);
|
||||
newXS(strcpy(buf, "remove_all_expedition_lockouts_by_char_id"), XS__remove_all_expedition_lockouts_by_char_id, file);
|
||||
newXS(strcpy(buf, "remove_expedition_lockout_by_char_id"), XS__remove_expedition_lockout_by_char_id, file);
|
||||
newXS(strcpy(buf, "removeitem"), XS__removeitem, file);
|
||||
newXS(strcpy(buf, "removetitle"), XS__removetitle, file);
|
||||
newXS(strcpy(buf, "repopzone"), XS__repopzone, file);
|
||||
newXS(strcpy(buf, "resettaskactivity"), XS__resettaskactivity, file);
|
||||
@ -6377,6 +6689,7 @@ EXTERN_C XS(boot_quest) {
|
||||
newXS(strcpy(buf, "voicetell"), XS__voicetell, file);
|
||||
newXS(strcpy(buf, "we"), XS__we, file);
|
||||
newXS(strcpy(buf, "wearchange"), XS__wearchange, file);
|
||||
newXS(strcpy(buf, "whisper"), XS__whisper, file);
|
||||
newXS(strcpy(buf, "write"), XS__write, file);
|
||||
newXS(strcpy(buf, "ze"), XS__ze, file);
|
||||
newXS(strcpy(buf, "zone"), XS__zone, file);
|
||||
|
||||
@ -37,6 +37,7 @@ EXTERN_C XS(boot_HateEntry);
|
||||
EXTERN_C XS(boot_Object);
|
||||
EXTERN_C XS(boot_Doors);
|
||||
EXTERN_C XS(boot_PerlPacket);
|
||||
EXTERN_C XS(boot_Expedition);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -87,6 +88,7 @@ EXTERN_C void xs_init(pTHX)
|
||||
newXS(strcpy(buf, "HateEntry::boot_HateEntry"), boot_HateEntry, file);
|
||||
newXS(strcpy(buf, "Object::boot_Object"), boot_Object, file);
|
||||
newXS(strcpy(buf, "Doors::boot_Doors"), boot_Doors, file);
|
||||
newXS(strcpy(buf, "Expedition::boot_Expedition"), boot_Expedition, file);
|
||||
;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
150
zone/entity.cpp
150
zone/entity.cpp
@ -32,6 +32,7 @@
|
||||
#include "../common/features.h"
|
||||
#include "../common/guilds.h"
|
||||
|
||||
#include "dynamiczone.h"
|
||||
#include "guild_mgr.h"
|
||||
#include "petitions.h"
|
||||
#include "quest_parser_collection.h"
|
||||
@ -712,6 +713,8 @@ void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue)
|
||||
npc_list.insert(std::pair<uint16, NPC *>(npc->GetID(), npc));
|
||||
mob_list.insert(std::pair<uint16, Mob *>(npc->GetID(), npc));
|
||||
|
||||
entity_list.ScanCloseMobs(npc->close_mobs, npc, true);
|
||||
|
||||
/* Zone controller process EVENT_SPAWN_ZONE */
|
||||
if (RuleB(Zone, UseZoneController)) {
|
||||
if (entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID) && npc->GetNPCTypeID() != ZONE_CONTROLLER_NPC_ID){
|
||||
@ -1322,8 +1325,8 @@ void EntityList::SendZoneSpawnsBulk(Client *client)
|
||||
const glm::vec4 &client_position = client->GetPosition();
|
||||
const float distance_max = (600.0 * 600.0);
|
||||
|
||||
for (auto it = mob_list.begin(); it != mob_list.end(); ++it) {
|
||||
spawn = it->second;
|
||||
for (auto & it : mob_list) {
|
||||
spawn = it.second;
|
||||
if (spawn && spawn->GetID() > 0 && spawn->Spawned()) {
|
||||
if (!spawn->ShouldISpawnFor(client)) {
|
||||
continue;
|
||||
@ -2508,7 +2511,7 @@ void EntityList::DespawnAllDoors()
|
||||
auto outapp = new EQApplicationPacket(OP_RemoveAllDoors, 0);
|
||||
for (auto it = client_list.begin(); it != client_list.end(); ++it) {
|
||||
if (it->second) {
|
||||
it->second->QueuePacket(outapp);
|
||||
it->second->QueuePacket(outapp, true, Client::CLIENT_CONNECTED);
|
||||
}
|
||||
}
|
||||
safe_delete(outapp);
|
||||
@ -2521,7 +2524,7 @@ void EntityList::RespawnAllDoors()
|
||||
if (it->second) {
|
||||
auto outapp = new EQApplicationPacket();
|
||||
MakeDoorSpawnPacket(outapp, it->second);
|
||||
it->second->FastQueuePacket(&outapp);
|
||||
it->second->FastQueuePacket(&outapp, true, Client::CLIENT_CONNECTED);
|
||||
}
|
||||
++it;
|
||||
}
|
||||
@ -2690,6 +2693,36 @@ void EntityList::RemoveAuraFromMobs(Mob *aura)
|
||||
}
|
||||
|
||||
/**
|
||||
* The purpose of this system is so that we cache relevant entities that are "close"
|
||||
*
|
||||
* In general; it becomes incredibly expensive to run zone-wide checks against every single mob in the zone when in reality
|
||||
* we only care about entities closest to us
|
||||
*
|
||||
* A very simple example of where this is relevant is Aggro, the below example is skewed because the overall implementation
|
||||
* of Aggro was also tweaked in conjunction with close lists. We also scan more aggressively when entities are moving (1-6 seconds)
|
||||
* versus 60 seconds when idle. We also have entities that are moving add themselves to those closest to them so that their close
|
||||
* lists remain always up to date
|
||||
*
|
||||
* Before: Aggro checks for NPC to Client aggro | (40 clients in zone) x (525 npcs) x 2 (times a second) = 2,520,000 checks a minute
|
||||
* After: Aggro checks for NPC to Client aggro | (40 clients in zone) x (20-30 npcs) x 2 (times a second) = 144,000 checks a minute (This is actually far less today)
|
||||
*
|
||||
* Places in the code where this logic makes a huge impact
|
||||
*
|
||||
* Aggro checks (zone wide -> close)
|
||||
* Aura processing (zone wide -> close)
|
||||
* AE Taunt (zone wide -> close)
|
||||
* AOE Spells (zone wide -> close)
|
||||
* Bard Pulse AOE (zone wide -> close)
|
||||
* Mass Group Buff (zone wide -> close)
|
||||
* AE Attack (zone wide -> close)
|
||||
* Packet QueueCloseClients (zone wide -> close)
|
||||
* Check Close Beneficial Spells (Buffs; should I heal other npcs) (zone wide -> close)
|
||||
* AI Yell for Help (NPC Assist other NPCs) (zone wide -> close)
|
||||
*
|
||||
* All of the above makes a tremendous impact on the bottom line of cpu cycle performance because we run an order of magnitude
|
||||
* less checks by focusing our hot path logic down to a very small subset of relevant entities instead of looping an entire
|
||||
* entity list (zone wide)
|
||||
*
|
||||
* @param close_mobs
|
||||
* @param scanning_mob
|
||||
*/
|
||||
@ -4102,8 +4135,13 @@ void EntityList::AddTempPetsToHateList(Mob *owner, Mob* other, bool bFrenzy)
|
||||
NPC* n = it->second;
|
||||
if (n->GetSwarmInfo()) {
|
||||
if (n->GetSwarmInfo()->owner_id == owner->GetID()) {
|
||||
if (!n->GetSpecialAbility(IMMUNE_AGGRO))
|
||||
if (
|
||||
!n->GetSpecialAbility(IMMUNE_AGGRO) &&
|
||||
!(n->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && other->IsClient()) &&
|
||||
!(n->GetSpecialAbility(IMMUNE_AGGRO_NPC) && other->IsNPC())
|
||||
) {
|
||||
n->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
|
||||
}
|
||||
}
|
||||
}
|
||||
++it;
|
||||
@ -4206,7 +4244,7 @@ void EntityList::ForceGroupUpdate(uint32 gid)
|
||||
}
|
||||
}
|
||||
|
||||
void EntityList::SendGroupLeave(uint32 gid, const char *name)
|
||||
void EntityList::SendGroupLeave(uint32 gid, const char *name, bool checkleader)
|
||||
{
|
||||
auto it = client_list.begin();
|
||||
while (it != client_list.end()) {
|
||||
@ -4222,13 +4260,39 @@ void EntityList::SendGroupLeave(uint32 gid, const char *name)
|
||||
gj->action = groupActLeave;
|
||||
strcpy(gj->yourname, c->GetName());
|
||||
Mob *Leader = g->GetLeader();
|
||||
if (Leader)
|
||||
if (Leader) {
|
||||
Leader->CastToClient()->GetGroupAAs(&gj->leader_aas);
|
||||
}
|
||||
c->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
g->DelMemberOOZ(name);
|
||||
if (g->IsLeader(c) && c->IsLFP())
|
||||
g->DelMemberOOZ(name, checkleader);
|
||||
if (g->IsLeader(c) && c->IsLFP()) {
|
||||
c->UpdateLFP();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void EntityList::SendGroupLeader(uint32 gid, const char *lname, const char *oldlname)
|
||||
{
|
||||
auto it = client_list.begin();
|
||||
while (it != client_list.end()) {
|
||||
if (it->second){
|
||||
Group *g = nullptr;
|
||||
g = it->second->GetGroup();
|
||||
if (g) {
|
||||
if (g->GetID() == gid) {
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupUpdate,sizeof(GroupJoin_Struct));
|
||||
GroupJoin_Struct* gj = (GroupJoin_Struct*) outapp->pBuffer;
|
||||
gj->action = groupActMakeLeader;
|
||||
strcpy(gj->membername, lname);
|
||||
strcpy(gj->yourname, oldlname);
|
||||
it->second->QueuePacket(outapp);
|
||||
Log(Logs::Detail, Logs::Group, "SendGroupLeader(): Entity loop leader update packet sent to: %s .", it->second->GetName());
|
||||
safe_delete(outapp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4251,9 +4315,9 @@ void EntityList::SendGroupJoin(uint32 gid, const char *name)
|
||||
gj->action = groupActJoin;
|
||||
strcpy(gj->yourname, it->second->GetName());
|
||||
Mob *Leader = g->GetLeader();
|
||||
if (Leader)
|
||||
if (Leader) {
|
||||
Leader->CastToClient()->GetGroupAAs(&gj->leader_aas);
|
||||
|
||||
}
|
||||
it->second->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
@ -5187,6 +5251,8 @@ void EntityList::ReloadMerchants() {
|
||||
* If we have a distance requested that is greater than our scanning distance
|
||||
* then we return the full list
|
||||
*
|
||||
* See comments @EntityList::ScanCloseMobs for system explanation
|
||||
*
|
||||
* @param mob
|
||||
* @param distance
|
||||
* @return
|
||||
@ -5200,3 +5266,65 @@ std::unordered_map<uint16, Mob *> &EntityList::GetCloseMobList(Mob *mob, float d
|
||||
return mob_list;
|
||||
}
|
||||
|
||||
void EntityList::GateAllClientsToSafeReturn()
|
||||
{
|
||||
DynamicZone dz;
|
||||
if (zone)
|
||||
{
|
||||
dz = zone->GetDynamicZone();
|
||||
|
||||
LogDynamicZones(
|
||||
"Sending all clients in zone: [{}] instance: [{}] to dz safereturn or bind",
|
||||
zone->GetZoneID(), zone->GetInstanceID()
|
||||
);
|
||||
}
|
||||
|
||||
for (const auto& client_list_iter : client_list)
|
||||
{
|
||||
if (client_list_iter.second)
|
||||
{
|
||||
// falls back to gating clients to bind if dz invalid
|
||||
client_list_iter.second->GoToDzSafeReturnOrBind(dz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int EntityList::MovePlayerCorpsesToGraveyard(bool force_move_from_instance)
|
||||
{
|
||||
if (!zone)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int moved_count = 0;
|
||||
|
||||
for (auto it = corpse_list.begin(); it != corpse_list.end();)
|
||||
{
|
||||
bool moved = false;
|
||||
if (it->second && it->second->IsPlayerCorpse())
|
||||
{
|
||||
if (zone->HasGraveyard())
|
||||
{
|
||||
moved = it->second->MovePlayerCorpseToGraveyard();
|
||||
}
|
||||
else if (force_move_from_instance && zone->GetInstanceID() != 0)
|
||||
{
|
||||
moved = it->second->MovePlayerCorpseToNonInstance();
|
||||
}
|
||||
}
|
||||
|
||||
if (moved)
|
||||
{
|
||||
safe_delete(it->second);
|
||||
free_ids.push(it->first);
|
||||
it = corpse_list.erase(it);
|
||||
++moved_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
return moved_count;
|
||||
}
|
||||
|
||||
@ -49,6 +49,7 @@ class Raid;
|
||||
class Spawn2;
|
||||
class Trap;
|
||||
|
||||
struct DynamicZoneSafeReturn;
|
||||
struct GuildBankItemUpdate_Struct;
|
||||
struct NewSpawn_Struct;
|
||||
struct QGlobal;
|
||||
@ -477,8 +478,9 @@ public:
|
||||
void CameraEffect(uint32 duration, uint32 intensity);
|
||||
Mob* GetClosestMobByBodyType(Mob* sender, bodyType BodyType);
|
||||
void ForceGroupUpdate(uint32 gid);
|
||||
void SendGroupLeave(uint32 gid, const char *name);
|
||||
void SendGroupLeave(uint32 gid, const char *name, bool checkleader);
|
||||
void SendGroupJoin(uint32 gid, const char *name);
|
||||
void SendGroupLeader(uint32 gid, const char *lname, const char *oldlname);
|
||||
|
||||
void SaveAllClientsTaskState();
|
||||
void ReloadAllClientsTaskState(int TaskID=0);
|
||||
@ -496,6 +498,8 @@ public:
|
||||
void UpdateFindableNPCState(NPC *n, bool Remove);
|
||||
void HideCorpses(Client *c, uint8 CurrentMode, uint8 NewMode);
|
||||
|
||||
void GateAllClientsToSafeReturn();
|
||||
|
||||
uint16 GetClientCount();
|
||||
void GetMobList(std::list<Mob*> &m_list);
|
||||
void GetNPCList(std::list<NPC*> &n_list);
|
||||
@ -534,6 +538,8 @@ public:
|
||||
void UpdateAllTraps(bool respawn, bool repopnow = false);
|
||||
void ClearTrapPointers();
|
||||
|
||||
int MovePlayerCorpsesToGraveyard(bool force_move_from_instance = false);
|
||||
|
||||
protected:
|
||||
friend class Zone;
|
||||
void Depop(bool StartSpawnTimer = false);
|
||||
|
||||
16
zone/exp.cpp
16
zone/exp.cpp
@ -664,11 +664,18 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
|
||||
m_pp.aapoints += last_unspentAA;
|
||||
|
||||
//figure out how many points were actually gained
|
||||
/*uint32 gained = m_pp.aapoints - last_unspentAA;*/ //unused
|
||||
uint32 gained = (m_pp.aapoints - last_unspentAA);
|
||||
|
||||
//Message(Chat::Yellow, "You have gained %d skill points!!", m_pp.aapoints - last_unspentAA);
|
||||
char val1[20]={0};
|
||||
MessageString(Chat::Experience, GAIN_ABILITY_POINT, ConvertArray(m_pp.aapoints, val1),m_pp.aapoints == 1 ? "" : "(s)"); //You have gained an ability point! You now have %1 ability point%2.
|
||||
char val1[20] = { 0 };
|
||||
char val2[20] = { 0 };
|
||||
if (gained == 1 && m_pp.aapoints == 1)
|
||||
MessageString(Chat::Experience, GAIN_SINGLE_AA_SINGLE_AA, ConvertArray(m_pp.aapoints, val1)); //You have gained an ability point! You now have %1 ability point.
|
||||
else if (gained == 1 && m_pp.aapoints > 1)
|
||||
MessageString(Chat::Experience, GAIN_SINGLE_AA_MULTI_AA, ConvertArray(m_pp.aapoints, val1)); //You have gained an ability point! You now have %1 ability points.
|
||||
else
|
||||
MessageString(Chat::Experience, GAIN_MULTI_AA_MULTI_AA, ConvertArray(gained, val1), ConvertArray(m_pp.aapoints, val2)); //You have gained %1 ability point(s)! You now have %2 ability point(s).
|
||||
|
||||
if (RuleB(AA, SoundForAAEarned)) {
|
||||
SendSound();
|
||||
}
|
||||
@ -718,7 +725,8 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
|
||||
else
|
||||
Message(Chat::Yellow, "Welcome to level %i!", check_level);
|
||||
|
||||
if (check_level == RuleI(Character, DeathItemLossLevel))
|
||||
if (check_level == RuleI(Character, DeathItemLossLevel) &&
|
||||
m_ClientVersionBit & EQ::versions::maskUFAndEarlier)
|
||||
MessageString(Chat::Yellow, CORPSE_ITEM_LOST);
|
||||
|
||||
if (check_level == RuleI(Character, DeathExpLossLevel))
|
||||
|
||||
2293
zone/expedition.cpp
Normal file
2293
zone/expedition.cpp
Normal file
File diff suppressed because it is too large
Load Diff
242
zone/expedition.h
Normal file
242
zone/expedition.h
Normal file
@ -0,0 +1,242 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* 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 EXPEDITION_H
|
||||
#define EXPEDITION_H
|
||||
|
||||
#include "dynamiczone.h"
|
||||
#include "expedition_lockout_timer.h"
|
||||
#include "../common/eq_constants.h"
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
class Client;
|
||||
class EQApplicationPacket;
|
||||
struct ExpeditionInvite;
|
||||
class ExpeditionRequest;
|
||||
class MySQLRequestResult;
|
||||
class ServerPacket;
|
||||
|
||||
extern const char* const DZ_YOU_NOT_ASSIGNED;
|
||||
extern const char* const EXPEDITION_OTHER_BELONGS;
|
||||
extern const char* const CREATE_NOT_ALL_ADDED;
|
||||
|
||||
enum class ExpeditionMemberStatus : uint8_t
|
||||
{
|
||||
Unknown = 0,
|
||||
Online,
|
||||
Offline,
|
||||
InDynamicZone,
|
||||
LinkDead
|
||||
};
|
||||
|
||||
enum class ExpeditionLockMessage : uint8_t
|
||||
{
|
||||
None = 0,
|
||||
Close,
|
||||
Begin
|
||||
};
|
||||
|
||||
struct ExpeditionMember
|
||||
{
|
||||
uint32_t char_id = 0;
|
||||
std::string name;
|
||||
ExpeditionMemberStatus status = ExpeditionMemberStatus::Online;
|
||||
|
||||
ExpeditionMember() = default;
|
||||
ExpeditionMember(uint32_t char_id_, const std::string& name_)
|
||||
: char_id(char_id_), name(name_) {}
|
||||
ExpeditionMember(uint32_t char_id_, const std::string& name_, ExpeditionMemberStatus status_)
|
||||
: char_id(char_id_), name(name_), status(status_) {}
|
||||
|
||||
bool IsValid() const { return char_id != 0 && !name.empty(); }
|
||||
};
|
||||
|
||||
class Expedition
|
||||
{
|
||||
public:
|
||||
Expedition() = delete;
|
||||
Expedition(uint32_t id, const std::string& uuid, const DynamicZone& dz, const std::string& expedition_name,
|
||||
const ExpeditionMember& leader, uint32_t min_players, uint32_t max_players);
|
||||
|
||||
static Expedition* TryCreate(Client* requester, DynamicZone& dynamiczone, ExpeditionRequest& request);
|
||||
|
||||
static void CacheFromDatabase(uint32_t expedition_id);
|
||||
static bool CacheAllFromDatabase();
|
||||
static Expedition* FindCachedExpeditionByCharacterID(uint32_t character_id);
|
||||
static Expedition* FindCachedExpeditionByCharacterName(const std::string& char_name);
|
||||
static Expedition* FindCachedExpeditionByDynamicZoneID(uint32_t dz_id);
|
||||
static Expedition* FindCachedExpeditionByID(uint32_t expedition_id);
|
||||
static Expedition* FindCachedExpeditionByZoneInstance(uint32_t zone_id, uint32_t instance_id);
|
||||
static std::vector<ExpeditionLockoutTimer> GetExpeditionLockoutsByCharacterID(uint32_t character_id);
|
||||
static void HandleWorldMessage(ServerPacket* pack);
|
||||
static void AddLockoutByCharacterID(uint32_t character_id, const std::string& expedition_name,
|
||||
const std::string& event_name, uint32_t seconds, const std::string& uuid = {});
|
||||
static void AddLockoutByCharacterName(const std::string& character_name, const std::string& expedition_name,
|
||||
const std::string& event_name, uint32_t seconds, const std::string& uuid = {});
|
||||
static bool HasLockoutByCharacterID(uint32_t character_id,
|
||||
const std::string& expedition_name, const std::string& event_name);
|
||||
static bool HasLockoutByCharacterName(const std::string& character_name,
|
||||
const std::string& expedition_name, const std::string& event_name);
|
||||
static void RemoveLockoutsByCharacterID(uint32_t character_id,
|
||||
const std::string& expedition_name = {}, const std::string& event_name = {});
|
||||
static void RemoveLockoutsByCharacterName(const std::string& character_name,
|
||||
const std::string& expedition_name = {}, const std::string& event_name = {});
|
||||
static void AddLockoutClients(const ExpeditionLockoutTimer& lockout, uint32_t exclude_id = 0);
|
||||
|
||||
uint32_t GetDynamicZoneID() const { return m_dynamiczone.GetID(); }
|
||||
uint32_t GetID() const { return m_id; }
|
||||
uint16_t GetInstanceID() const { return m_dynamiczone.GetInstanceID(); }
|
||||
uint32_t GetLeaderID() const { return m_leader.char_id; }
|
||||
uint32_t GetMinPlayers() const { return m_min_players; }
|
||||
uint32_t GetMaxPlayers() const { return m_max_players; }
|
||||
uint32_t GetMemberCount() const { return static_cast<uint32_t>(m_members.size()); }
|
||||
const DynamicZone& GetDynamicZone() const { return m_dynamiczone; }
|
||||
const std::string& GetName() const { return m_expedition_name; }
|
||||
const std::string& GetLeaderName() const { return m_leader.name; }
|
||||
const std::string& GetUUID() const { return m_uuid; }
|
||||
const std::unordered_map<std::string, ExpeditionLockoutTimer>& GetLockouts() const { return m_lockouts; }
|
||||
const std::vector<ExpeditionMember>& GetMembers() const { return m_members; }
|
||||
|
||||
bool AddMember(const std::string& add_char_name, uint32_t add_char_id);
|
||||
bool HasMember(const std::string& character_name);
|
||||
bool HasMember(uint32_t character_id);
|
||||
void RemoveAllMembers(bool enable_removal_timers = true);
|
||||
bool RemoveMember(const std::string& remove_char_name);
|
||||
void SetMemberStatus(Client* client, ExpeditionMemberStatus status);
|
||||
void SwapMember(Client* add_client, const std::string& remove_char_name);
|
||||
void SetLocked(bool lock_expedition, ExpeditionLockMessage lock_msg,
|
||||
bool update_db = false, uint32_t msg_color = Chat::Yellow);
|
||||
|
||||
void AddLockout(const std::string& event_name, uint32_t seconds);
|
||||
void AddLockoutDuration(const std::string& event_name, int seconds, bool members_only = true);
|
||||
void AddReplayLockout(uint32_t seconds);
|
||||
void AddReplayLockoutDuration(int seconds, bool members_only = true);
|
||||
bool HasLockout(const std::string& event_name);
|
||||
bool HasReplayLockout();
|
||||
void RemoveLockout(const std::string& event_name);
|
||||
void SetReplayLockoutOnMemberJoin(bool add_on_join, bool update_db = false);
|
||||
void SyncCharacterLockouts(uint32_t character_id, std::vector<ExpeditionLockoutTimer>& client_lockouts);
|
||||
void UpdateLockoutDuration(const std::string& event_name, uint32_t seconds, bool members_only = true);
|
||||
|
||||
bool CanClientLootCorpse(Client* client, uint32_t npc_type_id, uint32_t spawn_id);
|
||||
std::string GetLootEventByNPCTypeID(uint32_t npc_id);
|
||||
std::string GetLootEventBySpawnID(uint32_t spawn_id);
|
||||
void SetLootEventByNPCTypeID(uint32_t npc_type_id, const std::string& event_name);
|
||||
void SetLootEventBySpawnID(uint32_t spawn_id, const std::string& event_name);
|
||||
|
||||
void SendClientExpeditionInfo(Client* client);
|
||||
void SendWorldMakeLeaderRequest(uint32_t requester_id, const std::string& new_leader_name);
|
||||
void SendWorldPendingInvite(const ExpeditionInvite& invite, const std::string& add_name);
|
||||
|
||||
void DzAddPlayer(Client* requester, const std::string& add_char_name, const std::string& swap_remove_name = {});
|
||||
void DzAddPlayerContinue(std::string leader_name, std::string add_char_name, std::string swap_remove_name = {});
|
||||
void DzInviteResponse(Client* add_client, bool accepted, const std::string& swap_remove_name);
|
||||
void DzMakeLeader(Client* requester, std::string new_leader_name);
|
||||
void DzPlayerList(Client* requester);
|
||||
void DzRemovePlayer(Client* requester, std::string remove_char_name);
|
||||
void DzSwapPlayer(Client* requester, std::string remove_char_name, std::string add_char_name);
|
||||
void DzQuit(Client* requester);
|
||||
void DzKickPlayers(Client* requester);
|
||||
|
||||
void SetDzCompass(uint32_t zone_id, float x, float y, float z, bool update_db = false);
|
||||
void SetDzCompass(const std::string& zone_name, float x, float y, float z, bool update_db = false);
|
||||
void SetDzSafeReturn(uint32_t zone_id, float x, float y, float z, float heading, bool update_db = false);
|
||||
void SetDzSafeReturn(const std::string& zone_name, float x, float y, float z, float heading, bool update_db = false);
|
||||
void SetDzSecondsRemaining(uint32_t seconds_remaining);
|
||||
void SetDzZoneInLocation(float x, float y, float z, float heading, bool update_db = false);
|
||||
|
||||
static const int32_t REPLAY_TIMER_ID;
|
||||
static const int32_t EVENT_TIMER_ID;
|
||||
|
||||
private:
|
||||
static void CacheExpeditions(MySQLRequestResult& results);
|
||||
static void SendWorldGetOnlineMembers(const std::vector<std::pair<uint32_t, uint32_t>>& expedition_character_ids);
|
||||
static void SendWorldCharacterLockout(uint32_t character_id, const ExpeditionLockoutTimer& lockout, bool remove);
|
||||
|
||||
void AddLockout(const ExpeditionLockoutTimer& lockout, bool members_only = false);
|
||||
void AddLockoutDurationClients(const ExpeditionLockoutTimer& lockout, int seconds, uint32_t exclude_id = 0);
|
||||
void AddInternalMember(const std::string& char_name, uint32_t char_id, ExpeditionMemberStatus status);
|
||||
bool ConfirmLeaderCommand(Client* requester);
|
||||
bool ProcessAddConflicts(Client* leader_client, Client* add_client, bool swapping);
|
||||
void ProcessLeaderChanged(uint32_t new_leader_id);
|
||||
void ProcessLockoutDuration(const ExpeditionLockoutTimer& lockout, int seconds, bool members_only = false);
|
||||
void ProcessLockoutUpdate(const ExpeditionLockoutTimer& lockout, bool remove, bool members_only = false);
|
||||
void ProcessMakeLeader(Client* old_leader, Client* new_leader,
|
||||
const std::string& new_leader_name, bool is_success, bool is_online);
|
||||
void ProcessMemberAdded(const std::string& added_char_name, uint32_t added_char_id);
|
||||
void ProcessMemberRemoved(const std::string& removed_char_name, uint32_t removed_char_id);
|
||||
void SaveLockouts(ExpeditionRequest& request);
|
||||
void SaveMembers(ExpeditionRequest& request);
|
||||
void SendClientExpeditionInvite(
|
||||
Client* client, const std::string& inviter_name, const std::string& swap_remove_name);
|
||||
void SendLeaderMessage(Client* leader_client, uint16_t chat_type, uint32_t string_id,
|
||||
const std::initializer_list<std::string>& args = {});
|
||||
void SendMembersExpireWarning(uint32_t minutes);
|
||||
void SendNewMemberAddedToZoneMembers(const std::string& added_name);
|
||||
void SendUpdatesToZoneMembers(bool clear = false, bool message_on_clear = true);
|
||||
void SendWorldDzLocationUpdate(uint16_t server_opcode, const DynamicZoneLocation& location);
|
||||
void SendWorldExpeditionUpdate(uint16_t server_opcode);
|
||||
void SendWorldAddPlayerInvite(const std::string& inviter_name, const std::string& swap_remove_name,
|
||||
const std::string& add_name, bool pending = false);
|
||||
void SendWorldLockoutDuration(
|
||||
const ExpeditionLockoutTimer& lockout, int seconds, bool members_only = false);
|
||||
void SendWorldLockoutUpdate(
|
||||
const ExpeditionLockoutTimer& lockout, bool remove, bool members_only = false);
|
||||
void SendWorldMemberChanged(const std::string& char_name, uint32_t char_id, bool remove);
|
||||
void SendWorldMemberStatus(uint32_t character_id, ExpeditionMemberStatus status);
|
||||
void SendWorldMemberSwapped(const std::string& remove_char_name, uint32_t remove_char_id,
|
||||
const std::string& add_char_name, uint32_t add_char_id);
|
||||
void SendWorldSetSecondsRemaining(uint32_t seconds_remaining);
|
||||
void SendWorldSettingChanged(uint16_t server_opcode, bool setting_value);
|
||||
void TryAddClient(Client* add_client, const std::string& inviter_name,
|
||||
const std::string& swap_remove_name, Client* leader_client = nullptr);
|
||||
void UpdateDzDuration(uint32_t new_duration) { m_dynamiczone.SetUpdatedDuration(new_duration); }
|
||||
void UpdateMemberStatus(uint32_t update_character_id, ExpeditionMemberStatus status);
|
||||
|
||||
ExpeditionMember GetMemberData(uint32_t character_id);
|
||||
ExpeditionMember GetMemberData(const std::string& character_name);
|
||||
std::unique_ptr<EQApplicationPacket> CreateExpireWarningPacket(uint32_t minutes_remaining);
|
||||
std::unique_ptr<EQApplicationPacket> CreateInfoPacket(bool clear = false);
|
||||
std::unique_ptr<EQApplicationPacket> CreateInvitePacket(const std::string& inviter_name, const std::string& swap_remove_name);
|
||||
std::unique_ptr<EQApplicationPacket> CreateMemberListPacket(bool clear = false);
|
||||
std::unique_ptr<EQApplicationPacket> CreateMemberListNamePacket(const std::string& name, bool remove_name);
|
||||
std::unique_ptr<EQApplicationPacket> CreateMemberListStatusPacket(const std::string& name, ExpeditionMemberStatus status);
|
||||
std::unique_ptr<EQApplicationPacket> CreateLeaderNamePacket();
|
||||
|
||||
uint32_t m_id = 0;
|
||||
uint32_t m_min_players = 0;
|
||||
uint32_t m_max_players = 0;
|
||||
bool m_is_locked = false;
|
||||
bool m_add_replay_on_join = true;
|
||||
std::string m_uuid;
|
||||
std::string m_expedition_name;
|
||||
DynamicZone m_dynamiczone { DynamicZoneType::Expedition };
|
||||
ExpeditionMember m_leader;
|
||||
std::vector<ExpeditionMember> m_members;
|
||||
std::unordered_map<std::string, ExpeditionLockoutTimer> m_lockouts;
|
||||
std::unordered_map<uint32_t, std::string> m_npc_loot_events; // only valid inside dz zone
|
||||
std::unordered_map<uint32_t, std::string> m_spawn_loot_events; // only valid inside dz zone
|
||||
};
|
||||
|
||||
#endif
|
||||
685
zone/expedition_database.cpp
Normal file
685
zone/expedition_database.cpp
Normal file
@ -0,0 +1,685 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "expedition_database.h"
|
||||
#include "expedition.h"
|
||||
#include "expedition_lockout_timer.h"
|
||||
#include "zonedb.h"
|
||||
#include "../common/database.h"
|
||||
#include "../common/string_util.h"
|
||||
#include <fmt/core.h>
|
||||
|
||||
uint32_t ExpeditionDatabase::InsertExpedition(
|
||||
const std::string& uuid, uint32_t dz_id, const std::string& expedition_name,
|
||||
uint32_t leader_id, uint32_t min_players, uint32_t max_players)
|
||||
{
|
||||
LogExpeditionsDetail(
|
||||
"Inserting new expedition [{}] leader [{}] uuid [{}]", expedition_name, leader_id, uuid
|
||||
);
|
||||
|
||||
std::string query = fmt::format(SQL(
|
||||
INSERT INTO expeditions
|
||||
(uuid, dynamic_zone_id, expedition_name, leader_id, min_players, max_players)
|
||||
VALUES
|
||||
('{}', {}, '{}', {}, {}, {});
|
||||
), uuid, dz_id, EscapeString(expedition_name), leader_id, min_players, max_players);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
{
|
||||
LogExpeditions("Failed to obtain an expedition id for [{}]", expedition_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return results.LastInsertedID();
|
||||
}
|
||||
|
||||
std::string ExpeditionDatabase::LoadExpeditionsSelectQuery()
|
||||
{
|
||||
return std::string(SQL(
|
||||
SELECT
|
||||
expeditions.id,
|
||||
expeditions.uuid,
|
||||
expeditions.dynamic_zone_id,
|
||||
expeditions.expedition_name,
|
||||
expeditions.leader_id,
|
||||
expeditions.min_players,
|
||||
expeditions.max_players,
|
||||
expeditions.add_replay_on_join,
|
||||
expeditions.is_locked,
|
||||
character_data.name leader_name,
|
||||
expedition_members.character_id,
|
||||
member_data.name
|
||||
FROM expeditions
|
||||
INNER JOIN character_data ON expeditions.leader_id = character_data.id
|
||||
INNER JOIN expedition_members ON expeditions.id = expedition_members.expedition_id
|
||||
AND expedition_members.is_current_member = TRUE
|
||||
INNER JOIN character_data member_data ON expedition_members.character_id = member_data.id
|
||||
));
|
||||
}
|
||||
|
||||
MySQLRequestResult ExpeditionDatabase::LoadExpedition(uint32_t expedition_id)
|
||||
{
|
||||
LogExpeditionsDetail("Loading expedition [{}]", expedition_id);
|
||||
|
||||
std::string query = fmt::format(SQL(
|
||||
{} WHERE expeditions.id = {};
|
||||
), LoadExpeditionsSelectQuery(), expedition_id);
|
||||
|
||||
return database.QueryDatabase(query);
|
||||
}
|
||||
|
||||
MySQLRequestResult ExpeditionDatabase::LoadAllExpeditions()
|
||||
{
|
||||
LogExpeditionsDetail("Loading all expeditions from database");
|
||||
|
||||
std::string query = fmt::format(SQL(
|
||||
{} ORDER BY expeditions.id;
|
||||
), LoadExpeditionsSelectQuery());
|
||||
|
||||
return database.QueryDatabase(query);
|
||||
}
|
||||
|
||||
std::vector<ExpeditionLockoutTimer> ExpeditionDatabase::LoadCharacterLockouts(uint32_t character_id)
|
||||
{
|
||||
LogExpeditionsDetail("Loading character [{}] lockouts", character_id);
|
||||
|
||||
std::vector<ExpeditionLockoutTimer> lockouts;
|
||||
|
||||
auto query = fmt::format(SQL(
|
||||
SELECT
|
||||
from_expedition_uuid,
|
||||
expedition_name,
|
||||
event_name,
|
||||
UNIX_TIMESTAMP(expire_time),
|
||||
duration
|
||||
FROM character_expedition_lockouts
|
||||
WHERE character_id = {} AND expire_time > NOW();
|
||||
), character_id);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (results.Success())
|
||||
{
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
{
|
||||
lockouts.emplace_back(
|
||||
row[0], // expedition_uuid
|
||||
row[1], // expedition_name
|
||||
row[2], // event_name
|
||||
strtoull(row[3], nullptr, 10), // expire_time
|
||||
static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) // duration
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return lockouts;
|
||||
}
|
||||
|
||||
std::vector<ExpeditionLockoutTimer> ExpeditionDatabase::LoadCharacterLockouts(
|
||||
uint32_t character_id, const std::string& expedition_name)
|
||||
{
|
||||
LogExpeditionsDetail("Loading character [{}] lockouts for [{}]", character_id, expedition_name);
|
||||
|
||||
std::vector<ExpeditionLockoutTimer> lockouts;
|
||||
|
||||
auto query = fmt::format(SQL(
|
||||
SELECT
|
||||
from_expedition_uuid,
|
||||
event_name,
|
||||
UNIX_TIMESTAMP(expire_time),
|
||||
duration
|
||||
FROM character_expedition_lockouts
|
||||
WHERE
|
||||
character_id = {}
|
||||
AND expire_time > NOW()
|
||||
AND expedition_name = '{}';
|
||||
), character_id, EscapeString(expedition_name));
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (results.Success())
|
||||
{
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
{
|
||||
lockouts.emplace_back(
|
||||
row[0], // expedition_uuid
|
||||
expedition_name,
|
||||
row[1], // event_name
|
||||
strtoull(row[2], nullptr, 10), // expire_time
|
||||
static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) // duration
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return lockouts;
|
||||
}
|
||||
|
||||
std::unordered_map<uint32_t, std::unordered_map<std::string, ExpeditionLockoutTimer>>
|
||||
ExpeditionDatabase::LoadMultipleExpeditionLockouts(
|
||||
const std::vector<uint32_t>& expedition_ids)
|
||||
{
|
||||
LogExpeditionsDetail("Loading internal lockouts for [{}] expeditions", expedition_ids.size());
|
||||
|
||||
std::string in_expedition_ids_query = fmt::format("{}", fmt::join(expedition_ids, ","));
|
||||
|
||||
// these are loaded into the same container type expeditions use to store lockouts
|
||||
std::unordered_map<uint32_t, std::unordered_map<std::string, ExpeditionLockoutTimer>> lockouts;
|
||||
|
||||
if (!in_expedition_ids_query.empty())
|
||||
{
|
||||
std::string query = fmt::format(SQL(
|
||||
SELECT
|
||||
expedition_lockouts.expedition_id,
|
||||
expedition_lockouts.from_expedition_uuid,
|
||||
expeditions.expedition_name,
|
||||
expedition_lockouts.event_name,
|
||||
UNIX_TIMESTAMP(expedition_lockouts.expire_time),
|
||||
expedition_lockouts.duration
|
||||
FROM expedition_lockouts
|
||||
INNER JOIN expeditions ON expedition_lockouts.expedition_id = expeditions.id
|
||||
WHERE expedition_id IN ({})
|
||||
ORDER BY expedition_id;
|
||||
), in_expedition_ids_query);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
if (results.Success())
|
||||
{
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
{
|
||||
auto expedition_id = strtoul(row[0], nullptr, 10);
|
||||
lockouts[expedition_id].emplace(row[3], ExpeditionLockoutTimer{
|
||||
row[1], // expedition_uuid
|
||||
row[2], // expedition_name
|
||||
row[3], // event_name
|
||||
strtoull(row[4], nullptr, 10), // expire_time
|
||||
static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) // original duration
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return lockouts;
|
||||
}
|
||||
|
||||
MySQLRequestResult ExpeditionDatabase::LoadMembersForCreateRequest(
|
||||
const std::vector<std::string>& character_names, const std::string& expedition_name)
|
||||
{
|
||||
LogExpeditionsDetail(
|
||||
"Loading data of [{}] characters for [{}] request", character_names.size(), expedition_name
|
||||
);
|
||||
|
||||
std::string in_character_names_query;
|
||||
for (const auto& character_name : character_names)
|
||||
{
|
||||
fmt::format_to(std::back_inserter(in_character_names_query), "'{}',", character_name);
|
||||
}
|
||||
|
||||
MySQLRequestResult results;
|
||||
|
||||
if (!in_character_names_query.empty())
|
||||
{
|
||||
in_character_names_query.pop_back(); // trailing comma
|
||||
|
||||
// for create validation, loads each character's lockouts and possible current expedition
|
||||
auto query = fmt::format(SQL(
|
||||
SELECT
|
||||
character_data.id,
|
||||
character_data.name,
|
||||
member.expedition_id,
|
||||
lockout.from_expedition_uuid,
|
||||
UNIX_TIMESTAMP(lockout.expire_time),
|
||||
lockout.duration,
|
||||
lockout.event_name
|
||||
FROM character_data
|
||||
LEFT JOIN character_expedition_lockouts lockout
|
||||
ON character_data.id = lockout.character_id
|
||||
AND lockout.expire_time > NOW()
|
||||
AND lockout.expedition_name = '{}'
|
||||
LEFT JOIN expedition_members member
|
||||
ON character_data.id = member.character_id
|
||||
AND member.is_current_member = TRUE
|
||||
WHERE character_data.name IN ({})
|
||||
ORDER BY FIELD(character_data.name, {})
|
||||
), EscapeString(expedition_name), in_character_names_query, in_character_names_query);
|
||||
|
||||
results = database.QueryDatabase(query);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
void ExpeditionDatabase::DeleteAllCharacterLockouts(uint32_t character_id)
|
||||
{
|
||||
LogExpeditionsDetail("Deleting all character [{}] lockouts", character_id);
|
||||
|
||||
if (character_id != 0)
|
||||
{
|
||||
std::string query = fmt::format(SQL(
|
||||
DELETE FROM character_expedition_lockouts
|
||||
WHERE character_id = {};
|
||||
), character_id);
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
|
||||
void ExpeditionDatabase::DeleteAllCharacterLockouts(
|
||||
uint32_t character_id, const std::string& expedition_name)
|
||||
{
|
||||
LogExpeditionsDetail("Deleting all character [{}] lockouts for [{}]", character_id, expedition_name);
|
||||
|
||||
if (character_id != 0 && !expedition_name.empty())
|
||||
{
|
||||
std::string query = fmt::format(SQL(
|
||||
DELETE FROM character_expedition_lockouts
|
||||
WHERE character_id = {} AND expedition_name = '{}';
|
||||
), character_id, EscapeString(expedition_name));
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
|
||||
void ExpeditionDatabase::DeleteCharacterLockout(
|
||||
uint32_t character_id, const std::string& expedition_name, const std::string& event_name)
|
||||
{
|
||||
LogExpeditionsDetail(
|
||||
"Deleting character [{}] lockout: [{}]:[{}]", character_id, expedition_name, event_name
|
||||
);
|
||||
|
||||
auto query = fmt::format(SQL(
|
||||
DELETE FROM character_expedition_lockouts
|
||||
WHERE
|
||||
character_id = {}
|
||||
AND expedition_name = '{}'
|
||||
AND event_name = '{}';
|
||||
), character_id, EscapeString(expedition_name), EscapeString(event_name));
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
|
||||
void ExpeditionDatabase::DeleteMembersLockout(
|
||||
const std::vector<ExpeditionMember>& members,
|
||||
const std::string& expedition_name, const std::string& event_name)
|
||||
{
|
||||
LogExpeditionsDetail("Deleting members lockout: [{}]:[{}]", expedition_name, event_name);
|
||||
|
||||
std::string query_character_ids;
|
||||
for (const auto& member : members)
|
||||
{
|
||||
fmt::format_to(std::back_inserter(query_character_ids), "{},", member.char_id);
|
||||
}
|
||||
|
||||
if (!query_character_ids.empty())
|
||||
{
|
||||
query_character_ids.pop_back(); // trailing comma
|
||||
|
||||
auto query = fmt::format(SQL(
|
||||
DELETE FROM character_expedition_lockouts
|
||||
WHERE character_id
|
||||
IN ({})
|
||||
AND expedition_name = '{}'
|
||||
AND event_name = '{}';
|
||||
), query_character_ids, EscapeString(expedition_name), EscapeString(event_name));
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
|
||||
void ExpeditionDatabase::DeleteLockout(uint32_t expedition_id, const std::string& event_name)
|
||||
{
|
||||
LogExpeditionsDetail("Deleting expedition [{}] lockout event [{}]", expedition_id, event_name);
|
||||
|
||||
auto query = fmt::format(SQL(
|
||||
DELETE FROM expedition_lockouts
|
||||
WHERE expedition_id = {} AND event_name = '{}';
|
||||
), expedition_id, EscapeString(event_name));
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
|
||||
uint32_t ExpeditionDatabase::GetExpeditionIDFromCharacterID(uint32_t character_id)
|
||||
{
|
||||
LogExpeditionsDetail("Getting expedition id for character [{}]", character_id);
|
||||
|
||||
uint32_t expedition_id = 0;
|
||||
auto query = fmt::format(SQL(
|
||||
SELECT expedition_id FROM expedition_members
|
||||
WHERE character_id = {} AND is_current_member = TRUE;
|
||||
), character_id);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (results.Success() && results.RowCount() > 0)
|
||||
{
|
||||
auto row = results.begin();
|
||||
expedition_id = strtoul(row[0], nullptr, 10);
|
||||
}
|
||||
return expedition_id;
|
||||
}
|
||||
|
||||
uint32_t ExpeditionDatabase::GetMemberCount(uint32_t expedition_id)
|
||||
{
|
||||
LogExpeditionsDetail("Getting expedition [{}] member count from db", expedition_id);
|
||||
|
||||
uint32_t member_count = 0;
|
||||
if (expedition_id != 0)
|
||||
{
|
||||
auto query = fmt::format(SQL(
|
||||
SELECT COUNT(*)
|
||||
FROM expedition_members
|
||||
WHERE expedition_id = {} AND is_current_member = TRUE;
|
||||
), expedition_id);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (results.Success() && results.RowCount() > 0)
|
||||
{
|
||||
auto row = results.begin();
|
||||
member_count = strtoul(row[0], nullptr, 10);
|
||||
}
|
||||
}
|
||||
return member_count;
|
||||
}
|
||||
|
||||
bool ExpeditionDatabase::HasMember(uint32_t expedition_id, uint32_t character_id)
|
||||
{
|
||||
LogExpeditionsDetail("Checking db expedition [{}] for character [{}]", expedition_id, character_id);
|
||||
|
||||
if (expedition_id == 0 || character_id == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto query = fmt::format(SQL(
|
||||
SELECT id
|
||||
FROM expedition_members
|
||||
WHERE expedition_id = {} AND character_id = {} AND is_current_member = TRUE;
|
||||
), expedition_id, character_id);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
return (results.Success() && results.RowCount() > 0);
|
||||
}
|
||||
|
||||
void ExpeditionDatabase::InsertCharacterLockouts(uint32_t character_id,
|
||||
const std::vector<ExpeditionLockoutTimer>& lockouts)
|
||||
{
|
||||
LogExpeditionsDetail("Inserting [{}] lockouts for character [{}]", lockouts.size(), character_id);
|
||||
|
||||
std::string insert_values;
|
||||
for (const auto& lockout : lockouts)
|
||||
{
|
||||
fmt::format_to(std::back_inserter(insert_values),
|
||||
"({}, FROM_UNIXTIME({}), {}, '{}', '{}', '{}'),",
|
||||
character_id,
|
||||
lockout.GetExpireTime(),
|
||||
lockout.GetDuration(),
|
||||
lockout.GetExpeditionUUID(),
|
||||
EscapeString(lockout.GetExpeditionName()),
|
||||
EscapeString(lockout.GetEventName())
|
||||
);
|
||||
}
|
||||
|
||||
if (!insert_values.empty())
|
||||
{
|
||||
insert_values.pop_back(); // trailing comma
|
||||
|
||||
auto query = fmt::format(SQL(
|
||||
INSERT INTO character_expedition_lockouts
|
||||
(character_id, expire_time, duration, from_expedition_uuid, expedition_name, event_name)
|
||||
VALUES {}
|
||||
ON DUPLICATE KEY UPDATE
|
||||
from_expedition_uuid = VALUES(from_expedition_uuid),
|
||||
expire_time = VALUES(expire_time),
|
||||
duration = VALUES(duration);
|
||||
), insert_values);
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
|
||||
void ExpeditionDatabase::InsertMembersLockout(
|
||||
const std::vector<ExpeditionMember>& members, const ExpeditionLockoutTimer& lockout)
|
||||
{
|
||||
LogExpeditionsDetail(
|
||||
"Inserting members lockout [{}]:[{}] with expire time [{}]",
|
||||
lockout.GetExpeditionName(), lockout.GetEventName(), lockout.GetExpireTime()
|
||||
);
|
||||
|
||||
std::string insert_values;
|
||||
for (const auto& member : members)
|
||||
{
|
||||
fmt::format_to(std::back_inserter(insert_values),
|
||||
"({}, FROM_UNIXTIME({}), {}, '{}', '{}', '{}'),",
|
||||
member.char_id,
|
||||
lockout.GetExpireTime(),
|
||||
lockout.GetDuration(),
|
||||
lockout.GetExpeditionUUID(),
|
||||
EscapeString(lockout.GetExpeditionName()),
|
||||
EscapeString(lockout.GetEventName())
|
||||
);
|
||||
}
|
||||
|
||||
if (!insert_values.empty())
|
||||
{
|
||||
insert_values.pop_back(); // trailing comma
|
||||
|
||||
auto query = fmt::format(SQL(
|
||||
INSERT INTO character_expedition_lockouts
|
||||
(character_id, expire_time, duration, from_expedition_uuid, expedition_name, event_name)
|
||||
VALUES {}
|
||||
ON DUPLICATE KEY UPDATE
|
||||
from_expedition_uuid = VALUES(from_expedition_uuid),
|
||||
expire_time = VALUES(expire_time),
|
||||
duration = VALUES(duration);
|
||||
), insert_values);
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
|
||||
void ExpeditionDatabase::InsertLockout(
|
||||
uint32_t expedition_id, const ExpeditionLockoutTimer& lockout)
|
||||
{
|
||||
LogExpeditionsDetail(
|
||||
"Inserting expedition [{}] lockout: [{}]:[{}] expire time: [{}]",
|
||||
expedition_id, lockout.GetExpeditionName(), lockout.GetEventName(), lockout.GetExpireTime()
|
||||
);
|
||||
|
||||
auto query = fmt::format(SQL(
|
||||
INSERT INTO expedition_lockouts
|
||||
(expedition_id, from_expedition_uuid, event_name, expire_time, duration)
|
||||
VALUES
|
||||
({}, '{}', '{}', FROM_UNIXTIME({}), {})
|
||||
ON DUPLICATE KEY UPDATE
|
||||
from_expedition_uuid = VALUES(from_expedition_uuid),
|
||||
expire_time = VALUES(expire_time),
|
||||
duration = VALUES(duration);
|
||||
),
|
||||
expedition_id,
|
||||
lockout.GetExpeditionUUID(),
|
||||
EscapeString(lockout.GetEventName()),
|
||||
lockout.GetExpireTime(),
|
||||
lockout.GetDuration()
|
||||
);
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
|
||||
void ExpeditionDatabase::InsertLockouts(
|
||||
uint32_t expedition_id, const std::unordered_map<std::string, ExpeditionLockoutTimer>& lockouts)
|
||||
{
|
||||
LogExpeditionsDetail("Inserting expedition [{}] lockouts", expedition_id);
|
||||
|
||||
std::string insert_values;
|
||||
for (const auto& lockout : lockouts)
|
||||
{
|
||||
fmt::format_to(std::back_inserter(insert_values),
|
||||
"({}, '{}', '{}', FROM_UNIXTIME({}), {}),",
|
||||
expedition_id,
|
||||
lockout.second.GetExpeditionUUID(),
|
||||
EscapeString(lockout.second.GetEventName()),
|
||||
lockout.second.GetExpireTime(),
|
||||
lockout.second.GetDuration()
|
||||
);
|
||||
}
|
||||
|
||||
if (!insert_values.empty())
|
||||
{
|
||||
insert_values.pop_back(); // trailing comma
|
||||
|
||||
auto query = fmt::format(SQL(
|
||||
INSERT INTO expedition_lockouts
|
||||
(expedition_id, from_expedition_uuid, event_name, expire_time, duration)
|
||||
VALUES {}
|
||||
ON DUPLICATE KEY UPDATE
|
||||
from_expedition_uuid = VALUES(from_expedition_uuid),
|
||||
expire_time = VALUES(expire_time),
|
||||
duration = VALUES(duration);
|
||||
), insert_values);
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
|
||||
void ExpeditionDatabase::InsertMember(uint32_t expedition_id, uint32_t character_id)
|
||||
{
|
||||
LogExpeditionsDetail("Inserting character [{}] into expedition [{}]", character_id, expedition_id);
|
||||
|
||||
auto query = fmt::format(SQL(
|
||||
INSERT INTO expedition_members
|
||||
(expedition_id, character_id)
|
||||
VALUES
|
||||
({}, {})
|
||||
ON DUPLICATE KEY UPDATE is_current_member = TRUE;
|
||||
), expedition_id, character_id);
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
|
||||
void ExpeditionDatabase::InsertMembers(
|
||||
uint32_t expedition_id, const std::vector<ExpeditionMember>& members)
|
||||
{
|
||||
LogExpeditionsDetail("Inserting characters into expedition [{}]", expedition_id);
|
||||
|
||||
std::string insert_values;
|
||||
for (const auto& member : members)
|
||||
{
|
||||
fmt::format_to(std::back_inserter(insert_values),
|
||||
"({}, {}),",
|
||||
expedition_id, member.char_id
|
||||
);
|
||||
}
|
||||
|
||||
if (!insert_values.empty())
|
||||
{
|
||||
insert_values.pop_back(); // trailing comma
|
||||
|
||||
auto query = fmt::format(SQL(
|
||||
INSERT INTO expedition_members
|
||||
(expedition_id, character_id)
|
||||
VALUES {}
|
||||
ON DUPLICATE KEY UPDATE is_current_member = TRUE;
|
||||
), insert_values);
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
|
||||
void ExpeditionDatabase::UpdateLockState(uint32_t expedition_id, bool is_locked)
|
||||
{
|
||||
LogExpeditionsDetail("Updating lock state [{}] for expedition [{}]", is_locked, expedition_id);
|
||||
|
||||
auto query = fmt::format(SQL(
|
||||
UPDATE expeditions SET is_locked = {} WHERE id = {};
|
||||
), is_locked, expedition_id);
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
|
||||
void ExpeditionDatabase::DeleteMember(uint32_t expedition_id, uint32_t character_id)
|
||||
{
|
||||
LogExpeditionsDetail("Removing member [{}] from expedition [{}]", character_id, expedition_id);
|
||||
|
||||
auto query = fmt::format(SQL(
|
||||
UPDATE expedition_members SET is_current_member = FALSE
|
||||
WHERE expedition_id = {} AND character_id = {};
|
||||
), expedition_id, character_id);
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
|
||||
void ExpeditionDatabase::DeleteAllMembers(uint32_t expedition_id)
|
||||
{
|
||||
LogExpeditionsDetail("Removing all members of expedition [{}]", expedition_id);
|
||||
|
||||
auto query = fmt::format(SQL(
|
||||
UPDATE expedition_members SET is_current_member = FALSE WHERE expedition_id = {};
|
||||
), expedition_id);
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
|
||||
void ExpeditionDatabase::UpdateReplayLockoutOnJoin(uint32_t expedition_id, bool add_on_join)
|
||||
{
|
||||
LogExpeditionsDetail("Updating replay lockout on join [{}] for expedition [{}]", add_on_join, expedition_id);
|
||||
|
||||
auto query = fmt::format(SQL(
|
||||
UPDATE expeditions SET add_replay_on_join = {} WHERE id = {};
|
||||
), add_on_join, expedition_id);
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
|
||||
void ExpeditionDatabase::AddLockoutDuration(const std::vector<ExpeditionMember>& members,
|
||||
const ExpeditionLockoutTimer& lockout, int seconds)
|
||||
{
|
||||
LogExpeditionsDetail(
|
||||
"Adding duration [{}] seconds to members lockouts [{}]:[{}]",
|
||||
seconds, lockout.GetExpeditionName(), lockout.GetEventName());
|
||||
|
||||
std::string insert_values;
|
||||
for (const auto& member : members)
|
||||
{
|
||||
fmt::format_to(std::back_inserter(insert_values),
|
||||
"({}, FROM_UNIXTIME({}), {}, '{}', '{}', '{}'),",
|
||||
member.char_id,
|
||||
lockout.GetExpireTime(),
|
||||
lockout.GetDuration(),
|
||||
lockout.GetExpeditionUUID(),
|
||||
EscapeString(lockout.GetExpeditionName()),
|
||||
EscapeString(lockout.GetEventName())
|
||||
);
|
||||
}
|
||||
|
||||
if (!insert_values.empty())
|
||||
{
|
||||
insert_values.pop_back(); // trailing comma
|
||||
|
||||
auto query = fmt::format(SQL(
|
||||
INSERT INTO character_expedition_lockouts
|
||||
(character_id, expire_time, duration, from_expedition_uuid, expedition_name, event_name)
|
||||
VALUES {}
|
||||
ON DUPLICATE KEY UPDATE
|
||||
from_expedition_uuid = VALUES(from_expedition_uuid),
|
||||
expire_time = DATE_ADD(expire_time, INTERVAL {} SECOND),
|
||||
duration = GREATEST(0, CAST(duration AS SIGNED) + {});
|
||||
), insert_values, seconds, seconds);
|
||||
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
111
zone/expedition_database.h
Normal file
111
zone/expedition_database.h
Normal file
@ -0,0 +1,111 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* 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 EXPEDITION_DATABASE_H
|
||||
#define EXPEDITION_DATABASE_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
class Expedition;
|
||||
class ExpeditionLockoutTimer;
|
||||
struct ExpeditionMember;
|
||||
class MySQLRequestResult;
|
||||
|
||||
namespace ExpeditionDatabase
|
||||
{
|
||||
uint32_t InsertExpedition(
|
||||
const std::string& uuid, uint32_t instance_id, const std::string& expedition_name,
|
||||
uint32_t leader_id, uint32_t min_players, uint32_t max_players);
|
||||
std::string LoadExpeditionsSelectQuery();
|
||||
MySQLRequestResult LoadExpedition(uint32_t expedition_id);
|
||||
MySQLRequestResult LoadAllExpeditions();
|
||||
MySQLRequestResult LoadMembersForCreateRequest(
|
||||
const std::vector<std::string>& character_names, const std::string& expedition_name);
|
||||
std::vector<ExpeditionLockoutTimer> LoadCharacterLockouts(uint32_t character_id);
|
||||
std::vector<ExpeditionLockoutTimer> LoadCharacterLockouts(uint32_t character_id,
|
||||
const std::string& expedition_name);
|
||||
std::unordered_map<uint32_t, std::unordered_map<std::string, ExpeditionLockoutTimer>>
|
||||
LoadMultipleExpeditionLockouts(const std::vector<uint32_t>& expedition_ids);
|
||||
void DeleteAllMembers(uint32_t expedition_id);
|
||||
void DeleteMember(uint32_t expedition_id, uint32_t character_id);
|
||||
void DeleteAllCharacterLockouts(uint32_t character_id);
|
||||
void DeleteAllCharacterLockouts(uint32_t character_id, const std::string& expedition_name);
|
||||
void DeleteCharacterLockout(uint32_t character_id, const std::string& expedition_name,
|
||||
const std::string& event_name);
|
||||
void DeleteLockout(uint32_t expedition_id, const std::string& event_name);
|
||||
void DeleteMembersLockout(const std::vector<ExpeditionMember>& members,
|
||||
const std::string& expedition_name, const std::string& event_name);
|
||||
uint32_t GetExpeditionIDFromCharacterID(uint32_t character_id);
|
||||
uint32_t GetMemberCount(uint32_t expedition_id);
|
||||
bool HasMember(uint32_t expedition_id, uint32_t character_id);
|
||||
void InsertCharacterLockouts(uint32_t character_id,
|
||||
const std::vector<ExpeditionLockoutTimer>& lockouts);
|
||||
void InsertMembersLockout(const std::vector<ExpeditionMember>& members,
|
||||
const ExpeditionLockoutTimer& lockout);
|
||||
void InsertLockout(uint32_t expedition_id, const ExpeditionLockoutTimer& lockout);
|
||||
void InsertLockouts(uint32_t expedition_id,
|
||||
const std::unordered_map<std::string, ExpeditionLockoutTimer>& lockouts);
|
||||
void InsertMember(uint32_t expedition_id, uint32_t character_id);
|
||||
void InsertMembers(uint32_t expedition_id, const std::vector<ExpeditionMember>& members);
|
||||
void UpdateLockState(uint32_t expedition_id, bool is_locked);
|
||||
void UpdateReplayLockoutOnJoin(uint32_t expedition_id, bool add_on_join);
|
||||
void AddLockoutDuration(const std::vector<ExpeditionMember>& members,
|
||||
const ExpeditionLockoutTimer& lockout, int seconds);
|
||||
};
|
||||
|
||||
namespace LoadExpeditionColumns
|
||||
{
|
||||
enum eLoadExpeditionColumns
|
||||
{
|
||||
id = 0,
|
||||
uuid,
|
||||
dz_id,
|
||||
expedition_name,
|
||||
leader_id,
|
||||
min_players,
|
||||
max_players,
|
||||
add_replay_on_join,
|
||||
is_locked,
|
||||
leader_name,
|
||||
member_id,
|
||||
member_name
|
||||
};
|
||||
};
|
||||
|
||||
namespace LoadMembersForCreateRequestColumns
|
||||
{
|
||||
enum eLoadMembersForCreateRequestColumns
|
||||
{
|
||||
character_id = 0,
|
||||
character_name,
|
||||
character_expedition_id,
|
||||
lockout_uuid,
|
||||
lockout_expire_time,
|
||||
lockout_duration,
|
||||
lockout_event_name
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
101
zone/expedition_lockout_timer.cpp
Normal file
101
zone/expedition_lockout_timer.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "expedition_lockout_timer.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/util/uuid.h"
|
||||
#include <fmt/format.h>
|
||||
|
||||
const char* const DZ_REPLAY_TIMER_NAME = "Replay Timer"; // see December 14, 2016 patch notes
|
||||
|
||||
ExpeditionLockoutTimer::ExpeditionLockoutTimer(
|
||||
const std::string& expedition_uuid, const std::string& expedition_name,
|
||||
const std::string& event_name, uint64_t expire_time, uint32_t duration
|
||||
) :
|
||||
m_expedition_uuid(expedition_uuid),
|
||||
m_expedition_name(expedition_name),
|
||||
m_event_name(event_name),
|
||||
m_expire_time(std::chrono::system_clock::from_time_t(expire_time)),
|
||||
m_duration(duration)
|
||||
{
|
||||
if (event_name == DZ_REPLAY_TIMER_NAME)
|
||||
{
|
||||
m_is_replay_timer = true;
|
||||
}
|
||||
}
|
||||
|
||||
ExpeditionLockoutTimer ExpeditionLockoutTimer::CreateLockout(
|
||||
const std::string& expedition_name, const std::string& event_name, uint32_t seconds, std::string uuid)
|
||||
{
|
||||
seconds = static_cast<uint32_t>(seconds * RuleR(Expedition, LockoutDurationMultiplier));
|
||||
|
||||
if (uuid.empty())
|
||||
{
|
||||
uuid = EQ::Util::UUID::Generate().ToString();
|
||||
}
|
||||
|
||||
ExpeditionLockoutTimer lockout{uuid, expedition_name, event_name, 0, seconds};
|
||||
lockout.Reset(); // sets expire time
|
||||
return lockout;
|
||||
}
|
||||
|
||||
uint32_t ExpeditionLockoutTimer::GetSecondsRemaining() const
|
||||
{
|
||||
auto now = std::chrono::system_clock::now();
|
||||
if (m_expire_time > now)
|
||||
{
|
||||
auto remaining = m_expire_time - now;
|
||||
return static_cast<uint32_t>(std::chrono::duration_cast<std::chrono::seconds>(remaining).count());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ExpeditionLockoutTimer::DaysHoursMinutes ExpeditionLockoutTimer::GetDaysHoursMinutesRemaining() const
|
||||
{
|
||||
auto seconds = GetSecondsRemaining();
|
||||
return ExpeditionLockoutTimer::DaysHoursMinutes{
|
||||
fmt::format_int(seconds / 86400).str(), // days
|
||||
fmt::format_int((seconds / 3600) % 24).str(), // hours
|
||||
fmt::format_int((seconds / 60) % 60).str() // minutes
|
||||
};
|
||||
}
|
||||
|
||||
bool ExpeditionLockoutTimer::IsSameLockout(const ExpeditionLockoutTimer& compare_lockout) const
|
||||
{
|
||||
return compare_lockout.IsSameLockout(GetExpeditionName(), GetEventName());
|
||||
}
|
||||
|
||||
bool ExpeditionLockoutTimer::IsSameLockout(
|
||||
const std::string& expedition_name, const std::string& event_name) const
|
||||
{
|
||||
return GetExpeditionName() == expedition_name && GetEventName() == event_name;
|
||||
}
|
||||
|
||||
void ExpeditionLockoutTimer::AddLockoutTime(int seconds)
|
||||
{
|
||||
seconds = static_cast<uint32_t>(seconds * RuleR(Expedition, LockoutDurationMultiplier));
|
||||
|
||||
auto new_duration = std::max(0, static_cast<int>(m_duration.count()) + seconds);
|
||||
|
||||
auto start_time = m_expire_time - m_duration;
|
||||
m_duration = std::chrono::seconds(new_duration);
|
||||
m_expire_time = start_time + m_duration;
|
||||
}
|
||||
76
zone/expedition_lockout_timer.h
Normal file
76
zone/expedition_lockout_timer.h
Normal file
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* 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 EXPEDITION_LOCKOUT_TIMER_H
|
||||
#define EXPEDITION_LOCKOUT_TIMER_H
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
|
||||
extern const char* const DZ_REPLAY_TIMER_NAME;
|
||||
|
||||
class ExpeditionLockoutTimer
|
||||
{
|
||||
public:
|
||||
ExpeditionLockoutTimer() = default;
|
||||
ExpeditionLockoutTimer(
|
||||
const std::string& expedition_uuid, const std::string& expedition_name,
|
||||
const std::string& event_name, uint64_t expire_time, uint32_t duration);
|
||||
|
||||
static ExpeditionLockoutTimer CreateLockout(
|
||||
const std::string& expedition_name, const std::string& event_name,
|
||||
uint32_t seconds, std::string uuid = {});
|
||||
|
||||
struct DaysHoursMinutes
|
||||
{
|
||||
std::string days;
|
||||
std::string hours;
|
||||
std::string mins;
|
||||
};
|
||||
|
||||
void AddLockoutTime(int seconds);
|
||||
uint32_t GetDuration() const { return static_cast<uint32_t>(m_duration.count()); }
|
||||
uint64_t GetExpireTime() const { return std::chrono::system_clock::to_time_t(m_expire_time); }
|
||||
uint64_t GetStartTime() const { return std::chrono::system_clock::to_time_t(m_expire_time - m_duration); }
|
||||
uint32_t GetSecondsRemaining() const;
|
||||
DaysHoursMinutes GetDaysHoursMinutesRemaining() const;
|
||||
const std::string& GetExpeditionName() const { return m_expedition_name; }
|
||||
const std::string& GetExpeditionUUID() const { return m_expedition_uuid; }
|
||||
const std::string& GetEventName() const { return m_event_name; }
|
||||
bool IsExpired() const { return GetSecondsRemaining() == 0; }
|
||||
bool IsFromExpedition(const std::string& uuid) const { return uuid == m_expedition_uuid; }
|
||||
bool IsReplayTimer() const { return m_is_replay_timer; }
|
||||
bool IsSameLockout(const ExpeditionLockoutTimer& compare_lockout) const;
|
||||
bool IsSameLockout(const std::string& expedition_name, const std::string& event_name) const;
|
||||
void Reset() { m_expire_time = std::chrono::system_clock::now() + m_duration; }
|
||||
void SetDuration(uint32_t seconds) { m_duration = std::chrono::seconds(seconds); }
|
||||
void SetExpireTime(uint64_t expire_time) { m_expire_time = std::chrono::system_clock::from_time_t(expire_time); }
|
||||
void SetUUID(const std::string& uuid) { m_expedition_uuid = uuid; }
|
||||
|
||||
private:
|
||||
bool m_is_replay_timer = false;
|
||||
std::string m_expedition_uuid; // expedition received in
|
||||
std::string m_expedition_name;
|
||||
std::string m_event_name;
|
||||
std::chrono::seconds m_duration;
|
||||
std::chrono::time_point<std::chrono::system_clock> m_expire_time;
|
||||
};
|
||||
|
||||
#endif
|
||||
397
zone/expedition_request.cpp
Normal file
397
zone/expedition_request.cpp
Normal file
@ -0,0 +1,397 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "expedition_request.h"
|
||||
#include "client.h"
|
||||
#include "expedition.h"
|
||||
#include "expedition_database.h"
|
||||
#include "expedition_lockout_timer.h"
|
||||
#include "groups.h"
|
||||
#include "raids.h"
|
||||
#include "string_ids.h"
|
||||
#include "worldserver.h"
|
||||
|
||||
extern WorldServer worldserver;
|
||||
|
||||
constexpr char SystemName[] = "expedition";
|
||||
|
||||
struct ExpeditionRequestConflict
|
||||
{
|
||||
std::string character_name;
|
||||
ExpeditionLockoutTimer lockout;
|
||||
};
|
||||
|
||||
ExpeditionRequest::ExpeditionRequest(
|
||||
std::string expedition_name, uint32_t min_players, uint32_t max_players, bool disable_messages
|
||||
) :
|
||||
m_expedition_name(expedition_name),
|
||||
m_min_players(min_players),
|
||||
m_max_players(max_players),
|
||||
m_disable_messages(disable_messages)
|
||||
{
|
||||
}
|
||||
|
||||
bool ExpeditionRequest::Validate(Client* requester)
|
||||
{
|
||||
m_requester = requester;
|
||||
if (!m_requester)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// a message is sent to leader for every member that fails a requirement
|
||||
|
||||
BenchTimer benchmark;
|
||||
|
||||
bool requirements_met = false;
|
||||
|
||||
Raid* raid = m_requester->GetRaid();
|
||||
Group* group = m_requester->GetGroup();
|
||||
if (raid)
|
||||
{
|
||||
requirements_met = CanRaidRequest(raid);
|
||||
}
|
||||
else if (group)
|
||||
{
|
||||
requirements_met = CanGroupRequest(group);
|
||||
}
|
||||
else // solo request
|
||||
{
|
||||
m_leader = m_requester;
|
||||
m_leader_id = m_requester->CharacterID();
|
||||
m_leader_name = m_requester->GetName();
|
||||
requirements_met = CanMembersJoin({m_leader_name});
|
||||
}
|
||||
|
||||
auto elapsed = benchmark.elapsed();
|
||||
LogExpeditions("Create validation for [{}] members took [{}s]", m_members.size(), elapsed);
|
||||
|
||||
return requirements_met;
|
||||
}
|
||||
|
||||
bool ExpeditionRequest::CanRaidRequest(Raid* raid)
|
||||
{
|
||||
m_leader = raid->GetLeader();
|
||||
m_leader_name = raid->leadername;
|
||||
m_leader_id = m_leader ? m_leader->CharacterID() : database.GetCharacterID(raid->leadername);
|
||||
|
||||
// live (as of September 16, 2020) supports creation even if raid count exceeds
|
||||
// expedition max. members are added up to the max ordered by group number.
|
||||
auto raid_members = raid->GetMembers();
|
||||
|
||||
if (raid_members.size() > m_max_players)
|
||||
{
|
||||
// stable_sort not needed, order within a raid group may not be what is displayed
|
||||
std::sort(raid_members.begin(), raid_members.end(),
|
||||
[&](const RaidMember& lhs, const RaidMember& rhs) {
|
||||
if (m_leader_name == lhs.membername) { // leader always added first
|
||||
return true;
|
||||
} else if (m_leader_name == rhs.membername) {
|
||||
return false;
|
||||
}
|
||||
return lhs.GroupNumber < rhs.GroupNumber;
|
||||
});
|
||||
|
||||
m_not_all_added_msg = fmt::format(CREATE_NOT_ALL_ADDED, "raid", SystemName,
|
||||
SystemName, m_max_players, "raid", raid_members.size());
|
||||
}
|
||||
|
||||
// live still performs conflict checks for all members even those beyond max
|
||||
std::vector<std::string> member_names;
|
||||
for (int i = 0; i < raid_members.size(); ++i)
|
||||
{
|
||||
member_names.emplace_back(raid_members[i].membername);
|
||||
}
|
||||
|
||||
return CanMembersJoin(member_names);
|
||||
}
|
||||
|
||||
bool ExpeditionRequest::CanGroupRequest(Group* group)
|
||||
{
|
||||
m_leader = nullptr;
|
||||
if (group->GetLeader() && group->GetLeader()->IsClient())
|
||||
{
|
||||
m_leader = group->GetLeader()->CastToClient();
|
||||
}
|
||||
|
||||
// Group::GetLeaderName() is broken if group formed across zones, ask database instead
|
||||
m_leader_name = m_leader ? m_leader->GetName() : GetGroupLeaderName(group->GetID()); // group->GetLeaderName();
|
||||
m_leader_id = m_leader ? m_leader->CharacterID() : database.GetCharacterID(m_leader_name.c_str());
|
||||
|
||||
std::vector<std::string> member_names;
|
||||
member_names.emplace_back(m_leader_name); // leader always added first
|
||||
|
||||
for (int i = 0; i < MAX_GROUP_MEMBERS; ++i)
|
||||
{
|
||||
if (group->membername[i][0] && m_leader_name != group->membername[i])
|
||||
{
|
||||
member_names.emplace_back(group->membername[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (member_names.size() > m_max_players)
|
||||
{
|
||||
m_not_all_added_msg = fmt::format(CREATE_NOT_ALL_ADDED, "group", SystemName,
|
||||
SystemName, m_max_players, "group", member_names.size());
|
||||
}
|
||||
|
||||
return CanMembersJoin(member_names);
|
||||
}
|
||||
|
||||
std::string ExpeditionRequest::GetGroupLeaderName(uint32_t group_id)
|
||||
{
|
||||
char leader_name_buffer[64] = { 0 };
|
||||
database.GetGroupLeadershipInfo(group_id, leader_name_buffer);
|
||||
return std::string(leader_name_buffer);
|
||||
}
|
||||
|
||||
bool ExpeditionRequest::CanMembersJoin(const std::vector<std::string>& member_names)
|
||||
{
|
||||
if (member_names.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool requirements_met = true;
|
||||
|
||||
if (CheckMembersForConflicts(member_names))
|
||||
{
|
||||
requirements_met = false;
|
||||
}
|
||||
|
||||
// live only checks player count requirement after other expensive checks pass (?)
|
||||
// maybe it's done intentionally as a way to preview lockout conflicts
|
||||
if (requirements_met)
|
||||
{
|
||||
requirements_met = IsPlayerCountValidated();
|
||||
}
|
||||
|
||||
return requirements_met;
|
||||
}
|
||||
|
||||
bool ExpeditionRequest::LoadLeaderLockouts()
|
||||
{
|
||||
// leader's lockouts are used to check member conflicts and later stored in expedition
|
||||
auto lockouts = ExpeditionDatabase::LoadCharacterLockouts(m_leader_id, m_expedition_name);
|
||||
|
||||
for (auto& lockout : lockouts)
|
||||
{
|
||||
if (!lockout.IsExpired())
|
||||
{
|
||||
m_lockouts.emplace(lockout.GetEventName(), lockout);
|
||||
|
||||
// on live if leader has a replay lockout it never bothers checking for event conflicts
|
||||
if (m_check_event_lockouts && lockout.IsReplayTimer())
|
||||
{
|
||||
m_check_event_lockouts = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExpeditionRequest::CheckMembersForConflicts(const std::vector<std::string>& member_names)
|
||||
{
|
||||
// load data for each member and compare with leader lockouts
|
||||
auto results = ExpeditionDatabase::LoadMembersForCreateRequest(member_names, m_expedition_name);
|
||||
if (!results.Success() || !LoadLeaderLockouts())
|
||||
{
|
||||
LogExpeditions("Failed to load data to verify members for expedition request");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_solo = (member_names.size() == 1);
|
||||
bool has_conflicts = false;
|
||||
|
||||
using col = LoadMembersForCreateRequestColumns::eLoadMembersForCreateRequestColumns;
|
||||
|
||||
std::vector<ExpeditionRequestConflict> member_lockout_conflicts;
|
||||
|
||||
uint32_t last_character_id = 0;
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
{
|
||||
uint32_t character_id = std::strtoul(row[col::character_id], nullptr, 10);
|
||||
std::string character_name = row[col::character_name];
|
||||
bool has_expedition = (row[col::character_expedition_id] != nullptr);
|
||||
|
||||
if (character_id != last_character_id)
|
||||
{
|
||||
// defaults to online status, if offline group members implemented this needs to change
|
||||
m_members.emplace_back(character_id, character_name);
|
||||
|
||||
// process event lockout conflict messages from the previous character
|
||||
for (const auto& member_lockout : member_lockout_conflicts)
|
||||
{
|
||||
SendLeaderMemberEventLockout(member_lockout.character_name, member_lockout.lockout);
|
||||
}
|
||||
member_lockout_conflicts.clear();
|
||||
|
||||
if (has_expedition)
|
||||
{
|
||||
has_conflicts = true;
|
||||
SendLeaderMemberInExpedition(character_name, is_solo);
|
||||
|
||||
// solo requests break out early if requester in an expedition
|
||||
if (is_solo)
|
||||
{
|
||||
return has_conflicts;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
last_character_id = character_id;
|
||||
|
||||
// compare member lockouts with leader lockouts
|
||||
if (row[col::lockout_uuid]) // lockout results may be null
|
||||
{
|
||||
auto expire_time = strtoull(row[col::lockout_expire_time], nullptr, 10);
|
||||
uint32_t duration = strtoul(row[col::lockout_duration], nullptr, 10);
|
||||
|
||||
ExpeditionLockoutTimer lockout{
|
||||
row[col::lockout_uuid], m_expedition_name, row[col::lockout_event_name], expire_time, duration
|
||||
};
|
||||
|
||||
if (!lockout.IsExpired())
|
||||
{
|
||||
if (lockout.IsReplayTimer())
|
||||
{
|
||||
// replay timer conflict messages always show up before event conflicts
|
||||
has_conflicts = true;
|
||||
SendLeaderMemberReplayLockout(character_name, lockout, is_solo);
|
||||
}
|
||||
else if (m_check_event_lockouts && character_id != m_leader_id)
|
||||
{
|
||||
if (m_lockouts.find(lockout.GetEventName()) == m_lockouts.end())
|
||||
{
|
||||
// leader doesn't have this lockout. queue instead of messaging
|
||||
// now so message comes after any replay lockout messages
|
||||
has_conflicts = true;
|
||||
member_lockout_conflicts.push_back({character_name, lockout});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// event lockout messages for last processed character
|
||||
for (const auto& member_lockout : member_lockout_conflicts)
|
||||
{
|
||||
SendLeaderMemberEventLockout(member_lockout.character_name, member_lockout.lockout);
|
||||
}
|
||||
|
||||
return has_conflicts;
|
||||
}
|
||||
|
||||
void ExpeditionRequest::SendLeaderMessage(
|
||||
uint16_t chat_type, uint32_t string_id, const std::initializer_list<std::string>& args)
|
||||
{
|
||||
if (!m_disable_messages)
|
||||
{
|
||||
Client::SendCrossZoneMessageString(m_leader, m_leader_name, chat_type, string_id, args);
|
||||
}
|
||||
}
|
||||
|
||||
void ExpeditionRequest::SendLeaderMemberInExpedition(const std::string& member_name, bool is_solo)
|
||||
{
|
||||
if (m_disable_messages)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_solo)
|
||||
{
|
||||
SendLeaderMessage(Chat::Red, EXPEDITION_YOU_BELONG);
|
||||
}
|
||||
else if (m_requester)
|
||||
{
|
||||
std::string message = fmt::format(EXPEDITION_OTHER_BELONGS, m_requester->GetName(), member_name);
|
||||
Client::SendCrossZoneMessage(m_leader, m_leader_name, Chat::Red, message);
|
||||
}
|
||||
}
|
||||
|
||||
void ExpeditionRequest::SendLeaderMemberReplayLockout(
|
||||
const std::string& member_name, const ExpeditionLockoutTimer& lockout, bool is_solo)
|
||||
{
|
||||
if (m_disable_messages)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto time_remaining = lockout.GetDaysHoursMinutesRemaining();
|
||||
if (is_solo)
|
||||
{
|
||||
SendLeaderMessage(Chat::Red, EXPEDITION_YOU_PLAYED_HERE, {
|
||||
time_remaining.days, time_remaining.hours, time_remaining.mins
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
SendLeaderMessage(Chat::Red, EXPEDITION_REPLAY_TIMER, {
|
||||
member_name, time_remaining.days, time_remaining.hours, time_remaining.mins
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ExpeditionRequest::SendLeaderMemberEventLockout(
|
||||
const std::string& member_name, const ExpeditionLockoutTimer& lockout)
|
||||
{
|
||||
if (m_disable_messages)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto time_remaining = lockout.GetDaysHoursMinutesRemaining();
|
||||
SendLeaderMessage(Chat::Red, EXPEDITION_EVENT_TIMER, {
|
||||
member_name,
|
||||
lockout.GetEventName(),
|
||||
time_remaining.days,
|
||||
time_remaining.hours,
|
||||
time_remaining.mins,
|
||||
lockout.GetEventName()
|
||||
});
|
||||
}
|
||||
|
||||
bool ExpeditionRequest::IsPlayerCountValidated()
|
||||
{
|
||||
// note: offline group members count towards requirement but not added to expedition
|
||||
bool requirements_met = true;
|
||||
|
||||
auto bypass_status = RuleI(Expedition, MinStatusToBypassPlayerCountRequirements);
|
||||
auto gm_bypass = (m_requester && m_requester->GetGM() && m_requester->Admin() >= bypass_status);
|
||||
|
||||
if (m_members.size() > m_max_players)
|
||||
{
|
||||
// members were sorted at start, truncate after conflict checks to act like live
|
||||
m_members.resize(m_max_players);
|
||||
}
|
||||
else if (!gm_bypass && m_members.size() < m_min_players)
|
||||
{
|
||||
requirements_met = false;
|
||||
|
||||
SendLeaderMessage(Chat::System, REQUIRED_PLAYER_COUNT, {
|
||||
fmt::format_int(m_members.size()).str(),
|
||||
fmt::format_int(m_min_players).str(),
|
||||
fmt::format_int(m_max_players).str()
|
||||
});
|
||||
}
|
||||
|
||||
return requirements_met;
|
||||
}
|
||||
83
zone/expedition_request.h
Normal file
83
zone/expedition_request.h
Normal file
@ -0,0 +1,83 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* 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 EXPEDITION_REQUEST_H
|
||||
#define EXPEDITION_REQUEST_H
|
||||
|
||||
#include "expedition.h"
|
||||
#include "expedition_lockout_timer.h"
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
class Client;
|
||||
class Group;
|
||||
class MySQLRequestResult;
|
||||
class Raid;
|
||||
class ServerPacket;
|
||||
|
||||
class ExpeditionRequest
|
||||
{
|
||||
public:
|
||||
ExpeditionRequest(
|
||||
std::string expedition_name, uint32_t min_players, uint32_t max_players,
|
||||
bool disable_messages = false);
|
||||
|
||||
bool Validate(Client* requester);
|
||||
|
||||
const std::string& GetExpeditionName() const { return m_expedition_name; }
|
||||
Client* GetLeaderClient() const { return m_leader; }
|
||||
uint32_t GetLeaderID() const { return m_leader_id; }
|
||||
const std::string& GetLeaderName() const { return m_leader_name; }
|
||||
const std::string& GetNotAllAddedMessage() const { return m_not_all_added_msg; }
|
||||
uint32_t GetMinPlayers() const { return m_min_players; }
|
||||
uint32_t GetMaxPlayers() const { return m_max_players; }
|
||||
std::vector<ExpeditionMember> GetMembers() const { return m_members; }
|
||||
std::unordered_map<std::string, ExpeditionLockoutTimer> GetLockouts() const { return m_lockouts; }
|
||||
|
||||
private:
|
||||
bool CanMembersJoin(const std::vector<std::string>& member_names);
|
||||
bool CanRaidRequest(Raid* raid);
|
||||
bool CanGroupRequest(Group* group);
|
||||
bool CheckMembersForConflicts(const std::vector<std::string>& member_names);
|
||||
std::string GetGroupLeaderName(uint32_t group_id);
|
||||
bool IsPlayerCountValidated();
|
||||
bool LoadLeaderLockouts();
|
||||
void SendLeaderMemberInExpedition(const std::string& member_name, bool is_solo);
|
||||
void SendLeaderMemberReplayLockout(const std::string& member_name, const ExpeditionLockoutTimer& lockout, bool is_solo);
|
||||
void SendLeaderMemberEventLockout(const std::string& member_name, const ExpeditionLockoutTimer& lockout);
|
||||
void SendLeaderMessage(uint16_t chat_type, uint32_t string_id, const std::initializer_list<std::string>& args = {});
|
||||
|
||||
Client* m_requester = nullptr;
|
||||
Client* m_leader = nullptr;
|
||||
uint32_t m_leader_id = 0;
|
||||
uint32_t m_min_players = 0;
|
||||
uint32_t m_max_players = 0;
|
||||
bool m_check_event_lockouts = true;
|
||||
bool m_disable_messages = false;
|
||||
std::string m_expedition_name;
|
||||
std::string m_leader_name;
|
||||
std::string m_not_all_added_msg;
|
||||
std::vector<ExpeditionMember> m_members;
|
||||
std::unordered_map<std::string, ExpeditionLockoutTimer> m_lockouts;
|
||||
};
|
||||
|
||||
#endif
|
||||
148
zone/groups.cpp
148
zone/groups.cpp
@ -18,6 +18,7 @@
|
||||
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "expedition.h"
|
||||
#include "masterentity.h"
|
||||
#include "npc_ai.h"
|
||||
#include "../common/packet_functions.h"
|
||||
@ -58,8 +59,12 @@ Group::Group(uint32 gid)
|
||||
}
|
||||
|
||||
if(gid != 0) {
|
||||
if(!LearnMembers())
|
||||
if(!LearnMembers()) {
|
||||
SetID(0);
|
||||
}
|
||||
if(GetLeader() != nullptr) {
|
||||
SetOldLeaderName(GetLeaderName());
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < MAX_MARKED_NPCS; ++i)
|
||||
MarkedNPCs[i] = 0;
|
||||
@ -77,6 +82,8 @@ Group::Group(Mob* leader)
|
||||
members[0] = leader;
|
||||
leader->SetGrouped(true);
|
||||
SetLeader(leader);
|
||||
SetOldLeaderName(leader->GetName());
|
||||
Log(Logs::Detail, Logs::Group, "Group:Group() Setting OldLeader to: %s and Leader to: %s", GetOldLeaderName(), leader->GetName());
|
||||
AssistTargetID = 0;
|
||||
TankTargetID = 0;
|
||||
PullerTargetID = 0;
|
||||
@ -603,39 +610,61 @@ void Group::SendGroupJoinOOZ(Mob* NewMember) {
|
||||
|
||||
}
|
||||
|
||||
bool Group::DelMemberOOZ(const char *Name) {
|
||||
bool Group::DelMemberOOZ(const char *Name, bool checkleader) {
|
||||
|
||||
if(!Name) return false;
|
||||
if (!Name) return false;
|
||||
|
||||
bool removed = false;
|
||||
// If a member out of zone has disbanded, clear out their name.
|
||||
//
|
||||
for(unsigned int i = 0; i < MAX_GROUP_MEMBERS; i++) {
|
||||
if(!strcasecmp(Name, membername[i]))
|
||||
for (unsigned int i = 0; i < MAX_GROUP_MEMBERS; i++) {
|
||||
if (!strcasecmp(Name, membername[i])) {
|
||||
// This shouldn't be called if the member is in this zone.
|
||||
if(!members[i]) {
|
||||
if(!strncmp(GetLeaderName(), Name, 64))
|
||||
{
|
||||
if (!members[i]) {
|
||||
if (!strncmp(GetLeaderName(), Name, 64)) {
|
||||
//TODO: Transfer leadership if leader disbands OOZ.
|
||||
UpdateGroupAAs();
|
||||
}
|
||||
|
||||
memset(membername[i], 0, 64);
|
||||
MemberRoles[i] = 0;
|
||||
if(GroupCount() < 3)
|
||||
{
|
||||
if (GroupCount() < 3) {
|
||||
UnDelegateMarkNPC(NPCMarkerName.c_str());
|
||||
if (GetLeader() && GetLeader()->IsClient() && GetLeader()->CastToClient()->ClientVersion() < EQ::versions::ClientVersion::SoD) {
|
||||
UnDelegateMainAssist(MainAssistName.c_str());
|
||||
if (GetLeader() && GetLeader()->IsClient() &&
|
||||
GetLeader()->CastToClient()->ClientVersion() < EQ::versions::ClientVersion::SoD) {
|
||||
UnDelegateMainAssist(MainAssistName.c_str());
|
||||
}
|
||||
ClearAllNPCMarks();
|
||||
}
|
||||
if (Name == mentoree_name)
|
||||
if (Name == mentoree_name) {
|
||||
ClearGroupMentor();
|
||||
return true;
|
||||
}
|
||||
|
||||
memset(membername[i], 0, 64);
|
||||
MemberRoles[i] = 0;
|
||||
removed = true;
|
||||
Log(Logs::Detail, Logs::Group, "DelMemberOOZ: Removed Member: %s", Name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
if (GroupCount() < 2) {
|
||||
DisbandGroup();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (checkleader) {
|
||||
Log(Logs::Detail, Logs::Group, "DelMemberOOZ: Checking leader...");
|
||||
if (strcmp(GetOldLeaderName(), Name) == 0 && GroupCount() >= 2) {
|
||||
for (uint32 nl = 0; nl < MAX_GROUP_MEMBERS; nl++) {
|
||||
if (members[nl]) {
|
||||
if (members[nl]->IsClient()) {
|
||||
ChangeLeader(members[nl]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
bool Group::DelMember(Mob* oldmember, bool ignoresender)
|
||||
@ -645,16 +674,6 @@ bool Group::DelMember(Mob* oldmember, bool ignoresender)
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: fix this shit
|
||||
// okay, so there is code below that tries to handle this. It does not.
|
||||
// So instead of figuring it out now, lets just disband the group so the client doesn't
|
||||
// sit there with a broken group and there isn't any group leader shuffling going on
|
||||
// since the code below doesn't work.
|
||||
if (oldmember == GetLeader()) {
|
||||
DisbandGroup();
|
||||
return true;
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < MAX_GROUP_MEMBERS; i++)
|
||||
{
|
||||
if (members[i] == oldmember)
|
||||
@ -663,44 +682,36 @@ bool Group::DelMember(Mob* oldmember, bool ignoresender)
|
||||
membername[i][0] = '\0';
|
||||
memset(membername[i],0,64);
|
||||
MemberRoles[i] = 0;
|
||||
Log(Logs::Detail, Logs::Group, "DelMember: Removed Member: %s", oldmember->GetCleanName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* This may seem pointless but the case above does not cover the following situation:
|
||||
* Group has Leader a, member b, member c
|
||||
* b and c are out of zone
|
||||
* a disconnects/quits
|
||||
* b or c zone back in and disconnects/quits
|
||||
* a is still "leader" from GetLeader()'s perspective and will crash the zone when we DelMember(b)
|
||||
* Ultimately we should think up a better solution to this.
|
||||
*/
|
||||
if(oldmember == GetLeader())
|
||||
if(GroupCount() < 2)
|
||||
{
|
||||
SetLeader(nullptr);
|
||||
DisbandGroup();
|
||||
return true;
|
||||
}
|
||||
|
||||
//handle leader quitting group gracefully
|
||||
if (oldmember == GetLeader() && GroupCount() >= 2)
|
||||
// If the leader has quit and we have 2 or more players left in group, we want to first check the zone the old leader was in for a new leader.
|
||||
// If a suitable replacement cannot be found, we need to go out of zone. If checkleader remains true after this method completes, another
|
||||
// loop will be run in DelMemberOOZ.
|
||||
bool checkleader = true;
|
||||
if (strcmp(GetOldLeaderName(),oldmember->GetCleanName()) == 0 && GroupCount() >= 2)
|
||||
{
|
||||
for(uint32 nl = 0; nl < MAX_GROUP_MEMBERS; nl++)
|
||||
{
|
||||
if(members[nl])
|
||||
if(members[nl])
|
||||
{
|
||||
if (members[nl]->IsClient())
|
||||
{
|
||||
ChangeLeader(members[nl]);
|
||||
checkleader = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!GetLeaderName())
|
||||
{
|
||||
DisbandGroup();
|
||||
return true;
|
||||
}
|
||||
|
||||
auto pack = new ServerPacket(ServerOP_GroupLeave, sizeof(ServerGroupLeave_Struct));
|
||||
ServerGroupLeave_Struct* gl = (ServerGroupLeave_Struct*)pack->pBuffer;
|
||||
@ -708,6 +719,7 @@ bool Group::DelMember(Mob* oldmember, bool ignoresender)
|
||||
gl->zoneid = zone->GetZoneID();
|
||||
gl->instance_id = zone->GetInstanceID();
|
||||
strcpy(gl->member_name, oldmember->GetCleanName());
|
||||
gl->checkleader = checkleader;
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
|
||||
@ -799,6 +811,7 @@ bool Group::DelMember(Mob* oldmember, bool ignoresender)
|
||||
Bot::UpdateGroupCastingRoles(this);
|
||||
#endif
|
||||
|
||||
safe_delete(outapp);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2329,17 +2342,16 @@ void Group::ChangeLeader(Mob* newleader)
|
||||
// this changes the current group leader, notifies other members, and updates leadship AA
|
||||
|
||||
// if the new leader is invalid, do nothing
|
||||
if (!newleader || !newleader->IsClient())
|
||||
if (!newleader) {
|
||||
return;
|
||||
|
||||
Mob* oldleader = GetLeader();
|
||||
}
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct));
|
||||
GroupJoin_Struct* gu = (GroupJoin_Struct*) outapp->pBuffer;
|
||||
gu->action = groupActMakeLeader;
|
||||
|
||||
strcpy(gu->membername, newleader->GetName());
|
||||
strcpy(gu->yourname, oldleader->GetName());
|
||||
strcpy(gu->yourname, GetOldLeaderName());
|
||||
SetLeader(newleader);
|
||||
database.SetGroupLeaderName(GetID(), newleader->GetName());
|
||||
UpdateGroupAAs();
|
||||
@ -2351,9 +2363,22 @@ void Group::ChangeLeader(Mob* newleader)
|
||||
members[i]->CastToClient()->SendGroupLeaderChangePacket(newleader->GetName());
|
||||
|
||||
members[i]->CastToClient()->QueuePacket(outapp);
|
||||
Log(Logs::Detail, Logs::Group, "ChangeLeader(): Local leader update packet sent to: %s .", members[i]->GetName());
|
||||
}
|
||||
}
|
||||
safe_delete(outapp);
|
||||
|
||||
Log(Logs::Detail, Logs::Group, "ChangeLeader(): Old Leader is: %s New leader is: %s", GetOldLeaderName(), newleader->GetName());
|
||||
|
||||
ServerPacket* pack = new ServerPacket(ServerOP_ChangeGroupLeader, sizeof(ServerGroupLeader_Struct));
|
||||
ServerGroupLeader_Struct* fgu = (ServerGroupLeader_Struct*)pack->pBuffer;
|
||||
fgu->zoneid = zone->GetZoneID();
|
||||
fgu->gid = GetID();
|
||||
strcpy(fgu->leader_name, newleader->GetName());
|
||||
strcpy(fgu->oldleader_name, GetOldLeaderName());
|
||||
worldserver.SendPacket(pack);
|
||||
|
||||
SetOldLeaderName(newleader->GetName());
|
||||
}
|
||||
|
||||
const char *Group::GetClientNameByIndex(uint8 index)
|
||||
@ -2503,3 +2528,24 @@ void Group::QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_r
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Group::DoesAnyMemberHaveExpeditionLockout(
|
||||
const std::string& expedition_name, const std::string& event_name, int max_check_count)
|
||||
{
|
||||
if (max_check_count <= 0)
|
||||
{
|
||||
max_check_count = MAX_GROUP_MEMBERS;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_GROUP_MEMBERS && i < max_check_count; ++i)
|
||||
{
|
||||
if (membername[i][0])
|
||||
{
|
||||
if (Expedition::HasLockoutByCharacterName(membername[i], expedition_name, event_name))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -37,6 +37,8 @@ public:
|
||||
GroupIDConsumer() { id = 0; }
|
||||
GroupIDConsumer(uint32 gid) { id = gid; }
|
||||
inline const uint32 GetID() const { return id; }
|
||||
void SetOldLeaderName(const char* oldleader) { strcpy(oldleadername, oldleader); }
|
||||
char* GetOldLeaderName() { return oldleadername; }
|
||||
|
||||
protected:
|
||||
friend class EntityList;
|
||||
@ -44,6 +46,7 @@ protected:
|
||||
inline void SetID(uint32 set_id) { id = set_id; }
|
||||
private:
|
||||
uint32 id;
|
||||
char oldleadername[64]; // Keeps the previous leader name, so when the entity is destroyed we can still transfer leadership.
|
||||
};
|
||||
|
||||
class Group : public GroupIDConsumer {
|
||||
@ -58,6 +61,7 @@ public:
|
||||
void SendLeadershipAAUpdate();
|
||||
void SendWorldGroup(uint32 zone_id,Mob* zoningmember);
|
||||
bool DelMemberOOZ(const char *Name);
|
||||
bool DelMemberOOZ(const char *Name, bool checkleader);
|
||||
bool DelMember(Mob* oldmember,bool ignoresender = false);
|
||||
void DisbandGroup(bool joinraid = false);
|
||||
void GetMemberList(std::list<Mob*>& member_list, bool clear_list = true);
|
||||
@ -153,6 +157,8 @@ public:
|
||||
inline int GetMentorPercent() { return mentor_percent; }
|
||||
inline Client *GetMentoree() { return mentoree; }
|
||||
|
||||
bool DoesAnyMemberHaveExpeditionLockout(const std::string& expedition_name, const std::string& event_name, int max_check_count = 0);
|
||||
|
||||
Mob* members[MAX_GROUP_MEMBERS];
|
||||
char membername[MAX_GROUP_MEMBERS][64];
|
||||
uint8 MemberRoles[MAX_GROUP_MEMBERS];
|
||||
|
||||
@ -1154,9 +1154,34 @@ bool Client::AutoPutLootInInventory(EQ::ItemInstance& inst, bool try_worn, bool
|
||||
}
|
||||
}
|
||||
}
|
||||
if( i == EQ::invslot::slotPrimary && m_inv[EQ::invslot::slotSecondary] ) {
|
||||
uint8 instrument = m_inv[EQ::invslot::slotSecondary]->GetItem()->ItemType;
|
||||
if(
|
||||
instrument == EQ::item::ItemTypeWindInstrument ||
|
||||
instrument == EQ::item::ItemTypeStringedInstrument ||
|
||||
instrument == EQ::item::ItemTypeBrassInstrument ||
|
||||
instrument == EQ::item::ItemTypePercussionInstrument
|
||||
) {
|
||||
LogInventory("Cannot equip a primary item with [{}] already in the secondary.", m_inv[EQ::invslot::slotSecondary]->GetItem()->Name);
|
||||
continue; // Do not auto-equip Primary when instrument is in Secondary
|
||||
}
|
||||
}
|
||||
if (i == EQ::invslot::slotSecondary && m_inv[EQ::invslot::slotPrimary]) { // check to see if primary slot is a two hander
|
||||
if (m_inv[EQ::invslot::slotPrimary]->GetItem()->IsType2HWeapon())
|
||||
uint8 instrument = inst.GetItem()->ItemType;
|
||||
if(
|
||||
instrument == EQ::item::ItemTypeWindInstrument ||
|
||||
instrument == EQ::item::ItemTypeStringedInstrument ||
|
||||
instrument == EQ::item::ItemTypeBrassInstrument ||
|
||||
instrument == EQ::item::ItemTypePercussionInstrument
|
||||
) {
|
||||
LogInventory("Cannot equip a secondary instrument with [{}] already in the primary.", m_inv[EQ::invslot::slotPrimary]->GetItem()->Name);
|
||||
continue; // Do not auto-equip instrument in Secondary when Primary is equipped.
|
||||
}
|
||||
|
||||
uint8 use = m_inv[EQ::invslot::slotPrimary]->GetItem()->ItemType;
|
||||
if(use == EQ::item::ItemType2HSlash || use == EQ::item::ItemType2HBlunt || use == EQ::item::ItemType2HPiercing) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (i == EQ::invslot::slotSecondary && inst.IsWeapon() && !CanThisClassDualWield()) {
|
||||
continue;
|
||||
@ -1169,7 +1194,6 @@ bool Client::AutoPutLootInInventory(EQ::ItemInstance& inst, bool try_worn, bool
|
||||
if (worn_slot_material != EQ::textures::materialInvalid) {
|
||||
SendWearChange(worn_slot_material);
|
||||
}
|
||||
|
||||
parse->EventItem(EVENT_EQUIP_ITEM, this, &inst, nullptr, "", i);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -4,7 +4,11 @@
|
||||
#include <luabind/luabind.hpp>
|
||||
|
||||
#include "client.h"
|
||||
#include "dynamiczone.h"
|
||||
#include "expedition_lockout_timer.h"
|
||||
#include "expedition_request.h"
|
||||
#include "lua_client.h"
|
||||
#include "lua_expedition.h"
|
||||
#include "lua_npc.h"
|
||||
#include "lua_item.h"
|
||||
#include "lua_iteminst.h"
|
||||
@ -130,6 +134,16 @@ void Lua_Client::SetBaseGender(int v) {
|
||||
self->SetBaseGender(v);
|
||||
}
|
||||
|
||||
int Lua_Client::GetClassBitmask() {
|
||||
Lua_Safe_Call_Int();
|
||||
return GetPlayerClassBit(self->GetClass());
|
||||
}
|
||||
|
||||
int Lua_Client::GetRaceBitmask() {
|
||||
Lua_Safe_Call_Int();
|
||||
return GetPlayerRaceBit(self->GetBaseRace());
|
||||
}
|
||||
|
||||
int Lua_Client::GetBaseFace() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetBaseFace();
|
||||
@ -325,6 +339,21 @@ uint32 Lua_Client::GetBindZoneID(int index) {
|
||||
return self->GetBindZoneID(index);
|
||||
}
|
||||
|
||||
float Lua_Client::GetTargetRingX() {
|
||||
Lua_Safe_Call_Real();
|
||||
return self->GetTargetRingX();
|
||||
}
|
||||
|
||||
float Lua_Client::GetTargetRingY() {
|
||||
Lua_Safe_Call_Real();
|
||||
return self->GetTargetRingY();
|
||||
}
|
||||
|
||||
float Lua_Client::GetTargetRingZ() {
|
||||
Lua_Safe_Call_Real();
|
||||
return self->GetTargetRingZ();
|
||||
}
|
||||
|
||||
void Lua_Client::MovePC(int zone, float x, float y, float z, float heading) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->MovePC(zone, x, y, z, heading);
|
||||
@ -605,6 +634,132 @@ int Lua_Client::MemmedCount() {
|
||||
return self->MemmedCount();
|
||||
}
|
||||
|
||||
luabind::object Lua_Client::GetLearnableDisciplines(lua_State* L) {
|
||||
auto lua_table = luabind::newtable(L);
|
||||
if (d_) {
|
||||
auto self = reinterpret_cast<NativeType*>(d_);
|
||||
auto learnable_disciplines = self->GetLearnableDisciplines();
|
||||
int index = 0;
|
||||
for (auto spell_id : learnable_disciplines) {
|
||||
lua_table[index] = spell_id;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return lua_table;
|
||||
}
|
||||
|
||||
luabind::object Lua_Client::GetLearnableDisciplines(lua_State* L, uint8 min_level) {
|
||||
auto lua_table = luabind::newtable(L);
|
||||
if (d_) {
|
||||
auto self = reinterpret_cast<NativeType*>(d_);
|
||||
auto learnable_disciplines = self->GetLearnableDisciplines(min_level);
|
||||
int index = 0;
|
||||
for (auto spell_id : learnable_disciplines) {
|
||||
lua_table[index] = spell_id;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return lua_table;
|
||||
}
|
||||
|
||||
luabind::object Lua_Client::GetLearnableDisciplines(lua_State* L, uint8 min_level, uint8 max_level) {
|
||||
auto lua_table = luabind::newtable(L);
|
||||
if (d_) {
|
||||
auto self = reinterpret_cast<NativeType*>(d_);
|
||||
auto learnable_disciplines = self->GetLearnableDisciplines(min_level, max_level);
|
||||
int index = 0;
|
||||
for (auto spell_id : learnable_disciplines) {
|
||||
lua_table[index] = spell_id;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return lua_table;
|
||||
}
|
||||
|
||||
luabind::object Lua_Client::GetLearnedDisciplines(lua_State* L) {
|
||||
auto lua_table = luabind::newtable(L);
|
||||
if (d_) {
|
||||
auto self = reinterpret_cast<NativeType*>(d_);
|
||||
auto learned_disciplines = self->GetLearnedDisciplines();
|
||||
int index = 0;
|
||||
for (auto spell_id : learned_disciplines) {
|
||||
lua_table[index] = spell_id;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return lua_table;
|
||||
}
|
||||
|
||||
luabind::object Lua_Client::GetMemmedSpells(lua_State* L) {
|
||||
auto lua_table = luabind::newtable(L);
|
||||
if (d_) {
|
||||
auto self = reinterpret_cast<NativeType*>(d_);
|
||||
auto memmed_spells = self->GetMemmedSpells();
|
||||
int index = 0;
|
||||
for (auto spell_id : memmed_spells) {
|
||||
lua_table[index] = spell_id;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return lua_table;
|
||||
}
|
||||
|
||||
luabind::object Lua_Client::GetScribeableSpells(lua_State* L) {
|
||||
auto lua_table = luabind::newtable(L);
|
||||
if (d_) {
|
||||
auto self = reinterpret_cast<NativeType*>(d_);
|
||||
auto scribeable_spells = self->GetScribeableSpells();
|
||||
int index = 0;
|
||||
for (auto spell_id : scribeable_spells) {
|
||||
lua_table[index] = spell_id;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return lua_table;
|
||||
}
|
||||
|
||||
luabind::object Lua_Client::GetScribeableSpells(lua_State* L, uint8 min_level) {
|
||||
auto lua_table = luabind::newtable(L);
|
||||
if (d_) {
|
||||
auto self = reinterpret_cast<NativeType*>(d_);
|
||||
auto scribeable_spells = self->GetScribeableSpells(min_level);
|
||||
int index = 0;
|
||||
for (auto spell_id : scribeable_spells) {
|
||||
lua_table[index] = spell_id;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return lua_table;
|
||||
}
|
||||
|
||||
luabind::object Lua_Client::GetScribeableSpells(lua_State* L, uint8 min_level, uint8 max_level) {
|
||||
auto lua_table = luabind::newtable(L);
|
||||
if (d_) {
|
||||
auto self = reinterpret_cast<NativeType*>(d_);
|
||||
auto scribeable_spells = self->GetScribeableSpells(min_level, max_level);
|
||||
int index = 0;
|
||||
for (auto spell_id : scribeable_spells) {
|
||||
lua_table[index] = spell_id;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return lua_table;
|
||||
}
|
||||
|
||||
luabind::object Lua_Client::GetScribedSpells(lua_State* L) {
|
||||
auto lua_table = luabind::newtable(L);
|
||||
if (d_) {
|
||||
auto self = reinterpret_cast<NativeType*>(d_);
|
||||
auto scribed_spells = self->GetScribedSpells();
|
||||
int index = 0;
|
||||
for (auto spell_id : scribed_spells) {
|
||||
lua_table[index] = spell_id;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return lua_table;
|
||||
}
|
||||
|
||||
void Lua_Client::ScribeSpell(int spell_id, int slot) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->ScribeSpell(spell_id, slot);
|
||||
@ -900,6 +1055,11 @@ bool Lua_Client::UseDiscipline(int spell_id, int target_id) {
|
||||
return self->UseDiscipline(spell_id, target_id);
|
||||
}
|
||||
|
||||
bool Lua_Client::HasDisciplineLearned(uint16 spell_id) {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->HasDisciplineLearned(spell_id);
|
||||
}
|
||||
|
||||
int Lua_Client::GetCharacterFactionLevel(int faction_id) {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetCharacterFactionLevel(faction_id);
|
||||
@ -1040,6 +1200,16 @@ void Lua_Client::AddCrystals(uint32 radiant, uint32 ebon) {
|
||||
self->AddCrystals(radiant, ebon);
|
||||
}
|
||||
|
||||
void Lua_Client::SetEbonCrystals(uint32 value) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetEbonCrystals(value);
|
||||
}
|
||||
|
||||
void Lua_Client::SetRadiantCrystals(uint32 value) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetRadiantCrystals(value);
|
||||
}
|
||||
|
||||
uint32 Lua_Client::GetPVPPoints() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetPVPPoints();
|
||||
@ -1160,6 +1330,11 @@ int Lua_Client::GetNextAvailableSpellBookSlot() {
|
||||
return self->GetNextAvailableSpellBookSlot();
|
||||
}
|
||||
|
||||
uint32 Lua_Client::GetSpellIDByBookSlot(int slot_id) {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetSpellIDByBookSlot(slot_id);
|
||||
}
|
||||
|
||||
int Lua_Client::GetNextAvailableSpellBookSlot(int start) {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetNextAvailableSpellBookSlot(start);
|
||||
@ -1629,7 +1804,249 @@ int Lua_Client::GetClientMaxLevel() {
|
||||
return self->GetClientMaxLevel();
|
||||
}
|
||||
|
||||
DynamicZoneLocation GetDynamicZoneLocationFromTable(const luabind::object& lua_table)
|
||||
{
|
||||
DynamicZoneLocation zone_location;
|
||||
|
||||
if (luabind::type(lua_table) == LUA_TTABLE)
|
||||
{
|
||||
luabind::object lua_zone = lua_table["zone"];
|
||||
|
||||
// default invalid/missing args to 0
|
||||
uint32_t zone_id = 0;
|
||||
if (luabind::type(lua_zone) == LUA_TSTRING)
|
||||
{
|
||||
zone_id = ZoneID(luabind::object_cast<std::string>(lua_zone));
|
||||
}
|
||||
else if (luabind::type(lua_zone) == LUA_TNUMBER)
|
||||
{
|
||||
zone_id = luabind::object_cast<uint32_t>(lua_zone);
|
||||
}
|
||||
|
||||
float x = (luabind::type(lua_table["x"]) != LUA_TNIL) ? luabind::object_cast<float>(lua_table["x"]) : 0.0f;
|
||||
float y = (luabind::type(lua_table["y"]) != LUA_TNIL) ? luabind::object_cast<float>(lua_table["y"]) : 0.0f;
|
||||
float z = (luabind::type(lua_table["z"]) != LUA_TNIL) ? luabind::object_cast<float>(lua_table["z"]) : 0.0f;
|
||||
float h = (luabind::type(lua_table["h"]) != LUA_TNIL) ? luabind::object_cast<float>(lua_table["h"]) : 0.0f;
|
||||
|
||||
zone_location = { zone_id, x, y, z, h };
|
||||
}
|
||||
|
||||
return zone_location;
|
||||
}
|
||||
|
||||
Lua_Expedition Lua_Client::CreateExpedition(luabind::object expedition_table) {
|
||||
Lua_Safe_Call_Class(Lua_Expedition);
|
||||
|
||||
if (luabind::type(expedition_table) != LUA_TTABLE)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// luabind will catch thrown cast_failed exceptions for invalid/missing args
|
||||
luabind::object instance_info = expedition_table["instance"];
|
||||
luabind::object zone = instance_info["zone"];
|
||||
|
||||
uint32_t zone_id = 0;
|
||||
if (luabind::type(zone) == LUA_TSTRING)
|
||||
{
|
||||
zone_id = ZoneID(luabind::object_cast<std::string>(zone));
|
||||
}
|
||||
else if (luabind::type(zone) == LUA_TNUMBER)
|
||||
{
|
||||
zone_id = luabind::object_cast<uint32_t>(zone);
|
||||
}
|
||||
|
||||
uint32_t zone_version = luabind::object_cast<uint32_t>(instance_info["version"]);
|
||||
uint32_t zone_duration = luabind::object_cast<uint32_t>(instance_info["duration"]);
|
||||
|
||||
DynamicZone dz{ zone_id, zone_version, zone_duration, DynamicZoneType::Expedition };
|
||||
|
||||
// the dz_info table supports optional hash entries for 'compass', 'safereturn', and 'zonein' data
|
||||
if (luabind::type(expedition_table["compass"]) == LUA_TTABLE)
|
||||
{
|
||||
auto compass_loc = GetDynamicZoneLocationFromTable(expedition_table["compass"]);
|
||||
dz.SetCompass(compass_loc);
|
||||
}
|
||||
|
||||
if (luabind::type(expedition_table["safereturn"]) == LUA_TTABLE)
|
||||
{
|
||||
auto safereturn_loc = GetDynamicZoneLocationFromTable(expedition_table["safereturn"]);
|
||||
dz.SetSafeReturn(safereturn_loc);
|
||||
}
|
||||
|
||||
if (luabind::type(expedition_table["zonein"]) == LUA_TTABLE)
|
||||
{
|
||||
auto zonein_loc = GetDynamicZoneLocationFromTable(expedition_table["zonein"]);
|
||||
dz.SetZoneInLocation(zonein_loc);
|
||||
}
|
||||
|
||||
luabind::object expedition_info = expedition_table["expedition"];
|
||||
|
||||
std::string expedition_name = luabind::object_cast<std::string>(expedition_info["name"]);
|
||||
uint32_t min_players = luabind::object_cast<uint32_t>(expedition_info["min_players"]);
|
||||
uint32_t max_players = luabind::object_cast<uint32_t>(expedition_info["max_players"]);
|
||||
bool disable_messages = false;
|
||||
|
||||
if (luabind::type(expedition_info["disable_messages"]) == LUA_TBOOLEAN)
|
||||
{
|
||||
disable_messages = luabind::object_cast<bool>(expedition_info["disable_messages"]);
|
||||
}
|
||||
|
||||
ExpeditionRequest request{ expedition_name, min_players, max_players, disable_messages };
|
||||
|
||||
return self->CreateExpedition(dz, request);
|
||||
}
|
||||
|
||||
Lua_Expedition Lua_Client::CreateExpedition(std::string zone_name, uint32 version, uint32 duration, std::string expedition_name, uint32 min_players, uint32 max_players) {
|
||||
Lua_Safe_Call_Class(Lua_Expedition);
|
||||
return self->CreateExpedition(zone_name, version, duration, expedition_name, min_players, max_players);
|
||||
}
|
||||
|
||||
Lua_Expedition Lua_Client::CreateExpedition(std::string zone_name, uint32 version, uint32 duration, std::string expedition_name, uint32 min_players, uint32 max_players, bool disable_messages) {
|
||||
Lua_Safe_Call_Class(Lua_Expedition);
|
||||
return self->CreateExpedition(zone_name, version, duration, expedition_name, min_players, max_players, disable_messages);
|
||||
}
|
||||
|
||||
Lua_Expedition Lua_Client::GetExpedition() {
|
||||
Lua_Safe_Call_Class(Lua_Expedition);
|
||||
return self->GetExpedition();
|
||||
}
|
||||
|
||||
luabind::object Lua_Client::GetExpeditionLockouts(lua_State* L)
|
||||
{
|
||||
auto lua_table = luabind::newtable(L);
|
||||
if (d_)
|
||||
{
|
||||
auto self = reinterpret_cast<NativeType*>(d_);
|
||||
auto lockouts = self->GetExpeditionLockouts();
|
||||
|
||||
for (const auto& lockout : lockouts)
|
||||
{
|
||||
auto lockout_table = lua_table[lockout.GetExpeditionName()];
|
||||
if (luabind::type(lockout_table) != LUA_TTABLE)
|
||||
{
|
||||
lockout_table = luabind::newtable(L);
|
||||
}
|
||||
lockout_table[lockout.GetEventName()] = lockout.GetSecondsRemaining();
|
||||
}
|
||||
}
|
||||
return lua_table;
|
||||
}
|
||||
|
||||
luabind::object Lua_Client::GetExpeditionLockouts(lua_State* L, std::string expedition_name)
|
||||
{
|
||||
auto lua_table = luabind::newtable(L);
|
||||
if (d_)
|
||||
{
|
||||
auto self = reinterpret_cast<NativeType*>(d_);
|
||||
auto lockouts = self->GetExpeditionLockouts();
|
||||
|
||||
for (const auto& lockout : lockouts)
|
||||
{
|
||||
if (lockout.GetExpeditionName() == expedition_name)
|
||||
{
|
||||
lua_table[lockout.GetEventName()] = lockout.GetSecondsRemaining();
|
||||
}
|
||||
}
|
||||
}
|
||||
return lua_table;
|
||||
}
|
||||
|
||||
std::string Lua_Client::GetLockoutExpeditionUUID(std::string expedition_name, std::string event_name) {
|
||||
Lua_Safe_Call_String();
|
||||
std::string uuid;
|
||||
auto lockout = self->GetExpeditionLockout(expedition_name, event_name);
|
||||
if (lockout)
|
||||
{
|
||||
uuid = lockout->GetExpeditionUUID();
|
||||
}
|
||||
return uuid;
|
||||
}
|
||||
|
||||
void Lua_Client::AddExpeditionLockout(std::string expedition_name, std::string event_name, uint32 seconds) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->AddNewExpeditionLockout(expedition_name, event_name, seconds);
|
||||
}
|
||||
|
||||
void Lua_Client::AddExpeditionLockout(std::string expedition_name, std::string event_name, uint32 seconds, std::string uuid) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->AddNewExpeditionLockout(expedition_name, event_name, seconds, uuid);
|
||||
}
|
||||
|
||||
void Lua_Client::AddExpeditionLockoutDuration(std::string expedition_name, std::string event_name, int seconds) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->AddExpeditionLockoutDuration(expedition_name, event_name, seconds, {}, true);
|
||||
}
|
||||
|
||||
void Lua_Client::AddExpeditionLockoutDuration(std::string expedition_name, std::string event_name, int seconds, std::string uuid) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->AddExpeditionLockoutDuration(expedition_name, event_name, seconds, uuid, true);
|
||||
}
|
||||
|
||||
void Lua_Client::RemoveAllExpeditionLockouts() {
|
||||
Lua_Safe_Call_Void();
|
||||
self->RemoveAllExpeditionLockouts({}, true);
|
||||
}
|
||||
|
||||
void Lua_Client::RemoveAllExpeditionLockouts(std::string expedition_name) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->RemoveAllExpeditionLockouts(expedition_name, true);
|
||||
}
|
||||
|
||||
void Lua_Client::RemoveExpeditionLockout(std::string expedition_name, std::string event_name) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->RemoveExpeditionLockout(expedition_name, event_name, true);
|
||||
}
|
||||
|
||||
bool Lua_Client::HasExpeditionLockout(std::string expedition_name, std::string event_name) {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->HasExpeditionLockout(expedition_name, event_name);
|
||||
}
|
||||
|
||||
void Lua_Client::MovePCDynamicZone(uint32 zone_id) {
|
||||
Lua_Safe_Call_Void();
|
||||
return self->MovePCDynamicZone(zone_id);
|
||||
}
|
||||
|
||||
void Lua_Client::MovePCDynamicZone(uint32 zone_id, int zone_version) {
|
||||
Lua_Safe_Call_Void();
|
||||
return self->MovePCDynamicZone(zone_id, zone_version);
|
||||
}
|
||||
|
||||
void Lua_Client::MovePCDynamicZone(uint32 zone_id, int zone_version, bool msg_if_invalid) {
|
||||
Lua_Safe_Call_Void();
|
||||
return self->MovePCDynamicZone(zone_id, zone_version, msg_if_invalid);
|
||||
}
|
||||
|
||||
void Lua_Client::MovePCDynamicZone(std::string zone_name) {
|
||||
Lua_Safe_Call_Void();
|
||||
return self->MovePCDynamicZone(zone_name);
|
||||
}
|
||||
|
||||
void Lua_Client::MovePCDynamicZone(std::string zone_name, int zone_version) {
|
||||
Lua_Safe_Call_Void();
|
||||
return self->MovePCDynamicZone(zone_name, zone_version);
|
||||
}
|
||||
|
||||
void Lua_Client::MovePCDynamicZone(std::string zone_name, int zone_version, bool msg_if_invalid) {
|
||||
Lua_Safe_Call_Void();
|
||||
return self->MovePCDynamicZone(zone_name, zone_version, msg_if_invalid);
|
||||
}
|
||||
|
||||
void Lua_Client::Fling(float value, float target_x, float target_y, float target_z) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->Fling(value, target_x, target_y, target_z);
|
||||
}
|
||||
|
||||
void Lua_Client::Fling(float value, float target_x, float target_y, float target_z, bool ignore_los) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->Fling(value, target_x, target_y, target_z, ignore_los);
|
||||
}
|
||||
|
||||
void Lua_Client::Fling(float value, float target_x, float target_y, float target_z, bool ignore_los, bool clipping) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->Fling(value, target_x, target_y, target_z, ignore_los, clipping);
|
||||
}
|
||||
|
||||
luabind::scope lua_register_client() {
|
||||
return luabind::class_<Lua_Client, Lua_Mob>("Client")
|
||||
@ -1657,6 +2074,8 @@ luabind::scope lua_register_client() {
|
||||
.def("SetBaseClass", (void(Lua_Client::*)(int))&Lua_Client::SetBaseClass)
|
||||
.def("SetBaseRace", (void(Lua_Client::*)(int))&Lua_Client::SetBaseRace)
|
||||
.def("SetBaseGender", (void(Lua_Client::*)(int))&Lua_Client::SetBaseGender)
|
||||
.def("GetClassBitmask", (int(Lua_Client::*)(void))&Lua_Client::GetClassBitmask)
|
||||
.def("GetRaceBitmask", (int(Lua_Client::*)(void))&Lua_Client::GetRaceBitmask)
|
||||
.def("GetBaseFace", (int(Lua_Client::*)(void))&Lua_Client::GetBaseFace)
|
||||
.def("GetLanguageSkill", (int(Lua_Client::*)(int))&Lua_Client::GetLanguageSkill)
|
||||
.def("GetLastName", (const char *(Lua_Client::*)(void))&Lua_Client::GetLastName)
|
||||
@ -1696,6 +2115,9 @@ luabind::scope lua_register_client() {
|
||||
.def("GetBindHeading", (float(Lua_Client::*)(int))&Lua_Client::GetBindHeading)
|
||||
.def("GetBindZoneID", (uint32(Lua_Client::*)(void))&Lua_Client::GetBindZoneID)
|
||||
.def("GetBindZoneID", (uint32(Lua_Client::*)(int))&Lua_Client::GetBindZoneID)
|
||||
.def("GetTargetRingX", (float(Lua_Client::*)(void))&Lua_Client::GetTargetRingX)
|
||||
.def("GetTargetRingY", (float(Lua_Client::*)(void))&Lua_Client::GetTargetRingY)
|
||||
.def("GetTargetRingZ", (float(Lua_Client::*)(void))&Lua_Client::GetTargetRingZ)
|
||||
.def("SetPrimaryWeaponOrnamentation", (void(Lua_Client::*)(uint32))&Lua_Client::SetPrimaryWeaponOrnamentation)
|
||||
.def("SetSecondaryWeaponOrnamentation", (void(Lua_Client::*)(uint32))&Lua_Client::SetSecondaryWeaponOrnamentation)
|
||||
.def("MovePC", (void(Lua_Client::*)(int,float,float,float,float))&Lua_Client::MovePC)
|
||||
@ -1754,6 +2176,15 @@ luabind::scope lua_register_client() {
|
||||
.def("UnmemSpellAll", (void(Lua_Client::*)(bool))&Lua_Client::UnmemSpellAll)
|
||||
.def("FindMemmedSpellBySlot", (uint16(Lua_Client::*)(int))&Lua_Client::FindMemmedSpellBySlot)
|
||||
.def("MemmedCount", (int(Lua_Client::*)(void))&Lua_Client::MemmedCount)
|
||||
.def("GetLearnableDisciplines", (luabind::object(Lua_Client::*)(lua_State* L))&Lua_Client::GetLearnableDisciplines)
|
||||
.def("GetLearnableDisciplines", (luabind::object(Lua_Client::*)(lua_State* L,uint8))&Lua_Client::GetLearnableDisciplines)
|
||||
.def("GetLearnableDisciplines", (luabind::object(Lua_Client::*)(lua_State* L,uint8,uint8))&Lua_Client::GetLearnableDisciplines)
|
||||
.def("GetLearnedDisciplines", (luabind::object(Lua_Client::*)(lua_State* L))&Lua_Client::GetLearnedDisciplines)
|
||||
.def("GetMemmedSpells", (luabind::object(Lua_Client::*)(lua_State* L))&Lua_Client::GetMemmedSpells)
|
||||
.def("GetScribedSpells", (luabind::object(Lua_Client::*)(lua_State* L))&Lua_Client::GetScribedSpells)
|
||||
.def("GetScribeableSpells", (luabind::object(Lua_Client::*)(lua_State* L))&Lua_Client::GetScribeableSpells)
|
||||
.def("GetScribeableSpells", (luabind::object(Lua_Client::*)(lua_State* L,uint8))&Lua_Client::GetScribeableSpells)
|
||||
.def("GetScribeableSpells", (luabind::object(Lua_Client::*)(lua_State* L,uint8,uint8))&Lua_Client::GetScribeableSpells)
|
||||
.def("ScribeSpell", (void(Lua_Client::*)(int,int))&Lua_Client::ScribeSpell)
|
||||
.def("ScribeSpell", (void(Lua_Client::*)(int,int,bool))&Lua_Client::ScribeSpell)
|
||||
.def("UnscribeSpell", (void(Lua_Client::*)(int))&Lua_Client::UnscribeSpell)
|
||||
@ -1813,6 +2244,7 @@ luabind::scope lua_register_client() {
|
||||
.def("GetDisciplineTimer", (uint32(Lua_Client::*)(uint32))&Lua_Client::GetDisciplineTimer)
|
||||
.def("ResetDisciplineTimer", (void(Lua_Client::*)(uint32))&Lua_Client::ResetDisciplineTimer)
|
||||
.def("UseDiscipline", (bool(Lua_Client::*)(int,int))&Lua_Client::UseDiscipline)
|
||||
.def("HasDisciplineLearned", (bool(Lua_Client::*)(uint16))&Lua_Client::HasDisciplineLearned)
|
||||
.def("GetCharacterFactionLevel", (int(Lua_Client::*)(int))&Lua_Client::GetCharacterFactionLevel)
|
||||
.def("SetZoneFlag", (void(Lua_Client::*)(int))&Lua_Client::SetZoneFlag)
|
||||
.def("ClearZoneFlag", (void(Lua_Client::*)(int))&Lua_Client::ClearZoneFlag)
|
||||
@ -1841,6 +2273,8 @@ luabind::scope lua_register_client() {
|
||||
.def("KeyRingCheck", (bool(Lua_Client::*)(uint32))&Lua_Client::KeyRingCheck)
|
||||
.def("AddPVPPoints", (void(Lua_Client::*)(uint32))&Lua_Client::AddPVPPoints)
|
||||
.def("AddCrystals", (void(Lua_Client::*)(uint32,uint32))&Lua_Client::AddCrystals)
|
||||
.def("SetEbonCrystals", (void(Lua_Client::*)(uint32))&Lua_Client::SetEbonCrystals)
|
||||
.def("SetRadiantCrystals", (void(Lua_Client::*)(uint32))&Lua_Client::SetRadiantCrystals)
|
||||
.def("GetPVPPoints", (uint32(Lua_Client::*)(void))&Lua_Client::GetPVPPoints)
|
||||
.def("GetRadiantCrystals", (uint32(Lua_Client::*)(void))&Lua_Client::GetRadiantCrystals)
|
||||
.def("GetEbonCrystals", (uint32(Lua_Client::*)(void))&Lua_Client::GetEbonCrystals)
|
||||
@ -1866,6 +2300,7 @@ luabind::scope lua_register_client() {
|
||||
.def("ClearCompassMark",(void(Lua_Client::*)(void))&Lua_Client::ClearCompassMark)
|
||||
.def("GetNextAvailableSpellBookSlot", (int(Lua_Client::*)(void))&Lua_Client::GetNextAvailableSpellBookSlot)
|
||||
.def("GetNextAvailableSpellBookSlot", (int(Lua_Client::*)(int))&Lua_Client::GetNextAvailableSpellBookSlot)
|
||||
.def("GetSpellIDByBookSlot", (uint32(Lua_Client::*)(int))& Lua_Client::GetSpellIDByBookSlot)
|
||||
.def("FindSpellBookSlotBySpellID", (int(Lua_Client::*)(int))&Lua_Client::FindSpellBookSlotBySpellID)
|
||||
.def("UpdateTaskActivity", (void(Lua_Client::*)(int,int,int))&Lua_Client::UpdateTaskActivity)
|
||||
.def("AssignTask", (void(Lua_Client::*)(int,int))&Lua_Client::AssignTask)
|
||||
@ -1934,7 +2369,31 @@ luabind::scope lua_register_client() {
|
||||
.def("EnableAreaRegens", &Lua_Client::EnableAreaRegens)
|
||||
.def("DisableAreaRegens", &Lua_Client::DisableAreaRegens)
|
||||
.def("SetClientMaxLevel", (void(Lua_Client::*)(int))&Lua_Client::SetClientMaxLevel)
|
||||
.def("GetClientMaxLevel", (int(Lua_Client::*)(void))&Lua_Client::GetClientMaxLevel);
|
||||
.def("GetClientMaxLevel", (int(Lua_Client::*)(void))&Lua_Client::GetClientMaxLevel)
|
||||
.def("CreateExpedition", (Lua_Expedition(Lua_Client::*)(luabind::object))&Lua_Client::CreateExpedition)
|
||||
.def("CreateExpedition", (Lua_Expedition(Lua_Client::*)(std::string, uint32, uint32, std::string, uint32, uint32))&Lua_Client::CreateExpedition)
|
||||
.def("CreateExpedition", (Lua_Expedition(Lua_Client::*)(std::string, uint32, uint32, std::string, uint32, uint32, bool))&Lua_Client::CreateExpedition)
|
||||
.def("GetExpedition", (Lua_Expedition(Lua_Client::*)(void))&Lua_Client::GetExpedition)
|
||||
.def("GetExpeditionLockouts", (luabind::object(Lua_Client::*)(lua_State* L))&Lua_Client::GetExpeditionLockouts)
|
||||
.def("GetExpeditionLockouts", (luabind::object(Lua_Client::*)(lua_State* L, std::string))&Lua_Client::GetExpeditionLockouts)
|
||||
.def("GetLockoutExpeditionUUID", (std::string(Lua_Client::*)(std::string, std::string))&Lua_Client::GetLockoutExpeditionUUID)
|
||||
.def("AddExpeditionLockout", (void(Lua_Client::*)(std::string, std::string, uint32))&Lua_Client::AddExpeditionLockout)
|
||||
.def("AddExpeditionLockout", (void(Lua_Client::*)(std::string, std::string, uint32, std::string))&Lua_Client::AddExpeditionLockout)
|
||||
.def("AddExpeditionLockoutDuration", (void(Lua_Client::*)(std::string, std::string, int))&Lua_Client::AddExpeditionLockoutDuration)
|
||||
.def("AddExpeditionLockoutDuration", (void(Lua_Client::*)(std::string, std::string, int, std::string))&Lua_Client::AddExpeditionLockoutDuration)
|
||||
.def("RemoveAllExpeditionLockouts", (void(Lua_Client::*)(void))&Lua_Client::RemoveAllExpeditionLockouts)
|
||||
.def("RemoveAllExpeditionLockouts", (void(Lua_Client::*)(std::string))&Lua_Client::RemoveAllExpeditionLockouts)
|
||||
.def("RemoveExpeditionLockout", (void(Lua_Client::*)(std::string, std::string))&Lua_Client::RemoveExpeditionLockout)
|
||||
.def("HasExpeditionLockout", (bool(Lua_Client::*)(std::string, std::string))&Lua_Client::HasExpeditionLockout)
|
||||
.def("MovePCDynamicZone", (void(Lua_Client::*)(uint32))&Lua_Client::MovePCDynamicZone)
|
||||
.def("MovePCDynamicZone", (void(Lua_Client::*)(uint32, int))&Lua_Client::MovePCDynamicZone)
|
||||
.def("MovePCDynamicZone", (void(Lua_Client::*)(uint32, int, bool))&Lua_Client::MovePCDynamicZone)
|
||||
.def("MovePCDynamicZone", (void(Lua_Client::*)(std::string))&Lua_Client::MovePCDynamicZone)
|
||||
.def("MovePCDynamicZone", (void(Lua_Client::*)(std::string, int))&Lua_Client::MovePCDynamicZone)
|
||||
.def("MovePCDynamicZone", (void(Lua_Client::*)(std::string, int, bool))&Lua_Client::MovePCDynamicZone)
|
||||
.def("Fling", (void(Lua_Client::*)(float,float,float,float))&Lua_Client::Fling)
|
||||
.def("Fling", (void(Lua_Client::*)(float,float,float,float,bool))&Lua_Client::Fling)
|
||||
.def("Fling", (void(Lua_Client::*)(float,float,float,float,bool,bool))&Lua_Client::Fling);
|
||||
}
|
||||
|
||||
luabind::scope lua_register_inventory_where() {
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include "lua_mob.h"
|
||||
|
||||
class Client;
|
||||
class Lua_Expedition;
|
||||
class Lua_Group;
|
||||
class Lua_Raid;
|
||||
class Lua_Inventory;
|
||||
@ -51,7 +52,9 @@ public:
|
||||
bool GetGM();
|
||||
void SetBaseClass(int v);
|
||||
void SetBaseRace(int v);
|
||||
void SetBaseGender(int v);
|
||||
void SetBaseGender(int v);
|
||||
int GetClassBitmask();
|
||||
int GetRaceBitmask();
|
||||
int GetBaseFace();
|
||||
int GetLanguageSkill(int skill_id);
|
||||
const char *GetLastName();
|
||||
@ -91,6 +94,9 @@ public:
|
||||
float GetBindHeading(int index);
|
||||
uint32 GetBindZoneID();
|
||||
uint32 GetBindZoneID(int index);
|
||||
float GetTargetRingX();
|
||||
float GetTargetRingY();
|
||||
float GetTargetRingZ();
|
||||
void MovePC(int zone, float x, float y, float z, float heading);
|
||||
void MovePCInstance(int zone, int instance, float x, float y, float z, float heading);
|
||||
void MoveZone(const char *zone_short_name);
|
||||
@ -146,6 +152,15 @@ public:
|
||||
void UnmemSpellAll(bool update_client);
|
||||
uint16 FindMemmedSpellBySlot(int slot);
|
||||
int MemmedCount();
|
||||
luabind::object GetLearnableDisciplines(lua_State* L);
|
||||
luabind::object GetLearnableDisciplines(lua_State* L, uint8 min_level);
|
||||
luabind::object GetLearnableDisciplines(lua_State* L, uint8 min_level, uint8 max_level);
|
||||
luabind::object GetLearnedDisciplines(lua_State* L);
|
||||
luabind::object GetMemmedSpells(lua_State* L);
|
||||
luabind::object GetScribedSpells(lua_State* L);
|
||||
luabind::object GetScribeableSpells(lua_State* L);
|
||||
luabind::object GetScribeableSpells(lua_State* L, uint8 min_level);
|
||||
luabind::object GetScribeableSpells(lua_State* L, uint8 min_level, uint8 max_level);
|
||||
void ScribeSpell(int spell_id, int slot);
|
||||
void ScribeSpell(int spell_id, int slot, bool update_client);
|
||||
void UnscribeSpell(int slot);
|
||||
@ -207,6 +222,7 @@ public:
|
||||
uint32 GetDisciplineTimer(uint32 timer_id);
|
||||
void ResetDisciplineTimer(uint32 timer_id);
|
||||
bool UseDiscipline(int spell_id, int target_id);
|
||||
bool HasDisciplineLearned(uint16 spell_id);
|
||||
int GetCharacterFactionLevel(int faction_id);
|
||||
void SetZoneFlag(int zone_id);
|
||||
void ClearZoneFlag(int zone_id);
|
||||
@ -235,6 +251,8 @@ public:
|
||||
bool KeyRingCheck(uint32 item);
|
||||
void AddPVPPoints(uint32 points);
|
||||
void AddCrystals(uint32 radiant, uint32 ebon);
|
||||
void SetEbonCrystals(uint32 value);
|
||||
void SetRadiantCrystals(uint32 value);
|
||||
uint32 GetPVPPoints();
|
||||
uint32 GetRadiantCrystals();
|
||||
uint32 GetEbonCrystals();
|
||||
@ -260,6 +278,7 @@ public:
|
||||
void ClearCompassMark();
|
||||
int GetNextAvailableSpellBookSlot();
|
||||
int GetNextAvailableSpellBookSlot(int start);
|
||||
uint32 GetSpellIDByBookSlot(int book_slot);
|
||||
int FindSpellBookSlotBySpellID(int spell_id);
|
||||
void UpdateTaskActivity(int task, int activity, int count);
|
||||
void AssignTask(int task, int npc_id);
|
||||
@ -329,12 +348,36 @@ public:
|
||||
void EnableAreaRegens(int value);
|
||||
void DisableAreaRegens();
|
||||
|
||||
|
||||
void SetPrimaryWeaponOrnamentation(uint32 model_id);
|
||||
void SetSecondaryWeaponOrnamentation(uint32 model_id);
|
||||
|
||||
void SetClientMaxLevel(int value);
|
||||
int GetClientMaxLevel();
|
||||
|
||||
Lua_Expedition CreateExpedition(luabind::object expedition_info);
|
||||
Lua_Expedition CreateExpedition(std::string zone_name, uint32 version, uint32 duration, std::string expedition_name, uint32 min_players, uint32 max_players);
|
||||
Lua_Expedition CreateExpedition(std::string zone_name, uint32 version, uint32 duration, std::string expedition_name, uint32 min_players, uint32 max_players, bool disable_messages);
|
||||
Lua_Expedition GetExpedition();
|
||||
luabind::object GetExpeditionLockouts(lua_State* L);
|
||||
luabind::object GetExpeditionLockouts(lua_State* L, std::string expedition_name);
|
||||
std::string GetLockoutExpeditionUUID(std::string expedition_name, std::string event_name);
|
||||
void AddExpeditionLockout(std::string expedition_name, std::string event_name, uint32 seconds);
|
||||
void AddExpeditionLockout(std::string expedition_name, std::string event_name, uint32 seconds, std::string uuid);
|
||||
void AddExpeditionLockoutDuration(std::string expedition_name, std::string event_name, int seconds);
|
||||
void AddExpeditionLockoutDuration(std::string expedition_name, std::string event_name, int seconds, std::string uuid);
|
||||
void RemoveAllExpeditionLockouts();
|
||||
void RemoveAllExpeditionLockouts(std::string expedition_name);
|
||||
void RemoveExpeditionLockout(std::string expedition_name, std::string event_name);
|
||||
bool HasExpeditionLockout(std::string expedition_name, std::string event_name);
|
||||
void MovePCDynamicZone(uint32 zone_id);
|
||||
void MovePCDynamicZone(uint32 zone_id, int zone_version);
|
||||
void MovePCDynamicZone(uint32 zone_id, int zone_version, bool msg_if_invalid);
|
||||
void MovePCDynamicZone(std::string zone_name);
|
||||
void MovePCDynamicZone(std::string zone_name, int zone_version);
|
||||
void MovePCDynamicZone(std::string zone_name, int zone_version, bool msg_if_invalid);
|
||||
void Fling(float value, float target_x, float target_y, float target_z);
|
||||
void Fling(float value, float target_x, float target_y, float target_z, bool ignore_los);
|
||||
void Fling(float value, float target_x, float target_y, float target_z, bool ignore_los, bool clipping);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
301
zone/lua_expedition.cpp
Normal file
301
zone/lua_expedition.cpp
Normal file
@ -0,0 +1,301 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef LUA_EQEMU
|
||||
|
||||
#include "lua_expedition.h"
|
||||
#include "expedition.h"
|
||||
#include "zone_store.h"
|
||||
#include "lua.hpp"
|
||||
#include <luabind/luabind.hpp>
|
||||
#include <luabind/object.hpp>
|
||||
|
||||
void Lua_Expedition::AddLockout(std::string event_name, uint32_t seconds) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->AddLockout(event_name, seconds);
|
||||
}
|
||||
|
||||
void Lua_Expedition::AddLockoutDuration(std::string event_name, int seconds) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->AddLockoutDuration(event_name, seconds);
|
||||
}
|
||||
|
||||
void Lua_Expedition::AddLockoutDuration(std::string event_name, int seconds, bool members_only) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->AddLockoutDuration(event_name, seconds, members_only);
|
||||
}
|
||||
|
||||
void Lua_Expedition::AddReplayLockout(uint32_t seconds) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->AddReplayLockout(seconds);
|
||||
}
|
||||
|
||||
void Lua_Expedition::AddReplayLockoutDuration(int seconds) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->AddReplayLockoutDuration(seconds);
|
||||
}
|
||||
|
||||
void Lua_Expedition::AddReplayLockoutDuration(int seconds, bool members_only) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->AddReplayLockoutDuration(seconds, members_only);
|
||||
}
|
||||
|
||||
uint32_t Lua_Expedition::GetDynamicZoneID() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetDynamicZoneID();
|
||||
}
|
||||
|
||||
uint32_t Lua_Expedition::GetID() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetID();
|
||||
}
|
||||
|
||||
int Lua_Expedition::GetInstanceID() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetDynamicZone().GetInstanceID();
|
||||
}
|
||||
|
||||
std::string Lua_Expedition::GetLeaderName() {
|
||||
Lua_Safe_Call_String();
|
||||
return self->GetLeaderName();
|
||||
}
|
||||
|
||||
luabind::object Lua_Expedition::GetLockouts(lua_State* L) {
|
||||
luabind::object lua_table = luabind::newtable(L);
|
||||
|
||||
if (d_)
|
||||
{
|
||||
auto self = reinterpret_cast<NativeType*>(d_);
|
||||
auto lockouts = self->GetLockouts();
|
||||
for (const auto& lockout : lockouts)
|
||||
{
|
||||
lua_table[lockout.first] = lockout.second.GetSecondsRemaining();
|
||||
}
|
||||
}
|
||||
return lua_table;
|
||||
}
|
||||
|
||||
std::string Lua_Expedition::GetLootEventByNPCTypeID(uint32_t npc_type_id) {
|
||||
Lua_Safe_Call_String();
|
||||
return self->GetLootEventByNPCTypeID(npc_type_id);
|
||||
}
|
||||
|
||||
std::string Lua_Expedition::GetLootEventBySpawnID(uint32_t spawn_id) {
|
||||
Lua_Safe_Call_String();
|
||||
return self->GetLootEventBySpawnID(spawn_id);
|
||||
}
|
||||
|
||||
uint32_t Lua_Expedition::GetMemberCount() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetMemberCount();
|
||||
}
|
||||
|
||||
luabind::object Lua_Expedition::GetMembers(lua_State* L) {
|
||||
luabind::object lua_table = luabind::newtable(L);
|
||||
|
||||
if (d_)
|
||||
{
|
||||
auto self = reinterpret_cast<NativeType*>(d_);
|
||||
for (const auto& member : self->GetMembers())
|
||||
{
|
||||
lua_table[member.name] = member.char_id;
|
||||
}
|
||||
}
|
||||
return lua_table;
|
||||
}
|
||||
|
||||
std::string Lua_Expedition::GetName() {
|
||||
Lua_Safe_Call_String();
|
||||
return self->GetName();
|
||||
}
|
||||
|
||||
int Lua_Expedition::GetSecondsRemaining() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetDynamicZone().GetSecondsRemaining();
|
||||
}
|
||||
|
||||
std::string Lua_Expedition::GetUUID() {
|
||||
Lua_Safe_Call_String();
|
||||
return self->GetUUID();
|
||||
}
|
||||
|
||||
int Lua_Expedition::GetZoneID() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetDynamicZone().GetZoneID();
|
||||
}
|
||||
|
||||
std::string Lua_Expedition::GetZoneName() {
|
||||
Lua_Safe_Call_String();
|
||||
return ZoneName(self->GetDynamicZone().GetZoneID());
|
||||
}
|
||||
|
||||
int Lua_Expedition::GetZoneVersion() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetDynamicZone().GetZoneVersion();
|
||||
}
|
||||
|
||||
bool Lua_Expedition::HasLockout(std::string event_name) {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->HasLockout(event_name);
|
||||
}
|
||||
|
||||
bool Lua_Expedition::HasReplayLockout() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->HasReplayLockout();
|
||||
}
|
||||
|
||||
void Lua_Expedition::RemoveCompass() {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetDzCompass(0, 0, 0, 0, true);
|
||||
}
|
||||
|
||||
void Lua_Expedition::RemoveLockout(std::string event_name) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->RemoveLockout(event_name);
|
||||
}
|
||||
|
||||
void Lua_Expedition::SetCompass(uint32_t zone_id, float x, float y, float z) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetDzCompass(zone_id, x, y, z, true);
|
||||
}
|
||||
|
||||
void Lua_Expedition::SetCompass(std::string zone_name, float x, float y, float z) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetDzCompass(zone_name, x, y, z, true);
|
||||
}
|
||||
|
||||
void Lua_Expedition::SetLocked(bool lock_expedition) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetLocked(lock_expedition, ExpeditionLockMessage::None, true);
|
||||
}
|
||||
|
||||
void Lua_Expedition::SetLocked(bool lock_expedition, int lock_msg) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetLocked(lock_expedition, static_cast<ExpeditionLockMessage>(lock_msg), true);
|
||||
}
|
||||
|
||||
void Lua_Expedition::SetLocked(bool lock_expedition, int lock_msg, uint32_t msg_color) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetLocked(lock_expedition, static_cast<ExpeditionLockMessage>(lock_msg), true, msg_color);
|
||||
}
|
||||
|
||||
void Lua_Expedition::SetLootEventByNPCTypeID(uint32_t npc_type_id, std::string event_name) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetLootEventByNPCTypeID(npc_type_id, event_name);
|
||||
}
|
||||
|
||||
void Lua_Expedition::SetLootEventBySpawnID(uint32_t spawn_id, std::string event_name) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetLootEventBySpawnID(spawn_id, event_name);
|
||||
}
|
||||
|
||||
void Lua_Expedition::SetReplayLockoutOnMemberJoin(bool enable) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetReplayLockoutOnMemberJoin(enable, true);
|
||||
}
|
||||
|
||||
void Lua_Expedition::SetSafeReturn(uint32_t zone_id, float x, float y, float z, float heading) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetDzSafeReturn(zone_id, x, y, z, heading, true);
|
||||
}
|
||||
|
||||
void Lua_Expedition::SetSafeReturn(std::string zone_name, float x, float y, float z, float heading) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetDzSafeReturn(zone_name, x, y, z, heading, true);
|
||||
}
|
||||
|
||||
void Lua_Expedition::SetSecondsRemaining(uint32_t seconds_remaining)
|
||||
{
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetDzSecondsRemaining(seconds_remaining);
|
||||
}
|
||||
|
||||
void Lua_Expedition::SetZoneInLocation(float x, float y, float z, float heading) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetDzZoneInLocation(x, y, z, heading, true);
|
||||
}
|
||||
|
||||
void Lua_Expedition::UpdateLockoutDuration(std::string event_name, uint32_t duration) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->UpdateLockoutDuration(event_name, duration);
|
||||
}
|
||||
|
||||
void Lua_Expedition::UpdateLockoutDuration(std::string event_name, uint32_t duration, bool members_only) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->UpdateLockoutDuration(event_name, duration, members_only);
|
||||
}
|
||||
|
||||
luabind::scope lua_register_expedition() {
|
||||
return luabind::class_<Lua_Expedition>("Expedition")
|
||||
.def(luabind::constructor<>())
|
||||
.property("null", &Lua_Expedition::Null)
|
||||
.property("valid", &Lua_Expedition::Valid)
|
||||
.def("AddLockout", (void(Lua_Expedition::*)(std::string, uint32_t))&Lua_Expedition::AddLockout)
|
||||
.def("AddLockoutDuration", (void(Lua_Expedition::*)(std::string, int))&Lua_Expedition::AddLockoutDuration)
|
||||
.def("AddLockoutDuration", (void(Lua_Expedition::*)(std::string, int, bool))&Lua_Expedition::AddLockoutDuration)
|
||||
.def("AddReplayLockout", (void(Lua_Expedition::*)(uint32_t))&Lua_Expedition::AddReplayLockout)
|
||||
.def("AddReplayLockoutDuration", (void(Lua_Expedition::*)(int))&Lua_Expedition::AddReplayLockoutDuration)
|
||||
.def("AddReplayLockoutDuration", (void(Lua_Expedition::*)(int, bool))&Lua_Expedition::AddReplayLockoutDuration)
|
||||
.def("GetDynamicZoneID", &Lua_Expedition::GetDynamicZoneID)
|
||||
.def("GetID", (uint32_t(Lua_Expedition::*)(void))&Lua_Expedition::GetID)
|
||||
.def("GetInstanceID", (int(Lua_Expedition::*)(void))&Lua_Expedition::GetInstanceID)
|
||||
.def("GetLeaderName", (std::string(Lua_Expedition::*)(void))&Lua_Expedition::GetLeaderName)
|
||||
.def("GetLockouts", &Lua_Expedition::GetLockouts)
|
||||
.def("GetLootEventByNPCTypeID", (std::string(Lua_Expedition::*)(uint32_t))&Lua_Expedition::GetLootEventByNPCTypeID)
|
||||
.def("GetLootEventBySpawnID", (std::string(Lua_Expedition::*)(uint32_t))&Lua_Expedition::GetLootEventBySpawnID)
|
||||
.def("GetMemberCount", (uint32_t(Lua_Expedition::*)(void))&Lua_Expedition::GetMemberCount)
|
||||
.def("GetMembers", &Lua_Expedition::GetMembers)
|
||||
.def("GetName", (std::string(Lua_Expedition::*)(void))&Lua_Expedition::GetName)
|
||||
.def("GetSecondsRemaining", (int(Lua_Expedition::*)(void))&Lua_Expedition::GetSecondsRemaining)
|
||||
.def("GetUUID", (std::string(Lua_Expedition::*)(void))&Lua_Expedition::GetUUID)
|
||||
.def("GetZoneID", (int(Lua_Expedition::*)(void))&Lua_Expedition::GetZoneID)
|
||||
.def("GetZoneName", &Lua_Expedition::GetZoneName)
|
||||
.def("GetZoneVersion", &Lua_Expedition::GetZoneVersion)
|
||||
.def("HasLockout", (bool(Lua_Expedition::*)(std::string))&Lua_Expedition::HasLockout)
|
||||
.def("HasReplayLockout", (bool(Lua_Expedition::*)(void))&Lua_Expedition::HasReplayLockout)
|
||||
.def("RemoveCompass", (void(Lua_Expedition::*)(void))&Lua_Expedition::RemoveCompass)
|
||||
.def("RemoveLockout", (void(Lua_Expedition::*)(std::string))&Lua_Expedition::RemoveLockout)
|
||||
.def("SetCompass", (void(Lua_Expedition::*)(uint32_t, float, float, float))&Lua_Expedition::SetCompass)
|
||||
.def("SetCompass", (void(Lua_Expedition::*)(std::string, float, float, float))&Lua_Expedition::SetCompass)
|
||||
.def("SetLocked", (void(Lua_Expedition::*)(bool))&Lua_Expedition::SetLocked)
|
||||
.def("SetLocked", (void(Lua_Expedition::*)(bool, int))&Lua_Expedition::SetLocked)
|
||||
.def("SetLocked", (void(Lua_Expedition::*)(bool, int, uint32_t))&Lua_Expedition::SetLocked)
|
||||
.def("SetLootEventByNPCTypeID", (void(Lua_Expedition::*)(uint32_t, std::string))&Lua_Expedition::SetLootEventByNPCTypeID)
|
||||
.def("SetLootEventBySpawnID", (void(Lua_Expedition::*)(uint32_t, std::string))&Lua_Expedition::SetLootEventBySpawnID)
|
||||
.def("SetReplayLockoutOnMemberJoin", (void(Lua_Expedition::*)(bool))&Lua_Expedition::SetReplayLockoutOnMemberJoin)
|
||||
.def("SetSafeReturn", (void(Lua_Expedition::*)(uint32_t, float, float, float, float))&Lua_Expedition::SetSafeReturn)
|
||||
.def("SetSafeReturn", (void(Lua_Expedition::*)(std::string, float, float, float, float))&Lua_Expedition::SetSafeReturn)
|
||||
.def("SetSecondsRemaining", &Lua_Expedition::SetSecondsRemaining)
|
||||
.def("SetZoneInLocation", (void(Lua_Expedition::*)(float, float, float, float))&Lua_Expedition::SetZoneInLocation)
|
||||
.def("UpdateLockoutDuration", (void(Lua_Expedition::*)(std::string, uint32_t))&Lua_Expedition::UpdateLockoutDuration)
|
||||
.def("UpdateLockoutDuration", (void(Lua_Expedition::*)(std::string, uint32_t, bool))&Lua_Expedition::UpdateLockoutDuration);
|
||||
}
|
||||
|
||||
luabind::scope lua_register_expedition_lock_messages() {
|
||||
return luabind::class_<ExpeditionLockMessage>("ExpeditionLockMessage")
|
||||
.enum_("constants")
|
||||
[
|
||||
luabind::value("None", static_cast<int>(ExpeditionLockMessage::None)),
|
||||
luabind::value("Close", static_cast<int>(ExpeditionLockMessage::Close)),
|
||||
luabind::value("Begin", static_cast<int>(ExpeditionLockMessage::Begin))
|
||||
];
|
||||
}
|
||||
|
||||
#endif // LUA_EQEMU
|
||||
98
zone/lua_expedition.h
Normal file
98
zone/lua_expedition.h
Normal file
@ -0,0 +1,98 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* 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 EQEMU_LUA_EXPEDITION_H
|
||||
#define EQEMU_LUA_EXPEDITION_H
|
||||
#ifdef LUA_EQEMU
|
||||
|
||||
#include "lua_ptr.h"
|
||||
#include "../common/types.h"
|
||||
#include <string>
|
||||
|
||||
class Expedition;
|
||||
class Lua_Client;
|
||||
struct lua_State;
|
||||
|
||||
namespace luabind {
|
||||
struct scope;
|
||||
namespace adl {
|
||||
class object;
|
||||
}
|
||||
using adl::object;
|
||||
}
|
||||
|
||||
luabind::scope lua_register_expedition();
|
||||
luabind::scope lua_register_expedition_lock_messages();
|
||||
|
||||
class Lua_Expedition : public Lua_Ptr<Expedition>
|
||||
{
|
||||
typedef Expedition NativeType;
|
||||
public:
|
||||
Lua_Expedition() : Lua_Ptr(nullptr) { }
|
||||
Lua_Expedition(Expedition *d) : Lua_Ptr(d) { }
|
||||
virtual ~Lua_Expedition() { }
|
||||
|
||||
operator Expedition*() {
|
||||
return reinterpret_cast<Expedition*>(GetLuaPtrData());
|
||||
}
|
||||
|
||||
void AddLockout(std::string event_name, uint32_t seconds);
|
||||
void AddLockoutDuration(std::string event_name, int seconds);
|
||||
void AddLockoutDuration(std::string event_name, int seconds, bool members_only);
|
||||
void AddReplayLockout(uint32_t seconds);
|
||||
void AddReplayLockoutDuration(int seconds);
|
||||
void AddReplayLockoutDuration(int seconds, bool members_only);
|
||||
uint32_t GetDynamicZoneID();
|
||||
uint32_t GetID();
|
||||
int GetInstanceID();
|
||||
std::string GetLeaderName();
|
||||
luabind::object GetLockouts(lua_State* L);
|
||||
std::string GetLootEventByNPCTypeID(uint32_t npc_type_id);
|
||||
std::string GetLootEventBySpawnID(uint32_t spawn_id);
|
||||
uint32_t GetMemberCount();
|
||||
luabind::object GetMembers(lua_State* L);
|
||||
std::string GetName();
|
||||
int GetSecondsRemaining();
|
||||
std::string GetUUID();
|
||||
int GetZoneID();
|
||||
std::string GetZoneName();
|
||||
int GetZoneVersion();
|
||||
bool HasLockout(std::string event_name);
|
||||
bool HasReplayLockout();
|
||||
void RemoveCompass();
|
||||
void RemoveLockout(std::string event_name);
|
||||
void SetCompass(uint32_t zone_id, float x, float y, float z);
|
||||
void SetCompass(std::string zone_name, float x, float y, float z);
|
||||
void SetLocked(bool lock_expedition);
|
||||
void SetLocked(bool lock_expedition, int lock_msg);
|
||||
void SetLocked(bool lock_expedition, int lock_msg, uint32_t color);
|
||||
void SetLootEventByNPCTypeID(uint32_t npc_type_id, std::string event_name);
|
||||
void SetLootEventBySpawnID(uint32_t spawn_id, std::string event_name);
|
||||
void SetReplayLockoutOnMemberJoin(bool enable);
|
||||
void SetSafeReturn(uint32_t zone_id, float x, float y, float z, float heading);
|
||||
void SetSafeReturn(std::string zone_name, float x, float y, float z, float heading);
|
||||
void SetSecondsRemaining(uint32_t seconds_remaining);
|
||||
void SetZoneInLocation(float x, float y, float z, float heading);
|
||||
void UpdateLockoutDuration(std::string event_name, uint32_t duration);
|
||||
void UpdateLockoutDuration(std::string event_name, uint32_t duration, bool members_only);
|
||||
};
|
||||
|
||||
#endif // LUA_EQEMU
|
||||
#endif // EQEMU_LUA_EXPEDITION_H
|
||||
@ -18,12 +18,14 @@
|
||||
#include "lua_client.h"
|
||||
#include "lua_npc.h"
|
||||
#include "lua_entity_list.h"
|
||||
#include "lua_expedition.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "questmgr.h"
|
||||
#include "qglobals.h"
|
||||
#include "encounter.h"
|
||||
#include "lua_encounter.h"
|
||||
#include "data_bucket.h"
|
||||
#include "expedition.h"
|
||||
|
||||
struct Events { };
|
||||
struct Factions { };
|
||||
@ -766,6 +768,14 @@ void lua_world_emote(int type, const char *str) {
|
||||
quest_manager.we(type, str);
|
||||
}
|
||||
|
||||
void lua_message(int color, const char *message) {
|
||||
quest_manager.message(color, message);
|
||||
}
|
||||
|
||||
void lua_whisper(const char *message) {
|
||||
quest_manager.whisper(message);
|
||||
}
|
||||
|
||||
int lua_get_level(int type) {
|
||||
return quest_manager.getlevel(type);
|
||||
}
|
||||
@ -806,6 +816,14 @@ int lua_count_item(uint32 item_id) {
|
||||
return quest_manager.countitem(item_id);
|
||||
}
|
||||
|
||||
void lua_remove_item(uint32 item_id) {
|
||||
quest_manager.removeitem(item_id);
|
||||
}
|
||||
|
||||
void lua_remove_item(uint32 item_id, uint32 quantity) {
|
||||
quest_manager.removeitem(item_id, quantity);
|
||||
}
|
||||
|
||||
void lua_update_spawn_timer(uint32 id, uint32 new_time) {
|
||||
quest_manager.UpdateSpawnTimer(id, new_time);
|
||||
}
|
||||
@ -2170,6 +2188,118 @@ void lua_set_content_flag(std::string flag_name, bool enabled){
|
||||
ZoneStore::SetContentFlag(flag_name, enabled);
|
||||
}
|
||||
|
||||
Lua_Expedition lua_get_expedition() {
|
||||
if (zone && zone->GetInstanceID() != 0)
|
||||
{
|
||||
return Expedition::FindCachedExpeditionByZoneInstance(zone->GetZoneID(), zone->GetInstanceID());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Lua_Expedition lua_get_expedition_by_char_id(uint32 char_id) {
|
||||
return Expedition::FindCachedExpeditionByCharacterID(char_id);
|
||||
}
|
||||
|
||||
Lua_Expedition lua_get_expedition_by_dz_id(uint32 dz_id) {
|
||||
return Expedition::FindCachedExpeditionByDynamicZoneID(dz_id);
|
||||
}
|
||||
|
||||
Lua_Expedition lua_get_expedition_by_zone_instance(uint32 zone_id, uint32 instance_id) {
|
||||
return Expedition::FindCachedExpeditionByZoneInstance(zone_id, instance_id);
|
||||
}
|
||||
|
||||
luabind::object lua_get_expedition_lockout_by_char_id(lua_State* L, uint32 char_id, std::string expedition_name, std::string event_name) {
|
||||
luabind::adl::object lua_table = luabind::newtable(L);
|
||||
|
||||
auto lockouts = Expedition::GetExpeditionLockoutsByCharacterID(char_id);
|
||||
|
||||
auto it = std::find_if(lockouts.begin(), lockouts.end(), [&](const ExpeditionLockoutTimer& lockout) {
|
||||
return lockout.IsSameLockout(expedition_name, event_name);
|
||||
});
|
||||
|
||||
if (it != lockouts.end())
|
||||
{
|
||||
lua_table["remaining"] = it->GetSecondsRemaining();
|
||||
lua_table["uuid"] = it->GetExpeditionUUID();
|
||||
}
|
||||
|
||||
return lua_table;
|
||||
}
|
||||
|
||||
luabind::object lua_get_expedition_lockouts_by_char_id(lua_State* L, uint32 char_id) {
|
||||
luabind::adl::object lua_table = luabind::newtable(L);
|
||||
|
||||
auto lockouts = Expedition::GetExpeditionLockoutsByCharacterID(char_id);
|
||||
for (const auto& lockout : lockouts)
|
||||
{
|
||||
auto lockout_table = lua_table[lockout.GetExpeditionName()];
|
||||
if (luabind::type(lockout_table) != LUA_TTABLE)
|
||||
{
|
||||
lockout_table = luabind::newtable(L);
|
||||
}
|
||||
|
||||
auto event_table = lockout_table[lockout.GetEventName()];
|
||||
if (luabind::type(event_table) != LUA_TTABLE)
|
||||
{
|
||||
event_table = luabind::newtable(L);
|
||||
}
|
||||
|
||||
event_table["remaining"] = lockout.GetSecondsRemaining();
|
||||
event_table["uuid"] = lockout.GetExpeditionUUID();
|
||||
}
|
||||
return lua_table;
|
||||
}
|
||||
|
||||
luabind::object lua_get_expedition_lockouts_by_char_id(lua_State* L, uint32 char_id, std::string expedition_name) {
|
||||
luabind::adl::object lua_table = luabind::newtable(L);
|
||||
|
||||
auto lockouts = Expedition::GetExpeditionLockoutsByCharacterID(char_id);
|
||||
for (const auto& lockout : lockouts)
|
||||
{
|
||||
if (lockout.GetExpeditionName() == expedition_name)
|
||||
{
|
||||
auto event_table = lua_table[lockout.GetEventName()];
|
||||
if (luabind::type(event_table) != LUA_TTABLE)
|
||||
{
|
||||
event_table = luabind::newtable(L);
|
||||
}
|
||||
event_table["remaining"] = lockout.GetSecondsRemaining();
|
||||
event_table["uuid"] = lockout.GetExpeditionUUID();
|
||||
}
|
||||
}
|
||||
return lua_table;
|
||||
}
|
||||
|
||||
void lua_add_expedition_lockout_all_clients(std::string expedition_name, std::string event_name, uint32 seconds) {
|
||||
auto lockout = ExpeditionLockoutTimer::CreateLockout(expedition_name, event_name, seconds);
|
||||
Expedition::AddLockoutClients(lockout);
|
||||
}
|
||||
|
||||
void lua_add_expedition_lockout_all_clients(std::string expedition_name, std::string event_name, uint32 seconds, std::string uuid) {
|
||||
auto lockout = ExpeditionLockoutTimer::CreateLockout(expedition_name, event_name, seconds, uuid);
|
||||
Expedition::AddLockoutClients(lockout);
|
||||
}
|
||||
|
||||
void lua_add_expedition_lockout_by_char_id(uint32 char_id, std::string expedition_name, std::string event_name, uint32 seconds) {
|
||||
Expedition::AddLockoutByCharacterID(char_id, expedition_name, event_name, seconds);
|
||||
}
|
||||
|
||||
void lua_add_expedition_lockout_by_char_id(uint32 char_id, std::string expedition_name, std::string event_name, uint32 seconds, std::string uuid) {
|
||||
Expedition::AddLockoutByCharacterID(char_id, expedition_name, event_name, seconds, uuid);
|
||||
}
|
||||
|
||||
void lua_remove_expedition_lockout_by_char_id(uint32 char_id, std::string expedition_name, std::string event_name) {
|
||||
Expedition::RemoveLockoutsByCharacterID(char_id, expedition_name, event_name);
|
||||
}
|
||||
|
||||
void lua_remove_all_expedition_lockouts_by_char_id(uint32 char_id) {
|
||||
Expedition::RemoveLockoutsByCharacterID(char_id);
|
||||
}
|
||||
|
||||
void lua_remove_all_expedition_lockouts_by_char_id(uint32 char_id, std::string expedition_name) {
|
||||
Expedition::RemoveLockoutsByCharacterID(char_id, expedition_name);
|
||||
}
|
||||
|
||||
#define LuaCreateNPCParse(name, c_type, default_value) do { \
|
||||
cur = table[#name]; \
|
||||
if(luabind::type(cur) != LUA_TNIL) { \
|
||||
@ -2477,6 +2607,8 @@ luabind::scope lua_register_general() {
|
||||
luabind::def("clear_spawn_timers", &lua_clear_spawn_timers),
|
||||
luabind::def("zone_emote", &lua_zone_emote),
|
||||
luabind::def("world_emote", &lua_world_emote),
|
||||
luabind::def("message", &lua_message),
|
||||
luabind::def("whisper", &lua_whisper),
|
||||
luabind::def("get_level", &lua_get_level),
|
||||
luabind::def("create_ground_object", (void(*)(uint32,float,float,float,float))&lua_create_ground_object),
|
||||
luabind::def("create_ground_object", (void(*)(uint32,float,float,float,float,uint32))&lua_create_ground_object),
|
||||
@ -2487,6 +2619,8 @@ luabind::scope lua_register_general() {
|
||||
luabind::def("modify_npc_stat", &lua_modify_npc_stat),
|
||||
luabind::def("collect_items", &lua_collect_items),
|
||||
luabind::def("count_item", &lua_count_item),
|
||||
luabind::def("remove_item", (void(*)(uint32))&lua_remove_item),
|
||||
luabind::def("remove_item", (void(*)(uint32,uint32))&lua_remove_item),
|
||||
luabind::def("update_spawn_timer", &lua_update_spawn_timer),
|
||||
luabind::def("merchant_set_item", (void(*)(uint32,uint32))&lua_merchant_set_item),
|
||||
luabind::def("merchant_set_item", (void(*)(uint32,uint32,uint32))&lua_merchant_set_item),
|
||||
@ -2765,7 +2899,22 @@ luabind::scope lua_register_general() {
|
||||
* Content flags
|
||||
*/
|
||||
luabind::def("is_content_flag_enabled", (bool(*)(std::string))&lua_is_content_flag_enabled),
|
||||
luabind::def("set_content_flag", (void(*)(std::string, bool))&lua_set_content_flag)
|
||||
luabind::def("set_content_flag", (void(*)(std::string, bool))&lua_set_content_flag),
|
||||
|
||||
luabind::def("get_expedition", &lua_get_expedition),
|
||||
luabind::def("get_expedition_by_char_id", &lua_get_expedition_by_char_id),
|
||||
luabind::def("get_expedition_by_dz_id", &lua_get_expedition_by_dz_id),
|
||||
luabind::def("get_expedition_by_zone_instance", &lua_get_expedition_by_zone_instance),
|
||||
luabind::def("get_expedition_lockout_by_char_id", &lua_get_expedition_lockout_by_char_id),
|
||||
luabind::def("get_expedition_lockouts_by_char_id", (luabind::object(*)(lua_State*, uint32))&lua_get_expedition_lockouts_by_char_id),
|
||||
luabind::def("get_expedition_lockouts_by_char_id", (luabind::object(*)(lua_State*, uint32, std::string))&lua_get_expedition_lockouts_by_char_id),
|
||||
luabind::def("add_expedition_lockout_all_clients", (void(*)(std::string, std::string, uint32))&lua_add_expedition_lockout_all_clients),
|
||||
luabind::def("add_expedition_lockout_all_clients", (void(*)(std::string, std::string, uint32, std::string))&lua_add_expedition_lockout_all_clients),
|
||||
luabind::def("add_expedition_lockout_by_char_id", (void(*)(uint32, std::string, std::string, uint32))&lua_add_expedition_lockout_by_char_id),
|
||||
luabind::def("add_expedition_lockout_by_char_id", (void(*)(uint32, std::string, std::string, uint32, std::string))&lua_add_expedition_lockout_by_char_id),
|
||||
luabind::def("remove_expedition_lockout_by_char_id", &lua_remove_expedition_lockout_by_char_id),
|
||||
luabind::def("remove_all_expedition_lockouts_by_char_id", (void(*)(uint32))&lua_remove_all_expedition_lockouts_by_char_id),
|
||||
luabind::def("remove_all_expedition_lockouts_by_char_id", (void(*)(uint32, std::string))&lua_remove_all_expedition_lockouts_by_char_id)
|
||||
];
|
||||
}
|
||||
|
||||
@ -3254,7 +3403,24 @@ luabind::scope lua_register_message_types() {
|
||||
return luabind::class_<MessageTypes>("MT")
|
||||
.enum_("constants")
|
||||
[
|
||||
luabind::value("White", Chat::White),
|
||||
luabind::value("DimGray", Chat::DimGray),
|
||||
luabind::value("Default", Chat::Default),
|
||||
luabind::value("Green", Chat::Green),
|
||||
luabind::value("BrightBlue", Chat::BrightBlue),
|
||||
luabind::value("LightBlue", Chat::LightBlue),
|
||||
luabind::value("Magenta", Chat::Magenta),
|
||||
luabind::value("Gray", Chat::Gray),
|
||||
luabind::value("LightGray", Chat::LightGray),
|
||||
luabind::value("NPCQuestSay", Chat::NPCQuestSay),
|
||||
luabind::value("DarkGray", Chat::DarkGray),
|
||||
luabind::value("Red", Chat::Red),
|
||||
luabind::value("Lime", Chat::Lime),
|
||||
luabind::value("Yellow", Chat::Yellow),
|
||||
luabind::value("Blue", Chat::Blue),
|
||||
luabind::value("LightNavy", Chat::LightNavy),
|
||||
luabind::value("Cyan", Chat::Cyan),
|
||||
luabind::value("Black", Chat::Black),
|
||||
luabind::value("Say", Chat::Say),
|
||||
luabind::value("Tell", Chat::Tell),
|
||||
luabind::value("Group", Chat::Group),
|
||||
|
||||
@ -107,6 +107,18 @@ Lua_Mob Lua_Group::GetMember(int index) {
|
||||
return self->members[index];
|
||||
}
|
||||
|
||||
bool Lua_Group::DoesAnyMemberHaveExpeditionLockout(std::string expedition_name, std::string event_name)
|
||||
{
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->DoesAnyMemberHaveExpeditionLockout(expedition_name, event_name);
|
||||
}
|
||||
|
||||
bool Lua_Group::DoesAnyMemberHaveExpeditionLockout(std::string expedition_name, std::string event_name, int max_check_count)
|
||||
{
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->DoesAnyMemberHaveExpeditionLockout(expedition_name, event_name, max_check_count);
|
||||
}
|
||||
|
||||
luabind::scope lua_register_group() {
|
||||
return luabind::class_<Lua_Group>("Group")
|
||||
.def(luabind::constructor<>())
|
||||
@ -129,7 +141,9 @@ luabind::scope lua_register_group() {
|
||||
.def("GetLowestLevel", (int(Lua_Group::*)(void))&Lua_Group::GetLowestLevel)
|
||||
.def("TeleportGroup", (void(Lua_Group::*)(Lua_Mob,uint32,uint32,float,float,float,float))&Lua_Group::TeleportGroup)
|
||||
.def("GetID", (int(Lua_Group::*)(void))&Lua_Group::GetID)
|
||||
.def("GetMember", (Lua_Mob(Lua_Group::*)(int))&Lua_Group::GetMember);
|
||||
.def("GetMember", (Lua_Mob(Lua_Group::*)(int))&Lua_Group::GetMember)
|
||||
.def("DoesAnyMemberHaveExpeditionLockout", (bool(Lua_Group::*)(std::string, std::string))&Lua_Group::DoesAnyMemberHaveExpeditionLockout)
|
||||
.def("DoesAnyMemberHaveExpeditionLockout", (bool(Lua_Group::*)(std::string, std::string, int))&Lua_Group::DoesAnyMemberHaveExpeditionLockout);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user