Merge branch 'master' of https://github.com/EQEmu/Server into eqemu_server_db_updates

This commit is contained in:
Uleat 2020-02-06 16:23:25 -05:00
commit 78756f27b6
30 changed files with 475 additions and 339 deletions

View File

@ -45,6 +45,7 @@
#include "eq_packet_structs.h" #include "eq_packet_structs.h"
#include "extprofile.h" #include "extprofile.h"
#include "string_util.h" #include "string_util.h"
#include "database_schema.h"
extern Client client; extern Client client;
@ -338,6 +339,21 @@ bool Database::ReserveName(uint32 account_id, char* name) {
query = StringFormat("INSERT INTO `character_data` SET `account_id` = %i, `name` = '%s'", account_id, name); query = StringFormat("INSERT INTO `character_data` SET `account_id` = %i, `name` = '%s'", account_id, name);
results = QueryDatabase(query); results = QueryDatabase(query);
if (!results.Success() || results.ErrorMessage() != ""){ return false; } if (!results.Success() || results.ErrorMessage() != ""){ return false; }
// Put character into the default guild if rule is being used.
int guild_id = RuleI(Character, DefaultGuild);
if (guild_id != 0) {
int character_id=results.LastInsertedID();
if (character_id > -1) {
query = StringFormat("INSERT INTO `guild_members` SET `char_id` = %i, `guild_id` = '%i'", character_id, guild_id);
results = QueryDatabase(query);
if (!results.Success() || results.ErrorMessage() != ""){
LogInfo("Could not put character [{}] into default Guild", name);
}
}
}
return true; return true;
} }
@ -386,46 +402,18 @@ bool Database::DeleteCharacter(char *character_name) {
LogInfo("DeleteCharacter | Character [{}] ({}) is being [{}]", character_name, character_id, delete_type); LogInfo("DeleteCharacter | Character [{}] ({}) is being [{}]", character_name, character_id, delete_type);
query = StringFormat("DELETE FROM `quest_globals` WHERE `charid` = '%d'", character_id); QueryDatabase(query); for (const auto& iter : DatabaseSchema::GetCharacterTables()) {
query = StringFormat("DELETE FROM `character_activities` WHERE `charid` = '%d'", character_id); QueryDatabase(query); std::string table_name = iter.first;
query = StringFormat("DELETE FROM `character_enabledtasks` WHERE `charid` = '%d'", character_id); QueryDatabase(query); std::string character_id_column_name = iter.second;
query = StringFormat("DELETE FROM `character_tasks` WHERE `charid` = '%d'", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `completed_tasks` WHERE `charid` = '%d'", character_id); QueryDatabase(query); QueryDatabase(fmt::format("DELETE FROM {} WHERE {} = {}", table_name, character_id_column_name, character_id));
query = StringFormat("DELETE FROM `friends` WHERE `charid` = '%d'", character_id); QueryDatabase(query); }
query = StringFormat("DELETE FROM `mail` WHERE `charid` = '%d'", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `timers` WHERE `char_id` = '%d'", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `inventory` WHERE `charid` = '%d'", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `char_recipe_list` WHERE `char_id` = '%d'", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `adventure_stats` WHERE `player_id` ='%d'", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `zone_flags` WHERE `charID` = '%d'", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `titles` WHERE `char_id` = '%d'", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `player_titlesets` WHERE `char_id` = '%d'", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `keyring` WHERE `char_id` = '%d'", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `faction_values` WHERE `char_id` = '%d'", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `instance_list_player` WHERE `charid` = '%d'", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `character_data` WHERE `id` = '%d'", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `character_skills` WHERE `id` = %u", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `character_languages` WHERE `id` = %u", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `character_bind` WHERE `id` = %u", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `character_alternate_abilities` WHERE `id` = %u", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `character_currency` WHERE `id` = %u", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `character_data` WHERE `id` = %u", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `character_spells` WHERE `id` = %u", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `character_memmed_spells` WHERE `id` = %u", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `character_disciplines` WHERE `id` = %u", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `character_material` WHERE `id` = %u", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `character_tribute` WHERE `id` = %u", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `character_bandolier` WHERE `id` = %u", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `character_potionbelt` WHERE `id` = %u", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `character_inspect_messages` WHERE `id` = %u", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `character_leadership_abilities` WHERE `id` = %u", character_id); QueryDatabase(query);
query = StringFormat("DELETE FROM `character_alt_currency` WHERE `char_id` = '%d'", character_id); QueryDatabase(query);
#ifdef BOTS #ifdef BOTS
query = StringFormat("DELETE FROM `guild_members` WHERE `char_id` = '%d' AND GetMobTypeById(%i) = 'C'", character_id); // note: only use of GetMobTypeById() query = StringFormat("DELETE FROM `guild_members` WHERE `char_id` = '%d' AND GetMobTypeById(%i) = 'C'", character_id); // note: only use of GetMobTypeById()
#else
query = StringFormat("DELETE FROM `guild_members` WHERE `char_id` = '%d'", character_id);
#endif
QueryDatabase(query); QueryDatabase(query);
#endif
return true; return true;
} }

View File

