aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/Banner.cpp38
-rw-r--r--src/common/Banner.h31
-rw-r--r--src/server/bnetserver/Main.cpp18
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.cpp8
-rw-r--r--src/server/game/Battlefield/Battlefield.h4
-rw-r--r--src/server/game/Battlefield/BattlefieldMgr.cpp4
-rw-r--r--src/server/game/Battlefield/Zones/BattlefieldTB.cpp869
-rw-r--r--src/server/game/Battlefield/Zones/BattlefieldTB.h728
-rw-r--r--src/server/game/Entities/Item/Item.cpp14
-rw-r--r--src/server/game/Entities/Object/Object.h2
-rw-r--r--src/server/game/Entities/Player/Player.cpp138
-rw-r--r--src/server/game/Entities/Player/Player.h1
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp10
-rw-r--r--src/server/game/Entities/Unit/Unit.h2
-rw-r--r--src/server/game/Groups/GroupMgr.cpp6
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp22
-rw-r--r--src/server/game/Handlers/QuestHandler.cpp1
-rw-r--r--src/server/game/Instances/InstanceSaveMgr.cpp16
-rw-r--r--src/server/game/Instances/InstanceSaveMgr.h8
-rw-r--r--src/server/game/Instances/InstanceScript.cpp12
-rw-r--r--src/server/game/Instances/InstanceScript.h11
-rw-r--r--src/server/game/Maps/Map.cpp2
-rw-r--r--src/server/game/Scripting/ScriptMgr.cpp8
-rw-r--r--src/server/game/Scripting/ScriptMgr.h3
-rw-r--r--src/server/game/Scripting/ScriptReloadMgr.cpp58
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp22
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.h1
-rw-r--r--src/server/game/Spells/Spell.cpp8
-rw-r--r--src/server/game/Spells/SpellMgr.cpp4
-rw-r--r--src/server/game/World/World.cpp10
-rw-r--r--src/server/game/World/World.h8
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp15
-rw-r--r--src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/zone_tol_barad.cpp131
-rw-r--r--src/server/scripts/Kalimdor/BlackfathomDeeps/blackfathom_deeps.cpp30
-rw-r--r--src/server/scripts/Spells/spell_holiday.cpp101
-rw-r--r--src/server/worldserver/Main.cpp27
-rw-r--r--src/server/worldserver/worldserver.conf.dist58
-rw-r--r--src/tools/connection_patcher/Program.cpp5
-rw-r--r--src/tools/map_extractor/System.cpp4
-rw-r--r--src/tools/mmaps_generator/PathGenerator.cpp3
-rw-r--r--src/tools/vmap4_assembler/VMapAssembler.cpp3
-rw-r--r--src/tools/vmap4_extractor/vmapexport.cpp4
43 files changed, 2339 insertions, 111 deletions
diff --git a/src/common/Banner.cpp b/src/common/Banner.cpp
new file mode 100644
index 00000000000..a9ba530baa9
--- /dev/null
+++ b/src/common/Banner.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Banner.h"
+#include "GitRevision.h"
+#include "StringFormat.h"
+
+void Trinity::Banner::Show(char const* applicationName, void(*log)(char const* text), void(*logExtraInfo)())
+{
+ log(Trinity::StringFormat("%s (%s)", GitRevision::GetFullVersion(), applicationName).c_str());
+ log("<Ctrl-C> to stop.\n");
+ log(" ______ __");
+ log("/\\__ _\\ __ __/\\ \\__");
+ log("\\/_/\\ \\/ _ __ /\\_\\ ___ /\\_\\ \\, _\\ __ __");
+ log(" \\ \\ \\/\\`'__\\/\\ \\ /' _ `\\/\\ \\ \\ \\/ /\\ \\/\\ \\");
+ log(" \\ \\ \\ \\ \\/ \\ \\ \\/\\ \\/\\ \\ \\ \\ \\ \\_\\ \\ \\_\\ \\");
+ log(" \\ \\_\\ \\_\\ \\ \\_\\ \\_\\ \\_\\ \\_\\ \\__\\\\/`____ \\");
+ log(" \\/_/\\/_/ \\/_/\\/_/\\/_/\\/_/\\/__/ `/___/> \\");
+ log(" C O R E /\\___/");
+ log("http://TrinityCore.org \\/__/\n");
+
+ if (logExtraInfo)
+ logExtraInfo();
+}
diff --git a/src/common/Banner.h b/src/common/Banner.h
new file mode 100644
index 00000000000..6e846b2fe9b
--- /dev/null
+++ b/src/common/Banner.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+ *
+ * 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_Banner_h__
+#define TrinityCore_Banner_h__
+
+#include "Define.h"
+
+namespace Trinity
+{
+ namespace Banner
+ {
+ TC_COMMON_API void Show(char const* applicationName, void(*log)(char const* text), void(*logExtraInfo)());
+ }
+}
+
+#endif // TrinityCore_Banner_h__
diff --git a/src/server/bnetserver/Main.cpp b/src/server/bnetserver/Main.cpp
index e2397981818..b54249f9412 100644
--- a/src/server/bnetserver/Main.cpp
+++ b/src/server/bnetserver/Main.cpp
@@ -28,6 +28,7 @@
#include "ProcessPriority.h"
#include "RealmList.h"
#include "GitRevision.h"
+#include "Banner.h"
#include "SslContext.h"
#include "DatabaseLoader.h"
#include "LoginRESTService.h"
@@ -108,11 +109,18 @@ int main(int argc, char** argv)
sLog->RegisterAppender<AppenderDB>();
sLog->Initialize(nullptr);
- TC_LOG_INFO("server.bnetserver", "%s (bnetserver)", GitRevision::GetFullVersion());
- TC_LOG_INFO("server.bnetserver", "<Ctrl-C> to stop.\n");
- TC_LOG_INFO("server.bnetserver", "Using configuration file %s.", sConfigMgr->GetFilename().c_str());
- TC_LOG_INFO("server.bnetserver", "Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION));
- TC_LOG_INFO("server.bnetserver", "Using Boost version: %i.%i.%i", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100);
+ Trinity::Banner::Show("bnetserver",
+ [](char const* text)
+ {
+ TC_LOG_INFO("server.bnetserver", "%s", text);
+ },
+ []()
+ {
+ TC_LOG_INFO("server.bnetserver", "Using configuration file %s.", sConfigMgr->GetFilename().c_str());
+ TC_LOG_INFO("server.bnetserver", "Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION));
+ TC_LOG_INFO("server.bnetserver", "Using Boost version: %i.%i.%i", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100);
+ }
+ );
// Seed the OpenSSL's PRNG here.
// That way it won't auto-seed when calling BigNumber::SetRand and slow down the first world login
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp
index 5789bab01c4..8ca023b1856 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp
@@ -87,7 +87,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
"FROM characters WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_GROUP_MEMBER, "SELECT guid FROM group_member WHERE memberGuid = ?", CONNECTION_BOTH);
- PrepareStatement(CHAR_SEL_CHARACTER_INSTANCE, "SELECT id, permanent, map, difficulty, extendState, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_SEL_CHARACTER_INSTANCE, "SELECT id, permanent, map, difficulty, extendState, resettime, entranceId FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_AURAS, "SELECT casterGuid, itemGuid, spell, effectMask, recalculateMask, stackCount, maxDuration, remainTime, remainCharges, castItemLevel FROM character_aura WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_AURA_EFFECTS, "SELECT casterGuid, itemGuid, spell, effectMask, effectIndex, amount, baseAmount FROM character_aura_effect WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_SPELL, "SELECT spell, active, disabled FROM character_spell WHERE guid = ?", CONNECTION_ASYNC);
@@ -311,8 +311,8 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_DEL_TUTORIALS, "DELETE FROM account_tutorial WHERE accountId = ?", CONNECTION_ASYNC);
// Instance saves
- PrepareStatement(CHAR_INS_INSTANCE_SAVE, "INSERT INTO instance (id, map, resettime, difficulty, completedEncounters, data) VALUES (?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
- PrepareStatement(CHAR_UPD_INSTANCE_DATA, "UPDATE instance SET completedEncounters=?, data=? WHERE id=?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_INS_INSTANCE_SAVE, "INSERT INTO instance (id, map, resettime, difficulty, completedEncounters, data, entranceId) VALUES (?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_UPD_INSTANCE_DATA, "UPDATE instance SET completedEncounters=?, data=?, entranceId=? WHERE id=?", CONNECTION_ASYNC);
// Game event saves
PrepareStatement(CHAR_DEL_GAME_EVENT_SAVE, "DELETE FROM game_event_save WHERE eventEntry = ?", CONNECTION_ASYNC);
@@ -487,7 +487,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_SEL_POOL_QUEST_SAVE, "SELECT quest_id FROM pool_quest_save WHERE pool_id = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHAR_CUSTOMIZE_INFO, "SELECT name, race, class, gender, at_login FROM characters WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHAR_RACE_OR_FACTION_CHANGE_INFOS, "SELECT at_login, knownTitles FROM characters WHERE guid = ?", CONNECTION_ASYNC);
- PrepareStatement(CHAR_SEL_INSTANCE, "SELECT data, completedEncounters FROM instance WHERE map = ? AND id = ?", CONNECTION_SYNCH);
+ PrepareStatement(CHAR_SEL_INSTANCE, "SELECT data, completedEncounters, entranceId FROM instance WHERE map = ? AND id = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_PERM_BIND_BY_INSTANCE, "SELECT guid FROM character_instance WHERE instance = ? and permanent = 1", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHAR_COD_ITEM_MAIL, "SELECT id, messageType, mailTemplateId, sender, subject, body, money, has_items FROM mail WHERE receiver = ? AND has_items <> 0 AND cod <> 0", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHAR_SOCIAL, "SELECT DISTINCT guid FROM character_social WHERE friend = ?", CONNECTION_SYNCH);
diff --git a/src/server/game/Battlefield/Battlefield.h b/src/server/game/Battlefield/Battlefield.h
index 172e1f9246c..eb0c3895c8c 100644
--- a/src/server/game/Battlefield/Battlefield.h
+++ b/src/server/game/Battlefield/Battlefield.h
@@ -107,14 +107,14 @@ class TC_GAME_API BfCapturePoint
virtual void SendChangePhase();
bool SetCapturePointData(GameObject* capturePoint);
+ bool DelCapturePoint();
GameObject* GetCapturePointGo();
uint32 GetCapturePointEntry() const { return m_capturePointEntry; }
TeamId GetTeamId() const { return m_team; }
+ BattlefieldObjectiveStates GetObjectiveState() const { return m_State; }
protected:
- bool DelCapturePoint();
-
// active Players in the area of the objective, 0 - alliance, 1 - horde
GuidSet m_activePlayers[BG_TEAMS_COUNT];
diff --git a/src/server/game/Battlefield/BattlefieldMgr.cpp b/src/server/game/Battlefield/BattlefieldMgr.cpp
index b92b2e64318..b4b4e269b28 100644
--- a/src/server/game/Battlefield/BattlefieldMgr.cpp
+++ b/src/server/game/Battlefield/BattlefieldMgr.cpp
@@ -17,6 +17,7 @@
#include "BattlefieldMgr.h"
#include "BattlefieldWG.h"
+#include "BattlefieldTB.h"
#include "Player.h"
BattlefieldMgr::BattlefieldMgr()
@@ -53,8 +54,6 @@ void BattlefieldMgr::InitBattlefield()
TC_LOG_INFO("bg.battlefield", "Battlefield: Wintergrasp successfully initiated.");
}
- /*
- For Cataclysm: Tol Barad
Battlefield* tb = new BattlefieldTB;
// respawn, init variables
if (!tb->SetupBattlefield())
@@ -67,7 +66,6 @@ void BattlefieldMgr::InitBattlefield()
_battlefieldSet.push_back(tb);
TC_LOG_DEBUG("bg.battlefield", "Battlefield: Tol Barad successfully initiated.");
}
- */
}
void BattlefieldMgr::AddZone(uint32 zoneId, Battlefield* bf)
diff --git a/src/server/game/Battlefield/Zones/BattlefieldTB.cpp b/src/server/game/Battlefield/Zones/BattlefieldTB.cpp
new file mode 100644
index 00000000000..affc1e0db47
--- /dev/null
+++ b/src/server/game/Battlefield/Zones/BattlefieldTB.cpp
@@ -0,0 +1,869 @@
+/*
+* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+*
+* 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/>.
+*/
+
+// TO-DO:
+// - Implement proper support for vehicles (Player::VehicleSpellInitialize())
+// - Siege Engine Turret (45564) crashing server (Auras: Unknown Shapeshift Type: 24)
+// - Graveyard spirit phasing, ressurection, Spiritual Immunity aura for players nearby
+// - Warn and teleport players out of the Baradin Hold instance (need sniffs; spell 94964?)
+// - Not sure, but players should probably be able to ressurect from guide spirits when there's no battle
+// - Check and script achievements
+
+#include "BattlefieldTB.h"
+#include "AchievementMgr.h"
+#include "CreatureTextMgr.h"
+#include "Battleground.h"
+#include "MapManager.h"
+#include "ObjectMgr.h"
+#include "Opcodes.h"
+#include "Player.h"
+#include "SpellAuras.h"
+#include "TemporarySummon.h"
+#include "WorldSession.h"
+
+BattlefieldTB::~BattlefieldTB() { }
+
+bool BattlefieldTB::SetupBattlefield()
+{
+ m_TypeId = BATTLEFIELD_TB; // See enum BattlefieldTypes
+ m_BattleId = BATTLEFIELD_BATTLEID_TB;
+ m_ZoneId = BATTLEFIELD_TB_ZONEID;
+ m_MapId = BATTLEFIELD_TB_MAPID;
+ m_Map = sMapMgr->CreateBaseMap(m_MapId);
+
+ InitStalker(NPC_DEBUG_ANNOUNCER, TolBaradDebugAnnouncerPos);
+
+ m_MaxPlayer = sWorld->getIntConfig(CONFIG_TOLBARAD_PLR_MAX);
+ m_IsEnabled = sWorld->getBoolConfig(CONFIG_TOLBARAD_ENABLE);
+ m_MinPlayer = sWorld->getIntConfig(CONFIG_TOLBARAD_PLR_MIN);
+ m_MinLevel = sWorld->getIntConfig(CONFIG_TOLBARAD_PLR_MIN_LVL);
+ m_BattleTime = sWorld->getIntConfig(CONFIG_TOLBARAD_BATTLETIME) * MINUTE * IN_MILLISECONDS;
+ m_BonusTime = sWorld->getIntConfig(CONFIG_TOLBARAD_BONUSTIME) * MINUTE * IN_MILLISECONDS;
+ m_NoWarBattleTime = sWorld->getIntConfig(CONFIG_TOLBARAD_NOBATTLETIME) * MINUTE * IN_MILLISECONDS;
+ m_RestartAfterCrash = sWorld->getIntConfig(CONFIG_TOLBARAD_RESTART_AFTER_CRASH) * MINUTE * IN_MILLISECONDS;
+
+ m_TimeForAcceptInvite = 20;
+ m_StartGroupingTimer = 15 * MINUTE * IN_MILLISECONDS;
+ m_StartGrouping = false;
+ m_isActive = false;
+
+ KickPosition.Relocate(-605.5f, 1181.31f, 95.96f, 6.177155f);
+ KickPosition.m_mapId = m_MapId;
+
+ RegisterZone(m_ZoneId);
+
+ m_Data32.resize(BATTLEFIELD_TB_DATA_MAX);
+
+ m_saveTimer = 5 * MINUTE * IN_MILLISECONDS;
+
+ updatedNPCAndObjects = true;
+ m_updateObjectsTimer = 0;
+
+ // Was there a battle going on or time isn't set yet? Then use m_RestartAfterCrash
+ if (sWorld->getWorldState(TB_WS_STATE_BATTLE) == 1 || sWorld->getWorldState(TB_WS_TIME_NEXT_BATTLE) == 0)
+ sWorld->setWorldState(TB_WS_TIME_NEXT_BATTLE, m_RestartAfterCrash);
+
+ // Set timer
+ m_Timer = sWorld->getWorldState(TB_WS_TIME_NEXT_BATTLE);
+
+ // Defending team isn't set yet? Choose randomly.
+ if (sWorld->getWorldState(TB_WS_FACTION_CONTROLLING) == 0)
+ sWorld->setWorldState(TB_WS_FACTION_CONTROLLING, uint64(urand(1, 2)));
+
+ // Set defender team
+ SetDefenderTeam(TeamId(sWorld->getWorldState(TB_WS_FACTION_CONTROLLING) - 1));
+
+ // Just to save world states
+ SendInitWorldStatesToAll();
+
+ // Create capture points
+ for (uint8 i = 0; i < TB_BASE_COUNT; i++)
+ {
+ TolBaradCapturePoint* capturePoint = new TolBaradCapturePoint(this, GetDefenderTeam());
+
+ //Spawn flag pole
+ if (GameObject* go = SpawnGameObject(TBCapturePoints[i].entryFlagPole[GetDefenderTeam()], TBCapturePoints[i].x, TBCapturePoints[i].y, TBCapturePoints[i].z, TBCapturePoints[i].o))
+ {
+ go->SetGoArtKit(GetDefenderTeam() == TEAM_ALLIANCE ? TB_GO_ARTKIT_FLAG_ALLIANCE : TB_GO_ARTKIT_FLAG_HORDE);
+ capturePoint->SetCapturePointData(go);
+ }
+ AddCapturePoint(capturePoint);
+ }
+
+ // Spawn towers
+ for (uint8 i = 0; i < TB_TOWERS_COUNT; i++)
+ if (GameObject* go = SpawnGameObject(TBTowers[i].entry, TBTowers[i].x, TBTowers[i].y, TBTowers[i].z, TBTowers[i].o))
+ Towers.insert(go->GetGUID());
+
+ // Init Graveyards
+ SetGraveyardNumber(BATTLEFIELD_TB_GRAVEYARD_MAX);
+
+ // Graveyards
+ for (uint8 i = 0; i < BATTLEFIELD_TB_GRAVEYARD_MAX; i++)
+ {
+ BfGraveyard* graveyard = new BfGraveyard(this);
+
+ // When between games, the graveyard is controlled by the defending team
+ graveyard->Initialize(GetDefenderTeam(), TBGraveyards[i].gyid);
+
+ // Spawn spirits
+ for (uint8 team = 0; team < 2; team++)
+ if (Creature* creature = SpawnCreature(TBGraveyards[i].spiritEntry[team], TBGraveyards[i].x, TBGraveyards[i].y, TBGraveyards[i].z, TBGraveyards[i].o, TeamId(team)))
+ graveyard->SetSpirit(creature, TeamId(team));
+
+ m_GraveyardList[i] = graveyard;
+ }
+
+ // Time warning vars
+ warnedFiveMinutes = false;
+ warnedTwoMinutes = false;
+ warnedOneMinute = false;
+
+ UpdateNPCsAndGameObjects();
+
+ return true;
+}
+
+bool BattlefieldTB::Update(uint32 diff)
+{
+ bool m_return = Battlefield::Update(diff);
+
+ // Minutes till battle preparation warnings
+ if (GetState() == BATTLEFIELD_INACTIVE)
+ {
+ if (m_Timer <= 5 * MINUTE * IN_MILLISECONDS + m_StartGroupingTimer && !warnedFiveMinutes)
+ {
+ warnedFiveMinutes = true;
+ SendWarning(TB_TEXT_PREPARATIONS_IN_5_MIN);
+ }
+
+ if (m_Timer <= 2 * MINUTE * IN_MILLISECONDS + m_StartGroupingTimer && !warnedTwoMinutes)
+ {
+ warnedTwoMinutes = true;
+ SendWarning(TB_TEXT_PREPARATIONS_IN_2_MIN);
+ }
+
+ if (m_Timer <= 1 * MINUTE * IN_MILLISECONDS + m_StartGroupingTimer && !warnedOneMinute)
+ {
+ warnedOneMinute = true;
+ SendWarning(TB_TEXT_PREPARATIONS_IN_1_MIN);
+ }
+ }
+
+ if (!updatedNPCAndObjects)
+ {
+ if (m_updateObjectsTimer <= diff)
+ {
+ UpdateNPCsAndGameObjects();
+ updatedNPCAndObjects = true;
+ }
+ else
+ m_updateObjectsTimer -= diff;
+ }
+
+ if (m_saveTimer <= diff)
+ {
+ if (!IsWarTime())
+ sWorld->setWorldState(TB_WS_TIME_NEXT_BATTLE, m_Timer);
+ m_saveTimer = 60 * IN_MILLISECONDS;
+ }
+ else
+ m_saveTimer -= diff;
+
+ return m_return;
+}
+
+void BattlefieldTB::OnPlayerEnterZone(Player* player)
+{
+ if (!m_isActive)
+ RemoveAurasFromPlayer(player);
+
+ SendInitWorldStatesTo(player);
+}
+
+void BattlefieldTB::OnPlayerLeaveZone(Player* player)
+{
+ if (!m_isActive)
+ RemoveAurasFromPlayer(player);
+}
+
+void BattlefieldTB::OnPlayerJoinWar(Player* player)
+{
+ RemoveAurasFromPlayer(player);
+
+ player->SetPvP(true);
+
+ // Bonus damage buff for attackers
+ if (player->GetTeam() == GetAttackerTeam() && GetData(BATTLEFIELD_TB_DATA_TOWERS_DESTROYED) > 0)
+ player->CastCustomSpell(SPELL_TOWER_ATTACK_BONUS, SPELLVALUE_AURA_STACK, GetData(BATTLEFIELD_TB_DATA_TOWERS_DESTROYED), player, TRIGGERED_FULL_MASK);
+}
+
+
+void BattlefieldTB::OnPlayerLeaveWar(Player* player)
+{
+ RemoveAurasFromPlayer(player);
+}
+
+void BattlefieldTB::RemoveAurasFromPlayer(Player* player)
+{
+ player->RemoveAurasDueToSpell(SPELL_TB_SLOW_FALL);
+ player->RemoveAurasDueToSpell(SPELL_TB_VETERAN);
+ player->RemoveAurasDueToSpell(SPELL_TOWER_ATTACK_BONUS);
+ player->RemoveAurasDueToSpell(SPELL_TB_SPIRITUAL_IMMUNITY);
+}
+
+// 62 fields, [7]-[68]
+void BattlefieldTB::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet)
+{
+ packet.Worldstates.emplace_back(uint32(TB_WS_ALLIANCE_ATTACKING_SHOW), int32(IsWarTime() && GetAttackerTeam() == TEAM_ALLIANCE ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(TB_WS_HORDE_ATTACKING_SHOW), int32(IsWarTime() && GetAttackerTeam() == TEAM_HORDE ? 1 : 0));
+
+ // Not sure if TB
+ //packet.Worldstates.emplace_back(uint32(TB_WS_9_UNKNOWN), int32(1));
+
+ packet.Worldstates.emplace_back(uint32(TB_WS_SOUTH_DAMAGED_NEUTRAL), int32(0));
+ packet.Worldstates.emplace_back(uint32(TB_WS_SOUTH_INTACT_NEUTRAL), int32(0));
+
+ packet.Worldstates.emplace_back(uint32(TB_WS_PROGRESS_SHOW), int32(0));
+
+ // Buildings/bases
+ for (BfCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr)
+ {
+ uint8 i = TB_BASE_COUNT;
+ switch (itr->second->GetCapturePointEntry())
+ {
+ case GO_CAPTURE_POINT_NORTH_A_DEFENDING:
+ case GO_CAPTURE_POINT_NORTH_H_DEFENDING:
+ i = TB_BASE_IRONCLAD_GARRISON;
+ break;
+ case GO_CAPTURE_POINT_EAST_A_DEFENDING:
+ case GO_CAPTURE_POINT_EAST_H_DEFENDING:
+ i = TB_BASE_SLAGWORKS;
+ break;
+ case GO_CAPTURE_POINT_WEST_A_DEFENDING:
+ case GO_CAPTURE_POINT_WEST_H_DEFENDING:
+ i = TB_BASE_WARDENS_VIGIL;
+ break;
+ default:
+ continue;
+ }
+
+ TeamId team = TEAM_NEUTRAL;
+ bool controlled = false;
+ bool capturing = false;
+
+ switch (itr->second->GetObjectiveState())
+ {
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE:
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE:
+ controlled = true;
+ team = itr->second->GetTeamId();
+ break;
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE:
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE:
+ team = TEAM_ALLIANCE;
+ capturing = true;
+ break;
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE:
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE:
+ team = TEAM_HORDE;
+ capturing = true;
+ break;
+ default:
+ team = TEAM_NEUTRAL;
+ break;
+ }
+
+ packet.Worldstates.emplace_back(uint32(TBCapturePoints[i].wsControlled[TEAM_ALLIANCE]), int32(team == TEAM_ALLIANCE && controlled ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(TBCapturePoints[i].wsCapturing[TEAM_ALLIANCE]), int32(team == TEAM_ALLIANCE && capturing ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(TBCapturePoints[i].wsNeutral), int32(team == TEAM_NEUTRAL ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(TBCapturePoints[i].wsCapturing[TEAM_HORDE]), int32(team == TEAM_HORDE && capturing ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(TBCapturePoints[i].wsControlled[TEAM_HORDE]), int32(team == TEAM_HORDE && controlled ? 1 : 0));
+ }
+
+ packet.Worldstates.emplace_back(uint32(TB_WS_TOWERS_DESTROYED_SHOW), int32(GetData(BATTLEFIELD_TB_DATA_TOWERS_DESTROYED)));
+ packet.Worldstates.emplace_back(uint32(TB_WS_BUILDINGS_CAPTURED_SHOW), int32(IsWarTime() ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(TB_WS_BUILDINGS_CAPTURED), int32(GetData(BATTLEFIELD_TB_DATA_BUILDINGS_CAPTURED)));
+ packet.Worldstates.emplace_back(uint32(TB_WS_TOWERS_DESTROYED), int32(0));
+
+ packet.Worldstates.emplace_back(uint32(TB_WS_TIME_BATTLE_END_SHOW), int32(IsWarTime() ? 1 : 0));
+
+ packet.Worldstates.emplace_back(uint32(TB_WS_STATE_BATTLE), int32(IsWarTime() ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(TB_WS_STATE_PREPARATIONS), int32(GetState() == BATTLEFIELD_WARMUP ? 1 : 0));
+
+ // Not sure if TB
+ //packet.Worldstates.emplace_back(uint32(TB_WS_35_UNKNOWN), int32(0));
+ //packet.Worldstates.emplace_back(uint32(TB_WS_36_UNKNOWN), int32(0));
+ //packet.Worldstates.emplace_back(uint32(TB_WS_37_UNKNOWN), int32(0));
+
+ // Unused tower icons
+ packet.Worldstates.emplace_back(uint32(TB_WS_WEST_DAMAGED_NEUTRAL), int32(0));
+ packet.Worldstates.emplace_back(uint32(TB_WS_WEST_INTACT_NEUTRAL), int32(0));
+ packet.Worldstates.emplace_back(uint32(TB_WS_EAST_DAMAGED_NEUTRAL), int32(0));
+ packet.Worldstates.emplace_back(uint32(TB_WS_EAST_INTACT_NEUTRAL), int32(0));
+
+ // Towers/spires
+ for (uint8 i = 0; i < TB_TOWERS_COUNT; i++)
+ {
+ // Find gameobject
+ for (ObjectGuid guid : Towers)
+ {
+ GameObject* tower = GetGameObject(guid);
+ if (!tower || tower->GetEntry() != TBTowers[i].entry)
+ continue;
+
+ TeamId team = GetDefenderTeam(); // 0-false -> alliance; 1-true -> horde
+ bool intact = tower->GetDestructibleState() == GO_DESTRUCTIBLE_INTACT;
+ bool damaged = tower->GetDestructibleState() == GO_DESTRUCTIBLE_DAMAGED;
+ bool destroyed = tower->GetDestructibleState() == GO_DESTRUCTIBLE_DESTROYED;
+
+ packet.Worldstates.emplace_back(uint32(TBTowers[i].wsIntact[TEAM_ALLIANCE]), int32(!team && intact ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(TBTowers[i].wsDamaged[TEAM_ALLIANCE]), int32(!team && damaged ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(TBTowers[i].wsDestroyed), int32(destroyed ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(TBTowers[i].wsDamaged[TEAM_HORDE]), int32(team && damaged ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(TBTowers[i].wsIntact[TEAM_HORDE]), int32(team && intact ? 1 : 0));
+ }
+ }
+
+ packet.Worldstates.emplace_back(uint32(TB_WS_TIME_NEXT_BATTLE_SHOW), int32(!IsWarTime() ? 1 : 0));
+
+ packet.Worldstates.emplace_back(uint32(TB_WS_ALLIANCE_CONTROLS_SHOW), int32(!IsWarTime() && GetDefenderTeam() == TEAM_ALLIANCE ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(TB_WS_HORDE_CONTROLS_SHOW), int32(!IsWarTime() && GetDefenderTeam() == TEAM_HORDE ? 1 : 0));
+
+ packet.Worldstates.emplace_back(uint32(TB_WS_TIME_BATTLE_END), int32(IsWarTime() ? time(NULL) + (m_Timer / 1000) : 0));
+ packet.Worldstates.emplace_back(uint32(TB_WS_TIME_NEXT_BATTLE), int32(!IsWarTime() ? time(NULL) + (m_Timer / 1000) : 0));
+
+ // Not sure if TB
+ //packet.Worldstates.emplace_back(uint32(TB_WS_65_UNKNOWN), int32(0));
+ //packet.Worldstates.emplace_back(uint32(TB_WS_66_UNKNOWN), int32(0));
+
+ packet.Worldstates.emplace_back(uint32(TB_WS_KEEP_ALLIANCE), int32(GetDefenderTeam() == TEAM_ALLIANCE ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(TB_WS_KEEP_HORDE), int32(GetDefenderTeam() == TEAM_HORDE ? 1 : 0));
+}
+
+void BattlefieldTB::SendInitWorldStatesTo(Player* player)
+{
+ WorldPackets::WorldState::InitWorldStates packet;
+ packet.AreaID = m_ZoneId;
+ packet.MapID = m_MapId;
+ packet.SubareaID = 0;
+
+ FillInitialWorldStates(packet);
+
+ player->SendDirectMessage(packet.Write());
+}
+
+void BattlefieldTB::SendInitWorldStatesToAll()
+{
+ // Save
+ sWorld->setWorldState(TB_WS_STATE_BATTLE, uint64(IsWarTime() ? 1 : 0));
+ sWorld->setWorldState(TB_WS_ALLIANCE_CONTROLS_SHOW, uint64(!IsWarTime() && GetDefenderTeam() == TEAM_ALLIANCE ? 1 : 0));
+ sWorld->setWorldState(TB_WS_HORDE_CONTROLS_SHOW, uint64(!IsWarTime() && GetDefenderTeam() == TEAM_HORDE ? 1 : 0));
+ sWorld->setWorldState(TB_WS_ALLIANCE_ATTACKING_SHOW, uint64(IsWarTime() && GetAttackerTeam() == TEAM_ALLIANCE ? 1 : 0));
+ sWorld->setWorldState(TB_WS_HORDE_ATTACKING_SHOW, uint64(IsWarTime() && GetAttackerTeam() == TEAM_HORDE ? 1 : 0));
+ sWorld->setWorldState(TB_WS_TIME_NEXT_BATTLE, uint64(!IsWarTime() ? m_Timer : 0));
+ sWorld->setWorldState(TB_WS_TIME_NEXT_BATTLE_SHOW, uint64(!IsWarTime() ? 1 : 0));
+
+ // Tol Barad
+ for (uint8 team = 0; team < 2; team++)
+ for (GuidSet::iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr)
+ if (Player* player = ObjectAccessor::FindPlayer(*itr))
+ SendInitWorldStatesTo(player);
+
+ // Tol Barad Peninsula
+ Map::PlayerList const& players = m_Map->GetPlayers();
+ for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
+ if (Player* player = itr->GetSource()->ToPlayer())
+ if (player->GetZoneId() == 5389) // ZONE_TOL_BARAD_PENINSULA
+ player->SendInitWorldStates(5389, player->GetAreaId());
+}
+
+void BattlefieldTB::OnStartGrouping()
+{
+ UpdateNPCsAndGameObjects();
+
+ SendUpdateWorldState(TB_WS_STATE_PREPARATIONS, uint32(1));
+
+ // Teleport players out of questing area
+ for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team)
+ for (GuidSet::const_iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr)
+ if (Player* player = ObjectAccessor::FindPlayer(*itr))
+ if (player->GetAreaId() == TBQuestAreas[m_iCellblockRandom].entry)
+ player->CastSpell(player, TBQuestAreas[m_iCellblockRandom].teleportSpell, true);
+
+ // Should we also teleport players out of Baradin Hold underground area?
+};
+
+void BattlefieldTB::OnBattleStart()
+{
+ SetData(BATTLEFIELD_TB_DATA_BUILDINGS_CAPTURED, uint32(0));
+ SetData(BATTLEFIELD_TB_DATA_TOWERS_INTACT, uint32(3));
+ SetData(BATTLEFIELD_TB_DATA_TOWERS_DESTROYED, uint32(0));
+
+ UpdateNPCsAndGameObjects();
+
+ SendInitWorldStatesToAll();
+};
+
+void BattlefieldTB::OnBattleEnd(bool endByTimer)
+{
+ if (!endByTimer) // Attackers win (but now they are defenders already)
+ SendWarning(GetDefenderTeam() == TEAM_ALLIANCE ? TB_TEXT_FORTRESS_CAPTURE_ALLIANCE : TB_TEXT_FORTRESS_CAPTURE_HORDE);
+ else // Defenders win
+ SendWarning(GetDefenderTeam() == TEAM_ALLIANCE ? TB_TEXT_FORTRESS_DEFEND_ALLIANCE : TB_TEXT_FORTRESS_DEFEND_HORDE);
+
+ // UpdateNPCsAndGameObjects() must be called 1 minute after battle ends
+ m_updateObjectsTimer = 1 * MINUTE * IN_MILLISECONDS;
+ updatedNPCAndObjects = false;
+
+ // Complete quest
+ TeamCastSpell(GetDefenderTeam(), GetDefenderTeam() == TEAM_ALLIANCE ? SPELL_VICTORY_ALLIANCE : SPELL_VICTORY_HORDE);
+
+ // Rewards
+ TeamCastSpell(GetDefenderTeam(), GetDefenderTeam() == TEAM_ALLIANCE ? SPELL_REWARD_VICTORY_ALLIANCE : SPELL_REWARD_VICTORY_HORDE);
+ for (uint32 i = 0; i < GetData(BATTLEFIELD_TB_DATA_TOWERS_INTACT); i++) // Unsure, for each intact tower or only once for having any tower intact?
+ TeamCastSpell(GetDefenderTeam(), SPELL_REWARD_TOWER_INTACT);
+ TeamCastSpell(GetAttackerTeam(), SPELL_REWARD_DEFEAT);
+
+ for (uint8 team = 0; team < 2; ++team)
+ {
+ for (GuidSet::const_iterator itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr)
+ if (Player* player = ObjectAccessor::FindPlayer(*itr))
+ RemoveAurasFromPlayer(player);
+
+ m_PlayersInWar[team].clear();
+ }
+
+ // Reset time warning vars
+ warnedFiveMinutes = false;
+ warnedTwoMinutes = false;
+ warnedOneMinute = false;
+};
+
+void BattlefieldTB::UpdateNPCsAndGameObjects()
+{
+ for (ObjectGuid guid : BattleInactiveNPCs)
+ if (Creature* creature = GetCreature(guid))
+ HideNpc(creature);
+
+ for (ObjectGuid guid : BattleInactiveGOs)
+ if (GameObject* gameobject = GetGameObject(guid))
+ gameobject->SetRespawnTime(RESPAWN_ONE_DAY);
+
+ for (ObjectGuid guid : TemporaryNPCs)
+ if (Creature* creature = GetCreature(guid))
+ creature->RemoveFromWorld();
+ TemporaryNPCs.clear();
+
+ for (ObjectGuid guid : TemporaryGOs)
+ if (GameObject* gameobject = GetGameObject(guid))
+ gameobject->Delete();
+ TemporaryGOs.clear();
+
+ // Tol Barad gates - closed during warmup
+ if (GameObject* gates = GetGameObject(TBGatesGUID))
+ gates->SetGoState(GetState() == BATTLEFIELD_WARMUP ? GO_STATE_READY : GO_STATE_ACTIVE);
+
+ // Baradin Hold door - open when inactive
+ if (GameObject* door = GetGameObject(TBDoorGUID))
+ door->SetGoState(GetState() == BATTLEFIELD_INACTIVE ? GO_STATE_ACTIVE : GO_STATE_READY);
+
+ // Decide which cellblock and questgiver will be active.
+ m_iCellblockRandom = GetState() == BATTLEFIELD_INACTIVE ? urand(0, CELLBLOCK_MAX - 1) : CELLBLOCK_NONE;
+
+ // To The Hole gate
+ if (GameObject* door = GetGameObject(m_gateToTheHoleGUID))
+ door->SetGoState(m_iCellblockRandom == CELLBLOCK_THE_HOLE ? GO_STATE_ACTIVE : GO_STATE_READY);
+
+ // D-Block gate
+ if (GameObject* door = GetGameObject(m_gateDBlockGUID))
+ door->SetGoState(m_iCellblockRandom == CELLBLOCK_D_BLOCK ? GO_STATE_ACTIVE : GO_STATE_READY);
+
+ // Cursed Depths gate
+ if (GameObject* door = GetGameObject(m_gateCursedDepthsGUID))
+ door->SetGoState(m_iCellblockRandom == CELLBLOCK_CURSED_DEPTHS ? GO_STATE_ACTIVE : GO_STATE_READY);
+
+ if (GetState() == BATTLEFIELD_INACTIVE)
+ {
+ // Delete capture points
+ for (BfCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr)
+ itr->second->DelCapturePoint();
+ m_capturePoints.clear();
+
+ // Create capture points
+ for (uint8 i = 0; i < TB_BASE_COUNT; i++)
+ {
+ TolBaradCapturePoint* capturePoint = new TolBaradCapturePoint(this, GetDefenderTeam());
+
+ //Spawn flag pole
+ if (GameObject* go = SpawnGameObject(TBCapturePoints[i].entryFlagPole[GetDefenderTeam()], TBCapturePoints[i].x, TBCapturePoints[i].y, TBCapturePoints[i].z, TBCapturePoints[i].o))
+ {
+ go->SetGoArtKit(GetDefenderTeam() == TEAM_ALLIANCE ? TB_GO_ARTKIT_FLAG_ALLIANCE : TB_GO_ARTKIT_FLAG_HORDE);
+ capturePoint->SetCapturePointData(go);
+ }
+
+ AddCapturePoint(capturePoint);
+ }
+
+ for (ObjectGuid guid : BattleInactiveNPCs)
+ if (Creature* creature = GetCreature(guid))
+ ShowNpc(creature, true);
+
+ for (ObjectGuid guid : BattleInactiveGOs)
+ if (GameObject* gameobject = GetGameObject(guid))
+ gameobject->SetRespawnTime(RESPAWN_IMMEDIATELY);
+
+ for (uint8 i = 0; i < TB_QUEST_INFANTRY_MAX; i++)
+ {
+ uint32 entry = TB_QUEST_INFANTRY[GetDefenderTeam()][urand(0,3)];
+ if (Creature* creature = SpawnCreature(entry, TBQuestInfantrySpawnData[i], GetDefenderTeam()))
+ TemporaryNPCs.insert(creature->GetGUID());
+ }
+
+ for (uint8 i = 0; i < TB_GUARDS_MAX; i++)
+ if (Creature* creature = SpawnCreature(GetDefenderTeam() == TEAM_ALLIANCE ? NPC_BARADIN_GUARD : NPC_HELLSCREAMS_SENTRY, GuardNPCSpawns[i], GetDefenderTeam()))
+ TemporaryNPCs.insert(creature->GetGUID());
+
+ for (uint8 i = 0; i < TB_FACTION_NPC_MAX; i++)
+ if (Creature* creature = SpawnCreature(GetDefenderTeam() == TEAM_ALLIANCE ? FactionNPCSpawns[i].entryAlliance : FactionNPCSpawns[i].entryHorde, FactionNPCSpawns[i].x, FactionNPCSpawns[i].y, FactionNPCSpawns[i].z, FactionNPCSpawns[i].o, GetDefenderTeam()))
+ TemporaryNPCs.insert(creature->GetGUID());
+
+ if (Creature* creature = SpawnCreature(RandomQuestgivers[GetDefenderTeam()][m_iCellblockRandom], RandomQuestgiverPos, GetDefenderTeam()))
+ TemporaryNPCs.insert(creature->GetGUID());
+
+ // Spawn portals
+ for (uint8 i = 0; i < TB_PORTAL_MAX; i++)
+ if (GameObject* go = SpawnGameObject(TBPortalEntry[GetDefenderTeam()], TBPortals[i].GetPositionX(), TBPortals[i].GetPositionY(), TBPortals[i].GetPositionZ(), TBPortals[i].GetOrientation()))
+ TemporaryGOs.insert(go->GetGUID());
+
+ // Update towers
+ for (ObjectGuid guid : Towers)
+ if (GameObject* go = GetGameObject(guid))
+ go->SetDestructibleState(GO_DESTRUCTIBLE_REBUILDING);
+ }
+ else if (GetState() == BATTLEFIELD_IN_PROGRESS)
+ {
+ for (uint8 i = 0; i < TB_ABANDONED_SIEGE_ENGINE_COUNT; i++)
+ if (Creature* creature = SpawnCreature(NPC_ABANDONED_SIEGE_ENGINE, TBAbandonedSiegeEngineSpawnData[i], GetDefenderTeam()))
+ TemporaryNPCs.insert(creature->GetGUID());
+
+ for (ObjectGuid guid : Towers)
+ {
+ if (GameObject* go = GetGameObject(guid))
+ {
+ go->SetDestructibleState(GO_DESTRUCTIBLE_INTACT);
+ go->ModifyHealth(go->GetGOValue()->Building.MaxHealth);
+ }
+ }
+ }
+
+ // Spawn banners
+ for (uint8 i = 0; i < TB_BANNER_MAX; i++)
+ if (GameObject* go = SpawnGameObject(TBBannerEntry[GetDefenderTeam()], TBBanners[i].GetPositionX(), TBBanners[i].GetPositionY(), TBBanners[i].GetPositionZ(), TBBanners[i].GetOrientation()))
+ TemporaryGOs.insert(go->GetGUID());
+
+ // Set graveyard controls
+ for (uint8 i = 0; i < BATTLEFIELD_TB_GRAVEYARD_MAX; i++)
+ if (BfGraveyard* graveyard = GetGraveyardById(i))
+ graveyard->GiveControlTo(!IsWarTime() || TBGraveyards[i].defenderControls ? GetDefenderTeam() : GetAttackerTeam());
+};
+
+void BattlefieldTB::OnCreatureCreate(Creature* creature)
+{
+ switch (creature->GetEntry())
+ {
+ // Store NPCs that need visibility toggling
+ case NPC_TOLBARAD_CAPTIVE_SPIRIT:
+ case NPC_TOLBARAD_CELLBLOCK_OOZE:
+ case NPC_TOLBARAD_ARCHMAGE_GALUS:
+ case NPC_TOLBARAD_GHASTLY_CONVICT:
+ case NPC_TOLBARAD_SHIVARRA_DESTROYER:
+ case NPC_TOLBARAD_CELL_WATCHER:
+ case NPC_TOLBARAD_SVARNOS:
+ case NPC_TOLBARAD_JAILED_WRATHGUARD:
+ case NPC_TOLBARAD_IMPRISONED_IMP:
+ case NPC_TOLBARAD_WARDEN_SILVA:
+ case NPC_TOLBARAD_WARDEN_GUARD:
+ case NPC_TOLBARAD_IMPRISONED_WORKER:
+ case NPC_TOLBARAD_EXILED_MAGE:
+ case NPC_CROCOLISK:
+ case NPC_PROBLIM:
+ BattleInactiveNPCs.insert(creature->GetGUID());
+ if (GetState() == BATTLEFIELD_WARMUP) // If battle is about to start, we must hide these.
+ HideNpc(creature);
+ break;
+ case NPC_ABANDONED_SIEGE_ENGINE:
+ creature->setFaction(TBFactions[GetDefenderTeam()]);
+ creature->CastSpell(creature, SPELL_THICK_LAYER_OF_RUST, true);
+ break;
+ case NPC_SIEGE_ENGINE_TURRET:
+ if (Unit* vehiclebase = creature->GetCharmerOrOwner()->GetVehicleBase())
+ creature->EnterVehicle(vehiclebase);
+ break;
+ case NPC_TOWER_RANGE_FINDER:
+ creature->CastSpell(creature, SPELL_TOWER_RANGE_FINDER_PERIODIC, true);
+ break;
+ case NPC_TB_GY_SPIRIT_BARADIN_HOLD_A:
+ case NPC_TB_GY_SPIRIT_BARADIN_HOLD_H:
+ case NPC_TB_GY_SPIRIT_IRONCLAD_GARRISON_A:
+ case NPC_TB_GY_SPIRIT_WARDENS_VIGIL_A:
+ case NPC_TB_GY_SPIRIT_EAST_SPIRE_A:
+ case NPC_TB_GY_SPIRIT_SOUTH_SPIRE_A:
+ case NPC_TB_GY_SPIRIT_WEST_SPIRE_A:
+ case NPC_TB_GY_SPIRIT_SLAGWORKS_A:
+ case NPC_TB_GY_SPIRIT_IRONCLAD_GARRISON_H:
+ case NPC_TB_GY_SPIRIT_WARDENS_VIGIL_H:
+ case NPC_TB_GY_SPIRIT_SLAGWORKS_H:
+ case NPC_TB_GY_SPIRIT_WEST_SPIRE_H:
+ case NPC_TB_GY_SPIRIT_EAST_SPIRE_H:
+ case NPC_TB_GY_SPIRIT_SOUTH_SPIRE_H:
+ creature->CastSpell(creature, SPELL_TB_SPIRITUAL_IMMUNITY, true);
+ creature->CastSpell(creature, SPELL_TB_SPIRIT_HEAL_CHANNEL, true);
+ break;
+ default:
+ break;
+ }
+};
+
+void BattlefieldTB::OnGameObjectCreate(GameObject* go)
+{
+ switch (go->GetEntry())
+ {
+ case GO_TOLBARAD_GATES:
+ TBGatesGUID = go->GetGUID();
+ go->SetGoState(GetState() == BATTLEFIELD_WARMUP ? GO_STATE_READY : GO_STATE_ACTIVE);
+ break;
+ case GO_TOLBARAD_DOOR:
+ TBDoorGUID = go->GetGUID();
+ go->SetGoState(GetState() == BATTLEFIELD_INACTIVE ? GO_STATE_ACTIVE : GO_STATE_READY);
+ break;
+ case GO_GATE_TO_THE_HOLE:
+ m_gateToTheHoleGUID = go->GetGUID();
+ go->SetGoState(m_iCellblockRandom == CELLBLOCK_THE_HOLE ? GO_STATE_ACTIVE : GO_STATE_READY);
+ break;
+ case GO_GATE_D_BLOCK:
+ m_gateDBlockGUID = go->GetGUID();
+ go->SetGoState(m_iCellblockRandom == CELLBLOCK_D_BLOCK ? GO_STATE_ACTIVE : GO_STATE_READY);
+ break;
+ case GO_CURSED_DEPTHS_GATE:
+ m_gateCursedDepthsGUID = go->GetGUID();
+ go->SetGoState(m_iCellblockRandom == CELLBLOCK_CURSED_DEPTHS ? GO_STATE_ACTIVE : GO_STATE_READY);
+ break;
+ case GO_CRATE_OF_CELLBLOCK_RATIONS:
+ case GO_CURSED_SHACKLES:
+ case GO_DUSTY_PRISON_JOURNAL:
+ case GO_TB_MEETING_STONE:
+ case GO_TB_INSTANCE_VISUAL_1:
+ case GO_TB_INSTANCE_VISUAL_2:
+ case GO_TB_INSTANCE_VISUAL_3:
+ case GO_TB_INSTANCE_VISUAL_4:
+ BattleInactiveGOs.insert(go->GetGUID());
+ if (GetState() == BATTLEFIELD_WARMUP) // If battle is about to start, we must hide these.
+ go->SetRespawnTime(RESPAWN_ONE_DAY);
+ break;
+ default:
+ break;
+ }
+};
+
+void BattlefieldTB::ProcessEvent(WorldObject* obj, uint32 eventId)
+{
+ if (!IsWarTime())
+ return;
+
+ if (eventId == EVENT_COUNT_CAPTURED_BASE)
+ {
+ UpdateCapturedBaseCount();
+ return;
+ }
+
+ if (!obj)
+ return;
+
+ GameObject* go = obj->ToGameObject();
+ if (!go)
+ return;
+
+ TBTowerId towerId;
+ switch (go->GetEntry())
+ {
+ case GO_WEST_SPIRE:
+ towerId = TB_TOWER_WEST_SPIRE;
+ break;
+ case GO_EAST_SPIRE:
+ towerId = TB_TOWER_EAST_SPIRE;
+ break;
+ case GO_SOUTH_SPIRE:
+ towerId = TB_TOWER_SOUTH_SPIRE;
+ break;
+ default:
+ return;
+ }
+
+ if (go->GetDestructibleState() == GO_DESTRUCTIBLE_DAMAGED)
+ TowerDamaged(towerId);
+ else if (go->GetDestructibleState() == GO_DESTRUCTIBLE_DESTROYED)
+ TowerDestroyed(towerId);
+}
+
+void BattlefieldTB::TowerDamaged(TBTowerId tbTowerId)
+{
+ if (!IsWarTime())
+ return;
+
+ SendWarning(TBTowers[tbTowerId].textDamaged);
+
+ SetData(BATTLEFIELD_TB_DATA_TOWERS_INTACT, GetData(BATTLEFIELD_TB_DATA_TOWERS_INTACT) - 1);
+
+ SendUpdateWorldState(uint32(TBTowers[tbTowerId].wsIntact[GetDefenderTeam()]), int32(0));
+ SendUpdateWorldState(uint32(TBTowers[tbTowerId].wsDamaged[GetDefenderTeam()]), int32(1));
+
+ TeamCastSpell(GetAttackerTeam(), SPELL_REWARD_TOWER_DAMAGED);
+}
+
+void BattlefieldTB::TowerDestroyed(TBTowerId tbTowerId)
+{
+ if (!IsWarTime())
+ return;
+
+ // Add 5 minute bonus time
+ m_Timer += m_BonusTime;
+
+ SendUpdateWorldState(TB_WS_TIME_BATTLE_END, uint32(time(NULL) + (m_Timer / 1000)));
+
+ SendWarning(TBTowers[tbTowerId].textDamaged);
+
+ SetData(BATTLEFIELD_TB_DATA_TOWERS_DESTROYED, GetData(BATTLEFIELD_TB_DATA_TOWERS_DESTROYED) + 1);
+ SendUpdateWorldState(uint32(TB_WS_TOWERS_DESTROYED), int32(GetData(BATTLEFIELD_TB_DATA_TOWERS_DESTROYED)));
+
+ SendUpdateWorldState(uint32(TBTowers[tbTowerId].wsDamaged[GetDefenderTeam()]), int32(0));
+ SendUpdateWorldState(uint32(TBTowers[tbTowerId].wsDestroyed), int32(1));
+
+ // Attack bonus buff
+ for (GuidSet::const_iterator itr = m_PlayersInWar[GetAttackerTeam()].begin(); itr != m_PlayersInWar[GetAttackerTeam()].end(); ++itr)
+ if (Player* player = ObjectAccessor::FindPlayer(*itr))
+ player->CastCustomSpell(SPELL_TOWER_ATTACK_BONUS, SPELLVALUE_AURA_STACK, GetData(BATTLEFIELD_TB_DATA_TOWERS_DESTROYED), player, TRIGGERED_FULL_MASK);
+
+ // Honor reward
+ TeamCastSpell(GetAttackerTeam(), SPELL_REWARD_TOWER_DESTROYED);
+}
+
+void BattlefieldTB::UpdateCapturedBaseCount()
+{
+ uint32 numCapturedBases = 0; // How many bases attacker has captured
+
+ for (BfCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr)
+ if (itr->second->GetTeamId() == GetAttackerTeam())
+ numCapturedBases += 1;
+
+ SetData(BATTLEFIELD_TB_DATA_BUILDINGS_CAPTURED, numCapturedBases);
+ SendUpdateWorldState(TB_WS_BUILDINGS_CAPTURED, uint32(numCapturedBases));
+
+ // Check if attackers won
+ if (numCapturedBases == TB_BASE_COUNT)
+ EndBattle(false);
+}
+
+// Called when player kill a unit in wg zone
+void BattlefieldTB::HandleKill(Player* killer, Unit* victim)
+{
+ if (killer == victim || victim->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ TeamId killerTeam = killer->GetTeamId();
+ for (GuidSet::const_iterator itr = m_PlayersInWar[killerTeam].begin(); itr != m_PlayersInWar[killerTeam].end(); ++itr)
+ if (Player* player = ObjectAccessor::FindPlayer(*itr))
+ if (player->GetDistance2d(killer) < 40.0f)
+ PromotePlayer(player);
+}
+
+void BattlefieldTB::PromotePlayer(Player* killer)
+{
+ if (!m_isActive || killer->HasAura(SPELL_TB_VETERAN))
+ return;
+
+ killer->CastSpell(killer, SPELL_TB_VETERAN, true);
+}
+
+TolBaradCapturePoint::TolBaradCapturePoint(BattlefieldTB* battlefield, TeamId teamInControl) : BfCapturePoint(battlefield)
+{
+ m_Bf = battlefield;
+ m_team = teamInControl;
+ m_value = teamInControl == TEAM_ALLIANCE ? m_maxValue : -m_maxValue;
+ m_State = teamInControl == TEAM_ALLIANCE ? BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE : BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE;
+}
+
+void TolBaradCapturePoint::ChangeTeam(TeamId /*oldTeam*/)
+{
+ // Find out index
+ uint8 iBase = TB_BASE_COUNT;
+ for (uint8 i = 0; i < TB_BASE_COUNT; i++)
+ if (GetCapturePointEntry() == TBCapturePoints[i].entryFlagPole[m_Bf->GetDefenderTeam()])
+ iBase = i;
+
+ if (iBase == TB_BASE_COUNT)
+ return;
+
+ // Turn off previous world state icon
+ switch (m_OldState)
+ {
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE:
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE:
+ SendUpdateWorldState(TBCapturePoints[iBase].wsControlled[GetTeamId()], uint32(0));
+ break;
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE:
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE:
+ SendUpdateWorldState(TBCapturePoints[iBase].wsCapturing[TEAM_ALLIANCE], uint32(0));
+ break;
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE:
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE:
+ SendUpdateWorldState(TBCapturePoints[iBase].wsCapturing[TEAM_HORDE], uint32(0));
+ break;
+ default:
+ break;
+ }
+
+ // Turn on new world state icon and send warning
+ switch (m_State)
+ {
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE:
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE:
+ m_Bf->SendWarning(TBCapturePoints[iBase].textGained[GetTeamId()]);
+ SendUpdateWorldState(TBCapturePoints[iBase].wsControlled[GetTeamId()], uint32(1));
+ GetCapturePointGo()->SetGoArtKit(GetTeamId() == TEAM_ALLIANCE ? TB_GO_ARTKIT_FLAG_ALLIANCE : TB_GO_ARTKIT_FLAG_HORDE);
+ break;
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE:
+ m_Bf->SendWarning(TBCapturePoints[iBase].textLost[TEAM_HORDE]);
+ //no break here!
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE:
+ SendUpdateWorldState(TBCapturePoints[iBase].wsCapturing[TEAM_ALLIANCE], uint32(1));
+ GetCapturePointGo()->SetGoArtKit(TB_GO_ARTKIT_FLAG_NONE);
+ break;
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE:
+ m_Bf->SendWarning(TBCapturePoints[iBase].textLost[TEAM_ALLIANCE]);
+ //no break here!
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE:
+ SendUpdateWorldState(TBCapturePoints[iBase].wsCapturing[TEAM_HORDE], uint32(1));
+ GetCapturePointGo()->SetGoArtKit(TB_GO_ARTKIT_FLAG_NONE);
+ break;
+ default:
+ break;
+ }
+
+ // Update counter
+ m_Bf->ProcessEvent(NULL, EVENT_COUNT_CAPTURED_BASE);
+}
diff --git a/src/server/game/Battlefield/Zones/BattlefieldTB.h b/src/server/game/Battlefield/Zones/BattlefieldTB.h
new file mode 100644
index 00000000000..06182c78e61
--- /dev/null
+++ b/src/server/game/Battlefield/Zones/BattlefieldTB.h
@@ -0,0 +1,728 @@
+/*
+* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+*
+* 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 BATTLEFIELD_TB_
+#define BATTLEFIELD_TB_
+
+#include "Battlefield.h"
+
+class BattlefieldTB;
+class TolBaradCapturePoint;
+
+enum TolBaradInfo
+{
+ BATTLEFIELD_TB_MAPID = 732, // Tol Barad
+ BATTLEFIELD_TB_ZONEID = 5095, // Tol Barad
+};
+
+enum TolBaradData
+{
+ BATTLEFIELD_TB_DATA_BUILDINGS_CAPTURED,
+ BATTLEFIELD_TB_DATA_TOWERS_INTACT,
+ BATTLEFIELD_TB_DATA_TOWERS_DESTROYED,
+ BATTLEFIELD_TB_DATA_MAX,
+};
+
+enum TolBaradSpells
+{
+ // Quest completion
+ SPELL_VICTORY_ALLIANCE = 94665,
+ SPELL_VICTORY_HORDE = 94763,
+
+ // Rewards
+ SPELL_REWARD_VICTORY_ALLIANCE = 89789,
+ SPELL_REWARD_VICTORY_HORDE = 89791,
+ SPELL_REWARD_DEFEAT = 89793,
+
+ SPELL_REWARD_TOWER_INTACT = 89794,
+ SPELL_REWARD_TOWER_DAMAGED = 89795,
+ SPELL_REWARD_TOWER_DESTROYED = 89796,
+
+ // Player buffs
+ SPELL_TB_SLOW_FALL = 88473,
+ SPELL_TB_VETERAN = 84655,
+ SPELL_TOWER_ATTACK_BONUS = 82629,
+ SPELL_TB_SPIRIT_HEAL_CHANNEL = 22011, // this spell replaces m_LastResurrectTimer in Battlefield.cpp?
+ SPELL_TB_SPIRITUAL_IMMUNITY = 95332,
+
+ // Vehicle
+ SPELL_THICK_LAYER_OF_RUST = 95330,
+ SPELL_RIDE_TOL_BARAD_VEHICLE = 84754,
+ SPELL_DEPLOY_SIEGE_MODE = 84974,
+ SPELL_SIEGE_CANNON_AURA = 85167, // aura, periodically triggers spell 85122
+// SPELL_SIEGE_CANNON_EFFECT = 85122, // targets random
+// SPELL_SIEGE_CANNON_DAMAGE = 85125,
+ SPELL_LEAVE_SIEGE_MODE = 85078,
+
+ SPELL_TOWER_RANGE_FINDER_PERIODIC = 85671,
+ SPELL_TOWER_RANGE_FINDER = 84979,
+
+ // Teleportation spells
+ SPELL_TB_THE_HOLE_TELEPORT = 89035,
+ SPELL_TB_D_BLOCK_TELEPORT = 89037,
+ SPELL_TB_CURSED_DEPTHS_TELEPORT = 89038,
+};
+
+enum TolBaradNpcs
+{
+ // Cursed Depths area
+ NPC_TOLBARAD_CAPTIVE_SPIRIT = 47531,
+ NPC_TOLBARAD_CELLBLOCK_OOZE = 47534,
+ NPC_TOLBARAD_ARCHMAGE_GALUS = 47537,
+ NPC_TOLBARAD_GHASTLY_CONVICT = 47590,
+
+ // D-Block area
+ NPC_TOLBARAD_SHIVARRA_DESTROYER = 47540,
+ NPC_TOLBARAD_CELL_WATCHER = 47542,
+ NPC_TOLBARAD_SVARNOS = 47544,
+ NPC_TOLBARAD_JAILED_WRATHGUARD = 47548,
+ NPC_TOLBARAD_IMPRISONED_IMP = 47549,
+
+ // The Hole area
+ NPC_TOLBARAD_WARDEN_SILVA = 48036,
+ NPC_TOLBARAD_WARDEN_GUARD = 47561,
+ NPC_TOLBARAD_IMPRISONED_WORKER = 47550,
+ NPC_TOLBARAD_EXILED_MAGE = 47552,
+
+ // Other
+ NPC_CROCOLISK = 47591,
+ NPC_PROBLIM = 47593,
+
+ // Graveyard spirits
+ NPC_TB_GY_SPIRIT_BARADIN_HOLD_A = 45066,
+ NPC_TB_GY_SPIRIT_BARADIN_HOLD_H = 45067,
+ NPC_TB_GY_SPIRIT_IRONCLAD_GARRISON_A = 45068,
+ NPC_TB_GY_SPIRIT_WARDENS_VIGIL_A = 45069,
+ NPC_TB_GY_SPIRIT_EAST_SPIRE_A = 45070,
+ NPC_TB_GY_SPIRIT_SOUTH_SPIRE_A = 45071,
+ NPC_TB_GY_SPIRIT_WEST_SPIRE_A = 45072,
+ NPC_TB_GY_SPIRIT_SLAGWORKS_A = 45073,
+ NPC_TB_GY_SPIRIT_IRONCLAD_GARRISON_H = 45074,
+ NPC_TB_GY_SPIRIT_WARDENS_VIGIL_H = 45075,
+ NPC_TB_GY_SPIRIT_SLAGWORKS_H = 45076,
+ NPC_TB_GY_SPIRIT_WEST_SPIRE_H = 45077,
+ NPC_TB_GY_SPIRIT_EAST_SPIRE_H = 45078,
+ NPC_TB_GY_SPIRIT_SOUTH_SPIRE_H = 45079,
+
+ // Stalker, dummies
+ NPC_DEBUG_ANNOUNCER = 43679,
+ NPC_TOWER_RANGE_FINDER = 45492,
+ NPC_TOWER_CANNON_TARGET = 45561,
+ NPC_SIEGE_ENGINE_TURRET = 45564,
+};
+
+enum TolBaradGOs
+{
+ // Towers
+ GO_WEST_SPIRE = 204588,
+ GO_EAST_SPIRE = 204589,
+ GO_SOUTH_SPIRE = 204590,
+
+ GO_CAPTURE_POINT_NORTH_A_DEFENDING = 205068,
+ GO_CAPTURE_POINT_NORTH_H_DEFENDING = 205096,
+ GO_CAPTURE_POINT_EAST_A_DEFENDING = 205138,
+ GO_CAPTURE_POINT_EAST_H_DEFENDING = 205139,
+ GO_CAPTURE_POINT_WEST_A_DEFENDING = 205101,
+ GO_CAPTURE_POINT_WEST_H_DEFENDING = 205103,
+
+ // Entrance gates and instance door
+ GO_TOLBARAD_GATES = 206598,
+ GO_TOLBARAD_DOOR = 206576,
+
+ // Other
+ GO_TB_MEETING_STONE = 206668,
+
+ GO_TB_INSTANCE_VISUAL_1 = 207746,
+ GO_TB_INSTANCE_VISUAL_2 = 207747,
+ GO_TB_INSTANCE_VISUAL_3 = 210114,
+ GO_TB_INSTANCE_VISUAL_4 = 210115,
+};
+
+enum TolBaradGOArtKit
+{
+ TB_GO_ARTKIT_FLAG_NONE = 0,
+ TB_GO_ARTKIT_FLAG_HORDE = 1,
+ TB_GO_ARTKIT_FLAG_ALLIANCE = 2,
+};
+
+enum TolBaradWorldStates
+{
+ TB_WS_ALLIANCE_CONTROLS_SHOW = 5385,
+ TB_WS_HORDE_CONTROLS_SHOW = 5384,
+ TB_WS_ALLIANCE_ATTACKING_SHOW = 5546,
+ TB_WS_HORDE_ATTACKING_SHOW = 5547,
+
+ TB_WS_BUILDINGS_CAPTURED = 5348,
+ TB_WS_BUILDINGS_CAPTURED_SHOW = 5349,
+ TB_WS_TOWERS_DESTROYED = 5347,
+ TB_WS_TOWERS_DESTROYED_SHOW = 5350,
+
+ TB_WS_FACTION_CONTROLLING = 5334, // 1 -> Alliance, 2 -> Horde
+
+ TB_WS_TIME_NEXT_BATTLE = 5332,
+ TB_WS_TIME_NEXT_BATTLE_SHOW = 5387,
+ TB_WS_TIME_BATTLE_END = 5333,
+ TB_WS_TIME_BATTLE_END_SHOW = 5346,
+
+ TB_WS_STATE_PREPARATIONS = 5684,
+ TB_WS_STATE_BATTLE = 5344,
+
+ /* Not Sure if TB
+ TB_WS_0_UNKNOWN = 5587,
+ TB_WS_9_UNKNOWN = 5508,
+ TB_WS_35_UNKNOWN = 5679,
+ TB_WS_36_UNKNOWN = 5678,
+ TB_WS_37_UNKNOWN = 5677,
+ TB_WS_60_UNKNOWN = 5361,
+ TB_WS_61_UNKNOWN = 5360,
+ TB_WS_65_UNKNOWN = 5195,
+ TB_WS_66_UNKNOWN = 5193,
+ */
+
+ TB_WS_PROGRESS_SHOW = 5376,
+ TB_WS_PROGRESS = 5377, // 0 horde, 100 alliance
+ TB_WS_PROGRESS_PERCENT_GREY = 5378,
+
+ TB_WS_KEEP_HORDE = 5469,
+ TB_WS_KEEP_ALLIANCE = 5470,
+
+ TB_WS_GARRISON_HORDE_CONTROLLED = 5418,
+ TB_WS_GARRISON_HORDE_CAPTURING = 5419,
+ TB_WS_GARRISON_NEUTRAL = 5420, // unused
+ TB_WS_GARRISON_ALLIANCE_CAPTURING = 5421,
+ TB_WS_GARRISON_ALLIANCE_CONTROLLED = 5422,
+
+ TB_WS_VIGIL_HORDE_CONTROLLED = 5423,
+ TB_WS_VIGIL_HORDE_CAPTURING = 5424,
+ TB_WS_VIGIL_NEUTRAL = 5425, // unused
+ TB_WS_VIGIL_ALLIANCE_CAPTURING = 5426,
+ TB_WS_VIGIL_ALLIANCE_CONTROLLED = 5427,
+
+ TB_WS_SLAGWORKS_HORDE_CONTROLLED = 5428,
+ TB_WS_SLAGWORKS_HORDE_CAPTURING = 5429,
+ TB_WS_SLAGWORKS_NEUTRAL = 5430, // unused
+ TB_WS_SLAGWORKS_ALLIANCE_CAPTURING = 5431,
+ TB_WS_SLAGWORKS_ALLIANCE_CONTROLLED = 5432,
+
+ TB_WS_WEST_INTACT_HORDE = 5433,
+ TB_WS_WEST_DAMAGED_HORDE = 5434,
+ TB_WS_WEST_DESTROYED_NEUTRAL = 5435,
+ TB_WS_WEST_INTACT_ALLIANCE = 5436,
+ TB_WS_WEST_DAMAGED_ALLIANCE = 5437,
+ TB_WS_WEST_INTACT_NEUTRAL = 5453, // unused
+ TB_WS_WEST_DAMAGED_NEUTRAL = 5454, // unused
+
+ TB_WS_SOUTH_INTACT_HORDE = 5438,
+ TB_WS_SOUTH_DAMAGED_HORDE = 5439,
+ TB_WS_SOUTH_DESTROYED_NEUTRAL = 5440,
+ TB_WS_SOUTH_INTACT_ALLIANCE = 5441,
+ TB_WS_SOUTH_DAMAGED_ALLIANCE = 5442,
+ TB_WS_SOUTH_INTACT_NEUTRAL = 5455, // unused
+ TB_WS_SOUTH_DAMAGED_NEUTRAL = 5456, // unused
+
+ TB_WS_EAST_INTACT_HORDE = 5443,
+ TB_WS_EAST_DAMAGED_HORDE = 5444,
+ TB_WS_EAST_DESTROYED_NEUTRAL = 5445,
+ TB_WS_EAST_INTACT_ALLIANCE = 5446,
+ TB_WS_EAST_DAMAGED_ALLIANCE = 5447,
+ TB_WS_EAST_INTACT_NEUTRAL = 5451,
+ TB_WS_EAST_DAMAGED_NEUTRAL = 5452,
+};
+
+enum TolBaradText
+{
+ // DEBUG Announcer
+ TB_TEXT_EAST_SPIRE_DAMAGED = 1,
+ TB_TEXT_EAST_SPIRE_DESTROYED = 2,
+ TB_TEXT_WEST_SPIRE_DAMAGED = 3,
+ TB_TEXT_WEST_SPIRE_DESTROYED = 4,
+ TB_TEXT_SOUTH_SPIRE_DAMAGED = 5,
+ TB_TEXT_SOUTH_SPIRE_DESTROYED = 6,
+ TB_TEXT_GARRISON_ALLIANCE_GAINED = 7,
+ TB_TEXT_GARRISON_ALLIANCE_LOST = 8,
+ TB_TEXT_GARRISON_HORDE_GAINED = 9,
+ TB_TEXT_GARRISON_HORDE_LOST = 10,
+ TB_TEXT_VIGIL_ALLIANCE_GAINED = 11,
+ TB_TEXT_VIGIL_ALLIANCE_LOST = 12,
+ TB_TEXT_VIGIL_HORDE_GAINED = 13,
+ TB_TEXT_VIGIL_HORDE_LOST = 14,
+ TB_TEXT_SLAGWORKS_ALLIANCE_GAINED = 15,
+ TB_TEXT_SLAGWORKS_ALLIANCE_LOST = 16,
+ TB_TEXT_SLAGWORKS_HORDE_GAINED = 17,
+ TB_TEXT_SLAGWORKS_HORDE_LOST = 18,
+ TB_TEXT_FORTRESS_DEFEND_ALLIANCE = 19,
+ TB_TEXT_FORTRESS_DEFEND_HORDE = 20,
+ TB_TEXT_FORTRESS_CAPTURE_ALLIANCE = 21,
+ TB_TEXT_FORTRESS_CAPTURE_HORDE = 22,
+ TB_TEXT_VEHICLE_OUTSIDE_WARNING = 23,
+ TB_TEXT_PREPARATIONS_IN_5_MIN = 24,
+ TB_TEXT_PREPARATIONS_IN_2_MIN = 25,
+ TB_TEXT_PREPARATIONS_IN_1_MIN = 26,
+};
+
+enum TolBaradEvent
+{
+ EVENT_COUNT_CAPTURED_BASE = 1,
+};
+
+const uint32 TBFactions[BG_TEAMS_COUNT] = { 1610, 1732 };
+
+// Stalker
+Position const TolBaradDebugAnnouncerPos = { -1234.25f, 961.903f, 159.4913f, 0.0f };
+
+// Quest Infantry NPCs
+enum TBQuestInfantryEntry
+{
+ NPC_ALLIANCE_WARRIOR_INFANTRY = 47599,
+ NPC_ALLIANCE_PALADIN_INFANTRY = 47600,
+ NPC_ALLIANCE_HUNTER_INFANTRY = 47595,
+ NPC_ALLIANCE_MAGE_INFANTRY = 47598,
+
+ NPC_HORDE_DRUID_INFANTRY = 47607,
+ NPC_HORDE_MAGE_INFANTRY = 47608,
+ NPC_HORDE_ROGUE_INFANTRY = 47609,
+ NPC_HORDE_SHAMAN_INFANTRY = 47610,
+};
+
+uint32 const TB_QUEST_INFANTRY[BG_TEAMS_COUNT][4] =
+{
+ { NPC_HORDE_DRUID_INFANTRY, NPC_HORDE_MAGE_INFANTRY, NPC_HORDE_ROGUE_INFANTRY, NPC_HORDE_SHAMAN_INFANTRY },
+ { NPC_ALLIANCE_WARRIOR_INFANTRY, NPC_ALLIANCE_PALADIN_INFANTRY, NPC_ALLIANCE_HUNTER_INFANTRY, NPC_ALLIANCE_MAGE_INFANTRY },
+};
+
+uint8 const TB_QUEST_INFANTRY_MAX = 37;
+Position const TBQuestInfantrySpawnData[TB_QUEST_INFANTRY_MAX] =
+{
+ { -930.4685f, 1020.178f, 121.5658f, 0.1537642f },
+ { -831.5157f, 975.816f, 121.5255f, 5.022717f },
+ { -837.0773f, 943.9008f, 121.5055f, 5.461119f },
+ { -839.1646f, 1024.046f, 121.5505f, 4.782219f },
+ { -881.283f, 1033.25f, 121.5243f, 0.0f },
+ { -883.038f, 924.955f, 121.5243f, 0.0f },
+ { -883.913f, 978.059f, 121.5243f, 3.388291f },
+ { -883.6224f, 950.8459f, 121.5122f, 0.8307042f },
+ { -895.181f, 1015.2f, 121.5505f, 2.652318f },
+ { -943.4023f, 961.7462f, 121.5658f, 5.258394f },
+ { -958.649f, 926.877f, 121.5243f, 0.0f },
+ { -959.743f, 1029.09f, 121.5243f, 0.0f },
+ { -964.6652f, 978.5373f, 121.5257f, 0.02025719f },
+ { -1407.14f, 721.42f, 123.5033f, 0.0f },
+ { -1414.46f, 671.66f, 123.5043f, 0.0f },
+ { -1431.7f, 623.073f, 123.5043f, 0.0f },
+ { -1434.162f, 655.8566f, 123.5051f, 4.84886f },
+ { -1445.19f, 739.729f, 123.5457f, 5.767949f },
+ { -1460.954f, 718.418f, 123.6453f, 5.178094f },
+ { -1462.48f, 694.378f, 123.5463f, 0.3441857f },
+ { -1372.23f, 683.707f, 123.5043f, 0.0f },
+ { -1479.46f, 635.799f, 123.5043f, 0.0f },
+ { -1491.259f, 734.5692f, 123.4525f, 1.529741f },
+ { -1509.024f, 688.8625f, 123.5463f, 6.243045f },
+ { -1419.311f, 1310.25f, 133.8389f, 0.0f },
+ { -1444.24f, 1266.439f, 133.8229f, 0.0f },
+ { -1450.569f, 1337.351f, 133.914f, 0.0f },
+ { -1479.819f, 1331.34f, 153.2f, 0.0f },
+ { -1497.62f, 1276.429f, 133.6676f, 3.147845f },
+ { -1498.37f, 1379.689f, 133.827f, 0.0f },
+ { -1499.97f, 1232.87f, 133.8239f, 0.0f },
+ { -1505.7f, 1261.99f, 133.7089f, 0.6167698f },
+ { -1531.84f, 1316.569f, 153.2f, 0.0f },
+ { -1533.141f, 1267.66f, 133.836f, 0.0f },
+ { -1547.59f, 1300.21f, 133.7094f, 1.908187f },
+ { -1563.3f, 1325.79f, 133.6673f, 0.0f },
+};
+
+// Guard NPCs
+enum TBGuardEntry
+{
+ NPC_BARADIN_GUARD = 51165,
+ NPC_HELLSCREAMS_SENTRY = 51166,
+};
+
+uint8 const TB_GUARDS_MAX = 8;
+Position const GuardNPCSpawns[TB_GUARDS_MAX] =
+{
+// { -837.3768f, 1196.082f, 114.2994f, 3.036873f },
+// { -762.118f, 1195.259f, 107.2007f, 3.036873f },
+// { -837.809f, 1179.842f, 114.1356f, 3.159046f },
+// { -762.5504f, 1179.019f, 107.2137f, 3.159046f },
+ { -1272.951f, 964.8854f, 119.5782f, 3.193953f },
+ { -1274.394f, 997.6511f, 119.5743f, 3.193953f },
+ { -1248.226f, 1018.476f, 119.8113f, 1.605703f },
+ { -1218.948f, 943.5695f, 119.5994f, 4.625123f },
+ { -1195.417f, 965.5364f, 119.8113f, 0.0f },
+ { -1220.832f, 1018.497f, 119.8113f, 1.605703f },
+ { -1196.151f, 999.5121f, 119.5966f, 0.0f },
+ { -1249.304f, 942.9063f, 119.5782f, 4.625123f },
+};
+
+enum TBFactionNPCEntry
+{
+ // Guards
+ NPC_BARADIN_GUARD_1 = 47324,
+ NPC_BARADIN_GUARD_2 = 47325,
+ NPC_BARADIN_GRUNT_1 = 47335,
+ NPC_BARADIN_GRUNT_2 = 47336,
+
+ // Questgivers
+ NPC_SERGEANT_PARKER = 48066, // Everytime
+ NPC_COMMANDER_STEVENS = 48039, // One of these three
+ NPC_2ND_LIEUTENANT_WANSWORTH = 48061,
+ NPC_MARSHAL_FALLOWS = 48074,
+
+ NPC_COMMANDER_ZANOTH = 48069, // Everytime!
+ NPC_STAFF_SERGEANT_LAZGAR = 48062, // One of these three
+ NPC_DRILLMASTER_RAZGOTH = 48070,
+ NPC_PRIVATE_GARNOTH = 48071,
+
+ // Portal summoners
+ NPC_MAVEN_ZARA = 50173,
+ NPC_RHAGHA = 50167,
+};
+
+struct TBFactionNPCInfo
+{
+ float x;
+ float y;
+ float z;
+ float o;
+ uint32 entryAlliance;
+ uint32 entryHorde;
+};
+
+uint8 const TB_FACTION_NPC_MAX = 4;
+TBFactionNPCInfo const FactionNPCSpawns[TB_FACTION_NPC_MAX] =
+{
+ { -1259.356f, 1057.108f, 107.0786f, 4.956735f, NPC_BARADIN_GUARD_1, NPC_BARADIN_GRUNT_1 },
+ { -1254.174f, 1061.094f, 107.0772f, 5.445427f, NPC_BARADIN_GUARD_2, NPC_BARADIN_GRUNT_2 },
+ { -1256.365f, 1058.47f, 107.0776f, 2.216568f, NPC_MAVEN_ZARA, NPC_RHAGHA },
+ { -1231.38f, 985.681f, 121.2403f, 0.6108652f, NPC_SERGEANT_PARKER, NPC_COMMANDER_ZANOTH },
+};
+
+// Questing
+enum TBQuesting
+{
+ CELLBLOCK_THE_HOLE = 0, // The Hole area
+ CELLBLOCK_D_BLOCK = 1, // D-Block area
+ CELLBLOCK_CURSED_DEPTHS = 2, // Cursed Depths area
+ CELLBLOCK_MAX = 3,
+ CELLBLOCK_NONE,
+
+ AREA_THE_HOLE = 5659,
+ AREA_D_BLOCK = 5657,
+ AREA_CURSED_DEPTHS = 5658,
+
+ GO_GATE_TO_THE_HOLE = 206845,
+ GO_GATE_D_BLOCK = 206844,
+ GO_CURSED_DEPTHS_GATE = 206843,
+
+ GO_CRATE_OF_CELLBLOCK_RATIONS = 206996,
+ GO_CURSED_SHACKLES = 206905,
+ GO_DUSTY_PRISON_JOURNAL = 206890,
+};
+
+Position const RandomQuestgiverPos = { -1228.93f, 975.038f, 121.7153f, 5.969026f };
+
+struct TBQuestAreaInfo
+{
+ uint32 entry;
+ uint32 teleportSpell;
+};
+TBQuestAreaInfo const TBQuestAreas[CELLBLOCK_MAX] =
+{
+ { AREA_THE_HOLE, SPELL_TB_THE_HOLE_TELEPORT },
+ { AREA_D_BLOCK, SPELL_TB_D_BLOCK_TELEPORT },
+ { AREA_CURSED_DEPTHS, SPELL_TB_CURSED_DEPTHS_TELEPORT },
+};
+uint32 const RandomQuestgivers[BG_TEAMS_COUNT][CELLBLOCK_MAX] =
+{
+ { NPC_MARSHAL_FALLOWS, NPC_2ND_LIEUTENANT_WANSWORTH, NPC_COMMANDER_STEVENS },
+ { NPC_DRILLMASTER_RAZGOTH, NPC_STAFF_SERGEANT_LAZGAR, NPC_PRIVATE_GARNOTH },
+};
+
+// Capture Points
+enum TBCapturePointId
+{
+ TB_BASE_IRONCLAD_GARRISON = 0,
+ TB_BASE_WARDENS_VIGIL = 1,
+ TB_BASE_SLAGWORKS = 2,
+ TB_BASE_COUNT = 3,
+};
+
+struct TBCapturePointSpawnData
+{
+ float x;
+ float y;
+ float z;
+ float o;
+ TBCapturePointId id;
+ uint32 entryFlagPole[2];
+ uint32 wsControlled[2];
+ uint32 wsCapturing[2];
+ uint32 wsNeutral;
+ uint32 textGained[2];
+ uint32 textLost[2];
+};
+
+TBCapturePointSpawnData const TBCapturePoints[TB_BASE_COUNT] =
+{
+ { -896.96f, 979.497f, 121.441f, 3.124123f, TB_BASE_IRONCLAD_GARRISON, { GO_CAPTURE_POINT_NORTH_A_DEFENDING, GO_CAPTURE_POINT_NORTH_H_DEFENDING }, { TB_WS_GARRISON_ALLIANCE_CONTROLLED, TB_WS_GARRISON_HORDE_CONTROLLED }, { TB_WS_GARRISON_ALLIANCE_CAPTURING, TB_WS_GARRISON_HORDE_CAPTURING }, TB_WS_GARRISON_NEUTRAL, { TB_TEXT_GARRISON_ALLIANCE_GAINED, TB_TEXT_GARRISON_HORDE_GAINED }, { TB_TEXT_GARRISON_ALLIANCE_LOST, TB_TEXT_GARRISON_HORDE_LOST } },
+ { -1492.34f, 1309.87f, 152.961f, 5.462882f, TB_BASE_WARDENS_VIGIL, { GO_CAPTURE_POINT_WEST_A_DEFENDING, GO_CAPTURE_POINT_WEST_H_DEFENDING }, { TB_WS_VIGIL_ALLIANCE_CONTROLLED, TB_WS_VIGIL_HORDE_CONTROLLED }, { TB_WS_VIGIL_ALLIANCE_CAPTURING, TB_WS_VIGIL_HORDE_CAPTURING }, TB_WS_VIGIL_NEUTRAL, { TB_TEXT_VIGIL_ALLIANCE_GAINED, TB_TEXT_VIGIL_HORDE_GAINED }, { TB_TEXT_VIGIL_ALLIANCE_LOST, TB_TEXT_VIGIL_HORDE_LOST } },
+ { -1437.f, 685.556f, 123.421f, 0.802851f, TB_BASE_SLAGWORKS, { GO_CAPTURE_POINT_EAST_A_DEFENDING, GO_CAPTURE_POINT_EAST_H_DEFENDING }, { TB_WS_SLAGWORKS_ALLIANCE_CONTROLLED, TB_WS_SLAGWORKS_HORDE_CONTROLLED }, { TB_WS_SLAGWORKS_ALLIANCE_CAPTURING, TB_WS_SLAGWORKS_HORDE_CAPTURING }, TB_WS_SLAGWORKS_NEUTRAL, { TB_TEXT_SLAGWORKS_ALLIANCE_GAINED, TB_TEXT_SLAGWORKS_HORDE_GAINED }, { TB_TEXT_SLAGWORKS_ALLIANCE_LOST, TB_TEXT_SLAGWORKS_HORDE_LOST } },
+};
+
+// Towers
+enum TBTowerId
+{
+ TB_TOWER_EAST_SPIRE = 0,
+ TB_TOWER_SOUTH_SPIRE = 1,
+ TB_TOWER_WEST_SPIRE = 2,
+ TB_TOWERS_COUNT = 3,
+};
+
+struct TBTowerInfo
+{
+ float x;
+ float y;
+ float z;
+ float o;
+ uint32 entry;
+ uint32 textDamaged;
+ uint32 textDestroyed;
+ uint32 wsIntact[BG_TEAMS_COUNT];
+ uint32 wsDamaged[BG_TEAMS_COUNT];
+ uint32 wsDestroyed;
+};
+
+TBTowerInfo const TBTowers[TB_TOWERS_COUNT] =
+{
+ { -1013.279f, 529.5382f, 146.427f, 1.97222f, GO_EAST_SPIRE, TB_TEXT_EAST_SPIRE_DAMAGED, TB_TEXT_EAST_SPIRE_DESTROYED, { TB_WS_EAST_INTACT_ALLIANCE, TB_WS_EAST_INTACT_HORDE }, { TB_WS_EAST_DAMAGED_ALLIANCE, TB_WS_EAST_DAMAGED_HORDE }, TB_WS_EAST_DESTROYED_NEUTRAL },
+ { -1618.91f, 954.5417f, 168.601f, 0.06981169f, GO_SOUTH_SPIRE, TB_TEXT_SOUTH_SPIRE_DAMAGED, TB_TEXT_SOUTH_SPIRE_DESTROYED, { TB_WS_SOUTH_INTACT_ALLIANCE, TB_WS_SOUTH_INTACT_HORDE }, { TB_WS_SOUTH_DAMAGED_ALLIANCE, TB_WS_SOUTH_DAMAGED_HORDE }, TB_WS_SOUTH_DESTROYED_NEUTRAL },
+ { -950.4097f, 1469.101f, 176.596f, 4.180066f, GO_WEST_SPIRE, TB_TEXT_WEST_SPIRE_DAMAGED, TB_TEXT_WEST_SPIRE_DESTROYED, { TB_WS_WEST_INTACT_ALLIANCE, TB_WS_WEST_INTACT_HORDE }, { TB_WS_WEST_DAMAGED_ALLIANCE, TB_WS_WEST_DAMAGED_HORDE }, TB_WS_WEST_DESTROYED_NEUTRAL },
+};
+
+// Vehicles
+enum TBVehicles
+{
+ NPC_ABANDONED_SIEGE_ENGINE = 45344,
+};
+
+int8 const TB_ABANDONED_SIEGE_ENGINE_COUNT = 6;
+Position const TBAbandonedSiegeEngineSpawnData[TB_ABANDONED_SIEGE_ENGINE_COUNT] =
+{
+ { -1106.57f, 1196.34f, 121.8023f, 0.4014257f },
+ { -1108.52f, 1111.33f, 121.2783f, 1.37881f },
+ { -1213.01f, 782.236f, 121.4473f, 1.675516f },
+ { -1258.26f, 780.497f, 122.4413f, 1.48353f },
+ { -1438.3f, 1095.24f, 121.1363f, 5.288348f },
+ { -1442.3f, 1141.07f, 123.6323f, 4.24115f },
+};
+
+// Banners
+enum TBFactionBannerEntry
+{
+ GO_BARADINS_WARDEN_BANNER = 207391, // Alliance banner
+ GO_HELLSCREAM_REACH_BANNER = 207400, // Horde banner
+};
+
+uint32 const TBBannerEntry[BG_TEAMS_COUNT] = { GO_BARADINS_WARDEN_BANNER, GO_HELLSCREAM_REACH_BANNER };
+
+uint8 const TB_BANNER_MAX = 23;
+Position const TBBanners[TB_BANNER_MAX] =
+{
+ { -987.6129f, 963.9861f, 121.4506f, 2.617989f },
+ { -988.118f, 993.0087f, 121.6746f, 3.612838f },
+ { -1195.941f, 964.342f, 119.728f, 0.8901166f },
+ { -1196.892f, 1000.957f, 119.8211f, 5.445428f },
+ { -1198.236f, 1081.898f, 120.2007f, 1.06465f },
+ { -1089.337f, 1157.161f, 120.2749f, 3.036838f },
+ { -1090.033f, 1143.476f, 120.2656f, 3.036838f },
+ { -1217.495f, 944.0261f, 119.4949f, 1.989672f },
+ { -1219.226f, 1018.168f, 119.728f, 2.251473f },
+ { -1210.319f, 1081.885f, 120.2396f, 2.007128f },
+ { -1226.903f, 786.7656f, 119.4592f, 1.553341f },
+ { -1228.464f, 979.7379f, 119.3814f, 0.03490625f },
+ { -1239.668f, 786.7899f, 119.4271f, 1.553341f },
+ { -1250.262f, 1017.887f, 119.728f, 0.8377575f },
+ { -1250.693f, 943.4496f, 119.4949f, 5.305802f },
+ { -1272.29f, 963.5208f, 119.4949f, 2.617989f },
+ { -1273.997f, 998.7934f, 119.4884f, 3.665196f },
+ { -1378.363f, 725.0087f, 124.2978f, 1.326448f },
+ { -1401.97f, 747.0972f, 123.2302f, 0.2443456f },
+ { -1421.953f, 1263.559f, 133.6141f, 5.009095f },
+ { -1446.497f, 1238.964f, 133.7601f, 5.969027f },
+ { -1488.908f, 1118.747f, 124.9255f, 6.248279f },
+ { -1488.533f, 1131.608f, 124.6363f, 6.248279f },
+};
+
+// Portals
+enum TBPortalEntry
+{
+ TB_PORTAL_ALLIANCE = 208227, // Portal to Stormwind
+ TB_PORTAL_HORDE = 208226, // Portal to Orgrimmar
+};
+
+uint32 const TBPortalEntry[BG_TEAMS_COUNT] = { TB_PORTAL_ALLIANCE, TB_PORTAL_HORDE };
+
+uint8 const TB_PORTAL_MAX = 2;
+Position const TBPortals[TB_PORTAL_MAX] =
+{
+ { -598.7656f, 1377.974f, 21.91898f, 0.0f },
+ { -1257.729f, 1060.365f, 106.9938f, 5.462882f },
+};
+
+/* ################### *
+ * Tol Barad graveyard *
+ * ################### */
+
+enum TBGraveyardAreaId
+{
+ // Tol Barad
+ TB_GY_BARADIN_HOLD = 1789,
+ TB_GY_IRONCLAD_GARRISON = 1783,
+ TB_GY_WARDENS_VIGIL = 1785,
+ TB_GY_SLAGWORKS = 1787,
+ TB_GY_WEST_SPIRE = 1784,
+ TB_GY_SOUTH_SPIRE = 1786,
+ TB_GY_EAST_SPIRE = 1788,
+ BATTLEFIELD_TB_GRAVEYARD_MAX = 7,
+
+ // Tol Barad Peninsula
+ TBP_GY_ALLIANCE_DAILY = 1808,
+ TBP_GY_HORDE_DAILY = 1807,
+};
+
+struct TBGraveyardInfo
+{
+ float x;
+ float y;
+ float z;
+ float o;
+ uint32 phaseId;
+ uint32 gyid;
+ uint32 spiritEntry[BG_TEAMS_COUNT];
+ bool defenderControls;
+};
+
+TBGraveyardInfo const TBGraveyards[BATTLEFIELD_TB_GRAVEYARD_MAX] =
+{
+ { -1247.42f, 981.25f, 155.35f, 6.28f, 128, TB_GY_BARADIN_HOLD, { NPC_TB_GY_SPIRIT_BARADIN_HOLD_A, NPC_TB_GY_SPIRIT_BARADIN_HOLD_H }, true },
+ { -974.28f, 1089.47f, 132.99f, 5.90f, 64, TB_GY_IRONCLAD_GARRISON, { NPC_TB_GY_SPIRIT_IRONCLAD_GARRISON_A, NPC_TB_GY_SPIRIT_IRONCLAD_GARRISON_H }, false },
+ { -1570.44f, 1167.57f, 159.50f, 2.20f, 64, TB_GY_WARDENS_VIGIL, { NPC_TB_GY_SPIRIT_WARDENS_VIGIL_A, NPC_TB_GY_SPIRIT_WARDENS_VIGIL_H }, false },
+ { -1343.32f, 565.24f, 139.04f, 1.66f, 64, TB_GY_SLAGWORKS, { NPC_TB_GY_SPIRIT_SLAGWORKS_A, NPC_TB_GY_SPIRIT_SLAGWORKS_H }, false },
+ { -1052.02f, 1494.05f, 191.41f, 4.13f, 64, TB_GY_WEST_SPIRE, { NPC_TB_GY_SPIRIT_WEST_SPIRE_A, NPC_TB_GY_SPIRIT_WEST_SPIRE_H }, false },
+ { -1603.34f, 874.29f, 193.69f, 5.27f, 64, TB_GY_SOUTH_SPIRE, { NPC_TB_GY_SPIRIT_SOUTH_SPIRE_A, NPC_TB_GY_SPIRIT_SOUTH_SPIRE_H }, false },
+ { -943.66f, 572.36f, 157.54f, 1.74f, 64, TB_GY_EAST_SPIRE, { NPC_TB_GY_SPIRIT_EAST_SPIRE_A, NPC_TB_GY_SPIRIT_EAST_SPIRE_H }, false },
+};
+
+/* ####################### *
+ * Tol Barad capture point *
+ * ####################### */
+
+class TolBaradCapturePoint : public BfCapturePoint
+{
+ public:
+ TolBaradCapturePoint(BattlefieldTB* battlefield, TeamId teamInControl);
+
+ void ChangeTeam(TeamId /*oldteam*/) override;
+};
+
+/* ##################### *
+ * Tol Barad battlefield *
+ * ##################### */
+
+class TC_GAME_API BattlefieldTB : public Battlefield
+{
+ public:
+ ~BattlefieldTB();
+
+ void OnStartGrouping() override;
+ void OnBattleStart() override;
+ void OnBattleEnd(bool endByTimer) override;
+
+ void OnPlayerEnterZone(Player* player) override;
+ void OnPlayerLeaveZone(Player* player) override;
+
+ void OnPlayerJoinWar(Player* player) override;
+ void OnPlayerLeaveWar(Player* player) override;
+
+ bool Update(uint32 diff) override;
+
+ void OnCreatureCreate(Creature* creature) override;
+ //void OnCreatureRemove(Creature* creature) override;
+
+ void OnGameObjectCreate(GameObject* go) override;
+
+ void UpdateCapturedBaseCount();
+ //void UpdatedDestroyedTowerCount(TeamId team);
+
+ //void DoCompleteOrIncrementAchievement(uint32 achievement, Player* player, uint8 incrementNumber = 1) override;
+
+ bool SetupBattlefield() override;
+
+ void SendInitWorldStatesTo(Player* player);
+ void SendInitWorldStatesToAll() override;
+ void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet) override;
+ void UpdateWorldStates();
+
+ void HandleKill(Player* killer, Unit* victim) override;
+ //void OnUnitDeath(Unit* unit) override;
+ void PromotePlayer(Player* killer);
+ void RemoveAurasFromPlayer(Player* player);
+
+ void ProcessEvent(WorldObject* obj, uint32 eventId) override;
+
+ void TowerDamaged(TBTowerId tbTowerId);
+ void TowerDestroyed(TBTowerId tbTowerId);
+
+ // returns the graveyardId in the specified area.
+ //uint8 GetSpiritGraveyardId(uint32 areaId) const;
+
+ void UpdateNPCsAndGameObjects();
+ void CreateCapturePoints();
+
+ protected:
+ // Minutes till battle preparation warnings
+ bool warnedFiveMinutes;
+ bool warnedTwoMinutes;
+ bool warnedOneMinute;
+
+ uint32 m_saveTimer;
+
+ bool updatedNPCAndObjects;
+ uint32 m_updateObjectsTimer;
+
+ uint32 m_BonusTime;
+
+ GuidSet BattleInactiveNPCs;
+ GuidSet BattleInactiveGOs;
+
+ GuidSet TemporaryNPCs;
+ GuidSet TemporaryGOs;
+
+ GuidSet Towers;
+
+ uint8 m_iCellblockRandom;
+
+ ObjectGuid TBGatesGUID;
+ ObjectGuid TBDoorGUID;
+
+ ObjectGuid m_gateToTheHoleGUID;
+ ObjectGuid m_gateDBlockGUID;
+ ObjectGuid m_gateCursedDepthsGUID;
+};
+
+#endif
diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp
index 18c61a4c094..f45f14eb427 100644
--- a/src/server/game/Entities/Item/Item.cpp
+++ b/src/server/game/Entities/Item/Item.cpp
@@ -1268,7 +1268,7 @@ void Item::BuildDynamicValuesUpdate(uint8 updateType, ByteBuffer* data, Player*
std::size_t arrayBlockCount = UpdateMask::GetBlockCount(values.size());
*data << uint16(UpdateMask::EncodeDynamicFieldChangeType(arrayBlockCount, _dynamicChangesMask[index], updateType));
- if (_dynamicChangesMask[index] == UpdateMask::VALUE_AND_SIZE_CHANGED && updateType == UPDATETYPE_VALUES)
+ if (updateType == UPDATETYPE_VALUES && _dynamicChangesMask[index] == UpdateMask::VALUE_AND_SIZE_CHANGED)
*data << uint32(values.size());
std::size_t arrayMaskPos = data->wpos();
@@ -1286,9 +1286,17 @@ void Item::BuildDynamicValuesUpdate(uint8 updateType, ByteBuffer* data, Player*
}
else
{
+ uint32 m = 0;
+
+ // work around stupid item modifier field requirements - push back values mask by sizeof(m) bytes if size was not appended yet
+ if (updateType == UPDATETYPE_VALUES && _dynamicChangesMask[index] != UpdateMask::VALUE_AND_SIZE_CHANGED && _changesMask[ITEM_FIELD_MODIFIERS_MASK])
+ {
+ *data << m;
+ arrayMaskPos += sizeof(m);
+ }
+
// in case of ITEM_DYNAMIC_FIELD_MODIFIERS it is ITEM_FIELD_MODIFIERS_MASK that controls index of each value, not updatemask
// so we just have to write this starting from 0 index
- uint32 m = 0;
for (std::size_t v = 0; v < values.size(); ++v)
{
if (values[v])
@@ -1298,7 +1306,7 @@ void Item::BuildDynamicValuesUpdate(uint8 updateType, ByteBuffer* data, Player*
}
}
- if (_changesMask[ITEM_FIELD_MODIFIERS_MASK] && updateType == UPDATETYPE_VALUES)
+ if (updateType == UPDATETYPE_VALUES && _changesMask[ITEM_FIELD_MODIFIERS_MASK])
data->put(arrayMaskPos - sizeof(m), m);
}
}
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index a78caf15e44..b4cc81dd735 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -110,7 +110,7 @@ namespace UpdateMask
inline std::size_t EncodeDynamicFieldChangeType(std::size_t blockCount, DynamicFieldChangeType changeType, uint8 updateType)
{
- return blockCount | ((changeType & VALUE_AND_SIZE_CHANGED) * (3 - updateType /*this part evaluates to 0 if update type is not VALUES*/));
+ return blockCount | ((changeType & VALUE_AND_SIZE_CHANGED) * ((3 - updateType /*this part evaluates to 0 if update type is not VALUES*/) / 3));
}
template<typename T>
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index e0d958d431f..8c804f0d94e 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -24,6 +24,7 @@
#include "Battlefield.h"
#include "BattlefieldMgr.h"
#include "BattlefieldWG.h"
+#include "BattlefieldTB.h"
#include "Battleground.h"
#include "BattlegroundMgr.h"
#include "BattlegroundScore.h"
@@ -1113,8 +1114,8 @@ void Player::Update(uint32 p_time)
m_swingErrorMsg = 1;
}
}
- //120 degrees of radiant range
- else if (!HasInArc(2 * float(M_PI) / 3, victim))
+ //120 degrees of radiant range, if player is not in boundary radius
+ else if (!IsWithinBoundaryRadius(victim) && !HasInArc(2 * float(M_PI) / 3, victim))
{
setAttackTimer(BASE_ATTACK, 100);
if (m_swingErrorMsg != 2) // send single time (client auto repeat)
@@ -1142,8 +1143,10 @@ void Player::Update(uint32 p_time)
{
if (!IsWithinMeleeRange(victim))
setAttackTimer(OFF_ATTACK, 100);
- else if (!HasInArc(2 * float(M_PI) / 3, victim))
- setAttackTimer(OFF_ATTACK, 100);
+ else if (!IsWithinBoundaryRadius(victim) && !HasInArc(2 * float(M_PI) / 3, victim))
+ {
+ setAttackTimer(BASE_ATTACK, 100);
+ }
else
{
// prevent base and off attack in same time, delay attack at 0.2 sec
@@ -5031,35 +5034,7 @@ float Player::GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const
void Player::ApplyRatingMod(CombatRating combatRating, int32 value, bool apply)
{
- float oldRating = m_baseRatingValue[combatRating];
m_baseRatingValue[combatRating] += (apply ? value : -value);
-
- // explicit affected values
- float const multiplier = GetRatingMultiplier(combatRating);
- float const oldVal = oldRating * multiplier;
- float const newVal = m_baseRatingValue[combatRating] * multiplier;
- switch (combatRating)
- {
- case CR_HASTE_MELEE:
- ApplyAttackTimePercentMod(BASE_ATTACK, oldVal, false);
- ApplyAttackTimePercentMod(OFF_ATTACK, oldVal, false);
- ApplyAttackTimePercentMod(BASE_ATTACK, newVal, true);
- ApplyAttackTimePercentMod(OFF_ATTACK, newVal, true);
- if (getClass() == CLASS_DEATH_KNIGHT)
- UpdateAllRunesRegen();
- break;
- case CR_HASTE_RANGED:
- ApplyAttackTimePercentMod(RANGED_ATTACK, oldVal, false);
- ApplyAttackTimePercentMod(RANGED_ATTACK, newVal, true);
- break;
- case CR_HASTE_SPELL:
- ApplyCastTimePercentMod(oldVal, false);
- ApplyCastTimePercentMod(newVal, true);
- break;
- default:
- break;
- }
-
UpdateRating(combatRating);
}
@@ -5070,10 +5045,18 @@ void Player::UpdateRating(CombatRating cr)
// stat used stored in miscValueB for this aura
AuraEffectList const& modRatingFromStat = GetAuraEffectsByType(SPELL_AURA_MOD_RATING_FROM_STAT);
for (AuraEffectList::const_iterator i = modRatingFromStat.begin(); i != modRatingFromStat.end(); ++i)
- if ((*i)->GetMiscValue() & (1<<cr))
+ if ((*i)->GetMiscValue() & (1 << cr))
amount += int32(CalculatePct(GetStat(Stats((*i)->GetMiscValueB())), (*i)->GetAmount()));
+
+ AuraEffectList const& modRatingPct = GetAuraEffectsByType(SPELL_AURA_MOD_RATING_PCT);
+ for (AuraEffectList::const_iterator i = modRatingPct.begin(); i != modRatingPct.end(); ++i)
+ if ((*i)->GetMiscValue() & (1 << cr))
+ amount += int32(CalculatePct(amount, (*i)->GetAmount()));
+
if (amount < 0)
amount = 0;
+
+ uint32 oldRating = GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + cr);
SetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + cr, uint32(amount));
bool affectStats = CanModifyStats();
@@ -5123,10 +5106,37 @@ void Player::UpdateRating(CombatRating cr)
case CR_RESILIENCE_CRIT_TAKEN:
case CR_LIFESTEAL:
break;
- case CR_HASTE_MELEE: // Implemented in Player::ApplyRatingMod
+ case CR_HASTE_MELEE:
case CR_HASTE_RANGED:
case CR_HASTE_SPELL:
+ {
+ // explicit affected values
+ float const multiplier = GetRatingMultiplier(cr);
+ float const oldVal = oldRating * multiplier;
+ float const newVal = amount * multiplier;
+ switch (cr)
+ {
+ case CR_HASTE_MELEE:
+ ApplyAttackTimePercentMod(BASE_ATTACK, oldVal, false);
+ ApplyAttackTimePercentMod(OFF_ATTACK, oldVal, false);
+ ApplyAttackTimePercentMod(BASE_ATTACK, newVal, true);
+ ApplyAttackTimePercentMod(OFF_ATTACK, newVal, true);
+ if (getClass() == CLASS_DEATH_KNIGHT)
+ UpdateAllRunesRegen();
+ break;
+ case CR_HASTE_RANGED:
+ ApplyAttackTimePercentMod(RANGED_ATTACK, oldVal, false);
+ ApplyAttackTimePercentMod(RANGED_ATTACK, newVal, true);
+ break;
+ case CR_HASTE_SPELL:
+ ApplyCastTimePercentMod(oldVal, false);
+ ApplyCastTimePercentMod(newVal, true);
+ break;
+ default:
+ break;
+ }
break;
+ }
case CR_AVOIDANCE:
case CR_STURDINESS:
case CR_UNUSED_7:
@@ -9024,6 +9034,22 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid)
if (bg && bg->GetTypeID(true) == BATTLEGROUND_BFG)
bg->FillInitialWorldStates(packet);
break;
+ // Tol Barad Peninsula
+ case 5389:
+ if (sWorld->getBoolConfig(CONFIG_TOLBARAD_ENABLE))
+ {
+ packet.Worldstates.emplace_back(5385, sWorld->getWorldState(5385)); // TB_WS_ALLIANCE_CONTROLS_SHOW
+ packet.Worldstates.emplace_back(5384, sWorld->getWorldState(5384)); // TB_WS_HORDE_CONTROLS_SHOW
+ packet.Worldstates.emplace_back(5387, sWorld->getWorldState(5387)); // TB_WS_TIME_NEXT_BATTLE_SHOW
+ packet.Worldstates.emplace_back(5546, sWorld->getWorldState(5546)); // TB_WS_ALLIANCE_ATTACKING_SHOW
+ packet.Worldstates.emplace_back(5547, sWorld->getWorldState(5547)); // TB_WS_HORDE_ATTACKING_SHOW
+ }
+ break;
+ // Tol Barad
+ case 5095:
+ if (bf && bf->GetTypeId() == BATTLEFIELD_TB)
+ bf->FillInitialWorldStates(packet);
+ break;
// Wintergrasp
case 4197:
if (bf && bf->GetTypeId() == BATTLEFIELD_WG)
@@ -9069,6 +9095,17 @@ void Player::SendBattlefieldWorldStates() const
SendUpdateWorldState(ClockWorldState[1], uint32(time(nullptr) + timer));
}
}
+
+ if (sWorld->getBoolConfig(CONFIG_TOLBARAD_ENABLE))
+ {
+ if (Battlefield* tb = sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_TB))
+ {
+ SendUpdateWorldState(TB_WS_FACTION_CONTROLLING, uint32(tb->GetDefenderTeam() + 1));
+ uint32 timer = tb->GetTimer() / 1000;
+ SendUpdateWorldState(TB_WS_TIME_BATTLE_END, uint32(tb->IsWarTime() ? uint32(time(nullptr) + timer) : 0));
+ SendUpdateWorldState(TB_WS_TIME_NEXT_BATTLE, uint32(!tb->IsWarTime() ? uint32(time(nullptr) + timer) : 0));
+ }
+ }
}
uint32 Player::GetXPRestBonus(uint32 xp)
@@ -15113,11 +15150,34 @@ void Player::FailQuest(uint32 questId)
// Destroy quest items on quest failure.
for (QuestObjective const& obj : quest->GetObjectives())
if (obj.Type == QUEST_OBJECTIVE_ITEM)
- DestroyItemCount(obj.ObjectID, obj.Amount, true, true);
+ if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(obj.ObjectID))
+ if (itemTemplate->GetBonding() == BIND_QUEST_ITEM || itemTemplate->GetBonding() == BIND_QUEST_ITEM1)
+ DestroyItemCount(obj.ObjectID, obj.Amount, true, true);
+
// Destroy items received during the quest.
for (uint8 i = 0; i < QUEST_ITEM_DROP_COUNT; ++i)
- if (quest->ItemDrop[i] && quest->ItemDropQuantity[i])
- DestroyItemCount(quest->ItemDrop[i], quest->ItemDropQuantity[i], true, true);
+ if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->ItemDrop[i]))
+ if (quest->ItemDropQuantity[i] && (itemTemplate->GetBonding() == BIND_QUEST_ITEM || itemTemplate->GetBonding() == BIND_QUEST_ITEM1))
+ DestroyItemCount(quest->ItemDrop[i], quest->ItemDropQuantity[i], true, true);
+ }
+}
+
+void Player::AbandonQuest(uint32 questId)
+{
+ if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId))
+ {
+ // Destroy quest items on quest abandon.
+ for (QuestObjective const& obj : quest->GetObjectives())
+ if (obj.Type == QUEST_OBJECTIVE_ITEM)
+ if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(obj.ObjectID))
+ if (itemTemplate->GetBonding() == BIND_QUEST_ITEM || itemTemplate->GetBonding() == BIND_QUEST_ITEM1)
+ DestroyItemCount(obj.ObjectID, obj.Amount, true, true);
+
+ // Destroy items received during the quest.
+ for (uint8 i = 0; i < QUEST_ITEM_DROP_COUNT; ++i)
+ if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->ItemDrop[i]))
+ if (quest->ItemDropQuantity[i] && (itemTemplate->GetBonding() == BIND_QUEST_ITEM || itemTemplate->GetBonding() == BIND_QUEST_ITEM1))
+ DestroyItemCount(quest->ItemDrop[i], quest->ItemDropQuantity[i], true, true);
}
}
@@ -18739,6 +18799,8 @@ void Player::_LoadBoundInstances(PreparedQueryResult result)
// so the value read from the DB may be wrong here but only if the InstanceSave is loaded
// and in that case it is not used
+ uint32 entranceId = fields[6].GetUInt32();
+
bool deleteInstance = false;
MapEntry const* mapEntry = sMapStore.LookupEntry(mapId);
@@ -18786,7 +18848,7 @@ void Player::_LoadBoundInstances(PreparedQueryResult result)
}
// since non permanent binds are always solo bind, they can always be reset
- if (InstanceSave* save = sInstanceSaveMgr->AddInstanceSave(mapId, instanceId, Difficulty(difficulty), resetTime, !perm, true))
+ if (InstanceSave* save = sInstanceSaveMgr->AddInstanceSave(mapId, instanceId, Difficulty(difficulty), resetTime, entranceId, !perm, true))
BindToInstance(save, perm, extendState, true);
}
while (result->NextRow());
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 99591ea5729..faac57d2c28 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1514,6 +1514,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
bool CanRewardQuest(Quest const* quest, uint32 reward, bool msg);
void AddQuestAndCheckCompletion(Quest const* quest, Object* questGiver);
void AddQuest(Quest const* quest, Object* questGiver);
+ void AbandonQuest(uint32 quest_id);
void CompleteQuest(uint32 quest_id);
void IncompleteQuest(uint32 quest_id);
uint32 GetQuestMoneyReward(Quest const* quest) const;
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 1dde054a0a6..96565ac12f2 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -514,6 +514,16 @@ bool Unit::IsWithinMeleeRange(Unit const* obj) const
return distsq <= maxdist * maxdist;
}
+bool Unit::IsWithinBoundaryRadius(const Unit* obj) const
+{
+ if (!obj || !IsInMap(obj) || !IsInPhase(obj))
+ return false;
+
+ float objBoundaryRadius = std::max(obj->GetBoundaryRadius(), MIN_MELEE_REACH);
+
+ return IsInDist(obj, objBoundaryRadius);
+}
+
void Unit::GetRandomContactPoint(const Unit* obj, float &x, float &y, float &z, float distance2dMin, float distance2dMax) const
{
float combat_reach = GetCombatReach();
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index e219d04908f..054720c2218 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -1374,8 +1374,10 @@ class TC_GAME_API Unit : public WorldObject
bool CanDualWield() const { return m_canDualWield; }
virtual void SetCanDualWield(bool value) { m_canDualWield = value; }
float GetCombatReach() const { return m_floatValues[UNIT_FIELD_COMBATREACH]; }
+ float GetBoundaryRadius() const { return m_floatValues[UNIT_FIELD_BOUNDINGRADIUS]; }
bool IsWithinCombatRange(const Unit* obj, float dist2compare) const;
bool IsWithinMeleeRange(Unit const* obj) const;
+ bool IsWithinBoundaryRadius(const Unit* obj) const;
void GetRandomContactPoint(const Unit* target, float &x, float &y, float &z, float distance2dMin, float distance2dMax) const;
uint32 m_extraAttacks;
bool m_canDualWield;
diff --git a/src/server/game/Groups/GroupMgr.cpp b/src/server/game/Groups/GroupMgr.cpp
index ad112c59a61..fc191e79532 100644
--- a/src/server/game/Groups/GroupMgr.cpp
+++ b/src/server/game/Groups/GroupMgr.cpp
@@ -200,8 +200,8 @@ void GroupMgr::LoadGroups()
TC_LOG_INFO("server.loading", "Loading Group instance saves...");
{
uint32 oldMSTime = getMSTime();
- // 0 1 2 3 4 5 6
- QueryResult result = CharacterDatabase.Query("SELECT gi.guid, i.map, gi.instance, gi.permanent, i.difficulty, i.resettime, COUNT(g.guid) "
+ // 0 1 2 3 4 5 6 7
+ QueryResult result = CharacterDatabase.Query("SELECT gi.guid, i.map, gi.instance, gi.permanent, i.difficulty, i.resettime, i.entranceId, COUNT(g.guid) "
"FROM group_instance gi INNER JOIN instance i ON gi.instance = i.id "
"LEFT JOIN character_instance ci LEFT JOIN groups g ON g.leaderGuid = ci.guid ON ci.instance = gi.instance AND ci.permanent = 1 GROUP BY gi.instance ORDER BY gi.guid");
if (!result)
@@ -229,7 +229,7 @@ void GroupMgr::LoadGroups()
if (!difficultyEntry || difficultyEntry->InstanceType != mapEntry->InstanceType)
continue;
- InstanceSave* save = sInstanceSaveMgr->AddInstanceSave(mapEntry->ID, fields[2].GetUInt32(), Difficulty(diff), time_t(fields[5].GetUInt32()), fields[6].GetUInt64() != 0, true);
+ InstanceSave* save = sInstanceSaveMgr->AddInstanceSave(mapEntry->ID, fields[2].GetUInt32(), Difficulty(diff), time_t(fields[5].GetUInt32()), fields[6].GetUInt32(), fields[7].GetUInt64() != 0, true);
group->BindToInstance(save, fields[3].GetBool(), true);
++count;
}
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index afcced346df..ab8bcc8e03a 100644
--- a/src/server/game/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -618,7 +618,27 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPackets::Misc::AreaTrigger& pack
}
if (!teleported)
- player->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, at->target_Orientation, TELE_TO_NOT_LEAVE_TRANSPORT);
+ {
+ WorldSafeLocsEntry const* entranceLocation = nullptr;
+ InstanceSave* instanceSave = player->GetInstanceSave(at->target_mapId);
+ if (instanceSave)
+ {
+ // Check if we can contact the instancescript of the instance for an updated entrance location
+ if (Map* map = sMapMgr->FindMap(at->target_mapId, player->GetInstanceSave(at->target_mapId)->GetInstanceId()))
+ if (InstanceMap* instanceMap = map->ToInstanceMap())
+ if (InstanceScript* instanceScript = instanceMap->GetInstanceScript())
+ entranceLocation = sWorldSafeLocsStore.LookupEntry(instanceScript->GetEntranceLocation());
+
+ // Finally check with the instancesave for an entrance location if we did not get a valid one from the instancescript
+ if (!entranceLocation)
+ entranceLocation = sWorldSafeLocsStore.LookupEntry(instanceSave->GetEntranceLocation());
+ }
+
+ if (entranceLocation)
+ player->TeleportTo(entranceLocation->MapID, entranceLocation->Loc.X, entranceLocation->Loc.Y, entranceLocation->Loc.Z, entranceLocation->Facing * M_PI / 180, TELE_TO_NOT_LEAVE_TRANSPORT);
+ else
+ player->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, at->target_Orientation, TELE_TO_NOT_LEAVE_TRANSPORT);
+ }
}
void WorldSession::HandleUpdateAccountData(WorldPackets::ClientConfig::UserClientUpdateAccountData& packet)
diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp
index 6ef966a2340..8430a30e86e 100644
--- a/src/server/game/Handlers/QuestHandler.cpp
+++ b/src/server/game/Handlers/QuestHandler.cpp
@@ -435,6 +435,7 @@ void WorldSession::HandleQuestLogRemoveQuest(WorldPackets::Quest::QuestLogRemove
}
_player->TakeQuestSourceItem(questId, true); // remove quest src item from player
+ _player->AbandonQuest(questId); // remove all quest items player received before abandoning quest. Note, this does not remove normal drop items that happen to be quest requirements.
_player->RemoveActiveQuest(questId);
_player->RemoveCriteriaTimer(CRITERIA_TIMED_TYPE_QUEST, questId);
diff --git a/src/server/game/Instances/InstanceSaveMgr.cpp b/src/server/game/Instances/InstanceSaveMgr.cpp
index 3a5c65a0932..4fa2682c7b6 100644
--- a/src/server/game/Instances/InstanceSaveMgr.cpp
+++ b/src/server/game/Instances/InstanceSaveMgr.cpp
@@ -71,7 +71,7 @@ void InstanceSaveManager::Unload()
- adding instance into manager
- called from InstanceMap::Add, _LoadBoundInstances, LoadGroups
*/
-InstanceSave* InstanceSaveManager::AddInstanceSave(uint32 mapId, uint32 instanceId, Difficulty difficulty, time_t resetTime, bool canReset, bool load)
+InstanceSave* InstanceSaveManager::AddInstanceSave(uint32 mapId, uint32 instanceId, Difficulty difficulty, time_t resetTime, uint32 entranceId, bool canReset, bool load)
{
if (InstanceSave* old_save = GetInstanceSave(instanceId))
return old_save;
@@ -96,6 +96,12 @@ InstanceSave* InstanceSaveManager::AddInstanceSave(uint32 mapId, uint32 instance
return NULL;
}
+ if (entranceId && !sWorldSafeLocsStore.LookupEntry(entranceId))
+ {
+ TC_LOG_WARN("misc", "InstanceSaveManager::AddInstanceSave: invalid entranceId = %d defined for instance save with mapid = %d, instanceid = %d!", entranceId, mapId, instanceId);
+ entranceId = 0;
+ }
+
if (!resetTime)
{
// initialize reset time
@@ -112,7 +118,7 @@ InstanceSave* InstanceSaveManager::AddInstanceSave(uint32 mapId, uint32 instance
TC_LOG_DEBUG("maps", "InstanceSaveManager::AddInstanceSave: mapid = %d, instanceid = %d", mapId, instanceId);
- InstanceSave* save = new InstanceSave(mapId, instanceId, difficulty, resetTime, canReset);
+ InstanceSave* save = new InstanceSave(mapId, instanceId, difficulty, entranceId, resetTime, canReset);
if (!load)
save->SaveToDB();
@@ -173,9 +179,9 @@ void InstanceSaveManager::UnloadInstanceSave(uint32 InstanceId)
save->UnloadIfEmpty();
}
-InstanceSave::InstanceSave(uint16 MapId, uint32 InstanceId, Difficulty difficulty, time_t resetTime, bool canReset)
+InstanceSave::InstanceSave(uint16 MapId, uint32 InstanceId, Difficulty difficulty, uint32 entranceId, time_t resetTime, bool canReset)
: m_resetTime(resetTime), m_instanceid(InstanceId), m_mapid(MapId),
- m_difficulty(difficulty), m_canReset(canReset), m_toDelete(false) { }
+ m_difficulty(difficulty), m_entranceId(entranceId), m_canReset(canReset), m_toDelete(false) { }
InstanceSave::~InstanceSave()
{
@@ -200,6 +206,7 @@ void InstanceSave::SaveToDB()
{
data = instanceScript->GetSaveData();
completedEncounters = instanceScript->GetCompletedEncounterMask();
+ m_entranceId = instanceScript->GetEntranceLocation();
}
}
@@ -210,6 +217,7 @@ void InstanceSave::SaveToDB()
stmt->setUInt8(3, uint8(GetDifficultyID()));
stmt->setUInt32(4, completedEncounters);
stmt->setString(5, data);
+ stmt->setUInt32(6, m_entranceId);
CharacterDatabase.Execute(stmt);
}
diff --git a/src/server/game/Instances/InstanceSaveMgr.h b/src/server/game/Instances/InstanceSaveMgr.h
index ff99736f2b7..6e0d34a88e6 100644
--- a/src/server/game/Instances/InstanceSaveMgr.h
+++ b/src/server/game/Instances/InstanceSaveMgr.h
@@ -49,7 +49,7 @@ class TC_GAME_API InstanceSave
- any new instance is being generated
- the first time a player bound to InstanceId logs in
- when a group bound to the instance is loaded */
- InstanceSave(uint16 MapId, uint32 InstanceId, Difficulty difficulty, time_t resetTime, bool canReset);
+ InstanceSave(uint16 MapId, uint32 InstanceId, Difficulty difficulty, uint32 entranceId, time_t resetTime, bool canReset);
/* Unloaded when m_playerList and m_groupList become empty
or when the instance is reset */
@@ -75,6 +75,9 @@ class TC_GAME_API InstanceSave
void SetResetTime(time_t resetTime) { m_resetTime = resetTime; }
time_t GetResetTimeForDB();
+ uint32 GetEntranceLocation() const { return m_entranceId; }
+ void SetEntranceLocation(uint32 entranceId) { m_entranceId = entranceId; }
+
InstanceTemplate const* GetTemplate();
MapEntry const* GetMapEntry();
@@ -139,6 +142,7 @@ class TC_GAME_API InstanceSave
uint32 m_instanceid;
uint32 m_mapid;
Difficulty m_difficulty;
+ uint32 m_entranceId;
bool m_canReset;
bool m_toDelete;
@@ -211,7 +215,7 @@ class TC_GAME_API InstanceSaveManager
void Update();
- InstanceSave* AddInstanceSave(uint32 mapId, uint32 instanceId, Difficulty difficulty, time_t resetTime,
+ InstanceSave* AddInstanceSave(uint32 mapId, uint32 instanceId, Difficulty difficulty, time_t resetTime, uint32 entranceId,
bool canReset, bool load = false);
void RemoveInstanceSave(uint32 InstanceId);
void UnloadInstanceSave(uint32 InstanceId);
diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp
index d8c99aa366d..9854e46f1cb 100644
--- a/src/server/game/Instances/InstanceScript.cpp
+++ b/src/server/game/Instances/InstanceScript.cpp
@@ -40,7 +40,7 @@ BossBoundaryData::~BossBoundaryData()
}
InstanceScript::InstanceScript(Map* map) : instance(map), completedEncounters(0),
-_combatResurrectionTimer(0), _combatResurrectionCharges(0), _combatResurrectionTimerStarted(false)
+_entranceId(0), _temporaryEntranceId(0), _combatResurrectionTimer(0), _combatResurrectionCharges(0), _combatResurrectionTimerStarted(false)
{
#ifdef TRINITY_API_USE_DYNAMIC_LINKING
uint32 scriptId = sObjectMgr->GetInstanceTemplate(map->GetId())->ScriptId;
@@ -61,7 +61,8 @@ void InstanceScript::SaveToDB()
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_INSTANCE_DATA);
stmt->setUInt32(0, GetCompletedEncounterMask());
stmt->setString(1, data);
- stmt->setUInt32(2, instance->GetInstanceId());
+ stmt->setUInt32(2, _entranceId);
+ stmt->setUInt32(3, instance->GetInstanceId());
CharacterDatabase.Execute(stmt);
}
@@ -606,6 +607,13 @@ bool InstanceScript::CheckAchievementCriteriaMeet(uint32 criteria_id, Player con
return false;
}
+void InstanceScript::SetEntranceLocation(uint32 worldSafeLocationId)
+{
+ _entranceId = worldSafeLocationId;
+ if (_temporaryEntranceId)
+ _temporaryEntranceId = 0;
+}
+
void InstanceScript::SendEncounterUnit(uint32 type, Unit* unit /*= NULL*/, uint8 priority)
{
switch (type)
diff --git a/src/server/game/Instances/InstanceScript.h b/src/server/game/Instances/InstanceScript.h
index d858bb6b9c2..eb0579ef63e 100644
--- a/src/server/game/Instances/InstanceScript.h
+++ b/src/server/game/Instances/InstanceScript.h
@@ -246,6 +246,15 @@ class TC_GAME_API InstanceScript : public ZoneScript
// Returns completed encounters mask for packets
uint32 GetCompletedEncounterMask() const { return completedEncounters; }
+ // Sets the entrance location (WorldSafeLoc) id
+ void SetEntranceLocation(uint32 worldSafeLocationId);
+
+ // Sets a temporary entrance that does not get saved to db
+ void SetTemporaryEntranceLocation(uint32 worldSafeLocationId) { _temporaryEntranceId = worldSafeLocationId; }
+
+ // Get's the current entrance id
+ uint32 GetEntranceLocation() const { return _temporaryEntranceId ? _temporaryEntranceId : _entranceId; }
+
void SendEncounterUnit(uint32 type, Unit* unit = NULL, uint8 priority = 0);
void SendEncounterStart(uint32 inCombatResCount = 0, uint32 maxInCombatResCount = 0, uint32 inCombatResChargeRecovery = 0, uint32 nextCombatResChargeTime = 0);
void SendEncounterEnd();
@@ -309,6 +318,8 @@ class TC_GAME_API InstanceScript : public ZoneScript
ObjectInfoMap _gameObjectInfo;
ObjectGuidMap _objectGuids;
uint32 completedEncounters; // completed encounter mask, bit indexes are DungeonEncounter.dbc boss numbers, used for packets
+ uint32 _entranceId;
+ uint32 _temporaryEntranceId;
uint32 _combatResurrectionTimer;
uint8 _combatResurrectionCharges; // the counter for available battle resurrections
bool _combatResurrectionTimerStarted;
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index 0b0868eddf4..0a7138616e0 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -3135,7 +3135,7 @@ bool InstanceMap::AddPlayerToMap(Player* player, bool initPlayer /*= true*/)
if (!mapSave)
{
TC_LOG_DEBUG("maps", "InstanceMap::Add: creating instance save for map %d spawnmode %d with instance id %d", GetId(), GetSpawnMode(), GetInstanceId());
- mapSave = sInstanceSaveMgr->AddInstanceSave(GetId(), GetInstanceId(), Difficulty(GetSpawnMode()), 0, true);
+ mapSave = sInstanceSaveMgr->AddInstanceSave(GetId(), GetInstanceId(), Difficulty(GetSpawnMode()), 0, 0, true);
}
ASSERT(mapSave);
diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp
index 14a4ea3590e..de13f63e099 100644
--- a/src/server/game/Scripting/ScriptMgr.cpp
+++ b/src/server/game/Scripting/ScriptMgr.cpp
@@ -986,7 +986,7 @@ void ScriptMgr::Initialize()
FillSpellSummary();
// Load core scripts
- SetScriptContext("___static___");
+ SetScriptContext(GetNameOfStaticContext());
// SmartAI
AddSC_SmartScripts();
@@ -1041,6 +1041,12 @@ void ScriptMgr::SwapScriptContext(bool initialize)
_currentContext.clear();
}
+std::string const& ScriptMgr::GetNameOfStaticContext()
+{
+ static std::string const name = "___static___";
+ return name;
+}
+
void ScriptMgr::ReleaseScriptContext(std::string const& context)
{
sScriptRegistryCompositum->ReleaseContext(context);
diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h
index 9acfc28db9c..b3436c4773e 100644
--- a/src/server/game/Scripting/ScriptMgr.h
+++ b/src/server/game/Scripting/ScriptMgr.h
@@ -876,6 +876,9 @@ class TC_GAME_API ScriptMgr
/// calls for better performance (bulk changes).
void SwapScriptContext(bool initialize = false);
+ /// Returns the context name of the static context provided by the worldserver
+ static std::string const& GetNameOfStaticContext();
+
/// Acquires a strong module reference to the module containing the given script name,
/// which prevents the shared library which contains the script from unloading.
/// The shared library is lazy unloaded as soon as all references to it are released.
diff --git a/src/server/game/Scripting/ScriptReloadMgr.cpp b/src/server/game/Scripting/ScriptReloadMgr.cpp
index d13fa9c30f0..b0c9b6821d2 100644
--- a/src/server/game/Scripting/ScriptReloadMgr.cpp
+++ b/src/server/game/Scripting/ScriptReloadMgr.cpp
@@ -194,6 +194,8 @@ public:
static Optional<std::shared_ptr<ScriptModule>>
CreateFromPath(fs::path const& path, Optional<fs::path> cache_path);
+ static void ScheduleDelayedDelete(ScriptModule* module);
+
char const* GetScriptModuleRevisionHash() const override
{
return _getScriptModuleRevisionHash();
@@ -287,8 +289,13 @@ Optional<std::shared_ptr<ScriptModule>>
GetFunctionFromSharedLibrary(handle, "AddScripts", addScripts) &&
GetFunctionFromSharedLibrary(handle, "GetScriptModule", getScriptModule) &&
GetFunctionFromSharedLibrary(handle, "GetBuildDirective", getBuildDirective))
- return std::make_shared<ScriptModule>(std::move(holder), getScriptModuleRevisionHash,
+ {
+ auto module = new ScriptModule(std::move(holder), getScriptModuleRevisionHash,
addScripts, getScriptModule, getBuildDirective, path);
+
+ // Unload the module at the next update tick as soon as all references are removed
+ return std::shared_ptr<ScriptModule>(module, ScheduleDelayedDelete);
+ }
else
{
TC_LOG_ERROR("scripts.hotswap", "Could not extract all required functions from the shared library \"%s\"!",
@@ -937,13 +944,6 @@ private:
}
}
- sScriptMgr->SetScriptContext(module_name);
- (*module)->AddScripts();
- TC_LOG_TRACE("scripts.hotswap", ">> Registered all scripts of module %s.", module_name.c_str());
-
- if (swap_context)
- sScriptMgr->SwapScriptContext();
-
// Create the source listener
auto listener = Trinity::make_unique<SourceUpdateListener>(
sScriptReloadMgr->GetSourceDirectory() / module_name,
@@ -952,8 +952,16 @@ private:
// Store the module
_known_modules_build_directives.insert(std::make_pair(module_name, (*module)->GetBuildDirective()));
_running_script_modules.insert(std::make_pair(module_name,
- std::make_pair(std::move(*module), std::move(listener))));
+ std::make_pair(*module, std::move(listener))));
_running_script_module_names.insert(std::make_pair(path, module_name));
+
+ // Process the script loading after the module was registered correctly (#17557).
+ sScriptMgr->SetScriptContext(module_name);
+ (*module)->AddScripts();
+ TC_LOG_TRACE("scripts.hotswap", ">> Registered all scripts of module %s.", module_name.c_str());
+
+ if (swap_context)
+ sScriptMgr->SwapScriptContext();
}
void ProcessReloadScriptModule(fs::path const& path)
@@ -1435,6 +1443,26 @@ private:
fs::path temporary_cache_path_;
};
+class ScriptModuleDeleteMessage
+{
+public:
+ explicit ScriptModuleDeleteMessage(ScriptModule* module)
+ : module_(module) { }
+
+ void operator() (HotSwapScriptReloadMgr*)
+ {
+ module_.reset();
+ }
+
+private:
+ std::unique_ptr<ScriptModule> module_;
+};
+
+void ScriptModule::ScheduleDelayedDelete(ScriptModule* module)
+{
+ sScriptReloadMgr->QueueMessage(ScriptModuleDeleteMessage(module));
+}
+
/// Maps efsw actions to strings
static char const* ActionToString(efsw::Action action)
{
@@ -1592,11 +1620,15 @@ void SourceUpdateListener::handleFileAction(efsw::WatchID watchid, std::string c
std::shared_ptr<ModuleReference>
ScriptReloadMgr::AcquireModuleReferenceOfContext(std::string const& context)
{
- auto const itr = sScriptReloadMgr->_running_script_modules.find(context);
- if (itr != sScriptReloadMgr->_running_script_modules.end())
- return itr->second.first;
- else
+ // Return empty references for the static context exported by the worldserver
+ if (context == ScriptMgr::GetNameOfStaticContext())
return { };
+
+ auto const itr = sScriptReloadMgr->_running_script_modules.find(context);
+ ASSERT(itr != sScriptReloadMgr->_running_script_modules.end()
+ && "Requested a reference to a non existent script context!");
+
+ return itr->second.first;
}
// Returns the full hot swap implemented ScriptReloadMgr
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index da8b43f37dc..fdd72e4ab6c 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -464,7 +464,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]=
&AuraEffect::HandleModPowerDisplay, //402 SPELL_AURA_MOD_POWER_DISPLAY
&AuraEffect::HandleNoImmediateEffect, //403 SPELL_AURA_OVERRIDE_SPELL_VISUAL implemented in Unit::GetCastSpellXSpellVisualId
&AuraEffect::HandleOverrideAttackPowerBySpellPower, //404 SPELL_AURA_OVERRIDE_ATTACK_POWER_BY_SP_PCT
- &AuraEffect::HandleNULL, //405 SPELL_AURA_MOD_RATING_PCT
+ &AuraEffect::HandleModRatingPct, //405 SPELL_AURA_MOD_RATING_PCT
&AuraEffect::HandleNULL, //406
&AuraEffect::HandleNULL, //407 SPELL_AURA_MOD_FEAR_2
&AuraEffect::HandleNULL, //408
@@ -4471,7 +4471,7 @@ void AuraEffect::HandleModRating(AuraApplication const* aurApp, uint8 mode, bool
target->ToPlayer()->ApplyRatingMod(CombatRating(rating), GetAmount(), apply);
}
-void AuraEffect::HandleModRatingFromStat(AuraApplication const* aurApp, uint8 mode, bool apply) const
+void AuraEffect::HandleModRatingFromStat(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const
{
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
return;
@@ -4484,7 +4484,23 @@ void AuraEffect::HandleModRatingFromStat(AuraApplication const* aurApp, uint8 mo
// Just recalculate ratings
for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
if (GetMiscValue() & (1 << rating))
- target->ToPlayer()->ApplyRatingMod(CombatRating(rating), 0, apply);
+ target->ToPlayer()->UpdateRating(CombatRating(rating));
+}
+
+void AuraEffect::HandleModRatingPct(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const
+{
+ if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
+ return;
+
+ Unit* target = aurApp->GetTarget();
+
+ if (target->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ // Just recalculate ratings
+ for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
+ if (GetMiscValue() & (1 << rating))
+ target->ToPlayer()->UpdateRating(CombatRating(rating));
}
/********************************/
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h
index b599fe1df28..5ecf741d967 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.h
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.h
@@ -270,6 +270,7 @@ class TC_GAME_API AuraEffect
// combat rating
void HandleModRating(AuraApplication const* aurApp, uint8 mode, bool apply) const;
void HandleModRatingFromStat(AuraApplication const* aurApp, uint8 mode, bool apply) const;
+ void HandleModRatingPct(AuraApplication const* aurApp, uint8 mode, bool apply) const;
// attack power
void HandleAuraModAttackPower(AuraApplication const* aurApp, uint8 mode, bool apply) const;
void HandleAuraModRangedAttackPower(AuraApplication const* aurApp, uint8 mode, bool apply) const;
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index e613952e015..6f5e3d4a1af 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -5905,7 +5905,8 @@ SpellCastResult Spell::CheckRange(bool strict)
return !(_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) ? SPELL_FAILED_OUT_OF_RANGE : SPELL_FAILED_DONT_REPORT;
if (m_caster->GetTypeId() == TYPEID_PLAYER &&
- (m_spellInfo->FacingCasterFlags & SPELL_FACING_FLAG_INFRONT) && !m_caster->HasInArc(static_cast<float>(M_PI), target))
+ (((m_spellInfo->FacingCasterFlags & SPELL_FACING_FLAG_INFRONT) && !m_caster->HasInArc(static_cast<float>(M_PI), target))
+ && !m_caster->IsWithinBoundaryRadius(target)))
return !(_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) ? SPELL_FAILED_UNIT_NOT_INFRONT : SPELL_FAILED_DONT_REPORT;
}
@@ -7563,8 +7564,9 @@ bool WorldObjectSpellConeTargetCheck::operator()(WorldObject* target)
}
else
{
- if (!_caster->isInFront(target, _coneAngle))
- return false;
+ if (!_caster->IsWithinBoundaryRadius(target->ToUnit()))
+ if (!_caster->isInFront(target, _coneAngle))
+ return false;
}
return WorldObjectSpellAreaTargetCheck::operator ()(target);
}
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 0ab8b919664..13d03c4ee57 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -3164,6 +3164,10 @@ void SpellMgr::LoadSpellInfoCorrections()
//! HACK: This spell break quest complete for alliance and on retail not used °_O
const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->Effect = 0;
break;
+ case 85123: // Siege Cannon (Tol Barad)
+ const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS);
+ const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetA = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ENTRY);
+ break;
// VIOLET HOLD SPELLS
//
case 54258: // Water Globule (Ichoron)
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index bf536765901..e2c80f16ca8 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1414,6 +1414,16 @@ void World::LoadConfigSettings(bool reload)
m_int_configs[CONFIG_WINTERGRASP_NOBATTLETIME] = sConfigMgr->GetIntDefault("Wintergrasp.NoBattleTimer", 150);
m_int_configs[CONFIG_WINTERGRASP_RESTART_AFTER_CRASH] = sConfigMgr->GetIntDefault("Wintergrasp.CrashRestartTimer", 10);
+ // Tol Barad battlefield
+ m_bool_configs[CONFIG_TOLBARAD_ENABLE] = sConfigMgr->GetBoolDefault("TolBarad.Enable", true);
+ m_int_configs[CONFIG_TOLBARAD_PLR_MAX] = sConfigMgr->GetIntDefault("TolBarad.PlayerMax", 100);
+ m_int_configs[CONFIG_TOLBARAD_PLR_MIN] = sConfigMgr->GetIntDefault("TolBarad.PlayerMin", 0);
+ m_int_configs[CONFIG_TOLBARAD_PLR_MIN_LVL] = sConfigMgr->GetIntDefault("TolBarad.PlayerMinLvl", 85);
+ m_int_configs[CONFIG_TOLBARAD_BATTLETIME] = sConfigMgr->GetIntDefault("TolBarad.BattleTimer", 15);
+ m_int_configs[CONFIG_TOLBARAD_BONUSTIME] = sConfigMgr->GetIntDefault("TolBarad.BonusTime", 5);
+ m_int_configs[CONFIG_TOLBARAD_NOBATTLETIME] = sConfigMgr->GetIntDefault("TolBarad.NoBattleTimer", 150);
+ m_int_configs[CONFIG_TOLBARAD_RESTART_AFTER_CRASH] = sConfigMgr->GetIntDefault("TolBarad.CrashRestartTimer", 10);
+
// Stats limits
m_bool_configs[CONFIG_STATS_LIMITS_ENABLE] = sConfigMgr->GetBoolDefault("Stats.Limits.Enable", false);
m_float_configs[CONFIG_STATS_LIMITS_DODGE] = sConfigMgr->GetFloatDefault("Stats.Limits.Dodge", 95.0f);
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index e37e0daa011..1851ffa6079 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -167,6 +167,7 @@ enum WorldBoolConfigs
CONFIG_WARDEN_ENABLED,
CONFIG_ENABLE_MMAPS,
CONFIG_WINTERGRASP_ENABLE,
+ CONFIG_TOLBARAD_ENABLE,
CONFIG_UI_QUESTLEVELS_IN_DIALOGS, // Should we add quest levels to the title in the NPC dialogs?
CONFIG_EVENT_ANNOUNCE,
CONFIG_STATS_LIMITS_ENABLE,
@@ -363,6 +364,13 @@ enum WorldIntConfigs
CONFIG_WINTERGRASP_BATTLETIME,
CONFIG_WINTERGRASP_NOBATTLETIME,
CONFIG_WINTERGRASP_RESTART_AFTER_CRASH,
+ CONFIG_TOLBARAD_PLR_MAX,
+ CONFIG_TOLBARAD_PLR_MIN,
+ CONFIG_TOLBARAD_PLR_MIN_LVL,
+ CONFIG_TOLBARAD_BATTLETIME,
+ CONFIG_TOLBARAD_BONUSTIME,
+ CONFIG_TOLBARAD_NOBATTLETIME,
+ CONFIG_TOLBARAD_RESTART_AFTER_CRASH,
CONFIG_GUILD_SAVE_INTERVAL,
CONFIG_GUILD_UNDELETABLE_LEVEL,
CONFIG_PACKET_SPOOF_POLICY,
diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp
index 6f27d733eb8..26385221d65 100644
--- a/src/server/scripts/Commands/cs_misc.cpp
+++ b/src/server/scripts/Commands/cs_misc.cpp
@@ -726,7 +726,7 @@ public:
static bool HandleCooldownCommand(ChatHandler* handler, char const* args)
{
- Player* target = handler->getSelectedPlayerOrSelf();
+ Unit* target = handler->getSelectedUnit();
if (!target)
{
handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
@@ -734,7 +734,14 @@ public:
return false;
}
- std::string nameLink = handler->GetNameLink(target);
+ Player* owner = target->GetCharmerOrOwnerPlayerOrPlayerItself();
+ if (!owner)
+ {
+ owner = handler->GetSession()->GetPlayer();
+ target = owner;
+ }
+
+ std::string nameLink = handler->GetNameLink(owner);
if (!*args)
{
@@ -752,14 +759,14 @@ public:
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellIid);
if (!spellInfo)
{
- handler->PSendSysMessage(LANG_UNKNOWN_SPELL, target == handler->GetSession()->GetPlayer() ? handler->GetTrinityString(LANG_YOU) : nameLink.c_str());
+ handler->PSendSysMessage(LANG_UNKNOWN_SPELL, owner == handler->GetSession()->GetPlayer() ? handler->GetTrinityString(LANG_YOU) : nameLink.c_str());
handler->SetSentErrorMessage(true);
return false;
}
target->GetSpellHistory()->ResetCooldown(spellIid, true);
target->GetSpellHistory()->ResetCharges(spellInfo->ChargeCategoryId);
- handler->PSendSysMessage(LANG_REMOVE_COOLDOWN, spellIid, target == handler->GetSession()->GetPlayer() ? handler->GetTrinityString(LANG_YOU) : nameLink.c_str());
+ handler->PSendSysMessage(LANG_REMOVE_COOLDOWN, spellIid, owner == handler->GetSession()->GetPlayer() ? handler->GetTrinityString(LANG_YOU) : nameLink.c_str());
}
return true;
}
diff --git a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp
index adf7219d2a3..123d4102794 100644
--- a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp
+++ b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp
@@ -193,6 +193,7 @@ void AddSC_stormwind_city();
void AddSC_stranglethorn_vale();
void AddSC_swamp_of_sorrows();
void AddSC_tirisfal_glades();
+void AddSC_tol_barad();
void AddSC_undercity();
void AddSC_western_plaguelands();
void AddSC_wetlands();
@@ -379,6 +380,7 @@ void AddEasternKingdomsScripts()
AddSC_stranglethorn_vale();
AddSC_swamp_of_sorrows();
AddSC_tirisfal_glades();
+ AddSC_tol_barad();
AddSC_undercity();
AddSC_western_plaguelands();
AddSC_wetlands();
diff --git a/src/server/scripts/EasternKingdoms/zone_tol_barad.cpp b/src/server/scripts/EasternKingdoms/zone_tol_barad.cpp
new file mode 100644
index 00000000000..54534a3d301
--- /dev/null
+++ b/src/server/scripts/EasternKingdoms/zone_tol_barad.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "BattlefieldMgr.h"
+#include "BattlefieldTB.h"
+#include "Battlefield.h"
+#include "ScriptSystem.h"
+#include "WorldSession.h"
+#include "ScriptedCreature.h"
+#include "ScriptedGossip.h"
+#include "SpellScript.h"
+#include "Player.h"
+
+enum TBSpiritGuide
+{
+ SPELL_CHANNEL_SPIRIT_HEAL = 22011,
+
+ GOSSIP_OPTION_ID_SLAGWORKS = 0,
+ GOSSIP_OPTION_ID_IRONCLAD_GARRISON = 1,
+ GOSSIP_OPTION_ID_WARDENS_VIGIL = 2,
+ GOSSIP_OPTION_ID_EAST_SPIRE = 3,
+ GOSSIP_OPTION_ID_WEST_SPIRE = 4,
+ GOSSIP_OPTION_ID_SOUTH_SPIRE = 5,
+};
+
+class npc_tb_spirit_guide : public CreatureScript
+{
+ public:
+ npc_tb_spirit_guide() : CreatureScript("npc_tb_spirit_guide") { }
+
+ struct npc_tb_spirit_guideAI : public ScriptedAI
+ {
+ npc_tb_spirit_guideAI(Creature* creature) : ScriptedAI(creature) { }
+
+ void UpdateAI(uint32 /*diff*/) override
+ {
+ if (!me->HasUnitState(UNIT_STATE_CASTING))
+ DoCast(me, SPELL_CHANNEL_SPIRIT_HEAL);
+ }
+
+ void sGossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override
+ {
+ player->PlayerTalkClass->SendCloseGossip();
+
+ uint32 areaId = 0;
+ switch (gossipListId)
+ {
+ case GOSSIP_OPTION_ID_SLAGWORKS:
+ areaId = TB_GY_SLAGWORKS;
+ break;
+ case GOSSIP_OPTION_ID_IRONCLAD_GARRISON:
+ areaId = TB_GY_IRONCLAD_GARRISON;
+ break;
+ case GOSSIP_OPTION_ID_WARDENS_VIGIL:
+ areaId = TB_GY_WARDENS_VIGIL;
+ break;
+ case GOSSIP_OPTION_ID_EAST_SPIRE:
+ areaId = TB_GY_EAST_SPIRE;
+ break;
+ case GOSSIP_OPTION_ID_WEST_SPIRE:
+ areaId = TB_GY_WEST_SPIRE;
+ break;
+ case GOSSIP_OPTION_ID_SOUTH_SPIRE:
+ areaId = TB_GY_SOUTH_SPIRE;
+ break;
+ default:
+ return;
+ }
+
+ if (WorldSafeLocsEntry const* safeLoc = sWorldSafeLocsStore.LookupEntry(areaId))
+ player->TeleportTo(safeLoc->MapID, safeLoc->Loc.X, safeLoc->Loc.Y, safeLoc->Loc.Z, 0);
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new npc_tb_spirit_guideAI(creature);
+ }
+};
+
+// 85123 - Siege Cannon - selects random target
+class spell_siege_cannon : public SpellScriptLoader
+{
+public:
+ spell_siege_cannon() : SpellScriptLoader("spell_siege_cannon") { }
+
+ class spell_siege_cannon_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_siege_cannon_SpellScript);
+
+ void SelectRandomTarget(std::list<WorldObject*>& targets)
+ {
+ if (targets.empty())
+ return;
+
+ WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets);
+ targets.clear();
+ targets.push_back(target);
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_siege_cannon_SpellScript::SelectRandomTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_siege_cannon_SpellScript();
+ }
+};
+
+void AddSC_tol_barad()
+{
+ new npc_tb_spirit_guide();
+ new spell_siege_cannon();
+}
diff --git a/src/server/scripts/Kalimdor/BlackfathomDeeps/blackfathom_deeps.cpp b/src/server/scripts/Kalimdor/BlackfathomDeeps/blackfathom_deeps.cpp
index 2b670b467e2..712b3597f1b 100644
--- a/src/server/scripts/Kalimdor/BlackfathomDeeps/blackfathom_deeps.cpp
+++ b/src/server/scripts/Kalimdor/BlackfathomDeeps/blackfathom_deeps.cpp
@@ -238,10 +238,40 @@ public:
}
};
+// 151159 - Darkness Calls
+class spell_subjugator_korul_darkness_calls : public SpellScriptLoader
+{
+public:
+ spell_subjugator_korul_darkness_calls() : SpellScriptLoader("spell_subjugator_korul_darkness_calls") { }
+
+ class spell_subjugator_korul_darkness_calls_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_subjugator_korul_darkness_calls_SpellScript);
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* hitUnit = GetHitUnit())
+ GetCaster()->CastSpell(hitUnit, uint32(GetEffectValue()), true);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_subjugator_korul_darkness_calls_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY);
+ OnEffectHitTarget += SpellEffectFn(spell_subjugator_korul_darkness_calls_SpellScript::HandleScript, EFFECT_1, SPELL_EFFECT_DUMMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_subjugator_korul_darkness_calls_SpellScript();
+ }
+};
+
void AddSC_blackfathom_deeps()
{
new go_blackfathom_altar();
new go_blackfathom_fire();
new npc_blackfathom_deeps_event();
new npc_morridune();
+ new spell_subjugator_korul_darkness_calls();
}
diff --git a/src/server/scripts/Spells/spell_holiday.cpp b/src/server/scripts/Spells/spell_holiday.cpp
index 352421a7188..a3ef98d00a1 100644
--- a/src/server/scripts/Spells/spell_holiday.cpp
+++ b/src/server/scripts/Spells/spell_holiday.cpp
@@ -113,6 +113,105 @@ class spell_love_is_in_the_air_romantic_picnic : public SpellScriptLoader
}
};
+enum HallowEndCandysSpells
+{
+ SPELL_HALLOWS_END_CANDY_ORANGE_GIANT = 24924, // Effect 1: Apply Aura: Mod Size, Value: 30%
+ SPELL_HALLOWS_END_CANDY_SKELETON = 24925, // Effect 1: Apply Aura: Change Model (Skeleton). Effect 2: Apply Aura: Underwater Breathing
+ SPELL_HALLOWS_END_CANDY_PIRATE = 24926, // Effect 1: Apply Aura: Increase Swim Speed, Value: 50%
+ SPELL_HALLOWS_END_CANDY_GHOST = 24927, // Effect 1: Apply Aura: Levitate / Hover. Effect 2: Apply Aura: Slow Fall, Effect 3: Apply Aura: Water Walking
+ SPELL_HALLOWS_END_CANDY_FEMALE_DEFIAS_PIRATE = 44742, // Effect 1: Apply Aura: Change Model (Defias Pirate, Female). Effect 2: Increase Swim Speed, Value: 50%
+ SPELL_HALLOWS_END_CANDY_MALE_DEFIAS_PIRATE = 44743 // Effect 1: Apply Aura: Change Model (Defias Pirate, Male). Effect 2: Increase Swim Speed, Value: 50%
+};
+
+// 24930 - Hallow's End Candy
+class spell_hallow_end_candy : public SpellScriptLoader
+{
+ public:
+ spell_hallow_end_candy() : SpellScriptLoader("spell_hallow_end_candy") { }
+
+ class spell_hallow_end_candy_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_hallow_end_candy_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ for (uint32 spellId : spells)
+ if (!sSpellMgr->GetSpellInfo(spellId))
+ return false;
+ return true;
+ }
+
+ void HandleDummy(SpellEffIndex /*effIndex*/)
+ {
+ GetCaster()->CastSpell(GetCaster(), spells[urand(0, 3)], true);
+ }
+
+ void Register() override
+ {
+ OnEffectHit += SpellEffectFn(spell_hallow_end_candy_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+
+ private:
+ static uint32 const spells[4];
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_hallow_end_candy_SpellScript();
+ }
+};
+
+uint32 const spell_hallow_end_candy::spell_hallow_end_candy_SpellScript::spells[4] =
+{
+ SPELL_HALLOWS_END_CANDY_ORANGE_GIANT,
+ SPELL_HALLOWS_END_CANDY_SKELETON,
+ SPELL_HALLOWS_END_CANDY_PIRATE,
+ SPELL_HALLOWS_END_CANDY_GHOST
+};
+
+// 24926 - Hallow's End Candy
+class spell_hallow_end_candy_pirate : public SpellScriptLoader
+{
+ public:
+ spell_hallow_end_candy_pirate() : SpellScriptLoader("spell_hallow_end_candy_pirate") { }
+
+ class spell_hallow_end_candy_pirate_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_hallow_end_candy_pirate_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_HALLOWS_END_CANDY_FEMALE_DEFIAS_PIRATE)
+ || !sSpellMgr->GetSpellInfo(SPELL_HALLOWS_END_CANDY_MALE_DEFIAS_PIRATE))
+ return false;
+ return true;
+ }
+
+ void HandleApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ uint32 spell = GetTarget()->getGender() == GENDER_FEMALE ? SPELL_HALLOWS_END_CANDY_FEMALE_DEFIAS_PIRATE : SPELL_HALLOWS_END_CANDY_MALE_DEFIAS_PIRATE;
+ GetTarget()->CastSpell(GetTarget(), spell, true);
+ }
+
+ void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ uint32 spell = GetTarget()->getGender() == GENDER_FEMALE ? SPELL_HALLOWS_END_CANDY_FEMALE_DEFIAS_PIRATE : SPELL_HALLOWS_END_CANDY_MALE_DEFIAS_PIRATE;
+ GetTarget()->RemoveAurasDueToSpell(spell);
+ }
+
+ void Register() override
+ {
+ AfterEffectApply += AuraEffectApplyFn(spell_hallow_end_candy_pirate_AuraScript::HandleApply, EFFECT_0, SPELL_AURA_MOD_INCREASE_SWIM_SPEED, AURA_EFFECT_HANDLE_REAL);
+ AfterEffectRemove += AuraEffectRemoveFn(spell_hallow_end_candy_pirate_AuraScript::HandleRemove, EFFECT_0, SPELL_AURA_MOD_INCREASE_SWIM_SPEED, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_hallow_end_candy_pirate_AuraScript();
+ }
+};
+
// 24750 Trick
enum TrickSpells
{
@@ -1189,6 +1288,8 @@ void AddSC_holiday_spell_scripts()
// Love is in the Air
new spell_love_is_in_the_air_romantic_picnic();
// Hallow's End
+ new spell_hallow_end_candy();
+ new spell_hallow_end_candy_pirate();
new spell_hallow_end_trick();
new spell_hallow_end_trick_or_treat();
new spell_hallow_end_tricky_treat();
diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp
index 2d14e3301a3..68c48853bad 100644
--- a/src/server/worldserver/Main.cpp
+++ b/src/server/worldserver/Main.cpp
@@ -39,6 +39,7 @@
#include "BattlegroundMgr.h"
#include "TCSoap.h"
#include "CliRunnable.h"
+#include "Banner.h"
#include "GitRevision.h"
#include "WorldSocket.h"
#include "WorldSocketMgr.h"
@@ -132,20 +133,18 @@ extern int main(int argc, char** argv)
// If logs are supposed to be handled async then we need to pass the io_service into the Log singleton
sLog->Initialize(sConfigMgr->GetBoolDefault("Log.Async.Enable", false) ? &_ioService : nullptr);
- TC_LOG_INFO("server.worldserver", "%s (worldserver-daemon)", GitRevision::GetFullVersion());
- TC_LOG_INFO("server.worldserver", "<Ctrl-C> to stop.\n");
- TC_LOG_INFO("server.worldserver", " ______ __");
- TC_LOG_INFO("server.worldserver", "/\\__ _\\ __ __/\\ \\__");
- TC_LOG_INFO("server.worldserver", "\\/_/\\ \\/ _ __ /\\_\\ ___ /\\_\\ \\, _\\ __ __");
- TC_LOG_INFO("server.worldserver", " \\ \\ \\/\\`'__\\/\\ \\ /' _ `\\/\\ \\ \\ \\/ /\\ \\/\\ \\");
- TC_LOG_INFO("server.worldserver", " \\ \\ \\ \\ \\/ \\ \\ \\/\\ \\/\\ \\ \\ \\ \\ \\_\\ \\ \\_\\ \\");
- TC_LOG_INFO("server.worldserver", " \\ \\_\\ \\_\\ \\ \\_\\ \\_\\ \\_\\ \\_\\ \\__\\\\/`____ \\");
- TC_LOG_INFO("server.worldserver", " \\/_/\\/_/ \\/_/\\/_/\\/_/\\/_/\\/__/ `/___/> \\");
- TC_LOG_INFO("server.worldserver", " C O R E /\\___/");
- TC_LOG_INFO("server.worldserver", "http://TrinityCore.org \\/__/\n");
- TC_LOG_INFO("server.worldserver", "Using configuration file %s.", sConfigMgr->GetFilename().c_str());
- TC_LOG_INFO("server.worldserver", "Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION));
- TC_LOG_INFO("server.worldserver", "Using Boost version: %i.%i.%i", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100);
+ Trinity::Banner::Show("worldserver-daemon",
+ [](char const* text)
+ {
+ TC_LOG_INFO("server.worldserver", "%s", text);
+ },
+ []()
+ {
+ TC_LOG_INFO("server.worldserver", "Using configuration file %s.", sConfigMgr->GetFilename().c_str());
+ TC_LOG_INFO("server.worldserver", "Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION));
+ TC_LOG_INFO("server.worldserver", "Using Boost version: %i.%i.%i", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100);
+ }
+ );
OpenSSLCrypto::threadsSetup();
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index 5bf03012ec1..49ddb92df24 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -2532,6 +2532,64 @@ Wintergrasp.NoBattleTimer = 150
Wintergrasp.CrashRestartTimer = 10
#
+# TolBarad.Enable
+# Description: Enable the Tol Barad battlefield.
+# Default: 0 - (Disabled)
+# 1 - (Enabled, Experimental as in incomplete, bugged and with crashes)
+
+TolBarad.Enable = 0
+
+#
+# TolBarad.PlayerMax
+# Description: Maximum number of players allowed in Tol Barad.
+# Default: 100
+
+TolBarad.PlayerMax = 100
+
+#
+# TolBarad.PlayerMin
+# Description: Minimum number of players required for Tol Barad.
+# Default: 0
+
+TolBarad.PlayerMin = 0
+
+#
+# TolBarad.PlayerMinLvl
+# Description: Required character level for the Tol Barad battle.
+# Default: 85
+
+TolBarad.PlayerMinLvl = 85
+
+#
+# TolBarad.BattleTimer
+# Description: Time (in minutes) for the Tol Barad battle to last.
+# Default: 15
+
+TolBarad.BattleTimer = 15
+
+#
+# TolBarad.BonusTime
+# Description: Bonus time (in minutes) for each tower destroyed in Tol Barad battle.
+# Default: 5
+
+TolBarad.BonusTime = 5
+
+#
+# TolBarad.NoBattleTimer
+# Description: Time (in minutes) between TolBarad battles.
+# Default: 150
+
+TolBarad.NoBattleTimer = 150
+
+#
+# TolBarad.CrashRestartTimer
+# Description: Time (in minutes) to delay the restart of TolBarad if the world server
+# crashed during a running battle.
+# Default: 10
+
+TolBarad.CrashRestartTimer = 10
+
+#
###################################################################################################
###################################################################################################
diff --git a/src/tools/connection_patcher/Program.cpp b/src/tools/connection_patcher/Program.cpp
index 0f2a829d71b..354cfa17191 100644
--- a/src/tools/connection_patcher/Program.cpp
+++ b/src/tools/connection_patcher/Program.cpp
@@ -25,7 +25,8 @@
#include "Patterns/Mac.hpp"
#include "Patterns/Windows.hpp"
-#include <CompilerDefs.h>
+#include "Banner.h"
+#include "CompilerDefs.h"
#include <boost/algorithm/string/replace.hpp>
#include <boost/program_options.hpp>
@@ -131,6 +132,8 @@ int main(int argc, char** argv)
try
{
+ Trinity::Banner::Show("connection_patcher", [](char const* text) { std::cout << text << std::endl; }, nullptr);
+
auto vm = GetConsoleArguments(argc, argv);
// exit if help is enabled
diff --git a/src/tools/map_extractor/System.cpp b/src/tools/map_extractor/System.cpp
index 22a8cc72c3c..91efa8ce287 100644
--- a/src/tools/map_extractor/System.cpp
+++ b/src/tools/map_extractor/System.cpp
@@ -35,6 +35,7 @@
#include "DBFilesClientList.h"
#include "CascLib.h"
#include "dbcfile.h"
+#include "Banner.h"
#include "StringFormat.h"
#include "adt.h"
@@ -1179,8 +1180,7 @@ bool OpenCascStorage(int locale)
int main(int argc, char * arg[])
{
- printf("Map & DBC Extractor\n");
- printf("===================\n");
+ Trinity::Banner::Show("Map & DBC Extractor", [](char const* text) { printf("%s\n", text); }, nullptr);
boost::filesystem::path current(boost::filesystem::current_path());
strcpy(input_path, current.string().c_str());
diff --git a/src/tools/mmaps_generator/PathGenerator.cpp b/src/tools/mmaps_generator/PathGenerator.cpp
index 7bec37a64e8..29b0715fdbf 100644
--- a/src/tools/mmaps_generator/PathGenerator.cpp
+++ b/src/tools/mmaps_generator/PathGenerator.cpp
@@ -19,6 +19,7 @@
#include "PathCommon.h"
#include "MapBuilder.h"
#include "Timer.h"
+#include "Banner.h"
using namespace MMAP;
@@ -242,6 +243,8 @@ int finish(const char* message, int returnValue)
int main(int argc, char** argv)
{
+ Trinity::Banner::Show("MMAP generator", [](char const* text) { printf("%s\n", text); }, nullptr);
+
int threads = 3, mapnum = -1;
float maxAngle = 70.0f;
int tileX = -1, tileY = -1;
diff --git a/src/tools/vmap4_assembler/VMapAssembler.cpp b/src/tools/vmap4_assembler/VMapAssembler.cpp
index efe705e8b6c..24889e7fa63 100644
--- a/src/tools/vmap4_assembler/VMapAssembler.cpp
+++ b/src/tools/vmap4_assembler/VMapAssembler.cpp
@@ -20,9 +20,12 @@
#include <iostream>
#include "TileAssembler.h"
+#include "Banner.h"
int main(int argc, char* argv[])
{
+ Trinity::Banner::Show("VMAP assembler", [](char const* text) { std::cout << text << std::endl; }, nullptr);
+
if (argc != 3)
{
std::cout << "usage: " << argv[0] << " <raw data dir> <vmap dest dir>" << std::endl;
diff --git a/src/tools/vmap4_extractor/vmapexport.cpp b/src/tools/vmap4_extractor/vmapexport.cpp
index 55f2e6efde4..e4177052751 100644
--- a/src/tools/vmap4_extractor/vmapexport.cpp
+++ b/src/tools/vmap4_extractor/vmapexport.cpp
@@ -49,7 +49,7 @@
#include "mpqfile.h"
#include "vmapexport.h"
-
+#include "Banner.h"
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
@@ -457,6 +457,8 @@ bool processArgv(int argc, char ** argv, const char *versionString)
int main(int argc, char ** argv)
{
+ Trinity::Banner::Show("VMAP data extractor", [](char const* text) { printf("%s\n", text); }, nullptr);
+
bool success = true;
const char *versionString = "V4.03 2015_05";