diff options
author | gvcoman <none@none> | 2008-11-14 20:40:35 -0600 |
---|---|---|
committer | gvcoman <none@none> | 2008-11-14 20:40:35 -0600 |
commit | 5deef1bb59ba53570d481a97e5c1df39ef316f37 (patch) | |
tree | 334e913e1247419d2ad485f1681e859aa8875044 | |
parent | 3085e66b966fec0012decf2543c7e32064b47102 (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.sql | 4 | ||||
-rw-r--r-- | src/game/Chat.cpp | 2 | ||||
-rw-r--r-- | src/game/Chat.h | 2 | ||||
-rw-r--r-- | src/game/DynamicObject.cpp | 5 | ||||
-rw-r--r-- | src/game/GridDefines.h | 2 | ||||
-rw-r--r-- | src/game/GridNotifiers.cpp | 54 | ||||
-rw-r--r-- | src/game/GridNotifiers.h | 14 | ||||
-rw-r--r-- | src/game/Level3.cpp | 23 | ||||
-rw-r--r-- | src/game/Map.cpp | 18 | ||||
-rw-r--r-- | src/game/MiscHandler.cpp | 28 | ||||
-rw-r--r-- | src/game/ObjectAccessor.cpp | 32 | ||||
-rw-r--r-- | src/game/ObjectAccessor.h | 1 | ||||
-rw-r--r-- | src/game/Player.cpp | 82 | ||||
-rw-r--r-- | src/game/Player.h | 9 | ||||
-rw-r--r-- | src/game/SpellAuras.cpp | 31 | ||||
-rw-r--r-- | src/game/SpellEffects.cpp | 17 | ||||
-rw-r--r-- | src/game/SpellHandler.cpp | 15 | ||||
-rw-r--r-- | src/game/Totem.h | 2 | ||||
-rw-r--r-- | src/game/TotemAI.cpp | 9 | ||||
-rw-r--r-- | src/game/Unit.cpp | 46 | ||||
-rw-r--r-- | src/game/Unit.h | 7 |
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; |