diff --git a/sql/updates/world/custom/custom_2019_01_08_00_world.sql b/sql/updates/world/custom/custom_2019_01_08_00_world.sql new file mode 100644 index 00000000000..498e6a1f9c7 --- /dev/null +++ b/sql/updates/world/custom/custom_2019_01_08_00_world.sql @@ -0,0 +1,313 @@ +DROP TABLE IF EXISTS `taxi_level_data`; +CREATE TABLE `taxi_level_data`( + `TaxiNodeId` SMALLINT(4) NOT NULL, + `Level` TINYINT(3) DEFAULT 0, + PRIMARY KEY (`TaxiNodeId`) +); + +INSERT INTO `taxi_level_data` (`TaxiNodeId`, `Level`) VALUES +-- Level 0 +(2, 0), +(582, 0), +(589, 0), +(6, 0), +(619, 0), +(620, 0), +(27, 0), +(456, 0), +(457, 0), +(94, 0), +(23, 0), +(536, 0), +(537, 0), +(11, 0), +(384, 0), +(460, 0), +(22, 0), +(402, 0), +(82, 0), +(624, 0), +-- Level 10 +(93, 10), +(26, 10), +(339, 10), +(4, 10), +(583, 10), +(584, 10), +(8, 10), +(555, 10), +(10, 10), +(645, 10), +(654, 10), +(681, 10), +(83, 10), +(205, 10), +(44, 10), +(613, 10), +(614, 10), +(683, 10), +(25, 10), +(80, 10), +(458, 10), +-- Level 15 +(5, 15), +(596, 15), +(615, 15), +-- Level 20 +(12, 20), +(622, 20), +(13, 20), +(667, 20), +(668, 20), +(669, 20), +(7, 20), +(551, 20), +(552, 20), +(553, 20), +(554, 20), +(28, 20), +(58, 20), +(61, 20), +(167, 20), +(338, 20), +(350, 20), +(351, 20), +(354, 20), +(356, 20), +-- Level 25 +(29, 25), +(33, 25), +(360, 25), +(361, 25), +(362, 25), +(363, 25), +(364, 25), +(365, 25), +(540, 25), +(541, 25), +(195, 25), +(590, 25), +(20, 25), +(16, 25), +(17, 25), +(601, 25), +-- Level 30 +(18, 30), +(19, 30), +(591, 30), +(592, 30), +(593, 30), +(37, 30), +(38, 30), +(366, 30), +(367, 30), +(368, 30), +(369, 30), +(370, 30), +(77, 30), +(387, 30), +(388, 30), +(389, 30), +(390, 30), +(391, 30), +(43, 30), +(76, 30), +(617, 30), +(618, 30), +-- Level 35 +(66, 35), +(649, 35), +(650, 35), +(651, 35), +(672, 35), +(31, 35), +(41, 35), +(42, 35), +(565, 35), +(567, 35), +(568, 35), +(569, 35), +(32, 35), +(55, 35), +(179, 35), +-- Level 40 +(30, 40), +(513, 40), +(67, 40), +(68, 40), +(84, 40), +(85, 40), +(86, 40), +(87, 40), +(383, 40), +(630, 40), +-- Level 44 +(21, 44), +(632, 44), +(633, 44), +(634, 44), +(635, 44), +-- Level 45 +(39, 45), +(40, 45), +(531, 45), +(532, 45), +(539, 45), +(65, 45), +(166, 45), +(594, 45), +(595, 45), +(597, 45), +-- Level 47 +(74, 47), +(75, 47), +(673, 47), +-- Level 49 +(70, 49), +(71, 49), +(675, 49), +(676, 49), +-- Level 50 +(79, 50), +(386, 50), +-- Level 52 +(56, 52), +(598, 52), +(599, 52), +(600, 52), +-- Level 54 +(45, 54), +(602, 54), +(603, 54), +(604, 54), +-- Level 55 +(72, 55), +(73, 55), +-- Level 58 +(99, 58), +(100, 58), +(101, 58), +(102, 58), +(129, 58), +(130, 58), +(141, 58), +-- Level 60 +(117, 60), +(118, 60), +(151, 60), +(164, 60), +-- Level 62 +(121, 62), +(127, 62), +(128, 62), +-- Level 64 +(119, 64), +(120, 64), +-- Level 65 +(125, 65), +(126, 65), +(156, 65), +(160, 65), +(163, 65), +-- Level 67 +(122, 67), +(139, 67), +(150, 67), +(123, 67), +(124, 67), +(140, 67), +(159, 67), +-- Level 68 +(245, 68), +(246, 68), +(257, 68), +(258, 68), +(259, 68), +(289, 68), +(296, 68), +(183, 68), +(184, 68), +(185, 68), +(190, 68), +(191, 68), +(192, 68), +(248, 68), +(295, 68), +(310, 68), +(213, 68), +-- Level 71 +(244, 71), +(247, 71), +(251, 71), +(252, 71), +(254, 71), +(256, 71), +(260, 71), +(294, 71), +-- Level 73 +(249, 73), +(250, 73), +(253, 73), +(255, 73), +-- Level 74 +(304, 74), +(305, 74), +(306, 74), +(307, 74), +(331, 74), +-- Level 76 +(308, 76), +(309, 76), +-- Level 77 +(303, 77), +(332, 77), +(336, 77), +(337, 77), +(320, 77), +(321, 77), +(322, 77), +(323, 77), +(324, 77), +(326, 77), +(327, 77), +(325, 77), +(333, 77), +(334, 77), +(335, 77), +(340, 77), +-- Level 80 +(521, 80), +(522, 80), +(523, 80), +(524, 80), +(525, 80), +(526, 80), +(605, 80), +(606, 80), +(607, 80), +(608, 80), +(609, 80), +(610, 80), +(611, 80), +(612, 80), +(557, 80), +(558, 80), +(559, 80), +(616, 80), +(781, 80), +-- Level 83 +(652, 83), +(653, 83), +(674, 83), +-- Level 84 +(656, 84), +(657, 84), +(658, 84), +(659, 84), +(660, 84), +(661, 84), +(662, 84), +(663, 84), +(664, 84), +(665, 84), +(666, 84); diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index 1a853ba0072..750bbd5cacd 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -522,6 +522,14 @@ enum EnchantmentSlotMask #define TaxiMaskSize 114 typedef std::array TaxiMask; +enum TaxiNodeFlags +{ + TAXI_NODE_FLAG_SCRIPT = 0x0, + TAXI_NODE_FLAG_ALLIANCE_RESTRICTED = 0x1, + TAXI_NODE_FLAG_HORDE_RESTRICTED = 0x2, + TAXI_NODE_FLAG_UNK = 0x4 +}; + enum TotemCategoryType { TOTEM_CATEGORY_TYPE_KNIFE = 1, diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 58e1c38375b..b87179ad1fd 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -22355,7 +22355,7 @@ void Player::SendTaxiNodeStatusMultiple() continue; WorldPacket data(SMSG_TAXINODE_STATUS, 9); data << *itr; - data << uint8(m_taxi.IsTaximaskNodeKnown(nearestNode) ? 1 : 0); + data << uint8(m_taxi.IsTaximaskNodeKnown(nearestNode) ? 1 : 2); SendDirectMessage(&data); } } diff --git a/src/server/game/Entities/Player/PlayerTaxi.cpp b/src/server/game/Entities/Player/PlayerTaxi.cpp index a5429a00c99..e4fa161245d 100644 --- a/src/server/game/Entities/Player/PlayerTaxi.cpp +++ b/src/server/game/Entities/Player/PlayerTaxi.cpp @@ -34,44 +34,26 @@ void PlayerTaxi::InitTaxiNodesForLevel(uint32 race, uint32 chrClass, uint8 level } } - // race specific initial known nodes: capital and taxi hub masks - switch (race) + uint32 team = Player::TeamForRace(race); + + // Patch 4.2: players will now unlock all taxi nodes within the recommended level range of the player + for (TaxiNodesEntry* itr : sTaxiNodesStore) { - case RACE_HUMAN: - SetTaximaskNode(2); - break; - case RACE_ORC: - SetTaximaskNode(23); - break; - case RACE_DWARF: - SetTaximaskNode(6); - break; - case RACE_NIGHTELF: - SetTaximaskNode(26); - SetTaximaskNode(27); - break; - case RACE_UNDEAD_PLAYER: - SetTaximaskNode(11); - break; - case RACE_TAUREN: - SetTaximaskNode(22); - break; - case RACE_GNOME: - SetTaximaskNode(6); - break; - case RACE_TROLL: - SetTaximaskNode(23); - break; - case RACE_BLOODELF: - SetTaximaskNode(82); - break; - case RACE_DRAENEI: - SetTaximaskNode(94); - break; + // Skip scripted and debug nodes + if (itr->Flags == TAXI_NODE_FLAG_SCRIPT) + continue; + + // Skip nodes that are restricted the player's opposite faction + if (!(itr->Flags & TAXI_NODE_FLAG_ALLIANCE_RESTRICTED) && team == ALLIANCE + || !(itr->Flags & TAXI_NODE_FLAG_HORDE_RESTRICTED) && team == HORDE) + continue; + + if (sObjectMgr->IsTaxiNodeUnlockedFor(itr->ID, level)) + SetTaximaskNode(itr->ID); } - // new continent starting masks (It will be accessible only at new map) - switch (Player::TeamForRace(race)) + // New continent starting masks (It will be accessible only at new map) + switch (team) { case ALLIANCE: SetTaximaskNode(100); // Honor Hold @@ -81,13 +63,9 @@ void PlayerTaxi::InitTaxiNodesForLevel(uint32 race, uint32 chrClass, uint8 level SetTaximaskNode(99); // Thrallmar SetTaximaskNode(257); // Warsong Hold break; + default: + break; } - // level dependent taxi hubs - if (level >= 68) - SetTaximaskNode(213); // Shattered Sun Staging Area - - if (level >= 78) - SetTaximaskNode(310); // Dalaran } void PlayerTaxi::LoadTaxiMask(std::string const &data) diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 1b432f8f762..2f096e33afe 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -10297,6 +10297,44 @@ void ObjectMgr::LoadCreatureQuestItems() TC_LOG_INFO("server.loading", ">> Loaded %u creature quest items in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } +void ObjectMgr::LoadTaxiNodeLevelData() +{ + uint32 oldMSTime = getMSTime(); + + // 0 1 + QueryResult result = WorldDatabase.Query("SELECT TaxiNodeId, `Level` FROM taxi_level_data ORDER BY TaxiNodeId ASC"); + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 taxi node level definitions. DB table `taxi_level_data` is empty."); + return; + } + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + + uint32 taxiNodeId = fields[0].GetUInt16(); + uint8 level = fields[1].GetUInt8(); + + TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(taxiNodeId); + + if (!node) + { + TC_LOG_ERROR("sql.sql", "Table `taxi_level_data` has data for nonexistent taxi node (ID: %u), skipped", taxiNodeId); + continue; + }; + + _taxiNodeLevelDataStore.emplace(taxiNodeId, level); + + ++count; + } + while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u taxi node level definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); +} + uint32 ObjectMgr::GetGameObjectTypeByEntry(uint32 entry) const { if (GameObjectTemplate const* goinfo = sObjectMgr->GetGameObjectTemplate(entry)) diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 38ad42da038..7a94c0c0e1f 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -558,6 +558,7 @@ typedef std::unordered_map ItemLocaleContainer; typedef std::unordered_map QuestLocaleContainer; typedef std::unordered_map NpcTextLocaleContainer; typedef std::unordered_map PageTextLocaleContainer; +typedef std::unordered_map TaxiNodeLevelDataContainer; struct GossipMenuItemsLocale { @@ -1215,6 +1216,8 @@ class TC_GAME_API ObjectMgr void LoadTerrainWorldMaps(); void LoadAreaPhases(); + void LoadTaxiNodeLevelData(); + std::string GeneratePetName(uint32 entry) const; uint32 GetBaseXP(uint8 level); uint32 GetXPForLevel(uint8 level) const; @@ -1522,6 +1525,16 @@ class TC_GAME_API ObjectMgr value = data[localeConstant]; } + // taxi node level data + bool IsTaxiNodeUnlockedFor(uint32 taxiNodeId, uint8 level) const + { + TaxiNodeLevelDataContainer::const_iterator itr = _taxiNodeLevelDataStore.find(taxiNodeId); + if (itr != _taxiNodeLevelDataStore.end()) + return itr->second <= level; + + return false; + } + CharacterConversionMap FactionChangeAchievements; CharacterConversionMap FactionChangeItems; CharacterConversionMap FactionChangeQuests; @@ -1715,6 +1728,8 @@ class TC_GAME_API ObjectMgr GraveyardOrientationContainer _graveyardOrientations; + TaxiNodeLevelDataContainer _taxiNodeLevelDataStore; + std::set _difficultyEntries[MAX_DIFFICULTY - 1]; // already loaded difficulty 1 value in creatures, used in CheckCreatureTemplate std::set _hasDifficultyEntries[MAX_DIFFICULTY - 1]; // already loaded creatures with difficulty 1 values, used in CheckCreatureTemplate diff --git a/src/server/game/Handlers/TaxiHandler.cpp b/src/server/game/Handlers/TaxiHandler.cpp index c341897698f..ccac699e0a9 100644 --- a/src/server/game/Handlers/TaxiHandler.cpp +++ b/src/server/game/Handlers/TaxiHandler.cpp @@ -57,7 +57,7 @@ void WorldSession::SendTaxiStatus(ObjectGuid guid) WorldPacket data(SMSG_TAXINODE_STATUS, 9); data << guid; - data << uint8(player->m_taxi.IsTaximaskNodeKnown(nearest) ? 1 : 0); + data << uint8(player->m_taxi.IsTaximaskNodeKnown(nearest) ? 1 : 2); SendPacket(&data); TC_LOG_DEBUG("network", "WORLD: Sent SMSG_TAXINODE_STATUS"); } diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 8c6257499e4..e435d4bcd3c 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -2095,6 +2095,9 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading Creature Text Locales..."); sCreatureTextMgr->LoadCreatureTextLocales(); + TC_LOG_INFO("server.loading", "Loading Taxi node level definitions..."); + sObjectMgr->LoadTaxiNodeLevelData(); + TC_LOG_INFO("server.loading", "Initializing Scripts..."); sScriptMgr->Initialize(); sScriptMgr->OnConfigLoad(false); // must be done after the ScriptMgr has been properly initialized