Skip to content

Instantly share code, notes, and snippets.

@walkline
Created December 24, 2011 12:07
Show Gist options
  • Save walkline/1517219 to your computer and use it in GitHub Desktop.
Save walkline/1517219 to your computer and use it in GitHub Desktop.
diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp
index 4ad00f5..5356680 100755
--- a/src/server/game/Battlegrounds/Battleground.cpp
+++ b/src/server/game/Battlegrounds/Battleground.cpp
@@ -1237,16 +1237,19 @@ 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));
+ 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()));
+ // 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()));
+ }
}
-
- player->LeaveBattleground();
+ if (!player->isSpectator())
+ player->LeaveBattleground();
}
// This method should be called only once ... it adds pointer to queue
diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp
index 185ac48..70b2885 100755
--- a/src/server/game/Chat/Chat.cpp
+++ b/src/server/game/Chat/Chat.cpp
@@ -355,6 +355,9 @@ ChatCommand* ChatHandler::getCommandTable()
{ "notify", SEC_MODERATOR, true, OldHandler<&ChatHandler::HandleNotifyCommand>, "", NULL },
{ "gmnotify", SEC_MODERATOR, true, OldHandler<&ChatHandler::HandleGMNotifyCommand>, "", NULL },
{ "appear", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleAppearCommand>, "", NULL },
+ { "spectate", SEC_PLAYER, false, OldHandler<&ChatHandler::HandleSpectateCommand>, "", NULL },
+ { "spectatecancel", SEC_PLAYER, false, OldHandler<&ChatHandler::HandleSpectateCancelCommand>, "", NULL },
+ { "spectatefrom", SEC_PLAYER, false, OldHandler<&ChatHandler::HandleSpectateFromCommand>, "", NULL },
{ "summon", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleSummonCommand>, "", NULL },
{ "groupsummon", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGroupSummonCommand>, "", NULL },
{ "commands", SEC_PLAYER, true, OldHandler<&ChatHandler::HandleCommandsCommand>, "", NULL },
diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h
index 24652fc..a744d7a 100755
--- a/src/server/game/Chat/Chat.h
+++ b/src/server/game/Chat/Chat.h
@@ -255,6 +255,9 @@ class ChatHandler
bool HandleSummonCommand(const char* args);
bool HandleAppearCommand(const char* args);
+ bool HandleSpectateCommand(const char* args);
+ bool HandleSpectateCancelCommand(const char* args);
+ bool HandleSpectateFromCommand(const char* args);
bool HandleGroupSummonCommand(const char* args);
bool HandleRecallCommand(const char* args);
bool HandleAnnounceCommand(const char* args);
diff --git a/src/server/game/Chat/Commands/Level0.cpp b/src/server/game/Chat/Commands/Level0.cpp
index 97173f7..3449d9e 100755
--- a/src/server/game/Chat/Commands/Level0.cpp
+++ b/src/server/game/Chat/Commands/Level0.cpp
@@ -157,3 +157,163 @@ bool ChatHandler::HandleServerMotdCommand(const char* /*args*/)
return true;
}
+bool ChatHandler::HandleSpectateCommand(const char *args)
+{
+ Player* target;
+ uint64 target_guid;
+ std::string target_name;
+ if (!extractPlayerTarget((char*)args, &target, &target_guid, &target_name))
+ return false;
+
+ Player* _player = m_session->GetPlayer();
+ if (target == _player || target_guid == _player->GetGUID())
+ {
+ SendSysMessage(LANG_CANT_TELEPORT_SELF);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ // check online security
+ if (HasLowerSecurity(target, 0))
+ return false;
+
+ std::string chrNameLink = playerLink(target_name);
+
+ if (_player->isInCombat())
+ {
+ SendSysMessage(LANG_YOU_IN_COMBAT);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if (!target)
+ {
+ SendSysMessage(LANG_PLAYER_NOT_EXIST_OR_OFFLINE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if (_player->GetMap()->IsBattlegroundOrArena() && !_player->isSpectator())
+ {
+ PSendSysMessage("You are already on battleground or arena.");
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ Map* cMap = target->GetMap();
+ if (!cMap->IsBattlegroundOrArena())
+ {
+ PSendSysMessage("Player didnt found in arena.");
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if (_player->GetMap()->IsBattleground())
+ {
+ PSendSysMessage("Cant do that while you are on battleground.");
+ 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();
+
+ if (target->isSpectator())
+ {
+ PSendSysMessage("Can`t do that. Your target is spectator.");
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ PSendSysMessage(LANG_APPEARING_AT, chrNameLink.c_str());
+
+ // stop flight if need
+ if (_player->isInFlight())
+ {
+ _player->GetMotionMaster()->MovementExpired();
+ _player->CleanupAfterTaxiFlight();
+ }
+ // save only in non-flight case
+ else
+ _player->SaveRecallPosition();
+
+ // to point to see at target with same orientation
+ float x, y, z;
+ target->GetContactPoint(_player, x, y, z);
+
+ _player->SetSpectate(true);
+ _player->TeleportTo(target->GetMapId(), x, y, z, _player->GetAngle(target), TELE_TO_GM_MODE);
+ _player->SetPhaseMask(target->GetPhaseMask(), true);
+
+ return true;
+}
+
+bool ChatHandler::HandleSpectateCancelCommand(const char */*args*/)
+{
+ Player* _player = m_session->GetPlayer();
+
+ if (!_player->isSpectator())
+ {
+ PSendSysMessage("You are not spectator.");
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ _player->CancelSpectate();
+ _player->TeleportToBGEntryPoint();
+
+ return true;
+}
+
+bool ChatHandler::HandleSpectateFromCommand(const char *args)
+{
+ Player* target;
+ uint64 target_guid;
+ std::string target_name;
+ if (!extractPlayerTarget((char*)args, &target, &target_guid, &target_name))
+ return false;
+
+ Player* _player = m_session->GetPlayer();
+
+ // check online security
+ if (HasLowerSecurity(target, 0))
+ return false;
+
+ if (!_player->isSpectator())
+ {
+ PSendSysMessage("You are not spectator, spectate someone first.");
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if (target->isSpectator() && target != _player)
+ {
+ PSendSysMessage("Can`t do that. Your target is spectator.");
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if (_player->GetMap() != target->GetMap())
+ {
+ PSendSysMessage("Cant do that. Different arenas?");
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ //check for arena preperation
+ //if exists than battle didn`t begin
+ if (target->HasAura(32728) || target->HasAura(32727))
+ {
+ PSendSysMessage("Cant do that. Arena didn`t started.");
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ (target == _player) ? _player->SetViewpoint(_player->getSpectateFrom(), false) :
+ _player->SetViewpoint(target, true);
+ return true;
+}
+
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index de1b0f8..6dcb89a 100755
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -443,6 +443,9 @@ 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);
@@ -1016,6 +1019,10 @@ void GameObject::SwitchDoorOrButton(bool activate, bool alternative /* = false *
void GameObject::Use(Unit* user)
{
+ if (Player *tmpPlayer = user->ToPlayer())
+ if (tmpPlayer->isSpectator())
+ return;
+
// by default spell caster is user
Unit* spellCaster = user;
uint32 spellId = 0;
@@ -1590,6 +1597,10 @@ void GameObject::Use(Unit* user)
void GameObject::CastSpell(Unit* target, uint32 spellId)
{
+ 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 b59c8c0..9d736bb 100755
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -852,6 +852,10 @@ Player::Player (WorldSession* session): Unit(), m_achievementMgr(this), m_reputa
isDebugAreaTriggers = false;
+ spectatorFlag = false;
+ spectateCanceled = false;
+ spectateFrom = NULL;
+
SetPendingBind(0, 0);
}
@@ -2308,7 +2312,12 @@ bool Player::TeleportToBGEntryPoint()
ScheduleDelayedOperation(DELAYED_BG_MOUNT_RESTORE);
ScheduleDelayedOperation(DELAYED_BG_TAXI_RESTORE);
ScheduleDelayedOperation(DELAYED_BG_GROUP_RESTORE);
- return TeleportTo(m_bgData.joinPos);
+ bool result = TeleportTo(m_bgData.joinPos);
+
+ if (isSpectator() && result)
+ SetSpectate(false);
+
+ return result;
}
void Player::ProcessDelayedOperations()
@@ -2715,6 +2724,7 @@ Creature* Player::GetNPCIfCanInteractWith(uint64 guid, uint32 npcflagmask)
GameObject* Player::GetGameObjectIfCanInteractWith(uint64 guid, GameobjectTypes type) const
{
+ sLog->outString("GetGameObjectIfCanInteractWith");
if (GameObject* go = GetMap()->GetGameObject(guid))
{
if (go->GetGoType() == type)
@@ -2851,6 +2861,78 @@ void Player::SetGMVisible(bool on)
}
}
+void Player::SetSpectate(bool on)
+{
+ if (on)
+ {
+ //add aspectof the cheetah
+ AddAura(5118, this);
+ spectatorFlag = true;
+
+ m_ExtraFlags |= PLAYER_EXTRA_GM_ON;
+ setFaction(35);
+
+ if (Pet* pet = GetPet())
+ {
+ pet->setFaction(35);
+ pet->getHostileRefManager().setOnlineOfflineState(false);
+ 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 (Pet* pet = GetPet())
+ {
+ pet->setFaction(getFaction());
+ pet->getHostileRefManager().setOnlineOfflineState(true);
+ }
+
+ 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;
+ RemoveAura(5118);
+ }
+ UpdateObjectVisibility();
+}
+
bool Player::IsGroupVisibleFor(Player const* p) const
{
switch (sWorld->getIntConfig(CONFIG_GROUP_VISIBILITY))
@@ -22817,9 +22899,19 @@ void Player::StopCastingBindSight()
}
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;
+ }
+
sLog->outDebug(LOG_FILTER_MAPS, "Player::CreateViewpoint: Player %s create seer %u (TypeId: %u).", GetName(), target->GetEntry(), target->GetTypeId());
if (!AddUInt64Value(PLAYER_FARSIGHT, target->GetGUID()))
@@ -22832,7 +22924,12 @@ 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
{
@@ -22847,6 +22944,9 @@ 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 8ee7d1a..e5bd4a9 100755
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1157,6 +1157,11 @@ class Player : public Unit, public GridObject<Player>
void SetTaxiCheater(bool on) { if (on) m_ExtraFlags |= PLAYER_EXTRA_TAXICHEAT; else m_ExtraFlags &= ~PLAYER_EXTRA_TAXICHEAT; }
bool isGMVisible() const { return !(m_ExtraFlags & PLAYER_EXTRA_GM_INVISIBLE); }
void SetGMVisible(bool on);
+ bool isSpectateCanceled() { return spectateCanceled; }
+ bool CancelSpectate() { spectateCanceled = true; }
+ Unit* getSpectateFrom() { return spectateFrom; }
+ bool isSpectator() const { return spectatorFlag; }
+ void SetSpectate(bool on);
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; }
@@ -2854,6 +2859,11 @@ class Player : public Unit, public GridObject<Player>
InstanceTimeMap _instanceResetTimes;
uint32 _pendingBindId;
uint32 _pendingBindTimer;
+
+ //flag for spectator system
+ bool spectatorFlag;
+ bool spectateCanceled;
+ Unit *spectateFrom;
};
void AddItemsSetItem(Player*player, Item* item);
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 5a7645b..1ca2de8 100755
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -3988,6 +3988,11 @@ void Unit::RemoveArenaAuras()
{
AuraApplication const* aurApp = iter->second;
Aura const* aura = aurApp->GetBase();
+ //allow aspect for spectator
+ if (Player *tmpPlayer = ToPlayer() )
+ if (tmpPlayer->isSpectator() && aura->GetId() == 5118)
+ ++iter;
+
if (!(aura->GetSpellInfo()->AttributesEx4 & SPELL_ATTR4_UNK21) // don't remove stances, shadowform, pally/hunter auras
&& !aura->IsPassive() // don't remove passive auras
&& (aurApp->IsPositive() || !(aura->GetSpellInfo()->AttributesEx3 & SPELL_ATTR3_DEATH_PERSISTENT))) // not negative death persistent auras
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index 306af9c..3dcc26e 100755
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -2591,6 +2591,8 @@ bool BattlegroundMap::AddPlayerToMap(Player* player)
void BattlegroundMap::RemovePlayerFromMap(Player* player, bool remove)
{
+ if (player->isSpectator() && !player->isSpectateCanceled())
+ player->SetSpectate(false);
sLog->outDetail("MAP: Removing player '%s' from bg '%u' of map '%s' before relocating to another map", player->GetName(), GetInstanceId(), GetMapName());
Map::RemovePlayerFromMap(player, remove);
}
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index e1c5b90..09fdc3d 100755
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -4604,6 +4604,10 @@ SpellCastResult Spell::CheckCast(bool strict)
return SPELL_FAILED_ONLY_INDOORS;
}
+ if (Player *tmpPlayer = m_caster->ToPlayer())
+ if(tmpPlayer->isSpectator() && m_spellInfo->Id != 5118)
+ 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 ab077af..8ed1173 100644
--- a/src/server/scripts/Commands/cs_gm.cpp
+++ b/src/server/scripts/Commands/cs_gm.cpp
@@ -134,6 +134,8 @@ public:
}
char const* name = itr->second->GetName();
uint8 security = itrSec;
+ if (security == 0)
+ continue;
uint8 max = ((16 - strlen(name)) / 2);
uint8 max2 = max;
if ((max + max2 + strlen(name)) == 16)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment