/* * This file is part of the TrinityCore 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 "PlayerTaxi.h" #include "DB2Stores.h" #include "ObjectMgr.h" #include "Player.h" #include "StringConvert.h" #include "TaxiPackets.h" #include PlayerTaxi::PlayerTaxi() = default; PlayerTaxi::PlayerTaxi(PlayerTaxi const& other) = default; PlayerTaxi::PlayerTaxi(PlayerTaxi&& other) noexcept = default; PlayerTaxi& PlayerTaxi::operator=(PlayerTaxi const& other) = default; PlayerTaxi& PlayerTaxi::operator=(PlayerTaxi&& other) noexcept = default; PlayerTaxi::~PlayerTaxi() = default; void PlayerTaxi::InitTaxiNodesForLevel(uint32 race, uint32 chrClass, uint8 level) { // class specific initial known nodes TaxiMask const& factionMask = Player::TeamForRace(race) == HORDE ? sHordeTaxiNodesMask : sAllianceTaxiNodesMask; switch (chrClass) { case CLASS_DEATH_KNIGHT: { for (std::size_t i = 0; i < m_taximask.size(); ++i) m_taximask[i] |= sOldContinentsNodesMask[i] & factionMask[i]; break; } } // race specific initial known nodes: capital and taxi hub masks switch (race) { case RACE_HUMAN: case RACE_DWARF: case RACE_NIGHTELF: case RACE_GNOME: case RACE_DRAENEI: case RACE_WORGEN: case RACE_PANDAREN_ALLIANCE: SetTaximaskNode(2); // Stormwind, Elwynn SetTaximaskNode(6); // Ironforge, Dun Morogh SetTaximaskNode(26); // Lor'danel, Darkshore SetTaximaskNode(27); // Rut'theran Village, Teldrassil SetTaximaskNode(49); // Moonglade (Alliance) SetTaximaskNode(94); // The Exodar SetTaximaskNode(456); // Dolanaar, Teldrassil SetTaximaskNode(457); // Darnassus, Teldrassil SetTaximaskNode(582); // Goldshire, Elwynn SetTaximaskNode(589); // Eastvale Logging Camp, Elwynn SetTaximaskNode(619); // Kharanos, Dun Morogh SetTaximaskNode(620); // Gol'Bolar Quarry, Dun Morogh SetTaximaskNode(624); // Azure Watch, Azuremyst Isle break; case RACE_ORC: case RACE_UNDEAD_PLAYER: case RACE_TAUREN: case RACE_TROLL: case RACE_BLOODELF: case RACE_GOBLIN: case RACE_PANDAREN_HORDE: SetTaximaskNode(11); // Undercity, Tirisfal SetTaximaskNode(22); // Thunder Bluff, Mulgore SetTaximaskNode(23); // Orgrimmar, Durotar SetTaximaskNode(69); // Moonglade (Horde) SetTaximaskNode(82); // Silvermoon City SetTaximaskNode(384); // The Bulwark, Tirisfal SetTaximaskNode(402); // Bloodhoof Village, Mulgore SetTaximaskNode(460); // Brill, Tirisfal Glades SetTaximaskNode(536); // Sen'jin Village, Durotar SetTaximaskNode(537); // Razor Hill, Durotar SetTaximaskNode(625); // Fairbreeze Village, Eversong Woods SetTaximaskNode(631); // Falconwing Square, Eversong Woods break; } // new continent starting masks (It will be accessible only at new map) switch (Player::TeamForRace(race)) { case ALLIANCE: SetTaximaskNode(100); break; case HORDE: SetTaximaskNode(99); break; default: break; } // level dependent taxi hubs if (level >= 68) SetTaximaskNode(213); //Shattered Sun Staging Area } bool PlayerTaxi::LoadTaxiMask(std::string const& data) { bool warn = false; std::vector tokens = Trinity::Tokenize(data, ' ', false); for (size_t index = 0; (index < m_taximask.size()) && (index < tokens.size()); ++index) { if (Optional mask = Trinity::StringTo(tokens[index])) { // load and set bits only for existing taxi nodes m_taximask[index] = sTaxiNodesMask[index] & *mask; if (m_taximask[index] != *mask) warn = true; } else { m_taximask[index] = 0; warn = true; } } return !warn; } void PlayerTaxi::AppendTaximaskTo(WorldPackets::Taxi::ShowTaxiNodes& data, bool all) { if (all) { data.CanLandNodes = sTaxiNodesMask; // all existed nodes data.CanUseNodes = sTaxiNodesMask; } else { data.CanLandNodes = m_taximask; // known nodes data.CanUseNodes = m_taximask; } } bool PlayerTaxi::LoadTaxiDestinationsFromString(const std::string& values, uint32 team) { ClearTaxiDestinations(); std::vector tokens = Trinity::Tokenize(values, ' ', false); auto itr = tokens.begin(); if (itr != tokens.end()) { if (Optional faction = Trinity::StringTo(*itr)) m_flightMasterFactionId = *faction; else return false; } else return false; while ((++itr) != tokens.end()) { if (Optional node = Trinity::StringTo(*itr)) AddTaxiDestination(*node); else return false; } if (m_TaxiDestinations.empty()) return true; // Check integrity if (m_TaxiDestinations.size() < 2) return false; for (size_t i = 1; i < m_TaxiDestinations.size(); ++i) { uint32 cost; uint32 path; sObjectMgr->GetTaxiPath(m_TaxiDestinations[i - 1], m_TaxiDestinations[i], path, cost); if (!path) return false; } // can't load taxi path without mount set (quest taxi path?) if (!sObjectMgr->GetTaxiMountDisplayId(GetTaxiSource(), team, true)) return false; return true; } std::string PlayerTaxi::SaveTaxiDestinationsToString() { if (m_TaxiDestinations.empty()) return ""; ASSERT(m_TaxiDestinations.size() >= 2); std::ostringstream ss; ss << m_flightMasterFactionId << ' '; for (size_t i = 0; i < m_TaxiDestinations.size(); ++i) ss << m_TaxiDestinations[i] << ' '; return ss.str(); } void PlayerTaxi::AddTaxiDestination(uint32 dest) { m_TaxiDestinations.push_back(dest); } uint32 PlayerTaxi::GetCurrentTaxiPath() const { if (m_TaxiDestinations.size() < 2) return 0; uint32 path; uint32 cost; sObjectMgr->GetTaxiPath(m_TaxiDestinations[0], m_TaxiDestinations[1], path, cost); return path; } std::ostringstream& operator<<(std::ostringstream& ss, PlayerTaxi const& taxi) { for (std::size_t i = 0; i < taxi.m_taximask.size(); ++i) ss << uint32(taxi.m_taximask[i]) << ' '; return ss; } bool PlayerTaxi::RequestEarlyLanding() { if (m_TaxiDestinations.size() <= 2) return false; // start from first destination - m_TaxiDestinations[0] is the current starting node for (std::deque::iterator it = ++m_TaxiDestinations.begin(); it != m_TaxiDestinations.end(); ++it) { if (IsTaximaskNodeKnown(*it)) { if (++it == m_TaxiDestinations.end()) return false; // if we are left with only 1 known node on the path don't change the spline, its our final destination anyway m_TaxiDestinations.erase(it, m_TaxiDestinations.end()); return true; } } return false; } FactionTemplateEntry const* PlayerTaxi::GetFlightMasterFactionTemplate() const { return sFactionTemplateStore.LookupEntry(m_flightMasterFactionId); }