-
-
Save callmephil/5ac52a0983dc433d6937 to your computer and use it in GitHub Desktop.
arena spectator system
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 7b0fad50ebcb1be886b807c9f8e6374311e6e234 Mon Sep 17 00:00:00 2001 | |
From: EmiliyanKurtseliyanski <[email protected]> | |
Date: Sun, 30 Mar 2014 22:22:16 -0700 | |
Subject: [PATCH] Proper Spectator | |
--- | |
sql/Razer/Custom/rbac_permissions_Spectate.sql | 12 + | |
.../Custom/rbac_role_permissions_Spectate.sql | 12 + | |
src/server/game/Accounts/RBAC.h | 6 + | |
src/server/game/Battlegrounds/Battleground.cpp | 34 +- | |
src/server/game/Battlegrounds/Battleground.h | 9 + | |
src/server/game/Battlegrounds/BattlegroundMgr.h | 15 +- | |
src/server/game/Battlegrounds/SpectatorAddon.cpp | 219 ++++++++ | |
src/server/game/Battlegrounds/SpectatorAddon.h | 95 ++++ | |
src/server/game/Entities/GameObject/GameObject.cpp | 11 + | |
src/server/game/Entities/Player/Player.cpp | 172 +++++- | |
src/server/game/Entities/Player/Player.h | 15 +- | |
src/server/game/Entities/Unit/Unit.cpp | 95 +++- | |
src/server/game/Handlers/ChatHandler.cpp | 6 + | |
src/server/game/Maps/Map.cpp | 7 + | |
src/server/game/Miscellaneous/Language.h | 3 + | |
src/server/game/Scripting/ScriptLoader.cpp | 4 +- | |
src/server/game/Spells/Spell.cpp | 14 + | |
src/server/scripts/Commands/cs_gm.cpp | 2 + | |
src/server/scripts/Custom/CMakeLists.txt | 1 + | |
.../scripts/Custom/custom_Arena_Spectator.cpp | 611 +++++++++++++++++++++ | |
20 files changed, 1317 insertions(+), 26 deletions(-) | |
create mode 100644 sql/Razer/Custom/rbac_permissions_Spectate.sql | |
create mode 100644 sql/Razer/Custom/rbac_role_permissions_Spectate.sql | |
create mode 100644 src/server/game/Battlegrounds/SpectatorAddon.cpp | |
create mode 100644 src/server/game/Battlegrounds/SpectatorAddon.h | |
create mode 100644 src/server/scripts/Custom/custom_Arena_Spectator.cpp | |
diff --git a/sql/Razer/Custom/rbac_permissions_Spectate.sql b/sql/Razer/Custom/rbac_permissions_Spectate.sql | |
new file mode 100644 | |
index 0000000..a71947f | |
--- /dev/null | |
+++ b/sql/Razer/Custom/rbac_permissions_Spectate.sql | |
@@ -0,0 +1,12 @@ | |
+/* | |
+SQLyog Ultimate v11.11 (64 bit) | |
+MySQL - 5.6.12-log | |
+********************************************************************* | |
+*/ | |
+/*!40101 SET NAMES utf8 */; | |
+ | |
+insert into `rbac_permissions` (`id`, `name`) values('1000','spectate'); | |
+insert into `rbac_permissions` (`id`, `name`) values('1001','spectate player'); | |
+insert into `rbac_permissions` (`id`, `name`) values('1002','spectate view'); | |
+insert into `rbac_permissions` (`id`, `name`) values('1003','spectate reset'); | |
+insert into `rbac_permissions` (`id`, `name`) values('1004','spectate leave'); | |
diff --git a/sql/Razer/Custom/rbac_role_permissions_Spectate.sql b/sql/Razer/Custom/rbac_role_permissions_Spectate.sql | |
new file mode 100644 | |
index 0000000..8af12a8 | |
--- /dev/null | |
+++ b/sql/Razer/Custom/rbac_role_permissions_Spectate.sql | |
@@ -0,0 +1,12 @@ | |
+/* | |
+SQLyog Ultimate v11.11 (64 bit) | |
+MySQL - 5.6.12-log | |
+********************************************************************* | |
+*/ | |
+/*!40101 SET NAMES utf8 */; | |
+ | |
+insert into `rbac_role_permissions` (`roleId`, `permissionId`, `command`) values('1','1000','spectate'); | |
+insert into `rbac_role_permissions` (`roleId`, `permissionId`, `command`) values('1','1001','spectate player'); | |
+insert into `rbac_role_permissions` (`roleId`, `permissionId`, `command`) values('1','1002','spectate view'); | |
+insert into `rbac_role_permissions` (`roleId`, `permissionId`, `command`) values('1','1003','spectate reset'); | |
+insert into `rbac_role_permissions` (`roleId`, `permissionId`, `command`) values('1','1004','spectate leave'); | |
diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h | |
index dc5a276..d28e0b5 100644 | |
--- a/src/server/game/Accounts/RBAC.h | |
+++ b/src/server/game/Accounts/RBAC.h | |
@@ -683,6 +683,12 @@ enum RBACPermissions | |
RBAC_PERM_COMMAND_MAILBOX = 777, | |
// custom permissions 1000+ | |
+ RBAC_PERM_COMMAND_SPECTATE = 1000, | |
+ RBAC_PERM_COMMAND_SPECTATE_PLAYER = 1001, | |
+ RBAC_PERM_COMMAND_SPECTATE_VIEW = 1002, | |
+ RBAC_PERM_COMMAND_SPECTATE_RESET = 1003, | |
+ RBAC_PERM_COMMAND_SPECTATE_LEAVE = 1004, | |
+ | |
RBAC_PERM_MAX | |
}; | |
diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp | |
index 4860f22..ae96071 100644 | |
--- a/src/server/game/Battlegrounds/Battleground.cpp | |
+++ b/src/server/game/Battlegrounds/Battleground.cpp | |
@@ -1328,14 +1328,23 @@ void Battleground::EventPlayerLoggedOut(Player* player) | |
m_Players[guid].OfflineRemoveTime = sWorld->GetGameTime() + MAX_OFFLINE_TIME; | |
if (GetStatus() == STATUS_IN_PROGRESS) | |
{ | |
- // drop flag and handle other cleanups | |
- RemovePlayer(player, guid, GetPlayerTeam(guid)); | |
- | |
- // 1 player is logging out, if it is the last, then end arena! | |
- if (isArena()) | |
- if (GetAlivePlayersCountByTeam(player->GetBGTeam()) <= 1 && GetPlayersCountByTeam(GetOtherTeam(player->GetBGTeam()))) | |
- EndBattleground(GetOtherTeam(player->GetBGTeam())); | |
- } | |
+ if (!player->IsSpectator()) | |
+ { | |
+ // drop flag and handle other cleanups | |
+ RemovePlayer(player, guid, GetPlayerTeam(guid)); | |
+ // 1 player is logging out, if it is the last, then end arena! | |
+ if (isArena()) | |
+ if (GetAlivePlayersCountByTeam(player->GetTeam()) <= 1 && GetPlayersCountByTeam(GetOtherTeam(player->GetTeam()))) | |
+ EndBattleground(GetOtherTeam(player->GetTeam())); | |
+ } | |
+ } | |
+ if (!player->IsSpectator()) | |
+ player->LeaveBattleground(); | |
+ else | |
+ { | |
+ player->TeleportToBGEntryPoint(); | |
+ RemoveSpectator(player->GetGUID()); | |
+ } | |
} | |
// This method should be called only once ... it adds pointer to queue | |
@@ -2032,3 +2041,12 @@ bool Battleground::CheckAchievementCriteriaMeet(uint32 criteriaId, Player const* | |
TC_LOG_ERROR("bg.battleground", "Battleground::CheckAchievementCriteriaMeet: No implementation for criteria %u", criteriaId); | |
return false; | |
} | |
+ | |
+void Battleground::SendSpectateAddonsMsg(SpectatorAddonMsg msg) | |
+{ | |
+ if (!HaveSpectators()) | |
+ return; | |
+ | |
+ for (SpectatorList::iterator itr = m_Spectators.begin(); itr != m_Spectators.end(); ++itr) | |
+ msg.SendPacket(*itr); | |
+} | |
\ No newline at end of file | |
diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h | |
index 824a71b..23c1b7e 100644 | |
--- a/src/server/game/Battlegrounds/Battleground.h | |
+++ b/src/server/game/Battlegrounds/Battleground.h | |
@@ -22,6 +22,7 @@ | |
#include "Common.h" | |
#include "SharedDefines.h" | |
#include "DBCEnums.h" | |
+#include "SpectatorAddon.h" | |
class Creature; | |
class GameObject; | |
@@ -364,6 +365,12 @@ class Battleground | |
bool HasFreeSlots() const; | |
uint32 GetFreeSlotsForTeam(uint32 Team) const; | |
+ typedef std::set<uint32> SpectatorList; | |
+ void AddSpectator(uint32 playerId) { m_Spectators.insert(playerId); } | |
+ void RemoveSpectator(uint32 playerId) { m_Spectators.erase(playerId); } | |
+ bool HaveSpectators() { return (m_Spectators.size() > 0); } | |
+ void SendSpectateAddonsMsg(SpectatorAddonMsg msg); | |
+ | |
bool isArena() const { return m_IsArena; } | |
bool isBattleground() const { return !m_IsArena; } | |
bool isRated() const { return m_IsRated; } | |
@@ -652,6 +659,8 @@ class Battleground | |
// Raid Group | |
Group* m_BgRaids[BG_TEAMS_COUNT]; // 0 - alliance, 1 - horde | |
+ SpectatorList m_Spectators; | |
+ | |
// Players count by team | |
uint32 m_PlayersCount[BG_TEAMS_COUNT]; | |
diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.h b/src/server/game/Battlegrounds/BattlegroundMgr.h | |
index 2c94636..ffc465b 100644 | |
--- a/src/server/game/Battlegrounds/BattlegroundMgr.h | |
+++ b/src/server/game/Battlegrounds/BattlegroundMgr.h | |
@@ -88,7 +88,7 @@ class BattlegroundMgr | |
Battleground* GetBattleground(uint32 InstanceID, BattlegroundTypeId bgTypeId); | |
Battleground* GetBattlegroundTemplate(BattlegroundTypeId bgTypeId); | |
Battleground* CreateNewBattleground(BattlegroundTypeId bgTypeId, PvPDifficultyEntry const* bracketEntry, uint8 arenaType, bool isRated); | |
- | |
+ BattlegroundContainer GetBattlegroundsByType(BattlegroundTypeId bgTypeId) { return m_Battlegrounds[bgTypeId]; } | |
void AddBattleground(Battleground* bg); | |
void RemoveBattleground(BattlegroundTypeId bgTypeId, uint32 instanceId); | |
void AddToBGFreeSlotQueue(BattlegroundTypeId bgTypeId, Battleground* bg); | |
@@ -112,6 +112,7 @@ class BattlegroundMgr | |
bool isArenaTesting() const { return m_ArenaTesting; } | |
bool isTesting() const { return m_Testing; } | |
+ bool IsArenaType(BattlegroundTypeId bgTypeId); | |
static BattlegroundQueueTypeId BGQueueTypeId(BattlegroundTypeId bgTypeId, uint8 arenaType); | |
static BattlegroundTypeId BGTemplateId(BattlegroundQueueTypeId bgQueueTypeId); | |
@@ -120,7 +121,14 @@ class BattlegroundMgr | |
static HolidayIds BGTypeToWeekendHolidayId(BattlegroundTypeId bgTypeId); | |
static BattlegroundTypeId WeekendHolidayIdToBGType(HolidayIds holiday); | |
static bool IsBGWeekend(BattlegroundTypeId bgTypeId); | |
- | |
+ BattlegroundData* GetAllBattlegroundsWithTypeId(BattlegroundTypeId bgTypeId) | |
+ { | |
+ BattlegroundDataContainer::iterator it = bgDataStore.find(bgTypeId); | |
+ if (it == bgDataStore.end()) | |
+ return NULL; | |
+ | |
+ return &it->second; | |
+ } | |
uint32 GetMaxRatingDifference() const; | |
uint32 GetRatingDiscardTimer() const; | |
void LoadBattleMastersEntry(); | |
@@ -135,12 +143,11 @@ class BattlegroundMgr | |
private: | |
bool CreateBattleground(CreateBattlegroundData& data); | |
uint32 CreateClientVisibleInstanceId(BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id); | |
- static bool IsArenaType(BattlegroundTypeId bgTypeId); | |
BattlegroundTypeId GetRandomBG(BattlegroundTypeId id); | |
typedef std::map<BattlegroundTypeId, BattlegroundData> BattlegroundDataContainer; | |
BattlegroundDataContainer bgDataStore; | |
- | |
+ BattlegroundContainer m_Battlegrounds[MAX_BATTLEGROUND_TYPE_ID]; | |
BattlegroundQueue m_BattlegroundQueues[MAX_BATTLEGROUND_QUEUE_TYPES]; | |
typedef std::map<BattlegroundTypeId, uint8> BattlegroundSelectionWeightMap; // TypeId and its selectionWeight | |
diff --git a/src/server/game/Battlegrounds/SpectatorAddon.cpp b/src/server/game/Battlegrounds/SpectatorAddon.cpp | |
new file mode 100644 | |
index 0000000..b00b8a4 | |
--- /dev/null | |
+++ b/src/server/game/Battlegrounds/SpectatorAddon.cpp | |
@@ -0,0 +1,219 @@ | |
+/* | |
+ * Copyright (C) 2008-2012 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 "Player.h" | |
+#include "Item.h" | |
+#include "SpellInfo.h" | |
+ | |
+SpectatorAddonMsg::SpectatorAddonMsg() | |
+{ | |
+ for (uint8 i = 0; i < SPECTATOR_PREFIX_COUNT; ++i) | |
+ prefixFlags[i] = false; | |
+ | |
+ player = ""; | |
+ target = ""; | |
+ isAlive = false; | |
+ pClass = CLASS_WARRIOR; | |
+ maxHP = 0; | |
+ maxPower = 0; | |
+ currHP = 0; | |
+ currPower = 0; | |
+ powerType = POWER_MANA; | |
+ spellId = 0; | |
+ castTime = 0; | |
+ team = ALLIANCE; | |
+} | |
+ | |
+bool SpectatorAddonMsg::CanSandAura(uint32 auraID) | |
+{ | |
+ const SpellInfo *spell = sSpellMgr->GetSpellInfo(auraID); | |
+ if (!spell) | |
+ return false; | |
+ | |
+ if (spell->SpellIconID == 1) | |
+ return false; | |
+ | |
+ return true; | |
+} | |
+ | |
+void SpectatorAddonMsg::CreateAura(uint32 _caster, uint32 _spellId, bool _isDebuff, uint8 _type, int32 _duration, int32 _expire, uint16 _stack, bool _isRemove) | |
+{ | |
+ if (!CanSandAura(_spellId)) | |
+ return; | |
+ | |
+ aCaster = _caster; | |
+ aSpellId = _spellId; | |
+ aIsDebuff = _isDebuff; | |
+ aType = _type; | |
+ aDuration = _duration; | |
+ aExpire = _expire; | |
+ aStack = _stack; | |
+ aRemove = _isRemove; | |
+ EnableFlag(SPECTATOR_PREFIX_AURA); | |
+} | |
+ | |
+std::string SpectatorAddonMsg::GetMsgData() | |
+{ | |
+ std::string addonData = ""; | |
+ | |
+ if (!isFilledIn(SPECTATOR_PREFIX_PLAYER)) | |
+ { | |
+ TC_LOG_ERROR("bg.battleground", "SPECTATOR ADDON: player is not filled in."); | |
+ return addonData; | |
+ } | |
+ | |
+ std::string msg = ""; | |
+ for (uint8 i = 0; i < SPECTATOR_PREFIX_COUNT; ++i) | |
+ if (isFilledIn(i)) | |
+ { | |
+ switch (i) | |
+ { | |
+ case SPECTATOR_PREFIX_PLAYER: | |
+ msg += player + ";"; | |
+ break; | |
+ case SPECTATOR_PREFIX_TARGET: | |
+ msg += "TRG=" + target + ";"; | |
+ break; | |
+ case SPECTATOR_PREFIX_TEAM: | |
+ { | |
+ char buffer[20]; | |
+ sprintf(buffer, "TEM=%i;", (uint16)team); | |
+ msg += buffer; | |
+ break; | |
+ } | |
+ case SPECTATOR_PREFIX_STATUS: | |
+ { | |
+ char buffer[20]; | |
+ sprintf(buffer, "STA=%d;", isAlive); | |
+ msg += buffer; | |
+ break; | |
+ } | |
+ case SPECTATOR_PREFIX_CLASS: | |
+ { | |
+ char buffer[20]; | |
+ sprintf(buffer, "CLA=%i;", (int)pClass); | |
+ msg += buffer; | |
+ break; | |
+ } | |
+ case SPECTATOR_PREFIX_MAXHP: | |
+ { | |
+ char buffer[30]; | |
+ sprintf(buffer, "MHP=%i;", maxHP); | |
+ msg += buffer; | |
+ break; | |
+ } | |
+ case SPECTATOR_PREFIX_CURHP: | |
+ { | |
+ char buffer[30]; | |
+ sprintf(buffer, "CHP=%i;", currHP); | |
+ msg += buffer; | |
+ break; | |
+ } | |
+ case SPECTATOR_PREFIX_MAXPOWER: | |
+ { | |
+ char buffer[30]; | |
+ sprintf(buffer, "MPW=%i;", maxPower); | |
+ msg += buffer; | |
+ break; | |
+ } | |
+ case SPECTATOR_PREFIX_CURPOWER: | |
+ { | |
+ char buffer[30]; | |
+ sprintf(buffer, "CPW=%i;", currPower); | |
+ msg += buffer; | |
+ break; | |
+ } | |
+ case SPECTATOR_PREFIX_POWERTYPE: | |
+ { | |
+ char buffer[20]; | |
+ sprintf(buffer, "PWT=%i;", (uint8)powerType); | |
+ msg += buffer; | |
+ break; | |
+ } | |
+ case SPECTATOR_PREFIX_SPELL: | |
+ { | |
+ char buffer[80]; | |
+ sprintf(buffer, "SPE=%i,%i;", spellId, castTime); | |
+ msg += buffer; | |
+ break; | |
+ } | |
+ case SPECTATOR_PREFIX_AURA: | |
+ { | |
+ char buffer[300]; | |
+ sprintf(buffer, "AUR=%i,%i,%i,%i,%i,%i,%i,0x%X;", aRemove, aStack, | |
+ aExpire, aDuration, | |
+ aSpellId, aType, | |
+ aIsDebuff, aCaster); | |
+ msg += buffer; | |
+ break; | |
+ } | |
+ } | |
+ } | |
+ | |
+ if (msg != "") | |
+ addonData = "ARENASPEC " + msg; | |
+ | |
+ return addonData; | |
+} | |
+ | |
+bool SpectatorAddonMsg::SendPacket(uint32 receiver) | |
+{ | |
+ std::string addonData = GetMsgData(); | |
+ if (addonData == "") | |
+ return false; | |
+ | |
+ Player* rPlayer = ObjectAccessor::FindPlayer(receiver); | |
+ if (!rPlayer) | |
+ return false; | |
+ | |
+ WorldPacket data(SMSG_MESSAGECHAT, 200); | |
+ data << uint8(CHAT_MSG_WHISPER); | |
+ data << uint32(LANG_ADDON); | |
+ data << uint64(0); | |
+ data << uint32(LANG_ADDON); //language 2.1.0 ? | |
+ data << uint64(0); | |
+ data << uint32(addonData.length() + 1); | |
+ data << addonData; | |
+ data << uint8(CHAT_TAG_NONE); | |
+ rPlayer->GetSession()->SendPacket(&data); | |
+ | |
+ return true; | |
+} | |
+ | |
+bool SpectatorAddonMsg::SendPacket(SpectatorAddonMsg msg, uint32 receiver) | |
+{ | |
+ std::string addonData = msg.GetMsgData(); | |
+ if (addonData == "") | |
+ return false; | |
+ | |
+ Player* rPlayer = ObjectAccessor::FindPlayer(receiver); | |
+ if (!rPlayer) | |
+ return false; | |
+ | |
+ WorldPacket data(SMSG_MESSAGECHAT, 200); | |
+ data << uint8(CHAT_MSG_WHISPER); | |
+ data << uint32(LANG_ADDON); | |
+ data << uint64(0); | |
+ data << uint32(LANG_ADDON); //language 2.1.0 ? | |
+ data << uint64(0); | |
+ data << uint32(addonData.length() + 1); | |
+ data << addonData; | |
+ data << uint8(CHAT_TAG_NONE); | |
+ rPlayer->GetSession()->SendPacket(&data); | |
+ | |
+ return true; | |
+} | |
\ No newline at end of file | |
diff --git a/src/server/game/Battlegrounds/SpectatorAddon.h b/src/server/game/Battlegrounds/SpectatorAddon.h | |
new file mode 100644 | |
index 0000000..9228ecc | |
--- /dev/null | |
+++ b/src/server/game/Battlegrounds/SpectatorAddon.h | |
@@ -0,0 +1,95 @@ | |
+/* | |
+ * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/> | |
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> | |
+ * | |
+ * This program is free software; you can redistribute it and/or modify it | |
+ * under the terms of the GNU General Public License as published by the | |
+ * Free Software Foundation; either version 2 of the License, or (at your | |
+ * option) any later version. | |
+ * | |
+ * This program is distributed in the hope that it will be useful, but WITHOUT | |
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
+ * more details. | |
+ * | |
+ * You should have received a copy of the GNU General Public License along | |
+ * with this program. If not, see <http://www.gnu.org/licenses/>. | |
+ */ | |
+ | |
+#define SPECTATOR_ADDON_SPELL_INTERUPTED 99999 // specific addons | |
+#define SPECTATOR_ADDON_SPELL_CANCELED 99998 // numbers =\ | |
+ | |
+enum SpectatorPrefix { | |
+ SPECTATOR_PREFIX_PLAYER, | |
+ SPECTATOR_PREFIX_STATUS, | |
+ SPECTATOR_PREFIX_MAXHP, | |
+ SPECTATOR_PREFIX_CURHP, | |
+ SPECTATOR_PREFIX_MAXPOWER, | |
+ SPECTATOR_PREFIX_CURPOWER, | |
+ SPECTATOR_PREFIX_POWERTYPE, | |
+ SPECTATOR_PREFIX_TARGET, | |
+ SPECTATOR_PREFIX_CLASS, | |
+ SPECTATOR_PREFIX_TEAM, | |
+ SPECTATOR_PREFIX_SPELL, | |
+ SPECTATOR_PREFIX_AURA, | |
+ SPECTATOR_PREFIX_COUNT // must be at the end of list | |
+}; | |
+ | |
+class SpectatorAddonMsg { | |
+ public: | |
+ SpectatorAddonMsg(); | |
+ | |
+ void SetPlayer(std::string _player) { player = _player; EnableFlag(SPECTATOR_PREFIX_PLAYER); } | |
+ void SetStatus(bool _isAlive) { isAlive = _isAlive; EnableFlag(SPECTATOR_PREFIX_STATUS); } | |
+ void SetClass(uint8 _class) { pClass = _class; EnableFlag(SPECTATOR_PREFIX_CLASS); } | |
+ void SetTarget(std::string _target) { target = _target; EnableFlag(SPECTATOR_PREFIX_TARGET); } | |
+ void SetTeam(uint32 _team) { team = _team; EnableFlag(SPECTATOR_PREFIX_TEAM); } | |
+ | |
+ void SetMaxHP(uint16 hp) { maxHP = hp; EnableFlag(SPECTATOR_PREFIX_MAXHP); } | |
+ void SetCurrentHP(uint16 hp) { currHP = hp; EnableFlag(SPECTATOR_PREFIX_CURHP); } | |
+ void SetMaxPower(uint16 power) { maxPower = power; EnableFlag(SPECTATOR_PREFIX_MAXPOWER); } | |
+ void SetCurrentPower(uint16 power) { currPower = power; EnableFlag(SPECTATOR_PREFIX_CURPOWER); } | |
+ void SetPowerType(Powers power) { powerType = power; EnableFlag(SPECTATOR_PREFIX_POWERTYPE); } | |
+ | |
+ void CastSpell(uint32 _spellId, uint32 _castTime) { spellId = _spellId; castTime = _castTime; EnableFlag(SPECTATOR_PREFIX_SPELL); } | |
+ void CreateAura(uint32 _caster, uint32 _spellId, bool _isDebuff, uint8 _type, int32 _duration, int32 _expire, uint16 _stack, bool _isRemove); | |
+ | |
+ static bool SendPacket(SpectatorAddonMsg msg, uint32 receiver); | |
+ bool SendPacket(uint32 receiver); | |
+ | |
+ std::string GetMsgData(); | |
+ | |
+ bool isFilledIn(uint8 prefix) { return prefixFlags[prefix]; } | |
+ | |
+ static bool CanSandAura(uint32 auraID); | |
+ private: | |
+ | |
+ void EnableFlag(uint8 prefix) { prefixFlags[prefix] = true; } | |
+ std::string player; | |
+ bool isAlive; | |
+ std::string target; | |
+ uint8 pClass; | |
+ | |
+ uint16 maxHP; | |
+ uint16 maxPower; | |
+ uint16 currHP; | |
+ uint16 currPower; | |
+ Powers powerType; | |
+ | |
+ uint32 spellId; | |
+ uint32 castTime; | |
+ | |
+ uint32 team; | |
+ | |
+ // aura data | |
+ uint32 aCaster; | |
+ uint32 aSpellId; | |
+ bool aIsDebuff; | |
+ uint8 aType; | |
+ int32 aDuration; | |
+ int32 aExpire; | |
+ uint16 aStack; | |
+ bool aRemove; | |
+ | |
+ bool prefixFlags[SPECTATOR_PREFIX_COUNT]; | |
+}; | |
\ No newline at end of file | |
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp | |
index 01bdf63..5ace1ec 100644 | |
--- a/src/server/game/Entities/GameObject/GameObject.cpp | |
+++ b/src/server/game/Entities/GameObject/GameObject.cpp | |
@@ -514,6 +514,11 @@ void GameObject::Update(uint32 diff) | |
if (ok) | |
{ | |
+ | |
+ if (Player *tmpPlayer = ok->ToPlayer()) | |
+ if (tmpPlayer->IsSpectator()) | |
+ return; | |
+ | |
// some traps do not have spell but should be triggered | |
if (goInfo->trap.spellId) | |
CastSpell(ok, goInfo->trap.spellId); | |
@@ -1713,6 +1718,12 @@ void GameObject::Use(Unit* user) | |
void GameObject::CastSpell(Unit* target, uint32 spellId) | |
{ | |
+ | |
+ if (target) | |
+ if (Player *tmpPlayer = target->ToPlayer()) | |
+ if (tmpPlayer->IsSpectator()) | |
+ return; | |
+ | |
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); | |
if (!spellInfo) | |
return; | |
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp | |
index 79f7c35..ea728a8 100644 | |
--- a/src/server/game/Entities/Player/Player.cpp | |
+++ b/src/server/game/Entities/Player/Player.cpp | |
@@ -895,7 +895,9 @@ Player::Player(WorldSession* session): Unit(true), phaseMgr(this) | |
m_MonthlyQuestChanged = false; | |
m_SeasonalQuestChanged = false; | |
- | |
+ spectatorFlag = false; | |
+ spectateCanceled = false; | |
+ spectateFrom = NULL; | |
SetPendingBind(0, 0); | |
_activeCheats = CHEAT_NONE; | |
@@ -1876,7 +1878,14 @@ void Player::setDeathState(DeathState s) | |
TC_LOG_ERROR("entities.player", "setDeathState: attempt to kill a dead player %s(%d)", GetName().c_str(), GetGUIDLow()); | |
return; | |
} | |
- | |
+ // send spectate addon message | |
+ if (HaveSpectators()) | |
+ { | |
+ SpectatorAddonMsg msg; | |
+ msg.SetPlayer(GetName()); | |
+ msg.SetStatus(false); | |
+ SendSpectatorAddonMsgToBG(msg); | |
+ } | |
// drunken state is cleared on death | |
SetDrunkValue(0); | |
// lost combo points at any target (targeted combo points clear in Unit::setDeathState) | |
@@ -1921,6 +1930,20 @@ void Player::InnEnter(time_t time, uint32 mapid, float x, float y, float z) | |
time_inn_enter = time; | |
} | |
+void Player::SetSelection(uint64 guid) | |
+{ | |
+ uint32 m_curSelection = guid; | |
+ SetUInt64Value(UNIT_FIELD_TARGET, guid); | |
+ if (Player *target = ObjectAccessor::FindPlayer(guid)) | |
+ if (HaveSpectators()) | |
+ { | |
+ SpectatorAddonMsg msg; | |
+ msg.SetPlayer(GetName()); | |
+ msg.SetTarget(target->GetName()); | |
+ SendSpectatorAddonMsgToBG(msg); | |
+ } | |
+} | |
+ | |
bool Player::BuildEnumData(PreparedQueryResult result, ByteBuffer* dataBuffer, ByteBuffer* bitBuffer) | |
{ | |
// 0 1 2 3 4 5 6 7 | |
@@ -2374,7 +2397,17 @@ bool Player::TeleportToBGEntryPoint() | |
ScheduleDelayedOperation(DELAYED_BG_MOUNT_RESTORE); | |
ScheduleDelayedOperation(DELAYED_BG_TAXI_RESTORE); | |
ScheduleDelayedOperation(DELAYED_BG_GROUP_RESTORE); | |
- return TeleportTo(m_bgData.joinPos); | |
+ Battleground *oldBg = GetBattleground(); | |
+ bool result = TeleportTo(m_bgData.joinPos); | |
+ | |
+ if (IsSpectator() && result) | |
+ { | |
+ SetSpectate(false); | |
+ if (oldBg) | |
+ oldBg->RemoveSpectator(GetGUID()); | |
+ } | |
+ | |
+ return result; | |
} | |
void Player::ProcessDelayedOperations() | |
@@ -2880,6 +2913,95 @@ void Player::SetInWater(bool apply) | |
getHostileRefManager().updateThreatTables(); | |
} | |
+void Player::SetSpectate(bool on) | |
+{ | |
+ if (on) | |
+ { | |
+ SetSpeed(MOVE_RUN, 5.0); | |
+ spectatorFlag = true; | |
+ | |
+ m_ExtraFlags |= PLAYER_EXTRA_GM_ON; | |
+ setFaction(35); | |
+ | |
+ if (Pet* pet = GetPet()) | |
+ { | |
+ RemovePet(pet, PET_SAVE_AS_CURRENT); | |
+ } | |
+ UnsummonPetTemporaryIfAny(); | |
+ | |
+ RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); | |
+ ResetContestedPvP(); | |
+ | |
+ getHostileRefManager().setOnlineOfflineState(false); | |
+ CombatStopWithPets(); | |
+ | |
+ SetDisplayId(22235); | |
+ | |
+ m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GM, SEC_ADMINISTRATOR); | |
+ } | |
+ else | |
+ { | |
+ uint32 newPhase = 0; | |
+ AuraEffectList const& phases = GetAuraEffectsByType(SPELL_AURA_PHASE); | |
+ if (!phases.empty()) | |
+ for (AuraEffectList::const_iterator itr = phases.begin(); itr != phases.end(); ++itr) | |
+ newPhase |= (*itr)->GetMiscValue(); | |
+ | |
+ if (!newPhase) | |
+ newPhase = PHASEMASK_NORMAL; | |
+ | |
+ SetPhaseMask(newPhase, false); | |
+ | |
+ m_ExtraFlags &= ~ PLAYER_EXTRA_GM_ON; | |
+ setFactionForRace(getRace()); | |
+ RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM); | |
+ RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_CHEAT_SPELLS); | |
+ | |
+ if (spectateFrom) | |
+ SetViewpoint(spectateFrom, false); | |
+ | |
+ // restore FFA PvP Server state | |
+ if (sWorld->IsFFAPvPRealm()) | |
+ SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); | |
+ | |
+ // restore FFA PvP area state, remove not allowed for GM mounts | |
+ UpdateArea(m_areaUpdateId); | |
+ | |
+ getHostileRefManager().setOnlineOfflineState(true); | |
+ m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GM, SEC_PLAYER); | |
+ spectateCanceled = false; | |
+ spectatorFlag = false; | |
+ RestoreDisplayId(); | |
+ UpdateSpeed(MOVE_RUN, true); | |
+ } | |
+ UpdateObjectVisibility(); | |
+} | |
+ | |
+bool Player::HaveSpectators() | |
+{ | |
+ if (IsSpectator()) | |
+ return false; | |
+ | |
+ if (Battleground *bg = GetBattleground()) | |
+ if (bg->isArena()) | |
+ { | |
+ if (bg->GetStatus() != STATUS_IN_PROGRESS) | |
+ return false; | |
+ | |
+ return bg->HaveSpectators(); | |
+ } | |
+ | |
+ return false; | |
+} | |
+ | |
+void Player::SendSpectatorAddonMsgToBG(SpectatorAddonMsg msg) | |
+{ | |
+ if (!HaveSpectators()) | |
+ return; | |
+ | |
+ GetBattleground()->SendSpectateAddonsMsg(msg); | |
+} | |
+ | |
void Player::SetGameMaster(bool on) | |
{ | |
if (on) | |
@@ -23625,7 +23747,28 @@ void Player::SendAurasForTarget(Unit* target) | |
AuraApplication * auraApp = itr->second; | |
auraApp->BuildUpdatePacket(data, false); | |
} | |
- | |
+ if (Player *stream = target->ToPlayer()) | |
+ if (stream->HaveSpectators() && IsSpectator()) | |
+ { | |
+ for (Unit::VisibleAuraMap::const_iterator itr = visibleAuras->begin(); itr != visibleAuras->end(); ++itr) | |
+ { | |
+ AuraApplication * auraApp = itr->second; | |
+ auraApp->BuildUpdatePacket(data, false); | |
+ if (Aura* aura = auraApp->GetBase()) | |
+ { | |
+ SpectatorAddonMsg msg; | |
+ uint64 casterID = 0; | |
+ if (aura->GetCaster()) | |
+ casterID = (aura->GetCaster()->ToPlayer()) ? aura->GetCaster()->GetGUID() : 0; | |
+ msg.SetPlayer(stream->GetName()); | |
+ msg.CreateAura(casterID, aura->GetSpellInfo()->Id, | |
+ aura->GetSpellInfo()->IsPositive(), aura->GetSpellInfo()->Dispel, | |
+ aura->GetDuration(), aura->GetMaxDuration(), | |
+ aura->GetStackAmount(), false); | |
+ msg.SendPacket(GetGUID()); | |
+ } | |
+ } | |
+ } | |
GetSession()->SendPacket(&data); | |
} | |
@@ -24775,6 +24918,15 @@ void Player::SetViewpoint(WorldObject* target, bool apply) | |
{ | |
if (apply) | |
{ | |
+ if (target->ToPlayer() == this) | |
+ return; | |
+ | |
+ //remove Viewpoint if already have | |
+ if (IsSpectator() && spectateFrom) | |
+ { | |
+ SetViewpoint(spectateFrom, false); | |
+ spectateFrom = NULL; | |
+ } | |
TC_LOG_DEBUG("maps", "Player::CreateViewpoint: Player %s create seer %u (TypeId: %u).", GetName().c_str(), target->GetEntry(), target->GetTypeId()); | |
if (!AddUInt64Value(PLAYER_FARSIGHT, target->GetGUID())) | |
@@ -24787,10 +24939,17 @@ void Player::SetViewpoint(WorldObject* target, bool apply) | |
UpdateVisibilityOf(target); | |
if (target->isType(TYPEMASK_UNIT) && !GetVehicle()) | |
- ((Unit*)target)->AddPlayerToVision(this); | |
+ { | |
+ if (IsSpectator()) | |
+ spectateFrom = (Unit*)target; | |
+ | |
+ ((Unit*)target)->AddPlayerToVision(this); | |
+ } | |
} | |
else | |
{ | |
+ if (IsSpectator() && !spectateFrom) | |
+ return; | |
TC_LOG_DEBUG("maps", "Player::CreateViewpoint: Player %s remove seer", GetName().c_str()); | |
if (!RemoveUInt64Value(PLAYER_FARSIGHT, target->GetGUID())) | |
@@ -24801,7 +24960,8 @@ void Player::SetViewpoint(WorldObject* target, bool apply) | |
if (target->isType(TYPEMASK_UNIT) && !GetVehicle()) | |
((Unit*)target)->RemovePlayerFromVision(this); | |
- | |
+ if (IsSpectator()) | |
+ spectateFrom = NULL; | |
//must immediately set seer back otherwise may crash | |
m_seer = this; | |
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h | |
index 9a77a99..6a02805 100644 | |
--- a/src/server/game/Entities/Player/Player.h | |
+++ b/src/server/game/Entities/Player/Player.h | |
@@ -31,6 +31,7 @@ | |
#include "Unit.h" | |
#include "Opcodes.h" | |
#include "WorldSession.h" | |
+#include "Battleground.h" | |
#include <string> | |
#include <vector> | |
@@ -1281,7 +1282,7 @@ class Player : public Unit, public GridObject<Player> | |
// mount_id can be used in scripting calls | |
bool isAcceptWhispers() const { return m_ExtraFlags & PLAYER_EXTRA_ACCEPT_WHISPERS; } | |
void SetAcceptWhispers(bool on) { if (on) m_ExtraFlags |= PLAYER_EXTRA_ACCEPT_WHISPERS; else m_ExtraFlags &= ~PLAYER_EXTRA_ACCEPT_WHISPERS; } | |
- bool IsGameMaster() const { return m_ExtraFlags & PLAYER_EXTRA_GM_ON; } | |
+ bool IsGameMaster() const { return ((m_ExtraFlags & PLAYER_EXTRA_GM_ON)); } | |
void SetGameMaster(bool on); | |
bool isGMChat() const { return m_ExtraFlags & PLAYER_EXTRA_GM_CHAT; } | |
void SetGMChat(bool on) { if (on) m_ExtraFlags |= PLAYER_EXTRA_GM_CHAT; else m_ExtraFlags &= ~PLAYER_EXTRA_GM_CHAT; } | |
@@ -1290,6 +1291,13 @@ class Player : public Unit, public GridObject<Player> | |
bool isGMVisible() const { return !(m_ExtraFlags & PLAYER_EXTRA_GM_INVISIBLE); } | |
void SetGMVisible(bool on); | |
void SetPvPDeath(bool on) { if (on) m_ExtraFlags |= PLAYER_EXTRA_PVP_DEATH; else m_ExtraFlags &= ~PLAYER_EXTRA_PVP_DEATH; } | |
+ bool HaveSpectators(); | |
+ void SendSpectatorAddonMsgToBG(SpectatorAddonMsg msg); | |
+ bool isSpectateCanceled() { return spectateCanceled; } | |
+ void CancelSpectate() { spectateCanceled = true; } | |
+ Unit* getSpectateFrom() { return spectateFrom; } | |
+ bool IsSpectator() const { return spectatorFlag; } | |
+ void SetSpectate(bool on); | |
void GiveXP(uint32 xp, Unit* victim, float group_rate=1.0f); | |
void GiveLevel(uint8 level); | |
@@ -1701,7 +1709,7 @@ class Player : public Unit, public GridObject<Player> | |
Player* GetSelectedPlayer() const; | |
void SetTarget(uint64 /*guid*/) OVERRIDE { } /// Used for serverside target changes, does not apply to players | |
- void SetSelection(uint64 guid) { SetUInt64Value(UNIT_FIELD_TARGET, guid); } | |
+ void SetSelection(uint64 guid); | |
uint8 GetComboPoints() const { return m_comboPoints; } | |
uint64 GetComboTarget() const { return m_comboTarget; } | |
@@ -2877,6 +2885,9 @@ class Player : public Unit, public GridObject<Player> | |
InstanceTimeMap _instanceResetTimes; | |
uint32 _pendingBindId; | |
uint32 _pendingBindTimer; | |
+ bool spectatorFlag; | |
+ bool spectateCanceled; | |
+ Unit *spectateFrom; | |
uint32 _activeCheats; | |
uint32 _maxPersonalArenaRate; | |
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp | |
index 7ff01c8..a5e6f3f 100644 | |
--- a/src/server/game/Entities/Unit/Unit.cpp | |
+++ b/src/server/game/Entities/Unit/Unit.cpp | |
@@ -292,6 +292,19 @@ Unit::~Unit() | |
m_currentSpells[i] = NULL; | |
} | |
+ // remove view point for spectator | |
+ if (!m_sharedVision.empty()) | |
+ { | |
+ for (SharedVisionList::iterator itr = m_sharedVision.begin(); itr != m_sharedVision.end(); ++itr) | |
+ if ((*itr)->IsSpectator() && (*itr)->getSpectateFrom()) | |
+ { | |
+ (*itr)->SetViewpoint((*itr)->getSpectateFrom(), false); | |
+ if (m_sharedVision.empty()) | |
+ break; | |
+ --itr; | |
+ } | |
+ } | |
+ | |
_DeleteRemovedAuras(); | |
delete i_motionMaster; | |
@@ -496,14 +509,50 @@ AuraApplication * Unit::GetVisibleAura(uint8 slot) const | |
void Unit::SetVisibleAura(uint8 slot, AuraApplication * aur) | |
{ | |
- m_visibleAuras[slot]=aur; | |
- UpdateAuraForGroup(slot); | |
+ if (Aura* aura = aur->GetBase()) | |
+ if (Player *player = ToPlayer()) | |
+ if (player->HaveSpectators() && slot < MAX_AURAS) | |
+ { | |
+ SpectatorAddonMsg msg; | |
+ uint64 casterID = 0; | |
+ if (aura->GetCaster()) | |
+ casterID = (aura->GetCaster()->ToPlayer()) ? aura->GetCaster()->GetGUID() : 0; | |
+ msg.SetPlayer(player->GetName()); | |
+ msg.CreateAura(casterID, aura->GetSpellInfo()->Id, | |
+ aura->GetSpellInfo()->IsPositive(), aura->GetSpellInfo()->Dispel, | |
+ aura->GetDuration(), aura->GetMaxDuration(), | |
+ aura->GetStackAmount(), false); | |
+ player->SendSpectatorAddonMsgToBG(msg); | |
+ } | |
+ | |
+ m_visibleAuras[slot] = aur; | |
+ UpdateAuraForGroup(slot); | |
} | |
void Unit::RemoveVisibleAura(uint8 slot) | |
{ | |
- m_visibleAuras.erase(slot); | |
- UpdateAuraForGroup(slot); | |
+ AuraApplication *aurApp = GetVisibleAura(slot); | |
+ if (aurApp && slot < MAX_AURAS) | |
+ { | |
+ if (Aura* aura = aurApp->GetBase()) | |
+ if (Player *player = ToPlayer()) | |
+ if (player->HaveSpectators()) | |
+ { | |
+ SpectatorAddonMsg msg; | |
+ uint64 casterID = 0; | |
+ if (aura->GetCaster()) | |
+ casterID = (aura->GetCaster()->ToPlayer()) ? aura->GetCaster()->GetGUID() : 0; | |
+ msg.SetPlayer(player->GetName()); | |
+ msg.CreateAura(casterID, aura->GetSpellInfo()->Id, | |
+ aurApp->IsPositive(), aura->GetSpellInfo()->Dispel, | |
+ aura->GetDuration(), aura->GetMaxDuration(), | |
+ aura->GetStackAmount(), true); | |
+ player->SendSpectatorAddonMsgToBG(msg); | |
+ } | |
+ } | |
+ | |
+ m_visibleAuras.erase(slot); | |
+ UpdateAuraForGroup(slot); | |
} | |
void Unit::UpdateInterruptMask() | |
@@ -11547,6 +11596,15 @@ void Unit::SetHealth(uint32 val) | |
// group update | |
if (Player* player = ToPlayer()) | |
{ | |
+ | |
+ if (player->HaveSpectators()) | |
+ { | |
+ SpectatorAddonMsg msg; | |
+ msg.SetPlayer(player->GetName()); | |
+ msg.SetCurrentHP(val); | |
+ player->SendSpectatorAddonMsgToBG(msg); | |
+ } | |
+ | |
if (player->GetGroup()) | |
player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP); | |
} | |
@@ -11572,6 +11630,15 @@ void Unit::SetMaxHealth(uint32 val) | |
// group update | |
if (GetTypeId() == TYPEID_PLAYER) | |
{ | |
+ | |
+ if (ToPlayer()->HaveSpectators()) | |
+ { | |
+ SpectatorAddonMsg msg; | |
+ msg.SetPlayer(ToPlayer()->GetName()); | |
+ msg.SetMaxHP(val); | |
+ ToPlayer()->SendSpectatorAddonMsgToBG(msg); | |
+ } | |
+ | |
if (ToPlayer()->GetGroup()) | |
ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_HP); | |
} | |
@@ -11632,6 +11699,16 @@ void Unit::SetPower(Powers power, int32 val) | |
// group update | |
if (Player* player = ToPlayer()) | |
{ | |
+ | |
+ if (player->HaveSpectators()) | |
+ { | |
+ SpectatorAddonMsg msg; | |
+ msg.SetPlayer(player->GetName()); | |
+ msg.SetCurrentPower(val); | |
+ msg.SetPowerType(power); | |
+ player->SendSpectatorAddonMsgToBG(msg); | |
+ } | |
+ | |
if (player->GetGroup()) | |
player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER); | |
} | |
@@ -11658,6 +11735,16 @@ void Unit::SetMaxPower(Powers power, int32 val) | |
// group update | |
if (GetTypeId() == TYPEID_PLAYER) | |
{ | |
+ | |
+ if (ToPlayer()->HaveSpectators()) | |
+ { | |
+ SpectatorAddonMsg msg; | |
+ msg.SetPlayer(ToPlayer()->GetName()); | |
+ msg.SetMaxPower(val); | |
+ msg.SetPowerType(power); | |
+ ToPlayer()->SendSpectatorAddonMsgToBG(msg); | |
+ } | |
+ | |
if (ToPlayer()->GetGroup()) | |
ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER); | |
} | |
diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp | |
index 8cac59d..7c6f615 100644 | |
--- a/src/server/game/Handlers/ChatHandler.cpp | |
+++ b/src/server/game/Handlers/ChatHandler.cpp | |
@@ -746,6 +746,12 @@ void WorldSession::HandleTextEmoteOpcode(WorldPacket& recvData) | |
recvData >> emoteNum; | |
recvData >> guid; | |
+ if (GetPlayer()->IsSpectator()) | |
+ { | |
+ SendNotification(LANG_SPEC_CAN_NOT_CHAT); | |
+ return; | |
+ } | |
+ | |
sScriptMgr->OnPlayerTextEmote(GetPlayer(), text_emote, emoteNum, guid); | |
EmotesTextEntry const* em = sEmotesTextStore.LookupEntry(text_emote); | |
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp | |
index 79e63cf..85d5ba2 100644 | |
--- a/src/server/game/Maps/Map.cpp | |
+++ b/src/server/game/Maps/Map.cpp | |
@@ -3102,6 +3102,13 @@ bool BattlegroundMap::AddPlayerToMap(Player* player) | |
void BattlegroundMap::RemovePlayerFromMap(Player* player, bool remove) | |
{ | |
+ if (player && player->IsSpectator() && !player->isSpectateCanceled()) | |
+ { | |
+ if (GetBG()) | |
+ GetBG()->RemoveSpectator(player->GetGUID()); | |
+ player->SetSpectate(false); | |
+ } | |
+ | |
TC_LOG_INFO("maps", "MAP: Removing player '%s' from bg '%u' of map '%s' before relocating to another map", player->GetName().c_str(), GetInstanceId(), GetMapName()); | |
Map::RemovePlayerFromMap(player, remove); | |
} | |
diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h | |
index 2e4d831..23a5d05 100644 | |
--- a/src/server/game/Miscellaneous/Language.h | |
+++ b/src/server/game/Miscellaneous/Language.h | |
@@ -852,6 +852,9 @@ enum TrinityStrings | |
LANG_RBAC_EMAIL_REQUIRED = 881, | |
// Room for in-game strings 882-999 not used | |
+ // Arena Spectator (Emote Disable) | |
+ LANG_SPEC_CAN_NOT_CHAT = 900, | |
+ | |
// Level 4 (CLI only commands) | |
LANG_COMMAND_EXIT = 1000, | |
LANG_ACCOUNT_DELETED = 1001, | |
diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp | |
index e4d2922..a825184 100644 | |
--- a/src/server/game/Scripting/ScriptLoader.cpp | |
+++ b/src/server/game/Scripting/ScriptLoader.cpp | |
@@ -1453,13 +1453,13 @@ void AddBattlegroundScripts() | |
#ifdef SCRIPTS | |
/* This is where custom scripts' loading functions should be declared. */ | |
- | |
+void AddSC_arena_spectator_script(); | |
#endif | |
void AddCustomScripts() | |
{ | |
#ifdef SCRIPTS | |
/* This is where custom scripts should be added. */ | |
- | |
+AddSC_arena_spectator_script(); | |
#endif | |
} | |
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp | |
index edf9271..f78cbbc 100644 | |
--- a/src/server/game/Spells/Spell.cpp | |
+++ b/src/server/game/Spells/Spell.cpp | |
@@ -2911,6 +2911,16 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered | |
TC_LOG_DEBUG("spells", "Spell::prepare: spell id %u source %u caster %d customCastFlags %u mask %u", m_spellInfo->Id, m_caster->GetEntry(), m_originalCaster ? m_originalCaster->GetEntry() : -1, _triggeredCastFlags, m_targets.GetTargetMask()); | |
+ if (GetCaster() && GetSpellInfo()) | |
+ if (Player *tmpPlayer = GetCaster()->ToPlayer()) | |
+ if (tmpPlayer->HaveSpectators()) | |
+ { | |
+ SpectatorAddonMsg msg; | |
+ msg.SetPlayer(tmpPlayer->GetName()); | |
+ msg.CastSpell(GetSpellInfo()->Id, GetSpellInfo()->CastTimeEntry->CastTime); | |
+ tmpPlayer->SendSpectatorAddonMsgToBG(msg); | |
+ } | |
+ | |
//Containers for channeled spells have to be set | |
/// @todoApply this to all cast spells if needed | |
// Why check duration? 29350: channelled triggers channelled | |
@@ -4675,6 +4685,10 @@ SpellCastResult Spell::CheckCast(bool strict) | |
return SPELL_FAILED_ONLY_INDOORS; | |
} | |
+ if (Player *tmpPlayer = m_caster->ToPlayer()) | |
+ if (tmpPlayer->IsSpectator()) | |
+ return SPELL_FAILED_SPELL_UNAVAILABLE; | |
+ | |
// only check at first call, Stealth auras are already removed at second call | |
// for now, ignore triggered spells | |
if (strict && !(_triggeredCastFlags & TRIGGERED_IGNORE_SHAPESHIFT)) | |
diff --git a/src/server/scripts/Commands/cs_gm.cpp b/src/server/scripts/Commands/cs_gm.cpp | |
index 5b58ccf..edabb43 100644 | |
--- a/src/server/scripts/Commands/cs_gm.cpp | |
+++ b/src/server/scripts/Commands/cs_gm.cpp | |
@@ -130,6 +130,8 @@ public: | |
itrSec <= AccountTypes(sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_GM_LIST)))) && | |
(!handler->GetSession() || itr->second->IsVisibleGloballyFor(handler->GetSession()->GetPlayer()))) | |
{ | |
+ if (itr->second->IsSpectator()) | |
+ continue; // don't show spectators, they're not really gms | |
if (first) | |
{ | |
first = false; | |
diff --git a/src/server/scripts/Custom/CMakeLists.txt b/src/server/scripts/Custom/CMakeLists.txt | |
index 78db719..a67b013 100644 | |
--- a/src/server/scripts/Custom/CMakeLists.txt | |
+++ b/src/server/scripts/Custom/CMakeLists.txt | |
@@ -10,6 +10,7 @@ | |
set(scripts_STAT_SRCS | |
${scripts_STAT_SRCS} | |
+ Custom/custom_Arena_Spectator.cpp | |
) | |
message(" -> Prepared: Custom") | |
diff --git a/src/server/scripts/Custom/custom_Arena_Spectator.cpp b/src/server/scripts/Custom/custom_Arena_Spectator.cpp | |
new file mode 100644 | |
index 0000000..01ccd34 | |
--- /dev/null | |
+++ b/src/server/scripts/Custom/custom_Arena_Spectator.cpp | |
@@ -0,0 +1,611 @@ | |
+/* | |
+* Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/> | |
+* Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> | |
+* | |
+* 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/>. | |
+*/ | |
+ | |
+/* ScriptData | |
+Name: Arena Spectator | |
+%Complete: 100 | |
+Comment: Script allow spectate arena games | |
+Category: Custom Script | |
+EndScriptData */ | |
+ | |
+#include "ScriptPCH.h" | |
+#include "Chat.h" | |
+#include "ArenaTeamMgr.h" | |
+#include "BattlegroundMgr.h" | |
+#include "WorldSession.h" | |
+#include "Player.h" | |
+#include "ArenaTeam.h" | |
+#include "Battleground.h" | |
+#include "BattlegroundMgr.h" | |
+#include "CreatureTextMgr.h" | |
+#include "Config.h" | |
+ | |
+int8 UsingGossip; | |
+ | |
+class arena_spectator_commands : public CommandScript | |
+{ | |
+public: | |
+ arena_spectator_commands() : CommandScript("arena_spectator_commands") { } | |
+ | |
+ static bool HandleSpectateCommand(ChatHandler* handler, char const* args) | |
+ { | |
+ Player* target; | |
+ uint64 target_guid; | |
+ std::string target_name; | |
+ if (!handler->extractPlayerTarget((char*)args, &target, &target_guid, &target_name)) | |
+ return false; | |
+ | |
+ Player* player = handler->GetSession()->GetPlayer(); | |
+ if (target == player || target_guid == player->GetGUID()) | |
+ { | |
+ handler->PSendSysMessage("You can't spectate yourself."); | |
+ handler->SetSentErrorMessage(true); | |
+ return false; | |
+ } | |
+ | |
+ if (player->IsInCombat()) | |
+ { | |
+ handler->PSendSysMessage("You are in combat."); | |
+ handler->SetSentErrorMessage(true); | |
+ return false; | |
+ } | |
+ | |
+ if (!target) | |
+ { | |
+ handler->PSendSysMessage("Target is not online or does not exist."); | |
+ handler->SetSentErrorMessage(true); | |
+ return false; | |
+ } | |
+ | |
+ if (player->GetPet()) | |
+ { | |
+ handler->PSendSysMessage("You must hide your pet."); | |
+ handler->SetSentErrorMessage(true); | |
+ return false; | |
+ } | |
+ | |
+ if (player->GetMap()->IsBattlegroundOrArena() && !player->IsSpectator()) | |
+ { | |
+ handler->PSendSysMessage("You are already in a battleground or arena."); | |
+ handler->SetSentErrorMessage(true); | |
+ return false; | |
+ } | |
+ | |
+ Map* cMap = target->GetMap(); | |
+ if (!cMap->IsBattleArena()) | |
+ { | |
+ handler->PSendSysMessage("Player is not in an Arena match."); | |
+ handler->SetSentErrorMessage(true); | |
+ return false; | |
+ } | |
+ | |
+ if (player->GetMap()->IsBattleground()) | |
+ { | |
+ handler->PSendSysMessage("You can't do that while in a battleground."); | |
+ handler->SetSentErrorMessage(true); | |
+ return false; | |
+ } | |
+ | |
+ if (target->HasAura(32728) || target->HasAura(32727)) | |
+ { | |
+ handler->PSendSysMessage("You can't do that. The Arena match didn't start yet."); | |
+ handler->SetSentErrorMessage(true); | |
+ return false; | |
+ } | |
+ | |
+ if (target->IsSpectator()) | |
+ { | |
+ handler->PSendSysMessage("You can't do that. Your target is a spectator."); | |
+ handler->SetSentErrorMessage(true); | |
+ return false; | |
+ } | |
+ | |
+ if (player->IsMounted()) | |
+ { | |
+ handler->PSendSysMessage("Cannot Spectate while mounted."); | |
+ handler->SetSentErrorMessage(true); | |
+ return false; | |
+ } | |
+ | |
+ | |
+ // all's well, set bg id | |
+ // when porting out from the bg, it will be reset to 0 | |
+ player->SetBattlegroundId(target->GetBattlegroundId(), target->GetBattlegroundTypeId()); | |
+ // remember current position as entry point for return at bg end teleportation | |
+ if (!player->GetMap()->IsBattlegroundOrArena()) | |
+ player->SetBattlegroundEntryPoint(); | |
+ | |
+ // stop flight if need | |
+ if (player->IsInFlight()) | |
+ { | |
+ player->GetMotionMaster()->MovementExpired(); | |
+ player->CleanupAfterTaxiFlight(); | |
+ } | |
+ // save only in non-flight case | |
+ else | |
+ player->SaveRecallPosition(); | |
+ | |
+ // search for two teams | |
+ Battleground *bGround = target->GetBattleground(); | |
+ if (bGround->isRated()) | |
+ { | |
+ uint32 slot = bGround->GetArenaType() - 2; | |
+ if (bGround->GetArenaType() > 3) | |
+ slot = 2; | |
+ uint32 firstTeamID = target->GetArenaTeamId(slot); | |
+ uint32 secondTeamID = 0; | |
+ Player *firstTeamMember = target; | |
+ Player *secondTeamMember = NULL; | |
+ for (Battleground::BattlegroundPlayerMap::const_iterator itr = bGround->GetPlayers().begin(); itr != bGround->GetPlayers().end(); ++itr) | |
+ if (Player* tmpPlayer = ObjectAccessor::FindPlayer(itr->first)) | |
+ { | |
+ if (tmpPlayer->IsSpectator()) | |
+ continue; | |
+ | |
+ uint32 tmpID = tmpPlayer->GetArenaTeamId(slot); | |
+ if (tmpID != firstTeamID && tmpID > 0) | |
+ { | |
+ secondTeamID = tmpID; | |
+ secondTeamMember = tmpPlayer; | |
+ break; | |
+ } | |
+ } | |
+ | |
+ if (firstTeamID > 0 && secondTeamID > 0 && secondTeamMember) | |
+ { | |
+ ArenaTeam *firstTeam = sArenaTeamMgr->GetArenaTeamById(firstTeamID); | |
+ ArenaTeam *secondTeam = sArenaTeamMgr->GetArenaTeamById(secondTeamID); | |
+ if (firstTeam && secondTeam) | |
+ { | |
+ handler->PSendSysMessage("You entered a Rated Arena."); | |
+ handler->PSendSysMessage("Teams:"); | |
+ handler->PSendSysMessage("|cFFffffff%s|r vs |cFFffffff%s|r", firstTeam->GetName().c_str(), secondTeam->GetName().c_str()); | |
+ handler->PSendSysMessage("|cFFffffff%u(%u)|r -- |cFFffffff%u(%u)|r", firstTeam->GetRating(), firstTeam->GetAverageMMR(firstTeamMember->GetGroup()), | |
+ secondTeam->GetRating(), secondTeam->GetAverageMMR(secondTeamMember->GetGroup())); | |
+ } | |
+ } | |
+ } | |
+ | |
+ // to point to see at target with same orientation | |
+ float x, y, z; | |
+ target->GetContactPoint(player, x, y, z); | |
+ | |
+ player->TeleportTo(target->GetMapId(), x, y, z, player->GetAngle(target), TELE_TO_GM_MODE); | |
+ player->SetPhaseMask(target->GetPhaseMask(), true); | |
+ player->SetSpectate(true); | |
+ target->GetBattleground()->AddSpectator(player->GetGUID()); | |
+ | |
+ return true; | |
+ } | |
+ | |
+ static bool HandleSpectateCancelCommand(ChatHandler* handler, const char* /*args*/) | |
+ { | |
+ Player* player = handler->GetSession()->GetPlayer(); | |
+ | |
+ if (!player->IsSpectator() || player->isSpectateCanceled()) | |
+ { | |
+ handler->PSendSysMessage("You are not a spectator."); | |
+ handler->SetSentErrorMessage(true); | |
+ return false; | |
+ } | |
+ | |
+ // RemoveSpectator shouldn't be needed to be done explicitly as it'll be done in the CancelSpectate func | |
+ //player->GetBattleground()->RemoveSpectator(player->GetGUID()); | |
+ player->CancelSpectate(); | |
+ player->TeleportToBGEntryPoint(); | |
+ | |
+ return true; | |
+ } | |
+ | |
+ static bool HandleSpectateFromCommand(ChatHandler* handler, const char *args) | |
+ { | |
+ Player* target; | |
+ uint64 target_guid; | |
+ std::string target_name; | |
+ if (!handler->extractPlayerTarget((char*)args, &target, &target_guid, &target_name)) | |
+ return false; | |
+ | |
+ Player* player = handler->GetSession()->GetPlayer(); | |
+ | |
+ if (!target) | |
+ { | |
+ handler->PSendSysMessage("Player is not online or does not exist."); | |
+ handler->SetSentErrorMessage(true); | |
+ return false; | |
+ } | |
+ | |
+ if (!player->IsSpectator()) | |
+ { | |
+ handler->PSendSysMessage("You are not a spectator, spectate someone first."); | |
+ handler->SetSentErrorMessage(true); | |
+ return false; | |
+ } | |
+ | |
+ if (target->IsSpectator() && target != player) | |
+ { | |
+ handler->PSendSysMessage("You can't do that. Your target is a spectator."); | |
+ handler->SetSentErrorMessage(true); | |
+ return false; | |
+ } | |
+ | |
+ if (player->GetMap() != target->GetMap()) | |
+ { | |
+ handler->PSendSysMessage("You can't do that. Your target might be in a different arena match."); | |
+ handler->SetSentErrorMessage(true); | |
+ return false; | |
+ } | |
+ | |
+ if (target && target->HasAuraType(SPELL_AURA_MOD_STEALTH)) | |
+ { | |
+ handler->PSendSysMessage("You can't target stealthed players."); | |
+ handler->SetSentErrorMessage(true); | |
+ return false; | |
+ } | |
+ | |
+ // check for arena preperation | |
+ // if exists than battle didn`t begin | |
+ if (target && target->HasAura(32728) || target->HasAura(32727)) | |
+ { | |
+ handler->PSendSysMessage("You can't do that. The Arena match didn't start yet."); | |
+ handler->SetSentErrorMessage(true); | |
+ return false; | |
+ } | |
+ | |
+ if (target == player && player->getSpectateFrom()) | |
+ player->SetViewpoint(player->getSpectateFrom(), false); | |
+ else | |
+ player->SetViewpoint(target, true); | |
+ return true; | |
+ } | |
+ | |
+ // addon data | |
+ static bool HandleSpectateResetCommand(ChatHandler* handler, const char *args) | |
+ { | |
+ Player* player = handler->GetSession()->GetPlayer(); | |
+ | |
+ if (!player->IsSpectator()) | |
+ { | |
+ handler->PSendSysMessage("You are not a spectator."); | |
+ handler->SetSentErrorMessage(true); | |
+ return false; | |
+ } | |
+ | |
+ Battleground *bGround = player->GetBattleground(); | |
+ if (!bGround) | |
+ return false; | |
+ | |
+ if (bGround->GetStatus() != STATUS_IN_PROGRESS) | |
+ return true; | |
+ | |
+ for (Battleground::BattlegroundPlayerMap::const_iterator itr = bGround->GetPlayers().begin(); itr != bGround->GetPlayers().end(); ++itr) | |
+ if (Player* tmpPlayer = ObjectAccessor::FindPlayer(itr->first)) | |
+ { | |
+ if (tmpPlayer->IsSpectator()) | |
+ continue; | |
+ | |
+ uint32 tmpID = bGround->GetPlayerTeam(tmpPlayer->GetGUID()); | |
+ | |
+ // generate addon massage | |
+ std::string pName = tmpPlayer->GetName(); | |
+ std::string tName = ""; | |
+ | |
+ if (Player *target = tmpPlayer->GetSelectedPlayer()) | |
+ tName = target->GetName(); | |
+ | |
+ SpectatorAddonMsg msg; | |
+ msg.SetPlayer(pName); | |
+ if (tName != "") | |
+ msg.SetTarget(tName); | |
+ msg.SetStatus(tmpPlayer->IsAlive()); | |
+ msg.SetClass(tmpPlayer->getClass()); | |
+ msg.SetCurrentHP(tmpPlayer->GetHealth()); | |
+ msg.SetMaxHP(tmpPlayer->GetMaxHealth()); | |
+ Powers powerType = tmpPlayer->getPowerType(); | |
+ msg.SetMaxPower(tmpPlayer->GetMaxPower(powerType)); | |
+ msg.SetCurrentPower(tmpPlayer->GetPower(powerType)); | |
+ msg.SetPowerType(powerType); | |
+ msg.SetTeam(tmpID); | |
+ msg.SendPacket(player->GetGUID()); | |
+ } | |
+ | |
+ return true; | |
+ } | |
+ | |
+ ChatCommand* GetCommands() const OVERRIDE | |
+ { | |
+ static ChatCommand spectateCommandTable[] = | |
+ { | |
+ { "player", rbac::RBAC_PERM_COMMAND_SPECTATE_PLAYER, true, &HandleSpectateCommand, "", NULL }, | |
+ { "view", rbac::RBAC_PERM_COMMAND_SPECTATE_VIEW, true, &HandleSpectateFromCommand, "", NULL }, | |
+ { "reset", rbac::RBAC_PERM_COMMAND_SPECTATE_RESET, true, &HandleSpectateResetCommand, "", NULL }, | |
+ { "leave", rbac::RBAC_PERM_COMMAND_SPECTATE_LEAVE, true, &HandleSpectateCancelCommand, "", NULL }, | |
+ { NULL, 0, false, NULL, "", NULL } | |
+ }; | |
+ | |
+ static ChatCommand commandTable[] = | |
+ { | |
+ { "spectate", rbac::RBAC_PERM_COMMAND_SPECTATE, false, NULL, "", spectateCommandTable }, | |
+ { NULL, 0, false, NULL, "", NULL } | |
+ }; | |
+ return commandTable; | |
+ } | |
+}; | |
+ | |
+enum NpcSpectatorAtions { | |
+ // will be used for scrolling | |
+ NPC_SPECTATOR_ACTION_2V2_GAMES = 1000, | |
+ NPC_SPECTATOR_ACTION_3V3_GAMES = 2000, | |
+ NPC_SPECTATOR_ACTION_SPECIFIC = 500, | |
+ | |
+ // NPC_SPECTATOR_ACTION_SELECTED_PLAYER + player.Guid() | |
+ NPC_SPECTATOR_ACTION_SELECTED_PLAYER = 3000 | |
+}; | |
+ | |
+const uint8 GamesOnPage = 15; | |
+ | |
+class npc_arena_spectator : public CreatureScript | |
+{ | |
+public: | |
+ npc_arena_spectator() : CreatureScript("npc_arena_spectator") { } | |
+ | |
+ bool OnGossipHello(Player* pPlayer, Creature* pCreature) | |
+ { | |
+ pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "|TInterface\\icons\\Achievement_Arena_2v2_7:35:35:-30:0|tGames: 2v2", GOSSIP_SENDER_MAIN, NPC_SPECTATOR_ACTION_2V2_GAMES); | |
+ pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "|TInterface\\icons\\Achievement_Arena_3v3_7:35:35:-30:0|tGames: 3v3", GOSSIP_SENDER_MAIN, NPC_SPECTATOR_ACTION_3V3_GAMES); | |
+ pPlayer->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_CHAT, "|TInterface\\icons\\Spell_Holy_DevineAegis:35:35:-30:0|tSpectate Specific Player.", GOSSIP_SENDER_MAIN, NPC_SPECTATOR_ACTION_SPECIFIC, "", 0, true); | |
+ pPlayer->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, pCreature->GetGUID()); | |
+ return true; | |
+ } | |
+ | |
+ bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) | |
+ { | |
+ player->PlayerTalkClass->ClearMenus(); | |
+ if (action == NPC_SPECTATOR_ACTION_SPECIFIC) | |
+ { | |
+ | |
+ } | |
+ if (action >= NPC_SPECTATOR_ACTION_2V2_GAMES && action < NPC_SPECTATOR_ACTION_3V3_GAMES) | |
+ { | |
+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_DOT, "Refresh", GOSSIP_SENDER_MAIN, NPC_SPECTATOR_ACTION_2V2_GAMES); | |
+ ShowPage(player, action - NPC_SPECTATOR_ACTION_2V2_GAMES, false); | |
+ player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID()); | |
+ } | |
+ else if (action >= NPC_SPECTATOR_ACTION_3V3_GAMES && action < NPC_SPECTATOR_ACTION_3V3_GAMES) | |
+ { | |
+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_DOT, "Refresh", GOSSIP_SENDER_MAIN, NPC_SPECTATOR_ACTION_3V3_GAMES); | |
+ ShowPage(player, action - NPC_SPECTATOR_ACTION_3V3_GAMES, true); | |
+ player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID()); | |
+ } | |
+ else | |
+ { | |
+ | |
+ uint64 guid = action - NPC_SPECTATOR_ACTION_SELECTED_PLAYER; | |
+ if (Player* target = ObjectAccessor::FindPlayer(guid)) | |
+ { | |
+ ChatHandler handler(player->GetSession()); | |
+ char const* pTarget = target->GetName().c_str(); | |
+ arena_spectator_commands::HandleSpectateCommand(&handler, pTarget); | |
+ } | |
+ } | |
+ return true; | |
+ } | |
+ | |
+ std::string GetClassNameById(uint8 id) | |
+ { | |
+ std::string sClass = ""; | |
+ switch (id) | |
+ { | |
+ case CLASS_WARRIOR: sClass = "Warrior "; break; | |
+ case CLASS_PALADIN: sClass = "Paladin "; break; | |
+ case CLASS_HUNTER: sClass = "Hunter "; break; | |
+ case CLASS_ROGUE: sClass = "Rogue "; break; | |
+ case CLASS_PRIEST: sClass = "Priest "; break; | |
+ case CLASS_DEATH_KNIGHT: sClass = "DKnight "; break; | |
+ case CLASS_SHAMAN: sClass = "Shaman "; break; | |
+ case CLASS_MAGE: sClass = "Mage "; break; | |
+ case CLASS_WARLOCK: sClass = "Warlock "; break; | |
+ case CLASS_DRUID: sClass = "Druid "; break; | |
+ } | |
+ return sClass; | |
+ } | |
+ | |
+ std::string GetGamesStringData(Battleground* team, uint16 mmr, uint16 mmrTwo) | |
+ { | |
+ std::string teamsMember[BG_TEAMS_COUNT]; | |
+ uint32 firstTeamId = 0; | |
+ for (Battleground::BattlegroundPlayerMap::const_iterator itr = team->GetPlayers().begin(); itr != team->GetPlayers().end(); ++itr) | |
+ if (Player* player = ObjectAccessor::FindPlayer(itr->first)) | |
+ { | |
+ if (player->IsSpectator()) | |
+ continue; | |
+ | |
+ if (player->IsGameMaster()) | |
+ continue; | |
+ | |
+ uint32 team = itr->second.Team; | |
+ if (!firstTeamId) | |
+ firstTeamId = team; | |
+ | |
+ teamsMember[firstTeamId == team] += GetClassNameById(player->getClass()); | |
+ } | |
+ | |
+ std::string data = teamsMember[0] + "("; | |
+ std::stringstream sstwo; | |
+ std::stringstream ss; | |
+ ss << mmr; | |
+ sstwo << mmrTwo; | |
+ data += ss.str(); | |
+ data += ") - "; | |
+ data += teamsMember[1] + "(" + sstwo.str(); | |
+ data += ")"; | |
+ return data; | |
+ } | |
+ | |
+ uint64 GetFirstPlayerGuid(Battleground* team) | |
+ { | |
+ for (Battleground::BattlegroundPlayerMap::const_iterator itr = team->GetPlayers().begin(); itr != team->GetPlayers().end(); ++itr) | |
+ if (Player* player = ObjectAccessor::FindPlayer(itr->first)) | |
+ return itr->first; | |
+ return 0; | |
+ } | |
+ | |
+ void ShowPage(Player* player, uint16 page, bool IsTop) | |
+ { | |
+ uint32 firstTeamId = 0; | |
+ uint16 TypeTwo = 0; | |
+ uint16 TypeThree = 0; | |
+ uint16 mmr = 0; | |
+ uint16 mmrTwo = 0; | |
+ bool haveNextPage = false; | |
+ for (uint8 i = 0; i <= MAX_BATTLEGROUND_TYPE_ID; ++i) | |
+ { | |
+ if (!sBattlegroundMgr->IsArenaType(BattlegroundTypeId(i))) | |
+ continue; | |
+ | |
+ BattlegroundData* arenas = sBattlegroundMgr->GetAllBattlegroundsWithTypeId(BattlegroundTypeId(i)); | |
+ | |
+ if (!arenas || arenas->m_Battlegrounds.empty()) | |
+ continue; | |
+ | |
+ for (BattlegroundContainer::const_iterator itr = arenas->m_Battlegrounds.begin(); itr != arenas->m_Battlegrounds.end(); ++itr) | |
+ { | |
+ Battleground* arena = itr->second; | |
+ Player* target = ObjectAccessor::FindPlayer(GetFirstPlayerGuid(arena)); | |
+ if (!target) | |
+ continue; | |
+ | |
+ if (target->HasAura(32728) || target->HasAura(32727)) | |
+ continue; | |
+ | |
+ if (!arena->GetPlayersSize()) | |
+ continue; | |
+ | |
+ if (!arena->isRated()) | |
+ continue; | |
+ | |
+ if (arena->GetArenaType() == ARENA_TYPE_2v2) | |
+ { | |
+ mmr = arena->GetArenaMatchmakerRatingByIndex(0); | |
+ firstTeamId = target->GetArenaTeamId(0); | |
+ Battleground::BattlegroundPlayerMap::const_iterator citr = arena->GetPlayers().begin(); | |
+ for (; citr != arena->GetPlayers().end(); ++citr) | |
+ if (Player* plrs = sObjectAccessor->FindPlayer(citr->first)) | |
+ if (plrs->GetArenaTeamId(0) != firstTeamId) | |
+ mmrTwo = arena->GetArenaMatchmakerRating(citr->second.Team); | |
+ } | |
+ else | |
+ { | |
+ mmr = arena->GetArenaMatchmakerRatingByIndex(1); | |
+ firstTeamId = target->GetArenaTeamId(1); | |
+ Battleground::BattlegroundPlayerMap::const_iterator citr = arena->GetPlayers().begin(); | |
+ for (; citr != arena->GetPlayers().end(); ++citr) | |
+ if (Player* plrs = sObjectAccessor->FindPlayer(citr->first)) | |
+ if (plrs->GetArenaTeamId(1) != firstTeamId) | |
+ mmrTwo = arena->GetArenaMatchmakerRating(citr->second.Team); | |
+ } | |
+ | |
+ if (IsTop && arena->GetArenaType() == ARENA_TYPE_3v3) | |
+ { | |
+ TypeThree++; | |
+ if (TypeThree > (page + 1) * GamesOnPage) | |
+ { | |
+ haveNextPage = true; | |
+ break; | |
+ } | |
+ | |
+ if (TypeThree >= page * GamesOnPage) | |
+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_BATTLE, GetGamesStringData(arena, mmr, mmrTwo), GOSSIP_SENDER_MAIN, NPC_SPECTATOR_ACTION_SELECTED_PLAYER + GetFirstPlayerGuid(arena)); | |
+ } | |
+ else if (!IsTop && arena->GetArenaType() == ARENA_TYPE_2v2) | |
+ { | |
+ TypeTwo++; | |
+ if (TypeTwo > (page + 1) * GamesOnPage) | |
+ { | |
+ haveNextPage = true; | |
+ break; | |
+ } | |
+ | |
+ if (TypeTwo >= page * GamesOnPage) | |
+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_BATTLE, GetGamesStringData(arena, mmr, mmrTwo), GOSSIP_SENDER_MAIN, NPC_SPECTATOR_ACTION_SELECTED_PLAYER + GetFirstPlayerGuid(arena)); | |
+ } | |
+ } | |
+ } | |
+ | |
+ if (page > 0) | |
+ { | |
+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_DOT, "Prev..", GOSSIP_SENDER_MAIN, NPC_SPECTATOR_ACTION_2V2_GAMES + page - 1); | |
+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_DOT, "Prev..", GOSSIP_SENDER_MAIN, NPC_SPECTATOR_ACTION_3V3_GAMES + page - 1); | |
+ } | |
+ | |
+ if (haveNextPage) | |
+ { | |
+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_DOT, "Next..", GOSSIP_SENDER_MAIN, NPC_SPECTATOR_ACTION_2V2_GAMES + page + 1); | |
+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_DOT, "Next..", GOSSIP_SENDER_MAIN, NPC_SPECTATOR_ACTION_3V3_GAMES + page + 1); | |
+ } | |
+ } | |
+ | |
+ bool OnGossipSelectCode(Player* player, Creature* creature, uint32 sender, uint32 action, const char* code) | |
+ { | |
+ if (!player) | |
+ return true; | |
+ | |
+ player->PlayerTalkClass->ClearMenus(); | |
+ player->CLOSE_GOSSIP_MENU(); | |
+ if (sender == GOSSIP_SENDER_MAIN) | |
+ { | |
+ switch (action) | |
+ { | |
+ case NPC_SPECTATOR_ACTION_SPECIFIC: // choosing a player | |
+ | |
+ const char* plrName = code; | |
+ | |
+ char playerName[50]; | |
+ strcpy(playerName, plrName); | |
+ | |
+ for (int i = 0; i < 13; i++) | |
+ { | |
+ if (playerName[i] == NULL) | |
+ break; | |
+ if (i == 0 && playerName[i] > 96) | |
+ playerName[0] -= 32; | |
+ else if (playerName[i] < 97) | |
+ playerName[i] += 32; | |
+ } | |
+ | |
+ if (Player* target = sObjectAccessor->FindPlayerByName(playerName)) | |
+ { | |
+ ChatHandler handler(player->GetSession()); | |
+ char const* pTarget = target->GetName().c_str(); | |
+ arena_spectator_commands::HandleSpectateCommand(&handler, pTarget); | |
+ } | |
+ ChatHandler(player->GetSession()).PSendSysMessage("Player is not online or does not exist."); | |
+ return true; | |
+ } | |
+ } | |
+ | |
+ return false; | |
+ } | |
+}; | |
+ | |
+ | |
+ | |
+void AddSC_arena_spectator_script() | |
+{ | |
+ new arena_spectator_commands(); | |
+ new npc_arena_spectator(); | |
+} | |
\ No newline at end of file | |
-- | |
1.8.3.msysgit.0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment