Last active
August 29, 2015 14:17
-
-
Save FALL1N1/29c64c1330a9154cb598 to your computer and use it in GitHub Desktop.
Arena Spectator (all revisions) \\ // All you need to do is to put the both files in the CMakeLists.txt and ScriptLoader.cpp
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 8f0b67ad3fda93e0cb7c2d29a3b4eaa405146aca Mon Sep 17 00:00:00 2001 | |
From: Emiliyan Kurtseliyanski <[email protected]> | |
Date: Fri, 13 Mar 2015 17:50:38 +0200 | |
Subject: [PATCH] Properly implement the Arena Spectator | |
--- | |
sql/custom/spectator.sql | 13 + | |
src/server/game/Accounts/RBAC.h | 6 + | |
src/server/game/Battlegrounds/Battleground.cpp | 24 +- | |
src/server/game/Battlegrounds/Battleground.h | 10 + | |
src/server/game/Battlegrounds/BattlegroundMgr.h | 12 +- | |
src/server/game/Battlegrounds/SpectatorAddon.cpp | 0 | |
src/server/game/Battlegrounds/SpectatorAddon.h | 0 | |
src/server/game/Entities/GameObject/GameObject.cpp | 10 + | |
src/server/game/Entities/Player/Player.cpp | 127 ++++- | |
src/server/game/Entities/Player/Player.h | 15 +- | |
src/server/game/Entities/Unit/Unit.cpp | 14 + | |
src/server/game/Handlers/ChatHandler.cpp | 6 + | |
src/server/game/Maps/Map.cpp | 7 + | |
src/server/game/Miscellaneous/Language.h | 3 + | |
src/server/game/Spells/Spell.cpp | 4 + | |
src/server/scripts/Commands/cs_gm.cpp | 2 + | |
src/server/scripts/Custom/arena_spectator.cpp | 611 +++++++++++++++++++++ | |
17 files changed, 848 insertions(+), 16 deletions(-) | |
create mode 100644 sql/custom/spectator.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/arena_spectator.cpp | |
diff --git a/sql/custom/spectator.sql b/sql/custom/spectator.sql | |
new file mode 100644 | |
index 0000000..f917883 | |
--- /dev/null | |
+++ b/sql/custom/spectator.sql | |
@@ -0,0 +1,13 @@ | |
+insert into `rbac_permissions` (`id`, `name`) values | |
+('1000', 'spectate'), | |
+('1001', 'spectate player'), | |
+('1002', 'spectate view'), | |
+('1003', 'spectate reset'), | |
+('1004', 'spectate leave'); | |
+ | |
+insert into `rbac_linked_permissions` (`id`, `linkedId`) values | |
+('195','1000'), | |
+('195','1001'), | |
+('195','1002'), | |
+('195','1003'), | |
+('195','1004'); | |
\ No newline at end of file | |
diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h | |
index d63ba84..51cdfbd 100644 | |
--- a/src/server/game/Accounts/RBAC.h | |
+++ b/src/server/game/Accounts/RBAC.h | |
@@ -696,6 +696,12 @@ enum RBACPermissions | |
RBAC_PERM_COMMAND_MODIFY_XP = 798, | |
// 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 f428c73..28531ed 100644 | |
--- a/src/server/game/Battlegrounds/Battleground.cpp | |
+++ b/src/server/game/Battlegrounds/Battleground.cpp | |
@@ -33,6 +33,7 @@ | |
#include "ReputationMgr.h" | |
#include "SpellAuraEffects.h" | |
#include "SpellAuras.h" | |
+#include "SpectatorAddon.h" | |
#include "Util.h" | |
#include "WorldPacket.h" | |
#include "Transport.h" | |
@@ -1134,13 +1135,22 @@ 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()); | |
} | |
} | |
diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h | |
index deba7aa..a952ec4 100644 | |
--- a/src/server/game/Battlegrounds/Battleground.h | |
+++ b/src/server/game/Battlegrounds/Battleground.h | |
@@ -26,6 +26,7 @@ | |
#include "WorldPacket.h" | |
#include "Object.h" | |
#include "GameObject.h" | |
+#include "SpectatorAddon.h" | |
class Creature; | |
class GameObject; | |
@@ -301,6 +302,13 @@ class Battleground | |
bool HasFreeSlots() const; | |
uint32 GetFreeSlotsForTeam(uint32 Team) const; | |
+ /* SPECTATOR */ | |
+ 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); } | |
+ /* SPECTATOR */ | |
+ | |
bool isArena() const { return m_IsArena; } | |
bool isBattleground() const { return !m_IsArena; } | |
bool isRated() const { return m_IsRated; } | |
@@ -581,6 +589,8 @@ class Battleground | |
// Raid Group | |
Group* m_BgRaids[BG_TEAMS_COUNT]; // 0 - alliance, 1 - horde | |
+ | |
+ SpectatorList m_Spectators; // Spectator | |
// 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 3b245ca..e84d352 100644 | |
--- a/src/server/game/Battlegrounds/BattlegroundMgr.h | |
+++ b/src/server/game/Battlegrounds/BattlegroundMgr.h | |
@@ -85,6 +85,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); | |
@@ -109,6 +110,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); | |
@@ -117,6 +119,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; | |
@@ -134,12 +144,12 @@ class BattlegroundMgr | |
private: | |
bool CreateBattleground(BattlegroundTemplate const* bgTemplate); | |
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]; | |
std::vector<uint64> m_QueueUpdateScheduler; | |
diff --git a/src/server/game/Battlegrounds/SpectatorAddon.cpp b/src/server/game/Battlegrounds/SpectatorAddon.cpp | |
new file mode 100644 | |
index 0000000..e69de29 | |
diff --git a/src/server/game/Battlegrounds/SpectatorAddon.h b/src/server/game/Battlegrounds/SpectatorAddon.h | |
new file mode 100644 | |
index 0000000..e69de29 | |
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp | |
index d77aab7..2d97fd8 100644 | |
--- a/src/server/game/Entities/GameObject/GameObject.cpp | |
+++ b/src/server/game/Entities/GameObject/GameObject.cpp | |
@@ -551,6 +551,11 @@ void GameObject::Update(uint32 diff) | |
} | |
else if (Unit* target = ObjectAccessor::GetUnit(*this, m_lootStateUnitGUID)) | |
{ | |
+ // If player is spectator do not activate. | |
+ if (Player *tmpPlayer = target->ToPlayer()) | |
+ if (tmpPlayer->IsSpectator()) | |
+ return; | |
+ | |
// Some traps do not have a spell but should be triggered | |
if (goInfo->trap.spellId) | |
CastSpell(target, goInfo->trap.spellId); | |
@@ -1752,6 +1757,11 @@ void GameObject::Use(Unit* user) | |
void GameObject::CastSpell(Unit* target, uint32 spellId, bool triggered /*= true*/) | |
{ | |
+ 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 b285d8d..70b8516 100644 | |
--- a/src/server/game/Entities/Player/Player.cpp | |
+++ b/src/server/game/Entities/Player/Player.cpp | |
@@ -69,6 +69,7 @@ | |
#include "SpellAuraEffects.h" | |
#include "SpellAuras.h" | |
#include "SpellMgr.h" | |
+#include "SpectatorAddon.h" | |
#include "Transport.h" | |
#include "UpdateData.h" | |
#include "UpdateFieldFlags.h" | |
@@ -907,7 +908,9 @@ Player::Player(WorldSession* session): Unit(true) | |
m_MonthlyQuestChanged = false; | |
m_SeasonalQuestChanged = false; | |
- | |
+ spectatorFlag = false; | |
+ spectateCanceled = false; | |
+ spectateFrom = NULL; | |
SetPendingBind(0, 0); | |
_activeCheats = CHEAT_NONE; | |
@@ -1906,7 +1909,6 @@ void Player::setDeathState(DeathState s) | |
TC_LOG_ERROR("entities.player", "setDeathState: attempt to kill a dead player %s(%d)", GetName().c_str(), GetGUIDLow()); | |
return; | |
} | |
- | |
// drunken state is cleared on death | |
SetDrunkValue(0); | |
// lost combo points at any target (targeted combo points clear in Unit::setDeathState) | |
@@ -1951,6 +1953,12 @@ void Player::InnEnter(time_t time, uint32 mapid, float x, float y, float z) | |
time_inn_enter = time; | |
} | |
+void Player::SetSelection(ObjectGuid guid) | |
+{ | |
+ uint32 m_curSelection = guid; | |
+ SetUInt64Value(UNIT_FIELD_TARGET, guid); | |
+} | |
+ | |
bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data) | |
{ | |
// 0 1 2 3 4 5 6 7 | |
@@ -2380,7 +2388,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() | |
@@ -2829,6 +2847,85 @@ 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(); | |
+ | |
+ 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::SetGameMaster(bool on) | |
{ | |
if (on) | |
@@ -24558,6 +24655,16 @@ 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 (!AddGuidValue(PLAYER_FARSIGHT, target->GetGUID())) | |
@@ -24570,10 +24677,18 @@ void Player::SetViewpoint(WorldObject* target, bool apply) | |
UpdateVisibilityOf(target); | |
if (target->isType(TYPEMASK_UNIT) && !GetVehicle()) | |
+ { | |
+ 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 (!RemoveGuidValue(PLAYER_FARSIGHT, target->GetGUID())) | |
@@ -24584,10 +24699,12 @@ void Player::SetViewpoint(WorldObject* target, bool apply) | |
if (target->isType(TYPEMASK_UNIT) && !GetVehicle()) | |
((Unit*)target)->RemovePlayerFromVision(this); | |
- | |
//must immediately set seer back otherwise may crash | |
m_seer = this; | |
- | |
+ | |
+ if (IsSpectator()) | |
+ spectateFrom = NULL; | |
+ | |
//WorldPacket data(SMSG_CLEAR_FAR_SIGHT_IMMEDIATE, 0); | |
//GetSession()->SendPacket(&data); | |
} | |
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h | |
index 2b9211e..8de7d6d 100644 | |
--- a/src/server/game/Entities/Player/Player.h | |
+++ b/src/server/game/Entities/Player/Player.h | |
@@ -28,6 +28,7 @@ | |
#include "QuestDef.h" | |
#include "SpellMgr.h" | |
#include "Unit.h" | |
+#include "Battleground.h" | |
#include <limits> | |
#include <string> | |
@@ -1176,7 +1177,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) != 0; } | |
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) != 0; } | |
+ bool IsGameMaster() const { return (m_ExtraFlags & PLAYER_EXTRA_GM_ON); } | |
void SetGameMaster(bool on); | |
bool isGMChat() const { return (m_ExtraFlags & PLAYER_EXTRA_GM_CHAT) != 0; } | |
void SetGMChat(bool on) { if (on) m_ExtraFlags |= PLAYER_EXTRA_GM_CHAT; else m_ExtraFlags &= ~PLAYER_EXTRA_GM_CHAT; } | |
@@ -1187,6 +1188,12 @@ class Player : public Unit, public GridObject<Player> | |
bool Has310Flyer(bool checkAllSpells, uint32 excludeSpellId = 0); | |
void SetHas310Flyer(bool on) { if (on) m_ExtraFlags |= PLAYER_EXTRA_HAS_310_FLYER; else m_ExtraFlags &= ~PLAYER_EXTRA_HAS_310_FLYER; } | |
void SetPvPDeath(bool on) { if (on) m_ExtraFlags |= PLAYER_EXTRA_PVP_DEATH; else m_ExtraFlags &= ~PLAYER_EXTRA_PVP_DEATH; } | |
+ bool HaveSpectators(); | |
+ 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); | |
@@ -1561,7 +1568,7 @@ class Player : public Unit, public GridObject<Player> | |
Player* GetSelectedPlayer() const; | |
void SetTarget(ObjectGuid /*guid*/) override { } /// Used for serverside target changes, does not apply to players | |
- void SetSelection(ObjectGuid guid) { SetGuidValue(UNIT_FIELD_TARGET, guid); } | |
+ void SetSelection(ObjectGuid guid); | |
uint8 GetComboPoints() const { return m_comboPoints; } | |
ObjectGuid GetComboTarget() const { return m_comboTarget; } | |
@@ -2693,7 +2700,9 @@ class Player : public Unit, public GridObject<Player> | |
InstanceTimeMap _instanceResetTimes; | |
uint32 _pendingBindId; | |
uint32 _pendingBindTimer; | |
- | |
+ bool spectatorFlag; | |
+ bool spectateCanceled; | |
+ Unit *spectateFrom; | |
uint32 _activeCheats; | |
}; | |
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp | |
index f47cc79..47f2a13 100644 | |
--- a/src/server/game/Entities/Unit/Unit.cpp | |
+++ b/src/server/game/Entities/Unit/Unit.cpp | |
@@ -54,6 +54,7 @@ | |
#include "Spell.h" | |
#include "SpellInfo.h" | |
#include "SpellMgr.h" | |
+#include "SpectatorAddon.h" | |
#include "TemporarySummon.h" | |
#include "Totem.h" | |
#include "Transport.h" | |
@@ -288,6 +289,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; | |
diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp | |
index 288bb82..b50accb 100644 | |
--- a/src/server/game/Handlers/ChatHandler.cpp | |
+++ b/src/server/game/Handlers/ChatHandler.cpp | |
@@ -553,6 +553,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 7f350df..58a8349 100644 | |
--- a/src/server/game/Maps/Map.cpp | |
+++ b/src/server/game/Maps/Map.cpp | |
@@ -3253,6 +3253,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 52254eb..517998f 100644 | |
--- a/src/server/game/Miscellaneous/Language.h | |
+++ b/src/server/game/Miscellaneous/Language.h | |
@@ -853,6 +853,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/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp | |
index e8e1bbd..f2b8d56 100644 | |
--- a/src/server/game/Spells/Spell.cpp | |
+++ b/src/server/game/Spells/Spell.cpp | |
@@ -4684,6 +4684,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 ee2bb89..58e3254 100644 | |
--- a/src/server/scripts/Commands/cs_gm.cpp | |
+++ b/src/server/scripts/Commands/cs_gm.cpp | |
@@ -133,6 +133,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/arena_spectator.cpp b/src/server/scripts/Custom/arena_spectator.cpp | |
new file mode 100644 | |
index 0000000..5c028c9 | |
--- /dev/null | |
+++ b/src/server/scripts/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) | |
+ { | |
+ 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) | |
+ { | |
+ 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