@ -22,17 +22,76 @@
#define EQEMU_DATABASE_SCHEMA_H #define EQEMU_DATABASE_SCHEMA_H
#include <vector> #include <vector>
#include <map>
namespace DatabaseSchema { namespace DatabaseSchema {
/** /**
* Gets player tables * Character-specific tables
*
* Does not included related meta-data tables such as 'guilds', 'accounts'
* @return
*/
static std::map<std::string, std::string> GetCharacterTables()
{
return {
{"adventure_stats", "player_id"},
{"buyer", "charid"},
{"char_recipe_list", "char_id"},
{"character_activities", "charid"},
{"character_alt_currency", "char_id"},
{"character_alternate_abilities", "id"},
{"character_auras", "id"},
{"character_bandolier", "id"},
{"character_bind", "id"},
{"character_buffs", "character_id"},
{"character_corpses", "id"},
{"character_currency", "id"},
{"character_data", "id"},
{"character_disciplines", "id"},
{"character_enabledtasks", "charid"},
{"character_inspect_messages", "id"},
{"character_item_recast", "id"},
{"character_languages", "id"},
{"character_leadership_abilities", "id"},
{"character_material", "id"},
{"character_memmed_spells", "id"},
{"character_pet_buffs", "char_id"},
{"character_pet_info", "char_id"},
{"character_pet_inventory", "char_id"},
{"character_potionbelt", "id"},
{"character_skills", "id"},
{"character_spells", "id"},
{"character_tasks", "charid"},
{"character_tribute", "id"},
{"completed_tasks", "charid"},
{"data_buckets", "id"},
{"faction_values", "char_id"},
{"friends", "charid"},
{"guild_members", "char_id"},
{"guilds", "id"},
{"instance_list_player", "id"},
{"inventory", "charid"},
{"inventory_snapshots", "charid"},
{"keyring", "char_id"},
{"mail", "charid"},
{"player_titlesets", "char_id"},
{"quest_globals", "charid"},
{"timers", "char_id"},
{"titles", "char_id"},
{"trader", "char_id"},
{"zone_flags", "charID"}
};
}
/**
* Gets all player and meta-data tables
* *
* @return * @return
*/ */
static std::vector<std::string> GetPlayerTables() static std::vector<std::string> GetPlayerTables()
{ {
std::vector<std::string> tables = { return {
"account", "account",
"account_ip", "account_ip",
"account_flags", "account_flags",
@ -91,8 +150,6 @@ namespace DatabaseSchema {
"trader_audit", "trader_audit",
"zone_flags" "zone_flags"
}; };
return tables;
} }
/** /**
@ -102,7 +159,7 @@ namespace DatabaseSchema {
*/ */
static std::vector<std::string> GetContentTables() static std::vector<std::string> GetContentTables()
{ {
std::vector<std::string> tables = { return {
"aa_ability", "aa_ability",
"aa_actions", "aa_actions",
"aa_effects", "aa_effects",
@ -188,8 +245,6 @@ namespace DatabaseSchema {
"zone_server", "zone_server",
"zoneserver_auth", "zoneserver_auth",
}; };
return tables;
} }
/** /**
@ -199,7 +254,7 @@ namespace DatabaseSchema {
*/ */
static std::vector<std::string> GetServerTables() static std::vector<std::string> GetServerTables()
{ {
std::vector<std::string> tables = { return {
"banned_ips", "banned_ips",
"bugs", "bugs",
"bug_reports", "bug_reports",
@ -225,8 +280,6 @@ namespace DatabaseSchema {
"saylink", "saylink",
"variables", "variables",
}; };
return tables;
} }
/** /**
@ -237,7 +290,7 @@ namespace DatabaseSchema {
*/ */
static std::vector<std::string> GetStateTables() static std::vector<std::string> GetStateTables()
{ {
std::vector<std::string> tables = { return {
"adventure_members", "adventure_members",
"chatchannels", "chatchannels",
"group_id", "group_id",
@ -253,8 +306,6 @@ namespace DatabaseSchema {
"spell_buckets", "spell_buckets",
"spell_globals", "spell_globals",
}; };
return tables;
} }
/** /**
@ -264,15 +315,13 @@ namespace DatabaseSchema {
*/ */
static std::vector<std::string> GetLoginTables() static std::vector<std::string> GetLoginTables()
{ {
std::vector<std::string> tables = { return {
"login_accounts", "login_accounts",
"login_api_tokens", "login_api_tokens",
"login_server_admins", "login_server_admins",
"login_server_list_types", "login_server_list_types",
"login_world_servers", "login_world_servers",
}; };
return tables;
} }
/** /**
@ -282,12 +331,10 @@ namespace DatabaseSchema {
*/ */
static std::vector<std::string> GetVersionTables() static std::vector<std::string> GetVersionTables()
{ {
std::vector<std::string> tables = { return {
"db_version", "db_version",
"inventory_versions", "inventory_versions",
}; };
return tables;
} }
} }

View File

@ -115,14 +115,14 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
auto errorBuffer = new char[MYSQL_ERRMSG_SIZE]; auto errorBuffer = new char[MYSQL_ERRMSG_SIZE];
snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql)); snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
/* Implement Logging at the Root */ /**
* Error logging
*/
if (mysql_errno(&mysql) > 0 && strlen(query) > 0) { if (mysql_errno(&mysql) > 0 && strlen(query) > 0) {
if (LogSys.log_settings[Logs::MySQLError].is_category_enabled == 1) LogMySQLError("[{}] [{}]\n[{}]", mysql_errno(&mysql), mysql_error(&mysql), query);
Log(Logs::General, Logs::MySQLError, "%i: %s \n %s", mysql_errno(&mysql), mysql_error(&mysql), query);
} }
return MySQLRequestResult(nullptr, 0, 0, 0, 0, mysql_errno(&mysql), errorBuffer); return MySQLRequestResult(nullptr, 0, 0, 0, 0, mysql_errno(&mysql), errorBuffer);
} }
// successful query. get results. // successful query. get results.
@ -143,9 +143,7 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
if (LogSys.log_settings[Logs::MySQLQuery].is_category_enabled == 1) { if (LogSys.log_settings[Logs::MySQLQuery].is_category_enabled == 1) {
if ((strncasecmp(query, "select", 6) == 0)) { if ((strncasecmp(query, "select", 6) == 0)) {
LogF( LogMySQLQuery(
Logs::General,
Logs::MySQLQuery,
"{0} ({1} row{2} returned) ({3}s)", "{0} ({1} row{2} returned) ({3}s)",
query, query,
requestResult.RowCount(), requestResult.RowCount(),
@ -154,9 +152,7 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
); );
} }
else { else {
LogF( LogMySQLQuery(
Logs::General,
Logs::MySQLQuery,
"{0} ({1} row{2} affected) ({3}s)", "{0} ({1} row{2} affected) ({3}s)",
query, query,
requestResult.RowsAffected(), requestResult.RowsAffected(),

View File

@ -317,6 +317,15 @@ namespace EQEmu
QuestControlGrid = -1 QuestControlGrid = -1
}; };
namespace consent {
enum eConsentType : uint8 {
Normal = 0,
Group,
Raid,
Guild
};
}; // namespace consent
} /*EQEmu*/ } /*EQEmu*/
#endif /*COMMON_EMU_CONSTANTS_H*/ #endif /*COMMON_EMU_CONSTANTS_H*/

View File

@ -89,9 +89,9 @@ namespace EQ {
public: public:
StaticPacket(void *data, size_t size) { m_data = data; m_data_length = size; m_max_data_length = size; } StaticPacket(void *data, size_t size) { m_data = data; m_data_length = size; m_max_data_length = size; }
virtual ~StaticPacket() { } virtual ~StaticPacket() { }
StaticPacket(const StaticPacket &o) { m_data = o.m_data; m_data_length = o.m_data_length; } StaticPacket(const StaticPacket &o) { m_data = o.m_data; m_data_length = o.m_data_length; m_max_data_length = o.m_max_data_length; }
StaticPacket& operator=(const StaticPacket &o) { m_data = o.m_data; m_data_length = o.m_data_length; return *this; } StaticPacket& operator=(const StaticPacket &o) { m_data = o.m_data; m_data_length = o.m_data_length; return *this; }
StaticPacket(StaticPacket &&o) { m_data = o.m_data; m_data_length = o.m_data_length; } StaticPacket(StaticPacket &&o) noexcept { m_data = o.m_data; m_data_length = o.m_data_length; }
virtual const void *Data() const { return m_data; } virtual const void *Data() const { return m_data; }
virtual void *Data() { return m_data; } virtual void *Data() { return m_data; }
@ -112,7 +112,7 @@ namespace EQ {
public: public:
DynamicPacket() { } DynamicPacket() { }
virtual ~DynamicPacket() { } virtual ~DynamicPacket() { }
DynamicPacket(DynamicPacket &&o) { m_data = std::move(o.m_data); } DynamicPacket(DynamicPacket &&o) noexcept { m_data = std::move(o.m_data); }
DynamicPacket(const DynamicPacket &o) { m_data = o.m_data; } DynamicPacket(const DynamicPacket &o) { m_data = o.m_data; }
DynamicPacket& operator=(const DynamicPacket &o) { m_data = o.m_data; return *this; } DynamicPacket& operator=(const DynamicPacket &o) { m_data = o.m_data; return *this; }

View File

@ -159,6 +159,7 @@ RULE_BOOL(Character, PetsUseReagents, true, "Pets use reagent on spells")
RULE_BOOL(Character, DismountWater, true, "Dismount horses when entering water") RULE_BOOL(Character, DismountWater, true, "Dismount horses when entering water")
RULE_BOOL(Character, UseNoJunkFishing, false, "Disregards junk items when fishing") RULE_BOOL(Character, UseNoJunkFishing, false, "Disregards junk items when fishing")
RULE_BOOL(Character, SoftDeletes, true, "When characters are deleted in character select, they are only soft deleted") RULE_BOOL(Character, SoftDeletes, true, "When characters are deleted in character select, they are only soft deleted")
RULE_INT(Character, DefaultGuild, 0, "If not 0, new characters placed into the guild # indicated")
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(Mercs) RULE_CATEGORY(Mercs)
@ -294,6 +295,7 @@ RULE_BOOL(Pathing, Find, true, "Enable pathing for FindPerson requests from the
RULE_BOOL(Pathing, Fear, true, "Enable pathing for fear") RULE_BOOL(Pathing, Fear, true, "Enable pathing for fear")
RULE_REAL(Pathing, NavmeshStepSize, 100.0f, "") RULE_REAL(Pathing, NavmeshStepSize, 100.0f, "")
RULE_REAL(Pathing, ShortMovementUpdateRange, 130.0f, "") RULE_REAL(Pathing, ShortMovementUpdateRange, 130.0f, "")
RULE_INT(Pathing, MaxNavmeshNodes, 4092, "Max navmesh nodes in a traversable path")
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(Watermap) RULE_CATEGORY(Watermap)
@ -492,6 +494,7 @@ RULE_INT(Combat, NPCAssistCapTimer, 6000, "Time in milliseconds a NPC will take
RULE_BOOL(Combat, UseRevampHandToHand, false, "use h2h revamped dmg/delays I believe this was implemented during SoF") RULE_BOOL(Combat, UseRevampHandToHand, false, "use h2h revamped dmg/delays I believe this was implemented during SoF")
RULE_BOOL(Combat, ClassicMasterWu, false, "classic master wu uses a random special, modern doesn't") RULE_BOOL(Combat, ClassicMasterWu, false, "classic master wu uses a random special, modern doesn't")
RULE_INT(Combat, LevelToStopDamageCaps, 0, "1 will effectively disable them, 20 should give basically same results as old incorrect system") RULE_INT(Combat, LevelToStopDamageCaps, 0, "1 will effectively disable them, 20 should give basically same results as old incorrect system")
RULE_INT(Combat, LevelToStopACTwinkControl, 50, "1 will effectively disable it, 50 should give basically same results as current system")
RULE_BOOL(Combat, ClassicNPCBackstab, false, "true disables npc facestab - npcs get normal attack if not behind") RULE_BOOL(Combat, ClassicNPCBackstab, false, "true disables npc facestab - npcs get normal attack if not behind")
RULE_BOOL(Combat, UseNPCDamageClassLevelMods, true, "Uses GetClassLevelDamageMod calc in npc_scale_manager") RULE_BOOL(Combat, UseNPCDamageClassLevelMods, true, "Uses GetClassLevelDamageMod calc in npc_scale_manager")
RULE_BOOL(Combat, UseExtendedPoisonProcs, false, "Allow old school poisons to last until characrer zones, at a lower proc rate") RULE_BOOL(Combat, UseExtendedPoisonProcs, false, "Allow old school poisons to last until characrer zones, at a lower proc rate")
@ -523,6 +526,7 @@ RULE_INT(NPC, NPCGatePercent, 20, "% at which the NPC Will attempt to gate at")
RULE_BOOL(NPC, NPCGateNearBind, false, "Will NPC attempt to gate when near bind location?") RULE_BOOL(NPC, NPCGateNearBind, false, "Will NPC attempt to gate when near bind location?")
RULE_INT(NPC, NPCGateDistanceBind, 75, "Distance from bind before NPC will attempt to gate") RULE_INT(NPC, NPCGateDistanceBind, 75, "Distance from bind before NPC will attempt to gate")
RULE_BOOL(NPC, NPCHealOnGate, true, "Will the NPC Heal on Gate") RULE_BOOL(NPC, NPCHealOnGate, true, "Will the NPC Heal on Gate")
RULE_BOOL(NPC, UseMeditateBasedManaRegen, false, "Based NPC ooc regen on Meditate skill")
RULE_REAL(NPC, NPCHealOnGateAmount, 25, "How much the npc will heal on gate if enabled") RULE_REAL(NPC, NPCHealOnGateAmount, 25, "How much the npc will heal on gate if enabled")
RULE_CATEGORY_END() RULE_CATEGORY_END()

View File

@ -866,10 +866,12 @@ struct SpawnPlayerCorpse_Struct {
struct ServerOP_Consent_Struct { struct ServerOP_Consent_Struct {
char grantname[64]; char grantname[64];
char ownername[64]; char ownername[64];
char zonename[32];
uint8 permission; uint8 permission;
uint32 zone_id; uint32 zone_id;
uint16 instance_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 { struct ReloadTasks_Struct {

View File

@ -34,7 +34,7 @@
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt * 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 9149
#ifdef BOTS #ifdef BOTS
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9026 #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9026

View File

@ -401,6 +401,8 @@
9145|2019_12_24_banned_ips_update.sql|SHOW TABLES LIKE 'Banned_IPs'|not_empty| 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| 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| 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|
9149|2020_02_06_globalloot.sql|SHOW COLUMNS FROM `global_loot` LIKE 'hot_zone'|empty|
# Upgrade conditions: # Upgrade conditions:
# This won't be needed after this system is implemented, but it is used database that are not # This won't be needed after this system is implemented, but it is used database that are not

View File

@ -0,0 +1 @@
ALTER TABLE `character_corpses` ADD COLUMN `guild_consent_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `time_of_death`;

View File

@ -0,0 +1,2 @@
ALTER TABLE `global_loot` ADD `hot_zone` TINYINT NULL;

View File

@ -1057,110 +1057,42 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
break; break;
} }
case ServerOP_Consent: { case ServerOP_Consent: {
// Message string id's likely to be used here are: zoneserver_list.SendPacket(pack); // update corpses in all zones
// 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);
}
break; break;
} }
case ServerOP_Consent_Response: { 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; ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer;
if (s->instance_id != 0)
{ ZoneServer* owner_zs = nullptr;
ZoneServer* zs = zoneserver_list.FindByInstanceID(s->instance_id); if (s->instance_id == 0) {
if (zs) { owner_zs = zoneserver_list.FindByZoneID(s->zone_id);
zs->SendPacket(pack);
}
else {
LogInfo("Unable to locate zone record for instance id [{}] in zoneserver list for ServerOP_Consent_Response operation", s->instance_id);
}
} }
else else {
{ owner_zs = zoneserver_list.FindByInstanceID(s->instance_id);
ZoneServer* zs = zoneserver_list.FindByZoneID(s->zone_id); }
if (zs) {
zs->SendPacket(pack); if (owner_zs) {
} owner_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 {
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; break;

View File

@ -799,7 +799,7 @@ int Mob::ACSum()
// EQ math // EQ math
ac = (ac * 4) / 3; ac = (ac * 4) / 3;
// anti-twink // anti-twink
if (IsClient() && GetLevel() < 50) if (IsClient() && GetLevel() < RuleI(Combat, LevelToStopACTwinkControl))
ac = std::min(ac, 25 + 6 * GetLevel()); ac = std::min(ac, 25 + 6 * GetLevel());
ac = std::max(0, ac + GetClassRaceACBonus()); ac = std::max(0, ac + GetClassRaceACBonus());
if (IsNPC()) { if (IsNPC()) {

View File

@ -165,6 +165,7 @@ Client::Client(EQStreamInterface* ieqs)
hp_self_update_throttle_timer(300), hp_self_update_throttle_timer(300),
hp_other_update_throttle_timer(500), hp_other_update_throttle_timer(500),
position_update_timer(10000), position_update_timer(10000),
consent_throttle_timer(2000),
tmSitting(0) 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) 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()) if(!target || !IsValidSpell(spell_id) || this->GetID() == target->GetID())

View File

@ -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]); } 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 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 SummonHorse(uint16 spell_id);
void SetHorseId(uint16 horseid_in); void SetHorseId(uint16 horseid_in);
@ -957,7 +960,6 @@ public:
void EnteringMessages(Client* client); void EnteringMessages(Client* client);
void SendRules(Client* client); void SendRules(Client* client);
std::list<std::string> consent_list;
const bool GetGMSpeed() const { return (gmspeed > 0); } const bool GetGMSpeed() const { return (gmspeed > 0); }
bool CanUseReport; bool CanUseReport;
@ -1137,6 +1139,7 @@ public:
inline bool IsDraggingCorpse() { return (DraggedCorpses.size() > 0); } inline bool IsDraggingCorpse() { return (DraggedCorpses.size() > 0); }
void DragCorpses(); void DragCorpses();
inline void ClearDraggedCorpses() { DraggedCorpses.clear(); } inline void ClearDraggedCorpses() { DraggedCorpses.clear(); }
void ConsentCorpses(std::string consent_name, bool deny = false);
void SendAltCurrencies(); void SendAltCurrencies();
void SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount); void SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount);
void AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 method = 0); 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_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 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 position_update_timer; /* Timer used when client hasn't updated within a 10 second window */
Timer consent_throttle_timer;
glm::vec3 m_Proximity; glm::vec3 m_Proximity;
glm::vec4 last_position_before_bulk_update; glm::vec4 last_position_before_bulk_update;

View File

@ -4643,43 +4643,16 @@ void Client::Handle_OP_Consent(const EQApplicationPacket *app)
{ {
if (app->size<64) { if (app->size<64) {
Consent_Struct* c = (Consent_Struct*)app->pBuffer; Consent_Struct* c = (Consent_Struct*)app->pBuffer;
if (strcmp(c->name, GetName()) != 0) { ConsentCorpses(c->name, false);
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);
}
} }
return;
} }
void Client::Handle_OP_ConsentDeny(const EQApplicationPacket *app) void Client::Handle_OP_ConsentDeny(const EQApplicationPacket *app)
{ {
if (app->size<64) { if (app->size<64) {
Consent_Struct* c = (Consent_Struct*)app->pBuffer; Consent_Struct* c = (Consent_Struct*)app->pBuffer;
auto pack = new ServerPacket(ServerOP_Consent, sizeof(ServerOP_Consent_Struct)); ConsentCorpses(c->name, true);
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);
} }
return;
} }
void Client::Handle_OP_Consider(const EQApplicationPacket *app) 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); 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 { else {
std::cout << "Unknown SpawnAppearance type: 0x" << std::hex << std::setw(4) << std::setfill('0') << sa->type << std::dec 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; << " value: 0x" << std::hex << std::setw(8) << std::setfill('0') << sa->parameter << std::dec << std::endl;

View File

@ -2543,7 +2543,7 @@ void command_size(Client *c, const Seperator *sep)
else if (!target) else if (!target)
c->Message(Chat::White,"Error: this command requires a target"); c->Message(Chat::White,"Error: this command requires a target");
else { else {
uint16 Race = target->GetRace(); uint16 Race = target->GetModel();
uint8 Gender = target->GetGender(); uint8 Gender = target->GetGender();
uint8 Texture = 0xFF; uint8 Texture = 0xFF;
uint8 HelmTexture = 0xFF; uint8 HelmTexture = 0xFF;

View File

@ -73,7 +73,7 @@ void Corpse::SendLootReqErrorPacket(Client* client, LootResponse response) {
safe_delete(outapp); 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); uint32 item_count = database.GetCharacterCorpseItemCount(in_dbid);
auto buffer = auto buffer =
new char[sizeof(PlayerCorpse_Struct) + (item_count * sizeof(player_lootitem::ServerLootItem_Struct))]; 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->drakkin_details = pcs->drakkin_details;
pc->IsRezzed(rezzed); pc->IsRezzed(rezzed);
pc->become_npc = false; pc->become_npc = false;
pc->consented_guild_id = guild_consent_id;
pc->UpdateEquipmentLight(); // itemlist populated above..need to determine actual values 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; 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; is_corpse_changed = true;
rez_experience = in_rezexp; rez_experience = in_rezexp;
can_corpse_be_rezzed = true; can_corpse_be_rezzed = true;
@ -611,11 +624,11 @@ bool Corpse::Save() {
/* Create New Corpse*/ /* Create New Corpse*/
if (corpse_db_id == 0) { 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 */ /* Update Corpse Data */
else{ 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); safe_delete_array(dbpc);
@ -647,6 +660,25 @@ void Corpse::DepopPlayerCorpse() {
player_corpse_depop = true; 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() { uint32 Corpse::CountItems() {
return itemlist.size(); return itemlist.size();
} }
@ -1434,29 +1466,50 @@ bool Corpse::Summon(Client* client, bool spell, bool CheckDistance) {
is_corpse_changed = true; is_corpse_changed = true;
} }
else { else {
client->Message(Chat::White, "Corpse is too far away."); client->MessageString(Chat::Red, CORPSE_TOO_FAR);
return false; return false;
} }
} }
else else
{ {
bool consented = false; bool consented = false;
std::list<std::string>::iterator itr; for (const auto& consented_player_name : consented_player_names) {
for(itr = client->consent_list.begin(); itr != client->consent_list.end(); ++itr) { if (strcasecmp(client->GetName(), consented_player_name.c_str()) == 0) {
if(strcmp(this->GetOwnerName(), itr->c_str()) == 0) { consented = true;
if (!CheckDistance || (DistanceSquaredNoZ(m_Position, client->GetPosition()) <= dist2)) { break;
GMMove(client->GetX(), client->GetY(), client->GetZ()); }
is_corpse_changed = true; }
}
else { if (!consented && consented_guild_id && consented_guild_id != GUILD_NONE) {
client->Message(Chat::White, "Corpse is too far away."); if (client->GuildID() == consented_guild_id) {
return false;
}
consented = true; consented = true;
} }
} }
if(!consented) { if (!consented && consented_group_id) {
client->Message(Chat::White, "You do not have permission to move this corpse."); 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; return false;
} }
} }

View File

@ -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(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(); ~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 */ /* Corpse: General */
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill) { return true; } 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 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(); } uint32 GetRezTime() { if (!corpse_rez_timer.Enabled()) return 0; else return corpse_rez_timer.GetRemainingTime(); }
void SetDecayTimer(uint32 decay_time); 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 Delete();
void Bury(); void Bury();
@ -142,6 +147,9 @@ private:
int32 player_kill_item; /* Determines if Player Kill Item */ int32 player_kill_item; /* Determines if Player Kill Item */
uint32 corpse_db_id; /* Corpse Database ID (Player Corpse) */ uint32 corpse_db_id; /* Corpse Database ID (Player Corpse) */
uint32 char_id; /* Character ID */ 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 */ ItemList itemlist; /* Internal Item list used for corpses */
uint32 copper; uint32 copper;
uint32 silver; uint32 silver;
@ -160,6 +168,7 @@ private:
Timer corpse_graveyard_timer; Timer corpse_graveyard_timer;
Timer loot_cooldown_timer; /* Delay between loot actions on the corpse entity */ Timer loot_cooldown_timer; /* Delay between loot actions on the corpse entity */
EQEmu::TintProfile item_tint; EQEmu::TintProfile item_tint;
std::vector<std::string> consented_player_names;
LootRequestType loot_request_type; LootRequestType loot_request_type;
}; };

View File

@ -1,6 +1,9 @@
#include "global_loot_manager.h" #include "global_loot_manager.h"
#include "npc.h" #include "npc.h"
#include "client.h" #include "client.h"
#include "zone.h"
extern Zone *zone;
std::vector<int> GlobalLootManager::GetGlobalLootTables(NPC *mob) const std::vector<int> GlobalLootManager::GetGlobalLootTables(NPC *mob) const
{ {
@ -78,6 +81,12 @@ bool GlobalLootEntry::PassesRules(NPC *mob) const
if (mob->GetBodyType() == r.value) if (mob->GetBodyType() == r.value)
bPassesBodyType = true; bPassesBodyType = true;
break; break;
case GlobalLoot::RuleTypes::HotZone: // value == 0 must not be hot_zone, value != must be hot_zone
if (zone->IsHotzone() && !r.value)
return false;
if (!zone->IsHotzone() && r.value)
return false;
break;
default: default:
break; break;
} }

View File

@ -17,6 +17,7 @@ enum class RuleTypes {
BodyType = 4, BodyType = 4,
Rare = 5, Rare = 5,
Raid = 6, Raid = 6,
HotZone = 7,
Max Max
}; };

View File

@ -464,7 +464,7 @@ void NPC::CheckGlobalLootTables()
void ZoneDatabase::LoadGlobalLoot() void ZoneDatabase::LoadGlobalLoot()
{ {
auto query = StringFormat("SELECT id, loottable_id, description, min_level, max_level, rare, raid, race, " auto query = StringFormat("SELECT id, loottable_id, description, min_level, max_level, rare, raid, race, "
"class, bodytype, zone FROM global_loot WHERE enabled = 1"); "class, bodytype, zone, hot_zone FROM global_loot WHERE enabled = 1");
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
if (!results.Success() || results.RowCount() == 0) if (!results.Success() || results.RowCount() == 0)
@ -518,9 +518,13 @@ void ZoneDatabase::LoadGlobalLoot()
auto bodytypes = SplitString(row[9], '|'); auto bodytypes = SplitString(row[9], '|');
for (auto &b : bodytypes) for (auto &b : bodytypes)
e.AddRule(GlobalLoot::RuleTypes::Class, std::stoi(b)); e.AddRule(GlobalLoot::RuleTypes::BodyType, std::stoi(b));
} }
// null is not used
if (row[11])
e.AddRule(GlobalLoot::RuleTypes::HotZone, atoi(row[11]));
zone->AddGlobalLootEntry(e); zone->AddGlobalLootEntry(e);
} }
} }

View File

@ -685,7 +685,7 @@ int Mob::_GetRunSpeed() const {
int runspeedcap = RuleI(Character,BaseRunSpeedCap); int runspeedcap = RuleI(Character,BaseRunSpeedCap);
runspeedcap += itembonuses.IncreaseRunSpeedCap + spellbonuses.IncreaseRunSpeedCap + aabonuses.IncreaseRunSpeedCap; runspeedcap += itembonuses.IncreaseRunSpeedCap + spellbonuses.IncreaseRunSpeedCap + aabonuses.IncreaseRunSpeedCap;
aa_mod = itembonuses.IncreaseRunSpeedCap + spellbonuses.IncreaseRunSpeedCap + aabonuses.IncreaseRunSpeedCap; aa_mod += aabonuses.BaseMovementSpeed + aabonuses.movementspeed;
int spell_mod = spellbonuses.movementspeed + itembonuses.movementspeed; int spell_mod = spellbonuses.movementspeed + itembonuses.movementspeed;
int movemod = 0; int movemod = 0;

View File

@ -1300,7 +1300,9 @@ void MobMovementManager::PushEvadeCombat(MobMovementEntry &mob_movement_entry)
*/ */
void MobMovementManager::HandleStuckBehavior(Mob *who, float x, float y, float z, MobMovementMode mob_movement_mode) void MobMovementManager::HandleStuckBehavior(Mob *who, float x, float y, float z, MobMovementMode mob_movement_mode)
{ {
auto sb = who->GetStuckBehavior(); LogDebug("Handle stuck behavior for {0} at ({1}, {2}, {3}) with movement_mode {4}", who->GetName(), x, y, z, mob_movement_mode);
auto sb = who->GetStuckBehavior();
MobStuckBehavior behavior = RunToTarget; MobStuckBehavior behavior = RunToTarget;
if (sb >= 0 && sb < MaxStuckBehavior) { if (sb >= 0 && sb < MaxStuckBehavior) {
@ -1308,7 +1310,7 @@ void MobMovementManager::HandleStuckBehavior(Mob *who, float x, float y, float z
} }
auto eiter = _impl->Entries.find(who); auto eiter = _impl->Entries.find(who);
auto &ent = (*eiter); auto &ent = (*eiter);
switch (sb) { switch (sb) {
case RunToTarget: case RunToTarget:
@ -1323,8 +1325,7 @@ void MobMovementManager::HandleStuckBehavior(Mob *who, float x, float y, float z
PushStopMoving(ent.second); PushStopMoving(ent.second);
break; break;
case EvadeCombat: case EvadeCombat:
//PushEvadeCombat(ent.second); PushEvadeCombat(ent.second);
PushStopMoving(ent.second);
break; break;
} }
} }

View File

@ -778,7 +778,20 @@ bool NPC::Process()
} }
if (GetMana() < GetMaxMana()) { if (GetMana() < GetMaxMana()) {
SetMana(GetMana() + mana_regen + npc_sitting_regen_bonus); if (RuleB(NPC, UseMeditateBasedManaRegen)) {
int32 npc_idle_mana_regen_bonus = 2;
uint16 meditate_skill = GetSkill(EQEmu::skills::SkillMeditate);
if (!IsEngaged() && meditate_skill > 0) {
uint8 clevel = GetLevel();
npc_idle_mana_regen_bonus =
(((meditate_skill / 10) +
(clevel - (clevel / 4))) / 4) + 4;
}
SetMana(GetMana() + mana_regen + npc_idle_mana_regen_bonus);
}
else {
SetMana(GetMana() + mana_regen + npc_sitting_regen_bonus);
}
} }
SendHPUpdate(); SendHPUpdate();

View File

@ -12,8 +12,6 @@
extern Zone *zone; extern Zone *zone;
const int MaxNavmeshNodes = 1024;
struct PathfinderNavmesh::Implementation struct PathfinderNavmesh::Implementation
{ {
dtNavMesh *nav_mesh; dtNavMesh *nav_mesh;
@ -45,7 +43,7 @@ IPathfinder::IPath PathfinderNavmesh::FindRoute(const glm::vec3 &start, const gl
m_impl->query = dtAllocNavMeshQuery(); m_impl->query = dtAllocNavMeshQuery();
} }
m_impl->query->init(m_impl->nav_mesh, MaxNavmeshNodes); m_impl->query->init(m_impl->nav_mesh, RuleI(Pathing, MaxNavmeshNodes));
glm::vec3 current_location(start.x, start.z, start.y); glm::vec3 current_location(start.x, start.z, start.y);
glm::vec3 dest_location(end.x, end.z, end.y); glm::vec3 dest_location(end.x, end.z, end.y);
@ -143,7 +141,7 @@ IPathfinder::IPath PathfinderNavmesh::FindPath(const glm::vec3 &start, const glm
m_impl->query = dtAllocNavMeshQuery(); m_impl->query = dtAllocNavMeshQuery();
} }
m_impl->query->init(m_impl->nav_mesh, MaxNavmeshNodes); m_impl->query->init(m_impl->nav_mesh, RuleI(Pathing, MaxNavmeshNodes));
glm::vec3 current_location(start.x, start.z, start.y); glm::vec3 current_location(start.x, start.z, start.y);
glm::vec3 dest_location(end.x, end.z, end.y); glm::vec3 dest_location(end.x, end.z, end.y);
@ -174,18 +172,13 @@ IPathfinder::IPath PathfinderNavmesh::FindPath(const glm::vec3 &start, const glm
int npoly = 0; int npoly = 0;
dtPolyRef path[max_polys] = { 0 }; dtPolyRef path[max_polys] = { 0 };
m_impl->query->findPath(start_ref, end_ref, &current_location[0], &dest_location[0], &filter, path, &npoly, max_polys); auto status = m_impl->query->findPath(start_ref, end_ref, &current_location[0], &dest_location[0], &filter, path, &npoly, max_polys);
if (npoly) { if (npoly) {
glm::vec3 epos = dest_location; glm::vec3 epos = dest_location;
if (path[npoly - 1] != end_ref) { if (path[npoly - 1] != end_ref) {
m_impl->query->closestPointOnPoly(path[npoly - 1], &dest_location[0], &epos[0], 0); m_impl->query->closestPointOnPoly(path[npoly - 1], &dest_location[0], &epos[0], 0);
partial = true; partial = true;
auto dist = DistanceSquared(epos, current_location);
if (dist < 10000.0f) {
stuck = true;
}
} }
int n_straight_polys; int n_straight_polys;
@ -313,7 +306,7 @@ glm::vec3 PathfinderNavmesh::GetRandomLocation(const glm::vec3 &start)
if (!m_impl->query) { if (!m_impl->query) {
m_impl->query = dtAllocNavMeshQuery(); m_impl->query = dtAllocNavMeshQuery();
m_impl->query->init(m_impl->nav_mesh, MaxNavmeshNodes); m_impl->query->init(m_impl->nav_mesh, RuleI(Pathing, MaxNavmeshNodes));
} }
dtQueryFilter filter; dtQueryFilter filter;

View File

@ -122,11 +122,13 @@
#define LOOT_LORE_ERROR 371 //You cannot loot this Lore Item. You already have one. #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 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 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 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 DISCIPLINE_RDY 393 //You are ready to use a new discipline now.
#define CONSENT_INVALID_NAME 397 //Not a valid consent name. #define CONSENT_INVALID_NAME 397 //Not a valid consent name.
#define CONSENT_NPC 398 //You cannot consent NPC\'s. #define CONSENT_NPC 398 //You cannot consent NPC\'s.
#define CONSENT_YOURSELF 399 //You cannot consent yourself. #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_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_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 #define SONG_NEEDS_STRINGS 407 //You need to play a stringed instrument for this song

View File

@ -1442,50 +1442,65 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
} }
case ServerOP_Consent: { case ServerOP_Consent: {
ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer; 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 = bool found_corpse = false;
new EQApplicationPacket(OP_ConsentResponse, sizeof(ConsentResponse_Struct)); for (auto const& it : entity_list.GetCorpseList()) {
ConsentResponse_Struct* crs = (ConsentResponse_Struct*)outapp->pBuffer; if (it.second->IsPlayerCorpse() && strcmp(it.second->GetOwnerName(), s->ownername) == 0) {
strcpy(crs->grantname, s->grantname); if (s->consent_type == EQEmu::consent::Normal) {
strcpy(crs->ownername, s->ownername); if (s->permission == 1) {
crs->permission = s->permission; it.second->AddConsentName(s->grantname);
strcpy(crs->zonename, "all zones"); }
client->QueuePacket(outapp); else {
safe_delete(outapp); 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: if (found_corpse) {
// CONSENT_YOURSELF = 399 // forward the grant/deny message for this zone to both owner and granted
// CONSENT_INVALID_NAME = 397 auto outapp = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
// TARGET_NOT_FOUND = 101 ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)outapp->pBuffer;
memcpy(outapp->pBuffer, s, sizeof(ServerOP_Consent_Struct));
auto scs_pack = if (zone) {
new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct)); strn0cpy(scs->zonename, zone->GetLongName(), sizeof(scs->zonename));
ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)scs_pack->pBuffer; }
strcpy(scs->grantname, s->grantname); worldserver.SendPacket(outapp);
strcpy(scs->ownername, s->ownername); safe_delete(outapp);
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);
} }
break; break;
} }
case ServerOP_Consent_Response: { case ServerOP_Consent_Response: {
ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer; ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer;
Client* client = entity_list.GetClientByName(s->ownername); Client* owner_client = entity_list.GetClientByName(s->ownername);
if (client) { Client* grant_client = nullptr;
client->MessageString(Chat::White, s->message_string_id); 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; break;
} }

View File

@ -4288,10 +4288,10 @@ uint32 ZoneDatabase::GetCharacterCorpseDecayTimer(uint32 corpse_db_id){
return 0; 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` " std::string query = StringFormat("UPDATE `character_corpses` "
"SET `charname` = '%s', `zone_id` = %u, `instance_id` = %u, `charid` = %d, " "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, " "`is_locked` = %d, `exp` = %u, `size` = %f, `level` = %u, "
"`race` = %u, `gender` = %u, `class` = %u, `deity` = %u, " "`race` = %u, `gender` = %u, `class` = %u, `deity` = %u, "
"`texture` = %u, `helm_texture` = %u, `copper` = %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 " "`wc_7` = %u, `wc_8` = %u, `wc_9` = %u "
"WHERE `id` = %u", "WHERE `id` = %u",
EscapeString(char_name).c_str(), zone_id, instance_id, char_id, 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->locked, dbpc->exp, dbpc->size, dbpc->level, dbpc->race,
dbpc->gender, dbpc->class_, dbpc->deity, dbpc->texture, dbpc->gender, dbpc->class_, dbpc->deity, dbpc->texture,
dbpc->helmtexture, dbpc->copper, dbpc->silver, dbpc->gold, 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; 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) { void ZoneDatabase::MarkCorpseAsRezzed(uint32 db_id) {
std::string query = StringFormat("UPDATE `character_corpses` SET `is_rezzed` = 1 WHERE `id` = %i", db_id); std::string query = StringFormat("UPDATE `character_corpses` SET `is_rezzed` = 1 WHERE `id` = %i", db_id);
auto results = QueryDatabase(query); 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 */ /* Dump Basic Corpse Data */
std::string query = StringFormat( std::string query = StringFormat(
"INSERT INTO `character_corpses` " "INSERT INTO `character_corpses` "
@ -4336,6 +4343,7 @@ uint32 ZoneDatabase::SaveCharacterCorpse(uint32 charid, const char* charname, ui
"`y` = %1.1f, " "`y` = %1.1f, "
"`z` = %1.1f, " "`z` = %1.1f, "
"`heading` = %1.1f, " "`heading` = %1.1f, "
"`guild_consent_id` = %u, "
"`time_of_death` = NOW(), " "`time_of_death` = NOW(), "
"`is_buried` = 0, " "`is_buried` = 0, "
"`is_locked` = %d, " "`is_locked` = %d, "
@ -4379,6 +4387,7 @@ uint32 ZoneDatabase::SaveCharacterCorpse(uint32 charid, const char* charname, ui
position.y, position.y,
position.z, position.z,
position.w, position.w,
guildid,
dbpc->locked, dbpc->locked,
dbpc->exp, dbpc->exp,
dbpc->size, 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* ZoneDatabase::SummonBuriedCharacterCorpses(uint32 char_id, uint32 dest_zone_id, uint16 dest_instance_id, const glm::vec4& position) {
Corpse* corpse = nullptr; 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` " "FROM `character_corpses` "
"WHERE `charid` = '%u' AND `is_buried` = 1 " "WHERE `charid` = '%u' AND `is_buried` = 1 "
"ORDER BY `time_of_death` LIMIT 1", "ORDER BY `time_of_death` LIMIT 1",
@ -4652,7 +4661,8 @@ Corpse* ZoneDatabase::SummonBuriedCharacterCorpses(uint32 char_id, uint32 dest_z
position, position,
row[2], // char* time_of_death row[2], // char* time_of_death
atoi(row[3]) == 1, // bool rezzed 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) if (!corpse)
continue; continue;
@ -4678,7 +4688,7 @@ bool ZoneDatabase::SummonAllCharacterCorpses(uint32 char_id, uint32 dest_zone_id
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
query = StringFormat( 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", "ORDER BY time_of_death",
char_id); char_id);
results = QueryDatabase(query); results = QueryDatabase(query);
@ -4691,7 +4701,8 @@ bool ZoneDatabase::SummonAllCharacterCorpses(uint32 char_id, uint32 dest_zone_id
position, position,
row[2], row[2],
atoi(row[3]) == 1, atoi(row[3]) == 1,
false); false,
atoul(row[4]));
if (corpse) { if (corpse) {
entity_list.AddCorpse(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* ZoneDatabase::LoadCharacterCorpse(uint32 player_corpse_id) {
Corpse* NewCorpse = 0; Corpse* NewCorpse = 0;
std::string query = StringFormat( 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 player_corpse_id
); );
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
@ -4779,7 +4790,8 @@ Corpse* ZoneDatabase::LoadCharacterCorpse(uint32 player_corpse_id) {
position, position,
row[7], // time_of_death char* time_of_death row[7], // time_of_death char* time_of_death
atoi(row[8]) == 1, // is_rezzed bool rezzed 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); entity_list.AddCorpse(NewCorpse);
} }
@ -4789,10 +4801,10 @@ Corpse* ZoneDatabase::LoadCharacterCorpse(uint32 player_corpse_id) {
bool ZoneDatabase::LoadCharacterCorpses(uint32 zone_id, uint16 instance_id) { bool ZoneDatabase::LoadCharacterCorpses(uint32 zone_id, uint16 instance_id) {
std::string query; std::string query;
if (!RuleB(Zone, EnableShadowrest)){ 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{ 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); auto results = QueryDatabase(query);
@ -4806,7 +4818,8 @@ bool ZoneDatabase::LoadCharacterCorpses(uint32 zone_id, uint16 instance_id) {
position, position,
row[7], // time_of_death char* time_of_death row[7], // time_of_death char* time_of_death
atoi(row[8]) == 1, // is_rezzed bool rezzed atoi(row[8]) == 1, // is_rezzed bool rezzed
atoi(row[9])) atoi(row[9]),
atoul(row[10])) // guild_consent_id uint32 guild_consent_id
); );
} }

View File

@ -367,8 +367,9 @@ public:
uint32 SendCharacterCorpseToGraveyard(uint32 dbid, uint32 zoneid, uint16 instanceid, const glm::vec4& position); uint32 SendCharacterCorpseToGraveyard(uint32 dbid, uint32 zoneid, uint16 instanceid, const glm::vec4& position);
uint32 CreateGraveyardRecord(uint32 graveyard_zoneid, const glm::vec4& position); uint32 CreateGraveyardRecord(uint32 graveyard_zoneid, const glm::vec4& position);
uint32 AddGraveyardIDToZone(uint32 zone_id, uint32 graveyard_id); 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 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, bool rezzed = false); 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 GetFirstCorpseID(uint32 char_id);
uint32 GetCharacterCorpseCount(uint32 char_id); uint32 GetCharacterCorpseCount(uint32 char_id);
uint32 GetCharacterCorpseID(uint32 char_id, uint8 corpse); uint32 GetCharacterCorpseID(uint32 char_id, uint8 corpse);