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

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

--HG--
branch : trunk
This commit is contained in:
gvcoman
2008-11-05 20:51:05 -06:00
parent 8d331f2b10
commit 44bdb135f4
41 changed files with 1105 additions and 374 deletions

View File

@@ -469,6 +469,9 @@ Player::~Player ()
for(BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr)
itr->second.save->RemovePlayer(this);
if (isPossessing())
RemovePossess(false);
delete m_declinedname;
}
@@ -1253,7 +1256,7 @@ void Player::Update( uint32 p_time )
SendUpdateToOutOfRangeGroupMembers();
Pet* pet = GetPet();
if(pet && !IsWithinDistInMap(pet, OWNER_MAX_DISTANCE))
if(pet && !IsWithinDistInMap(pet, OWNER_MAX_DISTANCE) && !pet->isPossessed())
{
RemovePet(pet, PET_SAVE_NOT_IN_SLOT, true);
return;
@@ -1534,6 +1537,10 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
SetSemaphoreTeleport(true);
// Remove any possession on the player before teleporting
if (isPossessedByPlayer())
((Player*)GetCharmer())->RemovePossess();
// The player was ported to another map and looses the duel immediatly.
// We have to perform this check before the teleport, otherwise the
// ObjectAccessor won't find the flag.
@@ -1747,6 +1754,7 @@ void Player::RemoveFromWorld()
if(IsInWorld())
{
///- Release charmed creatures, unsummon totems and remove pets/guardians
RemovePossess(false);
Uncharm();
UnsummonAllTotems();
RemoveMiniPet();
@@ -5266,19 +5274,19 @@ void Player::SaveRecallPosition()
m_recallO = GetOrientation();
}
void Player::SendMessageToSet(WorldPacket *data, bool self)
void Player::SendMessageToSet(WorldPacket *data, bool self, bool to_possessor)
{
MapManager::Instance().GetMap(GetMapId(), this)->MessageBroadcast(this, data, self);
MapManager::Instance().GetMap(GetMapId(), this)->MessageBroadcast(this, data, self, to_possessor);
}
void Player::SendMessageToSetInRange(WorldPacket *data, float dist, bool self)
void Player::SendMessageToSetInRange(WorldPacket *data, float dist, bool self, bool to_possessor)
{
MapManager::Instance().GetMap(GetMapId(), this)->MessageDistBroadcast(this, data, dist, self);
MapManager::Instance().GetMap(GetMapId(), this)->MessageDistBroadcast(this, data, dist, self, to_possessor);
}
void Player::SendMessageToSetInRange(WorldPacket *data, float dist, bool self, bool own_team_only)
void Player::SendMessageToSetInRange(WorldPacket *data, float dist, bool self, bool own_team_only, bool to_possessor)
{
MapManager::Instance().GetMap(GetMapId(), this)->MessageDistBroadcast(this, data, dist, self,own_team_only);
MapManager::Instance().GetMap(GetMapId(), this)->MessageDistBroadcast(this, data, dist, self, to_possessor, own_team_only);
}
void Player::SendDirectMessage(WorldPacket *data)
@@ -15973,7 +15981,6 @@ void Player::Uncharm()
return;
charm->RemoveSpellsCausingAura(SPELL_AURA_MOD_CHARM);
charm->RemoveSpellsCausingAura(SPELL_AURA_MOD_POSSESS);
}
void Player::BuildPlayerChat(WorldPacket *data, uint8 msgtype, std::string text, uint32 language) const
@@ -16006,7 +16013,7 @@ void Player::TextEmote(const std::string text)
{
WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildPlayerChat(&data, CHAT_MSG_EMOTE, text, LANG_UNIVERSAL);
SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),true, !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT) );
SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),true, !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT), true );
}
void Player::Whisper(std::string text, uint32 language,uint64 receiver)
@@ -18505,13 +18512,253 @@ void Player::SetCanBlock( bool value )
UpdateBlockPercentage();
}
bool ItemPosCount::isContainedIn(ItemPosCountVec const& vec) const
void Player::HandleFallDamage(MovementInfo& movementInfo)
{
for(ItemPosCountVec::const_iterator itr = vec.begin(); itr != vec.end();++itr)
if(itr->pos == this->pos)
return true;
//Players with Feather Fall or low fall time, or physical immunity (charges used) are ignored
if (!isInFlight() && movementInfo.fallTime > 1100 && !isDead() && !isGameMaster() &&
!HasAuraType(SPELL_AURA_HOVER) && !HasAuraType(SPELL_AURA_FEATHER_FALL) &&
!HasAuraType(SPELL_AURA_FLY) && !IsImmunedToDamage(SPELL_SCHOOL_MASK_NORMAL,true) )
{
//Safe fall, fall time reduction
int32 safe_fall = GetTotalAuraModifier(SPELL_AURA_SAFE_FALL);
uint32 fall_time = (movementInfo.fallTime > (safe_fall*10)) ? movementInfo.fallTime - (safe_fall*10) : 0;
return false;
if(fall_time > 1100) //Prevent damage if fall time < 1100
{
//Fall Damage calculation
float fallperc = float(fall_time)/1100;
uint32 damage = (uint32)(((fallperc*fallperc -1) / 9 * GetMaxHealth())*sWorld.getRate(RATE_DAMAGE_FALL));
float height = movementInfo.z;
UpdateGroundPositionZ(movementInfo.x,movementInfo.y,height);
if (damage > 0)
{
//Prevent fall damage from being more than the player maximum health
if (damage > GetMaxHealth())
damage = GetMaxHealth();
// Gust of Wind
if (GetDummyAura(43621))
damage = GetMaxHealth()/2;
EnvironmentalDamage(GetGUID(), DAMAGE_FALL, damage);
}
//Z given by moveinfo, LastZ, FallTime, WaterZ, MapZ, Damage, Safefall reduction
DEBUG_LOG("FALLDAMAGE z=%f sz=%f pZ=%f FallTime=%d mZ=%f damage=%d SF=%d" , movementInfo.z, height, GetPositionZ(), movementInfo.fallTime, height, damage, safe_fall);
}
}
}
void Player::HandleFallUnderMap()
{
if(InBattleGround() && GetBattleGround()
&& GetBattleGround()->HandlePlayerUnderMap(this))
{
// do nothing, the handle already did if returned true
}
else
{
// NOTE: this is actually called many times while falling
// even after the player has been teleported away
// TODO: discard movement packets after the player is rooted
if(isAlive())
{
EnvironmentalDamage(GetGUID(),DAMAGE_FALL_TO_VOID, GetMaxHealth());
// change the death state to CORPSE to prevent the death timer from
// starting in the next player update
KillPlayer();
BuildPlayerRepop();
}
// cancel the death timer here if started
RepopAtGraveyard();
}
}
void Player::Possess(Unit *target)
{
if(!target || target == this)
return;
// Don't allow possession of someone else's pet
if(target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->isPet() && target != GetPet())
return;
// Don't allow possession on transports or when in flight; also remove possession from the now-to-be-possessed
if (target->GetTypeId() == TYPEID_PLAYER)
{
if (((Player*)target)->m_transport || ((Player*)target)->isInFlight())
return;
if (target->isPossessing())
((Player*)target)->RemovePossess(true);
}
// Remove any previous possession from the target
if (target->isPossessedByPlayer())
((Player*)target->GetCharmer())->RemovePossess(false);
else if (target->isCharmed())
target->UncharmSelf(); // Target isn't possessed, but charmed; uncharm before possessing
// Remove our previous possession
if (isPossessing())
RemovePossess(true);
else if (GetCharm()) // We are charming a creature, not possessing it; uncharm ourself first
Uncharm();
// Interrupt any current casting of the target
if(target->IsNonMeleeSpellCasted(true))
target->InterruptNonMeleeSpells(true);
// Update the proper unit fields
SetPossessedTarget(target);
target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, getFaction());
target->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNKNOWN5);
target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
SetUInt64Value(PLAYER_FARSIGHT, target->GetGUID());
if(target->GetTypeId() == TYPEID_UNIT)
{
// Set target to active in the grid and place it in the world container to be picked up by all regular player cell visits
Map* map = target->GetMap();
map->SwitchGridContainers((Creature*)target, true);
target->setActive(true);
((Creature*)target)->InitPossessedAI(); // Initialize the possessed AI
target->StopMoving();
target->GetMotionMaster()->Clear(false);
target->GetMotionMaster()->MoveIdle();
}
target->CombatStop();
target->DeleteThreatList();
// Pets already have a properly initialized CharmInfo, don't overwrite it.
if(target->GetTypeId() == TYPEID_PLAYER || (target->GetTypeId() == TYPEID_UNIT && !((Creature*)target)->isPet()))
{
CharmInfo* charmInfo = target->InitCharmInfo(target);
charmInfo->InitPossessCreateSpells();
}
// Disable control for target player and remove AFK
if(target->GetTypeId() == TYPEID_PLAYER)
{
if(((Player*)target)->isAFK())
((Player*)target)->ToggleAFK();
((Player*)target)->SetViewport(target->GetGUID(), false);
}
// Set current viewport to target unit, controllable
SetViewport(target->GetGUID(), true);
PossessSpellInitialize();
}
void Player::RemovePossess(bool attack)
{
Unit* target = GetCharm();
if(!target || !target->isPossessed())
return;
// Remove area auras from possessed
Unit::AuraMap& tAuras = target->GetAuras();
for(Unit::AuraMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
{
if(itr->second && itr->second->IsAreaAura())
target->RemoveAura(itr);
else
++itr;
}
RemovePossessedTarget();
if(target->GetTypeId() == TYPEID_PLAYER)
((Player*)target)->setFactionForRace(target->getRace());
else if(target->GetTypeId() == TYPEID_UNIT)
{
// Set creature to inactive in grid and place it back into the grid container
Map* map = target->GetMap();
target->setActive(false);
map->SwitchGridContainers((Creature*)target, false);
if(((Creature*)target)->isPet())
{
if(Unit* owner = target->GetOwner())
target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, owner->getFaction());
} else
{
if(CreatureInfo const* cInfo = ((Creature*)target)->GetCreatureInfo())
target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, cInfo->faction_A);
}
}
target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNKNOWN5);
target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
SetUInt64Value(PLAYER_FARSIGHT, 0);
// Remove pet spell action bar
WorldPacket data(SMSG_PET_SPELLS, 8);
data << uint64(0);
m_session->SendPacket(&data);
// Restore original view
SetViewport(GetGUID(), true);
if(target->GetTypeId() == TYPEID_PLAYER)
((Player*)target)->SetViewport(target->GetGUID(), true);
else
{
if(((Creature*)target)->isPet())
{
((Pet*)target)->InitPetCreateSpells();
PetSpellInitialize();
}
if (target->isAlive())
{
// If we're still hostile to our target, continue attacking otherwise reset threat and go home
if (target->getVictim())
{
Unit* victim = target->getVictim();
FactionTemplateEntry const* t_faction = target->getFactionTemplateEntry();
FactionTemplateEntry const* v_faction = victim->getFactionTemplateEntry();
// Unit::IsHostileTo will always return true since the unit is always hostile to its victim
if (t_faction && v_faction && !t_faction->IsHostileTo(*v_faction))
{
// Stop combat and remove the target from the threat lists of all its victims
target->CombatStop();
target->getHostilRefManager().deleteReferences();
target->DeleteThreatList();
target->GetMotionMaster()->Clear();
target->GetMotionMaster()->MoveTargetedHome();
}
}
else if (target->GetTypeId() == TYPEID_UNIT)
{
target->GetMotionMaster()->Clear();
target->GetMotionMaster()->MoveTargetedHome();
}
// Add high amount of threat on the player
if(target != GetPet() && attack)
target->AddThreat(this, 1000000.0f);
}
// Delete the assigned possessed AI
((Creature*)target)->DeletePossessedAI();
}
}
void Player::SetViewport(uint64 guid, bool moveable)
{
WorldPacket data(SMSG_CLIENT_CONTROL_UPDATE, 8+1);
data.appendPackGUID(guid); // Packed guid of object to set client's view to
data << (moveable ? uint8(0x01) : uint8(0x00)); // 0 - can't move; 1 - can move
m_session->SendPacket(&data);
sLog.outDetail("Viewport for "I64FMT" (%s) changed to "I64FMT, GetGUID(), GetName(), guid);
}
bool Player::isAllowUseBattleGroundObject()
@@ -18524,3 +18771,12 @@ bool Player::isAllowUseBattleGroundObject()
isAlive() // live player
);
}
bool ItemPosCount::isContainedIn(ItemPosCountVec const& vec) const
{
for(ItemPosCountVec::const_iterator itr = vec.begin(); itr != vec.end();++itr)
if(itr->pos == this->pos)
return true;
return false;
}