1
0

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

This commit is contained in:
Emagi 2024-12-04 21:53:57 -05:00
parent 48b2b1cc4d
commit c17b4d5588
19 changed files with 613 additions and 174 deletions

View File

@ -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.");
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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, ...) {

View File

@ -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<int32> 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<GroupMemberInfo*>* 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;

View File

@ -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<int32>* 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

View File

@ -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<bool>("success")) {
success = successful.get();
}
@ -307,6 +309,14 @@ void HandleCreateGuild(boost::property_tree::ptree tree) {
leaderName = name.get();
}
if (auto prompt = tree.get_optional<bool>("prompted_dialog")) {
promptedDialog = prompt.get();
}
if (auto spawnid = tree.get_optional<int32>("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()) {

View File

@ -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<Peer> 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);

View File

@ -206,7 +206,7 @@ public:
std::string peerId = "", std::vector<int32>* 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);

View File

@ -618,6 +618,7 @@ void World::Web_worldhandle_startzone(const http::request<http::string_body>& 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<int32>("instance_id")) {
instanceId = inst_id.get();
}
@ -633,6 +634,22 @@ void World::Web_worldhandle_startzone(const http::request<http::string_body>& re
if (auto always_loaded = json_tree.get_optional<bool>("always_loaded")) {
alwaysLoaded = always_loaded.get();
}
if (auto level = json_tree.get_optional<int32>("min_level")) {
minLevel = level.get();
}
if (auto level = json_tree.get_optional<int32>("max_level")) {
maxLevel = level.get();
}
if (auto level = json_tree.get_optional<int32>("avg_level")) {
avgLevel = level.get();
}
if (auto level = json_tree.get_optional<int32>("first_level")) {
firstLevel = level.get();
}
sint32 success = 0;
ZoneChangeDetails details;
@ -642,7 +659,7 @@ void World::Web_worldhandle_startzone(const http::request<http::string_body>& 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;
}
}

View File

@ -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<ZoneServer*>::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<ZoneServer*>::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();
}
}

View File

@ -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);

View File

@ -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();

View File

@ -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<int32,int32>* 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 );

View File

@ -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;
}

View File

@ -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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CLIENT_H
#define CLIENT_H
@ -24,6 +24,12 @@
#include <atomic>
#include <mutex>
#include <shared_mutex>
#include <iostream>
#include <map>
#include <string>
#include <thread>
#include <chrono>
#include <condition_variable>
#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<std::mutex> 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<std::mutex> 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<std::mutex> lock(mutex_);
return acceptMap_.erase(key) > 0;
}
// Clear a specific decline string
bool clearDecline(const std::string& key) {
std::lock_guard<std::mutex> lock(mutex_);
return declineMap_.erase(key) > 0;
}
int32 getAcceptValue(const std::string& key) {
std::lock_guard<std::mutex> lock(mutex_);
if (acceptMap_.count(key)) {
return acceptMap_.at(key);
}
return 0; // Key not found
}
int32 getDeclineValue(const std::string& key) {
std::lock_guard<std::mutex> 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<std::mutex> lock(mutex_);
return acceptMap_.count(key) > 0 || declineMap_.count(key) > 0;
}
private:
std::map<std::string, int32> acceptMap_;
std::map<std::string, int32> 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<std::mutex> 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<TransportDestination*>* 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<Item*>* 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<Item*>* rewards=0, vector<Item*>* selectable_rewards=0, map<int32, sint32>* factions=0, const char* header="Quest Reward!", int32 status_points=0, const char* text=0, bool was_displayed = false);
void PopulateQuestRewardItems(vector <Item*>* 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<Item*>* rewards = 0, vector<Item*>* selectable_rewards = 0, map<int32, sint32>* factions = 0, const char* header = "Quest Reward!", int32 status_points = 0, const char* text = 0, bool was_displayed = false);
void PopulateQuestRewardItems(vector <Item*>* 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<ConversationOption>* conversations, const char* text, const char* mp3, int32 key1, int32 key2, int8 language = 0, int8 can_close = 1);
void DisplayConversation(Item* item, vector<ConversationOption>* 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<ConversationOption>* 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<BuyBackItem*>* GetBuyBacks();
deque<BuyBackItem*>* GetBuyBacks();
vector<Item*>* GetRepairableItems();
vector<Item*>* 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<int32>* 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<Item::BookPage*> 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<int32, int32>::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<Spell*>* spells);
map<int32, map<int32, int32> > quest_pending_updates;
vector<QueuedQuest*> quest_queue;
vector<QuestRewardData*> quest_pending_reward;
@ -622,16 +710,16 @@ private:
vector<Item*>* search_items;
int32 waypoint_id = 0;
map<string, WaypointInfo> waypoints;
Spawn* transport_spawn;
Spawn* transport_spawn;
Mutex MBuyBack;
deque<BuyBackItem*> buy_back_items;
Spawn* merchant_transaction;
Spawn* mail_transaction;
Spawn* merchant_transaction;
Spawn* mail_transaction;
mutable std::shared_mutex MPendingQuestAccept;
vector<int32> pending_quest_accept;
vector<int32> pending_quest_accept;
bool lua_debug;
bool should_target;
Spawn* combine_spawn;
Spawn* combine_spawn;
int8 num_active_failures;
int32 next_conversation_id;
map<int32, int32> conversation_spawns;
@ -639,10 +727,10 @@ private:
mutable std::shared_mutex MConversation;
map<int32, map<int8, string> > conversation_map;
int32 current_quest_id;
Spawn* banker;
Spawn* banker;
map<int32, int32> sent_spell_details;
map<int32, bool> 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<bool> ready_for_spawns;
std::atomic<bool> ready_for_updates;
bool seencharsel;
bool connected_to_zone;
std::atomic<bool> 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<int8> 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<bool> 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<int32> 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);

View File

@ -177,6 +177,11 @@ ZoneServer::ZoneServer(const char* name) {
lifetime_client_count = 0;
groupraidMinLevel = 0;
groupraidMaxLevel = 0;
groupraidAvgLevel = 0;
groupraidFirstLevel = 0;
is_initialized = false;
}

View File

@ -1036,6 +1036,11 @@ private:
mutable std::shared_mutex MIgnoredWidgets;
std::map<int32, bool> 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;
};