From db7998ae283c43cf23ba4d81efc7d85b07f0e90f Mon Sep 17 00:00:00 2001 From: Ovahlord <18347559+Ovahlord@users.noreply.github.com> Date: Sun, 22 Mar 2026 18:07:14 +0100 Subject: [PATCH] Core/Players: use CharacterFlags enums to store player information in database and set player flags accordingly --- sql/base/characters_database.sql | 4 +- .../4.3.4/2026_03_18_00_characters.sql | 31 +++ .../Implementation/CharacterDatabase.cpp | 14 +- src/server/game/Entities/Player/Player.cpp | 183 ++++++++++++------ src/server/game/Entities/Player/Player.h | 25 ++- src/server/game/Handlers/CharacterHandler.cpp | 12 ++ src/server/game/Handlers/GuildHandler.cpp | 11 +- src/server/game/Handlers/MiscHandler.cpp | 26 +-- .../game/Server/Packets/CharacterPackets.cpp | 44 ++--- .../game/Spells/Auras/SpellAuraEffects.cpp | 6 +- src/server/scripts/Commands/cs_misc.cpp | 4 +- src/server/scripts/World/npcs_special.cpp | 2 + src/server/shared/SharedDefines.h | 5 + 13 files changed, 243 insertions(+), 124 deletions(-) create mode 100644 sql/updates/characters/4.3.4/2026_03_18_00_characters.sql diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql index 4de6b3c685..de6bdf9c81 100644 --- a/sql/base/characters_database.sql +++ b/sql/base/characters_database.sql @@ -1560,7 +1560,8 @@ CREATE TABLE `characters` ( `facialStyle` tinyint unsigned NOT NULL DEFAULT '0', `bankSlots` tinyint unsigned NOT NULL DEFAULT '0', `restState` tinyint unsigned NOT NULL DEFAULT '0', - `playerFlags` int unsigned NOT NULL DEFAULT '0', + `characterFlags` int unsigned NOT NULL DEFAULT '0', + `characterFlags2` int unsigned NOT NULL DEFAULT '0', `position_x` float NOT NULL DEFAULT '0', `position_y` float NOT NULL DEFAULT '0', `position_z` float NOT NULL DEFAULT '0', @@ -3063,6 +3064,7 @@ INSERT INTO `updates` VALUES ('2022_12_24_00_characters.sql','D3F04078C0846BCF7C8330AC20C39B8C3AEE7002','RELEASED','2022-12-24 23:52:52',0), ('2022_12_26_00_characters.sql','74EDF8E4AC31419144E4535A295DB8B189CFAF95','RELEASED','2022-12-26 10:51:39',0), ('2023_07_11_00_characters.sql','0BA579ED21F4E75AC2B4797421B5029568B3F6E2','RELEASED','2023-07-16 22:00:15',0), +('2026_03_18_00_characters.sql','37744EF940E093FF1D21A21DC37FF5D604FD695B','RELEASED','2026-03-22 18:02:12',0), ('custom_2017_12_21_00_characters.sql','2D5B3830D47E4BC717EC468E18E477A32B9A21BF','ARCHIVED','2019-11-06 00:17:44',0), ('custom_2018_01_07_00_characters.sql','7437B6243B3CB6FA08F6A37BB39E38930B0DCFD3','ARCHIVED','2019-11-06 00:17:44',0), ('custom_2018_03_18_00_characters.sql','8D1E81A7272F643687C67443C270D17255A9AA84','ARCHIVED','2019-11-06 00:17:44',0), diff --git a/sql/updates/characters/4.3.4/2026_03_18_00_characters.sql b/sql/updates/characters/4.3.4/2026_03_18_00_characters.sql new file mode 100644 index 0000000000..09ef5bf34a --- /dev/null +++ b/sql/updates/characters/4.3.4/2026_03_18_00_characters.sql @@ -0,0 +1,31 @@ +-- Adding columns +ALTER TABLE `characters` + ADD COLUMN `characterFlags` INT(10) UNSIGNED DEFAULT 0 NOT NULL AFTER `playerFlags`, + ADD COLUMN `characterFlags2` INT(10) UNSIGNED DEFAULT 0 NOT NULL AFTER `characterFlags`; + +-- Migrate data +-- Ghost +UPDATE `characters` SET `characterFlags`= `characterFlags` | 0x00002000 WHERE (`playerFlags` & 0x00000010) != 0; +-- Hide Cloak +UPDATE `characters` SET `characterFlags`= `characterFlags` | 0x00000800 WHERE (`playerFlags` & 0x00000800) != 0; +-- Hide Helm +UPDATE `characters` SET `characterFlags`= `characterFlags` | 0x00000400 WHERE (`playerFlags` & 0x00000400) != 0; +-- Game Master +UPDATE `characters` SET `characterFlags`= `characterFlags` | 0x00020000 WHERE (`playerFlags` & 0x00000008) != 0; +-- Resting +UPDATE `characters` SET `characterFlags`= `characterFlags` | 0x00000002 WHERE (`playerFlags` & 0x00000020) != 0; +-- PvP Enabled +UPDATE `characters` SET `characterFlags`= `characterFlags` | 0x00000040 WHERE (`playerFlags` & 0x00000100) != 0; +-- PvP Desired +UPDATE `characters` SET `characterFlags`= `characterFlags` | 0x00010000 WHERE (`playerFlags` & 0x00000200) != 0; +-- No XP Gain +UPDATE `characters` SET `characterFlags2`= `characterFlags2` | 0x00040000 WHERE (`playerFlags` & 0x02000000) != 0; +-- Can Use Void Storage Feature +UPDATE `characters` SET `characterFlags2`= `characterFlags2` | 0x04000000 WHERE (`playerFlags` & 0x20000000) != 0; +-- Low Level Raids enabled +UPDATE `characters` SET `characterFlags2`= `characterFlags2` | 0x20000000 WHERE (`playerFlags` & 0x00010000) != 0; +-- Auto Decline Guild Invites +UPDATE `characters` SET `characterFlags2`= `characterFlags2` | 0x40000000 WHERE (`playerFlags` & 0x08000000) != 0; + +-- Conversion done, drop no longer needed column +ALTER TABLE `characters` DROP COLUMN `playerFlags`; diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index 209149dca5..a9cef7a5ac 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -43,11 +43,11 @@ void CharacterDatabaseConnection::DoPrepareStatements() "subject, deliver_time, expire_time, money, has_items FROM mail WHERE receiver = ? ", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_MAIL_LIST_ITEMS, "SELECT itemEntry,count FROM item_instance WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_ENUM, "SELECT c.guid, c.name, c.race, c.class, c.gender, c.skin, c.face, c.hairStyle, c.hairColor, c.facialStyle, c.level, c.zone, c.map, c.position_x, c.position_y, c.position_z, " - "gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, cb.guid, c.slot " + "gm.guildid, c.characterFlags, c.characterFlags2, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, cb.guid, c.slot " "FROM characters AS c LEFT JOIN character_pet AS cp ON c.guid = cp.owner AND cp.active = 1 LEFT JOIN guild_member AS gm ON c.guid = gm.guid " "LEFT JOIN character_banned AS cb ON c.guid = cb.guid AND cb.active = 1 WHERE c.account = ? AND c.deleteInfos_Name IS NULL", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_ENUM_DECLINED_NAME, "SELECT c.guid, c.name, c.race, c.class, c.gender, c.skin, c.face, c.hairStyle, c.hairColor, c.facialStyle, c.level, c.zone, c.map, " - "c.position_x, c.position_y, c.position_z, gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, " + "c.position_x, c.position_y, c.position_z, gm.guildid, c.characterFlags, c.characterFlags2, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, " "cb.guid, c.slot, cd.genitive FROM characters AS c LEFT JOIN character_pet AS cp ON c.guid = cp.owner AND cp.active = 1 " "LEFT JOIN character_declinedname AS cd ON c.guid = cd.guid LEFT JOIN guild_member AS gm ON c.guid = gm.guid " "LEFT JOIN character_banned AS cb ON c.guid = cb.guid AND cb.active = 1 WHERE c.account = ? AND c.deleteInfos_Name IS NULL", CONNECTION_ASYNC); @@ -61,7 +61,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_BATTLEGROUND_RANDOM, "DELETE FROM character_battleground_random WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_BATTLEGROUND_RANDOM, "INSERT INTO character_battleground_random (guid) VALUES (?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER, "SELECT c.guid, account, name, race, class, gender, level, xp, money, skin, face, hairStyle, hairColor, facialStyle, bankSlots, restState, playerFlags, " + PrepareStatement(CHAR_SEL_CHARACTER, "SELECT c.guid, account, name, race, class, gender, level, xp, money, skin, face, hairStyle, hairColor, facialStyle, bankSlots, restState, characterFlags, characterFlags2 " "position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, " "resettalents_time, talentTree, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, instance_mode_mask, " "totalKills, todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, health, power1, power2, power3, power4, power5, instance_id, talentGroupsCount, activeTalentGroup, " @@ -378,7 +378,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_LFG_DATA, "DELETE FROM lfg_data WHERE guid = ?", CONNECTION_ASYNC); // Player saving - PrepareStatement(CHAR_INS_CHARACTER, "INSERT INTO characters (guid, account, name, race, class, gender, level, xp, money, skin, face, hairStyle, hairColor, facialStyle, bankSlots, restState, playerFlags, " + PrepareStatement(CHAR_INS_CHARACTER, "INSERT INTO characters (guid, account, name, race, class, gender, level, xp, money, skin, face, hairStyle, hairColor, facialStyle, bankSlots, restState, characterFlags, characterFlags2, " "map, instance_id, instance_mode_mask, position_x, position_y, position_z, orientation, trans_x, trans_y, trans_z, trans_o, transguid, " "taximask, cinematic, " "totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, talentTree, " @@ -386,8 +386,8 @@ void CharacterDatabaseConnection::DoPrepareStatements() "death_expire_time, taxi_path, totalKills, " "todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, health, power1, power2, power3, " "power4, power5, latency, talentGroupsCount, activeTalentGroup, exploredZones, equipmentCache, knownTitles, actionBars, grantableLevels, achievementPoints) VALUES " - "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHARACTER, "UPDATE characters SET name=?,race=?,class=?,gender=?,level=?,xp=?,money=?,skin=?,face=?,hairStyle=?,hairColor=?,facialStyle=?,bankSlots=?,restState=?,playerFlags=?," + "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHARACTER, "UPDATE characters SET name=?,race=?,class=?,gender=?,level=?,xp=?,money=?,skin=?,face=?,hairStyle=?,hairColor=?,facialStyle=?,bankSlots=?,restState=?,characterFlags=?,characterFlags2=?," "map=?,instance_id=?,instance_mode_mask=?,position_x=?,position_y=?,position_z=?,orientation=?,trans_x=?,trans_y=?,trans_z=?,trans_o=?,transguid=?,taximask=?,cinematic=?," "totaltime=?,leveltime=?,rest_bonus=?,logout_time=?,is_logout_resting=?,resettalents_cost=?,resettalents_time=?,talentTree=?,extra_flags=?,stable_slots=?,at_login=?,zone=?,death_expire_time=?,taxi_path=?," "totalKills=?,todayKills=?,yesterdayKills=?,chosenTitle=?," @@ -451,7 +451,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_CHAR_DEL_INFO_BY_NAME, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate FROM characters WHERE deleteDate IS NOT NULL AND deleteInfos_Name LIKE CONCAT('%%', ?, '%%')", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHAR_DEL_INFO, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate FROM characters WHERE deleteDate IS NOT NULL", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID, "SELECT guid FROM characters WHERE account = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_CHAR_PINFO, "SELECT totaltime, level, money, account, race, class, map, zone, gender, health, playerFlags FROM characters WHERE guid = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHAR_PINFO, "SELECT totaltime, level, money, account, race, class, map, zone, gender, health, characterFlags FROM characters WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_PINFO_BANS, "SELECT unbandate, bandate = unbandate, bannedby, banreason FROM character_banned WHERE guid = ? AND active ORDER BY bandate ASC LIMIT 1", CONNECTION_SYNCH); //0: lowGUID PrepareStatement(CHAR_SEL_PINFO_MAILS, "SELECT SUM(CASE WHEN (checked & 1) THEN 1 ELSE 0 END) AS 'readmail', COUNT(*) AS 'totalmail' FROM mail WHERE `receiver` = ?", CONNECTION_SYNCH); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index f816a7f45c..bd98be3eb0 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -93,6 +93,7 @@ #include "QuestPools.h" #include "Realm.h" #include "ReputationMgr.h" +#include "SharedDefines.h" #include "SkillDiscovery.h" #include "SocialMgr.h" #include "Spell.h" @@ -145,7 +146,8 @@ std::array const MasterySpells = uint64 const MAX_MONEY_AMOUNT = 9999999999ULL; -Player::Player(WorldSession* session): Unit(true) +Player::Player(WorldSession* session) : Unit(true), + _characterFlags(CHARACTER_FLAG_NONE), _characterFlags2(CHARACTER_FLAG_2_NONE) { m_objectType |= TYPEMASK_PLAYER; m_objectTypeId = TYPEID_PLAYER; @@ -161,11 +163,10 @@ Player::Player(WorldSession* session): Unit(true) m_ExtraFlags = 0; m_spellModTakingSpell = nullptr; - //m_pad = 0; + // m_pad = 0; // players always accept - if (!GetSession()->HasPermission(rbac::RBAC_PERM_CAN_FILTER_WHISPERS)) - SetAcceptWhispers(true); + if (!GetSession()->HasPermission(rbac::RBAC_PERM_CAN_FILTER_WHISPERS)) SetAcceptWhispers(true); m_comboPoints = 0; @@ -218,7 +219,7 @@ Player::Player(WorldSession* session): Unit(true) // Init rune flags m_runeGraceCooldown.fill(0xFFFFFFFF); - m_lastRuneGraceTimers = { }; + m_lastRuneGraceTimers = {}; m_MirrorTimer.fill(DISABLED_MIRROR_TIMER); @@ -239,7 +240,7 @@ Player::Player(WorldSession* session): Unit(true) m_logintime = GameTime::GetGameTime(); m_Last_tick = m_logintime; - m_Played_time = { }; + m_Played_time = {}; m_WeaponProficiency = 0; m_ArmorProficiency = 0; m_canParry = false; @@ -248,9 +249,9 @@ Player::Player(WorldSession* session): Unit(true) m_titanGripPenaltySpellId = 0; m_temporaryUnsummonedPetNumber = 0; - //cache for UNIT_CREATED_BY_SPELL to allow - //returning reagents for temporarily removed pets - //when dying/logging out + // cache for UNIT_CREATED_BY_SPELL to allow + // returning reagents for temporarily removed pets + // when dying/logging out m_oldpetspell = 0; m_lastpetnumber = 0; @@ -283,7 +284,7 @@ Player::Player(WorldSession* session): Unit(true) m_auraBaseFlatMod.fill(0.0f); m_auraBasePctMod.fill(1.0f); - m_baseRatingValue = { }; + m_baseRatingValue = {}; m_baseSpellPower = 0; m_baseManaRegen = 0; @@ -2020,6 +2021,7 @@ void Player::SetGameMaster(bool on) { m_ExtraFlags |= PLAYER_EXTRA_GM_ON; SetFaction(FACTION_FRIENDLY); + AddCharacterFlag(CHARACTER_FLAG_GM_MODE); SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM); SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_CHEAT_SPELLS); @@ -2040,6 +2042,7 @@ void Player::SetGameMaster(bool on) m_ExtraFlags &= ~ PLAYER_EXTRA_GM_ON; SetFactionForRace(getRace()); + RemoveCharacterFlag(CHARACTER_FLAG_GM_MODE); RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM); RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_CHEAT_SPELLS); @@ -6944,6 +6947,45 @@ void Player::UpdateConquestCurrencyCap(uint32 currency) SendDirectMessage(&packet); } } +void Player::InitializePlayerFlags() +{ + uint32 flags = PLAYER_FLAGS_NONE; + + if (HasCharacterFlag(CHARACTER_FLAG_HIDE_CLOAK)) + flags |= PLAYER_FLAGS_HIDE_CLOAK; + + if (HasCharacterFlag(CHARACTER_FLAG_HIDE_HELM)) + flags |= PLAYER_FLAGS_HIDE_HELM; + + if (HasCharacterFlag(CHARACTER_FLAG_GM_MODE)) + flags |= PLAYER_FLAGS_GM; + + if (HasCharacterFlag(CHARACTER_FLAG_GHOST)) + flags |= PLAYER_FLAGS_GHOST; + + if (HasCharacterFlag(CHARACTER_FLAG_RESTING)) + flags |= PLAYER_FLAGS_RESTING; + + if (HasCharacterFlag(CHARACTER_FLAG_PVP_ENABLED)) + flags |= PLAYER_FLAGS_CONTESTED_PVP; + + if (HasCharacterFlag(CHARACTER_FLAG_PVP_DESIRED)) + flags |= PLAYER_FLAGS_IN_PVP; + + if (HasCharacterFlag(CHARACTER_FLAG_2_NO_XP_GAIN)) + flags |= PLAYER_FLAGS_NO_XP_GAIN; + + if (HasCharacterFlag(CHARACTER_FLAG_2_CAN_USE_VOID_STORAGE_FEATURE)) + flags |= PLAYER_FLAGS_VOID_UNLOCKED; + + if (HasCharacterFlag(CHARACTER_FLAG_2_AUTO_DECLINE_GUILD)) + flags |= PLAYER_FLAGS_AUTO_DECLINE_GUILD; + + if (HasCharacterFlag(CHARACTER_FLAG_2_LOW_LEVEL_RAID_ENABLED)) + flags |= PLAYER_FLAGS_LOW_LEVEL_RAID_ENABLED; + + SetUInt32Value(PLAYER_FLAGS, flags); +} void Player::SetInGuild(uint32 guildId) { @@ -16423,17 +16465,17 @@ bool Player::IsLoading() const bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& holder) { - //// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 - //QueryResult* result = CharacterDatabase.PQuery("SELECT guid, account, name, race, class, gender, level, xp, money, skin, face, hairStyle, hairColor, facialStyle, bankSlots, restState, playerFlags, " - // 17 18 19 20 21 22 23 24 25 26 27 28 29 - //"position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, " - // 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 + //// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + //QueryResult* result = CharacterDatabase.PQuery("SELECT guid, account, name, race, class, gender, level, xp, money, skin, face, hairStyle, hairColor, facialStyle, bankSlots, restState, " + // 16, 17 18 19 20 21 22 23 24 25 26 27 28 29 30 + //" characterFlags, characterFlags2, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, " + // 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 //"resettalents_time, talentTree, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, instance_mode_mask, " - // 45 46 47 48 49 50 + // 46 47 48 49 50 51 //"totalKills, todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, " - // 51 52 53 54 55 56 57 58 59 60 61 + // 52 53 54 55 56 57 58 59 60 61 62 //"health, power1, power2, power3, power4, power5, instance_id, speccount, activespec, exploredZones, equipmentCache, " - // 62 63 64 65 + // 63 64 65 66 //"knownTitles, actionBars, grantableLevels, fishing_steps FROM characters WHERE guid = '%u'", guid); PreparedQueryResult result = holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_FROM); @@ -16503,11 +16545,11 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol SetUInt32Value(UNIT_FIELD_LEVEL, fields[6].GetUInt8()); SetUInt32Value(PLAYER_XP, fields[7].GetUInt32()); - if (!_LoadIntoDataField(fields[60].GetString(), PLAYER_EXPLORED_ZONES_1, PLAYER_EXPLORED_ZONES_SIZE)) - TC_LOG_WARN("entities.player.loading", "Player::LoadFromDB: Player (%s) has invalid exploredzones data (%s). Forcing partial load.", guid.ToString().c_str(), fields[60].GetCString()); + if (!_LoadIntoDataField(fields[61].GetString(), PLAYER_EXPLORED_ZONES_1, PLAYER_EXPLORED_ZONES_SIZE)) + TC_LOG_WARN("entities.player.loading", "Player::LoadFromDB: Player (%s) has invalid exploredzones data (%s). Forcing partial load.", guid.ToString().c_str(), fields[61].GetCString()); - if (!_LoadIntoDataField(fields[62].GetString(), PLAYER__FIELD_KNOWN_TITLES, KNOWN_TITLES_SIZE * 2)) - TC_LOG_WARN("entities.player.loading", "Player::LoadFromDB: Player (%s) has invalid knowntitles mask (%s). Forcing partial load.", guid.ToString().c_str(), fields[62].GetCString()); + if (!_LoadIntoDataField(fields[63].GetString(), PLAYER__FIELD_KNOWN_TITLES, KNOWN_TITLES_SIZE * 2)) + TC_LOG_WARN("entities.player.loading", "Player::LoadFromDB: Player (%s) has invalid knowntitles mask (%s). Forcing partial load.", guid.ToString().c_str(), fields[63].GetCString()); SetObjectScale(1.0f); SetFloatValue(UNIT_FIELD_HOVERHEIGHT, 1.0f); @@ -16528,7 +16570,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol SetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_BANK_BAG_SLOTS, fields[14].GetUInt8()); SetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_REST_STATE, fields[15].GetUInt8()); SetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_GENDER, fields[5].GetUInt8()); - SetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_INEBRIATION, fields[50].GetUInt8()); + SetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_INEBRIATION, fields[51].GetUInt8()); if (!ValidateAppearance( fields[3].GetUInt8(), // race @@ -16544,13 +16586,17 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol return false; } - SetUInt32Value(PLAYER_FLAGS, fields[16].GetUInt32()); - SetInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, fields[49].GetUInt32()); + _characterFlags = static_cast(fields[16].GetUInt32()); + _characterFlags2 = static_cast(fields[17].GetUInt32()); + + InitializePlayerFlags(); + + SetInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, fields[50].GetUInt32()); // set which actionbars the client has active - DO NOT REMOVE EVER AGAIN (can be changed though, if it does change fieldwise) - SetByteValue(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTES_OFFSET_ACTION_BAR_TOGGLES, fields[63].GetUInt8()); + SetByteValue(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTES_OFFSET_ACTION_BAR_TOGGLES, fields[64].GetUInt8()); - m_fishingSteps = fields[65].GetUInt8(); + m_fishingSteps = fields[66].GetUInt8(); InitDisplayIds(); @@ -16579,23 +16625,23 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol InitPrimaryProfessions(); // to max set before any spell loaded // init saved position, and fix it later if problematic - ObjectGuid::LowType transLowGUID = fields[36].GetUInt32(); + ObjectGuid::LowType transLowGUID = fields[37].GetUInt32(); - Relocate(fields[17].GetFloat(), fields[18].GetFloat(), fields[19].GetFloat(), fields[21].GetFloat()); + Relocate(fields[18].GetFloat(), fields[19].GetFloat(), fields[20].GetFloat(), fields[22].GetFloat()); - uint32 mapId = fields[20].GetUInt16(); - uint32 instanceId = fields[57].GetUInt32(); + uint32 mapId = fields[21].GetUInt16(); + uint32 instanceId = fields[58].GetUInt32(); - uint32 dungeonDiff = fields[44].GetUInt8() & 0x0F; + uint32 dungeonDiff = fields[45].GetUInt8() & 0x0F; if (dungeonDiff >= MAX_DUNGEON_DIFFICULTY) dungeonDiff = DUNGEON_DIFFICULTY_NORMAL; - uint32 raidDiff = (fields[44].GetUInt8() >> 4) & 0x0F; + uint32 raidDiff = (fields[45].GetUInt8() >> 4) & 0x0F; if (raidDiff >= MAX_RAID_DIFFICULTY) raidDiff = RAID_DIFFICULTY_10MAN_NORMAL; SetDungeonDifficulty(Difficulty(dungeonDiff)); // may be changed in _LoadGroup SetRaidDifficulty(Difficulty(raidDiff)); // may be changed in _LoadGroup - std::string taxi_nodes = fields[43].GetString(); + std::string taxi_nodes = fields[44].GetString(); #define RelocateToHomebind(){ mapId = m_homebindMapId; instanceId = 0; Relocate(m_homebindX, m_homebindY, m_homebindZ); } @@ -16620,9 +16666,9 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol } _LoadCurrency(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CURRENCY)); - SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, fields[45].GetUInt32()); - SetUInt16Value(PLAYER_FIELD_KILLS, 0, fields[46].GetUInt16()); - SetUInt16Value(PLAYER_FIELD_KILLS, 1, fields[47].GetUInt16()); + SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, fields[46].GetUInt32()); + SetUInt16Value(PLAYER_FIELD_KILLS, 0, fields[47].GetUInt16()); + SetUInt16Value(PLAYER_FIELD_KILLS, 1, fields[48].GetUInt16()); _LoadBoundInstances(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_BOUND_INSTANCES)); _LoadInstanceTimeRestrictions(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES)); @@ -16716,7 +16762,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol if (transport) { - float x = fields[32].GetFloat(), y = fields[33].GetFloat(), z = fields[34].GetFloat(), o = fields[35].GetFloat(); + float x = fields[33].GetFloat(), y = fields[34].GetFloat(), z = fields[35].GetFloat(), o = fields[36].GetFloat(); m_movementInfo.transport.pos.Relocate(x, y, z, o); transport->CalculatePassengerPosition(x, y, z, &o); @@ -16911,7 +16957,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol SaveRecallPosition(); time_t now = GameTime::GetGameTime(); - time_t logoutTime = time_t(fields[27].GetUInt32()); + time_t logoutTime = time_t(fields[28].GetUInt32()); // since last logout (in seconds) uint32 time_diff = uint32(now - logoutTime); //uint64 is excessive for a time_diff in seconds.. uint32 allows for 136~ year difference. @@ -16924,15 +16970,15 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol SetDrunkValue(newDrunkValue); - m_cinematic = fields[23].GetUInt8(); - m_Played_time[PLAYED_TIME_TOTAL]= fields[24].GetUInt32(); - m_Played_time[PLAYED_TIME_LEVEL]= fields[25].GetUInt32(); + m_cinematic = fields[24].GetUInt8(); + m_Played_time[PLAYED_TIME_TOTAL]= fields[25].GetUInt32(); + m_Played_time[PLAYED_TIME_LEVEL]= fields[26].GetUInt32(); - SetTalentResetCost(fields[29].GetUInt32()); - SetTalentResetTime(time_t(fields[30].GetUInt32())); + SetTalentResetCost(fields[30].GetUInt32()); + SetTalentResetTime(time_t(fields[31].GetUInt32())); - SetSpecsCount(fields[58].GetUInt8()); - SetActiveSpec(fields[59].GetUInt8()); + SetSpecsCount(fields[59].GetUInt8()); + SetActiveSpec(fields[60].GetUInt8()); // sanity check if (GetSpecsCount() > MAX_TALENT_SPECS || GetActiveSpec() > MAX_TALENT_SPEC || GetSpecsCount() < MIN_TALENT_SPECS) @@ -16942,7 +16988,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol } // Only load selected specializations, learning mastery spells requires this - std::vector talentTrees = Trinity::Tokenize(fields[31].GetStringView(), ' ', false); + std::vector talentTrees = Trinity::Tokenize(fields[32].GetStringView(), ' ', false); for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i) { if (i >= talentTrees.size()) @@ -16953,12 +16999,12 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol SetPrimaryTalentTree(i, *talentTree); } - if (!m_taxi.LoadTaxiMask(fields[22].GetString())) // must be before InitTaxiNodesForLevel - TC_LOG_WARN("entities.player.loading", "Player::LoadFromDB: Player (%s) has invalid taximask (%s) in DB. Forced partial load.", GetGUID().ToString().c_str(), fields[22].GetString().c_str()); + if (!m_taxi.LoadTaxiMask(fields[23].GetString())) // must be before InitTaxiNodesForLevel + TC_LOG_WARN("entities.player.loading", "Player::LoadFromDB: Player (%s) has invalid taximask (%s) in DB. Forced partial load.", GetGUID().ToString().c_str(), fields[23].GetString().c_str()); - uint32 extraflags = fields[37].GetUInt16(); + uint32 extraflags = fields[38].GetUInt16(); - m_stableSlots = fields[38].GetUInt8(); + m_stableSlots = fields[39].GetUInt8(); if (m_stableSlots > MAX_PET_STABLES) { TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player (%s) can't have more stable slots than %u, but has %u in DB", @@ -16966,7 +17012,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol m_stableSlots = MAX_PET_STABLES; } - m_atLoginFlags = fields[39].GetUInt16(); + m_atLoginFlags = fields[40].GetUInt16(); if (HasAtLoginFlag(AT_LOGIN_RENAME)) { @@ -16979,7 +17025,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol m_lastHonorUpdateTime = logoutTime; UpdateHonorFields(); - m_deathExpireTime = time_t(fields[42].GetUInt32()); + m_deathExpireTime = time_t(fields[43].GetUInt32()); if (m_deathExpireTime > now + MAX_DEATH_COUNT * DEATH_EXPIRE_STEP) m_deathExpireTime = now + MAX_DEATH_COUNT * DEATH_EXPIRE_STEP - 1; @@ -17016,7 +17062,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol InitRunes(); // rest bonus can only be calculated after InitStatsForLevel() - m_rest_bonus = fields[26].GetFloat(); + m_rest_bonus = fields[27].GetFloat(); if (time_diff > 0) { @@ -17024,7 +17070,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol float bubble0 = 0.031f; //speed collect rest bonus in offline, in logout, in tavern, city (section/in hour) float bubble1 = 0.125f; - float bubble = fields[28].GetUInt8() > 0 + float bubble = fields[29].GetUInt8() > 0 ? bubble1*sWorld->getRate(RATE_REST_OFFLINE_IN_TAVERN_OR_CITY) : bubble0*sWorld->getRate(RATE_REST_OFFLINE_IN_WILDERNESS); @@ -17087,7 +17133,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol // check PLAYER_CHOSEN_TITLE compatibility with PLAYER__FIELD_KNOWN_TITLES // note: PLAYER__FIELD_KNOWN_TITLES updated at quest status loaded - uint32 curTitle = fields[48].GetUInt32(); + uint32 curTitle = fields[49].GetUInt32(); if (curTitle && !HasTitle(curTitle)) curTitle = 0; @@ -17098,7 +17144,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol GetSpellHistory()->LoadFromDB(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS)); - uint32 savedHealth = fields[51].GetUInt32(); + uint32 savedHealth = fields[52].GetUInt32(); if (!savedHealth) m_deathState = CORPSE; @@ -17120,7 +17166,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol { if (GetPowerIndex(Powers(i)) != MAX_POWERS) { - uint32 savedPower = fields[52 + loadedPowers].GetUInt32(); + uint32 savedPower = fields[53 + loadedPowers].GetUInt32(); uint32 maxPower = GetUInt32Value(UNIT_FIELD_MAXPOWER1 + loadedPowers); SetPower(Powers(i), (savedPower > maxPower) ? maxPower : savedPower); if (++loadedPowers >= MAX_POWERS_PER_CLASS) @@ -17200,7 +17246,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol } // RaF stuff. - m_grantableLevels = fields[64].GetUInt8(); + m_grantableLevels = fields[65].GetUInt8(); if (GetSession()->IsARecruiter() || (GetSession()->GetRecruiterId() != 0)) SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_REFER_A_FRIEND); @@ -18938,7 +18984,8 @@ void Player::SaveToDB(CharacterDatabaseTransaction trans, bool create /* = false stmt->setUInt8(index++, GetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_FACIAL_STYLE)); stmt->setUInt8(index++, GetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_BANK_BAG_SLOTS)); stmt->setUInt8(index++, GetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_REST_STATE)); - stmt->setUInt32(index++, GetUInt32Value(PLAYER_FLAGS)); + stmt->setUInt32(index++, GetCharacterFlags().AsUnderlyingType()); + stmt->setUInt32(index++, GetCharacterFlags2().AsUnderlyingType()); stmt->setUInt16(index++, (uint16)GetMapId()); stmt->setUInt32(index++, (uint32)GetInstanceId()); stmt->setUInt8(index++, (uint8(GetDungeonDifficulty()) | uint8(GetRaidDifficulty()) << 4)); @@ -19058,7 +19105,8 @@ void Player::SaveToDB(CharacterDatabaseTransaction trans, bool create /* = false stmt->setUInt8(index++, GetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_FACIAL_STYLE)); stmt->setUInt8(index++, GetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_BANK_BAG_SLOTS)); stmt->setUInt8(index++, GetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_REST_STATE)); - stmt->setUInt32(index++, GetUInt32Value(PLAYER_FLAGS)); + stmt->setUInt32(index++, GetCharacterFlags().AsUnderlyingType()); + stmt->setUInt32(index++, GetCharacterFlags2().AsUnderlyingType()); if (!IsBeingTeleported()) { @@ -27307,6 +27355,17 @@ std::string Player::GetCoordsMapAreaAndZoneString() const return str.str(); } +void Player::UnlockVoidStorage() +{ + AddCharacterFlag(CHARACTER_FLAG_2_CAN_USE_VOID_STORAGE_FEATURE); + SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_VOID_UNLOCKED); +} +void Player::LockVoidStorage() +{ + RemoveCharacterFlag(CHARACTER_FLAG_2_CAN_USE_VOID_STORAGE_FEATURE); + RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_VOID_UNLOCKED); +} + Guild* Player::GetGuild() { uint32 guildId = GetGuildId(); @@ -27933,6 +27992,7 @@ void Player::SetRestFlag(RestFlag restFlag) if (!oldRestMask && _restFlagMask) // only set flag/time on the first rest state { _restTime = GameTime::GetGameTime(); + AddCharacterFlag(CHARACTER_FLAG_RESTING); SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING); } } @@ -27945,6 +28005,7 @@ void Player::RemoveRestFlag(RestFlag restFlag) if (oldRestMask && !_restFlagMask) // only remove flag/time on the last rest state remove { _restTime = 0; + RemoveCharacterFlag(CHARACTER_FLAG_RESTING); RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING); } } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 9900d366eb..02bf486618 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -22,6 +22,7 @@ #include "CUFProfile.h" #include "DatabaseEnvFwd.h" #include "DBCEnums.h" +#include "EnumFlag.h" #include "EquipmentSet.h" #include "GroupReference.h" #include "ItemDefines.h" @@ -83,6 +84,8 @@ class ReputationMgr; class SpellCastTargets; class TradeData; +enum CharacterFlags : int32; +enum CharacterFlags2 : int32; enum InventoryType : uint8; enum ItemClass : uint8; enum LootError : uint8; @@ -402,6 +405,7 @@ constexpr uint8 MAX_DRUNKEN = 4; enum PlayerFlags { + PLAYER_FLAGS_NONE = 0x00000000, PLAYER_FLAGS_GROUP_LEADER = 0x00000001, PLAYER_FLAGS_AFK = 0x00000002, PLAYER_FLAGS_DND = 0x00000004, @@ -2360,8 +2364,8 @@ class TC_GAME_API Player : public Unit, public GridObject // Void Storage bool IsVoidStorageUnlocked() const { return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_VOID_UNLOCKED); } - void UnlockVoidStorage() { SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_VOID_UNLOCKED); } - void LockVoidStorage() { RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_VOID_UNLOCKED); } + void UnlockVoidStorage(); + void LockVoidStorage(); uint8 GetNextVoidStorageFreeSlot() const; uint8 GetNumOfVoidStorageFreeSlots() const; uint8 AddVoidStorageItem(VoidStorageItem const& item); @@ -2552,6 +2556,23 @@ class TC_GAME_API Player : public Unit, public GridObject uint32 m_ExtraFlags; + private: + EnumFlag _characterFlags; + EnumFlag _characterFlags2; + public: + EnumFlag GetCharacterFlags() const { return _characterFlags; } + void AddCharacterFlag(CharacterFlags flag) { _characterFlags |= flag; } + void RemoveCharacterFlag(CharacterFlags flag) { _characterFlags &= ~flag; } + bool HasCharacterFlag(CharacterFlags flag) const { return _characterFlags.HasFlag(flag); } + + EnumFlag GetCharacterFlags2() const { return _characterFlags2; } + void AddCharacterFlag(CharacterFlags2 flag) { _characterFlags2 |= flag; } + void RemoveCharacterFlag(CharacterFlags2 flag) { _characterFlags2 &= ~flag; } + bool HasCharacterFlag(CharacterFlags2 flag) const { return _characterFlags2.HasFlag(flag); } + + void InitializePlayerFlags(); + + protected: QuestStatusMap m_QuestStatus; QuestStatusSaveMap m_QuestStatusSave; diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 1ca11ab6a1..c584360a05 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -1189,17 +1189,29 @@ void WorldSession::HandleSetFactionInactiveOpcode(WorldPacket& recvData) void WorldSession::HandleShowingHelmOpcode(WorldPackets::Character::ShowingHelm& packet) { if (packet.ShowHelm) + { + _player->RemoveCharacterFlag(CHARACTER_FLAG_HIDE_HELM); _player->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM); + } else + { + _player->AddCharacterFlag(CHARACTER_FLAG_HIDE_HELM); _player->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM); + } } void WorldSession::HandleShowingCloakOpcode(WorldPackets::Character::ShowingCloak& packet) { if (packet.ShowCloak) + { + _player->RemoveCharacterFlag(CHARACTER_FLAG_HIDE_CLOAK); _player->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK); + } else + { + _player->AddCharacterFlag(CHARACTER_FLAG_HIDE_CLOAK); _player->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK); + } } void WorldSession::HandleCharRenameOpcode(WorldPacket& recvData) diff --git a/src/server/game/Handlers/GuildHandler.cpp b/src/server/game/Handlers/GuildHandler.cpp index 3aa4de57eb..a181413bf6 100644 --- a/src/server/game/Handlers/GuildHandler.cpp +++ b/src/server/game/Handlers/GuildHandler.cpp @@ -635,7 +635,16 @@ void WorldSession::HandleAutoDeclineGuildInvites(WorldPacket& recvPacket) uint8 enable; recvPacket >> enable; - GetPlayer()->ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_AUTO_DECLINE_GUILD, enable != 0); + if (enable) + { + _player->AddCharacterFlag(CHARACTER_FLAG_2_AUTO_DECLINE_GUILD); + _player->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_AUTO_DECLINE_GUILD); + } + else + { + _player->RemoveCharacterFlag(CHARACTER_FLAG_2_AUTO_DECLINE_GUILD); + _player->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_AUTO_DECLINE_GUILD); + } } void WorldSession::HandleRequestGuildRewardsList(WorldPackets::Guild::RequestGuildRewardsList& /*packet*/) diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 3e67f8fc07..374b7ec2ad 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -408,33 +408,27 @@ void WorldSession::HandleLogoutCancelOpcode(WorldPacket& /*recvData*/) void WorldSession::HandleTogglePvP(WorldPacket& recvData) { - // this opcode can be used in two ways: Either set explicit new status or toggle old status + bool enablePvp = !_player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP); + // If a byte is sent, we want a specific state if (recvData.size() == 1) - { - bool newPvPStatus; - recvData >> newPvPStatus; - GetPlayer()->ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP, newPvPStatus); - GetPlayer()->ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_PVP_TIMER, !newPvPStatus); - } - else - { - GetPlayer()->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP); - GetPlayer()->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_PVP_TIMER); - } + recvData >> enablePvp; - if (GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP)) + if (enablePvp) { + _player->AddCharacterFlag(CHARACTER_FLAG_PVP_DESIRED); + _player->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP); + _player->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_PVP_TIMER); if (!GetPlayer()->IsPvP() || GetPlayer()->pvpInfo.EndTimer) GetPlayer()->UpdatePvP(true, true); } else { + _player->RemoveCharacterFlag(CHARACTER_FLAG_PVP_DESIRED); + _player->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP); + _player->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_PVP_TIMER); if (!GetPlayer()->pvpInfo.IsHostile && GetPlayer()->IsPvP()) GetPlayer()->pvpInfo.EndTimer = GameTime::GetGameTime(); // start toggle-off } - - //if (OutdoorPvP* pvp = _player->GetOutdoorPvP()) - // pvp->HandlePlayerActivityChanged(_player); } void WorldSession::HandleZoneUpdateOpcode(WorldPacket& recvData) diff --git a/src/server/game/Server/Packets/CharacterPackets.cpp b/src/server/game/Server/Packets/CharacterPackets.cpp index 840045c344..0ce300ccba 100644 --- a/src/server/game/Server/Packets/CharacterPackets.cpp +++ b/src/server/game/Server/Packets/CharacterPackets.cpp @@ -53,28 +53,23 @@ WorldPackets::Character::EnumCharactersResult::CharacterInfo::CharacterInfo(Fiel if (ObjectGuid::LowType guildId = fields[16].GetUInt32()) GuildGUID = ObjectGuid::Create(guildId); - uint32 playerFlags = fields[17].GetUInt32(); - uint32 atLoginFlags = fields[18].GetUInt16(); - - if (playerFlags & PLAYER_FLAGS_RESTING) - Flags |= CHARACTER_FLAG_RESTING; + Flags = fields[17].GetUInt32(); + Flags2 = fields[18].GetUInt32(); + uint32 atLoginFlags = fields[19].GetUInt16(); if (atLoginFlags & AT_LOGIN_RESET_TALENTS) Flags |= CHARACTER_FLAG_RESET_TALENTS_ON_LOGIN; if (atLoginFlags & AT_LOGIN_RESURRECT) - playerFlags &= ~PLAYER_FLAGS_GHOST; - - if (playerFlags & PLAYER_FLAGS_GHOST) - Flags |= CHARACTER_FLAG_GHOST; + Flags &= ~CHARACTER_FLAG_GHOST; if (atLoginFlags & AT_LOGIN_RENAME) Flags |= CHARACTER_FLAG_RENAME; - if (fields[23].GetUInt32()) + if (fields[24].GetUInt32()) Flags |= CHARACTER_FLAG_LOCKED_BY_BILLING; - if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED) && !fields[22].GetString().empty()) + if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED) && !fields[23].GetString().empty()) Flags |= CHARACTER_FLAG_DECLINED; if (atLoginFlags & AT_LOGIN_CUSTOMIZE) @@ -84,36 +79,21 @@ WorldPackets::Character::EnumCharactersResult::CharacterInfo::CharacterInfo(Fiel else if (atLoginFlags & AT_LOGIN_CHANGE_RACE) Flags2 = CHARACTER_FLAG_2_RACE_CHANGE; - if (playerFlags & PLAYER_FLAGS_NO_XP_GAIN) - Flags2 |= CHARACTER_FLAG_2_NO_XP_GAIN; - - if (playerFlags & PLAYER_FLAGS_LOW_LEVEL_RAID_ENABLED) - Flags2 |= CHARACTER_FLAG_2_LOW_LEVEL_RAID_ENABLED; - - if (playerFlags & PLAYER_FLAGS_AUTO_DECLINE_GUILD) - Flags2 |= CHARACTER_FLAG_2_AUTO_DECLINE_GUILD; - FirstLogin = (atLoginFlags & AT_LOGIN_FIRST) != 0; - if (playerFlags & PLAYER_FLAGS_HIDE_HELM) - Flags |= CHARACTER_FLAG_HIDE_HELM; - - if (playerFlags & PLAYER_FLAGS_HIDE_CLOAK) - Flags |= CHARACTER_FLAG_HIDE_CLOAK; - // show pet at selection character in character list only for non-ghost character - if (!(playerFlags & PLAYER_FLAGS_GHOST) && (ClassID == CLASS_WARLOCK || ClassID == CLASS_HUNTER || ClassID == CLASS_DEATH_KNIGHT)) + if (!(Flags & CHARACTER_FLAG_GHOST) && (ClassID == CLASS_WARLOCK || ClassID == CLASS_HUNTER || ClassID == CLASS_DEATH_KNIGHT)) { - if (CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(fields[19].GetUInt32())) + if (CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(fields[20].GetUInt32())) { - PetCreatureDisplayID = fields[20].GetUInt32(); - PetExperienceLevel = fields[21].GetUInt16(); + PetCreatureDisplayID = fields[21].GetUInt32(); + PetExperienceLevel = fields[22].GetUInt16(); PetCreatureFamilyID = creatureInfo->family; } } - std::vector equipment = Trinity::Tokenize(fields[22].GetStringView(), ' ', false); - ListPosition = fields[24].GetUInt8(); + std::vector equipment = Trinity::Tokenize(fields[23].GetStringView(), ' ', false); + ListPosition = fields[25].GetUInt8(); for (uint8 slot = 0; slot < INVENTORY_SLOT_BAG_END; ++slot) { diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 5cc77a909b..f3f60714a8 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -1748,12 +1748,13 @@ void AuraEffect::HandleAuraGhost(AuraApplication const* aurApp, uint8 mode, bool if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; - Unit* target = aurApp->GetTarget(); - if (target->GetTypeId() != TYPEID_PLAYER) + Player* target = Object::ToPlayer(aurApp->GetTarget()); + if (!target) return; if (apply) { + target->AddCharacterFlag(CHARACTER_FLAG_GHOST); target->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST); target->m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST); target->m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST); @@ -1763,6 +1764,7 @@ void AuraEffect::HandleAuraGhost(AuraApplication const* aurApp, uint8 mode, bool if (target->HasAuraType(SPELL_AURA_GHOST)) return; + target->RemoveCharacterFlag(CHARACTER_FLAG_GHOST); target->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST); target->m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); target->m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index de0fe9d39b..7b99fe363d 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -1663,9 +1663,9 @@ public: areaId = fields[7].GetUInt16(); gender = fields[8].GetUInt8(); uint32 health = fields[9].GetUInt32(); - uint32 playerFlags = fields[10].GetUInt32(); + uint32 characterFlags = fields[10].GetUInt32(); - if (!health || playerFlags & PLAYER_FLAGS_GHOST) + if (!health || characterFlags & CHARACTER_FLAG_GHOST) alive = handler->GetTrinityString(LANG_NO); else alive = handler->GetTrinityString(LANG_YES); diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index b4884c858c..0de622a5f7 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -1973,9 +1973,11 @@ class npc_experience : public CreatureScript switch (action) { case GOSSIP_ACTION_INFO_DEF + 1: // XP ON selected + player->RemoveCharacterFlag(CHARACTER_FLAG_2_NO_XP_GAIN); player->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_NO_XP_GAIN); // turn on XP gain break; case GOSSIP_ACTION_INFO_DEF + 2: // XP OFF selected + player->AddCharacterFlag(CHARACTER_FLAG_2_NO_XP_GAIN); player->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_NO_XP_GAIN); // turn off XP gain break; } diff --git a/src/server/shared/SharedDefines.h b/src/server/shared/SharedDefines.h index ffe5e80646..ac86b2811a 100644 --- a/src/server/shared/SharedDefines.h +++ b/src/server/shared/SharedDefines.h @@ -20,6 +20,7 @@ #include "Define.h" #include "DetourNavMesh.h" +#include "EnumFlag.h" float const GROUND_HEIGHT_TOLERANCE = 0.05f; // Extra tolerance to z position to check if it is in air or on ground. constexpr float Z_OFFSET_FIND_HEIGHT = 1.5f; @@ -831,6 +832,8 @@ enum CharacterFlags : int32 CHARACTER_FLAG_COMPENSATE_FOR_SPELLS = 0x40000000 // Compensate for spells }; +DEFINE_ENUM_FLAG(CharacterFlags); + enum CharacterFlags2 : int32 { CHARACTER_FLAG_2_NONE = 0x00000000, @@ -867,6 +870,8 @@ enum CharacterFlags2 : int32 CHARACTER_FLAG_2_AUTO_DECLINE_GUILD = 0x40000000 // The player will automatically decline guild invites }; +DEFINE_ENUM_FLAG(CharacterFlags2); + enum CharacterSlot { SLOT_HEAD = 0,