From c17b4d558884af3f1788086c675e061f06eb9e31 Mon Sep 17 00:00:00 2001 From: Emagi Date: Wed, 4 Dec 2024 21:53:57 -0500 Subject: [PATCH] Added CreateChoiceWindow, ClearChoice and GetChoiceSpawnID lua functions, added base of tracking for min, max, avg, first level for raid/group into instances... more work to complete tomorrow --- source/WorldServer/Commands/Commands.cpp | 57 +++- source/WorldServer/Commands/Commands.h | 4 +- source/WorldServer/LuaFunctions.cpp | 101 ++++++ source/WorldServer/LuaFunctions.h | 4 + source/WorldServer/LuaInterface.cpp | 4 + source/WorldServer/PlayerGroups.cpp | 74 +++++ source/WorldServer/PlayerGroups.h | 3 +- source/WorldServer/Web/HTTPSClientPool.cpp | 16 + source/WorldServer/Web/PeerManager.cpp | 4 +- source/WorldServer/Web/PeerManager.h | 2 +- source/WorldServer/Web/WorldWeb.cpp | 19 +- source/WorldServer/World.cpp | 20 +- source/WorldServer/World.h | 4 +- source/WorldServer/WorldDatabase.cpp | 15 +- source/WorldServer/WorldDatabase.h | 4 +- source/WorldServer/client.cpp | 69 +++- source/WorldServer/client.h | 354 +++++++++++++-------- source/WorldServer/zoneserver.cpp | 5 + source/WorldServer/zoneserver.h | 28 ++ 19 files changed, 613 insertions(+), 174 deletions(-) diff --git a/source/WorldServer/Commands/Commands.cpp b/source/WorldServer/Commands/Commands.cpp index 025917d..64c1c5e 100644 --- a/source/WorldServer/Commands/Commands.cpp +++ b/source/WorldServer/Commands/Commands.cpp @@ -5595,7 +5595,7 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie case COMMAND_SET_GUILD_MEMBER_NOTE : { Command_SetGuildMemberNote(client, sep); break; } case COMMAND_SET_GUILD_OFFICER_NOTE : { Command_SetGuildOfficerNote(client, sep); break; } case COMMAND_GUILD : { Command_Guild(client, sep); break; } - case COMMAND_CREATE_GUILD : { Command_CreateGuild(client); break; } + case COMMAND_CREATE_GUILD : { Command_CreateGuild(client, sep); break; } case COMMAND_GUILDS : { Command_Guilds(client); break; } case COMMAND_GUILDS_ADD : { Command_GuildsAdd(client, sep); break; } case COMMAND_GUILDS_CREATE : { Command_GuildsCreate(client, sep); break; } @@ -6541,9 +6541,9 @@ void Commands::Command_Guild(Client* client, Seperator* sep) Purpose : Display's in-game Guild Creation window Dev : Scatman */ -void Commands::Command_CreateGuild(Client* client) +void Commands::Command_CreateGuild(Client* client, Seperator* sep) { - client->SendGuildCreateWindow(); + Command_GuildsCreate(client, sep, true); } /* @@ -6692,11 +6692,33 @@ void Commands::Command_GuildsAdd(Client* client, Seperator* sep) Dev : Scatman Example : /guilds create [guild name] (player name) */ -void Commands::Command_GuildsCreate(Client* client, Seperator* sep) +void Commands::Command_GuildsCreate(Client* client, Seperator* sep, bool prompted_dialog) { + Spawn* npc = nullptr; + if(prompted_dialog) { + auto target_npc = client->dialog_manager.getAcceptValue("create guild"); + if(!target_npc) { + // well this is not acceptable!! CHEATER! :D + return; + } + else { + if(!client->GetPlayer()->GetZone()){ + // player isn't in a zone? eh.. + return; + } + npc = client->GetPlayer()->GetZone()->GetSpawnByID(target_npc); + if(!npc) { + client->Message(CHANNEL_COLOR_RED, "Did not find guild registrar, please re-initiate dialog with them."); + return; + } + } + } if (sep && sep->arg[0]) { const char* guild_name = sep->arg[0]; + if(prompted_dialog) + guild_name = sep->argplus[0]; + int8 resp = database.CheckNameFilter(guild_name, 4, 41); if(!guild_name || resp == BADNAMELENGTH_REPLY) { client->Message(CHANNEL_COLOR_YELLOW, "Guild name is too short."); @@ -6708,7 +6730,7 @@ void Commands::Command_GuildsCreate(Client* client, Seperator* sep) { bool ret = false; - if (sep->arg[1] && strlen(sep->arg[1]) > 0 && client->GetAdminStatus() > 0) + if (!prompted_dialog && sep->arg[1] && strlen(sep->arg[1]) > 0 && client->GetAdminStatus() > 0) { Client* to_client = zone_list.GetClientByCharName(string(sep->arg[1])); @@ -6728,7 +6750,7 @@ void Commands::Command_GuildsCreate(Client* client, Seperator* sep) client->Message(CHANNEL_COLOR_YELLOW, "Could not find target %s or target is already in a guild.", sep->arg[1]); } } - else if (client->GetAdminStatus() > 0 && client->GetPlayer()->GetTarget() && client->GetPlayer()->GetTarget()->IsPlayer()) + else if (!prompted_dialog && client->GetAdminStatus() > 0 && client->GetPlayer()->GetTarget() && client->GetPlayer()->GetTarget()->IsPlayer()) { Client* to_client = ((Player*)client->GetPlayer()->GetTarget())->GetClient(); @@ -6752,27 +6774,38 @@ void Commands::Command_GuildsCreate(Client* client, Seperator* sep) { if(client->GetPlayer()->GetGuild()) { client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are already in a guild."); + if(client->GetAdminStatus() < 1) + return; } else if(net.is_primary) { - int32 guildID = world.CreateGuild(guild_name); - if(guildID > 0) + Client* leader = nullptr; + if(prompted_dialog || client->GetAdminStatus() < 1) + leader = client; + int32 guildID = world.CreateGuild(guild_name, leader); + if(guildID > 0) { peer_manager.sendPeersCreateGuild(guildID); + ret = true; + } } else { - peer_manager.sendPrimaryCreateGuildRequest(std::string(guild_name), ""); + peer_manager.sendPrimaryCreateGuildRequest(std::string(guild_name), "", prompted_dialog, npc->GetID()); + return; } - ret = true; } - if (ret) + if (ret) { client->Message(CHANNEL_COLOR_YELLOW, "Guild '%s' was successfully created.", guild_name); + if(prompted_dialog) { // prompted dialog requires npc be defined + client->GetCurrentZone()->CallSpawnScript(npc, SPAWN_SCRIPT_CASTED_ON, client->GetPlayer(), guild_name); + } + } else client->SimpleMessage(CHANNEL_COLOR_YELLOW, "There was an error creating the guild."); } else client->Message(CHANNEL_COLOR_YELLOW, "Guild '%s' already exists.", guild_name); } - else + else if(!prompted_dialog) client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Usage: /guilds create [guild name] (player name). If no player is specified, the player's target will be used. If the player has no target, a guild with no members will be created."); } diff --git a/source/WorldServer/Commands/Commands.h b/source/WorldServer/Commands/Commands.h index 759fbec..547595e 100644 --- a/source/WorldServer/Commands/Commands.h +++ b/source/WorldServer/Commands/Commands.h @@ -311,14 +311,14 @@ public: void Command_StopFollow(Client* client, Seperator* sep); void Command_Grid(Client* client, Seperator* sep); void Command_Guild(Client* client, Seperator* sep); - void Command_CreateGuild(Client* client); + void Command_CreateGuild(Client* client, Seperator* sep); void Command_SetGuildOfficerNote(Client* client, Seperator* sep); void Command_SetGuildMemberNote(Client* client, Seperator* sep); void Command_OfficerSay(Client* client, Seperator* sep); void Command_GuildSay(Client* client, Seperator* sep); void Command_Guilds(Client* client); void Command_GuildsAdd(Client* client, Seperator* sep); - void Command_GuildsCreate(Client* client, Seperator* sep); + void Command_GuildsCreate(Client* client, Seperator* sep, bool prompted_dialog = false); void Command_GuildsDelete(Client* client, Seperator* sep); void Command_GuildsList(Client* client); void Command_GuildsRemove(Client* client, Seperator* sep); diff --git a/source/WorldServer/LuaFunctions.cpp b/source/WorldServer/LuaFunctions.cpp index e3b0a7d..b5667e2 100644 --- a/source/WorldServer/LuaFunctions.cpp +++ b/source/WorldServer/LuaFunctions.cpp @@ -14313,3 +14313,104 @@ int EQ2Emu_lua_CreatePersistedRespawn(lua_State* state) { return 1; } + +int EQ2Emu_lua_CreateChoiceWindow(lua_State* state) { + if (!lua_interface) + return 0; + Spawn* npc = lua_interface->GetSpawn(state); + Spawn* spawn = lua_interface->GetSpawn(state, 2); + std::string windowTextPrompt = lua_interface->GetStringValue(state, 3); + std::string acceptText = lua_interface->GetStringValue(state, 4); + std::string acceptCommand = lua_interface->GetStringValue(state, 5); + std::string declineText = lua_interface->GetStringValue(state, 6); + std::string declineCommand = lua_interface->GetStringValue(state, 7); + int32 time = lua_interface->GetInt32Value(state, 8); + int8 textBox = lua_interface->GetInt8Value(state, 9); + int8 textBoxRequired = lua_interface->GetInt8Value(state, 10); + int32 maxLength = lua_interface->GetInt32Value(state, 11); + lua_interface->ResetFunctionStack(state); + if(!npc || !npc->IsNPC()) + { + lua_interface->LogError("%s: LUA CreateChoiceWindow command error: npc is not valid, either does not exist or is not a npc", lua_interface->GetScriptName(state)); + lua_interface->SetBooleanValue(state, false); + return 1; + } + + if(!spawn || !spawn->IsPlayer()) + { + lua_interface->LogError("%s: LUA CreateChoiceWindow command error: spawn is not valid, either does not exist or is not a player", lua_interface->GetScriptName(state)); + lua_interface->SetBooleanValue(state, false); + return 1; + } + + Client* client = ((Player*)spawn)->GetClient(); + + if(client) { + bool success = client->SendDialogChoice(npc->GetID(), windowTextPrompt, acceptText, acceptCommand, declineText, declineCommand, time, textBox, textBoxRequired, maxLength); + lua_interface->SetBooleanValue(state, success); + return 1; + } + lua_interface->SetBooleanValue(state, false); + return 1; +} + + +int EQ2Emu_lua_ClearChoice(lua_State* state) { + if (!lua_interface) + return 0; + Spawn* spawn = lua_interface->GetSpawn(state); + std::string commandToClear = lua_interface->GetStringValue(state, 2); + int8 clearDecline = lua_interface->GetInt8Value(state, 3); + lua_interface->ResetFunctionStack(state); + if(!spawn || !spawn->IsPlayer()) + { + lua_interface->LogError("%s: LUA ClearChoice command error: spawn is not valid, either does not exist or is not a player", lua_interface->GetScriptName(state)); + lua_interface->SetBooleanValue(state, false); + return 1; + } + + Client* client = ((Player*)spawn)->GetClient(); + + if(client) { + bool success = false; + + if(clearDecline) { + success = client->dialog_manager.clearDecline(commandToClear); + } + else { + success = client->dialog_manager.clearAccept(commandToClear); + } + lua_interface->SetBooleanValue(state, success); + return 1; + } + lua_interface->SetBooleanValue(state, false); + return 1; +} + +int EQ2Emu_lua_GetChoiceSpawnID(lua_State* state) { + if (!lua_interface) + return 0; + Spawn* spawn = lua_interface->GetSpawn(state); + std::string commandMatch = lua_interface->GetStringValue(state, 2); + int8 declineValue = lua_interface->GetInt8Value(state, 3); + lua_interface->ResetFunctionStack(state); + if(!spawn || !spawn->IsPlayer()) + { + lua_interface->LogError("%s: LUA GetChoiceSpawnID command error: spawn is not valid, either does not exist or is not a player", lua_interface->GetScriptName(state)); + lua_interface->SetInt32Value(state, 0); + return 1; + } + + Client* client = ((Player*)spawn)->GetClient(); + int32 spawn_id = 0; + if(client) { + if(declineValue) { + spawn_id = client->dialog_manager.getDeclineValue(commandMatch); + } + else { + spawn_id = client->dialog_manager.getAcceptValue(commandMatch); + } + } + lua_interface->SetInt32Value(state, spawn_id); + return 1; +} \ No newline at end of file diff --git a/source/WorldServer/LuaFunctions.h b/source/WorldServer/LuaFunctions.h index fb19357..66606d7 100644 --- a/source/WorldServer/LuaFunctions.h +++ b/source/WorldServer/LuaFunctions.h @@ -663,4 +663,8 @@ int EQ2Emu_lua_DespawnByLocationID(lua_State* state); int EQ2Emu_lua_AddRespawn(lua_State* state); int EQ2Emu_lua_CreatePersistedRespawn(lua_State* state); + +int EQ2Emu_lua_CreateChoiceWindow(lua_State* state); +int EQ2Emu_lua_ClearChoice(lua_State* state); +int EQ2Emu_lua_GetChoiceSpawnID(lua_State* state); #endif \ No newline at end of file diff --git a/source/WorldServer/LuaInterface.cpp b/source/WorldServer/LuaInterface.cpp index e152216..af817e9 100644 --- a/source/WorldServer/LuaInterface.cpp +++ b/source/WorldServer/LuaInterface.cpp @@ -1568,6 +1568,10 @@ void LuaInterface::RegisterFunctions(lua_State* state) { lua_register(state,"AddRespawn", EQ2Emu_lua_AddRespawn); lua_register(state,"CreatePersistedRespawn", EQ2Emu_lua_CreatePersistedRespawn); + + lua_register(state,"CreateChoiceWindow", EQ2Emu_lua_CreateChoiceWindow); + lua_register(state,"ClearChoice", EQ2Emu_lua_ClearChoice); + lua_register(state,"GetChoiceSpawnID", EQ2Emu_lua_GetChoiceSpawnID); } void LuaInterface::LogError(const char* error, ...) { diff --git a/source/WorldServer/PlayerGroups.cpp b/source/WorldServer/PlayerGroups.cpp index 698e9a3..ff87a1e 100644 --- a/source/WorldServer/PlayerGroups.cpp +++ b/source/WorldServer/PlayerGroups.cpp @@ -1977,7 +1977,81 @@ void PlayerGroupManager::ClearGroupRaidLooterFlag(int32 groupID) { } } +void PlayerGroupManager::EstablishRaidLevelRange(Client* client, int32* min_level, int32* max_level, int32* avg_level, int32* first_level) { + std::shared_lock lock(MGroups); + if(!client) + return; + + if (!client->GetPlayer()->GetGroupMemberInfo()) { + *min_level = *max_level = *avg_level = *first_level = client->GetPlayer()->GetLevel(); + return; + } + int32 groupID = client->GetPlayer()->GetGroupMemberInfo()->group_id; + + if (m_groups.count(groupID) < 1) { + *min_level = *max_level = *avg_level = *first_level = client->GetPlayer()->GetLevel(); + return; + } + + PlayerGroup* group = m_groups[groupID]; + if (group) { + bool isInRaid = group->IsInRaidGroup(group->GetID()); + std::vector raidGroups; + group->GetRaidGroups(&raidGroups); + + if (!isInRaid && raidGroups.size() < 1) { + raidGroups.push_back(group->GetID()); + } + + // Initialize tracking variables + int32 local_min_level = INT32_MAX; + int32 local_max_level = INT32_MIN; + int32 total_levels = 0; + int8 level_count = 0; + + // Get the first player's level + *first_level = client->GetPlayer()->GetLevel(); + + for (auto& groupID : raidGroups) { + group = m_groups[groupID]; + if (!group) + continue; + + group->MGroupMembers.readlock(__FUNCTION__, __LINE__); + deque* members = group->GetMembers(); + + for (auto& memberInfo : *members) { + Entity* member = memberInfo->member; + if (!member || !member->IsPlayer()) + continue; + + if (member->GetZone() != client->GetPlayer()->GetZone()) + continue; + + int32 member_level = member->GetLevel(); + local_min_level = std::min(local_min_level, member_level); + local_max_level = std::max(local_max_level, member_level); + total_levels += member_level; + level_count++; + } + group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__); + } + + // Finalize values with divide-by-zero protection + if (level_count > 0) { + *min_level = local_min_level; + *max_level = local_max_level; + *avg_level = total_levels / level_count; + } + else { + *min_level = *max_level = *avg_level = *first_level = client->GetPlayer()->GetLevel(); + } + } + else { + *min_level = *max_level = *avg_level = *first_level = client->GetPlayer()->GetLevel(); + } +} Entity* PlayerGroup::GetGroupMemberByPosition(Entity* seeker, int32 mapped_position) { Entity* ret = nullptr; diff --git a/source/WorldServer/PlayerGroups.h b/source/WorldServer/PlayerGroups.h index 1a24d6b..2b23c01 100644 --- a/source/WorldServer/PlayerGroups.h +++ b/source/WorldServer/PlayerGroups.h @@ -124,7 +124,7 @@ public: GroupOptions* GetGroupOptions() { return &group_options; } int8 GetLastLooterIndex() { return group_options.last_looted_index; } void SetNextLooterIndex(int8 new_index) { group_options.last_looted_index = new_index; } - + int32 GetID() { return m_id; } void GetRaidGroups(std::vector* groups); @@ -255,6 +255,7 @@ public: void SplitWithGroupOrRaid(Client* client, int32 coin_plat, int32 coin_gold, int32 coin_silver, int32 coin_copper); bool IdentifyMemberInGroupOrRaid(ZoneChangeDetails* details, Client* client, int32 zoneID, int32 instanceID = 0); void ClearGroupRaidLooterFlag(int32 groupID); + void EstablishRaidLevelRange(Client* client, int32* min_level, int32* max_level, int32* avg_level, int32* first_level); private: int32 m_nextGroupID; // Used to generate a new unique id for new groups diff --git a/source/WorldServer/Web/HTTPSClientPool.cpp b/source/WorldServer/Web/HTTPSClientPool.cpp index 108e5a7..9ba784c 100644 --- a/source/WorldServer/Web/HTTPSClientPool.cpp +++ b/source/WorldServer/Web/HTTPSClientPool.cpp @@ -295,6 +295,8 @@ void HandleCreateGuild(boost::property_tree::ptree tree) { bool success = false; int32 guildID = 0; std::string leaderName(""); + bool promptedDialog = false; + int32 spawnID = 0; if (auto successful = tree.get_optional("success")) { success = successful.get(); } @@ -307,6 +309,14 @@ void HandleCreateGuild(boost::property_tree::ptree tree) { leaderName = name.get(); } + if (auto prompt = tree.get_optional("prompted_dialog")) { + promptedDialog = prompt.get(); + } + + if (auto spawnid = tree.get_optional("spawn_id")) { + spawnID = spawnid.get(); + } + if (net.is_primary) { // we send out to peers } @@ -315,6 +325,12 @@ void HandleCreateGuild(boost::property_tree::ptree tree) { Guild* guild = guild_list.GetGuild(guildID); Client* leader = zone_list.GetClientByCharName(leaderName.c_str()); if (leader && guild && !leader->GetPlayer()->GetGuild()) { + if(spawnID) { + Spawn* npc = leader->GetPlayer()->GetZone()->GetSpawnByID(spawnID); + if(promptedDialog && npc && npc->IsNPC()) { + leader->GetCurrentZone()->CallSpawnScript(npc, SPAWN_SCRIPT_CASTED_ON, leader->GetPlayer(), guild->GetName()); + } + } guild->AddNewGuildMember(leader, 0, GUILD_RANK_LEADER); database.SaveGuildMembers(guild); if (leader && leader->GetPlayer()->GetGroupMemberInfo()) { diff --git a/source/WorldServer/Web/PeerManager.cpp b/source/WorldServer/Web/PeerManager.cpp index cdb086f..bc83ef4 100644 --- a/source/WorldServer/Web/PeerManager.cpp +++ b/source/WorldServer/Web/PeerManager.cpp @@ -619,7 +619,7 @@ void PeerManager::sendPeersDisbandGroup(int32 group_id) { } } -bool PeerManager::sendPrimaryCreateGuildRequest(std::string guild_name, std::string leader_name) { +bool PeerManager::sendPrimaryCreateGuildRequest(std::string guild_name, std::string leader_name, bool prompted_dialog, int32 spawnID) { std::shared_ptr primary = getHealthyPrimaryPeerPtr(); if (primary) { boost::property_tree::ptree root; @@ -628,6 +628,8 @@ bool PeerManager::sendPrimaryCreateGuildRequest(std::string guild_name, std::str root.put("peer_web_port", std::to_string(net.GetWebWorldPort())); root.put("guild_name", guild_name); root.put("leader_name", leader_name); + root.put("prompted_dialog", prompted_dialog); + root.put("spawn_id", spawnID); std::ostringstream jsonStream; boost::property_tree::write_json(jsonStream, root); diff --git a/source/WorldServer/Web/PeerManager.h b/source/WorldServer/Web/PeerManager.h index 56649be..484ce14 100644 --- a/source/WorldServer/Web/PeerManager.h +++ b/source/WorldServer/Web/PeerManager.h @@ -206,7 +206,7 @@ public: std::string peerId = "", std::vector* raidGroups = nullptr, bool is_update = false); void sendPeersDisbandGroup(int32 group_id); - bool sendPrimaryCreateGuildRequest(std::string guild_name, std::string leader_name); + bool sendPrimaryCreateGuildRequest(std::string guild_name, std::string leader_name, bool prompted_dialog = false, int32 spawnID = 0); void sendPeersAddGuildMember(int32 character_id, int32 guild_id, std::string invited_by, int32 join_timestamp, int8 rank); void sendPeersRemoveGuildMember(int32 character_id, int32 guild_id, std::string removed_by); void sendPeersCreateGuild(int32 guild_id); diff --git a/source/WorldServer/Web/WorldWeb.cpp b/source/WorldServer/Web/WorldWeb.cpp index 7b2c07c..fa6c0a6 100644 --- a/source/WorldServer/Web/WorldWeb.cpp +++ b/source/WorldServer/Web/WorldWeb.cpp @@ -618,6 +618,7 @@ void World::Web_worldhandle_startzone(const http::request& re int32 zoneId = 0; std::string zoneName(""); bool alwaysLoaded = false; + int32 minLevel = 0, maxLevel = 0, avgLevel = 0, firstLevel = 0; if (auto inst_id = json_tree.get_optional("instance_id")) { instanceId = inst_id.get(); } @@ -633,6 +634,22 @@ void World::Web_worldhandle_startzone(const http::request& re if (auto always_loaded = json_tree.get_optional("always_loaded")) { alwaysLoaded = always_loaded.get(); } + + if (auto level = json_tree.get_optional("min_level")) { + minLevel = level.get(); + } + + if (auto level = json_tree.get_optional("max_level")) { + maxLevel = level.get(); + } + + if (auto level = json_tree.get_optional("avg_level")) { + avgLevel = level.get(); + } + + if (auto level = json_tree.get_optional("first_level")) { + firstLevel = level.get(); + } sint32 success = 0; ZoneChangeDetails details; @@ -642,7 +659,7 @@ void World::Web_worldhandle_startzone(const http::request& re success = 1; } else { - if ((zone_list.GetZoneByInstance(&details, instanceId, zoneId, true, false, false, false))) + if ((zone_list.GetZoneByInstance(&details, instanceId, zoneId, true, false, false, false, minLevel, maxLevel, avgLevel, firstLevel))) success = 1; } } diff --git a/source/WorldServer/World.cpp b/source/WorldServer/World.cpp index 04d0b4b..1930f58 100644 --- a/source/WorldServer/World.cpp +++ b/source/WorldServer/World.cpp @@ -684,7 +684,7 @@ void ZoneList::Remove(ZoneServer* zone) { } } -bool ZoneList::GetZone(ZoneChangeDetails* zone_details, int32 opt_zone_id, std::string opt_zone_name, bool loadZone, bool skip_existing_zones, bool increment_zone, bool check_peers, bool check_instances, bool only_always_loaded, bool skip_self) { +bool ZoneList::GetZone(ZoneChangeDetails* zone_details, int32 opt_zone_id, std::string opt_zone_name, bool loadZone, bool skip_existing_zones, bool increment_zone, bool check_peers, bool check_instances, bool only_always_loaded, bool skip_self, int32 minLevel, int32 maxLevel, int32 avgLevel, int32 firstLevel) { list::iterator zone_iter; ZoneServer* tmp = 0; ZoneServer* ret = 0; @@ -736,6 +736,11 @@ bool ZoneList::GetZone(ZoneChangeDetails* zone_details, int32 opt_zone_id, std:: root.put("zone_name", opt_zone_name); root.put("zone_id", std::to_string(opt_zone_id)); root.put("always_loaded", only_always_loaded); + + root.put("min_level", minLevel); + root.put("max_level", maxLevel); + root.put("avg_level", avgLevel); + root.put("first_level", firstLevel); std::ostringstream jsonStream; boost::property_tree::write_json(jsonStream, root); std::string jsonPayload = jsonStream.str(); @@ -751,7 +756,7 @@ bool ZoneList::GetZone(ZoneChangeDetails* zone_details, int32 opt_zone_id, std:: } else { tmp = new ZoneServer(opt_zone_name.c_str()); - database.LoadZoneInfo(tmp); + database.LoadZoneInfo(tmp, minLevel, maxLevel, avgLevel, firstLevel); tmp->Init(); tmp->SetAlwaysLoaded(only_always_loaded); } @@ -771,7 +776,8 @@ bool ZoneList::GetZone(ZoneChangeDetails* zone_details, int32 opt_zone_id, std:: return (tmp != nullptr) ? true : false; } -bool ZoneList::GetZoneByInstance(ZoneChangeDetails* zone_details, int32 instance_id, int32 zone_id, bool loadZone, bool skip_existing_zones, bool increment_zone, bool check_peers) { +bool ZoneList::GetZoneByInstance(ZoneChangeDetails* zone_details, int32 instance_id, int32 zone_id, bool loadZone, bool skip_existing_zones, bool increment_zone, bool check_peers, + int32 minLevel, int32 maxLevel, int32 avgLevel, int32 firstLevel) { list::iterator zone_iter; ZoneServer* tmp = 0; ZoneServer* ret = 0; @@ -814,6 +820,12 @@ bool ZoneList::GetZoneByInstance(ZoneChangeDetails* zone_details, int32 instance root.put("zone_name", zonename); root.put("zone_id", std::to_string(zone_id)); root.put("always_loaded", false); + + root.put("min_level", minLevel); + root.put("max_level", maxLevel); + root.put("avg_level", avgLevel); + root.put("first_level", firstLevel); + std::ostringstream jsonStream; boost::property_tree::write_json(jsonStream, root); std::string jsonPayload = jsonStream.str(); @@ -834,7 +846,7 @@ bool ZoneList::GetZoneByInstance(ZoneChangeDetails* zone_details, int32 instance if ( instance_id > 0 ) tmp->SetupInstance(instance_id); - database.LoadZoneInfo(tmp); + database.LoadZoneInfo(tmp, minLevel, maxLevel, avgLevel, firstLevel); tmp->Init(); } } diff --git a/source/WorldServer/World.h b/source/WorldServer/World.h index 70a5e2c..0c3ea63 100644 --- a/source/WorldServer/World.h +++ b/source/WorldServer/World.h @@ -419,8 +419,8 @@ class ZoneList { void Add(ZoneServer* zone); void Remove(ZoneServer* zone); - bool GetZone(ZoneChangeDetails* zone_details, int32 opt_zone_id, std::string opt_zone_name = "", bool loadZone = true, bool skip_existing_zones = false, bool increment_zone = true, bool check_peers = true, bool check_instances = false, bool only_always_loaded = false, bool skip_self = false); - bool GetZoneByInstance(ZoneChangeDetails* zone_details, int32 instance_id, int32 zone_id = 0, bool loadZone = true, bool skip_existing_zones = false, bool increment_zone = true, bool check_peers = true); + bool GetZone(ZoneChangeDetails* zone_details, int32 opt_zone_id, std::string opt_zone_name = "", bool loadZone = true, bool skip_existing_zones = false, bool increment_zone = true, bool check_peers = true, bool check_instances = false, bool only_always_loaded = false, bool skip_self = false, int32 minLevel = 0, int32 maxLevel = 0, int32 avgLevel = 0, int32 firstLevel = 0); + bool GetZoneByInstance(ZoneChangeDetails* zone_details, int32 instance_id, int32 zone_id = 0, bool loadZone = true, bool skip_existing_zones = false, bool increment_zone = true, bool check_peers = true, int32 minLevel = 0, int32 maxLevel = 0, int32 avgLevel = 0, int32 firstLevel = 0); bool IsClientConnectedPeer(int32 account_id); //ZoneServer* Get(int32 id, bool loadZone = true, bool skip_existing_zones = false, bool increment_zone = true); diff --git a/source/WorldServer/WorldDatabase.cpp b/source/WorldServer/WorldDatabase.cpp index 9e31bd9..80d3269 100644 --- a/source/WorldServer/WorldDatabase.cpp +++ b/source/WorldServer/WorldDatabase.cpp @@ -2954,9 +2954,11 @@ void WorldDatabase::LoadCharacterFriendsIgnoreList(Player* player) { } } -void WorldDatabase::LoadZoneInfo(ZoneServer* zone){ +void WorldDatabase::LoadZoneInfo(ZoneServer* zone, int32 minLevel, int32 maxLevel, int32 avgLevel, int32 firstLevel){ Query query; int32 ruleset_id; + zone->setGroupRaidLevels(minLevel, maxLevel, avgLevel, firstLevel); + char* escaped = getEscapeString(zone->GetZoneName()); MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT id, file, description, underworld, safe_x, safe_y, safe_z, min_status, min_level, max_level, instance_type+0, shutdown_timer, zone_motd, default_reenter_time, default_reset_time, default_lockout_time, force_group_to_zone, safe_heading, xp_modifier, ruleset_id, expansion_id, weather_allowed, sky_file, can_bind, can_gate, city_zone, can_evac FROM zones where name='%s'",escaped); if(result && mysql_num_rows(result) > 0) { @@ -2999,8 +3001,10 @@ void WorldDatabase::LoadZoneInfo(ZoneServer* zone){ if (zone->IsInstanceZone()) { - if ( zone->GetInstanceID() < 1 ) - zone->SetupInstance(CreateNewInstance(zone->GetZoneID())); + if ( zone->GetInstanceID() < 1 ) { + zone->SetupInstance(CreateNewInstance(zone->GetZoneID(), minLevel, maxLevel, avgLevel, firstLevel)); + zone->setGroupRaidLevels(minLevel, maxLevel, avgLevel, firstLevel); + } else zone->SetupInstance(zone->GetInstanceID()); } @@ -4085,7 +4089,6 @@ void WorldDatabase::UpdateStartingZone(int32 char_id, int8 class_id, int8 race_i instance_id = CreateNewInstance(zone_id); tmp->SetInstanceID(instance_id); LoadZoneInfo(tmp); - instance_id = CreateNewInstance(zone_id); AddCharacterInstance(char_id, instance_id, string(tmp->GetZoneName()), tmp->GetInstanceType(), Timer::GetUnixTimeStamp(), 0, tmp->GetDefaultLockoutTime(), tmp->GetDefaultReenterTime()); safe_delete(tmp); } @@ -5935,13 +5938,13 @@ bool WorldDatabase::UpdateInstancedSpawnRemoved(int32 spawn_location_entry_id, i return false; } -int32 WorldDatabase::CreateNewInstance(int32 zone_id) +int32 WorldDatabase::CreateNewInstance(int32 zone_id, int32 playersMinLevel, int32 playersMaxLevel, int32 playersavgLevel, int32 playersfirstLevel) { int32 ret = 0; LogWrite(INSTANCE__DEBUG, 0, "Instance", "Creating new instance for zone: %u ", zone_id); - if( !database_new.Query("INSERT INTO instances (zone_id) VALUES (%u)", zone_id) ) + if( !database_new.Query("INSERT INTO instances (zone_id, player_minlevel, player_maxlevel, player_avglevel, player_firstlevel) VALUES (%u, %u, %u, %u, %u)", zone_id, playersMinLevel, playersMaxLevel, playersavgLevel, playersfirstLevel) ) LogWrite(INSTANCE__ERROR, 0, "Instance", "Error in CreateNewInstance() '%s': %i", database_new.GetErrorMsg(), database_new.GetError()); else ret = database_new.LastInsertID(); diff --git a/source/WorldServer/WorldDatabase.h b/source/WorldServer/WorldDatabase.h index ee964ca..e572fd2 100644 --- a/source/WorldServer/WorldDatabase.h +++ b/source/WorldServer/WorldDatabase.h @@ -217,7 +217,7 @@ public: void LoadPlayerAA(Player *player); void LoadCharacterQuestProgress(Client* client); void LoadCharacterFriendsIgnoreList(Player* player); - void LoadZoneInfo(ZoneServer* zone); + void LoadZoneInfo(ZoneServer* zone, int32 minLevel=0, int32 maxLevel=0, int32 avgLevel=0, int32 firstLevel=0); void LoadZoneInfo(ZoneInfo* zone_info); int32 GetZoneID(const char* name); void SaveZoneInfo(int32 zone_id, const char* field, sint32 value); @@ -398,7 +398,7 @@ public: // Zone Instance DB Functions map* GetInstanceRemovedSpawns(int32 instance_id, int8 type); - int32 CreateNewInstance(int32 zone_id); + int32 CreateNewInstance(int32 zone_id, int32 playersMinLevel=0, int32 playersMaxLevel=0, int32 playersavgLevel=0, int32 playersfirstLevel=0); //int32 AddCharacterInstance(int32 char_id, int32 instance_id, int32 grant_reenter_time_left=0, int32 grant_reset_time_left=0, int32 lockout_time=0); int32 AddCharacterInstance(int32 char_id, int32 instance_id, string zone_name, int8 instance_type, int32 last_success, int32 last_failure, int32 success_lockout, int32 failure_lockout); bool UpdateCharacterInstanceTimers(int32 char_id, int32 instance_id, int32 lockout_time=0, int32 reset_time=0, int32 reenter_time=0 ); diff --git a/source/WorldServer/client.cpp b/source/WorldServer/client.cpp index 5991c24..d69fc2b 100644 --- a/source/WorldServer/client.cpp +++ b/source/WorldServer/client.cpp @@ -4152,7 +4152,9 @@ void Client::SetCurrentZoneByInstanceID(int32 id, int32 zoneid) { current_zone->RemoveSpawn(player, false, true, true, true, true); } ZoneChangeDetails zone_details; - if (zone_list.GetZoneByInstance(&zone_details, id, zoneid, true, false, true, false)) { + int32 minLevel = 0, maxLevel = 0, avgLevel = 0, firstLevel = 0; + world.GetGroupManager()->EstablishRaidLevelRange(this, &minLevel, &maxLevel, &avgLevel, &firstLevel); + if (zone_list.GetZoneByInstance(&zone_details, id, zoneid, true, false, true, false, minLevel, maxLevel, avgLevel, firstLevel)) { SetCurrentZone((ZoneServer*)zone_details.zonePtr); } else { @@ -4649,6 +4651,9 @@ bool Client::IdentifyInstance(ZoneChangeDetails* zone_details, int32 zoneID) { if (instanceType < 1) return false; + int32 minLevel = 0, maxLevel = 0, avgLevel = 0, firstLevel = 0; + world.GetGroupManager()->EstablishRaidLevelRange(this, &minLevel, &maxLevel, &avgLevel, &firstLevel); + bool foundZone = false; InstanceData* data = GetPlayer()->GetCharacterInstances()->FindInstanceByZoneID(zoneID); if (data) { @@ -4659,7 +4664,7 @@ bool Client::IdentifyInstance(ZoneChangeDetails* zone_details, int32 zoneID) { } // Need to update `character_instances` table with new timestamps (for persistent) and instance id's - foundZone = zone_list.GetZoneByInstance(zone_details, data->instance_id, zoneID, true, false, false); + foundZone = zone_list.GetZoneByInstance(zone_details, data->instance_id, zoneID, true, false, false, true, minLevel, maxLevel, avgLevel, firstLevel); // if we got an instance_zone and the instance_id from the data is 0 or data instance id is not the same as the zone instance id then update values if (foundZone && (data->instance_id == 0 || data->instance_id != zone_details->instanceId)) { @@ -4685,6 +4690,9 @@ bool Client::TryZoneInstance(int32 zoneID, bool zone_coords_valid) { // determine if this is a group instanced zone that already exists foundZone = world.GetGroupManager()->IdentifyMemberInGroupOrRaid(&zone_details, this, zoneID); + int32 minLevel = 0, maxLevel = 0, avgLevel = 0, firstLevel = 0; + world.GetGroupManager()->EstablishRaidLevelRange(this, &minLevel, &maxLevel, &avgLevel, &firstLevel); + if (foundZone) { InstanceData* data = nullptr; if (zone_details.instanceId) @@ -4720,7 +4728,7 @@ bool Client::TryZoneInstance(int32 zoneID, bool zone_coords_valid) { case GROUP_LOCKOUT_INSTANCE: case RAID_LOCKOUT_INSTANCE: { - if ((foundZone = zone_list.GetZoneByInstance(&zone_details, 0, zoneID))) { + if ((foundZone = zone_list.GetZoneByInstance(&zone_details, 0, zoneID, true, false, true, true, minLevel, maxLevel, avgLevel, firstLevel))) { // once lockout instance zone shuts down you can't renenter if you have a lockout or if you don't you get a new zone // so delete `instances` entry for the zone when it shuts down. int32 db_id = database.AddCharacterInstance(GetPlayer()->GetCharacterID(), zone_details.instanceId, zone_details.zoneName, zone_details.instanceType, 0, 0, zone_details.defaultLockoutTime, zone_details.defaultReenterTime); @@ -4734,7 +4742,7 @@ bool Client::TryZoneInstance(int32 zoneID, bool zone_coords_valid) { case GROUP_PERSIST_INSTANCE: case RAID_PERSIST_INSTANCE: { - if ((foundZone = zone_list.GetZoneByInstance(&zone_details, 0, zoneID))) { + if ((foundZone = zone_list.GetZoneByInstance(&zone_details, 0, zoneID, true, false, true, true, minLevel, maxLevel, avgLevel, firstLevel))) { int32 db_id = database.AddCharacterInstance(GetPlayer()->GetCharacterID(), zone_details.instanceId, zone_details.zoneName, zone_details.instanceType, Timer::GetUnixTimeStamp(), 0, zone_details.defaultLockoutTime, zone_details.defaultReenterTime); if (db_id > 0) @@ -4750,7 +4758,7 @@ bool Client::TryZoneInstance(int32 zoneID, bool zone_coords_valid) { if (instance_zone) { // Check the current population against the max population, if greater or equal start a new version if (instance_zone->GetClientCount() >= rule_manager.GetZoneRule(GetCurrentZoneID(), R_Zone, MaxPlayers)->GetInt32()) { - foundZone = zone_list.GetZoneByInstance(&zone_details, 0, zoneID); + foundZone = zone_list.GetZoneByInstance(&zone_details, 0, zoneID, true, false, true, true, minLevel, maxLevel, avgLevel, firstLevel); } else { peer_manager.setZonePeerDataSelf(&zone_details, std::string(instance_zone->GetZoneFile()), std::string(instance_zone->GetZoneName()), @@ -4762,7 +4770,7 @@ bool Client::TryZoneInstance(int32 zoneID, bool zone_coords_valid) { } } else { - foundZone = zone_list.GetZoneByInstance(&zone_details, 0, zoneID); + foundZone = zone_list.GetZoneByInstance(&zone_details, 0, zoneID, true, false, true, true, minLevel, maxLevel, avgLevel, firstLevel); } break; @@ -4779,7 +4787,7 @@ bool Client::TryZoneInstance(int32 zoneID, bool zone_coords_valid) { case QUEST_INSTANCE: { - foundZone = zone_list.GetZoneByInstance(&zone_details, 0, zoneID); + foundZone = zone_list.GetZoneByInstance(&zone_details, 0, zoneID, true, false, true, true, minLevel, maxLevel, avgLevel, firstLevel); break; /* ALTER TABLE `zones` CHANGE COLUMN `instance_type` `instance_type` ENUM('NONE','GROUP_LOCKOUT_INSTANCE','GROUP_PERSIST_INSTANCE','RAID_LOCKOUT_INSTANCE','RAID_PERSIST_INSTANCE','SOLO_LOCKOUT_INSTANCE','SOLO_PERSIST_INSTANCE','TRADESKILL_INSTANCE','PUBLIC_INSTANCE','PERSONAL_HOUSE_INSTANCE','GUILD_HOUSE_INSTANCE','QUEST_INSTANCE') NOT NULL DEFAULT 'NONE' COLLATE 'latin1_general_ci' AFTER `start_zone`; @@ -4938,7 +4946,9 @@ bool Client::CheckZoneAccess(const char* zoneName) { void Client::Zone(int32 instanceid, bool set_coords, bool byInstanceID, bool is_spell) { ZoneChangeDetails zone_details; - if (zone_list.GetZoneByInstance(&zone_details, instanceid, 0)) { + int32 minLevel = 0, maxLevel = 0, avgLevel = 0, firstLevel = 0; + world.GetGroupManager()->EstablishRaidLevelRange(this, &minLevel, &maxLevel, &avgLevel, &firstLevel); + if (zone_list.GetZoneByInstance(&zone_details, instanceid, 0, true, false, true, true, minLevel, maxLevel, avgLevel, firstLevel)) { Zone(&zone_details, (ZoneServer*)zone_details.zonePtr, set_coords, is_spell); } @@ -5102,7 +5112,11 @@ void Client::Zone(const char* new_zone, bool set_coords, bool is_spell) std::string camelCaseName = database.GetZoneName(zone_id); InstanceData* data = GetPlayer()->GetCharacterInstances()->FindInstanceByZoneID(zone_id); - if ((data && zone_list.GetZoneByInstance(&zone_details, data->instance_id, zone_id)) || zone_list.GetZone(&zone_details, 0, camelCaseName)) { + + int32 minLevel = 0, maxLevel = 0, avgLevel = 0, firstLevel = 0; + world.GetGroupManager()->EstablishRaidLevelRange(this, &minLevel, &maxLevel, &avgLevel, &firstLevel); + + if ((data && zone_list.GetZoneByInstance(&zone_details, data->instance_id, zone_id, true, false, true, true, minLevel, maxLevel, avgLevel, firstLevel)) || zone_list.GetZone(&zone_details, 0, camelCaseName)) { Zone(&zone_details, (ZoneServer*)zone_details.zonePtr, set_coords, is_spell); } } @@ -13402,4 +13416,41 @@ void Client::SendReceiveOffer(Client* target_client, int8 type, std::string name target_client->QueuePacket(packet->serialize()); } safe_delete(packet); +} + +bool Client::SendDialogChoice(int32 spawnID, const std::string& windowTextPrompt, const std::string& acceptText, const std::string& acceptCommand, const std::string& declineText, const std::string& declineCommand, int32 time, int8 textBox, int8 textBoxRequired, int32 maxLength) { + PacketStruct* p = configReader.getStruct("WS_ChoiceWindow", GetVersion()); + if (!p) { + LogWrite(CCLIENT__ERROR, 0, "Client", "CreateChoiceWindow command error: WS_ChoiceWindow packet does not exist for client version %u", GetVersion()); + return false; + } + + bool successAccept = true; + bool successDecline = true; + + if(acceptCommand.size() > 0) + successAccept = dialog_manager.addAccept(acceptCommand, spawnID, time); + + if(declineCommand.size() > 0) + successDecline = dialog_manager.addDecline(declineCommand, spawnID, time); + + if(!successAccept || !successDecline) { // failed to successfully add command + LogWrite(CCLIENT__ERROR, 0, "Client", "CreateChoiceWindow command error: Window has a conflict with accept (%s) %u or decline (%s) %u. Call ClearChoice(Player, Command, x) x being 0 for accept 1 for decline commands.", acceptCommand.c_str(), successAccept, declineCommand.c_str(), successDecline); + return false; + } + + p->setMediumStringByName("text", windowTextPrompt.c_str()); + p->setMediumStringByName("accept_text", acceptText.c_str()); + p->setMediumStringByName("accept_command", acceptCommand.c_str()); + p->setMediumStringByName("cancel_text", declineText.c_str()); + p->setMediumStringByName("cancel_command", declineCommand.c_str()); + p->setDataByName("time", time); + p->setDataByName("text_box", textBox); + p->setDataByName("text_required", textBoxRequired); + p->setDataByName("max_length", maxLength); + + QueuePacket(p->serialize()); + safe_delete(p); + + return true; } \ No newline at end of file diff --git a/source/WorldServer/client.h b/source/WorldServer/client.h index 7bba81b..6e69eea 100644 --- a/source/WorldServer/client.h +++ b/source/WorldServer/client.h @@ -1,21 +1,21 @@ -/* - EQ2Emulator: Everquest II Server Emulator - Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net) +/* + EQ2Emulator: Everquest II Server Emulator + Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net) - This file is part of EQ2Emulator. + This file is part of EQ2Emulator. - EQ2Emulator 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, either version 3 of the License, or - (at your option) any later version. + EQ2Emulator 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, either version 3 of the License, or + (at your option) any later version. - EQ2Emulator is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + EQ2Emulator is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see . + You should have received a copy of the GNU General Public License + along with EQ2Emulator. If not, see . */ #ifndef CLIENT_H #define CLIENT_H @@ -24,6 +24,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include "../common/EQStream.h" #include "../common/timer.h" @@ -61,13 +67,13 @@ struct GroupOptions; #define MAIL_TYPE_SPAM 1 #define MAIL_TYPE_GM 2 -struct QueuedQuest{ +struct QueuedQuest { int32 quest_id; int32 step; bool display_quest_helper; }; -struct BuyBackItem{ +struct BuyBackItem { int32 item_id; int32 unique_id; int16 quantity; @@ -75,7 +81,7 @@ struct BuyBackItem{ bool save_needed; }; -struct MacroData{ +struct MacroData { string name; string text; int16 icon; @@ -107,7 +113,7 @@ struct MailWindow { int32 coin_silver; int32 coin_gold; int32 coin_plat; - Item* item; + Item* item; int32 char_item_id; int32 stack; }; @@ -150,22 +156,101 @@ struct WaypointInfo { }; +class DialogManager { +public: + // Add accept string with int32 id and a timer + bool addAccept(const std::string& key, int32 id, int32 seconds) { + std::lock_guard lock(mutex_); + if (acceptMap_.count(key) == 0) { + acceptMap_[key] = id; + if (seconds) + startTimer(key, seconds, true); // true indicates it's an accept key + return true; + } + return false; // Duplicate found in either map + } + + // Add decline string with int32 id and a timer + bool addDecline(const std::string& key, int32 id, int32 seconds) { + std::lock_guard lock(mutex_); + if (declineMap_.count(key) == 0) { + declineMap_[key] = id; + if (seconds) + startTimer(key, seconds, false); // false indicates it's a decline key + return true; + } + return false; // Duplicate found in either map + } + + // Clear a specific accept string + bool clearAccept(const std::string& key) { + std::lock_guard lock(mutex_); + return acceptMap_.erase(key) > 0; + } + + // Clear a specific decline string + bool clearDecline(const std::string& key) { + std::lock_guard lock(mutex_); + return declineMap_.erase(key) > 0; + } + + int32 getAcceptValue(const std::string& key) { + std::lock_guard lock(mutex_); + if (acceptMap_.count(key)) { + return acceptMap_.at(key); + } + return 0; // Key not found + } + + int32 getDeclineValue(const std::string& key) { + std::lock_guard lock(mutex_); + if (declineMap_.count(key)) { + return declineMap_.at(key); + } + return 0; // Key not found + } + + // Check if a dialog is active + bool isDialogActive(const std::string& key) { + std::lock_guard lock(mutex_); + return acceptMap_.count(key) > 0 || declineMap_.count(key) > 0; + } + +private: + std::map acceptMap_; + std::map declineMap_; + std::mutex mutex_; + + void startTimer(const std::string& key, int32 seconds, bool isAccept) { + std::thread([this, key, seconds, isAccept]() { + std::this_thread::sleep_for(std::chrono::seconds(seconds)); + std::lock_guard lock(mutex_); + if (isAccept) { + acceptMap_.erase(key); + } + else { + declineMap_.erase(key); + } + }).detach(); + } +}; + class Client { public: Client(EQStream* ieqs); - ~Client(); - + ~Client(); + void RemoveClientFromZone(); bool Process(bool zone_process = false); void Disconnect(bool send_disconnect = true); - void SetConnected(bool val){ connected = val; } - bool IsConnected(){ return connected; } - bool IsReadyForSpawns(){ return ready_for_spawns; } + void SetConnected(bool val) { connected = val; } + bool IsConnected() { return connected; } + bool IsReadyForSpawns() { return ready_for_spawns; } bool IsReadyForUpdates() { return ready_for_updates; } - bool IsZoning(){ return client_zoning; } + bool IsZoning() { return client_zoning; } void SetReadyForUpdates(); void SetReadyForSpawns(bool val); - void QueuePacket(EQ2Packet* app, bool attemptedCombine=false); + void QueuePacket(EQ2Packet* app, bool attemptedCombine = false); void SendLoginInfo(); int8 GetMessageChannelColor(int8 channel_type); void HandleTellMessage(const char* fromName, const char* message, const char* to, int32 current_language_id); @@ -174,12 +259,12 @@ public: void SendSpellUpdate(Spell* spell, bool add_silently = false, bool add_to_hotbar = true); void Zone(ZoneChangeDetails* new_zone, ZoneServer* opt_zone = nullptr, bool set_coords = true, bool is_spell = false); void Zone(const char* new_zone, bool set_coords = true, bool is_spell = false); - void Zone(int32 instanceid, bool set_coords = true, bool byInstanceID=false, bool is_spell = false); + void Zone(int32 instanceid, bool set_coords = true, bool byInstanceID = false, bool is_spell = false); void ApproveZone(); void SendZoneInfo(); void SendZoneSpawns(); void HandleVerbRequest(EQApplicationPacket* app); - void SendControlGhost(int32 send_id=0xFFFFFFFF, int8 unknown2=0); + void SendControlGhost(int32 send_id = 0xFFFFFFFF, int8 unknown2 = 0); void SendCharInfo(); void SendLoginDeniedBadVersion(); void SendCharPOVGhost(); @@ -187,20 +272,20 @@ public: float DistanceFrom(Client* client); void SendDefaultGroupOptions(); bool HandleLootItemByID(Spawn* entity, int32 item_id, Spawn* target); - bool HandleLootItem(Spawn* entity, Item* item, Spawn* target=nullptr, bool overrideLootRestrictions = false); + bool HandleLootItem(Spawn* entity, Item* item, Spawn* target = nullptr, bool overrideLootRestrictions = false); void HandleLootItemRequestPacket(EQApplicationPacket* app); void HandleSkillInfoRequest(EQApplicationPacket* app); void HandleExamineInfoRequest(EQApplicationPacket* app); void HandleQuickbarUpdateRequest(EQApplicationPacket* app); - void SendPopupMessage(int8 unknown, const char* text, const char* type, float size, int8 red, int8 green, int8 blue); + void SendPopupMessage(int8 unknown, const char* text, const char* type, float size, int8 red, int8 green, int8 blue); void PopulateSkillMap(); void ChangeLevel(int16 old_level, int16 new_level); void ChangeTSLevel(int16 old_level, int16 new_level); bool Summon(const char* search_name); std::string IdentifyInstanceLockout(int32 zoneID, bool displayClient = true); bool IdentifyInstance(ZoneChangeDetails* zone_details, int32 zoneID); - bool TryZoneInstance(int32 zoneID, bool zone_coords_valid=false); - bool GotoSpawn(const char* search_name, bool forceTarget=false); + bool TryZoneInstance(int32 zoneID, bool zone_coords_valid = false); + bool GotoSpawn(const char* search_name, bool forceTarget = false); void DisplayDeadWindow(); void HandlePlayerRevive(int32 point_id); void Bank(Spawn* banker, bool cancel = false); @@ -208,23 +293,23 @@ public: bool BankWithdrawalNoBanker(int64 amount); bool BankHasCoin(int64 amount); void BankDeposit(int64 amount); - Spawn* GetBanker(); + Spawn* GetBanker(); void SetBanker(Spawn* in_banker); bool AddItem(int32 item_id, int16 quantity = 0, AddItemType type = AddItemType::NOT_SET); bool AddItem(Item* item, bool* item_deleted = 0, AddItemType type = AddItemType::NOT_SET); bool AddItemToBank(int32 item_id, int16 quantity = 0); bool AddItemToBank(Item* item); void UnequipItem(int16 index, sint32 bag_id = -999, int8 to_slot = 255, int8 appearance_equip = 0); - bool RemoveItem(Item *item, int16 quantity, bool force_override_no_delete = false); + bool RemoveItem(Item* item, int16 quantity, bool force_override_no_delete = false); void ProcessTeleport(Spawn* spawn, vector* destinations, int32 transport_id = 0, bool is_spell = false); - void ProcessTeleportLocation(EQApplicationPacket* app); + void ProcessTeleportLocation(EQApplicationPacket* app); void UpdateCharacterInstances(); void SetLastSavedTimeStamp(int32 unixts) { last_saved_timestamp = unixts; } int32 GetLastSavedTimeStamp() { return last_saved_timestamp; } bool CheckZoneAccess(const char* zoneName); - + ZoneServer* GetCurrentZone(); int32 GetCurrentZoneID(); void SetCurrentZoneByInstanceID(int32 id, int32 zoneid); @@ -235,46 +320,46 @@ public: zoning_destination = zone; } ZoneServer* GetZoningDestination() { return zoning_destination; } - Player* GetPlayer(){ return player; } - EQStream* getConnection(){ return eqs; } - void setConnection(EQStream* ieqs){ eqs = ieqs; } + Player* GetPlayer() { return player; } + EQStream* getConnection() { return eqs; } + void setConnection(EQStream* ieqs) { eqs = ieqs; } - inline int32 GetIP() { return ip; } - inline int16 GetPort() { return port; } - inline int32 WaitingForBootup() { return pwaitingforbootup; } - inline int32 GetCharacterID() { return character_id; } - inline int32 GetAccountID() { return account_id; } - inline const char* GetAccountName() { return account_name; } - inline sint16 GetAdminStatus() { return admin_status; } - inline int16 GetVersion() { return version; } - void SetNameCRC(int32 val){ name_crc = val; } - int32 GetNameCRC(){ return name_crc; } + inline int32 GetIP() { return ip; } + inline int16 GetPort() { return port; } + inline int32 WaitingForBootup() { return pwaitingforbootup; } + inline int32 GetCharacterID() { return character_id; } + inline int32 GetAccountID() { return account_id; } + inline const char* GetAccountName() { return account_name; } + inline sint16 GetAdminStatus() { return admin_status; } + inline int16 GetVersion() { return version; } + void SetNameCRC(int32 val) { name_crc = val; } + int32 GetNameCRC() { return name_crc; } - void SetVersion(int16 new_version){ version = new_version; } + void SetVersion(int16 new_version) { version = new_version; } void SetAccountID(int32 in_accountid) { account_id = in_accountid; } void SetCharacterID(int32 in_characterid) { character_id = in_characterid; } void SetAdminStatus(sint16 in_status) { admin_status = in_status; } - - void DetermineCharacterUpdates ( ); - void UpdateTimeStampFlag ( int8 flagType ) + void DetermineCharacterUpdates(); + + void UpdateTimeStampFlag(int8 flagType) { - if(! (timestamp_flag & flagType ) ) - timestamp_flag |= flagType; + if (!(timestamp_flag & flagType)) + timestamp_flag |= flagType; } - int8 GetTimeStampFlag ( ) { return timestamp_flag; } + int8 GetTimeStampFlag() { return timestamp_flag; } bool UpdateQuickbarNeeded(); void Save(); bool remove_from_list; void CloseLoot(int32 spawn_id); void SendLootResponsePacket(int32 total_coins, vector* items, Spawn* entity, bool ignore_loot_tier = false); - void LootSpawnRequest(Spawn* entity, bool attemptDisarm=true); + void LootSpawnRequest(Spawn* entity, bool attemptDisarm = true); bool LootSpawnByMethod(Spawn* entity); - void OpenChest(Spawn* entity, bool attemptDisarm=true); - void CastGroupOrSelf(Entity* source, uint32 spellID, uint32 spellTier=1, float restrictiveRadius=0.0f); + void OpenChest(Spawn* entity, bool attemptDisarm = true); + void CastGroupOrSelf(Entity* source, uint32 spellID, uint32 spellTier = 1, float restrictiveRadius = 0.0f); void CheckPlayerQuestsKillUpdate(Spawn* spawn); void CheckPlayerQuestsChatUpdate(Spawn* spawn); void CheckPlayerQuestsItemUpdate(Item* item); @@ -291,12 +376,12 @@ public: void SendQuestFailure(Quest* quest); void SendQuestUpdateStep(Quest* quest, int32 step, bool display_quest_helper = true); void SendQuestUpdateStepImmediately(Quest* quest, int32 step, bool display_quest_helper = true); - void DisplayQuestRewards(Quest* quest, int64 coin, vector* rewards=0, vector* selectable_rewards=0, map* factions=0, const char* header="Quest Reward!", int32 status_points=0, const char* text=0, bool was_displayed = false); - void PopulateQuestRewardItems(vector * items, PacketStruct* packet, std::string num_rewards_str = "num_rewards", std::string reward_id_str = "reward_id" , std::string item_str = "item"); + void DisplayQuestRewards(Quest* quest, int64 coin, vector* rewards = 0, vector* selectable_rewards = 0, map* factions = 0, const char* header = "Quest Reward!", int32 status_points = 0, const char* text = 0, bool was_displayed = false); + void PopulateQuestRewardItems(vector * items, PacketStruct* packet, std::string num_rewards_str = "num_rewards", std::string reward_id_str = "reward_id", std::string item_str = "item"); void DisplayQuestComplete(Quest* quest, bool tempReward = false, std::string customDescription = string(""), bool was_displayed = false); void DisplayRandomizeFeatures(int32 features); void AcceptQuestReward(Quest* quest, int32 item_id); - Quest* GetPendingQuestAcceptance(int32 item_id); + Quest* GetPendingQuestAcceptance(int32 item_id); void DisplayConversation(int32 conversation_id, int32 spawn_id, vector* conversations, const char* text, const char* mp3, int32 key1, int32 key2, int8 language = 0, int8 can_close = 1); void DisplayConversation(Item* item, vector* conversations, const char* text, int8 type, const char* mp3 = 0, int32 key1 = 0, int32 key2 = 0, int8 language = 0, int8 can_close = 1); void DisplayConversation(Spawn* src, int8 type, vector* conversations, const char* text, const char* mp3 = 0, int32 key1 = 0, int32 key2 = 0, int8 language = 0, int8 can_close = 1); @@ -306,16 +391,16 @@ public: void AddCombineSpawn(Spawn* spawn); void RemoveCombineSpawn(Spawn* spawn); void SaveCombineSpawns(const char* name = 0); - Spawn* GetCombineSpawn(); + Spawn* GetCombineSpawn(); bool ShouldTarget(); void TargetSpawn(Spawn* spawn); void ReloadQuests(); - int32 GetCurrentQuestID(){ return current_quest_id; } + int32 GetCurrentQuestID() { return current_quest_id; } void SetLuaDebugClient(bool val); void SetMerchantTransaction(Spawn* spawn); - Spawn* GetMerchantTransaction(); + Spawn* GetMerchantTransaction(); void SetMailTransaction(Spawn* spawn); - Spawn* GetMailTransaction(); + Spawn* GetMailTransaction(); void PlaySound(const char* name); void SendBuyMerchantList(bool sell = false); void SendSellMerchantList(bool sell = false); @@ -332,7 +417,7 @@ public: void RepairItem(int32 item_id); void RepairAllItems(); void AddBuyBack(int32 unique_id, int32 item_id, int16 quantity, int32 price, bool save_needed = true); - deque* GetBuyBacks(); + deque* GetBuyBacks(); vector* GetRepairableItems(); vector* GetItemsByEffectType(ItemEffectType type, ItemEffectType secondary_effect = NO_EFFECT_TYPE); void SendMailList(); @@ -360,29 +445,29 @@ public: void SetPlayer(Player* new_player); void AddPendingQuestAcceptReward(Quest* quest); - void AddPendingQuestReward(Quest* quest, bool update=true, bool is_temporary = false, std::string description = std::string("")); + void AddPendingQuestReward(Quest* quest, bool update = true, bool is_temporary = false, std::string description = std::string("")); bool HasQuestRewardQueued(int32 quest_id, bool is_temporary, bool is_collection); - void QueueQuestReward(int32 quest_id, bool is_temporary, bool is_collection, bool has_displayed, int64 tmp_coin, int32 tmp_status, std::string description, bool db_saved=false, int32 index=0); + void QueueQuestReward(int32 quest_id, bool is_temporary, bool is_collection, bool has_displayed, int64 tmp_coin, int32 tmp_status, std::string description, bool db_saved = false, int32 index = 0); void RemoveQueuedQuestReward(); void AddPendingQuestUpdate(int32 quest_id, int32 step_id, int32 progress = 0xFFFFFFFF); - void ProcessQuestUpdates(); + void ProcessQuestUpdates(); void AddWaypoint(const char* waypoint_name, int8 waypoint_category, int32 spawn_id); void BeginWaypoint(const char* waypoint_name, float x, float y, float z); void InspectPlayer(Player* player_to_inspect); void SetPendingGuildInvite(Guild* guild, Player* invited_by = 0); - PendingGuildInvite* GetPendingGuildInvite() {return &pending_guild_invite;} + PendingGuildInvite* GetPendingGuildInvite() { return &pending_guild_invite; } void ShowClaimWindow(); void ShowGuildSearchWindow(); void CheckQuestQueue(); - void ShowDressingRoom(Item *item, sint32 crc); + void ShowDressingRoom(Item* item, sint32 crc); void SendCollectionList(); - bool SendCollectionsForItem(Item *item); - void HandleCollectionAddItem(int32 collection_id, Item *item); - void DisplayCollectionComplete(Collection *collection); + bool SendCollectionsForItem(Item* item); + void HandleCollectionAddItem(int32 collection_id, Item* item); + void DisplayCollectionComplete(Collection* collection); void HandInCollections(); - void AcceptCollectionRewards(Collection *collection, int32 selectable_item_id = 0); + void AcceptCollectionRewards(Collection* collection, int32 selectable_item_id = 0); void SendRecipeList(); - void PopulateRecipeData(Recipe* recipe, PacketStruct* packet, int i=0); + void PopulateRecipeData(Recipe* recipe, PacketStruct* packet, int i = 0); int32 GetRecipeCRC(Recipe* recipe); void SendRecipeDetails(vector* recipes); void SendTitleUpdate(); @@ -398,7 +483,7 @@ public: bool IsCrafting(); - void SetRecipeListSent(bool val) {m_recipeListSent = val; } + void SetRecipeListSent(bool val) { m_recipeListSent = val; } bool GetRecipeListSent() { return m_recipeListSent; } void ShowRecipeBook(); PendingResurrection* GetCurrentRez(); @@ -415,7 +500,7 @@ public: bool GetInitialSpawnsSent() { return initial_spawns_sent; } - void SendQuestJournalUpdate(Quest* quest, bool updated=true); + void SendQuestJournalUpdate(Quest* quest, bool updated = true); void AddQuestTimer(int32 quest_id); @@ -426,7 +511,7 @@ public: void EndAutoMount(); bool GetOnAutoMount() { return on_auto_mount; } - + bool IsCurrentTransmuteID(int32 trans_id); void SetTransmuteID(int32 trans_id); int32 GetTransmuteID(); @@ -445,7 +530,7 @@ public: void SendDefaultCommand(Spawn* spawn, const char* command, float distance); void SetTempPlacementSpawn(Spawn* tmp); - + Spawn* GetTempPlacementSpawn() { return tempPlacementSpawn; } void SetPlacementUniqueItemID(int32 id) { placement_unique_item_id = id; } @@ -457,13 +542,13 @@ public: bool HandleHouseEntityCommands(Spawn* spawn, int32 spawnid, string command); // find an appropriate spawn to use for the house object, save spawn location/entry data to DB bool PopulateHouseSpawn(PacketStruct* place_object); - + // finalize the spawn-in of the object in world, remove the item from player inventory, set the spawned in object item id (for future pickup) bool PopulateHouseSpawnFinalize(); - void SendMoveObjectMode(Spawn* spawn, uint8 placementMode, float unknown2_3=0.0f); + void SendMoveObjectMode(Spawn* spawn, uint8 placementMode, float unknown2_3 = 0.0f); - void SendFlightAutoMount(int32 path_id, int16 mount_id = 0, int8 mount_red_color = 0xFF, int8 mount_green_color = 0xFF, int8 mount_blue_color=0xFF); + void SendFlightAutoMount(int32 path_id, int16 mount_id = 0, int8 mount_red_color = 0xFF, int8 mount_green_color = 0xFF, int8 mount_blue_color = 0xFF); void SendShowBook(Spawn* sender, string title, int8 language, int8 num_pages, ...); void SendShowBook(Spawn* sender, string title, int8 language, vector pages); @@ -480,7 +565,7 @@ public: void AddWaypoint(string name, int8 type); void RemoveWaypoint(string name) { - if (waypoints.count(name) > 0){ + if (waypoints.count(name) > 0) { waypoints.erase(name); } } @@ -491,9 +576,9 @@ public: void SetRegionDebug(bool val) { regionDebugMessaging = val; } - static void CreateMail(int32 charID, std::string fromName, std::string subjectName, std::string mailBody, + static void CreateMail(int32 charID, std::string fromName, std::string subjectName, std::string mailBody, int8 mailType, int32 copper, int32 silver, int32 gold, int32 platinum, int32 item_id, int16 stack_size, int32 time_sent, int32 expire_time); - void CreateAndUpdateMail(std::string fromName, std::string subjectName, std::string mailBody, + void CreateAndUpdateMail(std::string fromName, std::string subjectName, std::string mailBody, int8 mailType, int32 copper, int32 silver, int32 gold, int32 platinum, int32 item_id, int16 stack_size, int32 time_sent, int32 expire_time); void SendEquipOrInvUpdateBySlot(int8 slot); @@ -509,7 +594,7 @@ public: void TriggerSpellSave(); - void ClearSentItemDetails() { + void ClearSentItemDetails() { MItemDetails.writelock(__FUNCTION__, __LINE__); sent_item_details.clear(); MItemDetails.releasewritelock(__FUNCTION__, __LINE__); @@ -519,7 +604,7 @@ public: int32 GetRejoinGroupID() { return rejoin_group_id; } - void ClearSentSpellList() { + void ClearSentSpellList() { MSpellDetails.writelock(__FUNCTION__, __LINE__); sent_spell_details.clear(); MSpellDetails.releasewritelock(__FUNCTION__, __LINE__); @@ -531,7 +616,7 @@ public: bool res = false; MSpellDetails.readlock(__FUNCTION__, __LINE__); std::map::iterator itr = sent_spell_details.find(id); - if(itr != sent_spell_details.end() && itr->second == tier) + if (itr != sent_spell_details.end() && itr->second == tier) res = true; MSpellDetails.releasereadlock(__FUNCTION__, __LINE__); return res; @@ -545,73 +630,76 @@ public: void DisableSave() { disable_save = true; } bool IsSaveDisabled() { return disable_save; } - void ResetZoningCoords() { + void ResetZoningCoords() { zoning_x = 0; zoning_y = 0; zoning_z = 0; zoning_h = 0; } - void SetZoningCoords(float x, float y, float z, float h) { + void SetZoningCoords(float x, float y, float z, float h) { zoning_x = x; zoning_y = y; zoning_z = z; zoning_h = h; } - + bool UseItem(Item* item, Spawn* target = nullptr); - + void SendPlayFlavor(Spawn* spawn, int8 language, VoiceOverStruct* non_garble, VoiceOverStruct* garble, bool success = false, bool garble_success = false); void SaveQuestRewardData(bool force_refresh = false); void UpdateCharacterRewardData(QuestRewardData* data); void SetQuestUpdateState(bool val) { quest_updates = val; } - - + + bool SetPlayerPOVGhost(Spawn* spawn); - + int32 GetPlayerPOVGhostSpawnID() { return pov_ghost_spawn_id; } - + void HandleDialogSelectMsg(int32 conversation_id, int32 response_index); bool SetPetName(const char* name); - + bool CheckConsumptionAllowed(int16 slot, bool send_message = true); - + void StartLinkdeadTimer(); bool IsLinkdeadTimerEnabled(); - + bool AddRecipeBookToPlayer(int32 recipe_id, Item* item = nullptr); bool RemoveRecipeFromPlayer(int32 recipe_id); - + void SaveSpells(); - + void GiveQuestReward(Quest* quest, bool has_displayed = false); - - void SendReplaceWidget(int32 widget_id, bool delete_widget, float x=0.0f, float y=0.0f, float z=0.0f, int32 grid_id=0); + + void SendReplaceWidget(int32 widget_id, bool delete_widget, float x = 0.0f, float y = 0.0f, float z = 0.0f, int32 grid_id = 0); void ProcessZoneIgnoreWidgets(); - + void SendHearCast(Spawn* caster, Spawn* target, int32 spell_visual, int16 cast_time); int32 GetSpellVisualOverride(int32 spell_visual); - - sint16 GetClientItemPacketOffset() { sint16 offset = -1; if(GetVersion() <= 373) { offset = -2; } return offset; } - + + sint16 GetClientItemPacketOffset() { sint16 offset = -1; if (GetVersion() <= 373) { offset = -2; } return offset; } + int32 GetZoningID() { return zoning_id; } int32 GetZoningInstanceID() { return zoning_instance_id; } - + void SetZoningDetails(ZoneChangeDetails* details) { zoning_details = ZoneChangeDetails(details); } - + void HandleGroupAcceptResponse(int8 result); void SetGroupOptionsReference(GroupOptions* options); void SendReceiveOffer(Client* client_target, int8 type, std::string name, int8 unknown2); + + bool SendDialogChoice(int32 spawnID, const std::string& windowTextPrompt, const std::string& acceptText, const std::string& acceptCommand, const std::string& declineText, const std::string& declineCommand, int32 time, int8 textBox, int8 textBoxRequired, int32 maxLength); + DialogManager dialog_manager; private: void AddRecipeToPlayerPack(Recipe* recipe, PacketStruct* packet, int16* i); void SavePlayerImages(); void SkillChanged(Skill* skill, int16 previous_value, int16 new_value); void SetStepComplete(int32 quest_id, int32 step); void AddStepProgress(int32 quest_id, int32 step, int32 progress); - + void SendNewSpells(int8 class_id); void SendNewTSSpells(int8 class_id); void AddSendNewSpells(vector* spells); - + map > quest_pending_updates; vector quest_queue; vector quest_pending_reward; @@ -622,16 +710,16 @@ private: vector* search_items; int32 waypoint_id = 0; map waypoints; - Spawn* transport_spawn; + Spawn* transport_spawn; Mutex MBuyBack; deque buy_back_items; - Spawn* merchant_transaction; - Spawn* mail_transaction; + Spawn* merchant_transaction; + Spawn* mail_transaction; mutable std::shared_mutex MPendingQuestAccept; - vector pending_quest_accept; + vector pending_quest_accept; bool lua_debug; bool should_target; - Spawn* combine_spawn; + Spawn* combine_spawn; int8 num_active_failures; int32 next_conversation_id; map conversation_spawns; @@ -639,10 +727,10 @@ private: mutable std::shared_mutex MConversation; map > conversation_map; int32 current_quest_id; - Spawn* banker; + Spawn* banker; map sent_spell_details; map sent_item_details; - Player* player; + Player* player; int16 version; int8 timestamp_flag; int32 ip; @@ -654,20 +742,20 @@ private: char zone_name[64]; int32 zoneID; int32 instanceID; - Timer* autobootup_timeout; + Timer* autobootup_timeout; int32 pwaitingforbootup; int32 last_update_time; int32 last_saved_timestamp; - Timer* CLE_keepalive_timer; - Timer* connect; - Timer* camp_timer; - Timer* linkdead_timer; + Timer* CLE_keepalive_timer; + Timer* connect; + Timer* camp_timer; + Timer* linkdead_timer; bool connected; std::atomic ready_for_spawns; std::atomic ready_for_updates; - + bool seencharsel; bool connected_to_zone; std::atomic client_zoning; @@ -681,7 +769,7 @@ private: float zoning_z; float zoning_h; bool firstlogin; - + enum NewLoginState { LOGIN_NONE, LOGIN_DELAYED, LOGIN_ALLOWED, LOGIN_INITIAL_LOAD, LOGIN_SEND }; NewLoginState new_client_login; // 1 = delayed state, 2 = let client in Timer underworld_cooldown_timer; @@ -694,7 +782,7 @@ private: std::atomic player_pos_change_count; int32 player_pos_timer; bool enabled_player_pos_timer; - bool HandlePacket(EQApplicationPacket *app); + bool HandlePacket(EQApplicationPacket* app); EQStream* eqs; bool quickbar_changed; ZoneServer* current_zone; @@ -707,7 +795,7 @@ private: IncomingPaperdollImage incoming_paperdoll; int32 transmuteID; bool GetHouseZoneServer(ZoneChangeDetails* zone_details, int32 spawn_id, int64 house_id); - + std::atomic m_recipeListSent; bool initial_spawns_sent; bool should_load_spells; @@ -733,9 +821,9 @@ private: int32 temporary_transport_id; int32 rejoin_group_id; - + int32 lastRegionRemapTime; - + bool regionDebugMessaging; bool client_reloading_zone; @@ -750,10 +838,10 @@ private: Mutex MSpellDetails; bool disable_save; vector< string > devices; - + std::atomic pov_ghost_spawn_id; Timer delay_msg_timer; - + uchar* recipe_orig_packet; uchar* recipe_xor_packet; int recipe_packet_count; @@ -766,7 +854,7 @@ public: ~ClientList(); bool ContainsStream(EQStream* eqs); void Add(Client* client); - Client* Get(int32 ip, int16 port); + Client* Get(int32 ip, int16 port); Client* FindByAccountID(int32 account_id); Client* FindByName(char* charname); void Remove(Client* client, bool delete_data = false); diff --git a/source/WorldServer/zoneserver.cpp b/source/WorldServer/zoneserver.cpp index 0218b32..85b759f 100644 --- a/source/WorldServer/zoneserver.cpp +++ b/source/WorldServer/zoneserver.cpp @@ -177,6 +177,11 @@ ZoneServer::ZoneServer(const char* name) { lifetime_client_count = 0; + groupraidMinLevel = 0; + groupraidMaxLevel = 0; + groupraidAvgLevel = 0; + groupraidFirstLevel = 0; + is_initialized = false; } diff --git a/source/WorldServer/zoneserver.h b/source/WorldServer/zoneserver.h index 1651ae0..68c9afd 100644 --- a/source/WorldServer/zoneserver.h +++ b/source/WorldServer/zoneserver.h @@ -1036,6 +1036,11 @@ private: mutable std::shared_mutex MIgnoredWidgets; std::map ignored_widgets; Map* default_zone_map; // this is the map that npcs, ground spawns, so on use. May not be the same as the clients! + + int32 groupraidMinLevel; + int32 groupraidMaxLevel; + int32 groupraidAvgLevel; + int32 groupraidFirstLevel; public: Spawn* GetSpawn(int32 id); @@ -1168,6 +1173,29 @@ public: void SendStateCommand(Spawn* spawn, int32 state); + int32 getGroupraidMinLevel() const { + return groupraidMinLevel; + } + + int32 getGroupraidMaxLevel() const { + return groupraidMaxLevel; + } + + int32 getGroupraidAvgLevel() const { + return groupraidAvgLevel; + } + + int32 getGroupraidFirstLevel() const { + return groupraidFirstLevel; + } + + void setGroupRaidLevels(int32 min_level, int32 max_level, int32 avg_level, int32 first_level) { + groupraidMinLevel = min_level; + groupraidMaxLevel = max_level; + groupraidAvgLevel = avg_level; + groupraidFirstLevel = first_level; + } + int32 lifetime_client_count; int32 incoming_clients; };