*Merge.
--HG-- branch : trunk
This commit is contained in:
@@ -316,9 +316,9 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
|
||||
break;
|
||||
|
||||
Group *group = GetPlayer()->GetGroup();
|
||||
if(!group || !group->isRaidGroup())
|
||||
if(!group || !group->isRaidGroup() || group->isBGGroup())
|
||||
return;
|
||||
|
||||
|
||||
WorldPacket data;
|
||||
ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID, lang, "", 0, msg.c_str(),NULL);
|
||||
group->BroadcastPacket(&data);
|
||||
@@ -342,7 +342,7 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
|
||||
break;
|
||||
|
||||
Group *group = GetPlayer()->GetGroup();
|
||||
if(!group || !group->isRaidGroup() || !group->IsLeader(GetPlayer()->GetGUID()))
|
||||
if(!group || !group->isRaidGroup() || !group->IsLeader(GetPlayer()->GetGUID()) || group->isBGGroup())
|
||||
return;
|
||||
|
||||
WorldPacket data;
|
||||
@@ -362,7 +362,7 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
|
||||
break;
|
||||
|
||||
Group *group = GetPlayer()->GetGroup();
|
||||
if(!group || !group->isRaidGroup() || !(group->IsLeader(GetPlayer()->GetGUID()) || group->IsAssistant(GetPlayer()->GetGUID())))
|
||||
if(!group || !group->isRaidGroup() || !(group->IsLeader(GetPlayer()->GetGUID()) || group->IsAssistant(GetPlayer()->GetGUID())) || group->isBGGroup())
|
||||
return;
|
||||
|
||||
WorldPacket data;
|
||||
@@ -383,7 +383,7 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
|
||||
break;
|
||||
|
||||
Group *group = GetPlayer()->GetGroup();
|
||||
if(!group || !group->isRaidGroup())
|
||||
if(!group || !group->isRaidGroup() || !group->isBGGroup())
|
||||
return;
|
||||
|
||||
WorldPacket data;
|
||||
@@ -404,7 +404,7 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
|
||||
break;
|
||||
|
||||
Group *group = GetPlayer()->GetGroup();
|
||||
if(!group || !group->isRaidGroup() || !group->IsLeader(GetPlayer()->GetGUID()))
|
||||
if(!group || !group->isRaidGroup() || !group->IsLeader(GetPlayer()->GetGUID()) || !group->isBGGroup())
|
||||
return;
|
||||
|
||||
WorldPacket data;
|
||||
@@ -587,4 +587,4 @@ void WorldSession::HandleChatIgnoredOpcode(WorldPacket& recv_data )
|
||||
void WorldSession::HandleChannelDeclineInvite(WorldPacket &recvPacket)
|
||||
{
|
||||
sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -594,10 +594,6 @@ bool Creature::AIM_Initialize(CreatureAI* ai)
|
||||
return false;
|
||||
}
|
||||
|
||||
// don't allow AI switch when possessed
|
||||
if (isPossessed())
|
||||
return false;
|
||||
|
||||
CreatureAI * oldAI = i_AI;
|
||||
i_motionMaster.Initialize();
|
||||
i_AI = ai ? ai : FactorySelector::selectAI(this);
|
||||
@@ -621,6 +617,8 @@ void Creature::DisablePossessedAI()
|
||||
{
|
||||
if (!i_AI_possessed) return;
|
||||
|
||||
delete i_AI_possessed;
|
||||
|
||||
// Signal the old AI that it's been re-enabled
|
||||
i_AI->OnPossess(false);
|
||||
}
|
||||
@@ -1158,6 +1156,7 @@ void Creature::SetLootRecipient(Unit *unit)
|
||||
if (!unit)
|
||||
{
|
||||
m_lootRecipient = 0;
|
||||
RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
|
||||
RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_OTHER_TAGGER);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,45 @@
|
||||
*/
|
||||
|
||||
#include "CreatureAI.h"
|
||||
#include "Creature.h"
|
||||
#include "Pet.h"
|
||||
#include "SpellAuras.h"
|
||||
|
||||
CreatureAI::~CreatureAI()
|
||||
{
|
||||
}
|
||||
|
||||
SimpleCharmedAI::SimpleCharmedAI(Unit &u) : me(u)
|
||||
{
|
||||
}
|
||||
|
||||
void SimpleCharmedAI::UpdateAI(const uint32 /*diff*/)
|
||||
{
|
||||
Creature *charmer = (Creature*)me.GetCharmer();
|
||||
|
||||
//kill self if charm aura has infinite duration
|
||||
if(charmer->IsInEvadeMode())
|
||||
{
|
||||
Unit::AuraList const& auras = me.GetAurasByType(SPELL_AURA_MOD_CHARM);
|
||||
for(Unit::AuraList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
|
||||
if((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->IsPermanent())
|
||||
{
|
||||
charmer->Kill(&me);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(!charmer->isInCombat())
|
||||
me.GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
|
||||
|
||||
Unit *target = me.getVictim();
|
||||
if(!target || !charmer->canAttack(target))
|
||||
{
|
||||
target = charmer->SelectNearestTarget();
|
||||
if(!target)
|
||||
return;
|
||||
|
||||
me.GetMotionMaster()->MoveChase(target);
|
||||
me.Attack(target, true);
|
||||
}
|
||||
}
|
||||
|
||||
+16
-1
@@ -69,7 +69,22 @@ enum SelectAggroTarget
|
||||
SELECT_TARGET_FARTHEST,
|
||||
};
|
||||
|
||||
class TRINITY_DLL_SPEC CreatureAI
|
||||
class TRINITY_DLL_SPEC UnitAI
|
||||
{
|
||||
public:
|
||||
virtual void UpdateAI(const uint32 diff) = 0;
|
||||
};
|
||||
|
||||
class TRINITY_DLL_SPEC SimpleCharmedAI
|
||||
{
|
||||
public:
|
||||
SimpleCharmedAI(Unit &u);
|
||||
virtual void UpdateAI(const uint32 diff);
|
||||
private:
|
||||
Unit &me;
|
||||
};
|
||||
|
||||
class TRINITY_DLL_SPEC CreatureAI : public UnitAI
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
@@ -34,6 +34,9 @@ namespace FactorySelector
|
||||
{
|
||||
CreatureAI* selectAI(Creature *creature)
|
||||
{
|
||||
//if(creature->isPossessed())
|
||||
// creature->InitPossessedAI();
|
||||
|
||||
// Allow scripting AI for normal creatures and not controlled pets (guardians and mini-pets)
|
||||
if((!creature->isPet() || !((Pet*)creature)->isControlled()) && !creature->isCharmed())
|
||||
if(CreatureAI* scriptedAI = Script->GetAI(creature))
|
||||
@@ -62,8 +65,6 @@ namespace FactorySelector
|
||||
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
|
||||
|
||||
@@ -63,4 +63,4 @@ extern UNORDERED_MAP<uint32, FormationMember*> CreatureGroupMap;
|
||||
|
||||
#define formation_mgr Trinity::Singleton<CreatureGroupManager>::Instance()
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+2
-6
@@ -6889,7 +6889,7 @@ bool ChatHandler::HandlePossessCommand(const char* args)
|
||||
if (pUnit->GetTypeId() == TYPEID_PLAYER)
|
||||
return false;
|
||||
|
||||
m_session->GetPlayer()->Possess(pUnit);
|
||||
pUnit->SetCharmedOrPossessedBy(m_session->GetPlayer(), true);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -6897,11 +6897,7 @@ bool ChatHandler::HandlePossessCommand(const char* args)
|
||||
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);
|
||||
|
||||
m_session->GetPlayer()->RemoveCharmedOrPossessedBy(NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1403,7 +1403,7 @@ bool Map::CheckGridIntegrity(Creature* c, bool moved) const
|
||||
Cell xy_cell(xy_val);
|
||||
if(xy_cell != cur_cell)
|
||||
{
|
||||
sLog.outError("ERROR: %s (GUID: %u) X: %f Y: %f (%s) in grid[%u,%u]cell[%u,%u] instead grid[%u,%u]cell[%u,%u]",
|
||||
sLog.outDebug("ERROR: %s (GUID: %u) X: %f Y: %f (%s) in grid[%u,%u]cell[%u,%u] instead grid[%u,%u]cell[%u,%u]",
|
||||
(c->GetTypeId()==TYPEID_PLAYER ? "Player" : "Creature"),c->GetGUIDLow(),
|
||||
c->GetPositionX(),c->GetPositionY(),(moved ? "final" : "original"),
|
||||
cur_cell.GridX(), cur_cell.GridY(), cur_cell.CellX(), cur_cell.CellY(),
|
||||
|
||||
@@ -247,17 +247,23 @@ MapManager::Update(time_t diff)
|
||||
if( !i_timer.Passed() )
|
||||
return;
|
||||
|
||||
sWorld.RecordTimeDiff(NULL);
|
||||
ObjectAccessor::Instance().UpdatePlayers(i_timer.GetCurrent());
|
||||
sWorld.RecordTimeDiff("UpdatePlayers");
|
||||
|
||||
|
||||
for(MapMapType::iterator iter=i_maps.begin(); iter != i_maps.end(); ++iter)
|
||||
{
|
||||
checkAndCorrectGridStatesArray(); // debugging code, should be deleted some day
|
||||
iter->second->Update(i_timer.GetCurrent());
|
||||
sWorld.RecordTimeDiff("UpdateMap %u", iter->second->GetId());
|
||||
}
|
||||
|
||||
ObjectAccessor::Instance().Update(i_timer.GetCurrent());
|
||||
sWorld.RecordTimeDiff("UpdateObjectAccessor");
|
||||
for (TransportSet::iterator iter = m_Transports.begin(); iter != m_Transports.end(); ++iter)
|
||||
(*iter)->Update(i_timer.GetCurrent());
|
||||
sWorld.RecordTimeDiff("UpdateTransports");
|
||||
|
||||
i_timer.SetCurrent(0);
|
||||
}
|
||||
|
||||
@@ -1648,3 +1648,15 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float &x, float &y,
|
||||
|
||||
UpdateGroundPositionZ(x,y,z);
|
||||
}
|
||||
|
||||
void WorldObject::GetClosePointAt(float &x, float &y, float &z, float dist, float angle)
|
||||
{
|
||||
angle += GetOrientation();
|
||||
x += dist * cos(angle);
|
||||
y += dist * sin(angle);
|
||||
Trinity::NormalizeMapCoord(x);
|
||||
Trinity::NormalizeMapCoord(y);
|
||||
UpdateGroundPositionZ(x, y, z);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -394,6 +394,12 @@ class TRINITY_DLL_SPEC WorldObject : public Object
|
||||
// angle calculated from current orientation
|
||||
GetNearPoint(NULL,x,y,z,size,distance2d,GetOrientation() + angle);
|
||||
}
|
||||
void GetClosePointAt(float &x, float &y, float &z, float dist, float angle);
|
||||
void GetClosePoint(float &x, float &y, float &z, float dist, float angle)
|
||||
{
|
||||
GetPosition(x, y, z);
|
||||
GetClosePointAt(x, y, z, dist, angle);
|
||||
}
|
||||
void GetContactPoint( const WorldObject* obj, float &x, float &y, float &z, float distance2d = CONTACT_DISTANCE) const
|
||||
{
|
||||
// angle to face `obj` to `this` using distance includes size of `obj`
|
||||
|
||||
+7
-145
@@ -1746,6 +1746,9 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
|
||||
|
||||
ResetContestedPvP();
|
||||
|
||||
DestroyForNearbyPlayers();
|
||||
m_clientGUIDs.clear();
|
||||
|
||||
// remove player from battleground on far teleport (when changing maps)
|
||||
if(BattleGround const* bg = GetBattleGround())
|
||||
{
|
||||
@@ -19512,150 +19515,12 @@ void Player::HandleFallUnderMap()
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// Start channeling packets to possessor
|
||||
target->AddPlayerToVision(this);
|
||||
|
||||
target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, getFaction());
|
||||
target->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
|
||||
target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNKNOWN5);
|
||||
target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
|
||||
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
|
||||
|
||||
if(target->GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
((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;
|
||||
if(Unit *u = GetCharm())
|
||||
u->RemoveCharmedOrPossessedBy(this);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Interrupt any current casting of the target
|
||||
if(target->IsNonMeleeSpellCasted(true))
|
||||
target->InterruptNonMeleeSpells(true);
|
||||
|
||||
RemovePossessedTarget();
|
||||
|
||||
// Stop channeling packets back to possessor
|
||||
target->RemovePlayerFromVision(this);
|
||||
|
||||
if(target->GetTypeId() == TYPEID_PLAYER)
|
||||
((Player*)target)->setFactionForRace(target->getRace());
|
||||
else if(target->GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
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);
|
||||
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
|
||||
|
||||
// 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
|
||||
{
|
||||
target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
|
||||
// Reinitialize the pet bar and make the pet come back to the owner
|
||||
if(((Creature*)target)->isPet())
|
||||
{
|
||||
PetSpellInitialize();
|
||||
if (!target->getVictim())
|
||||
{
|
||||
target->GetMotionMaster()->MoveFollow(this, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
|
||||
target->GetCharmInfo()->SetCommandState(COMMAND_FOLLOW);
|
||||
}
|
||||
}
|
||||
else if (target->isAlive())
|
||||
/*else if (target->isAlive())
|
||||
{
|
||||
// If we're still hostile to our target, continue attacking otherwise reset threat and go home
|
||||
if (Unit* victim = target->getVictim())
|
||||
@@ -19682,10 +19547,7 @@ void Player::RemovePossess(bool attack)
|
||||
// Add high amount of threat on the player
|
||||
if(attack)
|
||||
target->AddThreat(this, 1000000.0f);
|
||||
}
|
||||
// Disable the assigned possessed AI
|
||||
((Creature*)target)->DisablePossessedAI();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
void Player::SetViewport(uint64 guid, bool moveable)
|
||||
|
||||
+9
-2
@@ -962,8 +962,14 @@ class TRINITY_DLL_SPEC Player : public Unit
|
||||
void RemoveFromWorld();
|
||||
|
||||
void SetViewport(uint64 guid, bool movable);
|
||||
void Possess(Unit *target);
|
||||
void RemovePossess(bool attack = true);
|
||||
void RemovePossess(bool attack = true);
|
||||
void StopCharmOrPossess()
|
||||
{
|
||||
if(isPossessing())
|
||||
RemovePossess(true);
|
||||
else if(GetCharm())
|
||||
Uncharm();
|
||||
}
|
||||
WorldObject* GetFarsightTarget() const;
|
||||
void ClearFarsight();
|
||||
void RemoveFarsightTarget();
|
||||
@@ -2430,6 +2436,7 @@ class TRINITY_DLL_SPEC Player : public Unit
|
||||
MapReference m_mapRef;
|
||||
|
||||
void UpdateCharmedAI();
|
||||
UnitAI *i_AI;
|
||||
};
|
||||
|
||||
void AddItemsSetItem(Player*player,Item *item);
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "ObjectMgr.h"
|
||||
|
||||
// Character Dump tables
|
||||
#define DUMP_TABLE_COUNT 19
|
||||
#define DUMP_TABLE_COUNT 18
|
||||
|
||||
struct DumpTable
|
||||
{
|
||||
|
||||
@@ -896,23 +896,33 @@ enum Targets
|
||||
TARGET_DEST_TARGET_BACK = 65, // uses in teleport behind spells
|
||||
TARGET_DEST_TARGET_RIGHT = 66,
|
||||
TARGET_DEST_TARGET_LEFT = 67,
|
||||
TARGET_DEST_TARGET_ENEMY_UNKNOWN2 = 70,
|
||||
TARGET_DEST_TARGET_FRONT_LEFT = 68,
|
||||
TARGET_DEST_TARGET_BACK_LEFT = 69,
|
||||
TARGET_DEST_TARGET_BACK_RIGHT = 70,
|
||||
TARGET_DEST_TARGET_FRONT_RIGHT = 71,
|
||||
TARGET_DEST_CASTER_RANDOM = 72,
|
||||
TARGET_DEST_CASTER_RADIUS = 73,
|
||||
TARGET_DEST_TARGET_RANDOM = 74,
|
||||
TARGET_DEST_TARGET_RADIUS = 75,
|
||||
TARGET_DEST_CHANNEL = 76,
|
||||
TARGET_SINGLE_ENEMY = 77,
|
||||
TARGET_UNIT_CHANNEL = 77,
|
||||
TARGET_DEST_CASTER_FRONT_UNKNOWN = 78,
|
||||
TARGET_DEST_TABLE_UNKNOWN2 = 80,
|
||||
TARGET_DEST_DEST_FRONT = 78,
|
||||
TARGET_DEST_DEST_BACK = 79,
|
||||
TARGET_DEST_DEST_RIGHT = 80,
|
||||
TARGET_DEST_DEST_LEFT = 81,
|
||||
TARGET_DEST_DEST_FRONT_LEFT = 82,
|
||||
TARGET_DEST_DEST_BACK_LEFT = 83,
|
||||
TARGET_DEST_DEST_BACK_RIGHT = 84,
|
||||
TARGET_DEST_DEST_FRONT_RIGHT = 85,
|
||||
TARGET_DEST_DEST_RANDOM = 86,
|
||||
TARGET_DEST_DEST = 87,
|
||||
TARGET_UNIT_AREA_ALL_CHANNEL = 88,
|
||||
TARGET_DEST_TRAJ = 89,
|
||||
TARGET_UNIT_MINIPET = 90,
|
||||
TARGET_CORPSE_AREA_ENEMY_PLAYER = 93,
|
||||
};
|
||||
|
||||
#define TOTAL_SPELL_TARGETS 91
|
||||
#define TOTAL_SPELL_TARGETS 94
|
||||
|
||||
enum SpellMissInfo
|
||||
{
|
||||
|
||||
+116
-100
@@ -171,6 +171,7 @@ bool SpellCastTargets::read ( WorldPacket * data, Unit *caster )
|
||||
return false;
|
||||
|
||||
*data >> m_targetMask;
|
||||
sLog.outDebug("Spell read, target mask = %u", m_targetMask);
|
||||
|
||||
if(m_targetMask == TARGET_FLAG_SELF)
|
||||
return true;
|
||||
@@ -229,6 +230,7 @@ bool SpellCastTargets::read ( WorldPacket * data, Unit *caster )
|
||||
void SpellCastTargets::write ( WorldPacket * data )
|
||||
{
|
||||
*data << uint32(m_targetMask);
|
||||
sLog.outDebug("Spell write, target mask = %u", m_targetMask);
|
||||
|
||||
if( m_targetMask & ( TARGET_FLAG_UNIT | TARGET_FLAG_PVP_CORPSE | TARGET_FLAG_OBJECT | TARGET_FLAG_OBJECT_UNK | TARGET_FLAG_CORPSE | TARGET_FLAG_UNK2 ) )
|
||||
{
|
||||
@@ -276,6 +278,7 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi
|
||||
ASSERT( info == sSpellStore.LookupEntry( info->Id ) && "`info` must be pointer to sSpellStore element");
|
||||
|
||||
m_spellInfo = info;
|
||||
m_customAttr = spellmgr.GetSpellCustomAttr(m_spellInfo->Id);
|
||||
m_caster = Caster;
|
||||
m_selfContainer = NULL;
|
||||
m_triggeringContainer = triggeringContainer;
|
||||
@@ -1012,7 +1015,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
|
||||
{
|
||||
m_caster->CombatStart(unit);
|
||||
}
|
||||
else if(spellmgr.GetSpellCustomAttr(m_spellInfo->Id) & SPELL_ATTR_CU_AURA_CC)
|
||||
else if(m_customAttr & SPELL_ATTR_CU_AURA_CC)
|
||||
{
|
||||
if(!unit->IsStandState())
|
||||
unit->SetStandState(PLAYER_STATE_NONE);
|
||||
@@ -1067,7 +1070,7 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
|
||||
}
|
||||
|
||||
unit->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_HITBYSPELL);
|
||||
if(spellmgr.GetSpellCustomAttr(m_spellInfo->Id) & SPELL_ATTR_CU_AURA_CC)
|
||||
if(m_customAttr & SPELL_ATTR_CU_AURA_CC)
|
||||
unit->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CC);
|
||||
}
|
||||
else
|
||||
@@ -1138,12 +1141,11 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
|
||||
}
|
||||
|
||||
//This is not needed with procflag patch
|
||||
/*if(spellmgr.GetSpellCustomAttr(m_spellInfo->Id) && m_originalCaster)
|
||||
/*if(m_originalCaster)
|
||||
{
|
||||
uint32 flag = spellmgr.GetSpellCustomAttr(m_spellInfo->Id);
|
||||
if(flag & SPELL_ATTR_CU_EFFECT_HEAL)
|
||||
if(m_customAttr & SPELL_ATTR_CU_EFFECT_HEAL)
|
||||
m_originalCaster->ProcDamageAndSpell(unit, PROC_FLAG_HEAL, PROC_FLAG_NONE, 0, GetSpellSchoolMask(m_spellInfo), m_spellInfo);
|
||||
if(m_originalCaster != unit && (flag & SPELL_ATTR_CU_EFFECT_DAMAGE))
|
||||
if(m_originalCaster != unit && (m_customAttr & SPELL_ATTR_CU_EFFECT_DAMAGE))
|
||||
m_originalCaster->ProcDamageAndSpell(unit, PROC_FLAG_HIT_SPELL, PROC_FLAG_STRUCK_SPELL, 0, GetSpellSchoolMask(m_spellInfo), m_spellInfo);
|
||||
}*/
|
||||
}
|
||||
@@ -1582,7 +1584,6 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)
|
||||
AddItemTarget(m_targets.getItemTarget(), i);
|
||||
}break;
|
||||
|
||||
case TARGET_DEST_TABLE_UNKNOWN2:
|
||||
case TARGET_TABLE_X_Y_Z_COORDINATES:
|
||||
if(SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id))
|
||||
{
|
||||
@@ -1605,9 +1606,9 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)
|
||||
|
||||
case TARGET_IN_FRONT_OF_CASTER:
|
||||
case TARGET_UNIT_CONE_ENEMY_UNKNOWN:
|
||||
if(spellmgr.GetSpellCustomAttr(m_spellInfo->Id) & SPELL_ATTR_CU_CONE_BACK)
|
||||
if(m_customAttr & SPELL_ATTR_CU_CONE_BACK)
|
||||
SearchAreaTarget(TagUnitMap, radius, PUSH_IN_BACK, SPELL_TARGETS_AOE_DAMAGE);
|
||||
else if(spellmgr.GetSpellCustomAttr(m_spellInfo->Id) & SPELL_ATTR_CU_CONE_LINE)
|
||||
else if(m_customAttr & SPELL_ATTR_CU_CONE_LINE)
|
||||
SearchAreaTarget(TagUnitMap, radius, PUSH_IN_LINE, SPELL_TARGETS_AOE_DAMAGE);
|
||||
else
|
||||
SearchAreaTarget(TagUnitMap, radius, PUSH_IN_FRONT, SPELL_TARGETS_AOE_DAMAGE);
|
||||
@@ -1831,15 +1832,12 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)
|
||||
|
||||
float x, y, z, angle, dist;
|
||||
|
||||
if (m_spellInfo->EffectRadiusIndex[i])
|
||||
dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
|
||||
else
|
||||
dist = 3.0f;//do we need this?
|
||||
if (cur == TARGET_DEST_CASTER_RANDOM)
|
||||
dist *= rand_norm(); // This case we need to consider caster size
|
||||
else
|
||||
dist -= m_caster->GetObjectSize(); // Size is calculated in GetNearPoint(), but we do not need it
|
||||
//need a new function to remove this repeated work
|
||||
float objSize = m_caster->GetObjectSize();
|
||||
dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
|
||||
if(dist < objSize)
|
||||
dist = objSize;
|
||||
else if(cur == TARGET_DEST_CASTER_RANDOM)
|
||||
dist = objSize + (dist - objSize) * rand_norm();
|
||||
|
||||
switch(cur)
|
||||
{
|
||||
@@ -1849,7 +1847,6 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)
|
||||
case TARGET_DEST_CASTER_FRONT_RIGHT:angle = M_PI/4; break;
|
||||
case TARGET_MINION:
|
||||
case TARGET_DEST_CASTER_FRONT_LEAP:
|
||||
case TARGET_DEST_CASTER_FRONT_UNKNOWN:
|
||||
case TARGET_DEST_CASTER_FRONT: angle = 0.0f; break;
|
||||
case TARGET_DEST_CASTER_BACK: angle = M_PI; break;
|
||||
case TARGET_DEST_CASTER_RIGHT: angle = M_PI/2; break;
|
||||
@@ -1857,7 +1854,7 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)
|
||||
default: angle = rand_norm()*2*M_PI; break;
|
||||
}
|
||||
|
||||
m_caster->GetClosePoint(x, y, z, 0, dist, angle);
|
||||
m_caster->GetClosePoint(x, y, z, dist, angle);
|
||||
m_targets.setDestination(x, y, z); // do not know if has ground visual
|
||||
}break;
|
||||
|
||||
@@ -1883,15 +1880,12 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)
|
||||
|
||||
float x, y, z, angle, dist;
|
||||
|
||||
if (m_spellInfo->EffectRadiusIndex[i])
|
||||
dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
|
||||
else
|
||||
dist = 3.0f;//do we need this?
|
||||
if (cur == TARGET_DEST_TARGET_RANDOM)
|
||||
dist *= rand_norm(); // This case we need to consider caster size
|
||||
else
|
||||
dist -= target->GetObjectSize(); // Size is calculated in GetNearPoint(), but we do not need it
|
||||
//need a new function to remove this repeated work
|
||||
float objSize = target->GetObjectSize();
|
||||
dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
|
||||
if(dist < objSize)
|
||||
dist = objSize;
|
||||
else if(cur == TARGET_DEST_CASTER_RANDOM)
|
||||
dist = objSize + (dist - objSize) * rand_norm();
|
||||
|
||||
switch(cur)
|
||||
{
|
||||
@@ -1899,10 +1893,14 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)
|
||||
case TARGET_DEST_TARGET_BACK: angle = M_PI; break;
|
||||
case TARGET_DEST_TARGET_RIGHT: angle = M_PI/2; break;
|
||||
case TARGET_DEST_TARGET_LEFT: angle = -M_PI/2; break;
|
||||
case TARGET_DEST_TARGET_FRONT_LEFT: angle = -M_PI/4; break;
|
||||
case TARGET_DEST_TARGET_BACK_LEFT: angle = -3*M_PI/4; break;
|
||||
case TARGET_DEST_TARGET_BACK_RIGHT: angle = 3*M_PI/4; break;
|
||||
case TARGET_DEST_TARGET_FRONT_RIGHT:angle = M_PI/4; break;
|
||||
default: angle = rand_norm()*2*M_PI; break;
|
||||
}
|
||||
|
||||
target->GetClosePoint(x, y, z, 0, dist, angle);
|
||||
target->GetClosePoint(x, y, z, dist, angle);
|
||||
m_targets.setDestination(x, y, z); // do not know if has ground visual
|
||||
}break;
|
||||
|
||||
@@ -1914,61 +1912,59 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)
|
||||
break;
|
||||
}
|
||||
|
||||
if(cur == TARGET_DEST_DEST)
|
||||
break;
|
||||
|
||||
float x, y, z, angle, dist;
|
||||
|
||||
dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
|
||||
if (cur == TARGET_DEST_DEST_RANDOM)
|
||||
dist *= rand_norm();
|
||||
|
||||
switch(cur)
|
||||
{
|
||||
case TARGET_DEST_DEST_RANDOM:
|
||||
{
|
||||
|
||||
float x, y, z, dist, px, py, pz;
|
||||
dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
|
||||
x = m_targets.m_destX;
|
||||
y = m_targets.m_destY;
|
||||
z = m_targets.m_destZ;
|
||||
m_caster->GetRandomPoint(x, y, z, dist, px, py, pz);
|
||||
m_targets.setDestination(px, py, pz);
|
||||
}
|
||||
break;
|
||||
case TARGET_DEST_DEST:
|
||||
break;
|
||||
case TARGET_DEST_DEST_FRONT: angle = 0.0f; break;
|
||||
case TARGET_DEST_DEST_BACK: angle = M_PI; break;
|
||||
case TARGET_DEST_DEST_RIGHT: angle = M_PI/2; break;
|
||||
case TARGET_DEST_DEST_LEFT: angle = -M_PI/2; break;
|
||||
case TARGET_DEST_DEST_FRONT_LEFT: angle = -M_PI/4; break;
|
||||
case TARGET_DEST_DEST_BACK_LEFT: angle = -3*M_PI/4; break;
|
||||
case TARGET_DEST_DEST_BACK_RIGHT: angle = 3*M_PI/4; break;
|
||||
case TARGET_DEST_DEST_FRONT_RIGHT:angle = M_PI/4; break;
|
||||
default: angle = rand_norm()*2*M_PI; break;
|
||||
}
|
||||
|
||||
x = m_targets.m_destX;
|
||||
y = m_targets.m_destY;
|
||||
z = m_targets.m_destZ;
|
||||
m_caster->GetClosePointAt(x, y, z, dist, angle);
|
||||
m_targets.setDestination(x, y, z); // do not know if has ground visual
|
||||
}break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (unMaxTargets && TagUnitMap.size() > unMaxTargets)
|
||||
if(unMaxTargets)
|
||||
{
|
||||
// make sure one unit is always removed per iteration
|
||||
uint32 removed_utarget = 0;
|
||||
for (std::list<Unit*>::iterator itr = TagUnitMap.begin(), next; itr != TagUnitMap.end(); itr = next)
|
||||
if(m_targets.getUnitTarget())
|
||||
{
|
||||
next = itr;
|
||||
++next;
|
||||
if (!*itr) continue;
|
||||
if ((*itr) == m_targets.getUnitTarget())
|
||||
{
|
||||
TagUnitMap.erase(itr);
|
||||
removed_utarget = 1;
|
||||
// break;
|
||||
}
|
||||
TagUnitMap.remove(m_targets.getUnitTarget());
|
||||
if(m_spellInfo->Id != 5246) //Intimidating Shout
|
||||
--unMaxTargets;
|
||||
}
|
||||
|
||||
// remove random units from the map
|
||||
while (TagUnitMap.size() > unMaxTargets - removed_utarget)
|
||||
std::list<Unit*>::iterator itr;
|
||||
while(TagUnitMap.size() > unMaxTargets)
|
||||
{
|
||||
uint32 poz = urand(0, TagUnitMap.size()-1);
|
||||
for (std::list<Unit*>::iterator itr = TagUnitMap.begin(); itr != TagUnitMap.end(); ++itr, --poz)
|
||||
{
|
||||
if (!*itr) continue;
|
||||
if (!poz)
|
||||
{
|
||||
TagUnitMap.erase(itr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
itr = TagUnitMap.begin();
|
||||
advance(itr, urand(0, TagUnitMap.size() - 1));
|
||||
TagUnitMap.erase(itr);
|
||||
}
|
||||
|
||||
// the player's target will always be added to the map
|
||||
if (removed_utarget && m_targets.getUnitTarget())
|
||||
if(m_targets.getUnitTarget() && m_spellInfo->Id != 5246)
|
||||
TagUnitMap.push_back(m_targets.getUnitTarget());
|
||||
}
|
||||
}
|
||||
@@ -2045,7 +2041,8 @@ void Spell::prepare(SpellCastTargets * targets, Aura* triggeredByAura)
|
||||
// set timer base at cast time
|
||||
ReSetTimer();
|
||||
|
||||
if(m_IsTriggeredSpell)
|
||||
//item: first cast may destroy item and second cast causes crash
|
||||
if(m_IsTriggeredSpell || !m_casttime && !m_spellInfo->StartRecoveryTime && !m_castItemGUID && GetCurrentContainer() == CURRENT_GENERIC_SPELL)
|
||||
cast(true);
|
||||
else
|
||||
{
|
||||
@@ -2161,16 +2158,8 @@ void Spell::cast(bool skipCheck)
|
||||
|
||||
FillTargetMap();
|
||||
|
||||
if(const std::vector<int32> *spell_triggered = spellmgr.GetSpellLinked(m_spellInfo->Id))
|
||||
{
|
||||
for(std::vector<int32>::const_iterator i = spell_triggered->begin(); i != spell_triggered->end(); ++i)
|
||||
{
|
||||
if(spell_triggered < 0)
|
||||
m_caster->RemoveAurasDueToSpell(-(*i));
|
||||
else
|
||||
m_caster->CastSpell(m_targets.getUnitTarget() ? m_targets.getUnitTarget() : m_caster, *i, true);
|
||||
}
|
||||
}
|
||||
if(m_customAttr & SPELL_ATTR_CU_DIRECT_DAMAGE)
|
||||
CalculateDamageDoneForAllTargets();
|
||||
|
||||
// traded items have trade slot instead of guid in m_itemTargetGUID
|
||||
// set to real guid to be sent later to the client
|
||||
@@ -2189,7 +2178,7 @@ void Spell::cast(bool skipCheck)
|
||||
|
||||
if(!m_IsTriggeredSpell)
|
||||
{
|
||||
TakePower();
|
||||
//TakePower();
|
||||
TakeReagents(); // we must remove reagents before HandleEffects to allow place crafted item in same slot
|
||||
}
|
||||
|
||||
@@ -2202,8 +2191,6 @@ void Spell::cast(bool skipCheck)
|
||||
SendCastResult(castResult);
|
||||
SendSpellGo(); // we must send smsg_spell_go packet before m_castItem delete in TakeCastItem()...
|
||||
|
||||
CalculateDamageDoneForAllTargets();
|
||||
|
||||
// Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells
|
||||
if (m_spellInfo->speed > 0.0f && !IsChanneledSpell(m_spellInfo))
|
||||
{
|
||||
@@ -2223,20 +2210,20 @@ void Spell::cast(bool skipCheck)
|
||||
handle_immediate();
|
||||
}
|
||||
|
||||
// Clear combo at finish state
|
||||
if(m_caster->GetTypeId() == TYPEID_PLAYER && NeedsComboPoints(m_spellInfo))
|
||||
if(!m_IsTriggeredSpell)
|
||||
{
|
||||
// Not drop combopoints if negative spell and if any miss on enemy exist
|
||||
bool needDrop = true;
|
||||
//if (!IsPositiveSpell(m_spellInfo->Id))
|
||||
for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
|
||||
if (ihit->missCondition != SPELL_MISS_NONE && ihit->missCondition != SPELL_MISS_MISS/* && ihit->targetGUID!=m_caster->GetGUID()*/)
|
||||
{
|
||||
needDrop = false;
|
||||
break;
|
||||
}
|
||||
if (needDrop)
|
||||
((Player*)m_caster)->ClearComboPoints();
|
||||
TakePower();
|
||||
}
|
||||
|
||||
if(const std::vector<int32> *spell_triggered = spellmgr.GetSpellLinked(m_spellInfo->Id))
|
||||
{
|
||||
for(std::vector<int32>::const_iterator i = spell_triggered->begin(); i != spell_triggered->end(); ++i)
|
||||
{
|
||||
if(spell_triggered < 0)
|
||||
m_caster->RemoveAurasDueToSpell(-(*i));
|
||||
else
|
||||
m_caster->CastSpell(m_targets.getUnitTarget() ? m_targets.getUnitTarget() : m_caster, *i, true);
|
||||
}
|
||||
}
|
||||
|
||||
SetExecutedCurrently(false);
|
||||
@@ -3256,9 +3243,25 @@ void Spell::TakeCastItem()
|
||||
|
||||
void Spell::TakePower()
|
||||
{
|
||||
if(m_CastItem || m_triggeredByAuraSpell)
|
||||
if(m_CastItem || m_triggeredByAuraSpell || !m_powerCost)
|
||||
return;
|
||||
|
||||
bool hit = true;
|
||||
if(m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
if(m_spellInfo->powerType == POWER_RAGE || m_spellInfo->powerType == POWER_ENERGY)
|
||||
if(uint64 targetGUID = m_targets.getUnitTargetGUID())
|
||||
for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
|
||||
if(ihit->targetGUID == targetGUID)
|
||||
{
|
||||
if(ihit->missCondition != SPELL_MISS_NONE && ihit->missCondition != SPELL_MISS_MISS/* && ihit->targetGUID!=m_caster->GetGUID()*/)
|
||||
hit = false;
|
||||
break;
|
||||
}
|
||||
if(hit && NeedsComboPoints(m_spellInfo))
|
||||
((Player*)m_caster)->ClearComboPoints();
|
||||
}
|
||||
|
||||
// health as power used
|
||||
if(m_spellInfo->powerType == POWER_HEALTH)
|
||||
{
|
||||
@@ -3280,7 +3283,10 @@ void Spell::TakePower()
|
||||
return;
|
||||
}
|
||||
|
||||
m_caster->ModifyPower(powerType, -(int32)m_powerCost);
|
||||
if(hit)
|
||||
m_caster->ModifyPower(powerType, -m_powerCost);
|
||||
else
|
||||
m_caster->ModifyPower(powerType, -irand(0, m_powerCost/4));
|
||||
|
||||
// Set the five second timer
|
||||
if (powerType == POWER_MANA && m_powerCost > 0)
|
||||
@@ -5326,6 +5332,10 @@ bool Spell::CheckTarget( Unit* target, uint32 eff, bool hitPhase )
|
||||
return false;
|
||||
}
|
||||
|
||||
//Do not check LOS for triggered spells
|
||||
if(m_IsTriggeredSpell)
|
||||
return true;
|
||||
|
||||
//Check targets for LOS visibility (except spells without range limitations )
|
||||
switch(m_spellInfo->Effect[eff])
|
||||
{
|
||||
@@ -5630,8 +5640,14 @@ int32 Spell::CalculateDamageDone(Unit *unit, const uint32 effectMask, float *mul
|
||||
break;
|
||||
}
|
||||
|
||||
if(m_damage > 0 && m_originalCaster)
|
||||
m_damage = m_originalCaster->SpellDamageBonus(unit, m_spellInfo, m_damage, SPELL_DIRECT_DAMAGE);
|
||||
if(m_damage > 0)
|
||||
{
|
||||
if(IsAreaEffectTarget[m_spellInfo->EffectImplicitTargetA[i]] || IsAreaEffectTarget[m_spellInfo->EffectImplicitTargetB[i]])
|
||||
{
|
||||
if(int32 reducedPct = unit->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE))
|
||||
m_damage = m_damage * (100 + reducedPct) / 100;
|
||||
}
|
||||
}
|
||||
if(m_applyMultiplierMask & (1 << i))
|
||||
{
|
||||
m_damage *= m_damageMultipliers[i];
|
||||
|
||||
@@ -600,6 +600,8 @@ class Spell
|
||||
// we can't store original aura link to prevent access to deleted auras
|
||||
// and in same time need aura data and after aura deleting.
|
||||
SpellEntry const* m_triggeredByAuraSpell;
|
||||
|
||||
uint32 m_customAttr;
|
||||
};
|
||||
|
||||
namespace Trinity
|
||||
|
||||
+174
-123
@@ -612,10 +612,13 @@ void Aura::Update(uint32 diff)
|
||||
// update before applying (aura can be removed in TriggerSpell or PeriodicTick calls)
|
||||
m_periodicTimer += m_modifier.periodictime;
|
||||
|
||||
if(m_isTrigger)
|
||||
TriggerSpell();
|
||||
else
|
||||
PeriodicTick();
|
||||
if(!m_target->hasUnitState(UNIT_STAT_ISOLATED))
|
||||
{
|
||||
if(m_isTrigger)
|
||||
TriggerSpell();
|
||||
else
|
||||
PeriodicTick();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -633,6 +636,9 @@ void AreaAura::Update(uint32 diff)
|
||||
|
||||
switch(m_areaAuraType)
|
||||
{
|
||||
case AREA_AURA_PARTY:
|
||||
caster->GetPartyMember(targets, m_radius);
|
||||
break;
|
||||
case AREA_AURA_RAID:
|
||||
caster->GetRaidMember(targets, m_radius);
|
||||
break;
|
||||
@@ -705,39 +711,13 @@ void AreaAura::Update(uint32 diff)
|
||||
}
|
||||
else if( m_areaAuraType == AREA_AURA_PARTY) // check if in same sub group
|
||||
{
|
||||
// not check group if target == owner or target == pet
|
||||
if (caster->GetCharmerOrOwnerGUID() != tmp_target->GetGUID() && caster->GetGUID() != tmp_target->GetCharmerOrOwnerGUID())
|
||||
{
|
||||
Player* check = caster->GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
|
||||
Group *pGroup = check ? check->GetGroup() : NULL;
|
||||
if( pGroup )
|
||||
{
|
||||
Player* checkTarget = tmp_target->GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
if(!checkTarget || !pGroup->SameSubGroup(check, checkTarget))
|
||||
tmp_target->RemoveAura(tmp_spellId, tmp_effIndex);
|
||||
}
|
||||
else
|
||||
tmp_target->RemoveAura(tmp_spellId, tmp_effIndex);
|
||||
}
|
||||
if(!tmp_target->IsInPartyWith(caster))
|
||||
tmp_target->RemoveAura(tmp_spellId, tmp_effIndex);
|
||||
}
|
||||
else if( m_areaAuraType == AREA_AURA_RAID) // TODO: fix me!
|
||||
{
|
||||
// not check group if target == owner or target == pet
|
||||
if (caster->GetCharmerOrOwnerGUID() != tmp_target->GetGUID() && caster->GetGUID() != tmp_target->GetCharmerOrOwnerGUID())
|
||||
{
|
||||
Player* check = caster->GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
|
||||
Group *pGroup = check ? check->GetGroup() : NULL;
|
||||
if( pGroup )
|
||||
{
|
||||
Player* checkTarget = tmp_target->GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
if(!checkTarget)
|
||||
tmp_target->RemoveAura(tmp_spellId, tmp_effIndex);
|
||||
}
|
||||
else
|
||||
tmp_target->RemoveAura(tmp_spellId, tmp_effIndex);
|
||||
}
|
||||
if(!tmp_target->IsInRaidWith(caster))
|
||||
tmp_target->RemoveAura(tmp_spellId, tmp_effIndex);
|
||||
}
|
||||
else if( m_areaAuraType == AREA_AURA_PET || m_areaAuraType == AREA_AURA_OWNER )
|
||||
{
|
||||
@@ -836,15 +816,6 @@ void Aura::_AddAura()
|
||||
// not call total regen auras at adding
|
||||
switch (m_modifier.m_auraname)
|
||||
{
|
||||
/*case SPELL_AURA_PERIODIC_DAMAGE:
|
||||
case SPELL_AURA_PERIODIC_LEECH:
|
||||
if(caster)
|
||||
m_modifier.m_amount = caster->SpellDamageBonus(m_target, m_spellProto, m_modifier.m_amount, DOT);
|
||||
break;
|
||||
case SPELL_AURA_PERIODIC_HEAL:
|
||||
if(caster)
|
||||
m_modifier.m_amount = caster->SpellHealingBonus(m_spellProto, m_modifier.m_amount, DOT, m_target);
|
||||
break;*/
|
||||
case SPELL_AURA_OBS_MOD_HEALTH:
|
||||
case SPELL_AURA_OBS_MOD_MANA:
|
||||
m_periodicTimer = m_modifier.periodictime;
|
||||
@@ -2976,7 +2947,7 @@ void Aura::HandleAuraModScale(bool apply, bool Real)
|
||||
m_target->ApplyPercentModFloatValue(OBJECT_FIELD_SCALE_X,m_modifier.m_amount,apply);
|
||||
}
|
||||
|
||||
void Aura::HandleModPossess(bool apply, bool Real)
|
||||
/*void Aura::HandleModPossess(bool apply, bool Real)
|
||||
{
|
||||
if(!Real)
|
||||
return;
|
||||
@@ -2994,12 +2965,28 @@ void Aura::HandleModPossess(bool apply, bool Real)
|
||||
|
||||
if( apply )
|
||||
{
|
||||
if (caster->GetTypeId() == TYPEID_PLAYER)
|
||||
((Player*)caster)->Possess(m_target);
|
||||
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();
|
||||
}
|
||||
}
|
||||
else
|
||||
m_target->UnpossessSelf(true);
|
||||
/*{
|
||||
{
|
||||
m_target->SetCharmerGUID(0);
|
||||
|
||||
if(m_target->GetTypeId() == TYPEID_PLAYER)
|
||||
@@ -3028,7 +3015,7 @@ void Aura::HandleModPossess(bool apply, bool Real)
|
||||
}
|
||||
}
|
||||
if(caster->GetTypeId() == TYPEID_PLAYER)
|
||||
((Player*)caster)->SetFarSight(apply ? m_target->GetGUID() : NULL);*/
|
||||
((Player*)caster)->SetFarSight(apply ? m_target->GetGUID() : NULL);
|
||||
}
|
||||
|
||||
void Aura::HandleModPossessPet(bool apply, bool Real)
|
||||
@@ -3055,14 +3042,12 @@ void Aura::HandleModPossessPet(bool apply, bool Real)
|
||||
|
||||
if(apply)
|
||||
{
|
||||
((Player*)caster)->Possess(m_target);
|
||||
pet->StopMoving();
|
||||
pet->GetMotionMaster()->Clear();
|
||||
pet->GetMotionMaster()->MoveIdle();
|
||||
}
|
||||
else
|
||||
{
|
||||
((Player*)caster)->RemovePossess(false);
|
||||
/*pet->StopMoving();
|
||||
pet->GetMotionMaster()->Clear();
|
||||
pet->GetMotionMaster()->MoveIdle();*/
|
||||
pet->AttackStop();
|
||||
pet->GetMotionMaster()->MoveFollow(caster, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
|
||||
pet->SetUnitMovementFlags(MOVEMENTFLAG_NONE);
|
||||
@@ -3079,93 +3064,85 @@ void Aura::HandleModCharm(bool apply, bool Real)
|
||||
return;
|
||||
|
||||
Unit* caster = GetCaster();
|
||||
if(!caster)
|
||||
return;
|
||||
|
||||
if( apply )
|
||||
if(int32(m_target->getLevel()) <= m_modifier.m_amount)
|
||||
{
|
||||
if(!caster)
|
||||
return;
|
||||
|
||||
if(int32(m_target->getLevel()) > m_modifier.m_amount)
|
||||
return;
|
||||
|
||||
m_target->SetCharmerGUID(GetCasterGUID());
|
||||
m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,caster->getFaction());
|
||||
m_target->CastStop(m_target==caster ? GetId() : 0);
|
||||
caster->SetCharm(m_target);
|
||||
|
||||
m_target->CombatStop();
|
||||
m_target->DeleteThreatList();
|
||||
|
||||
if(m_target->GetTypeId() == TYPEID_UNIT)
|
||||
if( apply )
|
||||
{
|
||||
((Creature*)m_target)->AIM_Initialize();
|
||||
CharmInfo *charmInfo = ((Creature*)m_target)->InitCharmInfo(m_target);
|
||||
charmInfo->InitCharmCreateSpells();
|
||||
charmInfo->SetReactState( REACT_DEFENSIVE );
|
||||
m_target->SetCharmerGUID(GetCasterGUID());
|
||||
m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,caster->getFaction());
|
||||
m_target->CastStop(m_target==caster ? GetId() : 0);
|
||||
caster->SetCharm(m_target);
|
||||
|
||||
if(caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK)
|
||||
m_target->CombatStop();
|
||||
m_target->DeleteThreatList();
|
||||
|
||||
if(m_target->GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
CreatureInfo const *cinfo = ((Creature*)m_target)->GetCreatureInfo();
|
||||
if(cinfo && cinfo->type == CREATURE_TYPE_DEMON)
|
||||
((Creature*)m_target)->AIM_Initialize();
|
||||
CharmInfo *charmInfo = ((Creature*)m_target)->InitCharmInfo(m_target);
|
||||
charmInfo->InitCharmCreateSpells();
|
||||
charmInfo->SetReactState( REACT_DEFENSIVE );
|
||||
|
||||
if(caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK)
|
||||
{
|
||||
//to prevent client crash
|
||||
m_target->SetFlag(UNIT_FIELD_BYTES_0, 2048);
|
||||
//just to enable stat window
|
||||
charmInfo->SetPetNumber(objmgr.GeneratePetNumber(), true);
|
||||
//if charmed two demons the same session, the 2nd gets the 1st one's name
|
||||
m_target->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
|
||||
CreatureInfo const *cinfo = ((Creature*)m_target)->GetCreatureInfo();
|
||||
if(cinfo && cinfo->type == CREATURE_TYPE_DEMON)
|
||||
{
|
||||
//to prevent client crash
|
||||
m_target->SetFlag(UNIT_FIELD_BYTES_0, 2048);
|
||||
//just to enable stat window
|
||||
charmInfo->SetPetNumber(objmgr.GeneratePetNumber(), true);
|
||||
//if charmed two demons the same session, the 2nd gets the 1st one's name
|
||||
m_target->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(caster->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
((Player*)caster)->CharmSpellInitialize();
|
||||
if(caster->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
((Player*)caster)->CharmSpellInitialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_target->SetCharmerGUID(0);
|
||||
|
||||
if(m_target->GetTypeId() == TYPEID_PLAYER)
|
||||
((Player*)m_target)->setFactionForRace(m_target->getRace());
|
||||
else
|
||||
{
|
||||
CreatureInfo const *cinfo = ((Creature*)m_target)->GetCreatureInfo();
|
||||
m_target->SetCharmerGUID(0);
|
||||
|
||||
// restore faction
|
||||
if(((Creature*)m_target)->isPet())
|
||||
if(m_target->GetTypeId() == TYPEID_PLAYER)
|
||||
((Player*)m_target)->setFactionForRace(m_target->getRace());
|
||||
else
|
||||
{
|
||||
if(Unit* owner = m_target->GetOwner())
|
||||
m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,owner->getFaction());
|
||||
else if(cinfo)
|
||||
CreatureInfo const *cinfo = ((Creature*)m_target)->GetCreatureInfo();
|
||||
|
||||
// restore faction
|
||||
if(((Creature*)m_target)->isPet())
|
||||
{
|
||||
if(Unit* owner = m_target->GetOwner())
|
||||
m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,owner->getFaction());
|
||||
else if(cinfo)
|
||||
m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,cinfo->faction_A);
|
||||
}
|
||||
else if(cinfo) // normal creature
|
||||
m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,cinfo->faction_A);
|
||||
}
|
||||
else if(cinfo) // normal creature
|
||||
m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,cinfo->faction_A);
|
||||
|
||||
// restore UNIT_FIELD_BYTES_0
|
||||
if(caster && cinfo && caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK && cinfo->type == CREATURE_TYPE_DEMON)
|
||||
{
|
||||
CreatureDataAddon const *cainfo = ((Creature*)m_target)->GetCreatureAddon();
|
||||
if(cainfo && cainfo->bytes0 != 0)
|
||||
m_target->SetUInt32Value(UNIT_FIELD_BYTES_0, cainfo->bytes0);
|
||||
else
|
||||
m_target->RemoveFlag(UNIT_FIELD_BYTES_0, 2048);
|
||||
// restore UNIT_FIELD_BYTES_0
|
||||
if(cinfo && caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK && cinfo->type == CREATURE_TYPE_DEMON)
|
||||
{
|
||||
CreatureDataAddon const *cainfo = ((Creature*)m_target)->GetCreatureAddon();
|
||||
if(cainfo && cainfo->bytes0 != 0)
|
||||
m_target->SetUInt32Value(UNIT_FIELD_BYTES_0, cainfo->bytes0);
|
||||
else
|
||||
m_target->RemoveFlag(UNIT_FIELD_BYTES_0, 2048);
|
||||
|
||||
if(m_target->GetCharmInfo())
|
||||
m_target->GetCharmInfo()->SetPetNumber(0, true);
|
||||
else
|
||||
sLog.outError("Aura::HandleModCharm: target="I64FMTD" with typeid=%d has a charm aura but no charm info!", m_target->GetGUID(), m_target->GetTypeId());
|
||||
if(m_target->GetCharmInfo())
|
||||
m_target->GetCharmInfo()->SetPetNumber(0, true);
|
||||
else
|
||||
sLog.outError("Aura::HandleModCharm: target="I64FMTD" with typeid=%d has a charm aura but no charm info!", m_target->GetGUID(), m_target->GetTypeId());
|
||||
}
|
||||
}
|
||||
|
||||
((Creature*)m_target)->AIM_Initialize();
|
||||
if(((Creature*)m_target)->AI() && caster)
|
||||
((Creature*)m_target)->AI()->AttackStart(caster);
|
||||
}
|
||||
|
||||
if(caster)
|
||||
{
|
||||
caster->SetCharm(0);
|
||||
|
||||
if(caster->GetTypeId() == TYPEID_PLAYER)
|
||||
@@ -3175,9 +3152,15 @@ void Aura::HandleModCharm(bool apply, bool Real)
|
||||
data << uint32(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
void Aura::HandleModConfuse(bool apply, bool Real)
|
||||
{
|
||||
@@ -6655,3 +6638,71 @@ void Aura::HandleModAttackerSpellHitChance(bool apply, bool Real)
|
||||
//cloak of shadows : flare
|
||||
m_target->ApplySpellImmune(31224, IMMUNITY_ID, 1543, apply);
|
||||
}
|
||||
|
||||
void Aura::HandleModPossess(bool apply, bool Real)
|
||||
{
|
||||
if(!Real)
|
||||
return;
|
||||
|
||||
Unit* caster = GetCaster();
|
||||
if(caster && caster->GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
HandleModCharm(apply, Real);
|
||||
return;
|
||||
}
|
||||
|
||||
if(apply)
|
||||
{
|
||||
if(m_target->getLevel() > m_modifier.m_amount)
|
||||
return;
|
||||
|
||||
m_target->SetCharmedOrPossessedBy(caster, true);
|
||||
}
|
||||
else
|
||||
m_target->RemoveCharmedOrPossessedBy(caster);
|
||||
}
|
||||
|
||||
void Aura::HandleModPossessPet(bool apply, bool Real)
|
||||
{
|
||||
if(!Real)
|
||||
return;
|
||||
|
||||
Unit* caster = GetCaster();
|
||||
if(!caster || caster->GetTypeId() != TYPEID_PLAYER)
|
||||
return;
|
||||
if(caster->GetPet() != m_target)
|
||||
return;
|
||||
|
||||
if(apply)
|
||||
m_target->SetCharmedOrPossessedBy(caster, true);
|
||||
else
|
||||
{
|
||||
m_target->RemoveCharmedOrPossessedBy(caster);
|
||||
|
||||
// Reinitialize the pet bar and make the pet come back to the owner
|
||||
((Player*)caster)->PetSpellInitialize();
|
||||
if(!m_target->getVictim())
|
||||
{
|
||||
m_target->GetMotionMaster()->MoveFollow(caster, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
|
||||
m_target->GetCharmInfo()->SetCommandState(COMMAND_FOLLOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Aura::HandleModCharm(bool apply, bool Real)
|
||||
{
|
||||
if(!Real)
|
||||
return;
|
||||
|
||||
Unit* caster = GetCaster();
|
||||
|
||||
if(apply)
|
||||
{
|
||||
if(int32(m_target->getLevel()) > m_modifier.m_amount)
|
||||
return;
|
||||
|
||||
m_target->SetCharmedOrPossessedBy(caster, false);
|
||||
}
|
||||
else
|
||||
m_target->RemoveCharmedOrPossessedBy(caster);
|
||||
}
|
||||
|
||||
@@ -325,7 +325,7 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
|
||||
}
|
||||
|
||||
// Meteor like spells (divided damage to targets)
|
||||
if(spellmgr.GetSpellCustomAttr(m_spellInfo->Id) & SPELL_ATTR_CU_SHARE_DAMAGE)
|
||||
if(m_customAttr & SPELL_ATTR_CU_SHARE_DAMAGE)
|
||||
{
|
||||
uint32 count = 0;
|
||||
for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
|
||||
@@ -682,8 +682,11 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
|
||||
}
|
||||
}
|
||||
|
||||
if(damage >= 0)
|
||||
m_damage+= damage;
|
||||
if(m_originalCaster)
|
||||
damage = m_originalCaster->SpellDamageBonus(unitTarget, m_spellInfo, damage, SPELL_DIRECT_DAMAGE);
|
||||
|
||||
if(damage > 0)
|
||||
m_damage += damage;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2367,7 +2370,9 @@ void Spell::EffectPowerBurn(uint32 i)
|
||||
new_damage = int32(new_damage*multiplier);
|
||||
//m_damage+=new_damage; should not apply spell bonus
|
||||
//TODO: no log
|
||||
unitTarget->ModifyHealth(-new_damage);
|
||||
//unitTarget->ModifyHealth(-new_damage);
|
||||
if(m_originalCaster)
|
||||
m_originalCaster->DealDamage(unitTarget, new_damage);
|
||||
}
|
||||
|
||||
void Spell::EffectHeal( uint32 /*i*/ )
|
||||
@@ -3759,7 +3764,7 @@ void Spell::EffectSummonPossessed(uint32 i)
|
||||
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);
|
||||
if(c) c->SetCharmedOrPossessedBy(m_caster, true);
|
||||
}
|
||||
|
||||
void Spell::EffectTeleUnitsFaceCaster(uint32 i)
|
||||
@@ -6570,4 +6575,4 @@ void Spell::EffectRedirectThreat(uint32 /*i*/)
|
||||
{
|
||||
if(unitTarget)
|
||||
m_caster->SetReducedThreatPercent((uint32)damage, unitTarget->GetGUID());
|
||||
}
|
||||
}
|
||||
|
||||
+25
-4
@@ -126,11 +126,14 @@ SpellMgr::SpellMgr()
|
||||
SpellTargetType[i] = TARGET_TYPE_AREA_DEST;
|
||||
break;
|
||||
case TARGET_DEST_TARGET_ENEMY:
|
||||
case TARGET_DEST_TARGET_ENEMY_UNKNOWN:
|
||||
case TARGET_DEST_TARGET_FRONT:
|
||||
case TARGET_DEST_TARGET_BACK:
|
||||
case TARGET_DEST_TARGET_RIGHT:
|
||||
case TARGET_DEST_TARGET_LEFT:
|
||||
case TARGET_DEST_TARGET_FRONT_LEFT:
|
||||
case TARGET_DEST_TARGET_BACK_LEFT:
|
||||
case TARGET_DEST_TARGET_BACK_RIGHT:
|
||||
case TARGET_DEST_TARGET_FRONT_RIGHT:
|
||||
case TARGET_DEST_TARGET_RANDOM:
|
||||
case TARGET_DEST_TARGET_RADIUS:
|
||||
SpellTargetType[i] = TARGET_TYPE_DEST_TARGET;
|
||||
@@ -144,7 +147,6 @@ SpellMgr::SpellMgr()
|
||||
case TARGET_DEST_CASTER_FRONT:
|
||||
case TARGET_MINION:
|
||||
case TARGET_DEST_CASTER_FRONT_LEAP:
|
||||
case TARGET_DEST_CASTER_FRONT_UNKNOWN:
|
||||
case TARGET_DEST_CASTER_BACK:
|
||||
case TARGET_DEST_CASTER_RIGHT:
|
||||
case TARGET_DEST_CASTER_LEFT:
|
||||
@@ -152,8 +154,16 @@ SpellMgr::SpellMgr()
|
||||
case TARGET_DEST_CASTER_RADIUS:
|
||||
SpellTargetType[i] = TARGET_TYPE_DEST_CASTER;
|
||||
break;
|
||||
case TARGET_DEST_DEST_RANDOM:
|
||||
case TARGET_DEST_DEST:
|
||||
case TARGET_DEST_DEST_FRONT_LEFT:
|
||||
case TARGET_DEST_DEST_BACK_LEFT:
|
||||
case TARGET_DEST_DEST_BACK_RIGHT:
|
||||
case TARGET_DEST_DEST_FRONT_RIGHT:
|
||||
case TARGET_DEST_DEST_FRONT:
|
||||
case TARGET_DEST_DEST_BACK:
|
||||
case TARGET_DEST_DEST_RIGHT:
|
||||
case TARGET_DEST_DEST_LEFT:
|
||||
case TARGET_DEST_DEST_RANDOM:
|
||||
SpellTargetType[i] = TARGET_TYPE_DEST_DEST;
|
||||
break;
|
||||
default:
|
||||
@@ -475,7 +485,7 @@ bool IsPositiveTarget(uint32 targetA, uint32 targetB)
|
||||
case TARGET_IN_FRONT_OF_CASTER:
|
||||
case TARGET_ALL_ENEMY_IN_AREA_CHANNELED:
|
||||
case TARGET_CURRENT_ENEMY_COORDINATES:
|
||||
case TARGET_SINGLE_ENEMY:
|
||||
case TARGET_UNIT_CHANNEL:
|
||||
return false;
|
||||
case TARGET_ALL_AROUND_CASTER:
|
||||
return (targetB == TARGET_ALL_PARTY || targetB == TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER);
|
||||
@@ -2064,6 +2074,17 @@ void SpellMgr::LoadSpellCustomAttr()
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch(spellInfo->Effect[j])
|
||||
{
|
||||
case SPELL_EFFECT_SCHOOL_DAMAGE:
|
||||
case SPELL_EFFECT_WEAPON_DAMAGE:
|
||||
case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
|
||||
case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
|
||||
case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
|
||||
case SPELL_EFFECT_HEAL:
|
||||
mSpellCustomAttr[i] |= SPELL_ATTR_CU_DIRECT_DAMAGE;
|
||||
}
|
||||
}
|
||||
|
||||
if(spellInfo->SpellVisual[0] == 3879)
|
||||
|
||||
+7
-1
@@ -416,12 +416,17 @@ inline bool IsAreaAuraEffect(uint32 effect)
|
||||
|
||||
inline bool IsDispelSpell(SpellEntry const *spellInfo)
|
||||
{
|
||||
//spellsteal is also dispel
|
||||
if (spellInfo->Effect[0] == SPELL_EFFECT_DISPEL ||
|
||||
spellInfo->Effect[0] == SPELL_EFFECT_STEAL_BENEFICIAL_BUFF ||
|
||||
spellInfo->Effect[1] == SPELL_EFFECT_DISPEL ||
|
||||
spellInfo->Effect[2] == SPELL_EFFECT_DISPEL )
|
||||
spellInfo->Effect[1] == SPELL_EFFECT_STEAL_BENEFICIAL_BUFF ||
|
||||
spellInfo->Effect[2] == SPELL_EFFECT_DISPEL ||
|
||||
spellInfo->Effect[2] == SPELL_EFFECT_STEAL_BENEFICIAL_BUFF)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool isSpellBreakStealth(SpellEntry const* spellInfo)
|
||||
{
|
||||
return !(spellInfo->AttributesEx & SPELL_ATTR_EX_NOT_BREAK_STEALTH);
|
||||
@@ -745,6 +750,7 @@ inline bool IsProfessionSkill(uint32 skill)
|
||||
#define SPELL_ATTR_CU_AURA_DOT 0x00000020
|
||||
#define SPELL_ATTR_CU_AURA_CC 0x00000040
|
||||
#define SPELL_ATTR_CU_AURA_SPELL 0x00000080
|
||||
#define SPELL_ATTR_CU_DIRECT_DAMAGE 0x00000100
|
||||
|
||||
typedef std::vector<uint32> SpellCustomAttribute;
|
||||
|
||||
|
||||
+23
-18
@@ -982,23 +982,6 @@ void Pet::UpdateAttackPowerAndDamage(bool ranged)
|
||||
frost = 0;
|
||||
SetBonusDamage( int32(frost * 0.4f));
|
||||
}
|
||||
//force of nature
|
||||
else if(GetEntry() == 1964)
|
||||
{
|
||||
int32 spellDmg = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_NATURE)) - owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_NATURE);
|
||||
if(spellDmg > 0)
|
||||
SetBonusDamage(int32(spellDmg * 0.09f));
|
||||
}
|
||||
//greater fire elemental
|
||||
else if(GetEntry() == 15438)
|
||||
{
|
||||
if(Unit* shaman = owner->GetOwner())
|
||||
{
|
||||
int32 spellDmg = int32(shaman->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FIRE)) - shaman->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FIRE);
|
||||
if(spellDmg > 0)
|
||||
SetBonusDamage(int32(spellDmg * 0.4f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, val + bonusAP);
|
||||
@@ -1024,11 +1007,33 @@ void Pet::UpdateDamagePhysical(WeaponAttackType attType)
|
||||
if(attType > BASE_ATTACK)
|
||||
return;
|
||||
|
||||
float bonusDamage = 0.0f;
|
||||
if(Unit* owner = GetOwner())
|
||||
{
|
||||
//force of nature
|
||||
if(GetEntry() == 1964)
|
||||
{
|
||||
int32 spellDmg = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_NATURE)) - owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_NATURE);
|
||||
if(spellDmg > 0)
|
||||
bonusDamage = spellDmg * 0.09f;
|
||||
}
|
||||
//greater fire elemental
|
||||
else if(GetEntry() == 15438)
|
||||
{
|
||||
if(Unit* shaman = owner->GetOwner())
|
||||
{
|
||||
int32 spellDmg = int32(shaman->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FIRE)) - shaman->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FIRE);
|
||||
if(spellDmg > 0)
|
||||
bonusDamage = spellDmg * 0.4f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND;
|
||||
|
||||
float att_speed = float(GetAttackTime(BASE_ATTACK))/1000.0f;
|
||||
|
||||
float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed;
|
||||
float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed + bonusDamage;
|
||||
float base_pct = GetModifierValue(unitMod, BASE_PCT);
|
||||
float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
|
||||
float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
|
||||
|
||||
@@ -172,9 +172,9 @@ void TemporarySummon::Summon(TempSummonType type, uint32 lifetime)
|
||||
|
||||
void TemporarySummon::UnSummon()
|
||||
{
|
||||
CombatStop();
|
||||
RemoveCharmedOrPossessedBy(NULL);
|
||||
|
||||
UnpossessSelf(false);
|
||||
CombatStop();
|
||||
|
||||
CleanupsBeforeDelete();
|
||||
AddObjectToRemoveList();
|
||||
|
||||
+260
-72
@@ -158,7 +158,6 @@ Unit::Unit()
|
||||
m_removedAuras = 0;
|
||||
m_charmInfo = NULL;
|
||||
m_unit_movement_flags = 0;
|
||||
m_isPossessed = false;
|
||||
m_reducedThreatPercent = 0;
|
||||
m_misdirectionTargetGUID = 0;
|
||||
|
||||
@@ -567,7 +566,7 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
|
||||
|
||||
CreatureInfo const* cInfo = ((Creature*)pVictim)->GetCreatureInfo();
|
||||
if(cInfo && cInfo->lootid)
|
||||
pVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
|
||||
pVictim->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
|
||||
|
||||
// some critters required for quests
|
||||
if(GetTypeId() == TYPEID_PLAYER)
|
||||
@@ -1160,17 +1159,14 @@ uint32 Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage
|
||||
|
||||
void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage *damageInfo, int32 damage, SpellEntry const *spellInfo, WeaponAttackType attackType)
|
||||
{
|
||||
SpellSchoolMask damageSchoolMask = SpellSchoolMask(damageInfo->schoolMask);
|
||||
Unit *pVictim = damageInfo->target;
|
||||
|
||||
if (damage < 0)
|
||||
return;
|
||||
|
||||
if(!this || !pVictim)
|
||||
return;
|
||||
if(!this->isAlive() || !pVictim->isAlive())
|
||||
Unit *pVictim = damageInfo->target;
|
||||
if(!pVictim || !pVictim->isAlive())
|
||||
return;
|
||||
|
||||
SpellSchoolMask damageSchoolMask = SpellSchoolMask(damageInfo->schoolMask);
|
||||
uint32 crTypeMask = pVictim->GetCreatureTypeMask();
|
||||
// Check spell crit chance
|
||||
bool crit = isSpellCrit(pVictim, spellInfo, damageSchoolMask, attackType);
|
||||
@@ -1185,17 +1181,10 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage *damageInfo, int32 dama
|
||||
// Physical Damage
|
||||
if ( damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL )
|
||||
{
|
||||
//Calculate armor mitigation
|
||||
//damage = CalcArmorReducedDamage(pVictim, damage);
|
||||
// Get blocked status
|
||||
blocked = isSpellBlocked(pVictim, spellInfo, attackType);
|
||||
}
|
||||
// Magical Damage
|
||||
/*else
|
||||
{
|
||||
// Calculate damage bonus
|
||||
damage = SpellDamageBonus(pVictim, spellInfo, damage, SPELL_DIRECT_DAMAGE);
|
||||
}*/
|
||||
|
||||
if (crit)
|
||||
{
|
||||
damageInfo->HitInfo|= SPELL_HIT_TYPE_CRIT;
|
||||
@@ -1240,8 +1229,6 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage *damageInfo, int32 dama
|
||||
case SPELL_DAMAGE_CLASS_NONE:
|
||||
case SPELL_DAMAGE_CLASS_MAGIC:
|
||||
{
|
||||
// Calculate damage bonus
|
||||
//damage = SpellDamageBonus(pVictim, spellInfo, damage, SPELL_DIRECT_DAMAGE);
|
||||
// If crit add critical bonus
|
||||
if (crit)
|
||||
{
|
||||
@@ -7038,10 +7025,11 @@ void Unit::SetPet(Pet* pet)
|
||||
|
||||
void Unit::SetCharm(Unit* pet)
|
||||
{
|
||||
SetUInt64Value(UNIT_FIELD_CHARM, pet ? pet->GetGUID() : 0);
|
||||
|
||||
if(GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
SetUInt64Value(UNIT_FIELD_CHARM, pet ? pet->GetGUID() : 0);
|
||||
((Player*)this)->m_mover = pet ? pet : this;
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::AddPlayerToVision(Player* plr)
|
||||
@@ -7084,21 +7072,6 @@ void Unit::UncharmSelf()
|
||||
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)
|
||||
@@ -7142,8 +7115,8 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
|
||||
if(!spellProto || !pVictim || damagetype==DIRECT_DAMAGE )
|
||||
return pdamage;
|
||||
|
||||
if(spellProto->SchoolMask == SPELL_SCHOOL_MASK_NORMAL)
|
||||
return pdamage;
|
||||
//if(spellProto->SchoolMask == SPELL_SCHOOL_MASK_NORMAL)
|
||||
// return pdamage;
|
||||
//damage = CalcArmorReducedDamage(pVictim, damage);
|
||||
|
||||
int32 BonusDamage = 0;
|
||||
@@ -7521,7 +7494,9 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
|
||||
|
||||
// Spellmod SpellDamage
|
||||
//float SpellModSpellDamage = 100.0f;
|
||||
float CoefficientPtc = ((float)CastingTime/3500.0f)*DotFactor*100.0f;
|
||||
float CoefficientPtc = DotFactor * 100.0f;
|
||||
if(spellProto->SchoolMask != SPELL_SCHOOL_MASK_NORMAL)
|
||||
CoefficientPtc *= ((float)CastingTime/3500.0f);
|
||||
|
||||
if(Player* modOwner = GetSpellModOwner())
|
||||
//modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_SPELL_BONUS_DAMAGE,SpellModSpellDamage);
|
||||
@@ -7531,10 +7506,11 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
|
||||
CoefficientPtc /= 100.0f;
|
||||
|
||||
//float DoneActualBenefit = DoneAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * SpellModSpellDamage * LvlPenalty;
|
||||
|
||||
float DoneActualBenefit = DoneAdvertisedBenefit * CoefficientPtc * LvlPenalty;
|
||||
float TakenActualBenefit = TakenAdvertisedBenefit;
|
||||
if(spellProto->SpellFamilyName)
|
||||
TakenActualBenefit *= (CastingTime / 3500.0f) * DotFactor * LvlPenalty;
|
||||
float TakenActualBenefit = TakenAdvertisedBenefit * DotFactor * LvlPenalty;
|
||||
if(spellProto->SpellFamilyName && spellProto->SchoolMask != SPELL_SCHOOL_MASK_NORMAL)
|
||||
TakenActualBenefit *= ((float)CastingTime / 3500.0f);
|
||||
|
||||
float tmpDamage = (float(pdamage)+DoneActualBenefit)*DoneTotalMod;
|
||||
|
||||
@@ -8642,6 +8618,24 @@ bool Unit::canDetectStealthOf(Unit const* target, float distance) const
|
||||
return distance < visibleDistance;
|
||||
}
|
||||
|
||||
void Unit::DestroyForNearbyPlayers()
|
||||
{
|
||||
if(!IsInWorld())
|
||||
return;
|
||||
|
||||
std::list<Unit*> targets;
|
||||
Trinity::AnyUnitInObjectRangeCheck check(this, World::GetMaxVisibleDistance());
|
||||
Trinity::UnitListSearcher<Trinity::AnyUnitInObjectRangeCheck> searcher(targets, check);
|
||||
VisitNearbyWorldObject(World::GetMaxVisibleDistance(), searcher);
|
||||
for(std::list<Unit*>::iterator iter = targets.begin(); iter != targets.end(); ++iter)
|
||||
if(*iter != this && (*iter)->GetTypeId() == TYPEID_PLAYER
|
||||
&& ((Player*)(*iter))->HaveAtClient(this))
|
||||
{
|
||||
DestroyForPlayer((Player*)(*iter));
|
||||
((Player*)(*iter))->m_clientGUIDs.erase(GetGUID());
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::SetVisibility(UnitVisibility x)
|
||||
{
|
||||
m_Visibility = x;
|
||||
@@ -8650,27 +8644,7 @@ void Unit::SetVisibility(UnitVisibility x)
|
||||
SetToNotify();
|
||||
|
||||
if(x == VISIBILITY_GROUP_STEALTH)
|
||||
{
|
||||
std::list<Unit*> targets;
|
||||
Trinity::AnyUnitInObjectRangeCheck check(this, World::GetMaxVisibleDistance());
|
||||
Trinity::UnitListSearcher<Trinity::AnyUnitInObjectRangeCheck> searcher(targets, check);
|
||||
VisitNearbyWorldObject(World::GetMaxVisibleDistance(), searcher);
|
||||
for(std::list<Unit*>::iterator iter = targets.begin(); iter != targets.end(); ++iter)
|
||||
if(*iter != this && (*iter)->GetTypeId() == TYPEID_PLAYER
|
||||
&& ((Player*)(*iter))->HaveAtClient(this))
|
||||
{
|
||||
DestroyForPlayer((Player*)(*iter));
|
||||
((Player*)(*iter))->m_clientGUIDs.erase(GetGUID());
|
||||
}
|
||||
}
|
||||
/*{
|
||||
Map *m = GetMap();
|
||||
|
||||
if(GetTypeId()==TYPEID_PLAYER)
|
||||
m->PlayerRelocation((Player*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
|
||||
else
|
||||
m->CreatureRelocation((Creature*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
|
||||
}*/
|
||||
DestroyForNearbyPlayers();
|
||||
}
|
||||
|
||||
void Unit::UpdateSpeed(UnitMoveType mtype, bool forced)
|
||||
@@ -8905,7 +8879,7 @@ void Unit::setDeathState(DeathState s)
|
||||
UnsummonAllTotems();
|
||||
|
||||
// Possessed unit died, restore control to possessor
|
||||
UnpossessSelf(false);
|
||||
RemoveCharmedOrPossessedBy(NULL);
|
||||
RemoveAllFromVision();
|
||||
|
||||
ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false);
|
||||
@@ -9779,7 +9753,7 @@ void Unit::CleanupsBeforeDelete()
|
||||
{
|
||||
if(m_uint32Values) // only for fully created object
|
||||
{
|
||||
UnpossessSelf(false);
|
||||
RemoveCharmedOrPossessedBy(NULL);
|
||||
RemoveAllFromVision();
|
||||
InterruptNonMeleeSpells(true);
|
||||
m_Events.KillAllEvents(false); // non-delatable (currently casted spells) will not deleted now but it will deleted at call in Map::RemoveAllObjectsInRemoveList
|
||||
@@ -11439,22 +11413,236 @@ void Unit::SetConfused(bool apply)
|
||||
((Player*)this)->SetClientControl(this, !apply);
|
||||
}
|
||||
|
||||
void Unit::SetCharmedOrPossessedBy(Unit* charmer, bool possess)
|
||||
{
|
||||
if(!charmer)
|
||||
return;
|
||||
|
||||
assert(!possess || charmer->GetTypeId() == TYPEID_PLAYER);
|
||||
|
||||
if(this == charmer)
|
||||
return;
|
||||
|
||||
if(isInFlight())
|
||||
return;
|
||||
|
||||
if(GetTypeId() == TYPEID_PLAYER && ((Player*)this)->GetTransport())
|
||||
return;
|
||||
|
||||
RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
|
||||
CastStop();
|
||||
CombatStop(); //TODO: CombatStop(true) may cause crash (interrupt spells)
|
||||
DeleteThreatList();
|
||||
|
||||
// Charmer stop charming
|
||||
if(charmer->GetTypeId() == TYPEID_PLAYER)
|
||||
((Player*)charmer)->StopCharmOrPossess();
|
||||
|
||||
// Charmed stop charming
|
||||
if(GetTypeId() == TYPEID_PLAYER)
|
||||
((Player*)this)->StopCharmOrPossess();
|
||||
|
||||
// Charmed stop being charmed
|
||||
RemoveCharmedOrPossessedBy(NULL);
|
||||
|
||||
// Set charmed
|
||||
charmer->SetCharm(this);
|
||||
SetCharmerGUID(charmer->GetGUID());
|
||||
setFaction(charmer->getFaction());
|
||||
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
|
||||
|
||||
if(GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
((Creature*)this)->InitPossessedAI();
|
||||
StopMoving();
|
||||
GetMotionMaster()->Clear(false);
|
||||
GetMotionMaster()->MoveIdle();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(((Player*)this)->isAFK())
|
||||
((Player*)this)->ToggleAFK();
|
||||
((Player*)this)->SetViewport(GetGUID(), false);
|
||||
}
|
||||
|
||||
// Pets already have a properly initialized CharmInfo, don't overwrite it.
|
||||
if(GetTypeId() == TYPEID_PLAYER || GetTypeId() == TYPEID_UNIT && !((Creature*)this)->isPet())
|
||||
{
|
||||
CharmInfo *charmInfo = InitCharmInfo(this);
|
||||
charmInfo->SetReactState(REACT_DEFENSIVE);
|
||||
if(possess)
|
||||
charmInfo->InitPossessCreateSpells();
|
||||
else
|
||||
charmInfo->InitCharmCreateSpells();
|
||||
}
|
||||
|
||||
//Set possessed
|
||||
if(possess)
|
||||
{
|
||||
addUnitState(UNIT_STAT_POSSESSED);
|
||||
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNKNOWN5);
|
||||
AddPlayerToVision((Player*)charmer);
|
||||
((Player*)charmer)->SetViewport(GetGUID(), true);
|
||||
charmer->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
|
||||
}
|
||||
// Charm demon
|
||||
else if(GetTypeId() == TYPEID_UNIT && charmer->GetTypeId() == TYPEID_PLAYER && charmer->getClass() == CLASS_WARLOCK)
|
||||
{
|
||||
CreatureInfo const *cinfo = ((Creature*)this)->GetCreatureInfo();
|
||||
if(cinfo && cinfo->type == CREATURE_TYPE_DEMON)
|
||||
{
|
||||
//to prevent client crash
|
||||
SetFlag(UNIT_FIELD_BYTES_0, 2048);
|
||||
|
||||
//just to enable stat window
|
||||
if(GetCharmInfo())
|
||||
GetCharmInfo()->SetPetNumber(objmgr.GeneratePetNumber(), true);
|
||||
|
||||
//if charmed two demons the same session, the 2nd gets the 1st one's name
|
||||
SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
|
||||
}
|
||||
}
|
||||
|
||||
if(possess)
|
||||
((Player*)charmer)->PossessSpellInitialize();
|
||||
else if(charmer->GetTypeId() == TYPEID_PLAYER)
|
||||
((Player*)charmer)->CharmSpellInitialize();
|
||||
}
|
||||
|
||||
void Unit::RemoveCharmedOrPossessedBy(Unit *charmer)
|
||||
{
|
||||
if(!isCharmed())
|
||||
return;
|
||||
|
||||
if(!charmer)
|
||||
charmer = GetCharmer();
|
||||
else if(charmer != GetCharmer()) // one aura overrides another?
|
||||
return;
|
||||
|
||||
bool possess = hasUnitState(UNIT_STAT_POSSESSED);
|
||||
|
||||
CastStop();
|
||||
CombatStop(); //TODO: CombatStop(true) may cause crash (interrupt spells)
|
||||
getHostilRefManager().deleteReferences();
|
||||
DeleteThreatList();
|
||||
SetCharmerGUID(0);
|
||||
RestoreFaction();
|
||||
|
||||
if(possess)
|
||||
{
|
||||
clearUnitState(UNIT_STAT_POSSESSED);
|
||||
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNKNOWN5);
|
||||
}
|
||||
|
||||
if(GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
if(!((Creature*)this)->isPet())
|
||||
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
|
||||
|
||||
((Creature*)this)->DisablePossessedAI();
|
||||
if(isAlive() && ((Creature*)this)->AI())
|
||||
{
|
||||
if(charmer && !IsFriendlyTo(charmer))
|
||||
{
|
||||
((Creature*)this)->AddThreat(charmer, 10000.0f);
|
||||
((Creature*)this)->AI()->AttackStart(charmer);
|
||||
}
|
||||
else
|
||||
((Creature*)this)->AI()->EnterEvadeMode();
|
||||
}
|
||||
}
|
||||
else
|
||||
((Player*)this)->SetViewport(GetGUID(), true);
|
||||
|
||||
// If charmer still exists
|
||||
if(!charmer)
|
||||
return;
|
||||
|
||||
assert(!possess || charmer->GetTypeId() == TYPEID_PLAYER);
|
||||
|
||||
charmer->SetCharm(0);
|
||||
if(possess)
|
||||
{
|
||||
RemovePlayerFromVision((Player*)charmer);
|
||||
((Player*)charmer)->SetViewport(charmer->GetGUID(), true);
|
||||
charmer->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
|
||||
}
|
||||
// restore UNIT_FIELD_BYTES_0
|
||||
else if(GetTypeId() == TYPEID_UNIT && charmer->GetTypeId() == TYPEID_PLAYER && charmer->getClass() == CLASS_WARLOCK)
|
||||
{
|
||||
CreatureInfo const *cinfo = ((Creature*)this)->GetCreatureInfo();
|
||||
if(cinfo && cinfo->type == CREATURE_TYPE_DEMON)
|
||||
{
|
||||
CreatureDataAddon const *cainfo = ((Creature*)this)->GetCreatureAddon();
|
||||
if(cainfo && cainfo->bytes0 != 0)
|
||||
SetUInt32Value(UNIT_FIELD_BYTES_0, cainfo->bytes0);
|
||||
else
|
||||
RemoveFlag(UNIT_FIELD_BYTES_0, 2048);
|
||||
|
||||
if(GetCharmInfo())
|
||||
GetCharmInfo()->SetPetNumber(0, true);
|
||||
else
|
||||
sLog.outError("Aura::HandleModCharm: target="I64FMTD" with typeid=%d has a charm aura but no charm info!", GetGUID(), GetTypeId());
|
||||
}
|
||||
}
|
||||
|
||||
if(possess || charmer->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
// Remove pet spell action bar
|
||||
WorldPacket data(SMSG_PET_SPELLS, 8);
|
||||
data << uint64(0);
|
||||
((Player*)charmer)->GetSession()->SendPacket(&data);
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::RestoreFaction()
|
||||
{
|
||||
if(GetTypeId() == TYPEID_PLAYER)
|
||||
((Player*)this)->setFactionForRace(getRace());
|
||||
else
|
||||
{
|
||||
CreatureInfo const *cinfo = ((Creature*)this)->GetCreatureInfo();
|
||||
|
||||
if(((Creature*)this)->isPet())
|
||||
{
|
||||
if(Unit* owner = GetOwner())
|
||||
setFaction(owner->getFaction());
|
||||
else if(cinfo)
|
||||
setFaction(cinfo->faction_A);
|
||||
}
|
||||
else if(cinfo) // normal creature
|
||||
setFaction(cinfo->faction_A);
|
||||
}
|
||||
}
|
||||
|
||||
bool Unit::IsInPartyWith(Unit const *unit) const
|
||||
{
|
||||
const Player *p1 = GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
const Player *p2 = unit->GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
if(p1 && p2)
|
||||
return p1->IsInSameGroupWith(p2);
|
||||
if(this == unit)
|
||||
return true;
|
||||
|
||||
const Unit *u1 = GetCharmerOrOwnerOrSelf();
|
||||
const Unit *u2 = unit->GetCharmerOrOwnerOrSelf();
|
||||
if(u1 == u2)
|
||||
return true;
|
||||
|
||||
if(u1->GetTypeId() == TYPEID_PLAYER && u2->GetTypeId() == TYPEID_PLAYER)
|
||||
return ((Player*)u1)->IsInSameGroupWith((Player*)u2);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Unit::IsInRaidWith(Unit const *unit) const
|
||||
{
|
||||
const Player *p1 = GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
const Player *p2 = unit->GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
if(p1 && p2)
|
||||
return p1->IsInSameRaidWith(p2);
|
||||
if(this == unit)
|
||||
return true;
|
||||
|
||||
const Unit *u1 = GetCharmerOrOwnerOrSelf();
|
||||
const Unit *u2 = unit->GetCharmerOrOwnerOrSelf();
|
||||
if(u1 == u2)
|
||||
return true;
|
||||
|
||||
if(u1->GetTypeId() == TYPEID_PLAYER && u2->GetTypeId() == TYPEID_PLAYER)
|
||||
return ((Player*)u1)->IsInSameRaidWith((Player*)u2);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
+28
-39
@@ -364,27 +364,28 @@ enum DeathState
|
||||
|
||||
enum UnitState
|
||||
{
|
||||
UNIT_STAT_DIED = 0x0001,
|
||||
UNIT_STAT_MELEE_ATTACKING = 0x0002, // player is melee attacking someone
|
||||
//UNIT_STAT_MELEE_ATTACK_BY = 0x0004, // player is melee attack by someone
|
||||
UNIT_STAT_STUNNED = 0x0008,
|
||||
UNIT_STAT_ROAMING = 0x0010,
|
||||
UNIT_STAT_CHASE = 0x0020,
|
||||
UNIT_STAT_SEARCHING = 0x0040,
|
||||
UNIT_STAT_FLEEING = 0x0080,
|
||||
UNIT_STAT_DIED = 0x00000001,
|
||||
UNIT_STAT_MELEE_ATTACKING = 0x00000002, // player is melee attacking someone
|
||||
//UNIT_STAT_MELEE_ATTACK_BY = 0x00000004, // player is melee attack by someone
|
||||
UNIT_STAT_STUNNED = 0x00000008,
|
||||
UNIT_STAT_ROAMING = 0x00000010,
|
||||
UNIT_STAT_CHASE = 0x00000020,
|
||||
UNIT_STAT_SEARCHING = 0x00000040,
|
||||
UNIT_STAT_FLEEING = 0x00000080,
|
||||
UNIT_STAT_IN_FLIGHT = 0x00000100, // player is in flight mode
|
||||
UNIT_STAT_FOLLOW = 0x00000200,
|
||||
UNIT_STAT_ROOT = 0x00000400,
|
||||
UNIT_STAT_CONFUSED = 0x00000800,
|
||||
UNIT_STAT_DISTRACTED = 0x00001000,
|
||||
UNIT_STAT_ISOLATED = 0x00002000, // area auras do not affect other players
|
||||
UNIT_STAT_ATTACK_PLAYER = 0x00004000,
|
||||
UNIT_STAT_CASTING = 0x00008000,
|
||||
UNIT_STAT_POSSESSED = 0x00010000,
|
||||
UNIT_STAT_MOVING = (UNIT_STAT_ROAMING | UNIT_STAT_CHASE | UNIT_STAT_SEARCHING | UNIT_STAT_FLEEING),
|
||||
UNIT_STAT_IN_FLIGHT = 0x0100, // player is in flight mode
|
||||
UNIT_STAT_FOLLOW = 0x0200,
|
||||
UNIT_STAT_ROOT = 0x0400,
|
||||
UNIT_STAT_CONFUSED = 0x0800,
|
||||
UNIT_STAT_DISTRACTED = 0x1000,
|
||||
UNIT_STAT_ISOLATED = 0x2000, // area auras do not affect other players
|
||||
UNIT_STAT_ATTACK_PLAYER = 0x4000,
|
||||
UNIT_STAT_CASTING = 0x8000,
|
||||
UNIT_STAT_LOST_CONTROL = (UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING),
|
||||
UNIT_STAT_SIGHTLESS = (UNIT_STAT_LOST_CONTROL | UNIT_STAT_CHASE | UNIT_STAT_SEARCHING),
|
||||
UNIT_STAT_CANNOT_AUTOATTACK = (UNIT_STAT_LOST_CONTROL | UNIT_STAT_CASTING),
|
||||
UNIT_STAT_ALL_STATE = 0xffff //(UNIT_STAT_STOPPED | UNIT_STAT_MOVING | UNIT_STAT_IN_COMBAT | UNIT_STAT_IN_FLIGHT)
|
||||
UNIT_STAT_ALL_STATE = 0xffffffff //(UNIT_STAT_STOPPED | UNIT_STAT_MOVING | UNIT_STAT_IN_COMBAT | UNIT_STAT_IN_FLIGHT)
|
||||
};
|
||||
|
||||
enum UnitMoveType
|
||||
@@ -937,7 +938,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
|
||||
|
||||
uint16 GetMaxSkillValueForLevel(Unit const* target = NULL) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; }
|
||||
void RemoveSpellbyDamageTaken(uint32 damage, uint32 spell);
|
||||
uint32 DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellEntry const *spellProto, bool durabilityLoss);
|
||||
uint32 DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage = NULL, DamageEffectType damagetype = DIRECT_DAMAGE, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellEntry const *spellProto = NULL, bool durabilityLoss = true);
|
||||
void Kill(Unit *pVictim, bool durabilityLoss = true);
|
||||
|
||||
void ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellEntry const *procSpell = NULL);
|
||||
@@ -1093,35 +1094,24 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
|
||||
Unit* GetCharmer() const;
|
||||
Unit* GetCharm() const;
|
||||
Unit* GetCharmerOrOwner() const { return GetCharmerGUID() ? GetCharmer() : GetOwner(); }
|
||||
Unit* GetCharmerOrOwnerOrSelf()
|
||||
Unit* GetCharmerOrOwnerOrSelf() const
|
||||
{
|
||||
if(Unit* u = GetCharmerOrOwner())
|
||||
if(Unit *u = GetCharmerOrOwner())
|
||||
return u;
|
||||
|
||||
return this;
|
||||
return (Unit*)this;
|
||||
}
|
||||
Player* GetCharmerOrOwnerPlayerOrPlayerItself() const;
|
||||
|
||||
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);
|
||||
}
|
||||
void SetCharmedOrPossessedBy(Unit* charmer, bool possess);
|
||||
void RemoveCharmedOrPossessedBy(Unit* charmer);
|
||||
void RestoreFaction();
|
||||
|
||||
bool isCharmed() const { return GetCharmerGUID() != 0; }
|
||||
bool isPossessed() const { return m_isPossessed; }
|
||||
bool isPossessedByPlayer() const { return m_isPossessed && IS_PLAYER_GUID(GetCharmerGUID()); }
|
||||
bool isPossessed() const { return hasUnitState(UNIT_STAT_POSSESSED); }
|
||||
bool isPossessedByPlayer() const { return hasUnitState(UNIT_STAT_POSSESSED) && IS_PLAYER_GUID(GetCharmerGUID()); }
|
||||
bool isPossessing() const
|
||||
{
|
||||
if(Unit *u = GetCharm())
|
||||
@@ -1139,7 +1129,6 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
|
||||
void RemovePlayerFromVision(Player* plr);
|
||||
void RemoveAllFromVision();
|
||||
void UncharmSelf();
|
||||
void UnpossessSelf(bool attack);
|
||||
|
||||
Pet* CreateTamedPetFrom(Creature* creatureTarget,uint32 spell_id = 0);
|
||||
|
||||
@@ -1260,6 +1249,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
|
||||
// Visibility system
|
||||
UnitVisibility GetVisibility() const { return m_Visibility; }
|
||||
void SetVisibility(UnitVisibility x);
|
||||
void DestroyForNearbyPlayers();
|
||||
|
||||
// common function for visibility checks for player/creatures with detection code
|
||||
virtual bool canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList = false, bool is3dDistance = true) const;
|
||||
@@ -1510,7 +1500,6 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
|
||||
float m_speed_rate[MAX_MOVE_TYPE];
|
||||
|
||||
CharmInfo *m_charmInfo;
|
||||
bool m_isPossessed;
|
||||
SharedVisionList m_sharedVision;
|
||||
|
||||
virtual SpellSchoolMask GetMeleeDamageSchoolMask() const;
|
||||
|
||||
+27
-10
@@ -1036,6 +1036,7 @@ void World::LoadConfigSettings(bool reload)
|
||||
m_configs[CONFIG_NO_RESET_TALENT_COST] = sConfig.GetBoolDefault("NoResetTalentsCost", false);
|
||||
m_configs[CONFIG_SHOW_KICK_IN_WORLD] = sConfig.GetBoolDefault("ShowKickInWorld", false);
|
||||
m_configs[CONFIG_INTERVAL_LOG_UPDATE] = sConfig.GetIntDefault("RecordUpdateTimeDiffInterval", 60000);
|
||||
m_configs[CONFIG_MIN_LOG_UPDATE] = sConfig.GetIntDefault("MinRecordUpdateTimeDiff", 10);
|
||||
|
||||
std::string forbiddenmaps = sConfig.GetStringDefault("ForbiddenMaps", "");
|
||||
char * forbiddenMaps = new char[forbiddenmaps.length() + 1];
|
||||
@@ -1471,14 +1472,29 @@ void World::DetectDBCLang()
|
||||
sLog.outString("Using %s DBC Locale as default. All available DBC locales: %s",localeNames[m_defaultDbcLocale],availableLocalsStr.empty() ? "<none>" : availableLocalsStr.c_str());
|
||||
}
|
||||
|
||||
void World::RecordTimeDiff(const char *text)
|
||||
void World::RecordTimeDiff(const char *text, ...)
|
||||
{
|
||||
if(m_updateTimeCount != 1)
|
||||
return;
|
||||
sLog.outDebugInLine("Difftime ");
|
||||
sLog.outDebugInLine(text);
|
||||
uint32 thisTime = getMSTime();
|
||||
sLog.outDebug(": %u.", getMSTimeDiff(m_currentTime, thisTime));
|
||||
if(!text)
|
||||
{
|
||||
m_currentTime = getMSTime();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 thisTime = getMSTime();
|
||||
uint32 diff = getMSTimeDiff(m_currentTime, thisTime);
|
||||
|
||||
if(diff > m_configs[CONFIG_MIN_LOG_UPDATE])
|
||||
{
|
||||
va_list ap;
|
||||
char str [256];
|
||||
va_start(ap, text);
|
||||
vsnprintf(str,256,text, ap );
|
||||
va_end(ap);
|
||||
sLog.outDetail("Difftime %s: %u.", str, diff);
|
||||
}
|
||||
|
||||
m_currentTime = thisTime;
|
||||
}
|
||||
|
||||
@@ -1493,7 +1509,6 @@ void World::Update(time_t diff)
|
||||
sLog.outString("Update time diff: %u. Players online: %u.", m_updateTimeSum / m_updateTimeCount, GetActiveSessionCount());
|
||||
m_updateTimeSum = m_updateTime;
|
||||
m_updateTimeCount = 1;
|
||||
m_currentTime = getMSTime();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1580,8 +1595,8 @@ void World::Update(time_t diff)
|
||||
}
|
||||
}
|
||||
}
|
||||
RecordTimeDiff("UpdateAuction");
|
||||
|
||||
RecordTimeDiff(NULL);
|
||||
/// <li> Handle session updates when the timer has passed
|
||||
if (m_timers[WUPDATE_SESSIONS].Passed())
|
||||
{
|
||||
@@ -1621,7 +1636,6 @@ void World::Update(time_t diff)
|
||||
m_timers[WUPDATE_UPTIME].Reset();
|
||||
WorldDatabase.PExecute("UPDATE uptime SET uptime = %d, maxplayers = %d WHERE starttime = " I64FMTD, tmpDiff, maxClientsNum, uint64(m_startTime));
|
||||
}
|
||||
RecordTimeDiff("UpdateWeatherAndUptime");
|
||||
|
||||
/// <li> Handle all other objects
|
||||
if (m_timers[WUPDATE_OBJECTS].Passed())
|
||||
@@ -1630,16 +1644,20 @@ void World::Update(time_t diff)
|
||||
///- Update objects when the timer has passed (maps, transport, creatures,...)
|
||||
MapManager::Instance().Update(diff); // As interval = 0
|
||||
|
||||
RecordTimeDiff(NULL);
|
||||
///- Process necessary scripts
|
||||
if (!m_scriptSchedule.empty())
|
||||
ScriptsProcess();
|
||||
RecordTimeDiff("UpdateScriptsProcess");
|
||||
|
||||
sBattleGroundMgr.Update(diff);
|
||||
RecordTimeDiff("UpdateBattleGroundMgr");
|
||||
|
||||
sOutdoorPvPMgr.Update(diff);
|
||||
RecordTimeDiff("UpdateOutdoorPvPMgr");
|
||||
}
|
||||
RecordTimeDiff("UpdateMaps");
|
||||
|
||||
RecordTimeDiff(NULL);
|
||||
// execute callbacks from sql queries that were queued recently
|
||||
UpdateResultQueue();
|
||||
RecordTimeDiff("UpdateResultQueue");
|
||||
@@ -1670,7 +1688,6 @@ void World::Update(time_t diff)
|
||||
|
||||
// And last, but not least handle the issued cli commands
|
||||
ProcessCliCommands();
|
||||
RecordTimeDiff("UpdateRemainingThings");
|
||||
}
|
||||
|
||||
void World::ForceGameEventUpdate()
|
||||
|
||||
+2
-1
@@ -207,6 +207,7 @@ enum WorldConfigs
|
||||
CONFIG_NO_RESET_TALENT_COST,
|
||||
CONFIG_SHOW_KICK_IN_WORLD,
|
||||
CONFIG_INTERVAL_LOG_UPDATE,
|
||||
CONFIG_MIN_LOG_UPDATE,
|
||||
CONFIG_ENABLE_SINFO_LOGIN,
|
||||
|
||||
CONFIG_VALUE_COUNT
|
||||
@@ -528,6 +529,7 @@ class World
|
||||
void SetScriptsVersion(char const* version) { m_ScriptsVersion = version ? version : "unknown scripting library"; }
|
||||
char const* GetScriptsVersion() { return m_ScriptsVersion.c_str(); }
|
||||
|
||||
void RecordTimeDiff(const char * text, ...);
|
||||
protected:
|
||||
void _UpdateGameTime();
|
||||
void ScriptsProcess();
|
||||
@@ -550,7 +552,6 @@ class World
|
||||
uint32 m_updateTime, m_updateTimeSum;
|
||||
uint32 m_updateTimeCount;
|
||||
uint32 m_currentTime;
|
||||
void RecordTimeDiff(const char * text);
|
||||
|
||||
typedef UNORDERED_MAP<uint32, Weather*> WeatherMap;
|
||||
WeatherMap m_weathers;
|
||||
|
||||
@@ -249,6 +249,14 @@ void WorldSession::LogoutPlayer(bool Save)
|
||||
|
||||
if (_player)
|
||||
{
|
||||
// Unpossess the current possessed unit of player
|
||||
_player->StopCharmOrPossess();
|
||||
|
||||
// Remove any possession of this player on logout
|
||||
_player->RemoveCharmedOrPossessedBy(NULL);
|
||||
|
||||
_player->DestroyForNearbyPlayers();
|
||||
|
||||
if (uint64 lguid = GetPlayer()->GetLootGUID())
|
||||
DoLootRelease(lguid);
|
||||
|
||||
@@ -374,13 +382,6 @@ 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
|
||||
|
||||
Reference in New Issue
Block a user