aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgvcoman <none@none>2008-11-14 20:40:35 -0600
committergvcoman <none@none>2008-11-14 20:40:35 -0600
commit5deef1bb59ba53570d481a97e5c1df39ef316f37 (patch)
tree334e913e1247419d2ad485f1681e859aa8875044
parent3085e66b966fec0012decf2543c7e32064b47102 (diff)
[svn] * Reimplemented packet/update forwarding in more generic way
* Implemented far sight spells (Far Sight, Eagle Eye, etc) at unlimited range and properly forward packets * Implemented bind vision spells (Mind Vision, etc) to forward packets at unlimited distance * Implemented Sentry Totem (both vision switching/forwarding and alerting) * Other misc possession fixes * Added .bindsight and .unbindsight commands Please test out the above spells (including Mind Control) and report any issues on the forums. --HG-- branch : trunk
-rw-r--r--sql/updates/241_world.sql4
-rw-r--r--src/game/Chat.cpp2
-rw-r--r--src/game/Chat.h2
-rw-r--r--src/game/DynamicObject.cpp5
-rw-r--r--src/game/GridDefines.h2
-rw-r--r--src/game/GridNotifiers.cpp54
-rw-r--r--src/game/GridNotifiers.h14
-rw-r--r--src/game/Level3.cpp23
-rw-r--r--src/game/Map.cpp18
-rw-r--r--src/game/MiscHandler.cpp28
-rw-r--r--src/game/ObjectAccessor.cpp32
-rw-r--r--src/game/ObjectAccessor.h1
-rw-r--r--src/game/Player.cpp82
-rw-r--r--src/game/Player.h9
-rw-r--r--src/game/SpellAuras.cpp31
-rw-r--r--src/game/SpellEffects.cpp17
-rw-r--r--src/game/SpellHandler.cpp15
-rw-r--r--src/game/Totem.h2
-rw-r--r--src/game/TotemAI.cpp9
-rw-r--r--src/game/Unit.cpp46
-rw-r--r--src/game/Unit.h7
21 files changed, 329 insertions, 74 deletions
diff --git a/sql/updates/241_world.sql b/sql/updates/241_world.sql
new file mode 100644
index 00000000000..d64c267e211
--- /dev/null
+++ b/sql/updates/241_world.sql
@@ -0,0 +1,4 @@
+DELETE FROM `command` WHERE name IN ('bindsight', 'unbindsight');
+INSERT INTO `command` (name,security,help) VALUES
+('bindsight',3,'Syntax: .bindsight\r\n\r\nBinds vision to the selected unit indefinitely. Cannot be used while currently possessing a target.'),
+('unbindsight',3,'Syntax: .unbindsight\r\n\r\nRemoves bound vision. Cannot be used while currently possessing a target.');
diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp
index 23749d884e0..bff970be3b7 100644
--- a/src/game/Chat.cpp
+++ b/src/game/Chat.cpp
@@ -565,6 +565,8 @@ ChatCommand * ChatHandler::getCommandTable()
{ "flusharenapoints", SEC_ADMINISTRATOR, false, &ChatHandler::HandleFlushArenaPointsCommand, "", NULL },
{ "possess", SEC_ADMINISTRATOR, false, &ChatHandler::HandlePossessCommand, "", NULL },
{ "unpossess", SEC_ADMINISTRATOR, false, &ChatHandler::HandleUnPossessCommand, "", NULL },
+ { "bindsight", SEC_ADMINISTRATOR, false, &ChatHandler::HandleBindSightCommand, "", NULL },
+ { "unbindsight", SEC_ADMINISTRATOR, false, &ChatHandler::HandleUnbindSightCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
diff --git a/src/game/Chat.h b/src/game/Chat.h
index 46635f795a9..0ba253defd9 100644
--- a/src/game/Chat.h
+++ b/src/game/Chat.h
@@ -453,6 +453,8 @@ class ChatHandler
bool HandleDebugHostilRefList(const char * args);
bool HandlePossessCommand(const char* args);
bool HandleUnPossessCommand(const char* args);
+ bool HandleBindSightCommand(const char* args);
+ bool HandleUnbindSightCommand(const char* args);
Player* getSelectedPlayer();
Creature* getSelectedCreature();
diff --git a/src/game/DynamicObject.cpp b/src/game/DynamicObject.cpp
index c1f5212ca05..854d2e82e3e 100644
--- a/src/game/DynamicObject.cpp
+++ b/src/game/DynamicObject.cpp
@@ -136,6 +136,9 @@ void DynamicObject::Update(uint32 p_time)
void DynamicObject::Delete()
{
+ // Make sure the object is back to grid container for removal as farsight targets
+ // are switched to world container on creation
+ GetMap()->SwitchGridContainers(this, false);
SendObjectDeSpawnAnim(GetGUID());
AddObjectToRemoveList();
}
@@ -150,5 +153,5 @@ void DynamicObject::Delay(int32 delaytime)
bool DynamicObject::isVisibleForInState(Player const* u, bool inVisibleList) const
{
- return IsInWorld() && u->IsInWorld() && IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f));
+ return IsInWorld() && u->IsInWorld() /*&& IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f))*/;
}
diff --git a/src/game/GridDefines.h b/src/game/GridDefines.h
index dba47c9644f..2a37ef2b542 100644
--- a/src/game/GridDefines.h
+++ b/src/game/GridDefines.h
@@ -57,7 +57,7 @@ class Player;
#define MAP_HALFSIZE (MAP_SIZE/2)
// Creature used instead pet to simplify *::Visit templates (not required duplicate code for Creature->Pet case)
-typedef TYPELIST_3(Player, Creature/*pets*/, Corpse/*resurrectable*/) AllWorldObjectTypes;
+typedef TYPELIST_4(Player, Creature/*pets*/, Corpse/*resurrectable*/, DynamicObject/*farsight target*/) AllWorldObjectTypes;
typedef TYPELIST_4(GameObject, Creature/*except pets*/, DynamicObject, Corpse/*Bones*/) AllGridObjectTypes;
typedef GridRefManager<Corpse> CorpseMapType;
diff --git a/src/game/GridNotifiers.cpp b/src/game/GridNotifiers.cpp
index 4b1f338f44d..54ee2e67726 100644
--- a/src/game/GridNotifiers.cpp
+++ b/src/game/GridNotifiers.cpp
@@ -40,8 +40,10 @@ Trinity::PlayerNotifier::Visit(PlayerMapType &m)
iter->getSource()->UpdateVisibilityOf(&i_player);
i_player.UpdateVisibilityOf(iter->getSource());
- if (i_player.isPossessedByPlayer())
- ((Player*)i_player.GetCharmer())->UpdateVisibilityOf(iter->getSource());
+
+ if (!i_player.GetSharedVisionList().empty())
+ for (SharedVisionList::const_iterator it = i_player.GetSharedVisionList().begin(); it != i_player.GetSharedVisionList().end(); ++it)
+ (*it)->UpdateVisibilityOf(iter->getSource());
}
}
@@ -148,9 +150,14 @@ Deliverer::Visit(PlayerMapType &m)
{
if (!i_dist || iter->getSource()->GetDistance(&i_source) <= i_dist)
{
- // Send packet to possessor
- if (iter->getSource()->isPossessedByPlayer())
- SendPacket((Player*)iter->getSource()->GetCharmer());
+ // Send packet to all who are sharing the player's vision
+ if (!iter->getSource()->GetSharedVisionList().empty())
+ {
+ SharedVisionList::const_iterator it = iter->getSource()->GetSharedVisionList().begin();
+ for ( ; it != iter->getSource()->GetSharedVisionList().end(); ++it)
+ SendPacket(*it);
+ }
+
VisitObject(iter->getSource());
}
}
@@ -163,9 +170,29 @@ Deliverer::Visit(CreatureMapType &m)
{
if (!i_dist || iter->getSource()->GetDistance(&i_source) <= i_dist)
{
- // Send packet to possessor
- if (iter->getSource()->isPossessedByPlayer())
- SendPacket((Player*)iter->getSource()->GetCharmer());
+ // Send packet to all who are sharing the creature's vision
+ if (!iter->getSource()->GetSharedVisionList().empty())
+ {
+ SharedVisionList::const_iterator it = iter->getSource()->GetSharedVisionList().begin();
+ for ( ; it != iter->getSource()->GetSharedVisionList().end(); ++it)
+ SendPacket(*it);
+ }
+ }
+ }
+}
+
+void
+Deliverer::Visit(DynamicObjectMapType &m)
+{
+ for (DynamicObjectMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
+ {
+ if (IS_PLAYER_GUID(iter->getSource()->GetCasterGUID()))
+ {
+ // Send packet back to the caster if the caster has vision of dynamic object
+ Player* caster = (Player*)iter->getSource()->GetCaster();
+ if (caster->GetUInt64Value(PLAYER_FARSIGHT) == iter->getSource()->GetGUID() &&
+ (!i_dist || iter->getSource()->GetDistance(&i_source) <= i_dist))
+ SendPacket(caster);
}
}
}
@@ -175,6 +202,11 @@ Deliverer::SendPacket(Player* plr)
{
if (!plr)
return;
+
+ // Don't send the packet to self if not supposed to
+ if (!i_toSelf && plr == &i_source)
+ return;
+
// Don't send the packet to possesor if not supposed to
if (!i_toPossessor && plr->isPossessing() && plr->GetCharmGUID() == i_source.GetGUID())
return;
@@ -190,15 +222,13 @@ Deliverer::SendPacket(Player* plr)
void
MessageDeliverer::VisitObject(Player* plr)
{
- if (i_toSelf || plr != &i_source)
- SendPacket(plr);
+ SendPacket(plr);
}
void
MessageDistDeliverer::VisitObject(Player* plr)
{
- if( (i_toSelf || plr != &i_source ) &&
- (!i_ownTeamOnly || (i_source.GetTypeId() == TYPEID_PLAYER && plr->GetTeam() == ((Player&)i_source).GetTeam())) )
+ if( !i_ownTeamOnly || (i_source.GetTypeId() == TYPEID_PLAYER && plr->GetTeam() == ((Player&)i_source).GetTeam()) )
{
SendPacket(plr);
}
diff --git a/src/game/GridNotifiers.h b/src/game/GridNotifiers.h
index daa5ece7c6a..972c209964c 100644
--- a/src/game/GridNotifiers.h
+++ b/src/game/GridNotifiers.h
@@ -95,10 +95,12 @@ namespace Trinity
WorldPacket *i_message;
std::set<uint64> plr_list;
bool i_toPossessor;
+ bool i_toSelf;
float i_dist;
- Deliverer(WorldObject &src, WorldPacket *msg, bool to_possessor, float dist = 0.0f) : i_source(src), i_message(msg), i_toPossessor(to_possessor), i_dist(dist) {}
+ Deliverer(WorldObject &src, WorldPacket *msg, bool to_possessor, bool to_self, float dist = 0.0f) : i_source(src), i_message(msg), i_toPossessor(to_possessor), i_toSelf(to_self), i_dist(dist) {}
void Visit(PlayerMapType &m);
void Visit(CreatureMapType &m);
+ void Visit(DynamicObjectMapType &m);
virtual void VisitObject(Player* plr) = 0;
void SendPacket(Player* plr);
template<class SKIP> void Visit(GridRefManager<SKIP> &) {}
@@ -106,28 +108,26 @@ namespace Trinity
struct TRINITY_DLL_DECL MessageDeliverer : public Deliverer
{
- bool i_toSelf;
- MessageDeliverer(Player &pl, WorldPacket *msg, bool to_possessor, bool to_self) : Deliverer(pl, msg, to_possessor), i_toSelf(to_self) {}
+ MessageDeliverer(Player &pl, WorldPacket *msg, bool to_possessor, bool to_self) : Deliverer(pl, msg, to_possessor, to_self) {}
void VisitObject(Player* plr);
};
struct TRINITY_DLL_DECL ObjectMessageDeliverer : public Deliverer
{
- explicit ObjectMessageDeliverer(WorldObject &src, WorldPacket *msg, bool to_possessor) : Deliverer(src, msg, to_possessor) {}
+ explicit ObjectMessageDeliverer(WorldObject &src, WorldPacket *msg, bool to_possessor) : Deliverer(src, msg, to_possessor, false) {}
void VisitObject(Player* plr) { SendPacket(plr); }
};
struct TRINITY_DLL_DECL MessageDistDeliverer : public Deliverer
{
- bool i_toSelf;
bool i_ownTeamOnly;
- MessageDistDeliverer(Player &pl, WorldPacket *msg, bool to_possessor, float dist, bool to_self, bool ownTeamOnly) : Deliverer(pl, msg, to_possessor, dist), i_toSelf(to_self), i_ownTeamOnly(ownTeamOnly) {}
+ MessageDistDeliverer(Player &pl, WorldPacket *msg, bool to_possessor, float dist, bool to_self, bool ownTeamOnly) : Deliverer(pl, msg, to_possessor, to_self, dist), i_ownTeamOnly(ownTeamOnly) {}
void VisitObject(Player* plr);
};
struct TRINITY_DLL_DECL ObjectMessageDistDeliverer : public Deliverer
{
- ObjectMessageDistDeliverer(WorldObject &obj, WorldPacket *msg, bool to_possessor, float dist) : Deliverer(obj, msg, to_possessor, dist) {}
+ ObjectMessageDistDeliverer(WorldObject &obj, WorldPacket *msg, bool to_possessor, float dist) : Deliverer(obj, msg, to_possessor, false, dist) {}
void VisitObject(Player* plr) { SendPacket(plr); }
};
diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp
index 8b368e737b5..0a204ed1803 100644
--- a/src/game/Level3.cpp
+++ b/src/game/Level3.cpp
@@ -6815,3 +6815,26 @@ bool ChatHandler::HandleUnPossessCommand(const char* args)
return true;
}
+
+bool ChatHandler::HandleBindSightCommand(const char* args)
+{
+ Unit* pUnit = getSelectedUnit();
+ if (!pUnit)
+ return false;
+
+ if (m_session->GetPlayer()->isPossessing())
+ return false;
+
+ pUnit->AddPlayerToVision(m_session->GetPlayer());
+
+ return true;
+}
+
+bool ChatHandler::HandleUnbindSightCommand(const char* args)
+{
+ if (m_session->GetPlayer()->isPossessing())
+ return false;
+
+ m_session->GetPlayer()->RemoveFarsightTarget();
+ return true;
+}
diff --git a/src/game/Map.cpp b/src/game/Map.cpp
index 2dde5708b1a..7b3e40c00b3 100644
--- a/src/game/Map.cpp
+++ b/src/game/Map.cpp
@@ -315,21 +315,29 @@ void Map::SwitchGridContainers(T* obj, bool active)
{
CellPair pair = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY());
Cell cell(pair);
- NGridType *grid = getNGrid(cell.GridX(), cell.GridY());
+ NGridType *ngrid = getNGrid(cell.GridX(), cell.GridY());
+ GridType &grid = (*ngrid)(cell.CellX(), cell.CellY());
if (active)
{
- (*grid)(cell.CellX(), cell.CellY()).RemoveGridObject<T>(obj, obj->GetGUID());
- (*grid)(cell.CellX(), cell.CellY()).AddWorldObject<T>(obj, obj->GetGUID());
+ if (!grid.GetWorldObject(obj->GetGUID(), obj))
+ {
+ grid.RemoveGridObject<T>(obj, obj->GetGUID());
+ grid.AddWorldObject<T>(obj, obj->GetGUID());
+ }
} else
{
- (*grid)(cell.CellX(), cell.CellY()).RemoveWorldObject<T>(obj, obj->GetGUID());
- (*grid)(cell.CellX(), cell.CellY()).AddGridObject<T>(obj, obj->GetGUID());
+ if (!grid.GetGridObject(obj->GetGUID(), obj))
+ {
+ grid.RemoveWorldObject<T>(obj, obj->GetGUID());
+ grid.AddGridObject<T>(obj, obj->GetGUID());
+ }
}
}
template void Map::SwitchGridContainers(Creature *, bool);
template void Map::SwitchGridContainers(Corpse *, bool);
+template void Map::SwitchGridContainers(DynamicObject *, bool);
template<class T>
void Map::DeleteFromWorld(T* obj)
diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp
index 4c1129e6a98..c4c6d4fc110 100644
--- a/src/game/MiscHandler.cpp
+++ b/src/game/MiscHandler.cpp
@@ -1391,21 +1391,33 @@ void WorldSession::HandleFarSightOpcode( WorldPacket & recv_data )
sLog.outDebug("WORLD: CMSG_FAR_SIGHT");
//recv_data.hexlike();
- uint8 unk;
- recv_data >> unk;
+ uint8 apply;
+ recv_data >> apply;
+
+ CellPair pair;
- switch(unk)
+ switch(apply)
{
case 0:
- //WorldPacket data(SMSG_CLEAR_FAR_SIGHT_IMMEDIATE, 0)
- //SendPacket(&data);
- //_player->SetUInt64Value(PLAYER_FARSIGHT, 0);
- sLog.outDebug("Removed FarSight from player %u", _player->GetGUIDLow());
+ _player->SetFarsightVision(false);
+ pair = Trinity::ComputeCellPair(_player->GetPositionX(), _player->GetPositionY());
+ sLog.outDebug("Player %u set vision to himself", _player->GetGUIDLow());
break;
case 1:
- sLog.outDebug("Added FarSight " I64FMTD " to player %u", _player->GetUInt64Value(PLAYER_FARSIGHT), _player->GetGUIDLow());
+ _player->SetFarsightVision(true);
+ if (WorldObject* obj = _player->GetFarsightTarget())
+ pair = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY());
+ else
+ return;
+ sLog.outDebug("Player %u set vision to farsight target " I64FMTD ".", _player->GetGUIDLow(), _player->GetUInt64Value(PLAYER_FARSIGHT));
break;
+ default:
+ sLog.outDebug("Unhandled mode in CMSG_FAR_SIGHT: %u", apply);
+ return;
}
+ // Update visibility after vision change
+ Cell cell(pair);
+ GetPlayer()->GetMap()->UpdateObjectsVisibilityFor(_player, cell, pair);
}
void WorldSession::HandleChooseTitleOpcode( WorldPacket & recv_data )
diff --git a/src/game/ObjectAccessor.cpp b/src/game/ObjectAccessor.cpp
index 654645f3068..e5243ab941e 100644
--- a/src/game/ObjectAccessor.cpp
+++ b/src/game/ObjectAccessor.cpp
@@ -624,8 +624,12 @@ ObjectAccessor::WorldObjectChangeAccumulator::Visit(PlayerMapType &m)
for(PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
{
BuildPacket(iter->getSource());
- if (iter->getSource()->isPossessedByPlayer())
- BuildPacket((Player*)iter->getSource()->GetCharmer());
+ if (!iter->getSource()->GetSharedVisionList().empty())
+ {
+ SharedVisionList::const_iterator it = iter->getSource()->GetSharedVisionList().begin();
+ for ( ; it != iter->getSource()->GetSharedVisionList().end(); ++it)
+ BuildPacket(*it);
+ }
}
}
@@ -633,8 +637,28 @@ void
ObjectAccessor::WorldObjectChangeAccumulator::Visit(CreatureMapType &m)
{
for(CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
- if (iter->getSource()->isPossessedByPlayer())
- BuildPacket((Player*)iter->getSource()->GetCharmer());
+ {
+ if (!iter->getSource()->GetSharedVisionList().empty())
+ {
+ SharedVisionList::const_iterator it = iter->getSource()->GetSharedVisionList().begin();
+ for ( ; it != iter->getSource()->GetSharedVisionList().end(); ++it)
+ BuildPacket(*it);
+ }
+ }
+}
+
+void
+ObjectAccessor::WorldObjectChangeAccumulator::Visit(DynamicObjectMapType &m)
+{
+ for(DynamicObjectMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
+ {
+ if (IS_PLAYER_GUID(iter->getSource()->GetCasterGUID()))
+ {
+ Player* caster = (Player*)iter->getSource()->GetCaster();
+ if (caster->GetUInt64Value(PLAYER_FARSIGHT) == iter->getSource()->GetGUID())
+ BuildPacket(caster);
+ }
+ }
}
void
diff --git a/src/game/ObjectAccessor.h b/src/game/ObjectAccessor.h
index 88d459ffa08..d0007d37f21 100644
--- a/src/game/ObjectAccessor.h
+++ b/src/game/ObjectAccessor.h
@@ -212,6 +212,7 @@ class TRINITY_DLL_DECL ObjectAccessor : public Trinity::Singleton<ObjectAccessor
WorldObjectChangeAccumulator(WorldObject &obj, UpdateDataMapType &d) : i_updateDatas(d), i_object(obj) {}
void Visit(PlayerMapType &);
void Visit(CreatureMapType &);
+ void Visit(DynamicObjectMapType &);
void BuildPacket(Player* plr);
template<class SKIP> void Visit(GridRefManager<SKIP> &) {}
};
diff --git a/src/game/Player.cpp b/src/game/Player.cpp
index 0d7c035711c..ec882ef1154 100644
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -427,6 +427,8 @@ Player::Player (WorldSession *session): Unit()
m_declinedname = NULL;
m_isActive = true;
+
+ m_farsightVision = false;
}
Player::~Player ()
@@ -1291,6 +1293,12 @@ void Player::setDeathState(DeathState s)
RemoveMiniPet();
RemoveGuardians();
+ // remove possession
+ if(isPossessing())
+ RemovePossess(false);
+ else
+ RemoveFarsightTarget();
+
// save value before aura remove in Unit::setDeathState
ressSpellId = GetUInt32Value(PLAYER_SELF_RES_SPELL);
@@ -1544,7 +1552,15 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
if (isPossessedByPlayer())
((Player*)GetCharmer())->RemovePossess();
- // The player was ported to another map and looses the duel immediately.
+ // Remove player's possession before teleporting
+ if (isPossessing())
+ RemovePossess(false);
+
+ // Empty vision list and clear farsight (if it hasn't already been cleared by RemovePossess) before teleporting
+ RemoveAllFromVision();
+ RemoveFarsightTarget();
+
+ // The player was ported to another map and looses the duel immediatly.
// We have to perform this check before the teleport, otherwise the
// ObjectAccessor won't find the flag.
if (duel && GetMapId()!=mapid)
@@ -1762,6 +1778,7 @@ void Player::RemoveFromWorld()
UnsummonAllTotems();
RemoveMiniPet();
RemoveGuardians();
+ RemoveFarsightTarget();
}
for(int i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; i++)
@@ -17293,8 +17310,10 @@ bool Player::canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList) cons
if(!u->IsVisibleInGridForPlayer(this))
return false;
- // If the player is currently possessing, update visibility from the possessed unit's location
- const Unit* target = isPossessing() ? GetCharm() : this;
+ // If the player is currently channeling vision, update visibility from the target unit's location
+ const WorldObject* target = GetFarsightTarget();
+ if (!target || !HasFarsightVision()) // Vision needs to be on the farsight target
+ target = this;
// different visible distance checks
if(isInFlight()) // what see player in flight
@@ -18743,20 +18762,17 @@ void Player::Possess(Unit *target)
// Update the proper unit fields
SetPossessedTarget(target);
+ // Start channeling packets to possessor
+ target->AddPlayerToVision(this);
+
target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, getFaction());
target->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNKNOWN5);
target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
- SetUInt64Value(PLAYER_FARSIGHT, target->GetGUID());
if(target->GetTypeId() == TYPEID_UNIT)
{
- // Set target to active in the grid and place it in the world container to be picked up by all regular player cell visits
- Map* map = target->GetMap();
- map->SwitchGridContainers((Creature*)target, true);
- target->setActive(true);
-
((Creature*)target)->InitPossessedAI(); // Initialize the possessed AI
target->StopMoving();
target->GetMotionMaster()->Clear(false);
@@ -18809,15 +18825,13 @@ void Player::RemovePossess(bool attack)
RemovePossessedTarget();
+ // Stop channeling packets back to possessor
+ target->RemovePlayerFromVision(this);
+
if(target->GetTypeId() == TYPEID_PLAYER)
((Player*)target)->setFactionForRace(target->getRace());
else if(target->GetTypeId() == TYPEID_UNIT)
{
- // Set creature to inactive in grid and place it back into the grid container
- Map* map = target->GetMap();
- target->setActive(false);
- map->SwitchGridContainers((Creature*)target, false);
-
if(((Creature*)target)->isPet())
{
if(Unit* owner = target->GetOwner())
@@ -18831,7 +18845,6 @@ void Player::RemovePossess(bool attack)
target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNKNOWN5);
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
- SetUInt64Value(PLAYER_FARSIGHT, 0);
// Remove pet spell action bar
WorldPacket data(SMSG_PET_SPELLS, 8);
@@ -18897,6 +18910,45 @@ void Player::SetViewport(uint64 guid, bool moveable)
sLog.outDetail("Viewport for "I64FMT" (%s) changed to "I64FMT, GetGUID(), GetName(), guid);
}
+WorldObject* Player::GetFarsightTarget() const
+{
+ // Players can have in farsight field another player's guid, a creature's guid, or a dynamic object's guid
+ if (uint64 guid = GetUInt64Value(PLAYER_FARSIGHT))
+ return (WorldObject*)ObjectAccessor::GetObjectByTypeMask(*this, guid, TYPEMASK_PLAYER | TYPEMASK_UNIT | TYPEMASK_DYNAMICOBJECT);
+ return NULL;
+}
+
+void Player::RemoveFarsightTarget()
+{
+ if (WorldObject* fTarget = GetFarsightTarget())
+ {
+ if (fTarget->isType(TYPEMASK_PLAYER | TYPEMASK_UNIT))
+ ((Unit*)fTarget)->RemovePlayerFromVision(this);
+ }
+ ClearFarsight();
+}
+
+void Player::ClearFarsight()
+{
+ if (GetUInt64Value(PLAYER_FARSIGHT))
+ {
+ SetUInt64Value(PLAYER_FARSIGHT, 0);
+ WorldPacket data(SMSG_CLEAR_FAR_SIGHT_IMMEDIATE, 0);
+ GetSession()->SendPacket(&data);
+ }
+}
+
+void Player::SetFarsightTarget(WorldObject* obj)
+{
+ if (!obj || !obj->isType(TYPEMASK_PLAYER | TYPEMASK_UNIT | TYPEMASK_DYNAMICOBJECT))
+ return;
+
+ // Remove the current target if there is one
+ RemoveFarsightTarget();
+
+ SetUInt64Value(PLAYER_FARSIGHT, obj->GetGUID());
+}
+
bool Player::isAllowUseBattleGroundObject()
{
return ( //InBattleGround() && // in battleground - not need, check in other cases
diff --git a/src/game/Player.h b/src/game/Player.h
index 8df59a3cece..4b92f8316d0 100644
--- a/src/game/Player.h
+++ b/src/game/Player.h
@@ -902,6 +902,13 @@ class TRINITY_DLL_SPEC Player : public Unit
void SetViewport(uint64 guid, bool movable);
void Possess(Unit *target);
void RemovePossess(bool attack = true);
+ WorldObject* GetFarsightTarget() const;
+ void ClearFarsight();
+ void RemoveFarsightTarget();
+ void SetFarsightTarget(WorldObject* target);
+ // Controls if vision is currently on farsight object, updated in FAR_SIGHT opcode
+ void SetFarsightVision(bool apply) { m_farsightVision = apply; }
+ bool HasFarsightVision() const { return m_farsightVision; }
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options = 0);
@@ -2289,6 +2296,8 @@ class TRINITY_DLL_SPEC Player : public Unit
// Far Teleport
WorldLocation m_teleport_dest;
+ bool m_farsightVision;
+
DeclinedName *m_declinedname;
private:
// internal common parts for CanStore/StoreItem functions
diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp
index 30afbdcfa7c..8edac052288 100644
--- a/src/game/SpellAuras.cpp
+++ b/src/game/SpellAuras.cpp
@@ -1964,14 +1964,10 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
// AT REMOVE
else
{
- if( m_target->GetTypeId() == TYPEID_PLAYER &&
- ( GetSpellProto()->Effect[0]==72 || GetSpellProto()->Effect[0]==6 &&
- ( GetSpellProto()->EffectApplyAuraName[0]==1 || GetSpellProto()->EffectApplyAuraName[0]==128 ) ) )
+ if( m_target->GetTypeId() == TYPEID_PLAYER && GetSpellProto()->Effect[0]==72 )
{
// spells with SpellEffect=72 and aura=4: 6196, 6197, 21171, 21425
- m_target->SetUInt64Value(PLAYER_FARSIGHT, 0);
- WorldPacket data(SMSG_CLEAR_FAR_SIGHT_IMMEDIATE, 0);
- ((Player*)m_target)->GetSession()->SendPacket(&data);
+ ((Player*)m_target)->ClearFarsight();
return;
}
@@ -2229,6 +2225,24 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
((Player*)m_target)->AddSpellMod(m_spellmod, apply);
return;
}
+
+ // Sentry Totem
+ if (GetId() == 6495 && caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ if (apply)
+ {
+ uint64 guid = caster->m_TotemSlot[3];
+ if (guid)
+ {
+ Creature *totem = ObjectAccessor::GetCreature(*caster, guid);
+ if (totem && totem->isTotem())
+ totem->AddPlayerToVision((Player*)caster);
+ }
+ }
+ else
+ ((Player*)caster)->RemoveFarsightTarget();
+ return;
+ }
break;
}
}
@@ -2830,7 +2844,10 @@ void Aura::HandleBindSight(bool apply, bool Real)
if(!caster || caster->GetTypeId() != TYPEID_PLAYER)
return;
- caster->SetUInt64Value(PLAYER_FARSIGHT,apply ? m_target->GetGUID() : 0);
+ if (apply)
+ m_target->AddPlayerToVision((Player*)caster);
+ else
+ m_target->RemovePlayerFromVision((Player*)caster);
}
void Aura::HandleFarSight(bool apply, bool Real)
diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp
index 739fa96cee2..daf05ec51a0 100644
--- a/src/game/SpellEffects.cpp
+++ b/src/game/SpellEffects.cpp
@@ -3490,6 +3490,9 @@ void Spell::EffectPickPocket(uint32 /*i*/)
void Spell::EffectAddFarsight(uint32 i)
{
+ if (m_caster->GetTypeId() != TYPEID_PLAYER)
+ return;
+
float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
int32 duration = GetSpellDuration(m_spellInfo);
DynamicObject* dynObj = new DynamicObject;
@@ -3501,8 +3504,18 @@ void Spell::EffectAddFarsight(uint32 i)
dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002);
m_caster->AddDynObject(dynObj);
- MapManager::Instance().GetMap(dynObj->GetMapId(), dynObj)->Add(dynObj);
- m_caster->SetUInt64Value(PLAYER_FARSIGHT, dynObj->GetGUID());
+
+ CellPair pair = Trinity::ComputeCellPair(dynObj->GetPositionX(), dynObj->GetPositionY());
+ Cell cell(pair);
+ Map* map = MapManager::Instance().GetMap(dynObj->GetMapId(), dynObj);
+ map->LoadGrid(cell); // In case the spell is casted into a different grid by player
+ map->Add(dynObj);
+ map->SwitchGridContainers(dynObj, true); // Needed for forwarding player packets
+ dynObj->setActive(true); // Keep the grid updated even if there are no players in it
+
+ // Need to update visibility of object for client to accept farsight guid
+ ((Player*)m_caster)->UpdateVisibilityOf(dynObj);
+ ((Player*)m_caster)->SetFarsightTarget(dynObj);
}
void Spell::EffectSummonWild(uint32 i)
diff --git a/src/game/SpellHandler.cpp b/src/game/SpellHandler.cpp
index 00979cd23d3..3ed9c04a259 100644
--- a/src/game/SpellHandler.cpp
+++ b/src/game/SpellHandler.cpp
@@ -352,18 +352,22 @@ void WorldSession::HandleCancelAuraOpcode( WorldPacket& recvPacket)
if (!spellInfo)
return;
- // Remove possess/charm aura from the possessed/charmed as well
+ // Remove possess/charm/sight aura from the possessed/charmed as well
// TODO: Remove this once the ability to cancel aura sets at once is implemented
- if(_player->GetCharm())
+ if(_player->GetCharm() || _player->GetFarsightTarget())
{
for (int i = 0; i < 3; ++i)
{
if (spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_POSSESS ||
spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_POSSESS_PET ||
- spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_CHARM)
+ spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_CHARM ||
+ spellInfo->EffectApplyAuraName[i] == SPELL_AURA_BIND_SIGHT)
{
_player->RemoveAurasDueToSpellByCancel(spellId);
- _player->GetCharm()->RemoveAurasDueToSpellByCancel(spellId);
+ if (_player->GetCharm())
+ _player->GetCharm()->RemoveAurasDueToSpellByCancel(spellId);
+ else if (_player->GetFarsightTarget()->GetTypeId() != TYPEID_DYNAMICOBJECT)
+ ((Unit*)_player->GetFarsightTarget())->RemoveAurasDueToSpellByCancel(spellId);
return;
}
}
@@ -464,7 +468,8 @@ void WorldSession::HandleTotemDestroy( WorldPacket& recvPacket)
return;
Creature* totem = ObjectAccessor::GetCreature(*_player,_player->m_TotemSlot[slotId]);
- if(totem && totem->isTotem())
+ // Don't unsummon sentry totem
+ if(totem && totem->isTotem() && totem->GetEntry() != SENTRY_TOTEM_ENTRY)
((Totem*)totem)->UnSummon();
}
diff --git a/src/game/Totem.h b/src/game/Totem.h
index a79e5128e65..717499ff850 100644
--- a/src/game/Totem.h
+++ b/src/game/Totem.h
@@ -30,6 +30,8 @@ enum TotemType
TOTEM_STATUE = 2
};
+#define SENTRY_TOTEM_ENTRY 3968
+
class Totem : public Creature
{
public:
diff --git a/src/game/TotemAI.cpp b/src/game/TotemAI.cpp
index f68d26df49d..7b99a8f0358 100644
--- a/src/game/TotemAI.cpp
+++ b/src/game/TotemAI.cpp
@@ -122,4 +122,13 @@ TotemAI::IsVisible(Unit *) const
void
TotemAI::AttackStart(Unit *)
{
+ // Sentry totem sends ping on attack
+ if (i_totem.GetEntry() == SENTRY_TOTEM_ENTRY && i_totem.GetOwner()->GetTypeId() == TYPEID_PLAYER)
+ {
+ WorldPacket data(MSG_MINIMAP_PING, (8+4+4));
+ data << i_totem.GetGUID();
+ data << i_totem.GetPositionX();
+ data << i_totem.GetPositionY();
+ ((Player*)i_totem.GetOwner())->GetSession()->SendPacket(&data);
+ }
}
diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp
index c620b86748d..2ff5fe47705 100644
--- a/src/game/Unit.cpp
+++ b/src/game/Unit.cpp
@@ -828,13 +828,6 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
he->DuelComplete(DUEL_INTERUPTED);
}
- // Possessed unit died, restore control to possessor
- pVictim->UnpossessSelf(false);
-
- // Possessor died, remove possession
- if(pVictim->GetTypeId() == TYPEID_PLAYER && pVictim->isPossessing())
- ((Player*)pVictim)->RemovePossess(false);
-
// battleground things (do this at the end, so the death state flag will be properly set to handle in the bg->handlekill)
if(pVictim->GetTypeId() == TYPEID_PLAYER && (((Player*)pVictim)->InBattleGround()))
{
@@ -7183,6 +7176,38 @@ void Unit::SetCharm(Unit* charmed)
SetUInt64Value(UNIT_FIELD_CHARM,charmed ? charmed->GetGUID() : 0);
}
+void Unit::AddPlayerToVision(Player* plr)
+{
+ if (m_sharedVision.empty() && GetTypeId() == TYPEID_UNIT)
+ {
+ setActive(true);
+ GetMap()->SwitchGridContainers((Creature*)this, true);
+ }
+ m_sharedVision.push_back(plr);
+ plr->SetFarsightTarget(this);
+}
+
+void Unit::RemovePlayerFromVision(Player* plr)
+{
+ m_sharedVision.remove(plr);
+ if (m_sharedVision.empty() && GetTypeId() == TYPEID_UNIT)
+ {
+ setActive(false);
+ GetMap()->SwitchGridContainers((Creature*)this, false);
+ }
+ plr->ClearFarsight();
+}
+
+void Unit::RemoveAllFromVision()
+{
+ while (!m_sharedVision.empty())
+ {
+ Player* plr = *m_sharedVision.begin();
+ m_sharedVision.erase(m_sharedVision.begin());
+ plr->ClearFarsight();
+ }
+}
+
void Unit::UncharmSelf()
{
if (!GetCharmer())
@@ -8935,6 +8960,10 @@ void Unit::setDeathState(DeathState s)
RemoveAllAurasOnDeath();
UnsummonAllTotems();
+ // Possessed unit died, restore control to possessor
+ UnpossessSelf(false);
+ RemoveAllFromVision();
+
ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false);
ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false);
// remove aurastates allowing special moves
@@ -9756,10 +9785,13 @@ void Unit::CleanupsBeforeDelete()
GetMotionMaster()->Clear(false); // remove different non-standard movement generators.
UnpossessSelf(false);
+ RemoveAllFromVision();
}
RemoveFromWorld();
}
+
+
CharmInfo* Unit::InitCharmInfo(Unit *charm)
{
if(!m_charmInfo)
diff --git a/src/game/Unit.h b/src/game/Unit.h
index 8e5d9237951..028c590c06f 100644
--- a/src/game/Unit.h
+++ b/src/game/Unit.h
@@ -638,6 +638,8 @@ struct CharmSpellEntry
uint16 active;
};
+typedef std::list<Player*> SharedVisionList;
+
struct CharmInfo
{
public:
@@ -1018,6 +1020,10 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
CharmInfo* GetCharmInfo() { return m_charmInfo; }
CharmInfo* InitCharmInfo(Unit* charm);
+ SharedVisionList const& GetSharedVisionList() { return m_sharedVision; }
+ void AddPlayerToVision(Player* plr);
+ void RemovePlayerFromVision(Player* plr);
+ void RemoveAllFromVision();
void UncharmSelf();
void UnpossessSelf(bool attack);
@@ -1350,6 +1356,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
CharmInfo *m_charmInfo;
bool m_isPossessed;
+ SharedVisionList m_sharedVision;
virtual SpellSchoolMask GetMeleeDamageSchoolMask() const;