feat(Core/Globals): Dynamically calculate max race and racemasks from DBC data. (#24665)

This commit is contained in:
Benjamin Jackson
2026-02-28 18:12:52 -05:00
committed by GitHub
parent 85b224bcef
commit 515aeca570
15 changed files with 221 additions and 75 deletions

View File

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

View File

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

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#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;
}
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef __ACORE_RACEMGR_H
#define __ACORE_RACEMGR_H
#include "DatabaseEnv.h"
#include "ObjectGuid.h"
#include "SharedDefines.h"
#include <map>
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

View File

@@ -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>();
float orientation = fields[7].Get<float>();
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<uint8>();
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>();
uint32 spellId = fields[2].Get<uint32>();
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>();
uint32 spellId = fields[2].Get<uint32>();
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<uint8>();
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<RaceStats, MAX_RACES> raceStatModifiers;
std::vector<RaceStats> 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<uint8>();
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;

View File

@@ -1602,7 +1602,7 @@ private:
void BuildPlayerLevelInfo(uint8 race, uint8 class_, uint8 level, PlayerLevelInfo* plinfo) const;
PlayerInfo* _playerInfo[MAX_RACES][MAX_CLASSES];
std::vector<std::vector<PlayerInfo*>> _playerInfo;
typedef std::vector<uint32> PlayerXPperLevel; // [level]
PlayerXPperLevel _playerXPperLevel;

View File

@@ -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_ptr<Charact
for (uint8 i = 0; i < 2; ++i) // check both neutral and faction-specific AH
{
AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(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_ptr<Charact
// Disable all old-faction specific quests
for (auto const& [questID, quest] : sObjectMgr->GetQuestTemplates())
{
uint32 newRaceMask = (newTeam == TEAM_ALLIANCE) ? RACEMASK_ALLIANCE : RACEMASK_HORDE;
uint32 newRaceMask = (newTeam == TEAM_ALLIANCE) ? sRaceMgr->GetAllianceRaceMask() : sRaceMgr->GetHordeRaceMask();
if (quest->GetAllowableRaces() && !(quest->GetAllowableRaces() & newRaceMask))
{

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 <unordered_map>
/*
* 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<uint8, argentPonyBanner> 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<uint8, bool> _banners;
uint32 _lastAura;
};

View File

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

View File

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

View File

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