mirror of
https://github.com/araxiaonline/TrinityCore2.git
synced 2026-06-18 05:49:41 -04:00
[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:
@@ -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);
|
||||
|
||||
|
||||
@@ -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 }
|
||||
};
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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; }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -174,6 +174,8 @@ void TemporarySummon::UnSummon()
|
||||
{
|
||||
CombatStop();
|
||||
|
||||
UnpossessSelf(false);
|
||||
|
||||
CleanupsBeforeDelete();
|
||||
AddObjectToRemoveList();
|
||||
|
||||
|
||||
+60
-20
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user