diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 2451aac3d..a3823112b 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -39,6 +39,7 @@ #include "MapMgr.h" #include "ObjectMgr.h" #include "Player.h" +#include "RaceMgr.h" #include "ReputationMgr.h" #include "ScriptMgr.h" #include "SpellMgr.h" @@ -115,7 +116,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) criteria->ID, criteria->requiredType, dataType, classRace.class_id); return false; } - if (classRace.race_id && ((1 << (classRace.race_id - 1)) & RACEMASK_ALL_PLAYABLE) == 0) + if (classRace.race_id && ((1 << (classRace.race_id - 1)) & sRaceMgr->GetPlayableRaceMask()) == 0) { LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE ({}) has non-existing race in value2 ({}), ignored.", criteria->ID, criteria->requiredType, dataType, classRace.race_id); @@ -275,7 +276,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) criteria->ID, criteria->requiredType, dataType, classRace.class_id); return false; } - if (classRace.race_id && ((1 << (classRace.race_id - 1)) & RACEMASK_ALL_PLAYABLE) == 0) + if (classRace.race_id && ((1 << (classRace.race_id - 1)) & sRaceMgr->GetPlayableRaceMask()) == 0) { LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE ({}) has non-existing race in value2 ({}), ignored.", criteria->ID, criteria->requiredType, dataType, classRace.race_id); diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index 688820001..213ee742f 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -24,6 +24,7 @@ #include "ObjectMgr.h" #include "Pet.h" #include "Player.h" +#include "RaceMgr.h" #include "ReputationMgr.h" #include "ScriptMgr.h" #include "ScriptedCreature.h" @@ -2082,9 +2083,9 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) } case CONDITION_RACE: { - if (!(cond->ConditionValue1 & RACEMASK_ALL_PLAYABLE)) + if (!(cond->ConditionValue1 & sRaceMgr->GetPlayableRaceMask())) { - LOG_ERROR("sql.sql", "Race condition has non existing racemask ({}), skipped", cond->ConditionValue1 & ~RACEMASK_ALL_PLAYABLE); + LOG_ERROR("sql.sql", "Race condition has non existing racemask ({}), skipped", cond->ConditionValue1 & ~sRaceMgr->GetPlayableRaceMask()); return false; } diff --git a/src/server/game/Entities/Player/RaceMgr.cpp b/src/server/game/Entities/Player/RaceMgr.cpp new file mode 100644 index 000000000..b1ac288cb --- /dev/null +++ b/src/server/game/Entities/Player/RaceMgr.cpp @@ -0,0 +1,77 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "RaceMgr.h" +#include "AccountMgr.h" +#include "DatabaseEnv.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "Util.h" +#include "WorldPacket.h" +#include "WorldSession.h" + +uint8 RaceMgr::_maxRaces = 0; + +uint32 RaceMgr::_playableRaceMask = 0; +uint32 RaceMgr::_allianceRaceMask = 0; +uint32 RaceMgr::_hordeRaceMask = 0; + +RaceMgr::RaceMgr() +{ +} + +RaceMgr::~RaceMgr() +{ +} + +RaceMgr* RaceMgr::instance() +{ + static RaceMgr instance; + return &instance; +} + +void RaceMgr::LoadRaces() +{ + SetMaxRaces(0 + 1); + _playableRaceMask = 0; + _hordeRaceMask = 0; + _allianceRaceMask = 0; + + for (auto const& raceEntry : sChrRacesStore) + { + if (!raceEntry) + continue; + + uint8 alliance = raceEntry->alliance; + uint8 raceId = raceEntry->RaceID; + + if (raceEntry->Flags & CHRRACES_FLAGS_NOT_PLAYABLE) + continue; + + if (GetMaxRaces() <= raceId) + SetMaxRaces(raceId + 1); + + uint32 raceBit = (1 << (raceId - 1)); + + _playableRaceMask |= raceBit; + + if (alliance == ALLIANCE_HORDE) + _hordeRaceMask |= raceBit; + else if (alliance == ALLIANCE_ALLIANCE) + _allianceRaceMask |= raceBit; + } +} diff --git a/src/server/game/Entities/Player/RaceMgr.h b/src/server/game/Entities/Player/RaceMgr.h new file mode 100644 index 000000000..239e69070 --- /dev/null +++ b/src/server/game/Entities/Player/RaceMgr.h @@ -0,0 +1,54 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef __ACORE_RACEMGR_H +#define __ACORE_RACEMGR_H + +#include "DatabaseEnv.h" +#include "ObjectGuid.h" +#include "SharedDefines.h" +#include + +class Player; +class WorldPacket; + +class RaceMgr +{ +private: + RaceMgr(); + ~RaceMgr(); + +public: + static RaceMgr* instance(); + + static void LoadRaces(); + static uint8 GetMaxRaces() { return _maxRaces; } + static void SetMaxRaces(uint8 max) { _maxRaces = max; } + static uint32 GetPlayableRaceMask() { return _playableRaceMask; } + static uint32 GetAllianceRaceMask() { return _allianceRaceMask; } + static uint32 GetHordeRaceMask() { return _hordeRaceMask; } +private: + static uint8 _maxRaces; // Max playable race + 1 + + static uint32 _playableRaceMask; + static uint32 _allianceRaceMask; + static uint32 _hordeRaceMask; +}; + +#define sRaceMgr RaceMgr::instance() + +#endif diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 41fbafc9e..5a522da7e 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -38,6 +38,7 @@ #include "MapMgr.h" #include "Pet.h" #include "PoolMgr.h" +#include "RaceMgr.h" #include "ReputationMgr.h" #include "ScriptMgr.h" #include "Spell.h" @@ -308,8 +309,6 @@ ObjectMgr::ObjectMgr(): for (uint8 i = 0; i < MAX_CLASSES; ++i) { _playerClassInfo[i] = nullptr; - for (uint8 j = 0; j < MAX_RACES; ++j) - _playerInfo[j][i] = nullptr; } } @@ -329,7 +328,7 @@ ObjectMgr::~ObjectMgr() delete _playerClassInfo[class_]; } - for (int race = 0; race < MAX_RACES; ++race) + for (int race = 0; race < sRaceMgr->GetMaxRaces(); ++race) { for (int class_ = 0; class_ < MAX_CLASSES; ++class_) { @@ -3492,7 +3491,7 @@ void ObjectMgr::LoadItemTemplates() if (!(itemTemplate.AllowableClass & CLASSMASK_ALL_PLAYABLE)) LOG_ERROR("sql.sql", "Item (Entry: {}) does not have any playable classes ({}) in `AllowableClass` and can't be equipped or used.", entry, itemTemplate.AllowableClass); - if (!(itemTemplate.AllowableRace & RACEMASK_ALL_PLAYABLE)) + if (!(itemTemplate.AllowableRace & sRaceMgr->GetPlayableRaceMask())) LOG_ERROR("sql.sql", "Item (Entry: {}) does not have any playable races ({}) in `AllowableRace` and can't be equipped or used.", entry, itemTemplate.AllowableRace); } } @@ -4252,6 +4251,14 @@ void ObjectMgr::LoadPlayerInfo() { // Load playercreate { + if (_playerInfo.empty() || _playerInfo.size() != sRaceMgr->GetMaxRaces()) + { + _playerInfo.clear(); + _playerInfo.resize(sRaceMgr->GetMaxRaces()); + for (auto& classVec : _playerInfo) + classVec.resize(MAX_CLASSES, nullptr); + } + uint32 oldMSTime = getMSTime(); // 0 1 2 3 4 5 6 QueryResult result = WorldDatabase.Query("SELECT race, class, map, zone, position_x, position_y, position_z, orientation FROM playercreateinfo"); @@ -4279,7 +4286,7 @@ void ObjectMgr::LoadPlayerInfo() float positionZ = fields[6].Get(); float orientation = fields[7].Get(); - if (current_race >= MAX_RACES) + if (current_race >= sRaceMgr->GetMaxRaces()) { LOG_ERROR("sql.sql", "Wrong race {} in `playercreateinfo` table, ignoring.", current_race); continue; @@ -4357,7 +4364,7 @@ void ObjectMgr::LoadPlayerInfo() Field* fields = result->Fetch(); uint32 current_race = fields[0].Get(); - if (current_race >= MAX_RACES) + if (current_race >= sRaceMgr->GetMaxRaces()) { LOG_ERROR("sql.sql", "Wrong race {} in `playercreateinfo_item` table, ignoring.", current_race); continue; @@ -4389,7 +4396,7 @@ void ObjectMgr::LoadPlayerInfo() if (!current_race || !current_class) { uint32 min_race = current_race ? current_race : 1; - uint32 max_race = current_race ? current_race + 1 : MAX_RACES; + uint32 max_race = current_race ? current_race + 1 : sRaceMgr->GetMaxRaces(); uint32 min_class = current_class ? current_class : 1; uint32 max_class = current_class ? current_class + 1 : MAX_CLASSES; for (uint32 r = min_race; r < max_race; ++r) @@ -4437,7 +4444,7 @@ void ObjectMgr::LoadPlayerInfo() continue; } - if (raceMask != 0 && !(raceMask & RACEMASK_ALL_PLAYABLE)) + if (raceMask != 0 && !(raceMask & sRaceMgr->GetPlayableRaceMask())) { LOG_ERROR("sql.sql", "Wrong race mask {} in `playercreateinfo_skills` table, ignoring.", raceMask); continue; @@ -4455,7 +4462,7 @@ void ObjectMgr::LoadPlayerInfo() continue; } - for (uint32 raceIndex = RACE_HUMAN; raceIndex < MAX_RACES; ++raceIndex) + for (uint32 raceIndex = RACE_HUMAN; raceIndex < sRaceMgr->GetMaxRaces(); ++raceIndex) { if (raceMask == 0 || ((1 << (raceIndex - 1)) & raceMask)) { @@ -4504,7 +4511,7 @@ void ObjectMgr::LoadPlayerInfo() uint32 classMask = fields[1].Get(); uint32 spellId = fields[2].Get(); - if (raceMask != 0 && !(raceMask & RACEMASK_ALL_PLAYABLE)) + if (raceMask != 0 && !(raceMask & sRaceMgr->GetPlayableRaceMask())) { LOG_ERROR("sql.sql", "Wrong race mask {} in `playercreateinfo_spell_custom` table, ignoring.", raceMask); continue; @@ -4516,7 +4523,7 @@ void ObjectMgr::LoadPlayerInfo() continue; } - for (uint32 raceIndex = RACE_HUMAN; raceIndex < MAX_RACES; ++raceIndex) + for (uint32 raceIndex = RACE_HUMAN; raceIndex < sRaceMgr->GetMaxRaces(); ++raceIndex) { if (raceMask == 0 || ((1 << (raceIndex - 1)) & raceMask)) { @@ -4562,7 +4569,7 @@ void ObjectMgr::LoadPlayerInfo() uint32 classMask = fields[1].Get(); uint32 spellId = fields[2].Get(); - if (raceMask != 0 && !(raceMask & RACEMASK_ALL_PLAYABLE)) + if (raceMask != 0 && !(raceMask & sRaceMgr->GetPlayableRaceMask())) { LOG_ERROR("sql.sql", "Wrong race mask {} in `playercreateinfo_cast_spell` table, ignoring.", raceMask); continue; @@ -4574,7 +4581,7 @@ void ObjectMgr::LoadPlayerInfo() continue; } - for (uint32 raceIndex = RACE_HUMAN; raceIndex < MAX_RACES; ++raceIndex) + for (uint32 raceIndex = RACE_HUMAN; raceIndex < sRaceMgr->GetMaxRaces(); ++raceIndex) { if (raceMask == 0 || ((1 << (raceIndex - 1)) & raceMask)) { @@ -4620,7 +4627,7 @@ void ObjectMgr::LoadPlayerInfo() Field* fields = result->Fetch(); uint32 current_race = fields[0].Get(); - if (current_race >= MAX_RACES) + if (current_race >= sRaceMgr->GetMaxRaces()) { LOG_ERROR("sql.sql", "Wrong race {} in `playercreateinfo_action` table, ignoring.", current_race); continue; @@ -4652,7 +4659,9 @@ void ObjectMgr::LoadPlayerInfo() int16 StatModifier[MAX_STATS]; }; - std::array raceStatModifiers; + std::vector raceStatModifiers; + + raceStatModifiers.resize(sRaceMgr->GetMaxRaces()); uint32 oldMSTime = getMSTime(); @@ -4671,7 +4680,7 @@ void ObjectMgr::LoadPlayerInfo() Field* fields = raceStatsResult->Fetch(); uint32 current_race = fields[0].Get(); - if (current_race >= MAX_RACES) + if (current_race >= sRaceMgr->GetMaxRaces()) { LOG_ERROR("sql.sql", "Wrong race {} in `player_race_stats` table, ignoring.", current_race); continue; @@ -4745,7 +4754,7 @@ void ObjectMgr::LoadPlayerInfo() } while (result->NextRow()); // Fill gaps and check integrity - for (int race = 0; race < MAX_RACES; ++race) + for (int race = RACE_HUMAN; race < sRaceMgr->GetMaxRaces(); ++race) { // skip non existed races if (!sChrRacesStore.LookupEntry(race)) @@ -4884,7 +4893,7 @@ void ObjectMgr::GetPlayerClassLevelInfo(uint32 class_, uint8 level, PlayerClassL void ObjectMgr::GetPlayerLevelInfo(uint32 race, uint32 class_, uint8 level, PlayerLevelInfo* info) const { - if (level < 1 || race >= MAX_RACES || class_ >= MAX_CLASSES) + if (level < 1 || race >= sRaceMgr->GetMaxRaces() || class_ >= MAX_CLASSES) return; PlayerInfo const* pInfo = _playerInfo[race][class_]; @@ -5253,10 +5262,10 @@ void ObjectMgr::LoadQuests() qinfo->RequiredClasses = 0; } } - // AllowableRaces, can be 0/RACEMASK_ALL_PLAYABLE to allow any race + // AllowableRaces, can be 0/PlayableRaceMask to allow any race if (qinfo->AllowableRaces) { - if (!(qinfo->AllowableRaces & RACEMASK_ALL_PLAYABLE)) + if (!(qinfo->AllowableRaces & sRaceMgr->GetPlayableRaceMask())) { LOG_ERROR("sql.sql", "Quest {} does not contain any playable races in `AllowableRaces` ({}), value set to 0 (all races).", qinfo->GetQuestId(), qinfo->AllowableRaces); qinfo->AllowableRaces = 0; @@ -9677,7 +9686,7 @@ void ObjectMgr::LoadMailLevelRewards() continue; } - if (!(raceMask & RACEMASK_ALL_PLAYABLE)) + if (!(raceMask & sRaceMgr->GetPlayableRaceMask())) { LOG_ERROR("sql.sql", "Table `mail_level_reward` have raceMask ({}) for level {} that not include any player races, ignoring.", raceMask, level); continue; @@ -10774,7 +10783,7 @@ VehicleAccessoryList const* ObjectMgr::GetVehicleAccessoryList(Vehicle* veh) con PlayerInfo const* ObjectMgr::GetPlayerInfo(uint32 race, uint32 class_) const { - if (race >= MAX_RACES) + if (race >= sRaceMgr->GetMaxRaces()) return nullptr; if (class_ >= MAX_CLASSES) return nullptr; diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 294f90959..d0b93880a 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -1602,7 +1602,7 @@ private: void BuildPlayerLevelInfo(uint8 race, uint8 class_, uint8 level, PlayerLevelInfo* plinfo) const; - PlayerInfo* _playerInfo[MAX_RACES][MAX_CLASSES]; + std::vector> _playerInfo; typedef std::vector PlayerXPperLevel; // [level] PlayerXPperLevel _playerXPperLevel; diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index acc3e15d7..2a605bcdb 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -44,6 +44,7 @@ #include "Player.h" #include "PlayerDump.h" #include "QueryHolder.h" +#include "RaceMgr.h" #include "Realm.h" #include "ReputationMgr.h" #include "ScriptMgr.h" @@ -2030,7 +2031,7 @@ void WorldSession::HandleCharFactionOrRaceChangeCallback(std::shared_ptrGetAuctionsMap(i == 0 ? 0 : (((1 << (playerData->Race - 1)) & RACEMASK_ALLIANCE) ? 12 : 29)); + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(i == 0 ? 0 : (((1 << (playerData->Race - 1)) & sRaceMgr->GetAllianceRaceMask()) ? 12 : 29)); for (auto const& [auID, Aentry] : auctionHouse->GetAuctions()) { @@ -2418,7 +2419,7 @@ void WorldSession::HandleCharFactionOrRaceChangeCallback(std::shared_ptrGetQuestTemplates()) { - uint32 newRaceMask = (newTeam == TEAM_ALLIANCE) ? RACEMASK_ALLIANCE : RACEMASK_HORDE; + uint32 newRaceMask = (newTeam == TEAM_ALLIANCE) ? sRaceMgr->GetAllianceRaceMask() : sRaceMgr->GetHordeRaceMask(); if (quest->GetAllowableRaces() && !(quest->GetAllowableRaces() & newRaceMask)) { diff --git a/src/server/game/Mails/ServerMailMgr.cpp b/src/server/game/Mails/ServerMailMgr.cpp index 9f8d05377..571e1ab44 100644 --- a/src/server/game/Mails/ServerMailMgr.cpp +++ b/src/server/game/Mails/ServerMailMgr.cpp @@ -25,6 +25,7 @@ #include "ObjectMgr.h" #include "Player.h" #include "QuestDef.h" +#include "RaceMgr.h" #include "SharedDefines.h" #include "Timer.h" @@ -247,7 +248,7 @@ void ServerMailMgr::LoadMailServerTemplatesConditions() } break; case ServerMailConditionType::Race: - if (conditionValue & ~RACEMASK_ALL_PLAYABLE) + if (conditionValue & ~sRaceMgr->GetPlayableRaceMask()) { LOG_ERROR("sql.sql", "Table `mail_server_template_conditions` has conditionType 'Race' with invalid conditionValue ({}) for templateID {}, skipped.", conditionValue, templateID); continue; diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index a179c1963..5e6b0b2fc 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -23,6 +23,7 @@ #include "InstanceScript.h" #include "ObjectMgr.h" #include "Player.h" +#include "RaceMgr.h" #include "ScriptMgr.h" #include "SharedDefines.h" #include "Spell.h" @@ -2779,7 +2780,7 @@ void SpellMgr::LoadSpellAreas() } } - if (spellArea.raceMask && (spellArea.raceMask & RACEMASK_ALL_PLAYABLE) == 0) + if (spellArea.raceMask && (spellArea.raceMask & sRaceMgr->GetPlayableRaceMask()) == 0) { LOG_ERROR("sql.sql", "Spell {} listed in `spell_area` have wrong race mask ({}) requirement", spell, spellArea.raceMask); continue; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 5038964b4..042da7585 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -71,6 +71,7 @@ #include "Player.h" #include "PlayerDump.h" #include "PoolMgr.h" +#include "RaceMgr.h" #include "Realm.h" #include "ScriptMgr.h" #include "ServerMailMgr.h" @@ -385,6 +386,9 @@ void World::SetInitialWorldSettings() // Load cinematic cameras LoadM2Cameras(_dataPath); + LOG_INFO("server.loading", "Loading Player race data..."); + sRaceMgr->LoadRaces(); + // Load IP Location Database sIPLocation->Load(); diff --git a/src/server/scripts/Northrend/zone_wintergrasp.cpp b/src/server/scripts/Northrend/zone_wintergrasp.cpp index 0c8aae002..770c8ae07 100644 --- a/src/server/scripts/Northrend/zone_wintergrasp.cpp +++ b/src/server/scripts/Northrend/zone_wintergrasp.cpp @@ -28,6 +28,7 @@ #include "ObjectMgr.h" #include "Player.h" #include "PoolMgr.h" +#include "RaceMgr.h" #include "ScriptedCreature.h" #include "ScriptedGossip.h" #include "SpellScript.h" @@ -859,8 +860,8 @@ public: bool IsFriendly(Unit* passenger) { - return ((me->GetUInt32Value(GAMEOBJECT_FACTION) == WintergraspFaction[TEAM_HORDE] && passenger->getRaceMask() & RACEMASK_HORDE) || - (me->GetUInt32Value(GAMEOBJECT_FACTION) == WintergraspFaction[TEAM_ALLIANCE] && passenger->getRaceMask() & RACEMASK_ALLIANCE)); + return ((me->GetUInt32Value(GAMEOBJECT_FACTION) == WintergraspFaction[TEAM_HORDE] && passenger->getRaceMask() & sRaceMgr->GetHordeRaceMask()) || + (me->GetUInt32Value(GAMEOBJECT_FACTION) == WintergraspFaction[TEAM_ALLIANCE] && passenger->getRaceMask() & sRaceMgr->GetAllianceRaceMask())); } Creature* IsValidVehicle(Creature* cVeh) diff --git a/src/server/scripts/Pet/pet_generic.cpp b/src/server/scripts/Pet/pet_generic.cpp index c3a3965d3..cafc40f25 100644 --- a/src/server/scripts/Pet/pet_generic.cpp +++ b/src/server/scripts/Pet/pet_generic.cpp @@ -20,11 +20,14 @@ #include "Group.h" #include "PassiveAI.h" #include "Player.h" +#include "RaceMgr.h" #include "ScriptedCreature.h" #include "ScriptedGossip.h" #include "SpellAuras.h" #include "SpellScript.h" #include "SpellScriptLoader.h" +#include + /* * Ordered alphabetically using scriptname. * Scriptnames of files in this file should be prefixed with "npc_pet_gen_". @@ -128,20 +131,17 @@ struct argentPonyBanner const char* text; }; -static argentPonyBanner argentBanners[MAX_RACES] = -{ - {0, 0, ""}, - {2781, 62594, "Stormwind Champion's Pennant"}, - {2783, 63433, "Orgrimmar Champion's Pennant"}, - {2780, 63427, "Ironforge Champion's Pennant"}, - {2777, 63406, "Darnassus Champion's Pennant"}, - {2787, 63430, "Forsaken Champion's Pennant"}, - {2786, 63436, "Thunder Bluff Champion's Pennant"}, - {2779, 63396, "Gnomeregan Champion's Pennant"}, - {2784, 63399, "Darkspear Champion's Pennant"}, - {0, 0, ""}, - {2785, 63403, "Silvermoon Champion's Pennant"}, - {2778, 63423, "Exodar Champion's Pennant"} +static std::unordered_map argentBanners = { + {RACE_HUMAN, {2781, 62594, "Stormwind Champion's Pennant"}}, + {RACE_ORC, {2783, 63433, "Orgrimmar Champion's Pennant"}}, + {RACE_DWARF, {2780, 63427, "Ironforge Champion's Pennant"}}, + {RACE_NIGHTELF, {2777, 63406, "Darnassus Champion's Pennant"}}, + {RACE_UNDEAD_PLAYER, {2787, 63430, "Forsaken Champion's Pennant"}}, + {RACE_TAUREN, {2786, 63436, "Thunder Bluff Champion's Pennant"}}, + {RACE_GNOME, {2779, 63396, "Gnomeregan Champion's Pennant"}}, + {RACE_TROLL, {2784, 63399, "Darkspear Champion's Pennant"}}, + {RACE_BLOODELF, {2785, 63403, "Silvermoon Champion's Pennant"}}, + {RACE_DRAENEI, {2778, 63423, "Exodar Champion's Pennant"}} }; struct npc_pet_gen_argent_pony_bridle : public ScriptedAI @@ -152,7 +152,6 @@ struct npc_pet_gen_argent_pony_bridle : public ScriptedAI _init = false; _mountTimer = 4000; _lastAura = 0; - memset(_banners, 0, sizeof(_banners)); } void EnterEvadeMode(EvadeReason /*why*/) override @@ -211,10 +210,12 @@ struct npc_pet_gen_argent_pony_bridle : public ScriptedAI } // Generate Banners - uint32 mask = player->GetTeamId(true) ? RACEMASK_HORDE : RACEMASK_ALLIANCE; - for (uint8 i = 1; i < MAX_RACES; ++i) - if (mask & (1 << (i - 1)) && player->HasAchieved(argentBanners[i].achievement)) - _banners[i] = true; + uint32 mask = player->GetTeamId(true) ? sRaceMgr->GetHordeRaceMask() : sRaceMgr->GetAllianceRaceMask(); + for (auto const& [raceId, banner] : argentBanners) + { + if ((mask & (1 << (raceId - 1))) && player->HasAchieved(banner.achievement)) + _banners[raceId] = true; + } } if (duration && aura) @@ -247,7 +248,8 @@ struct npc_pet_gen_argent_pony_bridle : public ScriptedAI if (param == 0) return _state; - return _banners[param]; + auto itr = _banners.find(param); + return (itr != _banners.end() && itr->second) ? 1 : 0; } void DoAction(int32 param) override @@ -279,9 +281,11 @@ struct npc_pet_gen_argent_pony_bridle : public ScriptedAI AddGossipItemFor(player, GOSSIP_ICON_CHAT, "Visit a mailbox.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_MAILBOX); } - for (uint8 i = RACE_HUMAN; i < MAX_RACES; ++i) - if (creature->AI()->GetData(i) == uint32(true)) - AddGossipItemFor(player, GOSSIP_ICON_CHAT, argentBanners[i].text, GOSSIP_SENDER_MAIN, argentBanners[i].spell); + for (auto const& [raceId, banner] : argentBanners) + { + if (creature->AI()->GetData(raceId) == uint32(true)) + AddGossipItemFor(player, GOSSIP_ICON_CHAT, banner.text, GOSSIP_SENDER_MAIN, banner.spell); + } SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID()); return true; @@ -336,7 +340,7 @@ private: bool _init; uint8 _state; int32 _mountTimer; - bool _banners[MAX_RACES]; + std::unordered_map _banners; uint32 _lastAura; }; diff --git a/src/server/shared/DataStores/DBCStructure.h b/src/server/shared/DataStores/DBCStructure.h index f72d4ead6..3ebac7eb9 100644 --- a/src/server/shared/DataStores/DBCStructure.h +++ b/src/server/shared/DataStores/DBCStructure.h @@ -687,8 +687,8 @@ struct ChrRacesEntry uint32 TeamID; // 7 (7-Alliance 1-Horde) // 8-11 unused uint32 CinematicSequence; // 12 id from CinematicSequences.dbc - //uint32 alliance; // 13 faction (0 alliance, 1 horde, 2 not available?) - char const* name[16]; // 14-29 used for DBC language detection/selection + uint32 alliance; // 13 faction (0 alliance, 1 horde, 2 not available?) + char const* name[16]; // 14-29 used for DBC language detection/selection // 30 string flags, unused //char const* nameFemale[16]; // 31-46, if different from base (male) case // 47 string flags, unused diff --git a/src/server/shared/DataStores/DBCfmt.h b/src/server/shared/DataStores/DBCfmt.h index 9a568d5bb..e3af013ca 100644 --- a/src/server/shared/DataStores/DBCfmt.h +++ b/src/server/shared/DataStores/DBCfmt.h @@ -32,7 +32,7 @@ char constexpr CharStartOutfitEntryfmt[] = "dbbbXiiiiiiiiiiiiiiiiiiiiiiiixxxxxxx char constexpr CharTitlesEntryfmt[] = "nxssssssssssssssssxssssssssssssssssxi"; char constexpr ChatChannelsEntryfmt[] = "nixssssssssssssssssxxxxxxxxxxxxxxxxxx"; // ChatChannelsEntryfmt, index not used (more compact store) char constexpr ChrClassesEntryfmt[] = "nxixssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixii"; -char constexpr ChrRacesEntryfmt[] = "niixiixixxxxixssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxi"; +char constexpr ChrRacesEntryfmt[] = "niixiixixxxxiissssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxi"; char constexpr CinematicCameraEntryfmt[] = "nsiffff"; char constexpr CinematicSequencesEntryfmt[] = "nxixxxxxxx"; char constexpr CreatureDisplayInfofmt[] = "nixifxxxxxxxxxxx"; diff --git a/src/server/shared/SharedDefines.h b/src/server/shared/SharedDefines.h index 31b1f84f7..1b461b53a 100644 --- a/src/server/shared/SharedDefines.h +++ b/src/server/shared/SharedDefines.h @@ -91,21 +91,6 @@ enum Races //RACE_ICE_TROLL = 21 }; -// max+1 for player race -#define MAX_RACES 12 - -#define RACEMASK_ALL_PLAYABLE \ - ((1<<(RACE_HUMAN-1)) |(1<<(RACE_ORC-1)) |(1<<(RACE_DWARF-1)) | \ - (1<<(RACE_NIGHTELF-1))|(1<<(RACE_UNDEAD_PLAYER-1))|(1<<(RACE_TAUREN-1)) | \ - (1<<(RACE_GNOME-1)) |(1<<(RACE_TROLL-1)) |(1<<(RACE_BLOODELF-1))| \ - (1<<(RACE_DRAENEI-1))) - -#define RACEMASK_ALLIANCE \ - ((1<<(RACE_HUMAN-1)) | (1<<(RACE_DWARF-1)) | (1<<(RACE_NIGHTELF-1)) | \ - (1<<(RACE_GNOME-1)) | (1<<(RACE_DRAENEI-1))) - -#define RACEMASK_HORDE RACEMASK_ALL_PLAYABLE & ~RACEMASK_ALLIANCE - // DisplayRace values from CreatureDisplayInfoExtra.dbc enum class DisplayRace : uint8 { @@ -3698,6 +3683,13 @@ enum PvPTeamId PVP_TEAM_NEUTRAL = 2 // Battleground: Neutral, Arena: None }; +enum AllianceId +{ + ALLIANCE_ALLIANCE = 0, + ALLIANCE_HORDE = 1, + ALLIANCE_NEUTRAL = 2 +}; + uint8 constexpr PVP_TEAMS_COUNT = 2; inline PvPTeamId GetPvPTeamId(TeamId teamId)