EverWrath/src/server/game/DataStores/DBCStores.cpp

1083 lines
51 KiB
C++

/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-GPL2
* Copyright (C) 2008-2020 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*/
#include "DBCStores.h"
#include "DBCFileLoader.h"
#include "DBCfmt.h"
#include "Errors.h"
#include "Log.h"
#include "SharedDefines.h"
#include "SpellMgr.h"
#include "TransportMgr.h"
#include "BattlegroundMgr.h"
#include "World.h"
#include <map>
#include <fstream>
#include <iostream>
#include <iomanip>
typedef std::map<uint16, uint32> AreaFlagByAreaID;
typedef std::map<uint32, uint32> AreaFlagByMapID;
typedef std::tuple<int16, int8, int32> WMOAreaTableKey;
typedef std::map<WMOAreaTableKey, WMOAreaTableEntry const*> WMOAreaInfoByTripple;
DBCStorage <AreaTableEntry> sAreaTableStore(AreaTableEntryfmt);
DBCStorage <AreaGroupEntry> sAreaGroupStore(AreaGroupEntryfmt);
DBCStorage <AreaPOIEntry> sAreaPOIStore(AreaPOIEntryfmt);
static WMOAreaInfoByTripple sWMOAreaInfoByTripple;
DBCStorage <AchievementEntry> sAchievementStore(Achievementfmt);
DBCStorage <AchievementCategoryEntry> sAchievementCategoryStore(AchievementCategoryfmt);
DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore(AchievementCriteriafmt);
DBCStorage <AuctionHouseEntry> sAuctionHouseStore(AuctionHouseEntryfmt);
DBCStorage <BankBagSlotPricesEntry> sBankBagSlotPricesStore(BankBagSlotPricesEntryfmt);
DBCStorage <BattlemasterListEntry> sBattlemasterListStore(BattlemasterListEntryfmt);
DBCStorage <BarberShopStyleEntry> sBarberShopStyleStore(BarberShopStyleEntryfmt);
DBCStorage <CharStartOutfitEntry> sCharStartOutfitStore(CharStartOutfitEntryfmt);
std::map<uint32, CharStartOutfitEntry const*> sCharStartOutfitMap;
DBCStorage <CharTitlesEntry> sCharTitlesStore(CharTitlesEntryfmt);
DBCStorage <ChatChannelsEntry> sChatChannelsStore(ChatChannelsEntryfmt);
DBCStorage <ChrClassesEntry> sChrClassesStore(ChrClassesEntryfmt);
DBCStorage <ChrRacesEntry> sChrRacesStore(ChrRacesEntryfmt);
DBCStorage <CinematicCameraEntry> sCinematicCameraStore(CinematicCameraEntryfmt);
DBCStorage <CinematicSequencesEntry> sCinematicSequencesStore(CinematicSequencesEntryfmt);
DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore(CreatureDisplayInfofmt);
DBCStorage <CreatureFamilyEntry> sCreatureFamilyStore(CreatureFamilyfmt);
DBCStorage <CreatureModelDataEntry> sCreatureModelDataStore(CreatureModelDatafmt);
DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore(CreatureSpellDatafmt);
DBCStorage <CreatureTypeEntry> sCreatureTypeStore(CreatureTypefmt);
DBCStorage <CurrencyTypesEntry> sCurrencyTypesStore(CurrencyTypesfmt);
DBCStorage <DestructibleModelDataEntry> sDestructibleModelDataStore(DestructibleModelDatafmt);
DBCStorage <DungeonEncounterEntry> sDungeonEncounterStore(DungeonEncounterfmt);
DBCStorage <DurabilityQualityEntry> sDurabilityQualityStore(DurabilityQualityfmt);
DBCStorage <DurabilityCostsEntry> sDurabilityCostsStore(DurabilityCostsfmt);
DBCStorage <EmotesEntry> sEmotesStore(EmotesEntryfmt);
DBCStorage <EmotesTextEntry> sEmotesTextStore(EmotesTextEntryfmt);
typedef std::map<uint32, SimpleFactionsList> FactionTeamMap;
static FactionTeamMap sFactionTeamMap;
DBCStorage <FactionEntry> sFactionStore(FactionEntryfmt);
DBCStorage <FactionTemplateEntry> sFactionTemplateStore(FactionTemplateEntryfmt);
DBCStorage <GameObjectDisplayInfoEntry> sGameObjectDisplayInfoStore(GameObjectDisplayInfofmt);
DBCStorage <GemPropertiesEntry> sGemPropertiesStore(GemPropertiesEntryfmt);
DBCStorage <GlyphPropertiesEntry> sGlyphPropertiesStore(GlyphPropertiesfmt);
DBCStorage <GlyphSlotEntry> sGlyphSlotStore(GlyphSlotfmt);
DBCStorage <GtBarberShopCostBaseEntry> sGtBarberShopCostBaseStore(GtBarberShopCostBasefmt);
DBCStorage <GtCombatRatingsEntry> sGtCombatRatingsStore(GtCombatRatingsfmt);
DBCStorage <GtChanceToMeleeCritBaseEntry> sGtChanceToMeleeCritBaseStore(GtChanceToMeleeCritBasefmt);
DBCStorage <GtChanceToMeleeCritEntry> sGtChanceToMeleeCritStore(GtChanceToMeleeCritfmt);
DBCStorage <GtChanceToSpellCritBaseEntry> sGtChanceToSpellCritBaseStore(GtChanceToSpellCritBasefmt);
DBCStorage <GtChanceToSpellCritEntry> sGtChanceToSpellCritStore(GtChanceToSpellCritfmt);
DBCStorage <GtNPCManaCostScalerEntry> sGtNPCManaCostScalerStore(GtNPCManaCostScalerfmt);
DBCStorage <GtOCTClassCombatRatingScalarEntry> sGtOCTClassCombatRatingScalarStore(GtOCTClassCombatRatingScalarfmt);
DBCStorage <GtOCTRegenHPEntry> sGtOCTRegenHPStore(GtOCTRegenHPfmt);
//DBCStorage <GtOCTRegenMPEntry> sGtOCTRegenMPStore(GtOCTRegenMPfmt); -- not used currently
DBCStorage <GtRegenHPPerSptEntry> sGtRegenHPPerSptStore(GtRegenHPPerSptfmt);
DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore(GtRegenMPPerSptfmt);
DBCStorage <HolidaysEntry> sHolidaysStore(Holidaysfmt);
DBCStorage <ItemBagFamilyEntry> sItemBagFamilyStore(ItemBagFamilyfmt);
//DBCStorage <ItemCondExtCostsEntry> sItemCondExtCostsStore(ItemCondExtCostsEntryfmt);
DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore(ItemDisplayTemplateEntryfmt);
DBCStorage <ItemExtendedCostEntry> sItemExtendedCostStore(ItemExtendedCostEntryfmt);
DBCStorage <ItemLimitCategoryEntry> sItemLimitCategoryStore(ItemLimitCategoryEntryfmt);
DBCStorage <ItemRandomPropertiesEntry> sItemRandomPropertiesStore(ItemRandomPropertiesfmt);
DBCStorage <ItemRandomSuffixEntry> sItemRandomSuffixStore(ItemRandomSuffixfmt);
DBCStorage <ItemSetEntry> sItemSetStore(ItemSetEntryfmt);
DBCStorage <LFGDungeonEntry> sLFGDungeonStore(LFGDungeonEntryfmt);
DBCStorage <LightEntry> sLightStore(LightEntryfmt);
DBCStorage <LiquidTypeEntry> sLiquidTypeStore(LiquidTypefmt);
DBCStorage <LockEntry> sLockStore(LockEntryfmt);
DBCStorage <MailTemplateEntry> sMailTemplateStore(MailTemplateEntryfmt);
DBCStorage <MapEntry> sMapStore(MapEntryfmt);
// DBC used only for initialization sMapDifficultyMap at startup.
DBCStorage <MapDifficultyEntry> sMapDifficultyStore(MapDifficultyEntryfmt); // only for loading
MapDifficultyMap sMapDifficultyMap;
DBCStorage <MovieEntry> sMovieStore(MovieEntryfmt);
DBCStorage <OverrideSpellDataEntry> sOverrideSpellDataStore(OverrideSpellDatafmt);
DBCStorage <PowerDisplayEntry> sPowerDisplayStore(PowerDisplayfmt);
DBCStorage <PvPDifficultyEntry> sPvPDifficultyStore(PvPDifficultyfmt);
DBCStorage <QuestSortEntry> sQuestSortStore(QuestSortEntryfmt);
DBCStorage <QuestXPEntry> sQuestXPStore(QuestXPfmt);
DBCStorage <QuestFactionRewEntry> sQuestFactionRewardStore(QuestFactionRewardfmt);
DBCStorage <RandomPropertiesPointsEntry> sRandomPropertiesPointsStore(RandomPropertiesPointsfmt);
DBCStorage <ScalingStatDistributionEntry> sScalingStatDistributionStore(ScalingStatDistributionfmt);
DBCStorage <ScalingStatValuesEntry> sScalingStatValuesStore(ScalingStatValuesfmt);
DBCStorage <SkillLineEntry> sSkillLineStore(SkillLinefmt);
DBCStorage <SkillLineAbilityEntry> sSkillLineAbilityStore(SkillLineAbilityfmt);
DBCStorage <SoundEntriesEntry> sSoundEntriesStore(SoundEntriesfmt);
DBCStorage <SpellItemEnchantmentEntry> sSpellItemEnchantmentStore(SpellItemEnchantmentfmt);
DBCStorage <SpellItemEnchantmentConditionEntry> sSpellItemEnchantmentConditionStore(SpellItemEnchantmentConditionfmt);
DBCStorage <SpellEntry> sSpellStore(SpellEntryfmt);
SpellCategoryStore sSpellsByCategoryStore;
PetFamilySpellsStore sPetFamilySpellsStore;
DBCStorage <SpellCastTimesEntry> sSpellCastTimesStore(SpellCastTimefmt);
DBCStorage <SpellCategoryEntry> sSpellCategoryStore(SpellCategoryfmt);
DBCStorage <SpellDifficultyEntry> sSpellDifficultyStore(SpellDifficultyfmt);
DBCStorage <SpellDurationEntry> sSpellDurationStore(SpellDurationfmt);
DBCStorage <SpellFocusObjectEntry> sSpellFocusObjectStore(SpellFocusObjectfmt);
DBCStorage <SpellRadiusEntry> sSpellRadiusStore(SpellRadiusfmt);
DBCStorage <SpellRangeEntry> sSpellRangeStore(SpellRangefmt);
DBCStorage <SpellRuneCostEntry> sSpellRuneCostStore(SpellRuneCostfmt);
DBCStorage <SpellShapeshiftEntry> sSpellShapeshiftStore(SpellShapeshiftfmt);
DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore(StableSlotPricesfmt);
DBCStorage <SummonPropertiesEntry> sSummonPropertiesStore(SummonPropertiesfmt);
DBCStorage <TalentEntry> sTalentStore(TalentEntryfmt);
TalentSpellPosMap sTalentSpellPosMap;
DBCStorage <TalentTabEntry> sTalentTabStore(TalentTabEntryfmt);
// store absolute bit position for first rank for talent inspect
static uint32 sTalentTabPages[MAX_CLASSES][3];
DBCStorage <TaxiNodesEntry> sTaxiNodesStore(TaxiNodesEntryfmt);
TaxiMask sTaxiNodesMask;
TaxiMask sOldContinentsNodesMask;
TaxiMask sHordeTaxiNodesMask;
TaxiMask sAllianceTaxiNodesMask;
TaxiMask sDeathKnightTaxiNodesMask;
// DBC used only for initialization sTaxiPathSetBySource at startup.
TaxiPathSetBySource sTaxiPathSetBySource;
DBCStorage <TaxiPathEntry> sTaxiPathStore(TaxiPathEntryfmt);
// DBC used only for initialization sTaxiPathNodeStore at startup.
TaxiPathNodesByPath sTaxiPathNodesByPath;
static DBCStorage <TaxiPathNodeEntry> sTaxiPathNodeStore(TaxiPathNodeEntryfmt);
DBCStorage <TeamContributionPointsEntry> sTeamContributionPointsStore(TeamContributionPointsfmt);
DBCStorage <TotemCategoryEntry> sTotemCategoryStore(TotemCategoryEntryfmt);
DBCStorage <TransportAnimationEntry> sTransportAnimationStore(TransportAnimationfmt);
DBCStorage <TransportRotationEntry> sTransportRotationStore(TransportRotationfmt);
DBCStorage <VehicleEntry> sVehicleStore(VehicleEntryfmt);
DBCStorage <VehicleSeatEntry> sVehicleSeatStore(VehicleSeatEntryfmt);
DBCStorage <WMOAreaTableEntry> sWMOAreaTableStore(WMOAreaTableEntryfmt);
DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore(WorldMapAreaEntryfmt);
DBCStorage <WorldMapOverlayEntry> sWorldMapOverlayStore(WorldMapOverlayEntryfmt);
std::unordered_map<uint32, FlyByCameraCollection> sFlyByCameraStore;
typedef std::list<std::string> StoreProblemList;
uint32 DBCFileCount = 0;
static bool LoadDBC_assert_print(uint32 fsize, uint32 rsize, const std::string& filename)
{
sLog->outError("Size of '%s' set by format string (%u) not equal size of C++ structure (%u).", filename.c_str(), fsize, rsize);
// ASSERT must fail after function call
return false;
}
template<class T>
inline void LoadDBC(uint32& availableDbcLocales, StoreProblemList& errors, DBCStorage<T>& storage, std::string const& dbcPath, std::string const& filename, char const* dbTable = nullptr)
{
// compatibility format and C++ structure sizes
ASSERT(DBCFileLoader::GetFormatRecordSize(storage.GetFormat()) == sizeof(T) || LoadDBC_assert_print(DBCFileLoader::GetFormatRecordSize(storage.GetFormat()), sizeof(T), filename));
++DBCFileCount;
std::string dbcFilename = dbcPath + filename;
bool existDBData = false;
if (storage.Load(dbcFilename.c_str()))
{
for (uint8 i = 0; i < TOTAL_LOCALES; ++i)
{
if (!(availableDbcLocales & (1 << i)))
continue;
std::string localizedName(dbcPath);
localizedName.append(localeNames[i]);
localizedName.push_back('/');
localizedName.append(filename);
if (!storage.LoadStringsFrom(localizedName.c_str()))
availableDbcLocales &= ~(1 << i); // mark as not available for speedup next checks
}
}
if (dbTable)
storage.LoadFromDB(dbTable, storage.GetFormat());
if (storage.GetNumRows())
existDBData = true;
if (!existDBData)
{
// sort problematic dbc to (1) non compatible and (2) non-existed
if (FILE* f = fopen(dbcFilename.c_str(), "rb"))
{
std::ostringstream stream;
stream << dbcFilename << " exists, and has " << storage.GetFieldCount() << " field(s) (expected " << strlen(storage.GetFormat()) << "). Extracted file might be from wrong client version or a database-update has been forgotten.";
std::string buf = stream.str();
errors.push_back(buf);
fclose(f);
}
else
errors.push_back(dbcFilename);
}
}
void LoadDBCStores(const std::string& dataPath)
{
uint32 oldMSTime = getMSTime();
std::string dbcPath = dataPath + "dbc/";
StoreProblemList bad_dbc_files;
uint32 availableDbcLocales = 0xFFFFFFFF;
#define LOAD_DBC(store, file, dbtable) LoadDBC(availableDbcLocales, bad_dbc_files, store, dbcPath, file, dbtable)
LOAD_DBC(sAreaTableStore, "AreaTable.dbc", "areatable_dbc");
LOAD_DBC(sAchievementStore, "Achievement.dbc", "achievement_dbc");
LOAD_DBC(sAchievementCategoryStore, "Achievement_Category.dbc", "achievement_category_dbc");
LOAD_DBC(sAchievementCriteriaStore, "Achievement_Criteria.dbc", "achievement_criteria_dbc");
LOAD_DBC(sAreaGroupStore, "AreaGroup.dbc", "areagroup_dbc");
LOAD_DBC(sAreaPOIStore, "AreaPOI.dbc", "areapoi_dbc");
LOAD_DBC(sAuctionHouseStore, "AuctionHouse.dbc", "auctionhouse_dbc");
LOAD_DBC(sBankBagSlotPricesStore, "BankBagSlotPrices.dbc", "bankbagslotprices_dbc");
LOAD_DBC(sBattlemasterListStore, "BattlemasterList.dbc", "battlemasterlist_dbc");
LOAD_DBC(sBarberShopStyleStore, "BarberShopStyle.dbc", "barbershopstyle_dbc");
LOAD_DBC(sCharStartOutfitStore, "CharStartOutfit.dbc", "charstartoutfit_dbc");
LOAD_DBC(sCharTitlesStore, "CharTitles.dbc", "chartitles_dbc");
LOAD_DBC(sChatChannelsStore, "ChatChannels.dbc", "chatchannels_dbc");
LOAD_DBC(sChrClassesStore, "ChrClasses.dbc", "chrclasses_dbc");
LOAD_DBC(sChrRacesStore, "ChrRaces.dbc", "chrraces_dbc");
LOAD_DBC(sCinematicCameraStore, "CinematicCamera.dbc", "cinematiccamera_dbc");
LOAD_DBC(sCinematicSequencesStore, "CinematicSequences.dbc", "cinematicsequences_dbc");
LOAD_DBC(sCreatureDisplayInfoStore, "CreatureDisplayInfo.dbc", "creaturedisplayinfo_dbc");
LOAD_DBC(sCreatureFamilyStore, "CreatureFamily.dbc", "creaturefamily_dbc");
LOAD_DBC(sCreatureModelDataStore, "CreatureModelData.dbc", "creaturemodeldata_dbc");
LOAD_DBC(sCreatureSpellDataStore, "CreatureSpellData.dbc", "creaturespelldata_dbc");
LOAD_DBC(sCreatureTypeStore, "CreatureType.dbc", "creaturetype_dbc");
LOAD_DBC(sCurrencyTypesStore, "CurrencyTypes.dbc", "currencytypes_dbc");
LOAD_DBC(sDestructibleModelDataStore, "DestructibleModelData.dbc", "destructiblemodeldata_dbc");
LOAD_DBC(sDungeonEncounterStore, "DungeonEncounter.dbc", "dungeonencounter_dbc");
LOAD_DBC(sDurabilityCostsStore, "DurabilityCosts.dbc", "durabilitycosts_dbc");
LOAD_DBC(sDurabilityQualityStore, "DurabilityQuality.dbc", "durabilityquality_dbc");
LOAD_DBC(sEmotesStore, "Emotes.dbc", "emotes_dbc");
LOAD_DBC(sEmotesTextStore, "EmotesText.dbc", "emotestext_dbc");
LOAD_DBC(sFactionStore, "Faction.dbc", "faction_dbc");
LOAD_DBC(sFactionTemplateStore, "FactionTemplate.dbc", "factiontemplate_dbc");
LOAD_DBC(sGameObjectDisplayInfoStore, "GameObjectDisplayInfo.dbc", "gameobjectdisplayinfo_dbc");
LOAD_DBC(sGemPropertiesStore, "GemProperties.dbc", "gemproperties_dbc");
LOAD_DBC(sGlyphPropertiesStore, "GlyphProperties.dbc", "glyphproperties_dbc");
LOAD_DBC(sGlyphSlotStore, "GlyphSlot.dbc", "glyphslot_dbc");
LOAD_DBC(sGtBarberShopCostBaseStore, "gtBarberShopCostBase.dbc", "gtbarbershopcostbase_dbc");
LOAD_DBC(sGtCombatRatingsStore, "gtCombatRatings.dbc", "gtcombatratings_dbc");
LOAD_DBC(sGtChanceToMeleeCritBaseStore, "gtChanceToMeleeCritBase.dbc", "gtchancetomeleecritbase_dbc");
LOAD_DBC(sGtChanceToMeleeCritStore, "gtChanceToMeleeCrit.dbc", "gtchancetomeleecrit_dbc");
LOAD_DBC(sGtChanceToSpellCritBaseStore, "gtChanceToSpellCritBase.dbc", "gtchancetospellcritbase_dbc");
LOAD_DBC(sGtChanceToSpellCritStore, "gtChanceToSpellCrit.dbc", "gtchancetospellcrit_dbc");
LOAD_DBC(sGtNPCManaCostScalerStore, "gtNPCManaCostScaler.dbc", "gtnpcmanacostscaler_dbc");
LOAD_DBC(sGtOCTClassCombatRatingScalarStore, "gtOCTClassCombatRatingScalar.dbc", "gtoctclasscombatratingscalar_dbc");
LOAD_DBC(sGtOCTRegenHPStore, "gtOCTRegenHP.dbc", "gtoctregenhp_dbc");
//LOAD_DBC(sGtOCTRegenMPStore, "gtOCTRegenMP.dbc", "gtoctregenmp_dbc"); -- not used currently
LOAD_DBC(sGtRegenHPPerSptStore, "gtRegenHPPerSpt.dbc", "gtregenhpperspt_dbc");
LOAD_DBC(sGtRegenMPPerSptStore, "gtRegenMPPerSpt.dbc", "gtregenmpperspt_dbc");
LOAD_DBC(sHolidaysStore, "Holidays.dbc", "holidays_dbc");
LOAD_DBC(sItemBagFamilyStore, "ItemBagFamily.dbc", "itembagfamily_dbc");
LOAD_DBC(sItemDisplayInfoStore, "ItemDisplayInfo.dbc", "itemdisplayinfo_dbc");
//LOAD_DBC(sItemCondExtCostsStore, "ItemCondExtCosts.dbc", "itemcondextcosts_dbc");
LOAD_DBC(sItemExtendedCostStore, "ItemExtendedCost.dbc", "itemextendedcost_dbc");
LOAD_DBC(sItemLimitCategoryStore, "ItemLimitCategory.dbc", "itemlimitcategory_dbc");
LOAD_DBC(sItemRandomPropertiesStore, "ItemRandomProperties.dbc", "itemrandomproperties_dbc");
LOAD_DBC(sItemRandomSuffixStore, "ItemRandomSuffix.dbc", "itemrandomsuffix_dbc");
LOAD_DBC(sItemSetStore, "ItemSet.dbc", "itemset_dbc");
LOAD_DBC(sLFGDungeonStore, "LFGDungeons.dbc", "lfgdungeons_dbc");
LOAD_DBC(sLightStore, "Light.dbc", "light_dbc");
LOAD_DBC(sLiquidTypeStore, "LiquidType.dbc", "liquidtype_dbc");
LOAD_DBC(sLockStore, "Lock.dbc", "lock_dbc");
LOAD_DBC(sMailTemplateStore, "MailTemplate.dbc", "mailtemplate_dbc");
LOAD_DBC(sMapStore, "Map.dbc", "map_dbc");
LOAD_DBC(sMapDifficultyStore, "MapDifficulty.dbc", "mapdifficulty_dbc");
LOAD_DBC(sMovieStore, "Movie.dbc", "movie_dbc");
LOAD_DBC(sOverrideSpellDataStore, "OverrideSpellData.dbc", "overridespelldata_dbc");
LOAD_DBC(sPowerDisplayStore, "PowerDisplay.dbc", "powerdisplay_dbc");
LOAD_DBC(sPvPDifficultyStore, "PvpDifficulty.dbc", "pvpdifficulty_dbc");
LOAD_DBC(sQuestXPStore, "QuestXP.dbc", "questxp_dbc");
LOAD_DBC(sQuestFactionRewardStore, "QuestFactionReward.dbc", "questfactionreward_dbc");
LOAD_DBC(sQuestSortStore, "QuestSort.dbc", "questsort_dbc");
LOAD_DBC(sRandomPropertiesPointsStore, "RandPropPoints.dbc", "randproppoints_dbc");
LOAD_DBC(sScalingStatDistributionStore, "ScalingStatDistribution.dbc", "scalingstatdistribution_dbc");
LOAD_DBC(sScalingStatValuesStore, "ScalingStatValues.dbc", "scalingstatvalues_dbc");
LOAD_DBC(sSkillLineStore, "SkillLine.dbc", "skillline_dbc");
LOAD_DBC(sSkillLineAbilityStore, "SkillLineAbility.dbc", "skilllineability_dbc");
LOAD_DBC(sSoundEntriesStore, "SoundEntries.dbc", "soundentries_dbc");
LOAD_DBC(sSpellStore, "Spell.dbc", "spell_dbc");
LOAD_DBC(sSpellCastTimesStore, "SpellCastTimes.dbc", "spellcasttimes_dbc");
LOAD_DBC(sSpellCategoryStore, "SpellCategory.dbc", "spellcategory_dbc");
LOAD_DBC(sSpellDifficultyStore, "SpellDifficulty.dbc", "spelldifficulty_dbc");
LOAD_DBC(sSpellDurationStore, "SpellDuration.dbc", "spellduration_dbc");
LOAD_DBC(sSpellFocusObjectStore, "SpellFocusObject.dbc", "spellfocusobject_dbc");
LOAD_DBC(sSpellItemEnchantmentStore, "SpellItemEnchantment.dbc", "spellitemenchantment_dbc");
LOAD_DBC(sSpellItemEnchantmentConditionStore, "SpellItemEnchantmentCondition.dbc", "spellitemenchantmentcondition_dbc");
LOAD_DBC(sSpellRadiusStore, "SpellRadius.dbc", "spellradius_dbc");
LOAD_DBC(sSpellRangeStore, "SpellRange.dbc", "spellrange_dbc");
LOAD_DBC(sSpellRuneCostStore, "SpellRuneCost.dbc", "spellrunecost_dbc");
LOAD_DBC(sSpellShapeshiftStore, "SpellShapeshiftForm.dbc", "spellshapeshiftform_dbc");
LOAD_DBC(sStableSlotPricesStore, "StableSlotPrices.dbc", "stableslotprices_dbc");
LOAD_DBC(sSummonPropertiesStore, "SummonProperties.dbc", "summonproperties_dbc");
LOAD_DBC(sTalentStore, "Talent.dbc", "talent_dbc");
LOAD_DBC(sTalentTabStore, "TalentTab.dbc", "talenttab_dbc");
LOAD_DBC(sTaxiNodesStore, "TaxiNodes.dbc", "taxinodes_dbc");
LOAD_DBC(sTaxiPathStore, "TaxiPath.dbc", "taxipath_dbc");
LOAD_DBC(sTaxiPathNodeStore, "TaxiPathNode.dbc", "taxipathnode_dbc");
LOAD_DBC(sTeamContributionPointsStore, "TeamContributionPoints.dbc", "teamcontributionpoints_dbc");
LOAD_DBC(sTotemCategoryStore, "TotemCategory.dbc", "totemcategory_dbc");
LOAD_DBC(sTransportAnimationStore, "TransportAnimation.dbc", "transportanimation_dbc");
LOAD_DBC(sTransportRotationStore, "TransportRotation.dbc", "transportrotation_dbc");
LOAD_DBC(sVehicleStore, "Vehicle.dbc", "vehicle_dbc");
LOAD_DBC(sVehicleSeatStore, "VehicleSeat.dbc", "vehicleseat_dbc");
LOAD_DBC(sWMOAreaTableStore, "WMOAreaTable.dbc", "wmoareatable_dbc");
LOAD_DBC(sWorldMapAreaStore, "WorldMapArea.dbc", "worldmaparea_dbc");
LOAD_DBC(sWorldMapOverlayStore, "WorldMapOverlay.dbc", "worldmapoverlay_dbc");
#undef LOAD_DBC
for (CharStartOutfitEntry const* outfit : sCharStartOutfitStore)
sCharStartOutfitMap[outfit->Race | (outfit->Class << 8) | (outfit->Gender << 16)] = outfit;
for (FactionEntry const* faction : sFactionStore)
{
if (faction->team)
{
SimpleFactionsList& flist = sFactionTeamMap[faction->team];
flist.push_back(faction->ID);
}
}
for (GameObjectDisplayInfoEntry const* info : sGameObjectDisplayInfoStore)
{
if (info->maxX < info->minX)
std::swap(*(float*)(&info->maxX), *(float*)(&info->minX));
if (info->maxY < info->minY)
std::swap(*(float*)(&info->maxY), *(float*)(&info->minY));
if (info->maxZ < info->minZ)
std::swap(*(float*)(&info->maxZ), *(float*)(&info->minZ));
}
// fill data
for (MapDifficultyEntry const* entry : sMapDifficultyStore)
sMapDifficultyMap[MAKE_PAIR32(entry->MapId, entry->Difficulty)] = MapDifficulty(entry->resetTime, entry->maxPlayers, entry->areaTriggerText[0] != '\0');
for (PvPDifficultyEntry const* entry : sPvPDifficultyStore)
if (entry->bracketId > MAX_BATTLEGROUND_BRACKETS)
ASSERT(false && "Need update MAX_BATTLEGROUND_BRACKETS by DBC data");
for (auto i : sSpellStore)
if (i->Category)
sSpellsByCategoryStore[i->Category].insert(i->Id);
for (SkillLineAbilityEntry const* skillLine : sSkillLineAbilityStore)
{
SpellEntry const* spellInfo = sSpellStore.LookupEntry(skillLine->spellId);
if (spellInfo && spellInfo->Attributes & SPELL_ATTR0_PASSIVE)
{
for (CreatureFamilyEntry const* cFamily : sCreatureFamilyStore)
{
if (skillLine->skillId != cFamily->skillLine[0] && skillLine->skillId != cFamily->skillLine[1])
continue;
if (spellInfo->SpellLevel)
continue;
if (skillLine->learnOnGetSkill != ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL)
continue;
sPetFamilySpellsStore[cFamily->ID].insert(spellInfo->Id);
}
}
}
// Create Spelldifficulty searcher
for (SpellDifficultyEntry const* spellDiff : sSpellDifficultyStore)
{
SpellDifficultyEntry newEntry;
memset(newEntry.SpellID, 0, 4 * sizeof(uint32));
for (uint8 x = 0; x < MAX_DIFFICULTY; ++x)
{
if (spellDiff->SpellID[x] <= 0 || !sSpellStore.LookupEntry(spellDiff->SpellID[x]))
{
if (spellDiff->SpellID[x] > 0) //don't show error if spell is <= 0, not all modes have spells and there are unknown negative values
sLog->outErrorDb("spelldifficulty_dbc: spell %i at field id: %u at spellid %i does not exist in SpellStore (spell.dbc), loaded as 0", spellDiff->SpellID[x], spellDiff->ID, x);
newEntry.SpellID[x] = 0; // spell was <= 0 or invalid, set to 0
}
else
newEntry.SpellID[x] = spellDiff->SpellID[x];
}
if (newEntry.SpellID[0] <= 0 || newEntry.SpellID[1] <= 0) // id0-1 must be always set!
continue;
for (uint8 x = 0; x < MAX_DIFFICULTY; ++x)
if (newEntry.SpellID[x])
sSpellMgr->SetSpellDifficultyId(uint32(newEntry.SpellID[x]), spellDiff->ID);
}
// create talent spells set
for (TalentEntry const* talentInfo : sTalentStore)
for (uint8 j = 0; j < MAX_TALENT_RANK; ++j)
if (talentInfo->RankID[j])
sTalentSpellPosMap[talentInfo->RankID[j]] = TalentSpellPos(talentInfo->TalentID, j);
// prepare fast data access to bit pos of talent ranks for use at inspecting
{
// now have all max ranks (and then bit amount used for store talent ranks in inspect)
for (uint32 talentTabId = 1; talentTabId < sTalentTabStore.GetNumRows(); ++talentTabId)
{
TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentTabId);
if (!talentTabInfo)
continue;
// prevent memory corruption; otherwise cls will become 12 below
if ((talentTabInfo->ClassMask & CLASSMASK_ALL_PLAYABLE) == 0)
continue;
// store class talent tab pages
for (uint32 cls = 1; cls < MAX_CLASSES; ++cls)
if (talentTabInfo->ClassMask & (1 << (cls - 1)))
sTalentTabPages[cls][talentTabInfo->tabpage] = talentTabId;
}
}
for (uint32 i = 1; i < sTaxiPathStore.GetNumRows(); ++i)
if (TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(i))
sTaxiPathSetBySource[entry->from][entry->to] = TaxiPathBySourceAndDestination(entry->ID, entry->price);
// Calculate path nodes count
uint32 pathCount = sTaxiPathStore.GetNumRows();
std::vector<uint32> pathLength;
pathLength.resize(pathCount); // 0 and some other indexes not used
for (uint32 i = 1; i < sTaxiPathNodeStore.GetNumRows(); ++i)
if (TaxiPathNodeEntry const* entry = sTaxiPathNodeStore.LookupEntry(i))
if (pathLength[entry->path] < entry->index + 1)
pathLength[entry->path] = entry->index + 1;
// Set path length
sTaxiPathNodesByPath.resize(pathCount); // 0 and some other indexes not used
for (uint32 i = 1; i < sTaxiPathNodesByPath.size(); ++i)
sTaxiPathNodesByPath[i].resize(pathLength[i]);
// fill data
for (TaxiPathNodeEntry const* entry : sTaxiPathNodeStore)
sTaxiPathNodesByPath[entry->path][entry->index] = entry;
// Initialize global taxinodes mask
// include existed nodes that have at least single not spell base (scripted) path
{
std::set<uint32> spellPaths;
for (SpellEntry const* sInfo : sSpellStore)
for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
if (sInfo->Effect[j] == SPELL_EFFECT_SEND_TAXI)
spellPaths.insert(sInfo->EffectMiscValue[j]);
memset(sTaxiNodesMask, 0, sizeof(sTaxiNodesMask));
memset(sOldContinentsNodesMask, 0, sizeof(sOldContinentsNodesMask));
memset(sHordeTaxiNodesMask, 0, sizeof(sHordeTaxiNodesMask));
memset(sAllianceTaxiNodesMask, 0, sizeof(sAllianceTaxiNodesMask));
memset(sDeathKnightTaxiNodesMask, 0, sizeof(sDeathKnightTaxiNodesMask));
for (uint32 i = 1; i < sTaxiNodesStore.GetNumRows(); ++i)
{
TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(i);
if (!node)
continue;
TaxiPathSetBySource::const_iterator src_i = sTaxiPathSetBySource.find(i);
if (src_i != sTaxiPathSetBySource.end() && !src_i->second.empty())
{
bool ok = false;
for (TaxiPathSetForSource::const_iterator dest_i = src_i->second.begin(); dest_i != src_i->second.end(); ++dest_i)
{
// not spell path
if (dest_i->second.price || spellPaths.find(dest_i->second.ID) == spellPaths.end())
{
ok = true;
break;
}
}
if (!ok)
continue;
}
// valid taxi network node
uint8 field = (uint8)((i - 1) / 32);
uint32 submask = 1 << ((i - 1) % 32);
sTaxiNodesMask[field] |= submask;
if (node->MountCreatureID[0] && node->MountCreatureID[0] != 32981)
sHordeTaxiNodesMask[field] |= submask;
if (node->MountCreatureID[1] && node->MountCreatureID[1] != 32981)
sAllianceTaxiNodesMask[field] |= submask;
if (node->MountCreatureID[0] == 32981 || node->MountCreatureID[1] == 32981)
sDeathKnightTaxiNodesMask[field] |= submask;
// old continent node (+ nodes virtually at old continents, check explicitly to avoid loading map files for zone info)
if (node->map_id < 2 || i == 82 || i == 83 || i == 93 || i == 94)
sOldContinentsNodesMask[field] |= submask;
// fix DK node at Ebon Hold and Shadow Vault flight master
if (i == 315 || i == 333)
((TaxiNodesEntry*)node)->MountCreatureID[1] = 32981;
}
}
for (TransportAnimationEntry const* anim : sTransportAnimationStore)
sTransportMgr->AddPathNodeToTransport(anim->TransportEntry, anim->TimeSeg, anim);
for (TransportRotationEntry const* rot : sTransportRotationStore)
sTransportMgr->AddPathRotationToTransport(rot->TransportEntry, rot->TimeSeg, rot);
for (WMOAreaTableEntry const* entry : sWMOAreaTableStore)
sWMOAreaInfoByTripple[WMOAreaTableKey(entry->rootId, entry->adtId, entry->groupId)] = entry;
// error checks
if (bad_dbc_files.size() >= DBCFileCount)
{
sLog->outError("Incorrect DataDir value in worldserver.conf or ALL required *.dbc files (%d) not found by path: %sdbc", DBCFileCount, dataPath.c_str());
exit(1);
}
else if (!bad_dbc_files.empty())
{
std::string str;
for (StoreProblemList::iterator i = bad_dbc_files.begin(); i != bad_dbc_files.end(); ++i)
str += *i + "\n";
sLog->outError("Some required *.dbc files (%u from %d) not found or not compatible:\n%s", (uint32)bad_dbc_files.size(), DBCFileCount, str.c_str());
exit(1);
}
// Check loaded DBC files proper version
if (!sAreaTableStore.LookupEntry(4987) || // last area added in 3.3.5a
!sCharTitlesStore.LookupEntry(177) || // last char title added in 3.3.5a
!sGemPropertiesStore.LookupEntry(1629) || // last added spell in 3.3.5a
!sItemExtendedCostStore.LookupEntry(2997) || // last item extended cost added in 3.3.5a
!sMapStore.LookupEntry(724) || // last map added in 3.3.5a
!sSpellStore.LookupEntry(80864) ) // last client known item added in 3.3.5a
{
sLog->outError("You have _outdated_ DBC data. Please extract correct versions from current using client.");
exit(1);
}
LoadM2Cameras(dataPath);
sLog->outString(">> Initialized %d data stores in %u ms", DBCFileCount, GetMSTimeDiffToNow(oldMSTime));
sLog->outString();
}
// Convert the geomoetry from a spline value, to an actual WoW XYZ
G3D::Vector3 TranslateLocation(G3D::Vector4 const* DBCPosition, G3D::Vector3 const* basePosition, G3D::Vector3 const* splineVector)
{
G3D::Vector3 work;
float x = basePosition->x + splineVector->x;
float y = basePosition->y + splineVector->y;
float z = basePosition->z + splineVector->z;
float const distance = sqrt((x * x) + (y * y));
float angle = std::atan2(x, y) - DBCPosition->w;
if (angle < 0)
{
angle += 2 * float(M_PI);
}
work.x = DBCPosition->x + (distance * sin(angle));
work.y = DBCPosition->y + (distance * cos(angle));
work.z = DBCPosition->z + z;
return work;
}
// Number of cameras not used. Multiple cameras never used in 3.3.5
bool readCamera(M2Camera const* cam, uint32 buffSize, M2Header const* header, CinematicCameraEntry const* dbcentry)
{
char const* buffer = reinterpret_cast<char const*>(header);
FlyByCameraCollection cameras;
FlyByCameraCollection targetcam;
G3D::Vector4 DBCData;
DBCData.x = dbcentry->base_x;
DBCData.y = dbcentry->base_y;
DBCData.z = dbcentry->base_z;
DBCData.w = dbcentry->base_o;
// Read target locations, only so that we can calculate orientation
for (uint32 k = 0; k < cam->target_positions.timestamps.number; ++k)
{
// Extract Target positions
if (cam->target_positions.timestamps.offset_elements + sizeof(M2Array) > buffSize)
{
return false;
}
M2Array const* targTsArray = reinterpret_cast<M2Array const*>(buffer + cam->target_positions.timestamps.offset_elements);
if (targTsArray->offset_elements + sizeof(uint32) > buffSize || cam->target_positions.values.offset_elements + sizeof(M2Array) > buffSize)
{
return false;
}
uint32 const* targTimestamps = reinterpret_cast<uint32 const*>(buffer + targTsArray->offset_elements);
M2Array const* targArray = reinterpret_cast<M2Array const*>(buffer + cam->target_positions.values.offset_elements);
if (targArray->offset_elements + sizeof(M2SplineKey<G3D::Vector3>) > buffSize)
{
return false;
}
M2SplineKey<G3D::Vector3> const* targPositions = reinterpret_cast<M2SplineKey<G3D::Vector3> const*>(buffer + targArray->offset_elements);
// Read the data for this set
uint32 currPos = targArray->offset_elements;
for (uint32 i = 0; i < targTsArray->number; ++i)
{
if (currPos + sizeof(M2SplineKey<G3D::Vector3>) > buffSize)
{
return false;
}
// Translate co-ordinates
G3D::Vector3 newPos = TranslateLocation(&DBCData, &cam->target_position_base, &targPositions->p0);
// Add to vector
FlyByCamera thisCam;
thisCam.timeStamp = targTimestamps[i];
thisCam.locations.x = newPos.x;
thisCam.locations.y = newPos.y;
thisCam.locations.z = newPos.z;
thisCam.locations.w = 0.0f;
targetcam.push_back(thisCam);
targPositions++;
currPos += sizeof(M2SplineKey<G3D::Vector3>);
}
}
// Read camera positions and timestamps (translating first position of 3 only, we don't need to translate the whole spline)
for (uint32 k = 0; k < cam->positions.timestamps.number; ++k)
{
// Extract Camera positions for this set
if (cam->positions.timestamps.offset_elements + sizeof(M2Array) > buffSize)
{
return false;
}
M2Array const* posTsArray = reinterpret_cast<M2Array const*>(buffer + cam->positions.timestamps.offset_elements);
if (posTsArray->offset_elements + sizeof(uint32) > buffSize || cam->positions.values.offset_elements + sizeof(M2Array) > buffSize)
{
return false;
}
uint32 const* posTimestamps = reinterpret_cast<uint32 const*>(buffer + posTsArray->offset_elements);
M2Array const* posArray = reinterpret_cast<M2Array const*>(buffer + cam->positions.values.offset_elements);
if (posArray->offset_elements + sizeof(M2SplineKey<G3D::Vector3>) > buffSize)
{
return false;
}
M2SplineKey<G3D::Vector3> const* positions = reinterpret_cast<M2SplineKey<G3D::Vector3> const*>(buffer + posArray->offset_elements);
// Read the data for this set
uint32 currPos = posArray->offset_elements;
for (uint32 i = 0; i < posTsArray->number; ++i)
{
if (currPos + sizeof(M2SplineKey<G3D::Vector3>) > buffSize)
{
return false;
}
// Translate co-ordinates
G3D::Vector3 newPos = TranslateLocation(&DBCData, &cam->position_base, &positions->p0);
// Add to vector
FlyByCamera thisCam;
thisCam.timeStamp = posTimestamps[i];
thisCam.locations.x = newPos.x;
thisCam.locations.y = newPos.y;
thisCam.locations.z = newPos.z;
if (targetcam.size() > 0)
{
// Find the target camera before and after this camera
FlyByCamera lastTarget;
FlyByCamera nextTarget;
// Pre-load first item
lastTarget = targetcam[0];
nextTarget = targetcam[0];
for (uint32 j = 0; j < targetcam.size(); ++j)
{
nextTarget = targetcam[j];
if (targetcam[j].timeStamp > posTimestamps[i])
{
break;
}
lastTarget = targetcam[j];
}
float x = lastTarget.locations.x;
float y = lastTarget.locations.y;
// float z = lastTarget.locations.z;
// Now, the timestamps for target cam and position can be different. So, if they differ we interpolate
if (lastTarget.timeStamp != posTimestamps[i])
{
uint32 timeDiffTarget = nextTarget.timeStamp - lastTarget.timeStamp;
uint32 timeDiffThis = posTimestamps[i] - lastTarget.timeStamp;
float xDiff = nextTarget.locations.x - lastTarget.locations.x;
float yDiff = nextTarget.locations.y - lastTarget.locations.y;
// float zDiff = nextTarget.locations.z - lastTarget.locations.z;
x = lastTarget.locations.x + (xDiff * (float(timeDiffThis) / float(timeDiffTarget)));
y = lastTarget.locations.y + (yDiff * (float(timeDiffThis) / float(timeDiffTarget)));
// z = lastTarget.locations.z + (zDiff * (float(timeDiffThis) / float(timeDiffTarget)));
}
float xDiff = x - thisCam.locations.x;
float yDiff = y - thisCam.locations.y;
thisCam.locations.w = std::atan2(yDiff, xDiff);
if (thisCam.locations.w < 0)
{
thisCam.locations.w += 2 * float(M_PI);
}
}
cameras.push_back(thisCam);
positions++;
currPos += sizeof(M2SplineKey<G3D::Vector3>);
}
}
sFlyByCameraStore[dbcentry->id] = cameras;
return true;
}
void LoadM2Cameras(const std::string& dataPath)
{
sFlyByCameraStore.clear();
sLog->outString(">> Loading Cinematic Camera files");
uint32 oldMSTime = getMSTime();
for (uint32 i = 0; i < sCinematicCameraStore.GetNumRows(); ++i)
{
if (CinematicCameraEntry const* dbcentry = sCinematicCameraStore.LookupEntry(i))
{
std::string filename = dataPath.c_str();
filename.append(dbcentry->filename);
// Replace slashes
size_t loc = filename.find("\\");
while (loc != std::string::npos)
{
filename.replace(loc, 1, "/");
loc = filename.find("\\");
}
// Replace mdx to .m2
loc = filename.find(".mdx");
if (loc != std::string::npos)
{
filename.replace(loc, 4, ".m2");
}
std::ifstream m2file(filename.c_str(), std::ios::in | std::ios::binary);
if (!m2file.is_open())
{
continue;
}
// Get file size
m2file.seekg(0, std::ios::end);
std::streamoff const fileSize = m2file.tellg();
// Reject if not at least the size of the header
if (static_cast<uint32>(fileSize) < sizeof(M2Header))
{
sLog->outError("Camera file %s is damaged. File is smaller than header size", filename.c_str());
m2file.close();
continue;
}
// Read 4 bytes (signature)
m2file.seekg(0, std::ios::beg);
char fileCheck[5];
m2file.read(fileCheck, 4);
fileCheck[4] = 0;
// Check file has correct magic (MD20)
if (strcmp(fileCheck, "MD20"))
{
sLog->outError("Camera file %s is damaged. File identifier not found", filename.c_str());
m2file.close();
continue;
}
// Now we have a good file, read it all into a vector of char's, then close the file.
std::vector<char> buffer(fileSize);
m2file.seekg(0, std::ios::beg);
if (!m2file.read(buffer.data(), fileSize))
{
m2file.close();
continue;
}
m2file.close();
// Read header
M2Header const* header = reinterpret_cast<M2Header const*>(buffer.data());
if (header->ofsCameras + sizeof(M2Camera) > static_cast<uint32>(fileSize))
{
sLog->outError("Camera file %s is damaged. Camera references position beyond file end", filename.c_str());
continue;
}
// Get camera(s) - Main header, then dump them.
M2Camera const* cam = reinterpret_cast<M2Camera const*>(buffer.data() + header->ofsCameras);
if (!readCamera(cam, fileSize, header, dbcentry))
{
sLog->outError("Camera file %s is damaged. Camera references position beyond file end", filename.c_str());
}
}
}
sLog->outString(">> Loaded %u cinematic waypoint sets in %u ms", (uint32)sFlyByCameraStore.size(), GetMSTimeDiffToNow(oldMSTime));
}
SimpleFactionsList const* GetFactionTeamList(uint32 faction)
{
FactionTeamMap::const_iterator itr = sFactionTeamMap.find(faction);
if (itr != sFactionTeamMap.end())
return &itr->second;
return nullptr;
}
char* GetPetName(uint32 petfamily, uint32 dbclang)
{
if (!petfamily)
return nullptr;
CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(petfamily);
if (!pet_family)
return nullptr;
return pet_family->Name[dbclang] ? pet_family->Name[dbclang] : nullptr;
}
TalentSpellPos const* GetTalentSpellPos(uint32 spellId)
{
TalentSpellPosMap::const_iterator itr = sTalentSpellPosMap.find(spellId);
if (itr == sTalentSpellPosMap.end())
return nullptr;
return &itr->second;
}
uint32 GetTalentSpellCost(uint32 spellId)
{
if (TalentSpellPos const* pos = GetTalentSpellPos(spellId))
return pos->rank + 1;
return 0;
}
WMOAreaTableEntry const* GetWMOAreaTableEntryByTripple(int32 rootid, int32 adtid, int32 groupid)
{
auto i = sWMOAreaInfoByTripple.find(WMOAreaTableKey(int16(rootid), int8(adtid), groupid));
if (i != sWMOAreaInfoByTripple.end())
return i->second;
return nullptr;
}
uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId)
{
if (mapid != 530 && mapid != 571) // speed for most cases
return mapid;
if (WorldMapAreaEntry const* wma = sWorldMapAreaStore.LookupEntry(zoneId))
return wma->virtual_map_id >= 0 ? wma->virtual_map_id : wma->map_id;
return mapid;
}
ContentLevels GetContentLevelsForMapAndZone(uint32 mapid, uint32 zoneId)
{
mapid = GetVirtualMapForMapAndZone(mapid, zoneId);
if (mapid < 2)
return CONTENT_1_60;
MapEntry const* mapEntry = sMapStore.LookupEntry(mapid);
if (!mapEntry)
return CONTENT_1_60;
switch (mapEntry->Expansion())
{
default:
return CONTENT_1_60;
case 1:
return CONTENT_61_70;
case 2:
return CONTENT_71_80;
}
}
void Zone2MapCoordinates(float& x, float& y, uint32 zone)
{
WorldMapAreaEntry const* maEntry = sWorldMapAreaStore.LookupEntry(zone);
// if not listed then map coordinates (instance)
if (!maEntry)
return;
std::swap(x, y); // at client map coords swapped
x = x * ((maEntry->x2 - maEntry->x1) / 100) + maEntry->x1;
y = y * ((maEntry->y2 - maEntry->y1) / 100) + maEntry->y1; // client y coord from top to down
}
void Map2ZoneCoordinates(float& x, float& y, uint32 zone)
{
WorldMapAreaEntry const* maEntry = sWorldMapAreaStore.LookupEntry(zone);
// if not listed then map coordinates (instance)
if (!maEntry)
return;
x = (x - maEntry->x1) / ((maEntry->x2 - maEntry->x1) / 100);
y = (y - maEntry->y1) / ((maEntry->y2 - maEntry->y1) / 100); // client y coord from top to down
std::swap(x, y); // client have map coords swapped
}
MapDifficulty const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty)
{
MapDifficultyMap::const_iterator itr = sMapDifficultyMap.find(MAKE_PAIR32(mapId, difficulty));
return itr != sMapDifficultyMap.end() ? &itr->second : nullptr;
}
MapDifficulty const* GetDownscaledMapDifficultyData(uint32 mapId, Difficulty& difficulty)
{
uint32 tmpDiff = difficulty;
MapDifficulty const* mapDiff = GetMapDifficultyData(mapId, Difficulty(tmpDiff));
if (!mapDiff)
{
if (tmpDiff > RAID_DIFFICULTY_25MAN_NORMAL) // heroic, downscale to normal
tmpDiff -= 2;
else
tmpDiff -= 1; // any non-normal mode for raids like tbc (only one mode)
// pull new data
mapDiff = GetMapDifficultyData(mapId, Difficulty(tmpDiff)); // we are 10 normal or 25 normal
if (!mapDiff)
{
tmpDiff -= 1;
mapDiff = GetMapDifficultyData(mapId, Difficulty(tmpDiff)); // 10 normal
}
}
difficulty = Difficulty(tmpDiff);
return mapDiff;
}
PvPDifficultyEntry const* GetBattlegroundBracketByLevel(uint32 mapid, uint32 level)
{
PvPDifficultyEntry const* maxEntry = nullptr; // used for level > max listed level case
for (PvPDifficultyEntry const* entry : sPvPDifficultyStore)
{
// skip unrelated and too-high brackets
if (entry->mapId != mapid || entry->minLevel > level)
continue;
// exactly fit
if (entry->maxLevel >= level)
return entry;
// remember for possible out-of-range case (search higher from existed)
if (!maxEntry || maxEntry->maxLevel < entry->maxLevel)
maxEntry = entry;
}
return maxEntry;
}
PvPDifficultyEntry const* GetBattlegroundBracketById(uint32 mapid, BattlegroundBracketId id)
{
for (PvPDifficultyEntry const* entry : sPvPDifficultyStore)
if (entry->mapId == mapid && entry->GetBracketId() == id)
return entry;
return nullptr;
}
uint32 const* GetTalentTabPages(uint8 cls)
{
return sTalentTabPages[cls];
}
bool IsSharedDifficultyMap(uint32 mapid)
{
return sWorld->getBoolConfig(CONFIG_INSTANCE_SHARED_ID) && (mapid == 631 || mapid == 724);
}
uint32 GetLiquidFlags(uint32 liquidType)
{
if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(liquidType))
return 1 << liq->Type;
return 0;
}
CharStartOutfitEntry const* GetCharStartOutfitEntry(uint8 race, uint8 class_, uint8 gender)
{
std::map<uint32, CharStartOutfitEntry const*>::const_iterator itr = sCharStartOutfitMap.find(race | (class_ << 8) | (gender << 16));
if (itr == sCharStartOutfitMap.end())
return nullptr;
return itr->second;
}
/// Returns LFGDungeonEntry for a specific map and difficulty. Will return first found entry if multiple dungeons use the same map (such as Scarlet Monastery)
LFGDungeonEntry const* GetLFGDungeon(uint32 mapId, Difficulty difficulty)
{
for (LFGDungeonEntry const* dungeon : sLFGDungeonStore)
if (dungeon->map == int32(mapId) && Difficulty(dungeon->difficulty) == difficulty)
return dungeon;
return nullptr;
}
uint32 GetDefaultMapLight(uint32 mapId)
{
for (int32 i = sLightStore.GetNumRows(); i >= 0; --i)
{
LightEntry const* light = sLightStore.LookupEntry(uint32(i));
if (!light)
continue;
if (light->MapId == mapId && light->X == 0.0f && light->Y == 0.0f && light->Z == 0.0f)
return light->Id;
}
return 0;
}