diff --git a/common/emu_constants.h b/common/emu_constants.h index c6491b3b3..945f513b5 100644 --- a/common/emu_constants.h +++ b/common/emu_constants.h @@ -317,6 +317,15 @@ namespace EQEmu QuestControlGrid = -1 }; + namespace consent { + enum eConsentType : uint8 { + Normal = 0, + Group, + Raid, + Guild + }; + }; // namespace consent + } /*EQEmu*/ #endif /*COMMON_EMU_CONSTANTS_H*/ diff --git a/common/servertalk.h b/common/servertalk.h index b9cb6202e..aa3529756 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -866,10 +866,12 @@ struct SpawnPlayerCorpse_Struct { struct ServerOP_Consent_Struct { char grantname[64]; char ownername[64]; + char zonename[32]; uint8 permission; uint32 zone_id; uint16 instance_id; - uint32 message_string_id; + uint8 consent_type; // 0 = normal, 1 = group, 2 = raid, 3 = guild + uint32 consent_id; }; struct ReloadTasks_Struct { diff --git a/common/version.h b/common/version.h index 5d00daaf4..ca37150ec 100644 --- a/common/version.h +++ b/common/version.h @@ -34,7 +34,7 @@ * Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9147 +#define CURRENT_BINARY_DATABASE_VERSION 9148 #ifdef BOTS #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9026 diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 53a71e109..8e3172b87 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -401,6 +401,7 @@ 9145|2019_12_24_banned_ips_update.sql|SHOW TABLES LIKE 'Banned_IPs'|not_empty| 9146|2020_01_10_character_soft_deletes.sql|SHOW COLUMNS FROM `character_data` LIKE 'deleted_at'|empty| 9147|2020_01_24_grid_centerpoint_wp.sql|SHOW COLUMNS FROM `grid_entries` LIKE 'centerpoint'|empty| +9148|2020_01_28_corpse_guild_consent_id.sql|SHOW COLUMNS FROM `character_corpses` LIKE 'guild_consent_id'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2020_01_28_corpse_guild_consent_id.sql b/utils/sql/git/required/2020_01_28_corpse_guild_consent_id.sql new file mode 100644 index 000000000..b42f257ea --- /dev/null +++ b/utils/sql/git/required/2020_01_28_corpse_guild_consent_id.sql @@ -0,0 +1 @@ +ALTER TABLE `character_corpses` ADD COLUMN `guild_consent_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `time_of_death`; diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index dd55fac39..08ccbfaff 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -1057,110 +1057,42 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) { break; } case ServerOP_Consent: { - // Message string id's likely to be used here are: - // CONSENT_YOURSELF = 399 - // CONSENT_INVALID_NAME = 397 - // TARGET_NOT_FOUND = 101 - ZoneServer* zs; - ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer; - ClientListEntry* cle = client_list.FindCharacter(s->grantname); - if (cle) { - if (cle->instance() != 0) - { - zs = zoneserver_list.FindByInstanceID(cle->instance()); - if (zs) { - zs->SendPacket(pack); - } - else - { - auto pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct)); - ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer; - strcpy(scs->grantname, s->grantname); - strcpy(scs->ownername, s->ownername); - scs->permission = s->permission; - scs->zone_id = s->zone_id; - scs->instance_id = s->instance_id; - scs->message_string_id = 101; - zs = zoneserver_list.FindByInstanceID(s->instance_id); - if (zs) { - zs->SendPacket(pack); - } - else { - LogInfo("Unable to locate zone record for instance id [{}] in zoneserver list for ServerOP_Consent_Response operation", s->instance_id); - } - safe_delete(pack); - } - } - else - { - zs = zoneserver_list.FindByZoneID(cle->zone()); - if (zs) { - zs->SendPacket(pack); - } - else { - // send target not found back to requester - auto pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct)); - ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer; - strcpy(scs->grantname, s->grantname); - strcpy(scs->ownername, s->ownername); - scs->permission = s->permission; - scs->zone_id = s->zone_id; - scs->message_string_id = 101; - zs = zoneserver_list.FindByZoneID(s->zone_id); - if (zs) { - zs->SendPacket(pack); - } - else { - LogInfo("Unable to locate zone record for zone id [{}] in zoneserver list for ServerOP_Consent_Response operation", s->zone_id); - } - safe_delete(pack); - } - } - } - else { - // send target not found back to requester - auto pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct)); - ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer; - strcpy(scs->grantname, s->grantname); - strcpy(scs->ownername, s->ownername); - scs->permission = s->permission; - scs->zone_id = s->zone_id; - scs->message_string_id = 397; - zs = zoneserver_list.FindByZoneID(s->zone_id); - if (zs) { - zs->SendPacket(pack); - } - else { - LogInfo("Unable to locate zone record for zone id [{}] in zoneserver list for ServerOP_Consent_Response operation", s->zone_id); - } - safe_delete(pack); - } + zoneserver_list.SendPacket(pack); // update corpses in all zones break; } case ServerOP_Consent_Response: { - // Message string id's likely to be used here are: - // CONSENT_YOURSELF = 399 - // CONSENT_INVALID_NAME = 397 - // TARGET_NOT_FOUND = 101 ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer; - if (s->instance_id != 0) - { - ZoneServer* zs = zoneserver_list.FindByInstanceID(s->instance_id); - if (zs) { - zs->SendPacket(pack); - } - else { - LogInfo("Unable to locate zone record for instance id [{}] in zoneserver list for ServerOP_Consent_Response operation", s->instance_id); - } + + ZoneServer* owner_zs = nullptr; + if (s->instance_id == 0) { + owner_zs = zoneserver_list.FindByZoneID(s->zone_id); } - else - { - ZoneServer* zs = zoneserver_list.FindByZoneID(s->zone_id); - if (zs) { - zs->SendPacket(pack); - } - else { - LogInfo("Unable to locate zone record for zone id [{}] in zoneserver list for ServerOP_Consent_Response operation", s->zone_id); + else { + owner_zs = zoneserver_list.FindByInstanceID(s->instance_id); + } + + if (owner_zs) { + owner_zs->SendPacket(pack); + } + else { + LogInfo("Unable to locate zone record for zone id [{}] or instance id [{}] in zoneserver list for ServerOP_Consent_Response operation", s->zone_id, s->instance_id); + } + + if (s->consent_type == EQEmu::consent::Normal) { + // send the message to the client being granted or denied permission + ClientListEntry* cle = client_list.FindCharacter(s->grantname); + if (cle) { + ZoneServer* granted_zs = nullptr; + if (cle->instance() == 0) { + granted_zs = zoneserver_list.FindByZoneID(cle->zone()); + } + else { + granted_zs = zoneserver_list.FindByInstanceID(cle->instance()); + } + // avoid sending twice if owner and granted are in same zone + if (granted_zs && granted_zs != owner_zs) { + granted_zs->SendPacket(pack); + } } } break; diff --git a/zone/client.cpp b/zone/client.cpp index 6b366afba..2398db500 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -165,6 +165,7 @@ Client::Client(EQStreamInterface* ieqs) hp_self_update_throttle_timer(300), hp_other_update_throttle_timer(500), position_update_timer(10000), + consent_throttle_timer(2000), tmSitting(0) { @@ -6254,6 +6255,52 @@ void Client::DragCorpses() } } +void Client::ConsentCorpses(std::string consent_name, bool deny) +{ + if (strcasecmp(consent_name.c_str(), GetName()) == 0) { + MessageString(Chat::Red, CONSENT_YOURSELF); + } + else if (!consent_throttle_timer.Check()) { + MessageString(Chat::Red, CONSENT_WAIT); + } + else { + auto pack = new ServerPacket(ServerOP_Consent, sizeof(ServerOP_Consent_Struct)); + ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer; + strn0cpy(scs->grantname, consent_name.c_str(), sizeof(scs->grantname)); + strn0cpy(scs->ownername, GetName(), sizeof(scs->ownername)); + strn0cpy(scs->zonename, "Unknown", sizeof(scs->zonename)); + scs->permission = deny ? 0 : 1; + scs->zone_id = zone->GetZoneID(); + scs->instance_id = zone->GetInstanceID(); + scs->consent_type = EQEmu::consent::Normal; + scs->consent_id = 0; + if (strcasecmp(scs->grantname, "group") == 0) { + if (!deny) { + Group* grp = GetGroup(); + scs->consent_id = grp ? grp->GetID() : 0; + } + scs->consent_type = EQEmu::consent::Group; + } + else if (strcasecmp(scs->grantname, "raid") == 0) { + if (!deny) { + Raid* raid = GetRaid(); + scs->consent_id = raid ? raid->GetID() : 0; + } + scs->consent_type = EQEmu::consent::Raid; + } + else if (strcasecmp(scs->grantname, "guild") == 0) { + if (!deny) { + scs->consent_id = GuildID(); + } + scs->consent_type = EQEmu::consent::Guild; + // update all corpses in db so buried/unloaded corpses see new consent id + database.UpdateCharacterCorpseConsent(CharacterID(), scs->consent_id); + } + worldserver.SendPacket(pack); + safe_delete(pack); + } +} + void Client::Doppelganger(uint16 spell_id, Mob *target, const char *name_override, int pet_count, int pet_duration) { if(!target || !IsValidSpell(spell_id) || this->GetID() == target->GetID()) diff --git a/zone/client.h b/zone/client.h index 300073bb5..a0655584b 100644 --- a/zone/client.h +++ b/zone/client.h @@ -793,6 +793,9 @@ public: virtual void UpdateEquipmentLight() { m_Light.Type[EQEmu::lightsource::LightEquipment] = m_inv.FindBrightestLightType(); m_Light.Level[EQEmu::lightsource::LightEquipment] = EQEmu::lightsource::TypeToLevel(m_Light.Type[EQEmu::lightsource::LightEquipment]); } inline bool AutoSplitEnabled() { return m_pp.autosplit != 0; } + inline bool AutoConsentGroupEnabled() const { return m_pp.groupAutoconsent != 0; } + inline bool AutoConsentRaidEnabled() const { return m_pp.raidAutoconsent != 0; } + inline bool AutoConsentGuildEnabled() const { return m_pp.guildAutoconsent != 0; } void SummonHorse(uint16 spell_id); void SetHorseId(uint16 horseid_in); @@ -957,7 +960,6 @@ public: void EnteringMessages(Client* client); void SendRules(Client* client); - std::list consent_list; const bool GetGMSpeed() const { return (gmspeed > 0); } bool CanUseReport; @@ -1137,6 +1139,7 @@ public: inline bool IsDraggingCorpse() { return (DraggedCorpses.size() > 0); } void DragCorpses(); inline void ClearDraggedCorpses() { DraggedCorpses.clear(); } + void ConsentCorpses(std::string consent_name, bool deny = false); void SendAltCurrencies(); void SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount); void AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 method = 0); @@ -1528,6 +1531,7 @@ private: Timer hp_self_update_throttle_timer; /* This is to prevent excessive packet sending under trains/fast combat */ Timer hp_other_update_throttle_timer; /* This is to keep clients from DOSing the server with macros that change client targets constantly */ Timer position_update_timer; /* Timer used when client hasn't updated within a 10 second window */ + Timer consent_throttle_timer; glm::vec3 m_Proximity; glm::vec4 last_position_before_bulk_update; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index dfb7ab673..0ea11e8ae 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -4643,43 +4643,16 @@ void Client::Handle_OP_Consent(const EQApplicationPacket *app) { if (app->size<64) { Consent_Struct* c = (Consent_Struct*)app->pBuffer; - if (strcmp(c->name, GetName()) != 0) { - auto pack = new ServerPacket(ServerOP_Consent, sizeof(ServerOP_Consent_Struct)); - ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer; - strcpy(scs->grantname, c->name); - strcpy(scs->ownername, GetName()); - scs->message_string_id = 0; - scs->permission = 1; - scs->zone_id = zone->GetZoneID(); - scs->instance_id = zone->GetInstanceID(); - //consent_list.push_back(scs->grantname); - worldserver.SendPacket(pack); - safe_delete(pack); - } - else { - MessageString(Chat::White, CONSENT_YOURSELF); - } + ConsentCorpses(c->name, false); } - return; } void Client::Handle_OP_ConsentDeny(const EQApplicationPacket *app) { if (app->size<64) { Consent_Struct* c = (Consent_Struct*)app->pBuffer; - auto pack = new ServerPacket(ServerOP_Consent, sizeof(ServerOP_Consent_Struct)); - ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer; - strcpy(scs->grantname, c->name); - strcpy(scs->ownername, GetName()); - scs->message_string_id = 0; - scs->permission = 0; - scs->zone_id = zone->GetZoneID(); - scs->instance_id = zone->GetInstanceID(); - //consent_list.remove(scs->grantname); - worldserver.SendPacket(pack); - safe_delete(pack); + ConsentCorpses(c->name, true); } - return; } void Client::Handle_OP_Consider(const EQApplicationPacket *app) @@ -13320,6 +13293,21 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app) entity_list.QueueClients(this, app, true); } } + else if (sa->type == AT_GroupConsent) + { + m_pp.groupAutoconsent = (sa->parameter == 1); + ConsentCorpses("Group", (sa->parameter != 1)); + } + else if (sa->type == AT_RaidConsent) + { + m_pp.raidAutoconsent = (sa->parameter == 1); + ConsentCorpses("Raid", (sa->parameter != 1)); + } + else if (sa->type == AT_GuildConsent) + { + m_pp.guildAutoconsent = (sa->parameter == 1); + ConsentCorpses("Guild", (sa->parameter != 1)); + } else { std::cout << "Unknown SpawnAppearance type: 0x" << std::hex << std::setw(4) << std::setfill('0') << sa->type << std::dec << " value: 0x" << std::hex << std::setw(8) << std::setfill('0') << sa->parameter << std::dec << std::endl; diff --git a/zone/corpse.cpp b/zone/corpse.cpp index 09661826d..0ac100997 100644 --- a/zone/corpse.cpp +++ b/zone/corpse.cpp @@ -73,7 +73,7 @@ void Corpse::SendLootReqErrorPacket(Client* client, LootResponse response) { safe_delete(outapp); } -Corpse* Corpse::LoadCharacterCorpseEntity(uint32 in_dbid, uint32 in_charid, std::string in_charname, const glm::vec4& position, std::string time_of_death, bool rezzed, bool was_at_graveyard) { +Corpse* Corpse::LoadCharacterCorpseEntity(uint32 in_dbid, uint32 in_charid, std::string in_charname, const glm::vec4& position, std::string time_of_death, bool rezzed, bool was_at_graveyard, uint32 guild_consent_id) { uint32 item_count = database.GetCharacterCorpseItemCount(in_dbid); auto buffer = new char[sizeof(PlayerCorpse_Struct) + (item_count * sizeof(player_lootitem::ServerLootItem_Struct))]; @@ -138,6 +138,7 @@ Corpse* Corpse::LoadCharacterCorpseEntity(uint32 in_dbid, uint32 in_charid, std: pc->drakkin_details = pcs->drakkin_details; pc->IsRezzed(rezzed); pc->become_npc = false; + pc->consented_guild_id = guild_consent_id; pc->UpdateEquipmentLight(); // itemlist populated above..need to determine actual values @@ -282,6 +283,18 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( allowed_looters[i] = 0; } + if (client->AutoConsentGroupEnabled()) { + Group* grp = client->GetGroup(); + consented_group_id = grp ? grp->GetID() : 0; + } + + if (client->AutoConsentRaidEnabled()) { + Raid* raid = client->GetRaid(); + consented_raid_id = raid ? raid->GetID() : 0; + } + + consented_guild_id = client->AutoConsentGuildEnabled() ? client->GuildID() : 0; + is_corpse_changed = true; rez_experience = in_rezexp; can_corpse_be_rezzed = true; @@ -611,11 +624,11 @@ bool Corpse::Save() { /* Create New Corpse*/ if (corpse_db_id == 0) { - corpse_db_id = database.SaveCharacterCorpse(char_id, corpse_name, zone->GetZoneID(), zone->GetInstanceID(), dbpc, m_Position); + corpse_db_id = database.SaveCharacterCorpse(char_id, corpse_name, zone->GetZoneID(), zone->GetInstanceID(), dbpc, m_Position, consented_guild_id); } /* Update Corpse Data */ else{ - corpse_db_id = database.UpdateCharacterCorpse(corpse_db_id, char_id, corpse_name, zone->GetZoneID(), zone->GetInstanceID(), dbpc, m_Position, IsRezzed()); + corpse_db_id = database.UpdateCharacterCorpse(corpse_db_id, char_id, corpse_name, zone->GetZoneID(), zone->GetInstanceID(), dbpc, m_Position, consented_guild_id, IsRezzed()); } safe_delete_array(dbpc); @@ -647,6 +660,25 @@ void Corpse::DepopPlayerCorpse() { player_corpse_depop = true; } +void Corpse::AddConsentName(std::string consent_player_name) +{ + for (const auto& consented_player_name : consented_player_names) { + if (strcasecmp(consented_player_name.c_str(), consent_player_name.c_str()) == 0) { + return; + } + } + consented_player_names.emplace_back(consent_player_name); +} + +void Corpse::RemoveConsentName(std::string consent_player_name) +{ + consented_player_names.erase(std::remove_if(consented_player_names.begin(), consented_player_names.end(), + [consent_player_name](const std::string& consented_player_name) { + return strcasecmp(consented_player_name.c_str(), consent_player_name.c_str()) == 0; + } + ), consented_player_names.end()); +} + uint32 Corpse::CountItems() { return itemlist.size(); } @@ -1434,29 +1466,50 @@ bool Corpse::Summon(Client* client, bool spell, bool CheckDistance) { is_corpse_changed = true; } else { - client->Message(Chat::White, "Corpse is too far away."); + client->MessageString(Chat::Red, CORPSE_TOO_FAR); return false; } } else { bool consented = false; - std::list::iterator itr; - for(itr = client->consent_list.begin(); itr != client->consent_list.end(); ++itr) { - if(strcmp(this->GetOwnerName(), itr->c_str()) == 0) { - if (!CheckDistance || (DistanceSquaredNoZ(m_Position, client->GetPosition()) <= dist2)) { - GMMove(client->GetX(), client->GetY(), client->GetZ()); - is_corpse_changed = true; - } - else { - client->Message(Chat::White, "Corpse is too far away."); - return false; - } + for (const auto& consented_player_name : consented_player_names) { + if (strcasecmp(client->GetName(), consented_player_name.c_str()) == 0) { + consented = true; + break; + } + } + + if (!consented && consented_guild_id && consented_guild_id != GUILD_NONE) { + if (client->GuildID() == consented_guild_id) { consented = true; } } - if(!consented) { - client->Message(Chat::White, "You do not have permission to move this corpse."); + if (!consented && consented_group_id) { + Group* grp = client->GetGroup(); + if (grp && grp->GetID() == consented_group_id) { + consented = true; + } + } + if (!consented && consented_raid_id) { + Raid* raid = client->GetRaid(); + if (raid && raid->GetID() == consented_raid_id) { + consented = true; + } + } + + if (consented) { + if (!CheckDistance || (DistanceSquaredNoZ(m_Position, client->GetPosition()) <= dist2)) { + GMMove(client->GetX(), client->GetY(), client->GetZ()); + is_corpse_changed = true; + } + else { + client->MessageString(Chat::Red, CORPSE_TOO_FAR); + return false; + } + } + else { + client->MessageString(Chat::Red, CONSENT_DENIED); return false; } } diff --git a/zone/corpse.h b/zone/corpse.h index e7a7c5805..d453c7e9e 100644 --- a/zone/corpse.h +++ b/zone/corpse.h @@ -48,7 +48,7 @@ class Corpse : public Mob { Corpse(uint32 in_corpseid, uint32 in_charid, const char* in_charname, ItemList* in_itemlist, uint32 in_copper, uint32 in_silver, uint32 in_gold, uint32 in_plat, const glm::vec4& position, float in_size, uint8 in_gender, uint16 in_race, uint8 in_class, uint8 in_deity, uint8 in_level, uint8 in_texture, uint8 in_helmtexture, uint32 in_rezexp, bool wasAtGraveyard = false); ~Corpse(); - static Corpse* LoadCharacterCorpseEntity(uint32 in_dbid, uint32 in_charid, std::string in_charname, const glm::vec4& position, std::string time_of_death, bool rezzed, bool was_at_graveyard); + static Corpse* LoadCharacterCorpseEntity(uint32 in_dbid, uint32 in_charid, std::string in_charname, const glm::vec4& position, std::string time_of_death, bool rezzed, bool was_at_graveyard, uint32 guild_consent_id); /* Corpse: General */ virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill) { return true; } @@ -74,6 +74,11 @@ class Corpse : public Mob { uint32 GetDecayTime() { if (!corpse_decay_timer.Enabled()) return 0xFFFFFFFF; else return corpse_decay_timer.GetRemainingTime(); } uint32 GetRezTime() { if (!corpse_rez_timer.Enabled()) return 0; else return corpse_rez_timer.GetRemainingTime(); } void SetDecayTimer(uint32 decay_time); + void SetConsentGroupID(uint32 group_id) { if (IsPlayerCorpse()) { consented_group_id = group_id; } } + void SetConsentRaidID(uint32 raid_id) { if (IsPlayerCorpse()) { consented_raid_id = raid_id; } } + void SetConsentGuildID(uint32 guild_id) { if (IsPlayerCorpse()) { consented_guild_id = guild_id; } } + void AddConsentName(std::string consent_player_name); + void RemoveConsentName(std::string consent_player_name); void Delete(); void Bury(); @@ -142,6 +147,9 @@ private: int32 player_kill_item; /* Determines if Player Kill Item */ uint32 corpse_db_id; /* Corpse Database ID (Player Corpse) */ uint32 char_id; /* Character ID */ + uint32 consented_group_id = 0; + uint32 consented_raid_id = 0; + uint32 consented_guild_id = 0; ItemList itemlist; /* Internal Item list used for corpses */ uint32 copper; uint32 silver; @@ -160,6 +168,7 @@ private: Timer corpse_graveyard_timer; Timer loot_cooldown_timer; /* Delay between loot actions on the corpse entity */ EQEmu::TintProfile item_tint; + std::vector consented_player_names; LootRequestType loot_request_type; }; diff --git a/zone/string_ids.h b/zone/string_ids.h index 25321b3c9..e543007a0 100644 --- a/zone/string_ids.h +++ b/zone/string_ids.h @@ -122,11 +122,13 @@ #define LOOT_LORE_ERROR 371 //You cannot loot this Lore Item. You already have one. #define PICK_LORE 379 //You cannot pick up a lore item you already possess. #define POISON_TOO_HIGH 382 // This poison is too high level for you to apply. +#define CORPSE_TOO_FAR 389 //The corpse is too far away to summon. #define CONSENT_DENIED 390 //You do not have consent to summon that corpse. #define DISCIPLINE_RDY 393 //You are ready to use a new discipline now. #define CONSENT_INVALID_NAME 397 //Not a valid consent name. #define CONSENT_NPC 398 //You cannot consent NPC\'s. #define CONSENT_YOURSELF 399 //You cannot consent yourself. +#define CONSENT_WAIT 400 //You must wait 2 seconds between consents. #define SONG_NEEDS_DRUM 405 //You need to play a percussion instrument for this song #define SONG_NEEDS_WIND 406 //You need to play a wind instrument for this song #define SONG_NEEDS_STRINGS 407 //You need to play a stringed instrument for this song diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index a5180963d..56f99067c 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -1442,50 +1442,65 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) } case ServerOP_Consent: { ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer; - Client* client = entity_list.GetClientByName(s->grantname); - if (client) { - if (s->permission == 1) - client->consent_list.push_back(s->ownername); - else - client->consent_list.remove(s->ownername); - auto outapp = - new EQApplicationPacket(OP_ConsentResponse, sizeof(ConsentResponse_Struct)); - ConsentResponse_Struct* crs = (ConsentResponse_Struct*)outapp->pBuffer; - strcpy(crs->grantname, s->grantname); - strcpy(crs->ownername, s->ownername); - crs->permission = s->permission; - strcpy(crs->zonename, "all zones"); - client->QueuePacket(outapp); - safe_delete(outapp); + bool found_corpse = false; + for (auto const& it : entity_list.GetCorpseList()) { + if (it.second->IsPlayerCorpse() && strcmp(it.second->GetOwnerName(), s->ownername) == 0) { + if (s->consent_type == EQEmu::consent::Normal) { + if (s->permission == 1) { + it.second->AddConsentName(s->grantname); + } + else { + it.second->RemoveConsentName(s->grantname); + } + } + else if (s->consent_type == EQEmu::consent::Group) { + it.second->SetConsentGroupID(s->consent_id); + } + else if (s->consent_type == EQEmu::consent::Raid) { + it.second->SetConsentRaidID(s->consent_id); + } + else if (s->consent_type == EQEmu::consent::Guild) { + it.second->SetConsentGuildID(s->consent_id); + } + found_corpse = true; + } } - else { - // target not found - // Message string id's likely to be used here are: - // CONSENT_YOURSELF = 399 - // CONSENT_INVALID_NAME = 397 - // TARGET_NOT_FOUND = 101 - - auto scs_pack = - new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct)); - ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)scs_pack->pBuffer; - strcpy(scs->grantname, s->grantname); - strcpy(scs->ownername, s->ownername); - scs->permission = s->permission; - scs->zone_id = s->zone_id; - scs->instance_id = s->instance_id; - scs->message_string_id = TARGET_NOT_FOUND; - worldserver.SendPacket(scs_pack); - safe_delete(scs_pack); + if (found_corpse) { + // forward the grant/deny message for this zone to both owner and granted + auto outapp = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct)); + ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)outapp->pBuffer; + memcpy(outapp->pBuffer, s, sizeof(ServerOP_Consent_Struct)); + if (zone) { + strn0cpy(scs->zonename, zone->GetLongName(), sizeof(scs->zonename)); + } + worldserver.SendPacket(outapp); + safe_delete(outapp); } break; } case ServerOP_Consent_Response: { ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer; - Client* client = entity_list.GetClientByName(s->ownername); - if (client) { - client->MessageString(Chat::White, s->message_string_id); + Client* owner_client = entity_list.GetClientByName(s->ownername); + Client* grant_client = nullptr; + if (s->consent_type == EQEmu::consent::Normal) { + grant_client = entity_list.GetClientByName(s->grantname); + } + if (owner_client || grant_client) { + auto outapp = new EQApplicationPacket(OP_ConsentResponse, sizeof(ConsentResponse_Struct)); + ConsentResponse_Struct* crs = (ConsentResponse_Struct*)outapp->pBuffer; + strn0cpy(crs->grantname, s->grantname, sizeof(crs->grantname)); + strn0cpy(crs->ownername, s->ownername, sizeof(crs->ownername)); + crs->permission = s->permission; + strn0cpy(crs->zonename, s->zonename, sizeof(crs->zonename)); + if (owner_client) { + owner_client->QueuePacket(outapp); // confirmation message to the owner + } + if (grant_client) { + grant_client->QueuePacket(outapp); // message to the client being granted/denied + } + safe_delete(outapp); } break; } diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index d5346877d..ea4287f9d 100755 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -4288,10 +4288,10 @@ uint32 ZoneDatabase::GetCharacterCorpseDecayTimer(uint32 corpse_db_id){ return 0; } -uint32 ZoneDatabase::UpdateCharacterCorpse(uint32 db_id, uint32 char_id, const char* char_name, uint32 zone_id, uint16 instance_id, PlayerCorpse_Struct* dbpc, const glm::vec4& position, bool is_rezzed) { +uint32 ZoneDatabase::UpdateCharacterCorpse(uint32 db_id, uint32 char_id, const char* char_name, uint32 zone_id, uint16 instance_id, PlayerCorpse_Struct* dbpc, const glm::vec4& position, uint32 guild_id, bool is_rezzed) { std::string query = StringFormat("UPDATE `character_corpses` " "SET `charname` = '%s', `zone_id` = %u, `instance_id` = %u, `charid` = %d, " - "`x` = %1.1f,`y` = %1.1f,`z` = %1.1f, `heading` = %1.1f, " + "`x` = %1.1f,`y` = %1.1f,`z` = %1.1f, `heading` = %1.1f, `guild_consent_id` = %u, " "`is_locked` = %d, `exp` = %u, `size` = %f, `level` = %u, " "`race` = %u, `gender` = %u, `class` = %u, `deity` = %u, " "`texture` = %u, `helm_texture` = %u, `copper` = %u, " @@ -4303,7 +4303,7 @@ uint32 ZoneDatabase::UpdateCharacterCorpse(uint32 db_id, uint32 char_id, const c "`wc_7` = %u, `wc_8` = %u, `wc_9` = %u " "WHERE `id` = %u", EscapeString(char_name).c_str(), zone_id, instance_id, char_id, - position.x, position.y, position.z, position.w, + position.x, position.y, position.z, position.w, guild_id, dbpc->locked, dbpc->exp, dbpc->size, dbpc->level, dbpc->race, dbpc->gender, dbpc->class_, dbpc->deity, dbpc->texture, dbpc->helmtexture, dbpc->copper, dbpc->silver, dbpc->gold, @@ -4319,12 +4319,19 @@ uint32 ZoneDatabase::UpdateCharacterCorpse(uint32 db_id, uint32 char_id, const c return db_id; } +uint32 ZoneDatabase::UpdateCharacterCorpseConsent(uint32 charid, uint32 guildid) +{ + std::string query = fmt::format("UPDATE `character_corpses` SET `guild_consent_id` = '{}' WHERE charid = '{}'", guildid, charid); + auto results = QueryDatabase(query); + return results.RowsAffected(); +} + void ZoneDatabase::MarkCorpseAsRezzed(uint32 db_id) { std::string query = StringFormat("UPDATE `character_corpses` SET `is_rezzed` = 1 WHERE `id` = %i", db_id); auto results = QueryDatabase(query); } -uint32 ZoneDatabase::SaveCharacterCorpse(uint32 charid, const char* charname, uint32 zoneid, uint16 instanceid, PlayerCorpse_Struct* dbpc, const glm::vec4& position) { +uint32 ZoneDatabase::SaveCharacterCorpse(uint32 charid, const char* charname, uint32 zoneid, uint16 instanceid, PlayerCorpse_Struct* dbpc, const glm::vec4& position, uint32 guildid) { /* Dump Basic Corpse Data */ std::string query = StringFormat( "INSERT INTO `character_corpses` " @@ -4336,6 +4343,7 @@ uint32 ZoneDatabase::SaveCharacterCorpse(uint32 charid, const char* charname, ui "`y` = %1.1f, " "`z` = %1.1f, " "`heading` = %1.1f, " + "`guild_consent_id` = %u, " "`time_of_death` = NOW(), " "`is_buried` = 0, " "`is_locked` = %d, " @@ -4379,6 +4387,7 @@ uint32 ZoneDatabase::SaveCharacterCorpse(uint32 charid, const char* charname, ui position.y, position.z, position.w, + guildid, dbpc->locked, dbpc->exp, dbpc->size, @@ -4637,7 +4646,7 @@ bool ZoneDatabase::LoadCharacterCorpseData(uint32 corpse_id, PlayerCorpse_Struct Corpse* ZoneDatabase::SummonBuriedCharacterCorpses(uint32 char_id, uint32 dest_zone_id, uint16 dest_instance_id, const glm::vec4& position) { Corpse* corpse = nullptr; - std::string query = StringFormat("SELECT `id`, `charname`, `time_of_death`, `is_rezzed` " + std::string query = StringFormat("SELECT `id`, `charname`, `time_of_death`, `is_rezzed`, `guild_consent_id` " "FROM `character_corpses` " "WHERE `charid` = '%u' AND `is_buried` = 1 " "ORDER BY `time_of_death` LIMIT 1", @@ -4652,7 +4661,8 @@ Corpse* ZoneDatabase::SummonBuriedCharacterCorpses(uint32 char_id, uint32 dest_z position, row[2], // char* time_of_death atoi(row[3]) == 1, // bool rezzed - false // bool was_at_graveyard + false, // bool was_at_graveyard + atoul(row[4]) // uint32 guild_consent_id ); if (!corpse) continue; @@ -4678,7 +4688,7 @@ bool ZoneDatabase::SummonAllCharacterCorpses(uint32 char_id, uint32 dest_zone_id auto results = QueryDatabase(query); query = StringFormat( - "SELECT `id`, `charname`, `time_of_death`, `is_rezzed` FROM `character_corpses` WHERE `charid` = '%u'" + "SELECT `id`, `charname`, `time_of_death`, `is_rezzed`, `guild_consent_id` FROM `character_corpses` WHERE `charid` = '%u'" "ORDER BY time_of_death", char_id); results = QueryDatabase(query); @@ -4691,7 +4701,8 @@ bool ZoneDatabase::SummonAllCharacterCorpses(uint32 char_id, uint32 dest_zone_id position, row[2], atoi(row[3]) == 1, - false); + false, + atoul(row[4])); if (corpse) { entity_list.AddCorpse(corpse); @@ -4766,7 +4777,7 @@ bool ZoneDatabase::UnburyCharacterCorpse(uint32 db_id, uint32 new_zone_id, uint1 Corpse* ZoneDatabase::LoadCharacterCorpse(uint32 player_corpse_id) { Corpse* NewCorpse = 0; std::string query = StringFormat( - "SELECT `id`, `charid`, `charname`, `x`, `y`, `z`, `heading`, `time_of_death`, `is_rezzed`, `was_at_graveyard` FROM `character_corpses` WHERE `id` = '%u' LIMIT 1", + "SELECT `id`, `charid`, `charname`, `x`, `y`, `z`, `heading`, `time_of_death`, `is_rezzed`, `was_at_graveyard`, `guild_consent_id` FROM `character_corpses` WHERE `id` = '%u' LIMIT 1", player_corpse_id ); auto results = QueryDatabase(query); @@ -4779,7 +4790,8 @@ Corpse* ZoneDatabase::LoadCharacterCorpse(uint32 player_corpse_id) { position, row[7], // time_of_death char* time_of_death atoi(row[8]) == 1, // is_rezzed bool rezzed - atoi(row[9]) // was_at_graveyard bool was_at_graveyard + atoi(row[9]), // was_at_graveyard bool was_at_graveyard + atoul(row[10]) // guild_consent_id uint32 guild_consent_id ); entity_list.AddCorpse(NewCorpse); } @@ -4789,10 +4801,10 @@ Corpse* ZoneDatabase::LoadCharacterCorpse(uint32 player_corpse_id) { bool ZoneDatabase::LoadCharacterCorpses(uint32 zone_id, uint16 instance_id) { std::string query; if (!RuleB(Zone, EnableShadowrest)){ - query = StringFormat("SELECT id, charid, charname, x, y, z, heading, time_of_death, is_rezzed, was_at_graveyard FROM character_corpses WHERE zone_id='%u' AND instance_id='%u'", zone_id, instance_id); + query = StringFormat("SELECT id, charid, charname, x, y, z, heading, time_of_death, is_rezzed, was_at_graveyard, guild_consent_id FROM character_corpses WHERE zone_id='%u' AND instance_id='%u'", zone_id, instance_id); } else{ - query = StringFormat("SELECT id, charid, charname, x, y, z, heading, time_of_death, is_rezzed, 0 as was_at_graveyard FROM character_corpses WHERE zone_id='%u' AND instance_id='%u' AND is_buried=0", zone_id, instance_id); + query = StringFormat("SELECT id, charid, charname, x, y, z, heading, time_of_death, is_rezzed, 0 as was_at_graveyard, guild_consent_id FROM character_corpses WHERE zone_id='%u' AND instance_id='%u' AND is_buried=0", zone_id, instance_id); } auto results = QueryDatabase(query); @@ -4806,7 +4818,8 @@ bool ZoneDatabase::LoadCharacterCorpses(uint32 zone_id, uint16 instance_id) { position, row[7], // time_of_death char* time_of_death atoi(row[8]) == 1, // is_rezzed bool rezzed - atoi(row[9])) + atoi(row[9]), + atoul(row[10])) // guild_consent_id uint32 guild_consent_id ); } diff --git a/zone/zonedb.h b/zone/zonedb.h index d5c02c693..b1d88539d 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -367,8 +367,9 @@ public: uint32 SendCharacterCorpseToGraveyard(uint32 dbid, uint32 zoneid, uint16 instanceid, const glm::vec4& position); uint32 CreateGraveyardRecord(uint32 graveyard_zoneid, const glm::vec4& position); uint32 AddGraveyardIDToZone(uint32 zone_id, uint32 graveyard_id); - uint32 SaveCharacterCorpse(uint32 charid, const char* charname, uint32 zoneid, uint16 instanceid, PlayerCorpse_Struct* dbpc, const glm::vec4& position); - uint32 UpdateCharacterCorpse(uint32 dbid, uint32 charid, const char* charname, uint32 zoneid, uint16 instanceid, PlayerCorpse_Struct* dbpc, const glm::vec4& position, bool rezzed = false); + uint32 SaveCharacterCorpse(uint32 charid, const char* charname, uint32 zoneid, uint16 instanceid, PlayerCorpse_Struct* dbpc, const glm::vec4& position, uint32 guildid); + uint32 UpdateCharacterCorpse(uint32 dbid, uint32 charid, const char* charname, uint32 zoneid, uint16 instanceid, PlayerCorpse_Struct* dbpc, const glm::vec4& position, uint32 guildid, bool rezzed = false); + uint32 UpdateCharacterCorpseConsent(uint32 charid, uint32 guildid); uint32 GetFirstCorpseID(uint32 char_id); uint32 GetCharacterCorpseCount(uint32 char_id); uint32 GetCharacterCorpseID(uint32 char_id, uint8 corpse);