aboutsummaryrefslogtreecommitdiff
path: root/src/game/Player.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/Player.cpp')
-rw-r--r--src/game/Player.cpp284
1 files changed, 270 insertions, 14 deletions
diff --git a/src/game/Player.cpp b/src/game/Player.cpp
index dc4092540d9..02d16277476 100644
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -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;
+}