diff options
Diffstat (limited to 'src')
57 files changed, 784 insertions, 650 deletions
diff --git a/src/common/Collision/Management/MMapManager.cpp b/src/common/Collision/Management/MMapManager.cpp index a5685c65d9c..00985e4fa1d 100644 --- a/src/common/Collision/Management/MMapManager.cpp +++ b/src/common/Collision/Management/MMapManager.cpp @@ -230,7 +230,7 @@ namespace MMAP // if the grid is later reloaded, dtNavMesh::addTile will return error but no extra memory is used // we cannot recover from this error - assert out TC_LOG_ERROR("maps", "MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId, x, y); - ASSERT(false); + ABORT(); } else { diff --git a/src/common/Common.h b/src/common/Common.h index 09d64acc795..4c209f89ec8 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -39,6 +39,7 @@ #include <sstream> #include <algorithm> #include <memory> +#include <vector> #include "Debugging/Errors.h" diff --git a/src/common/Debugging/Errors.cpp b/src/common/Debugging/Errors.cpp index cebd9d4cf2f..f2da96b86bf 100644 --- a/src/common/Debugging/Errors.cpp +++ b/src/common/Debugging/Errors.cpp @@ -29,8 +29,7 @@ void Assert(char const* file, int line, char const* function, char const* messag { fprintf(stderr, "\n%s:%i in %s ASSERTION FAILED:\n %s\n", file, line, function, message); - *((volatile int*)NULL) = 0; - exit(1); + abort(); } void Assert(char const* file, int line, char const* function, char const* message, char const* format, ...) @@ -44,8 +43,7 @@ void Assert(char const* file, int line, char const* function, char const* messag fflush(stderr); va_end(args); - *((volatile int*)NULL) = 0; - exit(1); + abort(); } void Fatal(char const* file, int line, char const* function, char const* message) @@ -54,16 +52,14 @@ void Fatal(char const* file, int line, char const* function, char const* message file, line, function, message); std::this_thread::sleep_for(std::chrono::seconds(10)); - *((volatile int*)NULL) = 0; - exit(1); + abort(); } void Error(char const* file, int line, char const* function, char const* message) { fprintf(stderr, "\n%s:%i in %s ERROR:\n %s\n", file, line, function, message); - *((volatile int*)NULL) = 0; - exit(1); + abort(); } void Warning(char const* file, int line, char const* function, char const* message) @@ -72,4 +68,11 @@ void Warning(char const* file, int line, char const* function, char const* messa file, line, function, message); } +void Abort(char const* file, int line, char const* function) +{ + fprintf(stderr, "\n%s:%i in %s ABORTED\n", + file, line, function); + abort(); +} + } // namespace Trinity diff --git a/src/common/Debugging/Errors.h b/src/common/Debugging/Errors.h index 4d4624b63dd..edf56b29136 100644 --- a/src/common/Debugging/Errors.h +++ b/src/common/Debugging/Errors.h @@ -29,6 +29,8 @@ namespace Trinity DECLSPEC_NORETURN void Fatal(char const* file, int line, char const* function, char const* message) ATTR_NORETURN; DECLSPEC_NORETURN void Error(char const* file, int line, char const* function, char const* message) ATTR_NORETURN; + + DECLSPEC_NORETURN void Abort(char const* file, int line, char const* function) ATTR_NORETURN; void Warning(char const* file, int line, char const* function, char const* message); @@ -46,8 +48,10 @@ namespace Trinity #define WPFatal(cond, msg) ASSERT_BEGIN do { if (!(cond)) Trinity::Fatal(__FILE__, __LINE__, __FUNCTION__, (msg)); } while(0) ASSERT_END #define WPError(cond, msg) ASSERT_BEGIN do { if (!(cond)) Trinity::Error(__FILE__, __LINE__, __FUNCTION__, (msg)); } while(0) ASSERT_END #define WPWarning(cond, msg) ASSERT_BEGIN do { if (!(cond)) Trinity::Warning(__FILE__, __LINE__, __FUNCTION__, (msg)); } while(0) ASSERT_END +#define WPAbort() ASSERT_BEGIN do { Trinity::Abort(__FILE__, __LINE__, __FUNCTION__); } while(0) ASSERT_END #define ASSERT WPAssert +#define ABORT WPAbort template <typename T> inline T* ASSERT_NOTNULL(T* pointer) { diff --git a/src/common/Utilities/Util.h b/src/common/Utilities/Util.h index 3da1c800410..6a872b44a60 100644 --- a/src/common/Utilities/Util.h +++ b/src/common/Utilities/Util.h @@ -537,7 +537,7 @@ bool CompareValues(ComparisionType type, T val1, T val2) return val1 <= val2; default: // incorrect parameter - ASSERT(false); + ABORT(); return false; } } diff --git a/src/server/authserver/Realms/RealmList.cpp b/src/server/authserver/Realms/RealmList.cpp index 59cb2392063..f5461d5f42e 100644 --- a/src/server/authserver/Realms/RealmList.cpp +++ b/src/server/authserver/Realms/RealmList.cpp @@ -145,7 +145,7 @@ void RealmList::UpdateRealms(bool init) catch (std::exception& ex) { TC_LOG_ERROR("server.authserver", "Realmlist::UpdateRealms has thrown an exception: %s", ex.what()); - ASSERT(false); + ABORT(); } } while (result->NextRow()); diff --git a/src/server/authserver/authserver.conf.dist b/src/server/authserver/authserver.conf.dist index ba9cb5b23b4..437ec221e94 100644 --- a/src/server/authserver/authserver.conf.dist +++ b/src/server/authserver/authserver.conf.dist @@ -182,7 +182,7 @@ Updates.EnableDatabases = 0 Updates.SourcePath = "" # -# Updates.SourcePath +# Updates.MySqlCLIPath # Description: The path to your mysql cli binary. # If the path is left empty, built-in path from cmake is used. # Example: "C:/Program Files/MySQL/MySQL Server 5.6/bin/mysql.exe" diff --git a/src/server/database/Database/DatabaseWorkerPool.h b/src/server/database/Database/DatabaseWorkerPool.h index f5002c6943b..6a0cf71cca6 100644 --- a/src/server/database/Database/DatabaseWorkerPool.h +++ b/src/server/database/Database/DatabaseWorkerPool.h @@ -482,7 +482,7 @@ class DatabaseWorkerPool else if (type == IDX_SYNCH) t = new T(*_connectionInfo); else - ASSERT(false); + ABORT(); _connections[type][i] = t; ++_connectionCount[type]; diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 9fa2269fd8b..dadffe735d2 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -123,13 +123,18 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u ObjectList* targets = GetTargets(e, unit); Creature* talker = me; Player* targetPlayer = NULL; + Unit* talkTarget = NULL; + if (targets) { for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { if (IsCreature(*itr) && !(*itr)->ToCreature()->IsPet()) // Prevented sending text to pets. { - talker = (*itr)->ToCreature(); + if (e.action.talk.useTalkTarget) + talkTarget = (*itr)->ToCreature(); + else + talker = (*itr)->ToCreature(); break; } else if (IsPlayer(*itr)) @@ -148,7 +153,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u mTalkerEntry = talker->GetEntry(); mLastTextID = e.action.talk.textGroupID; mTextTimer = e.action.talk.duration; - Unit* talkTarget = NULL; + if (IsPlayer(GetLastInvoker())) // used for $vars in texts and whisper target talkTarget = GetLastInvoker(); else if (targetPlayer) diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index 8565c5d3497..60a4ce5e8ed 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -426,7 +426,7 @@ enum SMART_SCRIPT_RESPAWN_CONDITION enum SMART_ACTION { SMART_ACTION_NONE = 0, // No action - SMART_ACTION_TALK = 1, // groupID from creature_text, duration to wait before TEXT_OVER event is triggered + SMART_ACTION_TALK = 1, // groupID from creature_text, duration to wait before TEXT_OVER event is triggered, useTalkTarget (0/1) - use target as talk target SMART_ACTION_SET_FACTION = 2, // FactionId (or 0 for default) SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL = 3, // Creature_template entry(param1) OR ModelId (param2) (or 0 for both to demorph) SMART_ACTION_SOUND = 4, // SoundId, onlySelf @@ -553,6 +553,7 @@ struct SmartAction { uint32 textGroupID; uint32 duration; + uint32 useTalkTarget; } talk; struct diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp index 00b6862369d..26b7f672cfa 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp @@ -309,7 +309,7 @@ int32 BattlegroundAB::_GetNodeNameId(uint8 node) case BG_AB_NODE_LUMBER_MILL:return LANG_BG_AB_NODE_LUMBER_MILL; case BG_AB_NODE_GOLD_MINE: return LANG_BG_AB_NODE_GOLD_MINE; default: - ASSERT(false); + ABORT(); } return 0; } diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp index 9c654a1793c..d4e51315e92 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp @@ -789,7 +789,7 @@ BG_AV_Nodes BattlegroundAV::GetNodeThroughObject(uint32 object) if (object == BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE) return BG_AV_NODES_SNOWFALL_GRAVE; TC_LOG_ERROR("bg.battleground", "BattlegroundAV: ERROR! GetPlace got a wrong object :("); - ASSERT(false); + ABORT(); return BG_AV_Nodes(0); } @@ -827,7 +827,7 @@ uint32 BattlegroundAV::GetObjectThroughNode(BG_AV_Nodes node) else if (m_Nodes[node].Owner == AV_NEUTRAL_TEAM) return BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE; TC_LOG_ERROR("bg.battleground", "BattlegroundAV: Error! GetPlaceNode couldn't resolve node %i", node); - ASSERT(false); + ABORT(); return 0; } @@ -1402,22 +1402,22 @@ void BattlegroundAV::AssaultNode(BG_AV_Nodes node, uint16 team) if (m_Nodes[node].TotalOwner == team) { TC_LOG_FATAL("bg.battleground", "Assaulting team is TotalOwner of node"); - ASSERT(false); + ABORT(); } if (m_Nodes[node].Owner == team) { TC_LOG_FATAL("bg.battleground", "Assaulting team is owner of node"); - ASSERT(false); + ABORT(); } if (m_Nodes[node].State == POINT_DESTROYED) { TC_LOG_FATAL("bg.battleground", "Destroyed node is being assaulted"); - ASSERT(false); + ABORT(); } if (m_Nodes[node].State == POINT_ASSAULTED && m_Nodes[node].TotalOwner) //only assault an assaulted node if no totalowner exists { TC_LOG_FATAL("bg.battleground", "Assault on an not assaulted node with total owner"); - ASSERT(false); + ABORT(); } //the timer gets another time, if the previous owner was 0 == Neutral m_Nodes[node].Timer = (m_Nodes[node].PrevOwner)? BG_AV_CAPTIME : BG_AV_SNOWFALL_FIRSTCAP; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp index f267bf7c6c6..c7d8132053c 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp @@ -744,7 +744,7 @@ bool BattlegroundSA::CanInteractWithObject(uint32 objectId) return false; break; default: - ASSERT(false); + ABORT(); break; } @@ -877,7 +877,7 @@ void BattlegroundSA::CaptureGraveyard(BG_SA_Graveyards i, Player* Source) break; default: - ASSERT(false); + ABORT(); break; }; } diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index 5a74ad05b66..0d6816fc80d 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -186,13 +186,33 @@ bool ChatHandler::hasStringAbbr(const char* name, const char* part) return true; } -void ChatHandler::SendSysMessage(const char *str) +void ChatHandler::SendSysMessage(const char *str, bool escapeCharacters) { WorldPacket data; // need copy to prevent corruption by strtok call in LineFromMessage original string - char* buf = strdup(str); - char* pos = buf; + char* buf; + char* pos; + + if (escapeCharacters && strchr(str, '|')) + { + size_t startPos = 0; + std::ostringstream o; + while (const char* charPos = strchr(str + startPos, '|')) + { + o.write(str + startPos, charPos - str - startPos); + o << "||"; + startPos = charPos - str + 1; + } + o.write(str + startPos, strlen(str) - startPos); + buf = strdup(o.str().c_str()); + } + else + { + buf = strdup(str); + } + + pos = buf; while (char* line = LineFromMessage(pos)) { @@ -1223,7 +1243,7 @@ bool CliHandler::isAvailable(ChatCommand const& cmd) const return cmd.AllowConsole; } -void CliHandler::SendSysMessage(const char *str) +void CliHandler::SendSysMessage(const char *str, bool /*escapeCharacters*/) { m_print(m_callbackArg, str); m_print(m_callbackArg, "\r\n"); diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h index 1b095534ad0..72d80aba7e6 100644 --- a/src/server/game/Chat/Chat.h +++ b/src/server/game/Chat/Chat.h @@ -66,7 +66,7 @@ class ChatHandler // function with different implementation for chat/console virtual char const* GetTrinityString(uint32 entry) const; - virtual void SendSysMessage(char const* str); + virtual void SendSysMessage(char const* str, bool escapeCharacters = false); void SendSysMessage(uint32 entry); @@ -166,7 +166,7 @@ class CliHandler : public ChatHandler char const* GetTrinityString(uint32 entry) const override; bool isAvailable(ChatCommand const& cmd) const override; bool HasPermission(uint32 /*permission*/) const override { return true; } - void SendSysMessage(const char *str) override; + void SendSysMessage(const char *str, bool escapeCharacters) override; std::string GetNameLink() const override; bool needReportToTarget(Player* chr) const override; LocaleConstant GetSessionDbcLocale() const override; diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index d9061dfb106..e268b376b34 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -570,7 +570,7 @@ void LoadDBCStores(const std::string& dataPath) // fill data for (uint32 i = 1; i < sTaxiPathNodeStore.GetNumRows(); ++i) if (TaxiPathNodeEntry const* entry = sTaxiPathNodeStore.LookupEntry(i)) - sTaxiPathNodesByPath[entry->PathID].set(entry->NodeIndex, entry); + sTaxiPathNodesByPath[entry->PathID][entry->NodeIndex] = entry; // Initialize global taxinodes mask // include existed nodes that have at least single not spell base (scripted) path diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index c680494cd72..092ef714145 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -22,13 +22,8 @@ #include "Common.h" #include "DBCEnums.h" #include "Define.h" -#include "Path.h" #include "Util.h" -#include <map> -#include <set> -#include <vector> - // Structures using to access raw DBC data and required packing to portability #pragma pack(push, 1) @@ -2211,15 +2206,7 @@ struct TaxiPathBySourceAndDestination typedef std::map<uint32, TaxiPathBySourceAndDestination> TaxiPathSetForSource; typedef std::map<uint32, TaxiPathSetForSource> TaxiPathSetBySource; -struct TaxiPathNodePtr -{ - TaxiPathNodePtr() : i_ptr(NULL) { } - TaxiPathNodePtr(TaxiPathNodeEntry const* ptr) : i_ptr(ptr) { } - TaxiPathNodeEntry const* i_ptr; - operator TaxiPathNodeEntry const& () const { return *i_ptr; } -}; - -typedef Path<TaxiPathNodePtr, TaxiPathNodeEntry const> TaxiPathNodeList; +typedef std::vector<TaxiPathNodeEntry const*> TaxiPathNodeList; typedef std::vector<TaxiPathNodeList> TaxiPathNodesByPath; #define TaxiMaskSize 14 diff --git a/src/server/game/DungeonFinding/LFGQueue.cpp b/src/server/game/DungeonFinding/LFGQueue.cpp index d2140a96a46..86b010a9ace 100644 --- a/src/server/game/DungeonFinding/LFGQueue.cpp +++ b/src/server/game/DungeonFinding/LFGQueue.cpp @@ -72,7 +72,7 @@ char const* GetCompatibleString(LfgCompatibility compatibles) case LFG_INCOMPATIBLES_NO_ROLES: return "Incompatible roles"; case LFG_INCOMPATIBLES_TOO_MUCH_PLAYERS: - return "Too much players"; + return "Too many players"; case LFG_INCOMPATIBLES_WRONG_GROUP_SIZE: return "Wrong group size"; default: @@ -80,7 +80,7 @@ char const* GetCompatibleString(LfgCompatibility compatibles) } } -std::string LFGQueue::GetDetailedMatchRoles(GuidList const& check) +std::string LFGQueue::GetDetailedMatchRoles(GuidList const& check) const { if (check.empty()) return ""; @@ -92,31 +92,25 @@ std::string LFGQueue::GetDetailedMatchRoles(GuidList const& check) GuidSet::const_iterator it = guids.begin(); o << it->GetRawValue(); - LfgQueueDataContainer::iterator itQueue = QueueDataStore.find(*it); - if (itQueue == QueueDataStore.end()) - { - TC_LOG_ERROR("lfg.queue.data.details", "Queue data not found for [%s]", it->ToString().c_str()); - o << ' ' << GetRolesString(PLAYER_ROLE_NONE); - } - else + LfgQueueDataContainer::const_iterator itQueue = QueueDataStore.find(*it); + if (itQueue != QueueDataStore.end()) { // skip leader flag, log only dps/tank/healer - o << ' ' << GetRolesString(itQueue->second.roles[*it] & uint8(~PLAYER_ROLE_LEADER)); + auto role = itQueue->second.roles.find(*it); + if (role != itQueue->second.roles.end()) + o << ' ' << GetRolesString(itQueue->second.roles.at(*it) & uint8(~PLAYER_ROLE_LEADER)); } for (++it; it != guids.end(); ++it) { o << '|' << it->GetRawValue(); itQueue = QueueDataStore.find(*it); - if (itQueue == QueueDataStore.end()) - { - TC_LOG_ERROR("lfg.queue.data.details", "Queue data not found for [%s]", it->ToString().c_str()); - o << ' ' << GetRolesString(PLAYER_ROLE_NONE); - } - else + if (itQueue != QueueDataStore.end()) { // skip leader flag, log only dps/tank/healer - o << ' ' << GetRolesString(itQueue->second.roles[*it] & uint8(~PLAYER_ROLE_LEADER)); + auto role = itQueue->second.roles.find(*it); + if (role != itQueue->second.roles.end()) + o << ' ' << GetRolesString(itQueue->second.roles.at(*it) & uint8(~PLAYER_ROLE_LEADER)); } } @@ -438,7 +432,7 @@ LfgCompatibility LFGQueue::CheckCompatibility(GuidList check) if (numPlayers > MAXGROUPSIZE) { - TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) Too much players (%u)", GetDetailedMatchRoles(check).c_str(), numPlayers); + TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) Too many players (%u)", GetDetailedMatchRoles(check).c_str(), numPlayers); SetCompatibles(strGuids, LFG_INCOMPATIBLES_TOO_MUCH_PLAYERS); return LFG_INCOMPATIBLES_TOO_MUCH_PLAYERS; } @@ -666,7 +660,23 @@ std::string LFGQueue::DumpCompatibleInfo(bool full /* = false */) const o << "Compatible Map size: " << CompatibleMapStore.size() << "\n"; if (full) for (LfgCompatibleContainer::const_iterator itr = CompatibleMapStore.begin(); itr != CompatibleMapStore.end(); ++itr) - o << "(" << itr->first << "): " << GetCompatibleString(itr->second.compatibility) << "\n"; + { + o << "(" << itr->first << "): " << GetCompatibleString(itr->second.compatibility); + if (!itr->second.roles.empty()) + { + o << " ("; + bool first = true; + for (const auto& role : itr->second.roles) + { + if (!first) + o << "|"; + o << role.first.GetRawValue() << " " << GetRolesString(role.second & uint8(~PLAYER_ROLE_LEADER)); + first = false; + } + o << ")"; + } + o << "\n"; + } return o.str(); } diff --git a/src/server/game/DungeonFinding/LFGQueue.h b/src/server/game/DungeonFinding/LFGQueue.h index 77683614d49..f72e9b4fd6d 100644 --- a/src/server/game/DungeonFinding/LFGQueue.h +++ b/src/server/game/DungeonFinding/LFGQueue.h @@ -88,7 +88,7 @@ class LFGQueue public: // Add/Remove from queue - std::string GetDetailedMatchRoles(GuidList const& check); + std::string GetDetailedMatchRoles(GuidList const& check) const; void AddToQueue(ObjectGuid guid); void RemoveFromQueue(ObjectGuid guid); void AddQueueData(ObjectGuid guid, time_t joinTime, LfgDungeonSet const& dungeons, LfgRolesMap const& rolesMap); diff --git a/src/server/game/Entities/Creature/CreatureGroups.cpp b/src/server/game/Entities/Creature/CreatureGroups.cpp index 2ccf4471788..505d41f63e7 100644 --- a/src/server/game/Entities/Creature/CreatureGroups.cpp +++ b/src/server/game/Entities/Creature/CreatureGroups.cpp @@ -228,10 +228,11 @@ void CreatureGroup::LeaderMoveTo(float x, float y, float z) if (itr->second->point_1) { - if (m_leader->GetCurrentWaypointID() == itr->second->point_1) + if (m_leader->GetCurrentWaypointID() == itr->second->point_1 - 1) itr->second->follow_angle = (2 * float(M_PI)) - itr->second->follow_angle; - if (m_leader->GetCurrentWaypointID() == itr->second->point_2) - itr->second->follow_angle = (2 * float(M_PI)) + itr->second->follow_angle; + + if (m_leader->GetCurrentWaypointID() == itr->second->point_2 - 1) + itr->second->follow_angle = (float(M_PI)) + itr->second->follow_angle; } float angle = itr->second->follow_angle; diff --git a/src/server/game/Entities/Creature/GossipDef.cpp b/src/server/game/Entities/Creature/GossipDef.cpp index 63be8d06739..db67f1f74f1 100644 --- a/src/server/game/Entities/Creature/GossipDef.cpp +++ b/src/server/game/Entities/Creature/GossipDef.cpp @@ -381,10 +381,10 @@ void PlayerMenu::SendQuestGiverStatus(uint8 questStatus, ObjectGuid npcGUID) con void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, ObjectGuid npcGUID, bool activateAccept) const { - std::string questTitle = quest->GetTitle(); - std::string questDetails = quest->GetDetails(); - std::string questObjectives = quest->GetObjectives(); - std::string questEndText = quest->GetEndText(); + std::string questTitle = quest->GetTitle(); + std::string questDetails = quest->GetDetails(); + std::string questObjectives = quest->GetObjectives(); + std::string questAreaDescription = quest->GetAreaDescription(); int32 locale = _session->GetSessionDbLocaleIndex(); if (locale >= 0) @@ -394,7 +394,7 @@ void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, ObjectGuid npcGU ObjectMgr::GetLocaleString(localeData->Title, locale, questTitle); ObjectMgr::GetLocaleString(localeData->Details, locale, questDetails); ObjectMgr::GetLocaleString(localeData->Objectives, locale, questObjectives); - ObjectMgr::GetLocaleString(localeData->EndText, locale, questEndText); + ObjectMgr::GetLocaleString(localeData->AreaDescription, locale, questAreaDescription); } } @@ -489,11 +489,11 @@ void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, ObjectGuid npcGU void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const { - std::string questTitle = quest->GetTitle(); - std::string questDetails = quest->GetDetails(); - std::string questObjectives = quest->GetObjectives(); - std::string questEndText = quest->GetEndText(); - std::string questCompletedText = quest->GetCompletedText(); + std::string questTitle = quest->GetTitle(); + std::string questDetails = quest->GetDetails(); + std::string questObjectives = quest->GetObjectives(); + std::string questAreaDescription = quest->GetAreaDescription(); + std::string questCompletedText = quest->GetCompletedText(); std::string questObjectiveText[QUEST_OBJECTIVES_COUNT]; for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) @@ -507,7 +507,7 @@ void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const ObjectMgr::GetLocaleString(localeData->Title, locale, questTitle); ObjectMgr::GetLocaleString(localeData->Details, locale, questDetails); ObjectMgr::GetLocaleString(localeData->Objectives, locale, questObjectives); - ObjectMgr::GetLocaleString(localeData->EndText, locale, questEndText); + ObjectMgr::GetLocaleString(localeData->AreaDescription, locale, questAreaDescription); ObjectMgr::GetLocaleString(localeData->CompletedText, locale, questCompletedText); for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) @@ -585,9 +585,9 @@ void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // unk (0) data << int32(quest->RewardFactionValueIdOverride[i]); - data << uint32(quest->GetPointMapId()); - data << float(quest->GetPointX()); - data << float(quest->GetPointY()); + data << uint32(quest->GetPOIContinent()); + data << float(quest->GetPOIx()); + data << float(quest->GetPOIy()); data << uint32(quest->GetPointOpt()); if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS)) @@ -596,7 +596,7 @@ void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const data << questTitle; data << questObjectives; data << questDetails; - data << questEndText; + data << questAreaDescription; data << questCompletedText; // display in quest objectives window once all objectives are completed for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) @@ -607,7 +607,7 @@ void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const data << uint32(quest->RequiredNpcOrGo[i]); data << uint32(quest->RequiredNpcOrGoCount[i]); - data << uint32(quest->RequiredSourceItemId[i]); + data << uint32(quest->ItemDrop[i]); data << uint32(0); // req source count? } diff --git a/src/server/game/Entities/Creature/TemporarySummon.cpp b/src/server/game/Entities/Creature/TemporarySummon.cpp index 2a3e91b7574..46422444bbb 100644 --- a/src/server/game/Entities/Creature/TemporarySummon.cpp +++ b/src/server/game/Entities/Creature/TemporarySummon.cpp @@ -368,7 +368,7 @@ void Puppet::InitSummon() { Minion::InitSummon(); if (!SetCharmedBy(GetOwner(), CHARM_TYPE_POSSESS)) - ASSERT(false); + ABORT(); } void Puppet::Update(uint32 time) diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index 7ef8ef2737d..e12bec768fb 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -680,7 +680,7 @@ class GameObject : public WorldObject, public GridObject<GameObject>, public Map // Owner already found and different than expected owner - remove object from old owner if (owner && GetOwnerGUID() && GetOwnerGUID() != owner) { - ASSERT(false); + ABORT(); } m_spawnedByDefault = false; // all object with owner is despawned after delay SetGuidValue(OBJECT_FIELD_CREATED_BY, owner); diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 141bac5e50f..4f91423d769 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -1070,7 +1070,7 @@ Item* Item::CreateItem(uint32 itemEntry, uint32 count, Player const* player) delete item; } else - ASSERT(false); + ABORT(); return NULL; } diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index fc55c09bffa..6087e03b1bb 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -67,7 +67,7 @@ WorldObject::~WorldObject() { TC_LOG_FATAL("misc", "WorldObject::~WorldObject Corpse Type: %d (%s) deleted but still in map!!", ToCorpse()->GetType(), GetGUID().ToString().c_str()); - ASSERT(false); + ABORT(); } ResetMap(); } @@ -80,14 +80,14 @@ Object::~Object() TC_LOG_FATAL("misc", "Object::~Object %s deleted but still in world!!", GetGUID().ToString().c_str()); if (isType(TYPEMASK_ITEM)) TC_LOG_FATAL("misc", "Item slot %u", ((Item*)this)->GetSlot()); - ASSERT(false); + ABORT(); RemoveFromWorld(); } if (m_objectUpdated) { TC_LOG_FATAL("misc", "Object::~Object %s deleted but still in update list!!", GetGUID().ToString().c_str()); - ASSERT(false); + ABORT(); sObjectAccessor->RemoveUpdateObject(this); } @@ -1795,7 +1795,7 @@ void WorldObject::SetMap(Map* map) if (m_currMap) { TC_LOG_FATAL("misc", "WorldObject::SetMap: obj %u new map %u %u, old map %u %u", (uint32)GetTypeId(), map->GetId(), map->GetInstanceId(), m_currMap->GetId(), m_currMap->GetInstanceId()); - ASSERT(false); + ABORT(); } m_currMap = map; m_mapId = map->GetId(); diff --git a/src/server/game/Entities/Pet/Pet.h b/src/server/game/Entities/Pet/Pet.h index b1d7fcaa28a..e47bf220195 100644 --- a/src/server/game/Entities/Pet/Pet.h +++ b/src/server/game/Entities/Pet/Pet.h @@ -159,11 +159,11 @@ class Pet : public Guardian private: void SaveToDB(uint32, uint8, uint32) override // override of Creature::SaveToDB - must not be called { - ASSERT(false); + ABORT(); } void DeleteFromDB() override // override of Creature::DeleteFromDB - must not be called { - ASSERT(false); + ABORT(); } }; #endif diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 88d7dfa6381..e4e07cfeb53 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -8335,9 +8335,6 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8 return; } - // use triggered flag only for items with many spell casts and for not first cast - uint8 count = 0; - // item spells cast at use for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) { @@ -8358,13 +8355,12 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8 continue; } - Spell* spell = new Spell(this, spellInfo, (count > 0) ? TRIGGERED_FULL_MASK : TRIGGERED_NONE); + Spell* spell = new Spell(this, spellInfo, TRIGGERED_NONE); spell->m_CastItem = item; spell->m_cast_count = cast_count; // set count of casts spell->m_glyphIndex = glyphIndex; // glyph index spell->prepare(&targets); - - ++count; + return; } // Item enchantments spells cast at use @@ -8386,13 +8382,12 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8 continue; } - Spell* spell = new Spell(this, spellInfo, (count > 0) ? TRIGGERED_FULL_MASK : TRIGGERED_NONE); + Spell* spell = new Spell(this, spellInfo, TRIGGERED_NONE); spell->m_CastItem = item; spell->m_cast_count = cast_count; // set count of casts spell->m_glyphIndex = glyphIndex; // glyph index spell->prepare(&targets); - - ++count; + return; } } } @@ -15065,15 +15060,15 @@ void Player::AddQuest(Quest const* quest, Object* questGiver) uint32 qtime = 0; if (quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_TIMED)) { - uint32 limittime = quest->GetLimitTime(); + uint32 timeAllowed = quest->GetTimeAllowed(); // shared timed quest if (questGiver && questGiver->GetTypeId() == TYPEID_PLAYER) - limittime = questGiver->ToPlayer()->getQuestStatusMap()[quest_id].Timer / IN_MILLISECONDS; + timeAllowed = questGiver->ToPlayer()->getQuestStatusMap()[quest_id].Timer / IN_MILLISECONDS; AddTimedQuest(quest_id); - questStatusData.Timer = limittime * IN_MILLISECONDS; - qtime = static_cast<uint32>(time(NULL)) + limittime; + questStatusData.Timer = timeAllowed * IN_MILLISECONDS; + qtime = static_cast<uint32>(time(NULL)) + timeAllowed; } else questStatusData.Timer = 0; @@ -15163,10 +15158,10 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, for (uint8 i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i) { - if (quest->RequiredSourceItemId[i]) + if (quest->ItemDrop[i]) { - uint32 count = quest->RequiredSourceItemCount[i]; - DestroyItemCount(quest->RequiredSourceItemId[i], count ? count : 9999, true); + uint32 count = quest->ItemDropQuantity[i]; + DestroyItemCount(quest->ItemDrop[i], count ? count : 9999, true); } } @@ -15373,9 +15368,9 @@ void Player::FailQuest(uint32 questId) // Destroy items received on starting the quest. DestroyItemCount(quest->RequiredItemId[i], quest->RequiredItemCount[i], true, true); for (uint8 i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i) - if (quest->RequiredSourceItemId[i] > 0 && quest->RequiredSourceItemCount[i] > 0) + if (quest->ItemDrop[i] > 0 && quest->ItemDropQuantity[i] > 0) // Destroy items received during the quest. - DestroyItemCount(quest->RequiredSourceItemId[i], quest->RequiredSourceItemCount[i], true, true); + DestroyItemCount(quest->ItemDrop[i], quest->ItemDropQuantity[i], true, true); } } @@ -15557,7 +15552,7 @@ bool Player::SatisfyQuestClass(Quest const* qInfo, bool msg) const bool Player::SatisfyQuestRace(Quest const* qInfo, bool msg) { - uint32 reqraces = qInfo->GetRequiredRaces(); + uint32 reqraces = qInfo->GetAllowableRaces(); if (reqraces == 0) return true; if ((reqraces & getRaceMask()) == 0) @@ -16678,7 +16673,7 @@ bool Player::HasQuestForItem(uint32 itemid) const for (uint8 j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; ++j) { // examined item is a source item - if (qinfo->RequiredSourceItemId[j] == itemid) + if (qinfo->ItemDrop[j] == itemid) { ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(itemid); @@ -16687,9 +16682,9 @@ bool Player::HasQuestForItem(uint32 itemid) const return true; // allows custom amount drop when not 0 - if (qinfo->RequiredSourceItemCount[j]) + if (qinfo->ItemDropQuantity[j]) { - if (GetItemCount(itemid, true) < qinfo->RequiredSourceItemCount[j]) + if (GetItemCount(itemid, true) < qinfo->ItemDropQuantity[j]) return true; } else if (GetItemCount(itemid, true) < pProto->GetMaxStackSize()) return true; @@ -20445,7 +20440,7 @@ void Player::StopCastingCharm() if (charm->GetCharmerGUID()) { TC_LOG_FATAL("entities.player", "Charmed unit has charmer %s", charm->GetCharmerGUID().ToString().c_str()); - ASSERT(false); + ABORT(); } else SetCharm(charm, false); @@ -21163,6 +21158,7 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc // fill destinations path tail uint32 sourcepath = 0; uint32 totalcost = 0; + uint32 firstcost = 0; uint32 prevnode = sourcenode; uint32 lastnode = 0; @@ -21181,6 +21177,8 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc } totalcost += cost; + if (i == 1) + firstcost = cost; if (prevnode == sourcenode) sourcepath = path; @@ -21219,8 +21217,6 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc } //Checks and preparations done, DO FLIGHT - ModifyMoney(-(int32)totalcost); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, totalcost); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN, 1); // prevent stealth flight @@ -21231,11 +21227,15 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc TaxiNodesEntry const* lastPathNode = sTaxiNodesStore.LookupEntry(nodes[nodes.size()-1]); ASSERT(lastPathNode); m_taxi.ClearTaxiDestinations(); + ModifyMoney(-(int32)totalcost); + UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, totalcost); TeleportTo(lastPathNode->map_id, lastPathNode->x, lastPathNode->y, lastPathNode->z, GetOrientation()); return false; } else { + ModifyMoney(-(int32)firstcost); + UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, firstcost); GetSession()->SendActivateTaxiReply(ERR_TAXIOK); GetSession()->SendDoFlight(mount_display_id, sourcepath); } @@ -21286,30 +21286,30 @@ void Player::ContinueTaxiFlight() float distPrev = MAP_SIZE*MAP_SIZE; float distNext = - (nodeList[0].LocX-GetPositionX())*(nodeList[0].LocX-GetPositionX())+ - (nodeList[0].LocY-GetPositionY())*(nodeList[0].LocY-GetPositionY())+ - (nodeList[0].LocZ-GetPositionZ())*(nodeList[0].LocZ-GetPositionZ()); + (nodeList[0]->LocX - GetPositionX())*(nodeList[0]->LocX - GetPositionX()) + + (nodeList[0]->LocY - GetPositionY())*(nodeList[0]->LocY - GetPositionY()) + + (nodeList[0]->LocZ - GetPositionZ())*(nodeList[0]->LocZ - GetPositionZ()); for (uint32 i = 1; i < nodeList.size(); ++i) { - TaxiPathNodeEntry const& node = nodeList[i]; - TaxiPathNodeEntry const& prevNode = nodeList[i-1]; + TaxiPathNodeEntry const* node = nodeList[i]; + TaxiPathNodeEntry const* prevNode = nodeList[i-1]; // skip nodes at another map - if (node.MapID != GetMapId()) + if (node->MapID != GetMapId()) continue; distPrev = distNext; distNext = - (node.LocX-GetPositionX())*(node.LocX-GetPositionX())+ - (node.LocY-GetPositionY())*(node.LocY-GetPositionY())+ - (node.LocZ-GetPositionZ())*(node.LocZ-GetPositionZ()); + (node->LocX - GetPositionX())*(node->LocX - GetPositionX()) + + (node->LocY - GetPositionY())*(node->LocY - GetPositionY()) + + (node->LocZ - GetPositionZ())*(node->LocZ - GetPositionZ()); float distNodes = - (node.LocX-prevNode.LocX)*(node.LocX-prevNode.LocX)+ - (node.LocY-prevNode.LocY)*(node.LocY-prevNode.LocY)+ - (node.LocZ-prevNode.LocZ)*(node.LocZ-prevNode.LocZ); + (node->LocX - prevNode->LocX)*(node->LocX - prevNode->LocX) + + (node->LocY - prevNode->LocY)*(node->LocY - prevNode->LocY) + + (node->LocZ - prevNode->LocZ)*(node->LocZ - prevNode->LocZ); if (distNext + distPrev < distNodes) { diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index a031840a1d8..94d0fa5697c 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -952,6 +952,8 @@ class PlayerTaxi m_TaxiDestinations.pop_front(); return GetTaxiDestination(); } + + std::deque<uint32> const& GetPath() const { return m_TaxiDestinations; } bool empty() const { return m_TaxiDestinations.empty(); } friend std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index d02a22d43f4..f8810c9d14f 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -3520,7 +3520,7 @@ void Unit::_UnapplyAura(AuraApplication * aurApp, AuraRemoveMode removeMode) else ++iter; } - ASSERT(false); + ABORT(); } void Unit::_RemoveNoStackAurasDueToAura(Aura* aura) @@ -3630,7 +3630,7 @@ void Unit::RemoveOwnedAura(Aura* aura, AuraRemoveMode removeMode) } } - ASSERT(false); + ABORT(); } Aura* Unit::GetOwnedAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint8 reqEffMask, Aura* except) const @@ -9450,7 +9450,7 @@ void Unit::SetMinion(Minion *minion, bool apply) { OutDebugInfo(); (*itr)->OutDebugInfo(); - ASSERT(false); + ABORT(); } ASSERT((*itr)->GetTypeId() == TYPEID_UNIT); @@ -13171,6 +13171,10 @@ bool Unit::IsInFeralForm() const bool Unit::IsInDisallowedMountForm() const { + if (SpellInfo const* transformSpellInfo = sSpellMgr->GetSpellInfo(getTransForm())) + if (transformSpellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_MOUNTED)) + return false; + if (ShapeshiftForm form = GetShapeshiftForm()) { SpellShapeshiftEntry const* shapeshift = sSpellShapeshiftStore.LookupEntry(form); @@ -13600,7 +13604,7 @@ void Unit::RemoveFromWorld() if (GetCharmerGUID()) { TC_LOG_FATAL("entities.unit", "Unit %u has charmer guid when removed from world", GetEntry()); - ASSERT(false); + ABORT(); } if (Unit* owner = GetOwner()) @@ -13608,7 +13612,7 @@ void Unit::RemoveFromWorld() if (owner->m_Controlled.find(this) != owner->m_Controlled.end()) { TC_LOG_FATAL("entities.unit", "Unit %u is in controlled list of %u when removed from world", GetEntry(), owner->GetEntry()); - ASSERT(false); + ABORT(); } } @@ -15976,7 +15980,7 @@ void Unit::RemoveCharmedBy(Unit* charmer) { // TC_LOG_FATAL("entities.unit", "Unit::RemoveCharmedBy: this: " UI64FMTD " true charmer: " UI64FMTD " false charmer: " UI64FMTD, // GetGUID(), GetCharmerGUID(), charmer->GetGUID()); -// ASSERT(false); +// ABORT(); return; } @@ -17273,7 +17277,7 @@ void Unit::SendChangeCurrentVictimOpcode(HostileReference* pHostileReference) for (ThreatContainer::StorageType::const_iterator itr = tlist.begin(); itr != tlist.end(); ++itr) { data << (*itr)->getUnitGuid().WriteAsPacked(); - data << uint32((*itr)->getThreat()); + data << uint32((*itr)->getThreat() * 100); } SendMessageToSet(&data, false); } diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index a568409d918..524bb442868 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -3966,31 +3966,31 @@ void ObjectMgr::LoadQuests() mExclusiveQuestGroups.clear(); QueryResult result = WorldDatabase.Query("SELECT " - //0 1 2 3 4 5 6 7 8 - "ID, Method, QuestLevel, MinLevel, QuestSortID, QuestType, SuggestedGroupNum, LimitTime, RequiredRaces," + //0 1 2 3 4 5 6 7 8 + "ID, QuestType, QuestLevel, MinLevel, QuestSortID, QuestInfoID, SuggestedGroupNum, TimeAllowed, AllowableRaces," // 9 10 11 12 "RequiredFactionId1, RequiredFactionId2, RequiredFactionValue1, RequiredFactionValue2, " - // 13 14 15 16 17 18 19 20 - "NextQuestIdChain, RewardXPId, RewardOrRequiredMoney, RewardMoneyMaxLevel, RewardSpell, RewardSpellCast, RewardHonor, RewardHonorMultiplier, " - // 21 22 23 24 25 26 - "SourceItemId, Flags, RewardTitle, RequiredPlayerKills, RewardTalents, RewardArenaPoints, " + // 13 14 15 16 17 18 19 20 + "RewardNextQuest, RewardXPDifficulty, RewardMoney, RewardBonusMoney, RewardDisplaySpell, RewardSpell, RewardHonor, RewardKillHonor, " + // 21 22 23 24 25 26 + "StartItem, Flags, RewardTitle, RequiredPlayerKills, RewardTalents, RewardArenaPoints, " // 27 28 29 30 31 32 33 34 "RewardItem1, RewardAmount1, RewardItem2, RewardAmount2, RewardItem3, RewardAmount3, RewardItem4, RewardAmount4, " // 35 36 37 38 39 40 41 42 43 44 45 46 "RewardChoiceItemID1, RewardChoiceItemQuantity1, RewardChoiceItemID2, RewardChoiceItemQuantity2, RewardChoiceItemID3, RewardChoiceItemQuantity3, RewardChoiceItemID4, RewardChoiceItemQuantity4, RewardChoiceItemID5, RewardChoiceItemQuantity5, RewardChoiceItemID6, RewardChoiceItemQuantity6, " // 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 "RewardFactionID1, RewardFactionValue1, RewardFactionOverride1, RewardFactionID2, RewardFactionValue2, RewardFactionOverride2, RewardFactionID3, RewardFactionValue3, RewardFactionOverride3, RewardFactionID4, RewardFactionValue4, RewardFactionOverride4, RewardFactionID5, RewardFactionValue5, RewardFactionOverride5," - // 62 63 64 65 - "PointMapId, PointX, PointY, PointOption, " - // 66 67 68 69 70 - "LogTitle, LogDescription, QuestDescription, EndText, QuestCompletionLog, " + // 62 63 64 65 + "POIContinent, POIx, POIy, POIPriority, " + // 66 67 68 69 70 + "LogTitle, LogDescription, QuestDescription, AreaDescription, QuestCompletionLog, " // 71 72 73 74 75 76 77 78 "RequiredNpcOrGo1, RequiredNpcOrGo2, RequiredNpcOrGo3, RequiredNpcOrGo4, RequiredNpcOrGoCount1, RequiredNpcOrGoCount2, RequiredNpcOrGoCount3, RequiredNpcOrGoCount4, " - // 79 80 81 82 83 84 85 86 - "RequiredSourceItemId1, RequiredSourceItemId2, RequiredSourceItemId3, RequiredSourceItemId4, RequiredSourceItemCount1, RequiredSourceItemCount2, RequiredSourceItemCount3, RequiredSourceItemCount4, " + // 79 80 81 82 83 84 85 86 + "ItemDrop1, ItemDrop2, ItemDrop3, ItemDrop4, ItemDropQuantity1, ItemDropQuantity2, ItemDropQuantity3, ItemDropQuantity4, " // 87 88 89 90 91 92 93 94 95 96 97 98 "RequiredItemId1, RequiredItemId2, RequiredItemId3, RequiredItemId4, RequiredItemId5, RequiredItemId6, RequiredItemCount1, RequiredItemCount2, RequiredItemCount3, RequiredItemCount4, RequiredItemCount5, RequiredItemCount6, " - // 99 100 101 102 103 + // 99 100 101 102 103 "Unknown0, ObjectiveText1, ObjectiveText2, ObjectiveText3, ObjectiveText4" " FROM quest_template"); if (!result) @@ -4011,7 +4011,7 @@ void ObjectMgr::LoadQuests() } while (result->NextRow()); std::map<uint32, uint32> usedMailTemplates; - + // Load `quest_details` // 0 1 2 3 4 5 6 7 8 result = WorldDatabase.Query("SELECT ID, Emote1, Emote2, Emote3, Emote4, EmoteDelay1, EmoteDelay2, EmoteDelay3, EmoteDelay4 FROM quest_details"); @@ -4215,13 +4215,13 @@ void ObjectMgr::LoadQuests() qinfo->RequiredClasses = 0; } } - // RequiredRaces, can be 0/RACEMASK_ALL_PLAYABLE to allow any race - if (qinfo->RequiredRaces) + // AllowableRaces, can be 0/RACEMASK_ALL_PLAYABLE to allow any race + if (qinfo->AllowableRaces) { - if (!(qinfo->RequiredRaces & RACEMASK_ALL_PLAYABLE)) + if (!(qinfo->AllowableRaces & RACEMASK_ALL_PLAYABLE)) { - TC_LOG_ERROR("sql.sql", "Quest %u does not contain any playable races in `RequiredRaces` (%u), value set to 0 (all races).", qinfo->GetQuestId(), qinfo->RequiredRaces); - qinfo->RequiredRaces = 0; + TC_LOG_ERROR("sql.sql", "Quest %u does not contain any playable races in `AllowableRaces` (%u), value set to 0 (all races).", qinfo->GetQuestId(), qinfo->AllowableRaces); + qinfo->AllowableRaces = 0; } } // RequiredSkillId, can be 0 @@ -4323,26 +4323,26 @@ void ObjectMgr::LoadQuests() // quest can't reward this title } - if (qinfo->SourceItemId) + if (qinfo->StartItem) { - if (!sObjectMgr->GetItemTemplate(qinfo->SourceItemId)) + if (!sObjectMgr->GetItemTemplate(qinfo->StartItem)) { - TC_LOG_ERROR("sql.sql", "Quest %u has `SourceItemId` = %u but item with entry %u does not exist, quest can't be done.", - qinfo->GetQuestId(), qinfo->SourceItemId, qinfo->SourceItemId); - qinfo->SourceItemId = 0; // quest can't be done for this requirement + TC_LOG_ERROR("sql.sql", "Quest %u has `StartItem` = %u but item with entry %u does not exist, quest can't be done.", + qinfo->GetQuestId(), qinfo->StartItem, qinfo->StartItem); + qinfo->StartItem = 0; // quest can't be done for this requirement } - else if (qinfo->SourceItemIdCount == 0) + else if (qinfo->StartItemCount == 0) { - TC_LOG_ERROR("sql.sql", "Quest %u has `SourceItemId` = %u but `SourceItemIdCount` = 0, set to 1 but need fix in DB.", - qinfo->GetQuestId(), qinfo->SourceItemId); - qinfo->SourceItemIdCount = 1; // update to 1 for allow quest work for backward compatibility with DB + TC_LOG_ERROR("sql.sql", "Quest %u has `StartItem` = %u but `StartItemCount` = 0, set to 1 but need fix in DB.", + qinfo->GetQuestId(), qinfo->StartItem); + qinfo->StartItemCount = 1; // update to 1 for allow quest work for backward compatibility with DB } } - else if (qinfo->SourceItemIdCount>0) + else if (qinfo->StartItemCount>0) { - TC_LOG_ERROR("sql.sql", "Quest %u has `SourceItemId` = 0 but `SourceItemIdCount` = %u, useless value.", - qinfo->GetQuestId(), qinfo->SourceItemIdCount); - qinfo->SourceItemIdCount=0; // no quest work changes in fact + TC_LOG_ERROR("sql.sql", "Quest %u has `StartItem` = 0 but `StartItemCount` = %u, useless value.", + qinfo->GetQuestId(), qinfo->StartItemCount); + qinfo->StartItemCount=0; // no quest work changes in fact } if (qinfo->SourceSpellid) @@ -4393,22 +4393,22 @@ void ObjectMgr::LoadQuests() for (uint8 j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; ++j) { - uint32 id = qinfo->RequiredSourceItemId[j]; + uint32 id = qinfo->ItemDrop[j]; if (id) { if (!sObjectMgr->GetItemTemplate(id)) { - TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredSourceItemId%d` = %u but item with entry %u does not exist, quest can't be done.", + TC_LOG_ERROR("sql.sql", "Quest %u has `ItemDrop%d` = %u but item with entry %u does not exist, quest can't be done.", qinfo->GetQuestId(), j+1, id, id); // no changes, quest can't be done for this requirement } } else { - if (qinfo->RequiredSourceItemCount[j]>0) + if (qinfo->ItemDropQuantity[j]>0) { - TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredSourceItemId%d` = 0 but `RequiredSourceItemCount%d` = %u.", - qinfo->GetQuestId(), j+1, j+1, qinfo->RequiredSourceItemCount[j]); + TC_LOG_ERROR("sql.sql", "Quest %u has `ItemDrop%d` = 0 but `ItemDropQuantity%d` = %u.", + qinfo->GetQuestId(), j+1, j+1, qinfo->ItemDropQuantity[j]); // no changes, quest ignore this data } } @@ -4529,55 +4529,55 @@ void ObjectMgr::LoadQuests() } } - if (qinfo->RewardSpell) + if (qinfo->RewardDisplaySpell) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->RewardSpell); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->RewardDisplaySpell); if (!spellInfo) { - TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSpell` = %u but spell %u does not exist, spell removed as display reward.", - qinfo->GetQuestId(), qinfo->RewardSpell, qinfo->RewardSpell); - qinfo->RewardSpell = 0; // no spell reward will display for this quest + TC_LOG_ERROR("sql.sql", "Quest %u has `RewardDisplaySpell` = %u but spell %u does not exist, spell removed as display reward.", + qinfo->GetQuestId(), qinfo->RewardDisplaySpell, qinfo->RewardDisplaySpell); + qinfo->RewardDisplaySpell = 0; // no spell reward will display for this quest } else if (!SpellMgr::IsSpellValid(spellInfo)) { - TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSpell` = %u but spell %u is broken, quest will not have a spell reward.", - qinfo->GetQuestId(), qinfo->RewardSpell, qinfo->RewardSpell); - qinfo->RewardSpell = 0; // no spell reward will display for this quest + TC_LOG_ERROR("sql.sql", "Quest %u has `RewardDisplaySpell` = %u but spell %u is broken, quest will not have a spell reward.", + qinfo->GetQuestId(), qinfo->RewardDisplaySpell, qinfo->RewardDisplaySpell); + qinfo->RewardDisplaySpell = 0; // no spell reward will display for this quest } - else if (GetTalentSpellCost(qinfo->RewardSpell)) + else if (GetTalentSpellCost(qinfo->RewardDisplaySpell)) { - TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSpell` = %u but spell %u is talent, quest will not have a spell reward.", - qinfo->GetQuestId(), qinfo->RewardSpell, qinfo->RewardSpell); - qinfo->RewardSpell = 0; // no spell reward will display for this quest + TC_LOG_ERROR("sql.sql", "Quest %u has `RewardDisplaySpell` = %u but spell %u is talent, quest will not have a spell reward.", + qinfo->GetQuestId(), qinfo->RewardDisplaySpell, qinfo->RewardDisplaySpell); + qinfo->RewardDisplaySpell = 0; // no spell reward will display for this quest } } - if (qinfo->RewardSpellCast > 0) + if (qinfo->RewardSpell > 0) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->RewardSpellCast); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->RewardSpell); if (!spellInfo) { - TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSpellCast` = %u but spell %u does not exist, quest will not have a spell reward.", - qinfo->GetQuestId(), qinfo->RewardSpellCast, qinfo->RewardSpellCast); - qinfo->RewardSpellCast = 0; // no spell will be cast on player + TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSpell` = %u but spell %u does not exist, quest will not have a spell reward.", + qinfo->GetQuestId(), qinfo->RewardSpell, qinfo->RewardSpell); + qinfo->RewardSpell = 0; // no spell will be cast on player } else if (!SpellMgr::IsSpellValid(spellInfo)) { - TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSpellCast` = %u but spell %u is broken, quest will not have a spell reward.", - qinfo->GetQuestId(), qinfo->RewardSpellCast, qinfo->RewardSpellCast); - qinfo->RewardSpellCast = 0; // no spell will be cast on player + TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSpell` = %u but spell %u is broken, quest will not have a spell reward.", + qinfo->GetQuestId(), qinfo->RewardSpell, qinfo->RewardSpell); + qinfo->RewardSpell = 0; // no spell will be cast on player } - else if (GetTalentSpellCost(qinfo->RewardSpellCast)) + else if (GetTalentSpellCost(qinfo->RewardSpell)) { - TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSpell` = %u but spell %u is talent, quest will not have a spell reward.", - qinfo->GetQuestId(), qinfo->RewardSpellCast, qinfo->RewardSpellCast); - qinfo->RewardSpellCast = 0; // no spell will be cast on player + TC_LOG_ERROR("sql.sql", "Quest %u has `RewardDisplaySpell` = %u but spell %u is talent, quest will not have a spell reward.", + qinfo->GetQuestId(), qinfo->RewardSpell, qinfo->RewardSpell); + qinfo->RewardSpell = 0; // no spell will be cast on player } } @@ -4602,14 +4602,14 @@ void ObjectMgr::LoadQuests() usedMailTemplates[qinfo->RewardMailTemplateId] = qinfo->GetQuestId(); } - if (qinfo->NextQuestIdChain) + if (qinfo->RewardNextQuest) { - QuestMap::iterator qNextItr = _questTemplates.find(qinfo->NextQuestIdChain); + QuestMap::iterator qNextItr = _questTemplates.find(qinfo->RewardNextQuest); if (qNextItr == _questTemplates.end()) { - TC_LOG_ERROR("sql.sql", "Quest %u has `NextQuestIdChain` = %u but quest %u does not exist, quest chain will not work.", - qinfo->GetQuestId(), qinfo->NextQuestIdChain, qinfo->NextQuestIdChain); - qinfo->NextQuestIdChain = 0; + TC_LOG_ERROR("sql.sql", "Quest %u has `RewardNextQuest` = %u but quest %u does not exist, quest chain will not work.", + qinfo->GetQuestId(), qinfo->RewardNextQuest, qinfo->RewardNextQuest); + qinfo->RewardNextQuest = 0; } else qNextItr->second->prevChainQuests.push_back(qinfo->GetQuestId()); @@ -4644,7 +4644,7 @@ void ObjectMgr::LoadQuests() if (qinfo->ExclusiveGroup) mExclusiveQuestGroups.insert(std::pair<int32, uint32>(qinfo->ExclusiveGroup, qinfo->GetQuestId())); - if (qinfo->LimitTime) + if (qinfo->TimeAllowed) qinfo->SetSpecialFlag(QUEST_SPECIAL_FLAGS_TIMED); if (qinfo->RequiredPlayerKills) qinfo->SetSpecialFlag(QUEST_SPECIAL_FLAGS_PLAYER_KILL); @@ -4720,7 +4720,7 @@ void ObjectMgr::LoadQuestLocales() AddLocaleString(fields[1 + 11 * (i - 1) + 2].GetString(), locale, data.Objectives); AddLocaleString(fields[1 + 11 * (i - 1) + 3].GetString(), locale, data.OfferRewardText); AddLocaleString(fields[1 + 11 * (i - 1) + 4].GetString(), locale, data.RequestItemsText); - AddLocaleString(fields[1 + 11 * (i - 1) + 5].GetString(), locale, data.EndText); + AddLocaleString(fields[1 + 11 * (i - 1) + 5].GetString(), locale, data.AreaDescription); AddLocaleString(fields[1 + 11 * (i - 1) + 6].GetString(), locale, data.CompletedText); for (uint8 k = 0; k < 4; ++k) @@ -5090,13 +5090,13 @@ void ObjectMgr::LoadEventScripts() { for (size_t node_idx = 0; node_idx < sTaxiPathNodesByPath[path_idx].size(); ++node_idx) { - TaxiPathNodeEntry const& node = sTaxiPathNodesByPath[path_idx][node_idx]; + TaxiPathNodeEntry const* node = sTaxiPathNodesByPath[path_idx][node_idx]; - if (node.ArrivalEventID) - evt_scripts.insert(node.ArrivalEventID); + if (node->ArrivalEventID) + evt_scripts.insert(node->ArrivalEventID); - if (node.DepartureEventID) - evt_scripts.insert(node.DepartureEventID); + if (node->DepartureEventID) + evt_scripts.insert(node->DepartureEventID); } } diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 11b31d98cc8..b6e8d3c3ede 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -1942,7 +1942,7 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) { Quest const* quest = iter->second; uint32 newRaceMask = (team == TEAM_ALLIANCE) ? RACEMASK_ALLIANCE : RACEMASK_HORDE; - if (!(quest->GetRequiredRaces() & newRaceMask)) + if (!(quest->GetAllowableRaces() & newRaceMask)) { stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE_BY_QUEST); stmt->setUInt32(0, lowGuid); diff --git a/src/server/game/Handlers/TaxiHandler.cpp b/src/server/game/Handlers/TaxiHandler.cpp index af0f5b0fc75..a671250c17d 100644 --- a/src/server/game/Handlers/TaxiHandler.cpp +++ b/src/server/game/Handlers/TaxiHandler.cpp @@ -24,7 +24,6 @@ #include "Log.h" #include "ObjectMgr.h" #include "Player.h" -#include "Path.h" #include "WaypointMovementGenerator.h" void WorldSession::HandleTaxiNodeStatusQueryOpcode(WorldPacket& recvData) @@ -212,7 +211,7 @@ void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recvData) MovementInfo movementInfo; // used only for proper packet read ReadMovementInfo(recvData, &movementInfo); - recvData.read_skip<uint32>(); // unk + recvData.read_skip<uint32>(); // spline id // in taxi flight packet received in 2 case: // 1) end taxi path in far (multi-node) flight @@ -220,59 +219,32 @@ void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recvData) // we need process only (1) uint32 curDest = GetPlayer()->m_taxi.GetTaxiDestination(); - if (!curDest) - return; - - TaxiNodesEntry const* curDestNode = sTaxiNodesStore.LookupEntry(curDest); - - // far teleport case - if (curDestNode && curDestNode->map_id != GetPlayer()->GetMapId()) + if (curDest) { - if (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) - { - // short preparations to continue flight - FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top()); - - flight->SetCurrentNodeAfterTeleport(); - TaxiPathNodeEntry const& node = flight->GetPath()[flight->GetCurrentNode()]; - flight->SkipCurrentNode(); + TaxiNodesEntry const* curDestNode = sTaxiNodesStore.LookupEntry(curDest); - GetPlayer()->TeleportTo(curDestNode->map_id, node.LocX, node.LocY, node.LocZ, GetPlayer()->GetOrientation()); - } - return; - } - - uint32 destinationnode = GetPlayer()->m_taxi.NextTaxiDestination(); - if (destinationnode > 0) // if more destinations to go - { - // current source node for next destination - uint32 sourcenode = GetPlayer()->m_taxi.GetTaxiSource(); - - // Add to taximask middle hubs in taxicheat mode (to prevent having player with disabled taxicheat and not having back flight path) - if (GetPlayer()->isTaxiCheater()) + // far teleport case + if (curDestNode && curDestNode->map_id != GetPlayer()->GetMapId()) { - if (GetPlayer()->m_taxi.SetTaximaskNode(sourcenode)) + if (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) { - WorldPacket data(SMSG_NEW_TAXI_PATH, 0); - _player->GetSession()->SendPacket(&data); - } - } + // short preparations to continue flight + FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top()); - TC_LOG_DEBUG("network", "WORLD: Taxi has to go from %u to %u", sourcenode, destinationnode); + flight->SetCurrentNodeAfterTeleport(); + TaxiPathNodeEntry const* node = flight->GetPath()[flight->GetCurrentNode()]; + flight->SkipCurrentNode(); - uint32 mountDisplayId = sObjectMgr->GetTaxiMountDisplayId(sourcenode, GetPlayer()->GetTeam()); - - uint32 path, cost; - sObjectMgr->GetTaxiPath(sourcenode, destinationnode, path, cost); + GetPlayer()->TeleportTo(curDestNode->map_id, node->LocX, node->LocY, node->LocZ, GetPlayer()->GetOrientation()); + } + } - if (path && mountDisplayId) - SendDoFlight(mountDisplayId, path, 1); // skip start fly node - else - GetPlayer()->m_taxi.ClearTaxiDestinations(); // clear problematic path and next return; } - else - GetPlayer()->m_taxi.ClearTaxiDestinations(); // not destinations, clear source node + + // at this point only 1 node is expected (final destination) + if (GetPlayer()->m_taxi.GetPath().size() != 1) + return; GetPlayer()->CleanupAfterTaxiFlight(); GetPlayer()->SetFallInformation(0, GetPlayer()->GetPositionZ()); diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 354bbe4e269..c758d132d6e 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -2571,7 +2571,7 @@ inline void Map::setNGrid(NGridType *grid, uint32 x, uint32 y) if (x >= MAX_NUMBER_OF_GRIDS || y >= MAX_NUMBER_OF_GRIDS) { TC_LOG_ERROR("maps", "map::setNGrid() Invalid grid coordinates found: %d, %d!", x, y); - ASSERT(false); + ABORT(); } i_grids[x][y] = grid; } @@ -2630,7 +2630,7 @@ void Map::AddObjectToSwitchList(WorldObject* obj, bool on) else if (itr->second != on) i_objectsToSwitch.erase(itr); else - ASSERT(false); + ABORT(); } void Map::RemoveAllObjectsInRemoveList() @@ -2867,7 +2867,7 @@ bool InstanceMap::CanEnter(Player* player) if (player->GetMapRef().getTarget() == this) { TC_LOG_ERROR("maps", "InstanceMap::CanEnter - player %s(%u) already in map %d, %d, %d!", player->GetName().c_str(), player->GetGUIDLow(), GetId(), GetInstanceId(), GetSpawnMode()); - ASSERT(false); + ABORT(); return false; } @@ -2976,7 +2976,7 @@ bool InstanceMap::AddPlayerToMap(Player* player) TC_LOG_ERROR("maps", "InstanceMap::Add: player %s(%d) is being put into instance %s %d, %d, %d, %d, %d, %d but he is in group %s and is bound to instance %d, %d, %d, %d, %d, %d!", player->GetName().c_str(), player->GetGUIDLow(), GetMapName(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset(), group->GetLeaderGUID().ToString().c_str(), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), playerBind->save->GetDifficulty(), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset()); if (groupBind) TC_LOG_ERROR("maps", "InstanceMap::Add: the group is bound to the instance %s %d, %d, %d, %d, %d, %d", GetMapName(), groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), groupBind->save->GetDifficulty(), groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount(), groupBind->save->CanReset()); - //ASSERT(false); + //ABORT(); return false; } // bind to the group or keep using the group save @@ -3256,7 +3256,7 @@ bool BattlegroundMap::CanEnter(Player* player) if (player->GetMapRef().getTarget() == this) { TC_LOG_ERROR("maps", "BGMap::CanEnter - player %u is already in map!", player->GetGUIDLow()); - ASSERT(false); + ABORT(); return false; } diff --git a/src/server/game/Maps/MapInstanced.cpp b/src/server/game/Maps/MapInstanced.cpp index e4632bb7515..32c10cae16f 100644 --- a/src/server/game/Maps/MapInstanced.cpp +++ b/src/server/game/Maps/MapInstanced.cpp @@ -194,13 +194,13 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave* save, if (!entry) { TC_LOG_ERROR("maps", "CreateInstance: no entry for map %d", GetId()); - ASSERT(false); + ABORT(); } const InstanceTemplate* iTemplate = sObjectMgr->GetInstanceTemplate(GetId()); if (!iTemplate) { TC_LOG_ERROR("maps", "CreateInstance: no instance template for map %d", GetId()); - ASSERT(false); + ABORT(); } // some instances only have one difficulty @@ -279,6 +279,6 @@ bool MapInstanced::DestroyInstance(InstancedMaps::iterator &itr) bool MapInstanced::CanEnter(Player* /*player*/) { - //ASSERT(false); + //ABORT(); return true; } diff --git a/src/server/game/Maps/TransportMgr.cpp b/src/server/game/Maps/TransportMgr.cpp index dadc2eeeac3..e5815a415e7 100644 --- a/src/server/game/Maps/TransportMgr.cpp +++ b/src/server/game/Maps/TransportMgr.cpp @@ -112,7 +112,7 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl Movement::PointsArray splinePath, allPoints; bool mapChange = false; for (size_t i = 0; i < path.size(); ++i) - allPoints.push_back(G3D::Vector3(path[i].LocX, path[i].LocY, path[i].LocZ)); + allPoints.push_back(G3D::Vector3(path[i]->LocX, path[i]->LocY, path[i]->LocZ)); // Add extra points to allow derivative calculations for all path nodes allPoints.insert(allPoints.begin(), allPoints.front().lerp(allPoints[1], -0.2f)); @@ -128,8 +128,8 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl { if (!mapChange) { - TaxiPathNodeEntry const& node_i = path[i]; - if (i != path.size() - 1 && (node_i.Flags & 1 || node_i.MapID != path[i + 1].MapID)) + TaxiPathNodeEntry const* node_i = path[i]; + if (i != path.size() - 1 && (node_i->Flags & 1 || node_i->MapID != path[i + 1]->MapID)) { keyFrames.back().Teleport = true; mapChange = true; @@ -142,7 +142,7 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl k.InitialOrientation = Position::NormalizeOrientation(std::atan2(h.y, h.x) + float(M_PI)); keyFrames.push_back(k); - splinePath.push_back(G3D::Vector3(node_i.LocX, node_i.LocY, node_i.LocZ)); + splinePath.push_back(G3D::Vector3(node_i->LocX, node_i->LocY, node_i->LocZ)); transport->mapsUsed.insert(k.Node->MapID); } } diff --git a/src/server/game/Maps/TransportMgr.h b/src/server/game/Maps/TransportMgr.h index fff7b9d8afa..c273ea7fb15 100644 --- a/src/server/game/Maps/TransportMgr.h +++ b/src/server/game/Maps/TransportMgr.h @@ -37,7 +37,7 @@ typedef std::unordered_map<uint32, std::set<uint32> > TransportInstanceMap; struct KeyFrame { - explicit KeyFrame(TaxiPathNodeEntry const& _node) : Index(0), Node(&_node), InitialOrientation(0.0f), + explicit KeyFrame(TaxiPathNodeEntry const* node) : Index(0), Node(node), InitialOrientation(0.0f), DistSinceStop(-1.0f), DistUntilStop(-1.0f), DistFromPrev(-1.0f), TimeFrom(0.0f), TimeTo(0.0f), Teleport(false), ArriveTime(0), DepartureTime(0), Spline(NULL), NextDistFromPrev(0.0f), NextArriveTime(0) { diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index b69322f5720..2bcb4aeb3b3 100644 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -563,7 +563,8 @@ void MotionMaster::MoveTaxiFlight(uint32 path, uint32 pathnode) if (path < sTaxiPathNodesByPath.size()) { TC_LOG_DEBUG("misc", "%s taxi to (Path %u node %u)", _owner->GetName().c_str(), path, pathnode); - FlightPathMovementGenerator* mgen = new FlightPathMovementGenerator(sTaxiPathNodesByPath[path], pathnode); + FlightPathMovementGenerator* mgen = new FlightPathMovementGenerator(pathnode); + mgen->LoadPath(_owner->ToPlayer()); Mutate(mgen, MOTION_SLOT_CONTROLLED); } else diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp index f91fc1985d5..8a5ac387f19 100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp @@ -245,17 +245,62 @@ bool WaypointMovementGenerator<Creature>::GetResetPos(Creature*, float& x, float uint32 FlightPathMovementGenerator::GetPathAtMapEnd() const { - if (i_currentNode >= i_path->size()) - return i_path->size(); + if (i_currentNode >= i_path.size()) + return i_path.size(); - uint32 curMapId = (*i_path)[i_currentNode].MapID; - for (uint32 i = i_currentNode; i < i_path->size(); ++i) - { - if ((*i_path)[i].MapID != curMapId) + uint32 curMapId = i_path[i_currentNode]->MapID; + for (uint32 i = i_currentNode; i < i_path.size(); ++i) + if (i_path[i]->MapID != curMapId) return i; - } - return i_path->size(); + return i_path.size(); +} + +#define SKIP_SPLINE_POINT_DISTANCE_SQ (40.0f * 40.0f) + +bool IsNodeIncludedInShortenedPath(TaxiPathNodeEntry const* p1, TaxiPathNodeEntry const* p2) +{ + return p1->MapID != p2->MapID || std::pow(p1->LocX - p2->LocX, 2) + std::pow(p1->LocY - p2->LocY, 2) > SKIP_SPLINE_POINT_DISTANCE_SQ; +} + +void FlightPathMovementGenerator::LoadPath(Player* player) +{ + _pointsForPathSwitch.clear(); + std::deque<uint32> const& taxi = player->m_taxi.GetPath(); + for (uint32 src = 0, dst = 1; dst < taxi.size(); src = dst++) + { + uint32 path, cost; + sObjectMgr->GetTaxiPath(taxi[src], taxi[dst], path, cost); + if (path > sTaxiPathNodesByPath.size()) + return; + + TaxiPathNodeList const& nodes = sTaxiPathNodesByPath[path]; + if (!nodes.empty()) + { + TaxiPathNodeEntry const* start = nodes[0]; + TaxiPathNodeEntry const* end = nodes[nodes.size() - 1]; + bool passedPreviousSegmentProximityCheck = false; + for (uint32 i = 0; i < nodes.size(); ++i) + { + if (passedPreviousSegmentProximityCheck || !src || i_path.empty() || IsNodeIncludedInShortenedPath(i_path[i_path.size() - 1], nodes[i])) + { + if ((!src || (IsNodeIncludedInShortenedPath(start, nodes[i]) && i >= 2)) && + (dst == taxi.size() - 1 || (IsNodeIncludedInShortenedPath(end, nodes[i]) && i < nodes.size() - 1))) + { + passedPreviousSegmentProximityCheck = true; + i_path.push_back(nodes[i]); + } + } + else + { + i_path.pop_back(); + --_pointsForPathSwitch.back().PathIndex; + } + } + } + + _pointsForPathSwitch.push_back({ uint32(i_path.size() - 1), int32(cost) }); + } } void FlightPathMovementGenerator::DoInitialize(Player* player) @@ -296,7 +341,7 @@ void FlightPathMovementGenerator::DoReset(Player* player) uint32 end = GetPathAtMapEnd(); for (uint32 i = GetCurrentNode(); i != end; ++i) { - G3D::Vector3 vertice((*i_path)[i].LocX, (*i_path)[i].LocY, (*i_path)[i].LocZ); + G3D::Vector3 vertice(i_path[i]->LocX, i_path[i]->LocY, i_path[i]->LocZ); init.Path().push_back(vertice); } init.SetFirstPointId(GetCurrentNode()); @@ -313,9 +358,21 @@ bool FlightPathMovementGenerator::DoUpdate(Player* player, uint32 /*diff*/) bool departureEvent = true; do { - DoEventIfAny(player, (*i_path)[i_currentNode], departureEvent); + DoEventIfAny(player, i_path[i_currentNode], departureEvent); + while (!_pointsForPathSwitch.empty() && _pointsForPathSwitch.front().PathIndex <= i_currentNode) + { + _pointsForPathSwitch.pop_front(); + player->m_taxi.NextTaxiDestination(); + if (!_pointsForPathSwitch.empty()) + { + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, _pointsForPathSwitch.front().Cost); + player->ModifyMoney(-_pointsForPathSwitch.front().Cost); + } + } + if (pointId == i_currentNode) break; + if (i_currentNode == _preloadTargetNode) PreloadEndGrid(); i_currentNode += (uint32)departureEvent; @@ -324,18 +381,18 @@ bool FlightPathMovementGenerator::DoUpdate(Player* player, uint32 /*diff*/) while (true); } - return i_currentNode < (i_path->size()-1); + return i_currentNode < (i_path.size() - 1); } void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport() { - if (i_path->empty()) + if (i_path.empty() || i_currentNode >= i_path.size()) return; - uint32 map0 = (*i_path)[0].MapID; - for (size_t i = 1; i < i_path->size(); ++i) + uint32 map0 = i_path[i_currentNode]->MapID; + for (size_t i = i_currentNode + 1; i < i_path.size(); ++i) { - if ((*i_path)[i].MapID != map0) + if (i_path[i]->MapID != map0) { i_currentNode = i; return; @@ -343,19 +400,21 @@ void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport() } } -void FlightPathMovementGenerator::DoEventIfAny(Player* player, TaxiPathNodeEntry const& node, bool departure) +void FlightPathMovementGenerator::DoEventIfAny(Player* player, TaxiPathNodeEntry const* node, bool departure) { - if (uint32 eventid = departure ? node.DepartureEventID : node.ArrivalEventID) + if (uint32 eventid = departure ? node->DepartureEventID : node->ArrivalEventID) { - TC_LOG_DEBUG("maps.script", "Taxi %s event %u of node %u of path %u for player %s", departure ? "departure" : "arrival", eventid, node.NodeIndex, node.PathID, player->GetName().c_str()); + TC_LOG_DEBUG("maps.script", "Taxi %s event %u of node %u of path %u for player %s", departure ? "departure" : "arrival", eventid, node->NodeIndex, node->PathID, player->GetName().c_str()); player->GetMap()->ScriptsStart(sEventScripts, eventid, player, player); } } bool FlightPathMovementGenerator::GetResetPos(Player*, float& x, float& y, float& z) { - const TaxiPathNodeEntry& node = (*i_path)[i_currentNode]; - x = node.LocX; y = node.LocY; z = node.LocZ; + TaxiPathNodeEntry const* node = i_path[i_currentNode]; + x = node->LocX; + y = node->LocY; + z = node->LocZ; return true; } @@ -363,11 +422,11 @@ void FlightPathMovementGenerator::InitEndGridInfo() { /*! Storage to preload flightmaster grid at end of flight. For multi-stop flights, this will be reinitialized for each flightmaster at the end of each spline (or stop) in the flight. */ - uint32 nodeCount = (*i_path).size(); //! Number of nodes in path. - _endMapId = (*i_path)[nodeCount - 1].MapID; //! MapId of last node + uint32 nodeCount = i_path.size(); //! Number of nodes in path. + _endMapId = i_path[nodeCount - 1]->MapID; //! MapId of last node _preloadTargetNode = nodeCount - 3; - _endGridX = (*i_path)[nodeCount - 1].LocX; - _endGridY = (*i_path)[nodeCount - 1].LocY; + _endGridX = i_path[nodeCount - 1]->LocX; + _endGridY = i_path[nodeCount - 1]->LocY; } void FlightPathMovementGenerator::PreloadEndGrid() @@ -378,7 +437,7 @@ void FlightPathMovementGenerator::PreloadEndGrid() // Load the grid if (endMap) { - TC_LOG_DEBUG("misc", "Preloading rid (%f, %f) for map %u at node index %u/%u", _endGridX, _endGridY, _endMapId, _preloadTargetNode, (uint32)(i_path->size()-1)); + TC_LOG_DEBUG("misc", "Preloading rid (%f, %f) for map %u at node index %u/%u", _endGridX, _endGridY, _endMapId, _preloadTargetNode, (uint32)(i_path.size() - 1)); endMap->LoadGrid(_endGridX, _endGridY); } else diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h index eb8533159a9..caf76b5ea19 100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h @@ -27,13 +27,8 @@ #include "MovementGenerator.h" #include "WaypointManager.h" -#include "Path.h" - #include "Player.h" -#include <vector> -#include <set> - #define FLIGHT_TRAVEL_UPDATE 100 #define STOP_TIME_FOR_PLAYER 3 * MINUTE * IN_MILLISECONDS // 3 Minutes #define TIMEDIFF_NEXT_WP 250 @@ -42,11 +37,9 @@ template<class T, class P> class PathMovementBase { public: - PathMovementBase() : i_path(NULL), i_currentNode(0) { } + PathMovementBase() : i_path(), i_currentNode(0) { } virtual ~PathMovementBase() { }; - // template pattern, not defined .. override required - void LoadPath(T &); uint32 GetCurrentNode() const { return i_currentNode; } protected: @@ -110,30 +103,30 @@ class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium< Crea * and hence generates ground and activities for the player. */ class FlightPathMovementGenerator : public MovementGeneratorMedium< Player, FlightPathMovementGenerator >, - public PathMovementBase<Player, TaxiPathNodeList const*> + public PathMovementBase<Player, TaxiPathNodeList> { public: - explicit FlightPathMovementGenerator(TaxiPathNodeList const& pathnodes, uint32 startNode = 0) + explicit FlightPathMovementGenerator(uint32 startNode = 0) { - i_path = &pathnodes; i_currentNode = startNode; _endGridX = 0.0f; _endGridY = 0.0f; _endMapId = 0; _preloadTargetNode = 0; } + void LoadPath(Player* player); void DoInitialize(Player*); void DoReset(Player*); void DoFinalize(Player*); bool DoUpdate(Player*, uint32); MovementGeneratorType GetMovementGeneratorType() const override { return FLIGHT_MOTION_TYPE; } - TaxiPathNodeList const& GetPath() { return *i_path; } + TaxiPathNodeList const& GetPath() { return i_path; } uint32 GetPathAtMapEnd() const; - bool HasArrived() const { return (i_currentNode >= i_path->size()); } + bool HasArrived() const { return (i_currentNode >= i_path.size()); } void SetCurrentNodeAfterTeleport(); void SkipCurrentNode() { ++i_currentNode; } - void DoEventIfAny(Player* player, TaxiPathNodeEntry const& node, bool departure); + void DoEventIfAny(Player* player, TaxiPathNodeEntry const* node, bool departure); bool GetResetPos(Player*, float& x, float& y, float& z); @@ -141,9 +134,18 @@ class FlightPathMovementGenerator : public MovementGeneratorMedium< Player, Flig void PreloadEndGrid(); private: - float _endGridX; //! X coord of last node location - float _endGridY; //! Y coord of last node location - uint32 _endMapId; //! map Id of last node location - uint32 _preloadTargetNode; //! node index where preloading starts + + float _endGridX; //! X coord of last node location + float _endGridY; //! Y coord of last node location + uint32 _endMapId; //! map Id of last node location + uint32 _preloadTargetNode; //! node index where preloading starts + + struct TaxiNodeChangeInfo + { + uint32 PathIndex; + int32 Cost; + }; + + std::deque<TaxiNodeChangeInfo> _pointsForPathSwitch; //! node indexes and costs where TaxiPath changes }; #endif diff --git a/src/server/game/Movement/Spline/Spline.h b/src/server/game/Movement/Spline/Spline.h index c8b7a19c943..59f514bed75 100644 --- a/src/server/game/Movement/Spline/Spline.h +++ b/src/server/game/Movement/Spline/Spline.h @@ -82,7 +82,7 @@ protected: typedef void (SplineBase::*InitMethtod)(const Vector3*, index_type, index_type); static InitMethtod initializers[ModesEnd]; - void UninitializedSpline() const { ASSERT(false);} + void UninitializedSpline() const { ABORT();} public: diff --git a/src/server/game/Movement/Waypoints/Path.h b/src/server/game/Movement/Waypoints/Path.h deleted file mode 100644 index bb8abc37eb3..00000000000 --- a/src/server/game/Movement/Waypoints/Path.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> - * - * 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 TRINITYCORE_PATH_H -#define TRINITYCORE_PATH_H - -#include "Common.h" -#include <deque> - -struct PathNode -{ - PathNode(): x(0.0f), y(0.0f), z(0.0f) { } - PathNode(float _x, float _y, float _z): x(_x), y(_y), z(_z) { } - float x, y, z; -}; -template<typename PathElem, typename PathNode = PathElem> - -class Path -{ - public: - size_t size() const { return i_nodes.size(); } - bool empty() const { return i_nodes.empty(); } - void resize(unsigned int sz) { i_nodes.resize(sz); } - void clear() { i_nodes.clear(); } - void erase(uint32 idx) { i_nodes.erase(i_nodes.begin()+idx); } - void crop(unsigned int start, unsigned int end) - { - while (start && !i_nodes.empty()) - { - i_nodes.pop_front(); - --start; - } - - while (end && !i_nodes.empty()) - { - i_nodes.pop_back(); - --end; - } - } - - float GetTotalLength(uint32 start, uint32 end) const - { - float len = 0.0f; - for (uint32 idx=start+1; idx < end; ++idx) - { - PathNode const& node = i_nodes[idx]; - PathNode const& prev = i_nodes[idx-1]; - float xd = node.x - prev.x; - float yd = node.y - prev.y; - float zd = node.z - prev.z; - len += std::sqrt(xd*xd + yd*yd + zd*zd); - } - return len; - } - - float GetTotalLength() const { return GetTotalLength(0, size()); } - - float GetPassedLength(uint32 curnode, float x, float y, float z) const - { - float len = GetTotalLength(0, curnode); - - if (curnode > 0) - { - PathNode const& node = i_nodes[curnode-1]; - float xd = x - node.x; - float yd = y - node.y; - float zd = z - node.z; - len += std::sqrt(xd*xd + yd*yd + zd*zd); - } - - return len; - } - - PathNode& operator[](size_t idx) { return i_nodes[idx]; } - PathNode const& operator[](size_t idx) const { return i_nodes[idx]; } - - void set(size_t idx, PathElem elem) { i_nodes[idx] = elem; } - - protected: - std::deque<PathElem> i_nodes; -}; - -typedef Path<PathNode> SimplePath; - -#endif diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp index eea0fd72e8b..58bc4915d3f 100644 --- a/src/server/game/Quests/QuestDef.cpp +++ b/src/server/game/Quests/QuestDef.cpp @@ -29,21 +29,21 @@ Quest::Quest(Field* questRecord) ZoneOrSort = questRecord[4].GetInt16(); Type = questRecord[5].GetUInt16(); SuggestedPlayers = questRecord[6].GetUInt8(); - LimitTime = questRecord[7].GetUInt32(); - RequiredRaces = questRecord[8].GetUInt16(); + TimeAllowed = questRecord[7].GetUInt32(); + AllowableRaces = questRecord[8].GetUInt16(); RequiredFactionId1 = questRecord[9].GetUInt16(); RequiredFactionId2 = questRecord[10].GetUInt16(); RequiredFactionValue1 = questRecord[11].GetInt32(); RequiredFactionValue2 = questRecord[12].GetInt32(); - NextQuestIdChain = questRecord[13].GetUInt32(); - RewardXPId = questRecord[14].GetUInt8(); - RewardOrRequiredMoney = questRecord[15].GetInt32(); - RewardMoneyMaxLevel = questRecord[16].GetUInt32(); - RewardSpell = questRecord[17].GetUInt32(); - RewardSpellCast = questRecord[18].GetInt32(); + RewardNextQuest = questRecord[13].GetUInt32(); + RewardXPDifficulty = questRecord[14].GetUInt8(); + RewardMoney = questRecord[15].GetInt32(); + RewardBonusMoney = questRecord[16].GetUInt32(); + RewardDisplaySpell = questRecord[17].GetUInt32(); + RewardSpell = questRecord[18].GetInt32(); RewardHonor = questRecord[19].GetUInt32(); - RewardHonorMultiplier = questRecord[20].GetFloat(); - SourceItemId = questRecord[21].GetUInt32(); + RewardKillHonor = questRecord[20].GetFloat(); + StartItem = questRecord[21].GetUInt32(); Flags = questRecord[22].GetUInt32(); RewardTitleId = questRecord[23].GetUInt8(); RequiredPlayerKills = questRecord[24].GetUInt8(); @@ -69,14 +69,14 @@ Quest::Quest(Field* questRecord) RewardFactionValueIdOverride[i] = questRecord[49+i*3].GetInt32(); } - PointMapId = questRecord[62].GetUInt16(); - PointX = questRecord[63].GetFloat(); - PointY = questRecord[64].GetFloat(); - PointOption = questRecord[65].GetUInt32(); + POIContinent = questRecord[62].GetUInt16(); + POIx = questRecord[63].GetFloat(); + POIy = questRecord[64].GetFloat(); + POIPriority = questRecord[65].GetUInt32(); Title = questRecord[66].GetString(); Objectives = questRecord[67].GetString(); Details = questRecord[68].GetString(); - EndText = questRecord[69].GetString(); + AreaDescription = questRecord[69].GetString(); CompletedText = questRecord[70].GetString(); for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) @@ -86,10 +86,10 @@ Quest::Quest(Field* questRecord) RequiredNpcOrGoCount[i] = questRecord[75+i].GetUInt16(); for (int i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i) - RequiredSourceItemId[i] = questRecord[79+i].GetUInt32(); + ItemDrop[i] = questRecord[79+i].GetUInt32(); for (int i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i) - RequiredSourceItemCount[i] = questRecord[83+i].GetUInt16(); + ItemDropQuantity[i] = questRecord[83+i].GetUInt16(); for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) RequiredItemId[i] = questRecord[87+i].GetUInt32(); @@ -102,6 +102,9 @@ Quest::Quest(Field* questRecord) for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) ObjectiveText[i] = questRecord[100+i].GetString(); + EmoteOnIncomplete = 0; + EmoteOnComplete = 0; + //int32 VerifiedBuild = questRecord[104].GetInt32(); _reqItemsCount = 0; @@ -169,7 +172,7 @@ void Quest::LoadQuestTemplateAddon(Field* fields) RequiredMaxRepFaction = fields[12].GetUInt16(); RequiredMinRepValue = fields[13].GetInt32(); RequiredMaxRepValue = fields[14].GetInt32(); - SourceItemIdCount = fields[15].GetUInt8(); + StartItemCount = fields[15].GetUInt8(); SpecialFlags = fields[16].GetUInt8(); if (SpecialFlags & QUEST_SPECIAL_FLAGS_AUTO_ACCEPT) @@ -191,7 +194,7 @@ uint32 Quest::XPValue(Player* player) const else if (diffFactor > 10) diffFactor = 10; - uint32 xp = diffFactor * xpentry->Exp[RewardXPId] / 10; + uint32 xp = diffFactor * xpentry->Exp[RewardXPDifficulty] / 10; if (xp <= 100) xp = 5 * ((xp + 2) / 5); else if (xp <= 500) @@ -210,11 +213,11 @@ uint32 Quest::XPValue(Player* player) const int32 Quest::GetRewOrReqMoney() const { // RequiredMoney: the amount is the negative copper sum. - if (RewardOrRequiredMoney <= 0) - return RewardOrRequiredMoney; + if (RewardMoney <= 0) + return RewardMoney; // RewardMoney: the positive amount - return int32(RewardOrRequiredMoney * sWorld->getRate(RATE_MONEY_QUEST)); + return int32(RewardMoney * sWorld->getRate(RATE_MONEY_QUEST)); } uint32 Quest::GetRewMoneyMaxLevel() const @@ -224,7 +227,7 @@ uint32 Quest::GetRewMoneyMaxLevel() const return 0; // Else, return the rewarded copper sum modified by the rate - return uint32(RewardMoneyMaxLevel * sWorld->getRate(RATE_MONEY_MAX_LEVEL_QUEST)); + return uint32(RewardBonusMoney * sWorld->getRate(RATE_MONEY_MAX_LEVEL_QUEST)); } bool Quest::IsAutoAccept() const diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h index 78fd065e9bd..91b4a3181f5 100644 --- a/src/server/game/Quests/QuestDef.h +++ b/src/server/game/Quests/QuestDef.h @@ -182,7 +182,7 @@ struct QuestLocale StringVector Objectives; StringVector OfferRewardText; StringVector RequestItemsText; - StringVector EndText; + StringVector AreaDescription; StringVector CompletedText; std::vector< StringVector > ObjectiveText; }; @@ -217,7 +217,7 @@ class Quest int32 GetQuestLevel() const { return Level; } uint32 GetType() const { return Type; } uint32 GetRequiredClasses() const { return RequiredClasses; } - uint32 GetRequiredRaces() const { return RequiredRaces; } + uint32 GetAllowableRaces() const { return AllowableRaces; } uint32 GetRequiredSkill() const { return RequiredSkillId; } uint32 GetRequiredSkillValue() const { return RequiredSkillPoints; } uint32 GetRepObjectiveFaction() const { return RequiredFactionId1; } @@ -229,38 +229,38 @@ class Quest uint32 GetRequiredMaxRepFaction() const { return RequiredMaxRepFaction; } int32 GetRequiredMaxRepValue() const { return RequiredMaxRepValue; } uint32 GetSuggestedPlayers() const { return SuggestedPlayers; } - uint32 GetLimitTime() const { return LimitTime; } + uint32 GetTimeAllowed() const { return TimeAllowed; } int32 GetPrevQuestId() const { return PrevQuestId; } int32 GetNextQuestId() const { return NextQuestId; } int32 GetExclusiveGroup() const { return ExclusiveGroup; } - uint32 GetNextQuestInChain() const { return NextQuestIdChain; } + uint32 GetNextQuestInChain() const { return RewardNextQuest; } uint32 GetCharTitleId() const { return RewardTitleId; } uint32 GetPlayersSlain() const { return RequiredPlayerKills; } uint32 GetBonusTalents() const { return RewardTalents; } int32 GetRewArenaPoints() const {return RewardArenaPoints; } - uint32 GetXPId() const { return RewardXPId; } - uint32 GetSrcItemId() const { return SourceItemId; } - uint32 GetSrcItemCount() const { return SourceItemIdCount; } + uint32 GetXPId() const { return RewardXPDifficulty; } + uint32 GetSrcItemId() const { return StartItem; } + uint32 GetSrcItemCount() const { return StartItemCount; } uint32 GetSrcSpell() const { return SourceSpellid; } std::string const& GetTitle() const { return Title; } std::string const& GetDetails() const { return Details; } std::string const& GetObjectives() const { return Objectives; } std::string const& GetOfferRewardText() const { return OfferRewardText; } std::string const& GetRequestItemsText() const { return RequestItemsText; } - std::string const& GetEndText() const { return EndText; } + std::string const& GetAreaDescription() const { return AreaDescription; } std::string const& GetCompletedText() const { return CompletedText; } int32 GetRewOrReqMoney() const; uint32 GetRewHonorAddition() const { return RewardHonor; } - float GetRewHonorMultiplier() const { return RewardHonorMultiplier; } + float GetRewHonorMultiplier() const { return RewardKillHonor; } uint32 GetRewMoneyMaxLevel() const; // use in XP calculation at client - uint32 GetRewSpell() const { return RewardSpell; } - int32 GetRewSpellCast() const { return RewardSpellCast; } + uint32 GetRewSpell() const { return RewardDisplaySpell; } + int32 GetRewSpellCast() const { return RewardSpell; } uint32 GetRewMailTemplateId() const { return RewardMailTemplateId; } uint32 GetRewMailDelaySecs() const { return RewardMailDelay; } - uint32 GetPointMapId() const { return PointMapId; } - float GetPointX() const { return PointX; } - float GetPointY() const { return PointY; } - uint32 GetPointOpt() const { return PointOption; } + uint32 GetPOIContinent() const { return POIContinent; } + float GetPOIx() const { return POIx; } + float GetPOIy() const { return POIy; } + uint32 GetPointOpt() const { return POIPriority; } uint32 GetIncompleteEmote() const { return EmoteOnIncomplete; } uint32 GetCompleteEmote() const { return EmoteOnComplete; } bool IsRepeatable() const { return SpecialFlags & QUEST_SPECIAL_FLAGS_REPEATABLE; } @@ -281,8 +281,8 @@ class Quest std::string ObjectiveText[QUEST_OBJECTIVES_COUNT]; uint32 RequiredItemId[QUEST_ITEM_OBJECTIVES_COUNT]; uint32 RequiredItemCount[QUEST_ITEM_OBJECTIVES_COUNT]; - uint32 RequiredSourceItemId[QUEST_SOURCE_ITEM_IDS_COUNT]; - uint32 RequiredSourceItemCount[QUEST_SOURCE_ITEM_IDS_COUNT]; + uint32 ItemDrop[QUEST_SOURCE_ITEM_IDS_COUNT]; + uint32 ItemDropQuantity[QUEST_SOURCE_ITEM_IDS_COUNT]; int32 RequiredNpcOrGo[QUEST_OBJECTIVES_COUNT]; // >0 Creature <0 Gameobject uint32 RequiredNpcOrGoCount[QUEST_OBJECTIVES_COUNT]; uint32 RewardChoiceItemId[QUEST_REWARD_CHOICES_COUNT]; @@ -322,38 +322,38 @@ class Quest uint32 MinLevel; int32 Level; uint32 Type; - uint32 RequiredRaces; + uint32 AllowableRaces; uint32 RequiredFactionId1; int32 RequiredFactionValue1; uint32 RequiredFactionId2; int32 RequiredFactionValue2; uint32 SuggestedPlayers; - uint32 LimitTime; + uint32 TimeAllowed; uint32 Flags; uint32 RewardTitleId; uint32 RequiredPlayerKills; uint32 RewardTalents; int32 RewardArenaPoints; - uint32 NextQuestIdChain; - uint32 RewardXPId; - uint32 SourceItemId; + uint32 RewardNextQuest; + uint32 RewardXPDifficulty; + uint32 StartItem; std::string Title; std::string Details; std::string Objectives; std::string OfferRewardText; std::string RequestItemsText; - std::string EndText; + std::string AreaDescription; std::string CompletedText; uint32 RewardHonor; - float RewardHonorMultiplier; - int32 RewardOrRequiredMoney; - uint32 RewardMoneyMaxLevel; - uint32 RewardSpell; - int32 RewardSpellCast; - uint32 PointMapId; - float PointX; - float PointY; - uint32 PointOption; + float RewardKillHonor; + int32 RewardMoney; + uint32 RewardBonusMoney; + uint32 RewardDisplaySpell; + int32 RewardSpell; + uint32 POIContinent; + float POIx; + float POIy; + uint32 POIPriority; uint32 EmoteOnIncomplete; uint32 EmoteOnComplete; @@ -372,7 +372,7 @@ class Quest int32 RequiredMinRepValue = 0; uint32 RequiredMaxRepFaction = 0; int32 RequiredMaxRepValue = 0; - uint32 SourceItemIdCount = 0; + uint32 StartItemCount = 0; uint32 SpecialFlags = 0; // custom flags, not sniffed/WDB }; diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index aed829a7b57..0ece05f1d93 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -108,7 +108,7 @@ class ScriptRegistry TC_LOG_ERROR("scripts", "Script '%s' already assigned with the same script name, so the script can't work.", script->GetName().c_str()); - ASSERT(false); // Error that should be fixed ASAP. + ABORT(); // Error that should be fixed ASAP. } } else @@ -960,7 +960,7 @@ bool ScriptMgr::OnAreaTrigger(Player* player, AreaTriggerEntry const* trigger) Battleground* ScriptMgr::CreateBattleground(BattlegroundTypeId /*typeId*/) { /// @todo Implement script-side battlegrounds. - ASSERT(false); + ABORT(); return NULL; } diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 4eea5eed03d..e380373f4c4 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -323,7 +323,7 @@ Aura* Aura::Create(SpellInfo const* spellproto, uint8 effMask, WorldObject* owne aura = new DynObjAura(spellproto, effMask, owner, caster, baseAmount, castItem, casterGUID); break; default: - ASSERT(false); + ABORT(); return NULL; } // aura can be removed in Unit::_AddAura call @@ -437,7 +437,7 @@ void Aura::_UnapplyForTarget(Unit* target, Unit* caster, AuraApplication * auraA { TC_LOG_ERROR("spells", "Aura::_UnapplyForTarget, target:%u, caster:%u, spell:%u was not found in owners application map!", target->GetGUIDLow(), caster ? caster->GetGUIDLow() : 0, auraApp->GetBase()->GetSpellInfo()->Id); - ASSERT(false); + ABORT(); } // aura has to be already applied @@ -528,7 +528,7 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply) else { // ok, we have one unit twice in target map (impossible, but...) - ASSERT(false); + ABORT(); } } @@ -586,7 +586,7 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply) TC_LOG_FATAL("spells", "Aura %u: Owner %s (map %u) is not in the same map as target %s (map %u).", GetSpellInfo()->Id, GetOwner()->GetName().c_str(), GetOwner()->IsInWorld() ? GetOwner()->GetMap()->GetId() : uint32(-1), itr->first->GetName().c_str(), itr->first->IsInWorld() ? itr->first->GetMap()->GetId() : uint32(-1)); - ASSERT(false); + ABORT(); } itr->first->_CreateAuraApplication(this, itr->second); ++itr; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 03f14d1cdc8..ca6946554d4 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -6586,7 +6586,7 @@ SpellEvent::~SpellEvent() { TC_LOG_ERROR("spells", "~SpellEvent: %s %u tried to delete non-deletable spell %u. Was not deleted, causes memory leak.", (m_Spell->GetCaster()->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), m_Spell->GetCaster()->GetGUIDLow(), m_Spell->m_spellInfo->Id); - ASSERT(false); + ABORT(); } } @@ -7044,7 +7044,7 @@ bool Spell::CallScriptEffectHandlers(SpellEffIndex effIndex, SpellEffectHandleMo hookType = SPELL_SCRIPT_HOOK_EFFECT_HIT_TARGET; break; default: - ASSERT(false); + ABORT(); return false; } (*scritr)->_PrepareScriptCall(hookType); diff --git a/src/server/scripts/Commands/cs_lfg.cpp b/src/server/scripts/Commands/cs_lfg.cpp index d1662f3a97c..8bb64a454d2 100644 --- a/src/server/scripts/Commands/cs_lfg.cpp +++ b/src/server/scripts/Commands/cs_lfg.cpp @@ -150,7 +150,7 @@ public: static bool HandleLfgQueueInfoCommand(ChatHandler* handler, char const* args) { - handler->SendSysMessage(sLFGMgr->DumpQueueInfo(*args != '\0').c_str()); + handler->SendSysMessage(sLFGMgr->DumpQueueInfo(*args != '\0').c_str(), true); return true; } diff --git a/src/server/scripts/Commands/cs_ticket.cpp b/src/server/scripts/Commands/cs_ticket.cpp index 5fc3cc618e5..b609dfe18dd 100644 --- a/src/server/scripts/Commands/cs_ticket.cpp +++ b/src/server/scripts/Commands/cs_ticket.cpp @@ -113,7 +113,7 @@ public: // If assigned to different player other than current, leave //! Console can override though - Player* player = handler->GetSession() ? handler->GetSession()->GetPlayer() : NULL; + Player* player = handler->GetSession() ? handler->GetSession()->GetPlayer() : nullptr; if (player && ticket->IsAssignedNotTo(player->GetGUID())) { handler->PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->GetId(), target.c_str()); @@ -146,7 +146,7 @@ public: // Ticket should be assigned to the player who tries to close it. // Console can override though - Player* player = handler->GetSession() ? handler->GetSession()->GetPlayer() : NULL; + Player* player = handler->GetSession() ? handler->GetSession()->GetPlayer() : nullptr; if (player && ticket->IsAssignedNotTo(player->GetGUID())) { handler->PSendSysMessage(LANG_COMMAND_TICKETCANNOTCLOSE, ticket->GetId()); @@ -190,7 +190,7 @@ public: // Cannot comment ticket assigned to someone else //! Console excluded - Player* player = handler->GetSession() ? handler->GetSession()->GetPlayer() : NULL; + Player* player = handler->GetSession() ? handler->GetSession()->GetPlayer() : nullptr; if (player && ticket->IsAssignedNotTo(player->GetGUID())) { handler->PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->GetId()); @@ -220,7 +220,9 @@ public: if (!*args) return false; - uint32 ticketId = atoi(args); + char* ticketIdStr = strtok((char*)args, " "); + uint32 ticketId = atoi(ticketIdStr); + GmTicket* ticket = sTicketMgr->GetTicket(ticketId); if (!ticket || ticket->IsClosed() || ticket->IsCompleted()) { @@ -228,6 +230,21 @@ public: return true; } + char* response = strtok(NULL, "\n"); + if (response) + { + // Cannot add response to ticket, assigned to someone else + //! Console excluded + Player* player = handler->GetSession() ? handler->GetSession()->GetPlayer() : nullptr; + if (player && ticket->IsAssignedNotTo(player->GetGUID())) + { + handler->PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->GetId()); + return true; + } + + ticket->AppendResponse(response); + } + if (Player* player = ticket->GetPlayer()) ticket->SendResponse(player->GetSession()); @@ -476,7 +493,7 @@ public: // Cannot add response to ticket, assigned to someone else //! Console excluded - Player* player = handler->GetSession() ? handler->GetSession()->GetPlayer() : NULL; + Player* player = handler->GetSession() ? handler->GetSession()->GetPlayer() : nullptr; if (player && ticket->IsAssignedNotTo(player->GetGUID())) { handler->PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->GetId()); diff --git a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp index f5842181358..7c85c5f73b9 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp @@ -21,7 +21,7 @@ enum Spells { - SPELL_HATEFUL_STRIKE = 41926, + SPELL_HATEFUL_STRIKE = 28308, SPELL_FRENZY = 28131, SPELL_BERSERK = 26662, SPELL_SLIME_BOLT = 32309 @@ -33,7 +33,7 @@ enum Yells SAY_SLAY = 1, SAY_DEATH = 2, EMOTE_BERSERK = 3, - EMOTE_ENRAGE = 4 + EMOTE_FRENZY = 4 }; enum Events @@ -49,6 +49,11 @@ enum Misc ACHIEV_MAKE_QUICK_WERK_OF_HIM_STARTING_EVENT = 10286 }; +enum HatefulThreatAmounts +{ + HATEFUL_THREAT_AMT = 1000, +}; + class boss_patchwerk : public CreatureScript { public: @@ -92,8 +97,8 @@ public: _EnterCombat(); Enraged = false; Talk(SAY_AGGRO); - events.ScheduleEvent(EVENT_HATEFUL, 1000); - events.ScheduleEvent(EVENT_BERSERK, 360000); + events.ScheduleEvent(EVENT_HATEFUL, 1 * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_BERSERK, 6 * MINUTE * IN_MILLISECONDS); instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_MAKE_QUICK_WERK_OF_HIM_STARTING_EVENT); } @@ -111,37 +116,68 @@ public: { case EVENT_HATEFUL: { - //Cast Hateful strike on the player with the highest - //amount of HP within melee distance - uint32 MostHP = 0; - Unit* pMostHPTarget = NULL; + // Hateful Strike targets the highest non-MT threat in melee range on 10man + // and the higher HP target out of the two highest non-MT threats in melee range on 25man + float MostThreat = 0.0f; + Unit* secondThreatTarget = NULL; + Unit* thirdThreatTarget = NULL; + std::list<HostileReference*>::const_iterator i = me->getThreatManager().getThreatList().begin(); for (; i != me->getThreatManager().getThreatList().end(); ++i) - { + { // find second highest Unit* target = (*i)->getTarget(); - if (target->IsAlive() && target != me->GetVictim() && target->GetHealth() > MostHP && me->IsWithinMeleeRange(target)) + if (target->IsAlive() && target != me->GetVictim() && (*i)->getThreat() >= MostThreat && me->IsWithinMeleeRange(target)) + { + MostThreat = (*i)->getThreat(); + secondThreatTarget = target; + } + } + + if (secondThreatTarget && Is25ManRaid()) + { // find third highest + MostThreat = 0.0f; + i = me->getThreatManager().getThreatList().begin(); + for (; i != me->getThreatManager().getThreatList().end(); ++i) { - MostHP = target->GetHealth(); - pMostHPTarget = target; + Unit* target = (*i)->getTarget(); + if (target->IsAlive() && target != me->GetVictim() && target != secondThreatTarget && (*i)->getThreat() >= MostThreat && me->IsWithinMeleeRange(target)) + { + MostThreat = (*i)->getThreat(); + thirdThreatTarget = target; + } } } - if (!pMostHPTarget) - pMostHPTarget = me->GetVictim(); + Unit* pHatefulTarget = NULL; + if (!thirdThreatTarget) + pHatefulTarget = secondThreatTarget; + else if (secondThreatTarget) + pHatefulTarget = (secondThreatTarget->GetHealth() < thirdThreatTarget->GetHealth()) ? thirdThreatTarget : secondThreatTarget; + + if (!pHatefulTarget) + pHatefulTarget = me->GetVictim(); + + DoCast(pHatefulTarget, SPELL_HATEFUL_STRIKE, true); - DoCast(pMostHPTarget, SPELL_HATEFUL_STRIKE, true); + // add threat to highest threat targets + if (me->GetVictim() && me->IsWithinMeleeRange(me->GetVictim())) + me->getThreatManager().addThreat(me->GetVictim(), HATEFUL_THREAT_AMT); + if (secondThreatTarget) + me->getThreatManager().addThreat(secondThreatTarget, HATEFUL_THREAT_AMT); + if (thirdThreatTarget) + me->getThreatManager().addThreat(thirdThreatTarget, HATEFUL_THREAT_AMT); // this will only ever be used in 25m - events.ScheduleEvent(EVENT_HATEFUL, 1000); + events.ScheduleEvent(EVENT_HATEFUL, 1 * IN_MILLISECONDS); break; } case EVENT_BERSERK: DoCast(me, SPELL_BERSERK, true); Talk(EMOTE_BERSERK); - events.ScheduleEvent(EVENT_SLIME, 2000); + events.ScheduleEvent(EVENT_SLIME, 2 * IN_MILLISECONDS); break; case EVENT_SLIME: DoCastVictim(SPELL_SLIME_BOLT, true); - events.ScheduleEvent(EVENT_SLIME, 2000); + events.ScheduleEvent(EVENT_SLIME, 2 * IN_MILLISECONDS); break; } } @@ -149,7 +185,7 @@ public: if (!Enraged && HealthBelowPct(5)) { DoCast(me, SPELL_FRENZY, true); - Talk(EMOTE_ENRAGE); + Talk(EMOTE_FRENZY); Enraged = true; } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp b/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp index ee482c23d1b..02a7aa570e5 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp @@ -43,6 +43,7 @@ enum Spells SPELL_BERSERK = 26662, SPELL_DIES = 29357, SPELL_CHILL = 28547, + SPELL_CHECK_RESISTS = 60539, }; enum Phases @@ -67,7 +68,8 @@ enum Events EVENT_EXPLOSION, EVENT_LAND, EVENT_GROUND, - EVENT_BIRTH + EVENT_BIRTH, + EVENT_CHECK_RESISTS }; enum Misc @@ -90,10 +92,9 @@ class boss_sapphiron : public CreatureScript struct boss_sapphironAI : public BossAI { boss_sapphironAI(Creature* creature) : - BossAI(creature, BOSS_SAPPHIRON), _map(me->GetMap()) + BossAI(creature, BOSS_SAPPHIRON), _iceboltCount(0), _map(me->GetMap()) { Initialize(); - _iceboltCount = 0; } void Initialize() @@ -101,7 +102,6 @@ class boss_sapphiron : public CreatureScript _phase = PHASE_NULL; _canTheHundredClub = true; - _checkFrostResistTimer = 5 * IN_MILLISECONDS; } void InitializeAI() override @@ -123,7 +123,16 @@ class boss_sapphiron : public CreatureScript _Reset(); if (_phase == PHASE_FLIGHT) + { ClearIceBlock(); + me->SetReactState(REACT_AGGRESSIVE); + if (me->IsHovering()) + { + me->HandleEmoteCommand(EMOTE_ONESHOT_LAND); + me->SetHover(false); + } + me->SetDisableGravity(false); + } Initialize(); } @@ -134,22 +143,30 @@ class boss_sapphiron : public CreatureScript me->CastSpell(me, SPELL_FROST_AURA, true); + DoCast(me, SPELL_CHECK_RESISTS); + events.ScheduleEvent(EVENT_CHECK_RESISTS, 30 * IN_MILLISECONDS); events.ScheduleEvent(EVENT_BERSERK, 15 * MINUTE * IN_MILLISECONDS); EnterPhaseGround(); - - CheckPlayersFrostResist(); } void SpellHitTarget(Unit* target, SpellInfo const* spell) override { - if (spell->Id == SPELL_ICEBOLT) + switch(spell->Id) { - IceBlockMap::iterator itr = _iceblocks.find(target->GetGUID()); - if (itr != _iceblocks.end() && !itr->second) + case SPELL_ICEBOLT: { - if (GameObject* iceblock = me->SummonGameObject(GO_ICEBLOCK, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, 0, 0, 0, 0, 25)) - itr->second = iceblock->GetGUID(); + IceBlockMap::iterator itr = _iceblocks.find(target->GetGUID()); + if (itr != _iceblocks.end() && !itr->second) + { + if (GameObject* iceblock = me->SummonGameObject(GO_ICEBLOCK, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, 0, 0, 0, 0, 25)) + itr->second = iceblock->GetGUID(); + } + break; } + case SPELL_CHECK_RESISTS: + if (target && target->GetResistance(SPELL_SCHOOL_FROST) > MAX_FROST_RESISTANCE) + _canTheHundredClub = false; + break; } } @@ -157,8 +174,6 @@ class boss_sapphiron : public CreatureScript { _JustDied(); me->CastSpell(me, SPELL_DIES, true); - - CheckPlayersFrostResist(); } void MovementInform(uint32 /*type*/, uint32 id) override @@ -176,22 +191,6 @@ class boss_sapphiron : public CreatureScript } } - void CheckPlayersFrostResist() - { - if (_canTheHundredClub && _map && _map->IsRaid()) - { - Map::PlayerList const &players = _map->GetPlayers(); - for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) - { - if (itr->GetSource()->GetResistance(SPELL_SCHOOL_FROST) > MAX_FROST_RESISTANCE) - { - _canTheHundredClub = false; - break; - } - } - } - } - void EnterPhaseGround() { _phase = PHASE_GROUND; @@ -235,23 +234,16 @@ class boss_sapphiron : public CreatureScript if ((_phase != PHASE_BIRTH && !UpdateVictim()) || !CheckInRoom()) return; - if (_canTheHundredClub) - { - if (_checkFrostResistTimer <= diff) - { - CheckPlayersFrostResist(); - _checkFrostResistTimer = 5 * IN_MILLISECONDS; - } - else - _checkFrostResistTimer -= diff; - } - if (_phase == PHASE_GROUND) { while (uint32 eventId = events.ExecuteEvent()) { switch (eventId) { + case EVENT_CHECK_RESISTS: + DoCast(me, SPELL_CHECK_RESISTS); + events.ScheduleEvent(EVENT_CHECK_RESISTS, 30 * IN_MILLISECONDS); + return; case EVENT_BERSERK: Talk(EMOTE_ENRAGE); DoCast(me, SPELL_BERSERK); @@ -270,7 +262,6 @@ class boss_sapphiron : public CreatureScript return; case EVENT_BLIZZARD: { - //DoCastAOE(SPELL_SUMMON_BLIZZARD); if (Creature* summon = DoSummon(NPC_BLIZZARD, me, 0.0f, urand(25, 30) * IN_MILLISECONDS, TEMPSUMMON_TIMED_DESPAWN)) summon->GetMotionMaster()->MoveRandom(40); events.ScheduleEvent(EVENT_BLIZZARD, RAID_MODE(20, 7) * IN_MILLISECONDS, 0, PHASE_GROUND); @@ -300,9 +291,14 @@ class boss_sapphiron : public CreatureScript { switch (eventId) { + case EVENT_CHECK_RESISTS: + DoCast(me, SPELL_CHECK_RESISTS); + events.ScheduleEvent(EVENT_CHECK_RESISTS, 30 * IN_MILLISECONDS); + return; case EVENT_LIFTOFF: Talk(EMOTE_AIR_PHASE); me->SetDisableGravity(true); + me->SetHover(true); events.ScheduleEvent(EVENT_ICEBOLT, 1500); _iceboltCount = RAID_MODE(2, 3); return; @@ -346,6 +342,7 @@ class boss_sapphiron : public CreatureScript case EVENT_LAND: me->HandleEmoteCommand(EMOTE_ONESHOT_LAND); Talk(EMOTE_GROUND_PHASE); + me->SetHover(false); me->SetDisableGravity(false); events.ScheduleEvent(EVENT_GROUND, 1500); return; @@ -406,7 +403,6 @@ class boss_sapphiron : public CreatureScript uint32 _iceboltCount; IceBlockMap _iceblocks; bool _canTheHundredClub; - uint32 _checkFrostResistTimer; Map* _map; }; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp index 61d64413178..b31436f656a 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp @@ -97,9 +97,6 @@ enum Creatures NPC_MIMIRON_TARGET_BEACON = 33369, NPC_HODIR_TARGET_BEACON = 33108, NPC_FREYA_TARGET_BEACON = 33366, - NPC_LOREKEEPER = 33686, // Hard mode starter - NPC_BRANZ_BRONZBEARD = 33579, - NPC_DELORAH = 33701, NPC_ULDUAR_GAUNTLET_GENERATOR = 33571, // Trigger tied to towers }; @@ -1167,9 +1164,49 @@ class npc_freya_ward_summon : public CreatureScript } }; -//npc lore keeper -#define GOSSIP_ITEM_1 "Activate secondary defensive systems" -#define GOSSIP_ITEM_2 "Confirmed" +enum BrannBronzebeardGossips +{ + GOSSIP_MENU_BRANN_BRONZEBEARD = 10355, + GOSSIP_OPTION_BRANN_BRONZEBEARD = 0 +}; + +class npc_brann_bronzebeard_ulduar_intro : public CreatureScript +{ + public: + npc_brann_bronzebeard_ulduar_intro() : CreatureScript("npc_brann_bronzebeard_ulduar_intro") { } + + struct npc_brann_bronzebeard_ulduar_introAI : public ScriptedAI + { + npc_brann_bronzebeard_ulduar_introAI(Creature* creature) : ScriptedAI(creature) + { + _instance = creature->GetInstanceScript(); + } + + void sGossipSelect(Player* player, uint32 menuId, uint32 gossipListId) override + { + if (menuId == GOSSIP_MENU_BRANN_BRONZEBEARD && gossipListId == GOSSIP_OPTION_BRANN_BRONZEBEARD) + { + player->PlayerTalkClass->SendCloseGossip(); + if (Creature* loreKeeper = _instance->GetCreature(DATA_LORE_KEEPER_OF_NORGANNON)) + loreKeeper->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + } + } + + private: + InstanceScript* _instance; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_brann_bronzebeard_ulduar_introAI>(creature); + } +}; + +enum LoreKeeperGossips +{ + GOSSIP_MENU_LORE_KEEPER = 10477, + GOSSIP_OPTION_LORE_KEEPER = 0 +}; class npc_lorekeeper : public CreatureScript { @@ -1180,6 +1217,7 @@ class npc_lorekeeper : public CreatureScript { npc_lorekeeperAI(Creature* creature) : ScriptedAI(creature) { + _instance = creature->GetInstanceScript(); } void DoAction(int32 action) override @@ -1187,66 +1225,42 @@ class npc_lorekeeper : public CreatureScript // Start encounter if (action == ACTION_SPAWN_VEHICLES) { - for (int32 i = 0; i < RAID_MODE(2, 5); ++i) + for (uint8 i = 0; i < RAID_MODE(2, 5); ++i) DoSummon(VEHICLE_SIEGE, PosSiege[i], 3000, TEMPSUMMON_CORPSE_TIMED_DESPAWN); - for (int32 i = 0; i < RAID_MODE(2, 5); ++i) + for (uint8 i = 0; i < RAID_MODE(2, 5); ++i) DoSummon(VEHICLE_CHOPPER, PosChopper[i], 3000, TEMPSUMMON_CORPSE_TIMED_DESPAWN); - for (int32 i = 0; i < RAID_MODE(2, 5); ++i) + for (uint8 i = 0; i < RAID_MODE(2, 5); ++i) DoSummon(VEHICLE_DEMOLISHER, PosDemolisher[i], 3000, TEMPSUMMON_CORPSE_TIMED_DESPAWN); - return; } } - }; - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override - { - player->CLOSE_GOSSIP_MENU(); - InstanceScript* instance = creature->GetInstanceScript(); - if (!instance) - return true; - switch (action) + void sGossipSelect(Player* player, uint32 menuId, uint32 gossipListId) override { - case GOSSIP_ACTION_INFO_DEF+1: - player->PrepareGossipMenu(creature); - instance->instance->LoadGrid(364, -16); //make sure leviathan is loaded + if (menuId == GOSSIP_MENU_LORE_KEEPER && gossipListId == GOSSIP_OPTION_LORE_KEEPER) + { + player->PlayerTalkClass->SendCloseGossip(); + _instance->instance->LoadGrid(364, -16); // make sure leviathan is loaded - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - if (Creature* leviathan = instance->instance->GetCreature(instance->GetGuidData(BOSS_LEVIATHAN))) + if (Creature* leviathan = _instance->instance->GetCreature(_instance->GetGuidData(BOSS_LEVIATHAN))) { leviathan->AI()->DoAction(ACTION_START_HARD_MODE); - creature->SetVisible(false); - creature->AI()->DoAction(ACTION_SPAWN_VEHICLES); // spawn the vehicles - if (Creature* Delorah = creature->FindNearestCreature(NPC_DELORAH, 1000, true)) + me->SetVisible(false); + DoAction(ACTION_SPAWN_VEHICLES); // spawn the vehicles + if (Creature* delorah = _instance->GetCreature(DATA_DELLORAH)) { - if (Creature* Branz = creature->FindNearestCreature(NPC_BRANZ_BRONZBEARD, 1000, true)) + if (Creature* brann = _instance->GetCreature(DATA_BRANN_BRONZEBEARD_INTRO)) { - Delorah->GetMotionMaster()->MovePoint(0, Branz->GetPositionX()-4, Branz->GetPositionY(), Branz->GetPositionZ()); - /// @todo Delorah->AI()->Talk(xxxx, Branz->GetGUID()); when reached at branz + delorah->GetMotionMaster()->MovePoint(0, brann->GetPositionX() - 4, brann->GetPositionY(), brann->GetPositionZ()); + /// @todo delorah->AI()->Talk(xxxx, brann->GetGUID()); when reached at branz } } } - break; + } } - return true; - } - - bool OnGossipHello(Player* player, Creature* creature) override - { - InstanceScript* instance = creature->GetInstanceScript(); - if (instance && instance->GetData(BOSS_LEVIATHAN) != DONE && player) - { - player->PrepareGossipMenu(creature); - - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); - } - return true; - } + private: + InstanceScript* _instance; + }; CreatureAI* GetAI(Creature* creature) const override { @@ -1254,56 +1268,6 @@ class npc_lorekeeper : public CreatureScript } }; -//enable hardmode -////npc_brann_bronzebeard this requires more work involving area triggers. if reached this guy speaks through his radio.. -//#define GOSSIP_ITEM_1 "xxxxx" -//#define GOSSIP_ITEM_2 "xxxxx" -// -/* -class npc_brann_bronzebeard : public CreatureScript -{ -public: - npc_brann_bronzebeard() : CreatureScript("npc_brann_bronzebeard") { } - - //bool OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action) override - //{ - // player->PlayerTalkClass->ClearMenus(); - // switch (action) - // { - // case GOSSIP_ACTION_INFO_DEF+1: - // if (player) - // { - // player->PrepareGossipMenu(creature); - // - // player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - // player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); - // } - // break; - // case GOSSIP_ACTION_INFO_DEF+2: - // if (player) - // player->CLOSE_GOSSIP_MENU(); - // if (Creature* Lorekeeper = creature->FindNearestCreature(NPC_LOREKEEPER, 1000, true)) //lore keeper of lorgannon - // Lorekeeper->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - // break; - // } - // return true; - //} - //bool OnGossipHello(Player* player, Creature* creature) override - //{ - // InstanceScript* instance = creature->GetInstanceScript(); - // if (instance && instance->GetData(BOSS_LEVIATHAN) !=DONE) - // { - // player->PrepareGossipMenu(creature); - // - // player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - // player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); - // } - // return true; - //} - // -} -*/ - class go_ulduar_tower : public GameObjectScript { public: @@ -1836,8 +1800,8 @@ void AddSC_boss_flame_leviathan() new npc_hodirs_fury(); new npc_freyas_ward(); new npc_freya_ward_summon(); + new npc_brann_bronzebeard_ulduar_intro(); new npc_lorekeeper(); - // new npc_brann_bronzebeard(); new go_ulduar_tower(); new achievement_three_car_garage_demolisher(); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp index 818bb0041a9..6958b5d78a5 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp @@ -749,8 +749,8 @@ class boss_elder_brightleaf : public CreatureScript case EVENT_SOLAR_FLARE: { uint8 stackAmount = 0; - if (me->GetAura(SPELL_FLUX_AURA)) - stackAmount = me->GetAura(SPELL_FLUX_AURA)->GetStackAmount(); + if (Aura* aura = me->GetAura(SPELL_FLUX_AURA)) + stackAmount = aura->GetStackAmount(); me->CastCustomSpell(SPELL_SOLAR_FLARE, SPELLVALUE_MAX_TARGETS, stackAmount, me, false); events.ScheduleEvent(EVENT_SOLAR_FLARE, urand(5000, 10000)); break; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp index 0c7df100f60..f2edfa816a0 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp @@ -54,6 +54,15 @@ MinionData const minionData[] = { 0, 0, } }; +ObjectData const creatureData[] = +{ + { NPC_BRANN_BRONZEBEARD_INTRO, DATA_BRANN_BRONZEBEARD_INTRO }, + { NPC_LORE_KEEPER_OF_NORGANNON, DATA_LORE_KEEPER_OF_NORGANNON }, + { NPC_HIGH_EXPLORER_DELLORAH, DATA_DELLORAH }, + { NPC_BRONZEBEARD_RADIO, DATA_BRONZEBEARD_RADIO }, + { 0, 0, } +}; + class instance_ulduar : public InstanceMapScript { public: @@ -68,6 +77,7 @@ class instance_ulduar : public InstanceMapScript LoadDoorData(doorData); LoadMinionData(minionData); + LoadObjectData(creatureData, nullptr); _algalonTimer = 61; _maxArmorItemLevel = 0; @@ -420,6 +430,8 @@ class instance_ulduar : public InstanceMapScript algalon->AI()->JustSummoned(creature); break; } + + InstanceScript::OnCreatureCreate(creature); } void OnCreatureRemove(Creature* creature) override @@ -446,6 +458,8 @@ class instance_ulduar : public InstanceMapScript default: break; } + + InstanceScript::OnCreatureRemove(creature); } void OnGameObjectCreate(GameObject* gameObject) override diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h index 9f640c410ef..834ab32864f 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h @@ -80,6 +80,23 @@ enum UlduarNPCs NPC_YOGG_SARON = 33288, NPC_ALGALON = 32871, + // Flame Leviathan + NPC_ULDUAR_COLOSSUS = 33237, + NPC_BRANN_BRONZEBEARD_INTRO = 33579, + NPC_BRANN_BRONZEBEARD_FLYING_MACHINE = 34119, + NPC_BRANN_S_FLYING_MACHINE = 34120, + NPC_ARCHMAGE_PENTARUS = 33624, + NPC_ARCHMAGE_RHYDIAN = 33696, + NPC_LORE_KEEPER_OF_NORGANNON = 33686, + NPC_HIGH_EXPLORER_DELLORAH = 33701, + NPC_BRONZEBEARD_RADIO = 34054, + NPC_FLAME_LEVIATHAN = 33113, + NPC_FLAME_LEVIATHAN_SEAT = 33114, + NPC_FLAME_LEVIATHAN_TURRET = 33139, + NPC_LEVIATHAN_DEFENSE_TURRET = 33142, + NPC_OVERLOAD_CONTROL_DEVICE = 33143, + NPC_ORBITAL_SUPPORT = 34286, + // Mimiron NPC_LEVIATHAN_MKII = 33432, NPC_VX_001 = 33651, @@ -382,6 +399,12 @@ enum UlduarData DATA_UNIVERSE_GLOBE, DATA_ALGALON_TRAPDOOR, DATA_BRANN_BRONZEBEARD_ALG, + + // Misc + DATA_BRANN_BRONZEBEARD_INTRO, + DATA_LORE_KEEPER_OF_NORGANNON, + DATA_DELLORAH, + DATA_BRONZEBEARD_RADIO }; enum UlduarWorldStates diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 68c115f9faf..0ab7c2fcb54 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -614,6 +614,47 @@ class spell_gen_burn_brutallus : public SpellScriptLoader } }; +// 48750 - Burning Depths Necrolyte Image +class spell_gen_burning_depths_necrolyte_image : public SpellScriptLoader +{ + public: + spell_gen_burning_depths_necrolyte_image() : SpellScriptLoader("spell_gen_burning_depths_necrolyte_image") { } + + class spell_gen_burning_depths_necrolyte_image_AuraScript : public AuraScript + { + PrepareAuraScript(spell_gen_burning_depths_necrolyte_image_AuraScript); + + bool Validate(SpellInfo const* spellInfo) override + { + if (!sSpellMgr->GetSpellInfo(uint32(spellInfo->Effects[EFFECT_2].CalcValue()))) + return false; + return true; + } + + void HandleApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Unit* caster = GetCaster()) + caster->CastSpell(GetTarget(), uint32(GetSpellInfo()->Effects[EFFECT_2].CalcValue())); + } + + void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + GetTarget()->RemoveAurasDueToSpell(uint32(GetSpellInfo()->Effects[EFFECT_2].CalcValue()), GetCasterGUID()); + } + + void Register() override + { + AfterEffectApply += AuraEffectApplyFn(spell_gen_burning_depths_necrolyte_image_AuraScript::HandleApply, EFFECT_0, SPELL_AURA_TRANSFORM, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_gen_burning_depths_necrolyte_image_AuraScript::HandleRemove, EFFECT_0, SPELL_AURA_TRANSFORM, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_gen_burning_depths_necrolyte_image_AuraScript(); + } +}; + enum CannibalizeSpells { SPELL_CANNIBALIZE_TRIGGERED = 20578 @@ -4093,6 +4134,7 @@ void AddSC_generic_spell_scripts() new spell_gen_break_shield("spell_gen_break_shield"); new spell_gen_break_shield("spell_gen_tournament_counterattack"); new spell_gen_burn_brutallus(); + new spell_gen_burning_depths_necrolyte_image(); new spell_gen_cannibalize(); new spell_gen_chaos_blast(); new spell_gen_clone(); diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index 57346443390..22eabd3dd65 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -57,6 +57,7 @@ EndContentData */ #include "SpellAuras.h" #include "Pet.h" #include "CreatureTextMgr.h" +#include "SmartAI.h" /*######## # npc_air_force_bots @@ -2321,6 +2322,71 @@ public: } }; +enum StableMasters +{ + SPELL_MINIWING = 54573, + SPELL_JUBLING = 54611, + SPELL_DARTER = 54619, + SPELL_WORG = 54631, + SPELL_SMOLDERWEB = 54634, + SPELL_CHIKEN = 54677, + SPELL_WOLPERTINGER = 54688, + + STABLE_MASTER_GOSSIP_SUB_MENU = 9820 +}; + +class npc_stable_master : public CreatureScript +{ + public: + npc_stable_master() : CreatureScript("npc_stable_master") { } + + struct npc_stable_masterAI : public SmartAI + { + npc_stable_masterAI(Creature* creature) : SmartAI(creature) { } + + void sGossipSelect(Player* player, uint32 menuId, uint32 gossipListId) override + { + SmartAI::sGossipSelect(player, menuId, gossipListId); + if (menuId != STABLE_MASTER_GOSSIP_SUB_MENU) + return; + + switch (gossipListId) + { + case 0: + player->CastSpell(player, SPELL_MINIWING, false); + break; + case 1: + player->CastSpell(player, SPELL_JUBLING, false); + break; + case 2: + player->CastSpell(player, SPELL_DARTER, false); + break; + case 3: + player->CastSpell(player, SPELL_WORG, false); + break; + case 4: + player->CastSpell(player, SPELL_SMOLDERWEB, false); + break; + case 5: + player->CastSpell(player, SPELL_CHIKEN, false); + break; + case 6: + player->CastSpell(player, SPELL_WOLPERTINGER, false); + break; + default: + return; + } + + player->PlayerTalkClass->SendCloseGossip(); + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_stable_masterAI(creature); + } +}; + void AddSC_npcs_special() { new npc_air_force_bots(); @@ -2343,4 +2409,5 @@ void AddSC_npcs_special() new npc_firework(); new npc_spring_rabbit(); new npc_imp_in_a_ball(); + new npc_stable_master(); } diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp index 10c41835a9f..387fb156dee 100644 --- a/src/server/worldserver/Main.cpp +++ b/src/server/worldserver/Main.cpp @@ -424,7 +424,7 @@ void FreezeDetectorHandler(const boost::system::error_code& error) else if (getMSTimeDiff(_lastChangeMsTime, curtime) > _maxCoreStuckTimeInMs) { TC_LOG_ERROR("server.worldserver", "World Thread hangs, kicking out server!"); - ASSERT(false); + ABORT(); } _freezeCheckTimer.expires_from_now(boost::posix_time::seconds(1)); |