[svn] Implemented player on player and player on creature possession:

* Implemented packet and vision forwarding through possessed units
* Added new OnPossess script call alerting scripts on when possession is applied/removed
* Moved fall damage and fall under map calculations into the Player class
* Added new PossessedAI that is applied only while possession on creature is active
* Implemented summon possessed spell effect
* Fixed Eyes of the Beast

--HG--
branch : trunk
This commit is contained in:
gvcoman
2008-11-05 20:51:05 -06:00
parent 8d331f2b10
commit 44bdb135f4
41 changed files with 1105 additions and 374 deletions
+4
View File
@@ -0,0 +1,4 @@
DELETE FROM `command` WHERE name IN ('possess', 'unpossess');
INSERT INTO `command` (name,security,help) VALUES
('possess',3,'Syntax: .possess\r\n\r\nPossesses indefinitely the selected creature.'),
('unpossess',3,'Syntax: .unpossess\r\n\r\nIf you are possessed, unpossesses yourself; otherwise unpossesses current possessed target.');
@@ -75,6 +75,9 @@ struct TRINITY_DLL_DECL ScriptedAI : public CreatureAI
//Called at waypoint reached or PointMovement end
void MovementInform(uint32, uint32){}
// Called when AI is temporarily replaced or put back when possess is applied or removed
void OnPossess(bool apply) {}
//*************
// Variables
//*************
@@ -256,6 +256,25 @@ void npc_escortAI::MovementInform(uint32 type, uint32 id)
}
}
void npc_escortAI::OnPossess(bool apply)
{
// We got possessed in the middle of being escorted, store the point
// where we left off to come back to when possess is removed
if (IsBeingEscorted)
{
if (apply)
m_creature->GetPosition(LastPos.x, LastPos.y, LastPos.z);
else
{
Returning = true;
m_creature->GetMotionMaster()->MovementExpired();
m_creature->GetMotionMaster()->MovePoint(WP_LAST_POINT, LastPos.x, LastPos.y, LastPos.z);
}
}
}
void npc_escortAI::AddWaypoint(uint32 id, float x, float y, float z, uint32 WaitTimeMs)
{
Escort_Waypoint t(id, x, y, z, WaitTimeMs);
@@ -51,6 +51,8 @@ struct TRINITY_DLL_DECL npc_escortAI : public ScriptedAI
void MovementInform(uint32, uint32);
void OnPossess(bool apply);
// EscortAI functions
void AddWaypoint(uint32 id, float x, float y, float z, uint32 WaitTimeMs = 0);
+2
View File
@@ -560,6 +560,8 @@ ChatCommand * ChatHandler::getCommandTable()
{ "unfreeze", SEC_ADMINISTRATOR, false, &ChatHandler::HandleUnFreezeCommand, "", NULL },
{ "listfreeze", SEC_ADMINISTRATOR, false, &ChatHandler::HandleListFreezeCommand, "", NULL },
{ "flusharenapoints", SEC_ADMINISTRATOR, false, &ChatHandler::HandleFlushArenaPointsCommand, "", NULL },
{ "possess", SEC_ADMINISTRATOR, false, &ChatHandler::HandlePossessCommand, "", NULL },
{ "unpossess", SEC_ADMINISTRATOR, false, &ChatHandler::HandleUnPossessCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
+2
View File
@@ -449,6 +449,8 @@ class ChatHandler
bool HandleDebugArenaCommand(const char * args);
bool HandleDebugThreatList(const char * args);
bool HandleDebugHostilRefList(const char * args);
bool HandlePossessCommand(const char* args);
bool HandleUnPossessCommand(const char* args);
Player* getSelectedPlayer();
Creature* getSelectedCreature();
+32 -3
View File
@@ -46,6 +46,7 @@
#include "CellImpl.h"
#include "OutdoorPvPMgr.h"
#include "GameEvent.h"
#include "PossessedAI.h"
// apply implementation of the singletons
#include "Policies/SingletonImp.h"
@@ -117,7 +118,7 @@ uint32 CreatureInfo::GetFirstValidModelId() const
}
Creature::Creature() :
Unit(), i_AI(NULL),
Unit(), i_AI(NULL), i_AI_possessed(NULL),
lootForPickPocketed(false), lootForBody(false), m_groupLootTimer(0), lootingGroupLeaderGUID(0),
m_lootMoney(0), m_lootRecipient(0),
m_deathTimer(0), m_respawnTime(0), m_respawnDelay(25), m_corpseDelay(60), m_respawnradius(0.0f),
@@ -145,6 +146,8 @@ Creature::~Creature()
delete i_AI;
i_AI = NULL;
DeletePossessedAI();
}
void Creature::AddToWorld()
@@ -364,7 +367,7 @@ void Creature::Update(uint32 diff)
setDeathState( JUST_ALIVED );
//Call AI respawn virtual function
i_AI->JustRespawned();
AI()->JustRespawned();
MapManager::Instance().GetMap(GetMapId(), this)->Add(this);
}
@@ -428,7 +431,7 @@ void Creature::Update(uint32 diff)
{
// do not allow the AI to be changed during update
m_AI_locked = true;
i_AI->UpdateAI(diff);
AI()->UpdateAI(diff);
m_AI_locked = false;
}
@@ -525,6 +528,10 @@ bool Creature::AIM_Initialize()
return false;
}
// don't allow AI switch when possessed
if (isPossessed())
return false;
CreatureAI * oldAI = i_AI;
i_motionMaster.Initialize();
i_AI = FactorySelector::selectAI(this);
@@ -533,6 +540,28 @@ bool Creature::AIM_Initialize()
return true;
}
void Creature::InitPossessedAI()
{
if (!isPossessed()) return;
if (!i_AI_possessed)
i_AI_possessed = new PossessedAI(*this);
// Signal the old AI that it's been disabled
i_AI->OnPossess(true);
}
void Creature::DeletePossessedAI()
{
if (!i_AI_possessed) return;
delete i_AI_possessed;
i_AI_possessed = NULL;
// Signal the old AI that it's been re-enabled
i_AI->OnPossess(false);
}
bool Creature::Create (uint32 guidlow, Map *map, uint32 Entry, uint32 team, const CreatureData *data)
{
SetMapId(map->GetId());
+4 -1
View File
@@ -395,6 +395,7 @@ typedef std::map<uint32,time_t> CreatureSpellCooldowns;
class TRINITY_DLL_SPEC Creature : public Unit
{
CreatureAI *i_AI;
CreatureAI *i_AI_possessed;
public:
@@ -455,9 +456,11 @@ class TRINITY_DLL_SPEC Creature : public Unit
bool IsInEvadeMode() const;
bool AIM_Initialize();
void InitPossessedAI();
void DeletePossessedAI();
void AI_SendMoveToPacket(float x, float y, float z, uint32 time, uint32 MovementFlags, uint8 type);
CreatureAI* AI() { return i_AI; }
CreatureAI* AI() { return isPossessed() && i_AI_possessed ? i_AI_possessed : i_AI; }
uint32 GetShieldBlockValue() const //dunno mob block value
{
+3
View File
@@ -121,6 +121,9 @@ class TRINITY_DLL_SPEC CreatureAI
// Called at waypoint reached or point movement finished
virtual void MovementInform(uint32 /*MovementType*/, uint32 /*Data*/) {}
// Called when AI is temporarily replaced or put back when possess is applied or removed
virtual void OnPossess(bool apply) {}
};
struct SelectableAI : public FactoryHolder<CreatureAI>, public Permissible<Creature>
+2
View File
@@ -24,6 +24,7 @@
#include "AggressorAI.h"
#include "GuardAI.h"
#include "PetAI.h"
#include "PossessedAI.h"
#include "TotemAI.h"
#include "OutdoorPvPObjectiveAI.h"
#include "RandomMovementGenerator.h"
@@ -44,6 +45,7 @@ namespace AIRegistry
(new CreatureAIFactory<PetAI>("PetAI"))->RegisterSelf();
(new CreatureAIFactory<TotemAI>("TotemAI"))->RegisterSelf();
(new CreatureAIFactory<OutdoorPvPObjectiveAI>("OutdoorPvPObjectiveAI"))->RegisterSelf();
(new CreatureAIFactory<PossessedAI>("PossessedAI"))->RegisterSelf();
(new MovementGeneratorFactory<RandomMovementGenerator<Creature> >(RANDOM_MOTION_TYPE))->RegisterSelf();
(new MovementGeneratorFactory<WaypointMovementGenerator<Creature> >(WAYPOINT_MOTION_TYPE))->RegisterSelf();
+3 -1
View File
@@ -56,12 +56,14 @@ namespace FactorySelector
{
if( creature->isGuard() )
ai_factory = ai_registry.GetRegistryItem("GuardAI");
else if(creature->isPet() || creature->isCharmed())
else if(creature->isPet() || (creature->isCharmed() && !creature->isPossessed()))
ai_factory = ai_registry.GetRegistryItem("PetAI");
else if(creature->isTotem())
ai_factory = ai_registry.GetRegistryItem("TotemAI");
else if(creature->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER)
ai_factory = ai_registry.GetRegistryItem("NullCreatureAI");
else if(creature->isPossessed())
creature->InitPossessedAI();
}
// select by permit check
+41 -27
View File
@@ -40,6 +40,8 @@ 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());
}
}
@@ -139,54 +141,66 @@ VisibleNotifier::Notify()
i_player.SendAuraDurationsForTarget((Unit*)(*vItr));
}
void
MessageDeliverer::Visit(PlayerMapType &m)
void
Deliverer::Visit(PlayerMapType &m)
{
for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
for (PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
{
if( i_toSelf || iter->getSource() != &i_player)
if (!i_dist || iter->getSource()->GetDistance(&i_source) <= i_dist)
{
if(WorldSession* session = iter->getSource()->GetSession())
session->SendPacket(i_message);
// Send packet to possessor
if (iter->getSource()->isPossessedByPlayer())
SendPacket((Player*)iter->getSource()->GetCharmer());
VisitObject(iter->getSource());
}
}
}
void
Deliverer::Visit(CreatureMapType &m)
{
for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
{
if (!i_dist || iter->getSource()->GetDistance(&i_source) <= i_dist)
{
// Send packet to possessor
if (iter->getSource()->isPossessedByPlayer())
SendPacket((Player*)iter->getSource()->GetCharmer());
}
}
}
void
ObjectMessageDeliverer::Visit(PlayerMapType &m)
Deliverer::SendPacket(Player* plr)
{
for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
if (!plr)
return;
// Don't send the packet to possesor if not supposed to
if (!i_toPossessor && plr->isPossessing() && plr->GetCharmGUID() == i_source.GetGUID())
return;
if (plr_list.find(plr->GetGUID()) == plr_list.end())
{
if(WorldSession* session = iter->getSource()->GetSession())
if (WorldSession* session = plr->GetSession())
session->SendPacket(i_message);
plr_list.insert(plr->GetGUID());
}
}
void
MessageDistDeliverer::Visit(PlayerMapType &m)
MessageDeliverer::VisitObject(Player* plr)
{
for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
{
if( (i_toSelf || iter->getSource() != &i_player ) &&
(!i_ownTeamOnly || iter->getSource()->GetTeam() == i_player.GetTeam() ) &&
(!i_dist || iter->getSource()->GetDistance(&i_player) <= i_dist) )
{
if(WorldSession* session = iter->getSource()->GetSession())
session->SendPacket(i_message);
}
}
if (i_toSelf || plr != &i_source)
SendPacket(plr);
}
void
ObjectMessageDistDeliverer::Visit(PlayerMapType &m)
MessageDistDeliverer::VisitObject(Player* plr)
{
for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
if( (i_toSelf || plr != &i_source ) &&
(!i_ownTeamOnly || (i_source.GetTypeId() == TYPEID_PLAYER && plr->GetTeam() == ((Player&)i_source).GetTeam())) )
{
if( !i_dist || iter->getSource()->GetDistance(&i_object) <= i_dist )
{
if(WorldSession* session = iter->getSource()->GetSession())
session->SendPacket(i_message);
}
SendPacket(plr);
}
}
+26 -24
View File
@@ -89,44 +89,46 @@ namespace Trinity
void Visit(CorpseMapType &m) { updateObjects<Corpse>(m); }
};
struct TRINITY_DLL_DECL MessageDeliverer
struct TRINITY_DLL_DECL Deliverer
{
Player &i_player;
WorldObject &i_source;
WorldPacket *i_message;
std::set<uint64> plr_list;
bool i_toPossessor;
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) {}
void Visit(PlayerMapType &m);
void Visit(CreatureMapType &m);
virtual void VisitObject(Player* plr) = 0;
void SendPacket(Player* plr);
template<class SKIP> void Visit(GridRefManager<SKIP> &) {}
};
struct TRINITY_DLL_DECL MessageDeliverer : public Deliverer
{
bool i_toSelf;
MessageDeliverer(Player &pl, WorldPacket *msg, bool to_self) : i_player(pl), i_message(msg), i_toSelf(to_self) {}
void Visit(PlayerMapType &m);
template<class SKIP> void Visit(GridRefManager<SKIP> &) {}
MessageDeliverer(Player &pl, WorldPacket *msg, bool to_possessor, bool to_self) : Deliverer(pl, msg, to_possessor), i_toSelf(to_self) {}
void VisitObject(Player* plr);
};
struct TRINITY_DLL_DECL ObjectMessageDeliverer
struct TRINITY_DLL_DECL ObjectMessageDeliverer : public Deliverer
{
WorldPacket *i_message;
explicit ObjectMessageDeliverer(WorldPacket *msg) : i_message(msg) {}
void Visit(PlayerMapType &m);
template<class SKIP> void Visit(GridRefManager<SKIP> &) {}
explicit ObjectMessageDeliverer(WorldObject &src, WorldPacket *msg, bool to_possessor) : Deliverer(src, msg, to_possessor) {}
void VisitObject(Player* plr) { SendPacket(plr); }
};
struct TRINITY_DLL_DECL MessageDistDeliverer
struct TRINITY_DLL_DECL MessageDistDeliverer : public Deliverer
{
Player &i_player;
WorldPacket *i_message;
bool i_toSelf;
bool i_ownTeamOnly;
float i_dist;
MessageDistDeliverer(Player &pl, WorldPacket *msg, float dist, bool to_self, bool ownTeamOnly) : i_player(pl), i_message(msg), i_dist(dist), i_toSelf(to_self), i_ownTeamOnly(ownTeamOnly) {}
void Visit(PlayerMapType &m);
template<class SKIP> void Visit(GridRefManager<SKIP> &) {}
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) {}
void VisitObject(Player* plr);
};
struct TRINITY_DLL_DECL ObjectMessageDistDeliverer
struct TRINITY_DLL_DECL ObjectMessageDistDeliverer : public Deliverer
{
WorldObject &i_object;
WorldPacket *i_message;
float i_dist;
ObjectMessageDistDeliverer(WorldObject &obj, WorldPacket *msg, float dist) : i_object(obj), i_message(msg), i_dist(dist) {}
void Visit(PlayerMapType &m);
template<class SKIP> void Visit(GridRefManager<SKIP> &) {}
ObjectMessageDistDeliverer(WorldObject &obj, WorldPacket *msg, bool to_possessor, float dist) : Deliverer(obj, msg, to_possessor, dist) {}
void VisitObject(Player* plr) { SendPacket(plr); }
};
struct TRINITY_DLL_DECL ObjectUpdater
+26
View File
@@ -6544,3 +6544,29 @@ bool ChatHandler::HandleGroupRemoveCommand(const char* args)
return true;
}
bool ChatHandler::HandlePossessCommand(const char* args)
{
Unit* pUnit = getSelectedUnit();
if(!pUnit)
return false;
// Don't allow unlimited possession of players
if (pUnit->GetTypeId() == TYPEID_PLAYER)
return false;
m_session->GetPlayer()->Possess(pUnit);
return true;
}
bool ChatHandler::HandleUnPossessCommand(const char* args)
{
// Use this command to also unpossess ourselves
if (m_session->GetPlayer()->isPossessed())
m_session->GetPlayer()->UnpossessSelf(false);
else
m_session->GetPlayer()->RemovePossess(false);
return true;
}
+2
View File
@@ -217,6 +217,8 @@ $(srcdir)/PlayerDump.cpp \
$(srcdir)/PlayerDump.h \
$(srcdir)/PointMovementGenerator.cpp \
$(srcdir)/PointMovementGenerator.h \
$(srcdir)/PossessedAI.cpp \
$(srcdir)/PossessedAI.h \
$(srcdir)/QueryHandler.cpp \
$(srcdir)/QuestDef.cpp \
$(srcdir)/QuestDef.h \
+43 -10
View File
@@ -255,7 +255,7 @@ template<>
void Map::AddToGrid(Creature* obj, NGridType *grid, Cell const& cell)
{
// add to world object registry in grid
if(obj->isPet())
if(obj->isPet() || obj->isPossessedByPlayer())
{
(*grid)(cell.CellX(), cell.CellY()).AddWorldObject<Creature>(obj, obj->GetGUID());
obj->SetCurrentCell(cell);
@@ -299,7 +299,7 @@ template<>
void Map::RemoveFromGrid(Creature* obj, NGridType *grid, Cell const& cell)
{
// remove from world object registry in grid
if(obj->isPet())
if(obj->isPet() || obj->isPossessedByPlayer())
{
(*grid)(cell.CellX(), cell.CellY()).RemoveWorldObject<Creature>(obj, obj->GetGUID());
}
@@ -310,6 +310,27 @@ void Map::RemoveFromGrid(Creature* obj, NGridType *grid, Cell const& cell)
}
}
template<class T>
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());
if (active)
{
(*grid)(cell.CellX(), cell.CellY()).RemoveGridObject<T>(obj, obj->GetGUID());
(*grid)(cell.CellX(), cell.CellY()).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());
}
}
template void Map::SwitchGridContainers(Creature *, bool);
template void Map::SwitchGridContainers(Corpse *, bool);
template<class T>
void Map::DeleteFromWorld(T* obj)
{
@@ -467,7 +488,7 @@ Map::Add(T *obj)
AddNotifier(obj,cell,p);
}
void Map::MessageBroadcast(Player *player, WorldPacket *msg, bool to_self)
void Map::MessageBroadcast(Player *player, WorldPacket *msg, bool to_self, bool to_possessor)
{
CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY());
@@ -483,13 +504,13 @@ void Map::MessageBroadcast(Player *player, WorldPacket *msg, bool to_self)
if( !loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y)) )
return;
Trinity::MessageDeliverer post_man(*player, msg, to_self);
Trinity::MessageDeliverer post_man(*player, msg, to_possessor, to_self);
TypeContainerVisitor<Trinity::MessageDeliverer, WorldTypeMapContainer > message(post_man);
CellLock<ReadGuard> cell_lock(cell, p);
cell_lock->Visit(cell_lock, message, *this);
}
void Map::MessageBroadcast(WorldObject *obj, WorldPacket *msg)
void Map::MessageBroadcast(WorldObject *obj, WorldPacket *msg, bool to_possessor)
{
CellPair p = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY());
@@ -506,13 +527,13 @@ void Map::MessageBroadcast(WorldObject *obj, WorldPacket *msg)
if( !loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y)) )
return;
Trinity::ObjectMessageDeliverer post_man(msg);
Trinity::ObjectMessageDeliverer post_man(*obj, msg, to_possessor);
TypeContainerVisitor<Trinity::ObjectMessageDeliverer, WorldTypeMapContainer > message(post_man);
CellLock<ReadGuard> cell_lock(cell, p);
cell_lock->Visit(cell_lock, message, *this);
}
void Map::MessageDistBroadcast(Player *player, WorldPacket *msg, float dist, bool to_self, bool own_team_only)
void Map::MessageDistBroadcast(Player *player, WorldPacket *msg, float dist, bool to_self, bool own_team_only, bool to_possessor)
{
CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY());
@@ -528,13 +549,13 @@ void Map::MessageDistBroadcast(Player *player, WorldPacket *msg, float dist, boo
if( !loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y)) )
return;
Trinity::MessageDistDeliverer post_man(*player, msg, dist, to_self, own_team_only);
Trinity::MessageDistDeliverer post_man(*player, msg, to_possessor, dist, to_self, own_team_only);
TypeContainerVisitor<Trinity::MessageDistDeliverer , WorldTypeMapContainer > message(post_man);
CellLock<ReadGuard> cell_lock(cell, p);
cell_lock->Visit(cell_lock, message, *this);
}
void Map::MessageDistBroadcast(WorldObject *obj, WorldPacket *msg, float dist)
void Map::MessageDistBroadcast(WorldObject *obj, WorldPacket *msg, float dist, bool to_possessor)
{
CellPair p = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY());
@@ -551,7 +572,7 @@ void Map::MessageDistBroadcast(WorldObject *obj, WorldPacket *msg, float dist)
if( !loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y)) )
return;
Trinity::ObjectMessageDistDeliverer post_man(*obj, msg,dist);
Trinity::ObjectMessageDistDeliverer post_man(*obj, msg, to_possessor, dist);
TypeContainerVisitor<Trinity::ObjectMessageDistDeliverer, WorldTypeMapContainer > message(post_man);
CellLock<ReadGuard> cell_lock(cell, p);
cell_lock->Visit(cell_lock, message, *this);
@@ -649,6 +670,7 @@ Map::Remove(T *obj, bool remove)
assert( grid != NULL );
obj->RemoveFromWorld();
RemoveFromGrid(obj,grid,cell);
UpdateObjectVisibility(obj,cell,p);
@@ -697,6 +719,11 @@ Map::PlayerRelocation(Player *player, float x, float y, float z, float orientati
// if move then update what player see and who seen
UpdatePlayerVisibility(player,new_cell,new_val);
UpdateObjectsVisibilityFor(player,new_cell,new_val);
// also update what possessing player sees
if(player->isPossessedByPlayer())
UpdateObjectsVisibilityFor((Player*)player->GetCharmer(), new_cell, new_val);
PlayerRelocationNotify(player,new_cell,new_val);
NGridType* newGrid = getNGrid(new_cell.GridX(), new_cell.GridY());
if( !same_cell && newGrid->GetGridState()!= GRID_STATE_ACTIVE )
@@ -725,10 +752,16 @@ Map::CreatureRelocation(Creature *creature, float x, float y, float z, float ang
#endif
AddCreatureToMoveList(creature,x,y,z,ang);
// in diffcell/diffgrid case notifiers called at finishing move creature in Map::MoveAllCreaturesInMoveList
if(creature->isPossessedByPlayer())
EnsureGridLoadedForPlayer(new_cell, (Player*)creature->GetCharmer(), false);
}
else
{
creature->Relocate(x, y, z, ang);
// Update visibility back to player who is controlling the creature
if(creature->isPossessedByPlayer())
UpdateObjectsVisibilityFor((Player*)creature->GetCharmer(), new_cell, new_val);
CreatureRelocationNotify(creature,new_cell,new_val);
}
assert(CheckGridIntegrity(creature,true));
+6 -4
View File
@@ -140,10 +140,10 @@ class TRINITY_DLL_SPEC Map : public GridRefManager<NGridType>, public Trinity::O
virtual void Update(const uint32&);
void MessageBroadcast(Player *, WorldPacket *, bool to_self);
void MessageBroadcast(WorldObject *, WorldPacket *);
void MessageDistBroadcast(Player *, WorldPacket *, float dist, bool to_self, bool own_team_only = false);
void MessageDistBroadcast(WorldObject *, WorldPacket *, float dist);
void MessageBroadcast(Player *, WorldPacket *, bool to_self, bool to_possessor);
void MessageBroadcast(WorldObject *, WorldPacket *, bool to_possessor);
void MessageDistBroadcast(Player *, WorldPacket *, float dist, bool to_self, bool to_possessor, bool own_team_only = false);
void MessageDistBroadcast(WorldObject *, WorldPacket *, float dist, bool to_possessor);
void PlayerRelocation(Player *, float x, float y, float z, float angl);
void CreatureRelocation(Creature *creature, float x, float y, float, float);
@@ -236,6 +236,8 @@ class TRINITY_DLL_SPEC Map : public GridRefManager<NGridType>, public Trinity::O
void markCell(uint32 pCellId) { marked_cells.set(pCellId); }
Creature* GetCreatureInMap(uint64 guid);
GameObject* GetGameObjectInMap(uint64 guid);
template<class T> void SwitchGridContainers(T* obj, bool active);
private:
void LoadVMap(int pX, int pY);
void LoadMap(uint32 mapid, uint32 instanceid, int x,int y);
+76 -83
View File
@@ -189,9 +189,6 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
{
CHECK_PACKET_SIZE(recv_data, 4+1+4+4+4+4+4);
if(GetPlayer()->GetDontMove())
return;
/* extract packet */
MovementInfo movementInfo;
uint32 MovementFlags;
@@ -204,9 +201,6 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
recv_data >> movementInfo.z;
recv_data >> movementInfo.o;
//Save movement flags
_player->SetUnitMovementFlags(MovementFlags);
if(MovementFlags & MOVEMENTFLAG_ONTRANSPORT)
{
// recheck
@@ -263,6 +257,20 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
if (!Trinity::IsValidMapCoord(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o))
return;
// Handle possessed unit movement separately
Unit* pos_unit = GetPlayer()->GetCharm();
if (pos_unit && pos_unit->isPossessed()) // can be charmed but not possessed
{
HandlePossessedMovement(recv_data, movementInfo, MovementFlags);
return;
}
if (GetPlayer()->GetDontMove())
return;
//Save movement flags
GetPlayer()->SetUnitMovementFlags(MovementFlags);
/* handle special cases */
if (MovementFlags & MOVEMENTFLAG_ONTRANSPORT)
{
@@ -284,7 +292,7 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
if ((*iter)->GetGUID() == movementInfo.t_guid)
{
// unmount before boarding
_player->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
GetPlayer()->m_transport = (*iter);
(*iter)->AddPassenger(GetPlayer());
@@ -304,60 +312,9 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
movementInfo.t_time = 0;
}
// fall damage generation (ignore in flight case that can be triggred also at lags in moment teleportation to another map).
if (recv_data.GetOpcode() == MSG_MOVE_FALL_LAND && !GetPlayer()->isInFlight())
{
Player *target = GetPlayer();
//Players with Feather Fall or low fall time, or physical immunity (charges used) are ignored
if (movementInfo.fallTime > 1100 && !target->isDead() && !target->isGameMaster() &&
!target->HasAuraType(SPELL_AURA_HOVER) && !target->HasAuraType(SPELL_AURA_FEATHER_FALL) &&
!target->HasAuraType(SPELL_AURA_FLY) && !target->IsImmunedToDamage(SPELL_SCHOOL_MASK_NORMAL,true) )
{
//Safe fall, fall time reduction
int32 safe_fall = target->GetTotalAuraModifier(SPELL_AURA_SAFE_FALL);
uint32 fall_time = (movementInfo.fallTime > (safe_fall*10)) ? movementInfo.fallTime - (safe_fall*10) : 0;
if(fall_time > 1100) //Prevent damage if fall time < 1100
{
//Fall Damage calculation
float fallperc = float(fall_time)/1100;
uint32 damage = (uint32)(((fallperc*fallperc -1) / 9 * target->GetMaxHealth())*sWorld.getRate(RATE_DAMAGE_FALL));
float height = movementInfo.z;
target->UpdateGroundPositionZ(movementInfo.x,movementInfo.y,height);
if (damage > 0)
{
//Prevent fall damage from being more than the player maximum health
if (damage > target->GetMaxHealth())
damage = target->GetMaxHealth();
// Gust of Wind
if (target->GetDummyAura(43621))
damage = target->GetMaxHealth()/2;
target->EnvironmentalDamage(target->GetGUID(), DAMAGE_FALL, damage);
}
//Z given by moveinfo, LastZ, FallTime, WaterZ, MapZ, Damage, Safefall reduction
DEBUG_LOG("FALLDAMAGE z=%f sz=%f pZ=%f FallTime=%d mZ=%f damage=%d SF=%d" , movementInfo.z, height, target->GetPositionZ(), movementInfo.fallTime, height, damage, safe_fall);
}
}
//handle fall and logout at the same time (logout started before fall finished)
/* outdated and create problems with sit at stun sometime
if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE))
{
target->SetStandState(PLAYER_STATE_SIT);
// Can't move
WorldPacket data( SMSG_FORCE_MOVE_ROOT, 12 );
data.append(target->GetPackGUID());
data << (uint32)2;
SendPacket( &data );
}
*/
}
// handle fall damage
if (recv_data.GetOpcode() == MSG_MOVE_FALL_LAND)
GetPlayer()->HandleFallDamage(movementInfo);
if(((MovementFlags & MOVEMENTFLAG_SWIMMING) != 0) != GetPlayer()->IsInWater())
{
@@ -381,30 +338,66 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
if(movementInfo.z < -500.0f)
{
if(GetPlayer()->InBattleGround()
&& GetPlayer()->GetBattleGround()
&& GetPlayer()->GetBattleGround()->HandlePlayerUnderMap(_player))
{
// do nothing, the handle already did if returned true
}
else
{
// NOTE: this is actually called many times while falling
// even after the player has been teleported away
// TODO: discard movement packets after the player is rooted
if(GetPlayer()->isAlive())
{
GetPlayer()->EnvironmentalDamage(GetPlayer()->GetGUID(),DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth());
// change the death state to CORPSE to prevent the death timer from
// starting in the next player update
GetPlayer()->KillPlayer();
GetPlayer()->BuildPlayerRepop();
}
GetPlayer()->HandleFallUnderMap();
}
// cancel the death timer here if started
GetPlayer()->RepopAtGraveyard();
void WorldSession::HandlePossessedMovement(WorldPacket& recv_data, MovementInfo& movementInfo, uint32& MovementFlags)
{
// Whatever the client is controlling, it will send the GUID of the original player.
// If current player is controlling, it must be handled like the controlled player sent these opcodes
Unit* pos_unit = GetPlayer()->GetCharm();
if (pos_unit->GetTypeId() == TYPEID_PLAYER && ((Player*)pos_unit)->GetDontMove())
return;
//Save movement flags
pos_unit->SetUnitMovementFlags(MovementFlags);
// Remove possession if possessed unit enters a transport
if (MovementFlags & MOVEMENTFLAG_ONTRANSPORT)
{
GetPlayer()->RemovePossess(true);
return;
}
recv_data.put<uint32>(5, getMSTime());
WorldPacket data(recv_data.GetOpcode(), pos_unit->GetPackGUID().size()+recv_data.size());
data.append(pos_unit->GetPackGUID());
data.append(recv_data.contents(), recv_data.size());
// Send the packet to self but not to the possessed player; for creatures the first bool is irrelevant
pos_unit->SendMessageToSet(&data, true, false);
// Possessed is a player
if (pos_unit->GetTypeId() == TYPEID_PLAYER)
{
Player* plr = (Player*)pos_unit;
if (recv_data.GetOpcode() == MSG_MOVE_FALL_LAND)
plr->HandleFallDamage(movementInfo);
if(((MovementFlags & MOVEMENTFLAG_SWIMMING) != 0) != plr->IsInWater())
{
// Now client not include swimming flag in case jumping under water
plr->SetInWater( !plr->IsInWater() || plr->GetBaseMap()->IsUnderWater(movementInfo.x, movementInfo.y, movementInfo.z) );
}
plr->SetPosition(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o, false);
plr->m_movementInfo = movementInfo;
if(plr->isMovingOrTurning())
plr->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
if(movementInfo.z < -500.0f)
{
GetPlayer()->RemovePossess(false);
plr->HandleFallUnderMap();
}
}
else // Possessed unit is a creature
{
Map* map = MapManager::Instance().GetMap(pos_unit->GetMapId(), pos_unit);
map->CreatureRelocation((Creature*)pos_unit, movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o);
}
}
+4 -4
View File
@@ -1411,14 +1411,14 @@ void WorldObject::BuildTeleportAckMsg(WorldPacket *data, float x, float y, float
*data << uint32(0);
}
void WorldObject::SendMessageToSet(WorldPacket *data, bool /*bToSelf*/)
void WorldObject::SendMessageToSet(WorldPacket *data, bool /*fake*/, bool bToPossessor)
{
MapManager::Instance().GetMap(m_mapId, this)->MessageBroadcast(this, data);
MapManager::Instance().GetMap(m_mapId, this)->MessageBroadcast(this, data, bToPossessor);
}
void WorldObject::SendMessageToSetInRange(WorldPacket *data, float dist, bool /*bToSelf*/)
void WorldObject::SendMessageToSetInRange(WorldPacket *data, float dist, bool /*bToSelf*/, bool bToPossessor)
{
MapManager::Instance().GetMap(m_mapId, this)->MessageDistBroadcast(this, data, dist);
MapManager::Instance().GetMap(m_mapId, this)->MessageDistBroadcast(this, data, dist, bToPossessor);
}
void WorldObject::SendObjectDeSpawnAnim(uint64 guid)
+2 -2
View File
@@ -413,8 +413,8 @@ class TRINITY_DLL_SPEC WorldObject : public Object
float GetAngle( const float x, const float y ) const;
bool HasInArc( const float arcangle, const WorldObject* obj ) const;
virtual void SendMessageToSet(WorldPacket *data, bool self);
virtual void SendMessageToSetInRange(WorldPacket *data, float dist, bool self);
virtual void SendMessageToSet(WorldPacket *data, bool self, bool to_possessor = true);
virtual void SendMessageToSetInRange(WorldPacket *data, float dist, bool self, bool to_possessor = true);
void BuildHeartBeatMsg( WorldPacket *data ) const;
void BuildTeleportAckMsg( WorldPacket *data, float x, float y, float z, float ang) const;
bool IsBeingTeleported() { return mSemaphoreTeleport; }
+24 -2
View File
@@ -622,8 +622,30 @@ void
ObjectAccessor::WorldObjectChangeAccumulator::Visit(PlayerMapType &m)
{
for(PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
if(iter->getSource()->HaveAtClient(&i_object))
ObjectAccessor::_buildPacket(iter->getSource(), &i_object, i_updateDatas);
{
BuildPacket(iter->getSource());
if (iter->getSource()->isPossessedByPlayer())
BuildPacket((Player*)iter->getSource()->GetCharmer());
}
}
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());
}
void
ObjectAccessor::WorldObjectChangeAccumulator::BuildPacket(Player* plr)
{
// Only send update once to a player
if (plr_list.find(plr->GetGUID()) == plr_list.end() && plr->HaveAtClient(&i_object))
{
ObjectAccessor::_buildPacket(plr, &i_object, i_updateDatas);
plr_list.insert(plr->GetGUID());
}
}
void
+3
View File
@@ -208,8 +208,11 @@ class TRINITY_DLL_DECL ObjectAccessor : public Trinity::Singleton<ObjectAccessor
{
UpdateDataMapType &i_updateDatas;
WorldObject &i_object;
std::set<uint64> plr_list;
WorldObjectChangeAccumulator(WorldObject &obj, UpdateDataMapType &d) : i_updateDatas(d), i_object(obj) {}
void Visit(PlayerMapType &);
void Visit(CreatureMapType &);
void BuildPacket(Player* plr);
template<class SKIP> void Visit(GridRefManager<SKIP> &) {}
};
+1 -1
View File
@@ -548,7 +548,7 @@ void Pet::Update(uint32 diff)
{
// unsummon pet that lost owner
Unit* owner = GetOwner();
if(!owner || !IsWithinDistInMap(owner, OWNER_MAX_DISTANCE) || isControlled() && !owner->GetPetGUID())
if(!owner || (!IsWithinDistInMap(owner, OWNER_MAX_DISTANCE) && !isPossessed()) || isControlled() && !owner->GetPetGUID())
{
Remove(PET_SAVE_NOT_IN_SLOT, true);
return;
+47 -30
View File
@@ -109,7 +109,6 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )
if(pet->GetTypeId() != TYPEID_PLAYER)
{
pet->GetMotionMaster()->Clear();
if (((Creature*)pet)->AI())
((Creature*)pet)->AI()->AttackStart(TargetUnit);
@@ -139,8 +138,13 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )
//dismissing a summoned pet is like killing them (this prevents returning a soulshard...)
p->setDeathState(CORPSE);
}
else // charmed
_player->Uncharm();
else // charmed or possessed
{
if (_player->isPossessing())
_player->RemovePossess(true);
else
_player->Uncharm();
}
break;
default:
sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.\n", flag, spellid);
@@ -194,7 +198,7 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )
int16 result = spell->PetCanCast(unit_target);
//auto turn to target unless possessed
if(result == SPELL_FAILED_UNIT_NOT_INFRONT && !pet->HasAuraType(SPELL_AURA_MOD_POSSESS))
if(result == SPELL_FAILED_UNIT_NOT_INFRONT && !pet->isPossessed())
{
pet->SetInFront(unit_target);
if( unit_target->GetTypeId() == TYPEID_PLAYER )
@@ -222,7 +226,7 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )
pet->SendPetAIReaction(guid1);
}
if( unit_target && !GetPlayer()->IsFriendlyTo(unit_target) && !pet->HasAuraType(SPELL_AURA_MOD_POSSESS))
if( unit_target && !GetPlayer()->IsFriendlyTo(unit_target) && !pet->isPossessed())
{
pet->clearUnitState(UNIT_STAT_FOLLOW);
if(pet->getVictim())
@@ -236,7 +240,7 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )
}
else
{
if(pet->HasAuraType(SPELL_AURA_MOD_POSSESS))
if(pet->isPossessed())
{
WorldPacket data(SMSG_CAST_FAILED, (4+1+1));
data << uint32(spellid) << uint8(2) << uint8(result);
@@ -478,7 +482,10 @@ void WorldSession::HandlePetAbandon( WorldPacket & recv_data )
}
else if(pet->GetGUID() == _player->GetCharmGUID())
{
_player->Uncharm();
if (_player->isPossessing())
_player->RemovePossess(true);
else
_player->Uncharm();
}
}
}
@@ -601,21 +608,19 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket )
recvPacket >> guid >> spellid;
// This opcode is also sent from charmed and possessed units (players and creatures)
if(!_player->GetPet() && !_player->GetCharm())
return;
if(ObjectAccessor::FindPlayer(guid))
return;
Unit* caster = ObjectAccessor::GetUnit(*_player, guid);
Creature* pet=ObjectAccessor::GetCreatureOrPet(*_player,guid);
if(!pet || (pet != _player->GetPet() && pet!= _player->GetCharm()))
if(!caster || (caster != _player->GetPet() && caster != _player->GetCharm()))
{
sLog.outError( "HandlePetCastSpellOpcode: Pet %u isn't pet of player %s .\n", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() );
return;
}
if (pet->GetGlobalCooldown() > 0)
if (caster->GetTypeId() == TYPEID_UNIT && ((Creature*)caster)->GetGlobalCooldown() > 0)
return;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid);
@@ -626,41 +631,53 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket )
}
// do not cast not learned spells
if(!pet->HasSpell(spellid) || IsPassiveSpell(spellid))
if(!caster->HasSpell(spellid) || IsPassiveSpell(spellid))
return;
SpellCastTargets targets;
if(!targets.read(&recvPacket,pet))
if(!targets.read(&recvPacket,caster))
return;
pet->clearUnitState(UNIT_STAT_FOLLOW);
caster->clearUnitState(UNIT_STAT_FOLLOW);
Spell *spell = new Spell(pet, spellInfo, false);
Spell *spell = new Spell(caster, spellInfo, false);
spell->m_targets = targets;
int16 result = spell->PetCanCast(NULL);
if(result == -1)
{
pet->AddCreatureSpellCooldown(spellid);
if(pet->isPet())
if(caster->GetTypeId() == TYPEID_UNIT)
{
Pet* p = (Pet*)pet;
p->CheckLearning(spellid);
//10% chance to play special pet attack talk, else growl
//actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
if(p->getPetType() == SUMMON_PET && (urand(0, 100) < 10))
pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL);
else
pet->SendPetAIReaction(guid);
Creature* pet = (Creature*)caster;
pet->AddCreatureSpellCooldown(spellid);
if(pet->isPet())
{
Pet* p = (Pet*)pet;
p->CheckLearning(spellid);
// 10% chance to play special pet attack talk, else growl
// actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
if(p->getPetType() == SUMMON_PET && (urand(0, 100) < 10))
pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL);
else
pet->SendPetAIReaction(guid);
}
}
spell->prepare(&(spell->m_targets));
}
else
{
pet->SendPetCastFail(spellid, result);
if(!pet->HasSpellCooldown(spellid))
pet->SendPetClearCooldown(spellid);
caster->SendPetCastFail(spellid, result);
if(caster->GetTypeId() == TYPEID_PLAYER)
{
if(!((Player*)caster)->HasSpellCooldown(spellid))
caster->SendPetClearCooldown(spellid);
}
else
{
if(!((Creature*)caster)->HasSpellCooldown(spellid))
caster->SendPetClearCooldown(spellid);
}
spell->finish(false);
delete spell;
+270 -14
View File
@@ -469,6 +469,9 @@ Player::~Player ()
for(BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr)
itr->second.save->RemovePlayer(this);
if (isPossessing())
RemovePossess(false);
delete m_declinedname;
}
@@ -1253,7 +1256,7 @@ void Player::Update( uint32 p_time )
SendUpdateToOutOfRangeGroupMembers();
Pet* pet = GetPet();
if(pet && !IsWithinDistInMap(pet, OWNER_MAX_DISTANCE))
if(pet && !IsWithinDistInMap(pet, OWNER_MAX_DISTANCE) && !pet->isPossessed())
{
RemovePet(pet, PET_SAVE_NOT_IN_SLOT, true);
return;
@@ -1534,6 +1537,10 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
SetSemaphoreTeleport(true);
// Remove any possession on the player before teleporting
if (isPossessedByPlayer())
((Player*)GetCharmer())->RemovePossess();
// 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.
@@ -1747,6 +1754,7 @@ void Player::RemoveFromWorld()
if(IsInWorld())
{
///- Release charmed creatures, unsummon totems and remove pets/guardians
RemovePossess(false);
Uncharm();
UnsummonAllTotems();
RemoveMiniPet();
@@ -5266,19 +5274,19 @@ void Player::SaveRecallPosition()
m_recallO = GetOrientation();
}
void Player::SendMessageToSet(WorldPacket *data, bool self)
void Player::SendMessageToSet(WorldPacket *data, bool self, bool to_possessor)
{
MapManager::Instance().GetMap(GetMapId(), this)->MessageBroadcast(this, data, self);
MapManager::Instance().GetMap(GetMapId(), this)->MessageBroadcast(this, data, self, to_possessor);
}
void Player::SendMessageToSetInRange(WorldPacket *data, float dist, bool self)
void Player::SendMessageToSetInRange(WorldPacket *data, float dist, bool self, bool to_possessor)
{
MapManager::Instance().GetMap(GetMapId(), this)->MessageDistBroadcast(this, data, dist, self);
MapManager::Instance().GetMap(GetMapId(), this)->MessageDistBroadcast(this, data, dist, self, to_possessor);
}
void Player::SendMessageToSetInRange(WorldPacket *data, float dist, bool self, bool own_team_only)
void Player::SendMessageToSetInRange(WorldPacket *data, float dist, bool self, bool own_team_only, bool to_possessor)
{
MapManager::Instance().GetMap(GetMapId(), this)->MessageDistBroadcast(this, data, dist, self,own_team_only);
MapManager::Instance().GetMap(GetMapId(), this)->MessageDistBroadcast(this, data, dist, self, to_possessor, own_team_only);
}
void Player::SendDirectMessage(WorldPacket *data)
@@ -15973,7 +15981,6 @@ void Player::Uncharm()
return;
charm->RemoveSpellsCausingAura(SPELL_AURA_MOD_CHARM);
charm->RemoveSpellsCausingAura(SPELL_AURA_MOD_POSSESS);
}
void Player::BuildPlayerChat(WorldPacket *data, uint8 msgtype, std::string text, uint32 language) const
@@ -16006,7 +16013,7 @@ void Player::TextEmote(const std::string text)
{
WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildPlayerChat(&data, CHAT_MSG_EMOTE, text, LANG_UNIVERSAL);
SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),true, !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT) );
SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),true, !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT), true );
}
void Player::Whisper(std::string text, uint32 language,uint64 receiver)
@@ -18505,13 +18512,253 @@ void Player::SetCanBlock( bool value )
UpdateBlockPercentage();
}
bool ItemPosCount::isContainedIn(ItemPosCountVec const& vec) const
void Player::HandleFallDamage(MovementInfo& movementInfo)
{
for(ItemPosCountVec::const_iterator itr = vec.begin(); itr != vec.end();++itr)
if(itr->pos == this->pos)
return true;
//Players with Feather Fall or low fall time, or physical immunity (charges used) are ignored
if (!isInFlight() && movementInfo.fallTime > 1100 && !isDead() && !isGameMaster() &&
!HasAuraType(SPELL_AURA_HOVER) && !HasAuraType(SPELL_AURA_FEATHER_FALL) &&
!HasAuraType(SPELL_AURA_FLY) && !IsImmunedToDamage(SPELL_SCHOOL_MASK_NORMAL,true) )
{
//Safe fall, fall time reduction
int32 safe_fall = GetTotalAuraModifier(SPELL_AURA_SAFE_FALL);
uint32 fall_time = (movementInfo.fallTime > (safe_fall*10)) ? movementInfo.fallTime - (safe_fall*10) : 0;
return false;
if(fall_time > 1100) //Prevent damage if fall time < 1100
{
//Fall Damage calculation
float fallperc = float(fall_time)/1100;
uint32 damage = (uint32)(((fallperc*fallperc -1) / 9 * GetMaxHealth())*sWorld.getRate(RATE_DAMAGE_FALL));
float height = movementInfo.z;
UpdateGroundPositionZ(movementInfo.x,movementInfo.y,height);
if (damage > 0)
{
//Prevent fall damage from being more than the player maximum health
if (damage > GetMaxHealth())
damage = GetMaxHealth();
// Gust of Wind
if (GetDummyAura(43621))
damage = GetMaxHealth()/2;
EnvironmentalDamage(GetGUID(), DAMAGE_FALL, damage);
}
//Z given by moveinfo, LastZ, FallTime, WaterZ, MapZ, Damage, Safefall reduction
DEBUG_LOG("FALLDAMAGE z=%f sz=%f pZ=%f FallTime=%d mZ=%f damage=%d SF=%d" , movementInfo.z, height, GetPositionZ(), movementInfo.fallTime, height, damage, safe_fall);
}
}
}
void Player::HandleFallUnderMap()
{
if(InBattleGround() && GetBattleGround()
&& GetBattleGround()->HandlePlayerUnderMap(this))
{
// do nothing, the handle already did if returned true
}
else
{
// NOTE: this is actually called many times while falling
// even after the player has been teleported away
// TODO: discard movement packets after the player is rooted
if(isAlive())
{
EnvironmentalDamage(GetGUID(),DAMAGE_FALL_TO_VOID, GetMaxHealth());
// change the death state to CORPSE to prevent the death timer from
// starting in the next player update
KillPlayer();
BuildPlayerRepop();
}
// cancel the death timer here if started
RepopAtGraveyard();
}
}
void Player::Possess(Unit *target)
{
if(!target || target == this)
return;
// Don't allow possession of someone else's pet
if(target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->isPet() && target != GetPet())
return;
// Don't allow possession on transports or when in flight; also remove possession from the now-to-be-possessed
if (target->GetTypeId() == TYPEID_PLAYER)
{
if (((Player*)target)->m_transport || ((Player*)target)->isInFlight())
return;
if (target->isPossessing())
((Player*)target)->RemovePossess(true);
}
// Remove any previous possession from the target
if (target->isPossessedByPlayer())
((Player*)target->GetCharmer())->RemovePossess(false);
else if (target->isCharmed())
target->UncharmSelf(); // Target isn't possessed, but charmed; uncharm before possessing
// Remove our previous possession
if (isPossessing())
RemovePossess(true);
else if (GetCharm()) // We are charming a creature, not possessing it; uncharm ourself first
Uncharm();
// Interrupt any current casting of the target
if(target->IsNonMeleeSpellCasted(true))
target->InterruptNonMeleeSpells(true);
// Update the proper unit fields
SetPossessedTarget(target);
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);
target->GetMotionMaster()->MoveIdle();
}
target->CombatStop();
target->DeleteThreatList();
// Pets already have a properly initialized CharmInfo, don't overwrite it.
if(target->GetTypeId() == TYPEID_PLAYER || (target->GetTypeId() == TYPEID_UNIT && !((Creature*)target)->isPet()))
{
CharmInfo* charmInfo = target->InitCharmInfo(target);
charmInfo->InitPossessCreateSpells();
}
// Disable control for target player and remove AFK
if(target->GetTypeId() == TYPEID_PLAYER)
{
if(((Player*)target)->isAFK())
((Player*)target)->ToggleAFK();
((Player*)target)->SetViewport(target->GetGUID(), false);
}
// Set current viewport to target unit, controllable
SetViewport(target->GetGUID(), true);
PossessSpellInitialize();
}
void Player::RemovePossess(bool attack)
{
Unit* target = GetCharm();
if(!target || !target->isPossessed())
return;
// Remove area auras from possessed
Unit::AuraMap& tAuras = target->GetAuras();
for(Unit::AuraMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
{
if(itr->second && itr->second->IsAreaAura())
target->RemoveAura(itr);
else
++itr;
}
RemovePossessedTarget();
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())
target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, owner->getFaction());
} else
{
if(CreatureInfo const* cInfo = ((Creature*)target)->GetCreatureInfo())
target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, cInfo->faction_A);
}
}
target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNKNOWN5);
target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
SetUInt64Value(PLAYER_FARSIGHT, 0);
// Remove pet spell action bar
WorldPacket data(SMSG_PET_SPELLS, 8);
data << uint64(0);
m_session->SendPacket(&data);
// Restore original view
SetViewport(GetGUID(), true);
if(target->GetTypeId() == TYPEID_PLAYER)
((Player*)target)->SetViewport(target->GetGUID(), true);
else
{
if(((Creature*)target)->isPet())
{
((Pet*)target)->InitPetCreateSpells();
PetSpellInitialize();
}
if (target->isAlive())
{
// If we're still hostile to our target, continue attacking otherwise reset threat and go home
if (target->getVictim())
{
Unit* victim = target->getVictim();
FactionTemplateEntry const* t_faction = target->getFactionTemplateEntry();
FactionTemplateEntry const* v_faction = victim->getFactionTemplateEntry();
// Unit::IsHostileTo will always return true since the unit is always hostile to its victim
if (t_faction && v_faction && !t_faction->IsHostileTo(*v_faction))
{
// Stop combat and remove the target from the threat lists of all its victims
target->CombatStop();
target->getHostilRefManager().deleteReferences();
target->DeleteThreatList();
target->GetMotionMaster()->Clear();
target->GetMotionMaster()->MoveTargetedHome();
}
}
else if (target->GetTypeId() == TYPEID_UNIT)
{
target->GetMotionMaster()->Clear();
target->GetMotionMaster()->MoveTargetedHome();
}
// Add high amount of threat on the player
if(target != GetPet() && attack)
target->AddThreat(this, 1000000.0f);
}
// Delete the assigned possessed AI
((Creature*)target)->DeletePossessedAI();
}
}
void Player::SetViewport(uint64 guid, bool moveable)
{
WorldPacket data(SMSG_CLIENT_CONTROL_UPDATE, 8+1);
data.appendPackGUID(guid); // Packed guid of object to set client's view to
data << (moveable ? uint8(0x01) : uint8(0x00)); // 0 - can't move; 1 - can move
m_session->SendPacket(&data);
sLog.outDetail("Viewport for "I64FMT" (%s) changed to "I64FMT, GetGUID(), GetName(), guid);
}
bool Player::isAllowUseBattleGroundObject()
@@ -18524,3 +18771,12 @@ bool Player::isAllowUseBattleGroundObject()
isAlive() // live player
);
}
bool ItemPosCount::isContainedIn(ItemPosCountVec const& vec) const
{
for(ItemPosCountVec::const_iterator itr = vec.begin(); itr != vec.end();++itr)
if(itr->pos == this->pos)
return true;
return false;
}
+10 -3
View File
@@ -905,6 +905,10 @@ class TRINITY_DLL_SPEC Player : public Unit
// always active
void setActive(bool) {}
void SetViewport(uint64 guid, bool movable);
void Possess(Unit *target);
void RemovePossess(bool attack = true);
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options = 0);
bool TeleportTo(WorldLocation const &loc, uint32 options = 0)
@@ -1421,6 +1425,7 @@ class TRINITY_DLL_SPEC Player : public Unit
PlayerSpellMap const& GetSpellMap() const { return m_spells; }
PlayerSpellMap & GetSpellMap() { return m_spells; }
ActionButtonList const& GetActionButtonList() const { return m_actionButtons; }
void AddSpellMod(SpellModifier* mod, bool apply);
int32 GetTotalFlatMods(uint32 spellId, SpellModOp op);
@@ -1619,10 +1624,10 @@ class TRINITY_DLL_SPEC Player : public Unit
bool SetPosition(float x, float y, float z, float orientation, bool teleport = false);
void UpdateUnderwaterState( Map * m, float x, float y, float z );
void SendMessageToSet(WorldPacket *data, bool self);// overwrite Object::SendMessageToSet
void SendMessageToSetInRange(WorldPacket *data, float fist, bool self);
void SendMessageToSet(WorldPacket *data, bool self, bool to_possessor = true);// overwrite Object::SendMessageToSet
void SendMessageToSetInRange(WorldPacket *data, float fist, bool self, bool to_possessor = true);
// overwrite Object::SendMessageToSetInRange
void SendMessageToSetInRange(WorldPacket *data, float dist, bool self, bool own_team_only);
void SendMessageToSetInRange(WorldPacket *data, float dist, bool self, bool own_team_only, bool to_possessor);
static void DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmChars = true);
@@ -1948,6 +1953,8 @@ class TRINITY_DLL_SPEC Player : public Unit
bool IsFlying() const { return HasUnitMovementFlag(MOVEMENTFLAG_FLYING); }
void HandleDrowning();
void HandleFallDamage(MovementInfo& movementInfo);
void HandleFallUnderMap();
void SetClientControl(Unit* target, uint8 allowMove);
+124
View File
@@ -0,0 +1,124 @@
/*
* Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
*
* Thanks to the original authors: MaNGOS <http://www.mangosproject.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "PossessedAI.h"
#include "Creature.h"
#include "World.h"
void PossessedAI::AttackStart(Unit *u)
{
if( i_pet.getVictim() || !u )
return;
if(i_pet.Attack(u, true))
i_victimGuid = u->GetGUID();
// Do not autochase our target, and also make sure our current movement generator
// is removed since the motion master is reset before this function is called
i_pet.GetMotionMaster()->Clear(false);
i_pet.GetMotionMaster()->MoveIdle();
}
bool PossessedAI::_needToStop() const
{
if(!i_pet.getVictim() || !i_pet.isAlive())
return true;
// This is needed for charmed creatures, as once their target was reset other effects can trigger threat
if(i_pet.getVictim() == i_pet.GetCharmer())
return true;
return !i_pet.getVictim()->isTargetableForAttack();
}
void PossessedAI::_stopAttack()
{
if( !i_victimGuid )
return;
Unit* victim = Unit::GetUnit(i_pet, i_victimGuid );
if ( !victim )
return;
assert(!i_pet.getVictim() || i_pet.getVictim() == victim);
if( !i_pet.isAlive() )
{
i_pet.StopMoving();
i_pet.GetMotionMaster()->Clear(false);
i_pet.GetMotionMaster()->MoveIdle();
i_victimGuid = 0;
i_pet.CombatStop();
i_pet.getHostilRefManager().deleteReferences();
return;
}
i_pet.GetMotionMaster()->Clear(false);
i_pet.GetMotionMaster()->MoveIdle();
i_victimGuid = 0;
i_pet.AttackStop();
}
void PossessedAI::UpdateAI(const uint32 diff)
{
// update i_victimGuid if i_pet.getVictim() !=0 and changed
if(i_pet.getVictim())
i_victimGuid = i_pet.getVictim()->GetGUID();
// i_pet.getVictim() can't be used for check in case stop fighting, i_pet.getVictim() clear at Unit death etc.
if( i_victimGuid )
{
if( _needToStop() )
{
_stopAttack(); // i_victimGuid == 0 && i_pet.getVictim() == NULL now
return;
}
else if(i_pet.IsWithinCombatDist(i_pet.getVictim(), ATTACK_DISTANCE) && i_pet.isAttackReady())
{
i_pet.AttackerStateUpdate(i_pet.getVictim());
i_pet.resetAttackTimer();
if( _needToStop() )
_stopAttack();
}
}
}
bool PossessedAI::_isVisible(Unit *u) const
{
return i_pet.GetDistance(u) < sWorld.getConfig(CONFIG_SIGHT_MONSTER)
&& u->isVisibleForOrDetect(&i_pet,true);
}
void PossessedAI::JustDied(Unit *u)
{
// We died while possessed, disable our loot
i_pet.RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
}
void PossessedAI::KilledUnit(Unit* victim)
{
// We killed a creature, disable victim's loot
if (victim->GetTypeId() == TYPEID_UNIT)
victim->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
}
+54
View File
@@ -0,0 +1,54 @@
/*
* Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
*
* Thanks to the original authors: MaNGOS <http://www.mangosproject.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef MANGOS_POSSESSEDAI_H
#define MANGOS_POSSESSEDAI_H
#include "CreatureAI.h"
class Creature;
class TRINITY_DLL_DECL PossessedAI : public CreatureAI
{
public:
PossessedAI(Creature &c) : i_pet(c), i_victimGuid(0) {}
// Possessed creatures shouldn't aggro by themselves
void MoveInLineOfSight(Unit *) {}
void AttackStart(Unit *);
void EnterEvadeMode() {}
void JustDied(Unit*);
void KilledUnit(Unit* victim);
void AttackedBy(Unit*) {}
bool IsVisible(Unit * u) const { return _isVisible(u); }
void UpdateAI(const uint32);
// Never permit this to be used, it must always be initialized with Creature::InitPossessedAI()
static int Permissible(const Creature *) { return PERMIT_BASE_NO; }
private:
bool _isVisible(Unit *) const;
bool _needToStop(void) const;
void _stopAttack(void);
Creature &i_pet;
uint64 i_victimGuid;
};
#endif
+2 -1
View File
@@ -4121,7 +4121,8 @@ int16 Spell::PetCanCast(Unit* target)
//TARGET_DUELVSPLAYER is positive AND negative
duelvsplayertar |= (m_spellInfo->EffectImplicitTargetA[j] == TARGET_DUELVSPLAYER);
}
if(m_caster->IsFriendlyTo(target) && !duelvsplayertar)
// AoE spells have the caster as their target
if(m_caster->IsFriendlyTo(target) && m_caster != target && !duelvsplayertar)
{
return SPELL_FAILED_BAD_TARGETS;
}
+1
View File
@@ -240,6 +240,7 @@ class Spell
void EffectDualWield(uint32 i);
void EffectPickPocket(uint32 i);
void EffectAddFarsight(uint32 i);
void EffectSummonPossessed(uint32 i);
void EffectSummonWild(uint32 i);
void EffectSummonGuardian(uint32 i);
void EffectHealMechanical(uint32 i);
+16 -54
View File
@@ -49,6 +49,7 @@
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
#include "TemporarySummon.h"
#define NULL_AURA_SLOT 0xFF
@@ -527,8 +528,8 @@ void Aura::Update(uint32 diff)
}
}
// Channeled aura required check distance from caster
if(IsChanneledSpell(m_spellProto) && m_caster_guid != m_target->GetGUID())
// Channeled aura required check distance from caster except in possessed cases
if(IsChanneledSpell(m_spellProto) && m_caster_guid != m_target->GetGUID() && !m_target->isPossessed())
{
Unit* caster = GetCaster();
if(!caster)
@@ -2003,6 +2004,7 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
caster->CastSpell(m_target,finalSpelId,true,NULL,this);
return;
}
// Dark Fiend
if(GetId()==45934)
{
@@ -2018,6 +2020,13 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
m_target->CastSpell(m_target,47287,true,NULL,this);
return;
}
// Eye of Kilrogg, unsummon eye when aura is gone
if(GetId() == 126 && caster->GetTypeId() == TYPEID_PLAYER && caster->GetCharm())
{
((TemporarySummon*)caster->GetCharm())->UnSummon();
return;
}
}
// AT APPLY & REMOVE
@@ -2886,56 +2895,11 @@ void Aura::HandleModPossess(bool apply, bool Real)
if( apply )
{
m_target->SetCharmerGUID(GetCasterGUID());
m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,caster->getFaction());
caster->SetCharm(m_target);
m_target->CombatStop();
m_target->DeleteThreatList();
if(m_target->GetTypeId() == TYPEID_UNIT)
{
m_target->StopMoving();
m_target->GetMotionMaster()->Clear();
m_target->GetMotionMaster()->MoveIdle();
CharmInfo *charmInfo = ((Creature*)m_target)->InitCharmInfo(m_target);
charmInfo->InitPossessCreateSpells();
}
if(caster->GetTypeId() == TYPEID_PLAYER)
{
((Player*)caster)->PossessSpellInitialize();
}
if (caster->GetTypeId() == TYPEID_PLAYER)
((Player*)caster)->Possess(m_target);
}
else
{
m_target->SetCharmerGUID(0);
if(m_target->GetTypeId() == TYPEID_PLAYER)
((Player*)m_target)->setFactionForRace(m_target->getRace());
else if(m_target->GetTypeId() == TYPEID_UNIT)
{
CreatureInfo const *cinfo = ((Creature*)m_target)->GetCreatureInfo();
m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,cinfo->faction_A);
}
caster->SetCharm(0);
if(caster->GetTypeId() == TYPEID_PLAYER)
{
WorldPacket data(SMSG_PET_SPELLS, 8);
data << uint64(0);
((Player*)caster)->GetSession()->SendPacket(&data);
}
if(m_target->GetTypeId() == TYPEID_UNIT)
{
((Creature*)m_target)->AIM_Initialize();
if (((Creature*)m_target)->AI())
((Creature*)m_target)->AI()->AttackStart(caster);
}
}
if(caster->GetTypeId() == TYPEID_PLAYER)
caster->SetUInt64Value(PLAYER_FARSIGHT,apply ? m_target->GetGUID() : 0);
m_target->UnpossessSelf(true);
}
void Aura::HandleModPossessPet(bool apply, bool Real)
@@ -2951,13 +2915,11 @@ void Aura::HandleModPossessPet(bool apply, bool Real)
if(apply)
{
caster->SetUInt64Value(PLAYER_FARSIGHT, m_target->GetGUID());
m_target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNKNOWN5);
((Player*)caster)->Possess(m_target);
}
else
{
caster->SetUInt64Value(PLAYER_FARSIGHT, 0);
m_target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNKNOWN5);
((Player*)caster)->RemovePossess(false);
}
}
+26 -2
View File
@@ -132,7 +132,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
&Spell::EffectPull, // 70 SPELL_EFFECT_PULL one spell: Distract Move
&Spell::EffectPickPocket, // 71 SPELL_EFFECT_PICKPOCKET
&Spell::EffectAddFarsight, // 72 SPELL_EFFECT_ADD_FARSIGHT
&Spell::EffectSummonGuardian, // 73 SPELL_EFFECT_SUMMON_POSSESSED
&Spell::EffectSummonPossessed, // 73 SPELL_EFFECT_SUMMON_POSSESSED
&Spell::EffectSummonTotem, // 74 SPELL_EFFECT_SUMMON_TOTEM
&Spell::EffectHealMechanical, // 75 SPELL_EFFECT_HEAL_MECHANICAL one spell: Mechanical Patch Kit
&Spell::EffectSummonObjectWild, // 76 SPELL_EFFECT_SUMMON_OBJECT_WILD
@@ -3127,9 +3127,11 @@ void Spell::EffectSummonType(uint32 i)
switch(m_spellInfo->EffectMiscValueB[i])
{
case SUMMON_TYPE_GUARDIAN:
EffectSummonGuardian(i);
break;
case SUMMON_TYPE_POSESSED:
case SUMMON_TYPE_POSESSED2:
EffectSummonGuardian(i);
EffectSummonPossessed(i);
break;
case SUMMON_TYPE_WILD:
EffectSummonWild(i);
@@ -3677,6 +3679,28 @@ void Spell::EffectSummonGuardian(uint32 i)
}
}
void Spell::EffectSummonPossessed(uint32 i)
{
uint32 creatureEntry = m_spellInfo->EffectMiscValue[i];
if(!creatureEntry)
return;
if(m_caster->GetTypeId() != TYPEID_PLAYER)
return;
uint32 level = m_caster->getLevel();
float px, py, pz;
m_caster->GetClosePoint(px, py, pz, DEFAULT_WORLD_OBJECT_SIZE);
int32 duration = GetSpellDuration(m_spellInfo);
TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_OR_DEAD_DESPAWN;
Creature* c = m_caster->SummonCreature(creatureEntry, px, py, pz, m_caster->GetOrientation(), summonType, duration);
((Player*)m_caster)->Possess(c);
}
void Spell::EffectTeleUnitsFaceCaster(uint32 i)
{
if(!unitTarget)
+19
View File
@@ -302,6 +302,10 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
return;
}
// can't use our own spells when we're in possession of another unit,
if(_player->isPossessing())
return;
// client provided targets
SpellCastTargets targets;
if(!targets.read(&recvPacket,_player))
@@ -348,6 +352,21 @@ void WorldSession::HandleCancelAuraOpcode( WorldPacket& recvPacket)
if (!spellInfo)
return;
// Remove possess aura from the possessed as well
if(_player->isPossessing())
{
for (int i = 0; i < 3; ++i)
{
if (spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_POSSESS ||
spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_POSSESS_PET)
{
_player->RemoveAurasDueToSpellByCancel(spellId);
_player->GetCharm()->RemoveAurasDueToSpellByCancel(spellId);
return;
}
}
}
// not allow remove non positive spells and spells with attr SPELL_ATTR_CANT_CANCEL
if(!IsPositiveSpell(spellId) || (spellInfo->Attributes & SPELL_ATTR_CANT_CANCEL))
return;
+2
View File
@@ -174,6 +174,8 @@ void TemporarySummon::UnSummon()
{
CombatStop();
UnpossessSelf(false);
CleanupsBeforeDelete();
AddObjectToRemoveList();
+60 -20
View File
@@ -226,6 +226,7 @@ Unit::Unit()
m_removedAuras = 0;
m_charmInfo = NULL;
m_unit_movement_flags = 0;
m_isPossessed = false;
// remove aurastates allowing special moves
for(int i=0; i < MAX_REACTIVE; ++i)
@@ -701,10 +702,6 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
if( pVictim->GetTypeId()==TYPEID_PLAYER && !damageFromSpiritOfRedemtionTalent )
((Player*)pVictim)->SetPvPDeath(player!=NULL);
// Call KilledUnit for creatures
if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->AI())
((Creature*)this)->AI()->KilledUnit(pVictim);
// 10% durability loss on death
// clean InHateListOf
if (pVictim->GetTypeId() == TYPEID_PLAYER)
@@ -718,6 +715,9 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0);
((Player*)pVictim)->GetSession()->SendPacket(&data);
}
// Call KilledUnit for creatures
if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->AI())
((Creature*)this)->AI()->KilledUnit(pVictim);
}
else // creature died
{
@@ -729,6 +729,11 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
cVictim->DeleteThreatList();
cVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
}
// Call KilledUnit for creatures, this needs to be called after the lootable flag is set
if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->AI())
((Creature*)this)->AI()->KilledUnit(pVictim);
// Call creature just died function
if (cVictim->AI())
cVictim->AI()->JustDied(this);
@@ -773,6 +778,13 @@ 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()))
{
@@ -7169,6 +7181,29 @@ void Unit::SetCharm(Unit* charmed)
SetUInt64Value(UNIT_FIELD_CHARM,charmed ? charmed->GetGUID() : 0);
}
void Unit::UncharmSelf()
{
if (!GetCharmer())
return;
RemoveSpellsCausingAura(SPELL_AURA_MOD_CHARM);
}
void Unit::UnpossessSelf(bool attack)
{
if (!isPossessed() || !GetCharmer())
return;
if (GetCharmer()->GetTypeId() == TYPEID_PLAYER)
((Player*)GetCharmer())->RemovePossess(attack);
else
{
GetCharmer()->SetCharm(0);
SetCharmerGUID(0);
m_isPossessed = false;
}
}
void Unit::UnsummonAllTotems()
{
for (int8 i = 0; i < MAX_TOTEM; ++i)
@@ -8588,16 +8623,19 @@ bool Unit::isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList)
return false;
}
// If the player is currently possessing, update visibility from the possessed unit's location
const Unit* target = u->GetTypeId() == TYPEID_PLAYER && u->isPossessing() ? u->GetCharm() : u;
// different visible distance checks
if(u->isInFlight()) // what see player in flight
{
// use object grey distance for all (only see objects any way)
if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceInFlight()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f)))
if (!IsWithinDistInMap(target,World::GetMaxVisibleDistanceInFlight()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f)))
return false;
}
else if(!isAlive()) // distance for show body
{
if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f)))
if (!IsWithinDistInMap(target,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f)))
return false;
}
else if(GetTypeId()==TYPEID_PLAYER) // distance for show player
@@ -8605,14 +8643,14 @@ bool Unit::isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList)
if(u->GetTypeId()==TYPEID_PLAYER)
{
// Players far than max visible distance for player or not in our map are not visible too
if (!at_same_transport && !IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f)))
if (!at_same_transport && !IsWithinDistInMap(target,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f)))
return false;
}
else
{
// Units far than max visible distance for creature or not in our map are not visible too
// Active unit should always be visibile
if (!IsWithinDistInMap(u, u->isActive()
if (!IsWithinDistInMap(target, target->isActive()
? (MAX_VISIBILITY_DISTANCE - (inVisibleList ? 0.0f : World::GetVisibleUnitGreyDistance()))
: (World::GetMaxVisibleDistanceForCreature() + (inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f))))
return false;
@@ -8621,13 +8659,13 @@ bool Unit::isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList)
else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed
{
// Pet/charmed far than max visible distance for player or not in our map are not visible too
if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f)))
if (!IsWithinDistInMap(target,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f)))
return false;
}
else // distance for show creature
{
// Units far than max visible distance for creature or not in our map are not visible too
if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f)))
if (!IsWithinDistInMap(target,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f)))
return false;
}
@@ -9871,6 +9909,8 @@ void Unit::CleanupsBeforeDelete()
RemoveAllGameObjects();
RemoveAllDynObjects();
GetMotionMaster()->Clear(false); // remove different non-standard movement generators.
UnpossessSelf(false);
}
RemoveFromWorld();
}
@@ -9923,17 +9963,17 @@ void CharmInfo::InitEmptyActionBar()
void CharmInfo::InitPossessCreateSpells()
{
if(m_unit->GetTypeId() == TYPEID_PLAYER)
return;
InitEmptyActionBar(); //charm action bar
for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x)
InitEmptyActionBar();
if(m_unit->GetTypeId() == TYPEID_UNIT)
{
if (IsPassiveSpell(((Creature*)m_unit)->m_spells[x]))
m_unit->CastSpell(m_unit, ((Creature*)m_unit)->m_spells[x], true);
else
AddSpellToAB(0, ((Creature*)m_unit)->m_spells[x], ACT_CAST);
for(uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i)
{
uint32 spellid = ((Creature*)m_unit)->m_spells[i];
if(IsPassiveSpell(spellid))
m_unit->CastSpell(m_unit, spellid, true);
else
AddSpellToAB(0, spellid, ACT_CAST);
}
}
}
+23
View File
@@ -989,10 +989,32 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void SetPet(Pet* pet);
void SetCharm(Unit* pet);
void SetPossessedTarget(Unit* target)
{
if (!target) return;
SetCharm(target);
target->SetCharmerGUID(GetGUID());
target->m_isPossessed = true;
}
void RemovePossessedTarget()
{
if (!GetCharm()) return;
GetCharm()->SetCharmerGUID(0);
GetCharm()->m_isPossessed = false;
SetCharm(0);
}
bool isCharmed() const { return GetCharmerGUID() != 0; }
bool isPossessed() const { return m_isPossessed; }
bool isPossessedByPlayer() const { return m_isPossessed && IS_PLAYER_GUID(GetCharmerGUID()); }
bool isPossessing() const { return GetCharm() && GetCharm()->isPossessed(); }
bool isPossessing(Unit* u) const { return u->isPossessed() && GetCharmGUID() == u->GetGUID(); }
bool isPossessingCreature() const { return isPossessing() && IS_CREATURE_GUID(GetCharmGUID()); }
CharmInfo* GetCharmInfo() { return m_charmInfo; }
CharmInfo* InitCharmInfo(Unit* charm);
void UncharmSelf();
void UnpossessSelf(bool attack);
Pet* CreateTamedPetFrom(Creature* creatureTarget,uint32 spell_id = 0);
@@ -1316,6 +1338,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
float m_speed_rate[MAX_MOVE_TYPE];
CharmInfo *m_charmInfo;
bool m_isPossessed;
virtual SpellSchoolMask GetMeleeDamageSchoolMask() const;
+7
View File
@@ -366,6 +366,13 @@ void WorldSession::LogoutPlayer(bool Save)
if(_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && m_Socket)
_player->RemoveFromGroup();
// Unpossess the current possessed unit of player
if (_player->isPossessing())
_player->RemovePossess(false);
// Remove any possession of this player on logout
_player->UnpossessSelf(false);
///- Remove the player from the world
// the player may not be in the world when logging out
// e.g if he got disconnected during a transfer to another map
+2
View File
@@ -31,6 +31,7 @@ class MailItemsInfo;
struct ItemPrototype;
struct AuctionEntry;
struct DeclinedName;
struct MovementInfo;
class Creature;
class Item;
@@ -317,6 +318,7 @@ class TRINITY_DLL_SPEC WorldSession
void HandleMoveWorldportAckOpcode(); // for server-side calls
void HandleMovementOpcodes(WorldPacket& recvPacket);
void HandlePossessedMovement(WorldPacket& recv_data, MovementInfo& movementInfo, uint32& MovementFlags);
void HandleSetActiveMoverOpcode(WorldPacket &recv_data);
void HandleMoveTimeSkippedOpcode(WorldPacket &recv_data);
+8
View File
@@ -732,6 +732,14 @@
<File
RelativePath="..\..\src\game\PointMovementGenerator.h">
</File>
<File
RelativePath="..\..\src\game\PossessedAI.cpp"
>
</File>
<File
RelativePath="..\..\src\game\PossessedAI.h"
>
</File>
<File
RelativePath="..\..\src\game\RandomMovementGenerator.cpp">
</File>
+8
View File
@@ -1126,6 +1126,14 @@
RelativePath="..\..\src\game\PointMovementGenerator.cpp"
>
</File>
<File
RelativePath="..\..\src\game\PossessedAI.cpp"
>
</File>
<File
RelativePath="..\..\src\game\PossessedAI.h"
>
</File>
<File
RelativePath="..\..\src\game\PointMovementGenerator.h"
>
+96 -88
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Version="9.00"
Name="game"
ProjectGUID="{1DC6C4DA-A028-41F3-877D-D5400C594F88}"
RootNamespace="game"
@@ -48,90 +48,7 @@
AdditionalOptions="/MP"
Optimization="0"
AdditionalIncludeDirectories="..\..\dep\include;..\..\src\framework;..\..\src\shared;..\..\src\shared\vmap;..\..\dep\ACE_wrappers"
PreprocessorDefinitions="WIN32;_DEBUG;MANGOS_DEBUG;_LIB;"
StringPooling="false"
MinimalRebuild="false"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
EnableFunctionLevelLinking="true"
RuntimeTypeInfo="true"
UsePrecompiledHeader="0"
PrecompiledHeaderFile=".\game__$(PlatformName)_$(ConfigurationName)\game.pch"
AssemblerListingLocation=".\game__$(PlatformName)_$(ConfigurationName)\"
ObjectFile=".\game__$(PlatformName)_$(ConfigurationName)\"
ProgramDataBaseFileName=".\game__$(PlatformName)_$(ConfigurationName)\"
WarningLevel="3"
SuppressStartupBanner="true"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="3"
CallingConvention="0"
CompileAs="0"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1033"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
AdditionalDependencies=".\shared__$(PlatformName)_$(ConfigurationName)\shared.lib"
OutputFile=".\game__$(PlatformName)_$(ConfigurationName)\game.lib"
SuppressStartupBanner="true"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Debug|x64"
OutputDirectory=".\game__$(PlatformName)_$(ConfigurationName)"
IntermediateDirectory=".\game__$(PlatformName)_$(ConfigurationName)"
ConfigurationType="4"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
AdditionalIncludeDirectories="..\..\dep\include;..\..\src\framework;..\..\src\shared;..\..\src\shared\vmap;..\..\dep\ACE_wrappers"
PreprocessorDefinitions="WIN32;_DEBUG;MANGOS_DEBUG;_LIB;"
PreprocessorDefinitions="WIN32;_DEBUG;TRINITY_DEBUG;_LIB;"
StringPooling="false"
MinimalRebuild="false"
BasicRuntimeChecks="3"
@@ -213,9 +130,11 @@
AdditionalOptions="/MP"
InlineFunctionExpansion="1"
AdditionalIncludeDirectories="..\..\dep\include;..\..\src\framework;..\..\src\shared;..\..\src\shared\vmap;..\..\dep\ACE_wrappers"
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;"
StringPooling="true"
RuntimeLibrary="2"
PreprocessorDefinitions="WIN32;_DEBUG;MANGOS_DEBUG;_LIB;"
StringPooling="false"
MinimalRebuild="false"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
EnableFunctionLevelLinking="true"
EnableEnhancedInstructionSet="1"
FloatingPointModel="2"
@@ -265,6 +184,87 @@
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Debug|x64"
OutputDirectory=".\game__$(PlatformName)_$(ConfigurationName)"
IntermediateDirectory=".\game__$(PlatformName)_$(ConfigurationName)"
ConfigurationType="4"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
AdditionalIncludeDirectories="..\..\dep\include;..\..\src\framework;..\..\src\shared;..\..\src\shared\vmap;..\..\dep\ACE_wrappers"
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;"
StringPooling="true"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
RuntimeTypeInfo="true"
UsePrecompiledHeader="0"
PrecompiledHeaderFile=".\game__$(PlatformName)_$(ConfigurationName)\game.pch"
AssemblerListingLocation=".\game__$(PlatformName)_$(ConfigurationName)\"
ObjectFile=".\game__$(PlatformName)_$(ConfigurationName)\"
ProgramDataBaseFileName=".\game__$(PlatformName)_$(ConfigurationName)\"
WarningLevel="3"
SuppressStartupBanner="true"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="3"
CallingConvention="0"
CompileAs="0"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1033"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
AdditionalDependencies=".\shared__$(PlatformName)_$(ConfigurationName)\shared.lib"
OutputFile=".\game__$(PlatformName)_$(ConfigurationName)\game.lib"
SuppressStartupBanner="true"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|x64"
OutputDirectory=".\game__$(PlatformName)_$(ConfigurationName)"
@@ -1135,6 +1135,14 @@
RelativePath="..\..\src\game\PointMovementGenerator.h"
>
</File>
<File
RelativePath="..\..\src\game\PossessedAI.cpp"
>
</File>
<File
RelativePath="..\..\src\game\PossessedAI.h"
>
</File>
<File
RelativePath="..\..\src\game\RandomMovementGenerator.cpp"
>