diff options
-rw-r--r-- | src/game/Creature.cpp | 6 | ||||
-rw-r--r-- | src/game/CreatureAI.cpp | 38 | ||||
-rw-r--r-- | src/game/CreatureAI.h | 17 | ||||
-rw-r--r-- | src/game/CreatureAISelector.cpp | 5 | ||||
-rw-r--r-- | src/game/Level3.cpp | 8 | ||||
-rw-r--r-- | src/game/Player.cpp | 149 | ||||
-rw-r--r-- | src/game/Player.h | 11 | ||||
-rw-r--r-- | src/game/SpellAuras.cpp | 152 | ||||
-rw-r--r-- | src/game/SpellEffects.cpp | 2 | ||||
-rw-r--r-- | src/game/TemporarySummon.cpp | 4 | ||||
-rw-r--r-- | src/game/Unit.cpp | 253 | ||||
-rw-r--r-- | src/game/Unit.h | 64 | ||||
-rw-r--r-- | src/game/WorldSession.cpp | 13 |
13 files changed, 361 insertions, 361 deletions
diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 081f1160b1a..03eeecb3e10 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -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); } diff --git a/src/game/CreatureAI.cpp b/src/game/CreatureAI.cpp index ad663d13b38..71046e2f154 100644 --- a/src/game/CreatureAI.cpp +++ b/src/game/CreatureAI.cpp @@ -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); + } +} diff --git a/src/game/CreatureAI.h b/src/game/CreatureAI.h index a1f78be1e86..b5fda95ef85 100644 --- a/src/game/CreatureAI.h +++ b/src/game/CreatureAI.h @@ -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: diff --git a/src/game/CreatureAISelector.cpp b/src/game/CreatureAISelector.cpp index 5e15efafe6f..9927ff34df3 100644 --- a/src/game/CreatureAISelector.cpp +++ b/src/game/CreatureAISelector.cpp @@ -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 diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index 6a05a81fbae..a825743481a 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -6915,7 +6915,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; } @@ -6923,11 +6923,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; } diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 81ebb45a92e..5dfc9a412b1 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -19039,150 +19039,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; - - // 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); + if(Unit *u = GetCharm()) + u->RemoveCharmedOrPossessedBy(this); - // 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()) @@ -19209,10 +19071,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) diff --git a/src/game/Player.h b/src/game/Player.h index 3dc1a691e44..cdf2005f111 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -899,8 +899,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(); @@ -2325,6 +2331,7 @@ class TRINITY_DLL_SPEC Player : public Unit MapReference m_mapRef; void UpdateCharmedAI(); + UnitAI *i_AI; }; void AddItemsSetItem(Player*player,Item *item); diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index ebee1e4c22b..0c9f8d54e4a 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -687,21 +687,8 @@ 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_PET || m_areaAuraType == AREA_AURA_OWNER ) { @@ -2866,24 +2853,22 @@ void Aura::HandleModPossess(bool apply, bool Real) if(!Real) return; - if(m_target->getLevel() > m_modifier.m_amount) - return; - - // not possess yourself - if(GetCasterGUID() == m_target->GetGUID()) - return; - Unit* caster = GetCaster(); - if(!caster) + if(caster && caster->GetTypeId() == TYPEID_UNIT) + { + HandleModCharm(apply, Real); return; + } - if( apply ) + if(apply) { - if (caster->GetTypeId() == TYPEID_PLAYER) - ((Player*)caster)->Possess(m_target); + if(m_target->getLevel() > m_modifier.m_amount) + return; + + m_target->SetCharmedOrPossessedBy(caster, true); } else - m_target->UnpossessSelf(true); + m_target->RemoveCharmedOrPossessedBy(caster); } void Aura::HandleModPossessPet(bool apply, bool Real) @@ -2898,12 +2883,18 @@ void Aura::HandleModPossessPet(bool apply, bool Real) return; if(apply) - { - ((Player*)caster)->Possess(m_target); - } + m_target->SetCharmedOrPossessedBy(caster, true); else { - ((Player*)caster)->RemovePossess(false); + 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); + } } } @@ -2912,108 +2903,17 @@ void Aura::HandleModCharm(bool apply, bool Real) if(!Real) return; - // not charm yourself - if(GetCasterGUID() == m_target->GetGUID()) - return; - Unit* caster = GetCaster(); - if( apply ) + if(apply) { - 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) - { - ((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) - { - 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(); - } + + m_target->SetCharmedOrPossessedBy(caster, false); } 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(); - - // 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); - - // 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); - - 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) - { - WorldPacket data(SMSG_PET_SPELLS, 8); - data << uint64(0); - ((Player*)caster)->GetSession()->SendPacket(&data); - } - } - } + m_target->RemoveCharmedOrPossessedBy(caster); } void Aura::HandleModConfuse(bool apply, bool Real) diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index fc9f132e23d..4c2c28e64e4 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -3704,7 +3704,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) diff --git a/src/game/TemporarySummon.cpp b/src/game/TemporarySummon.cpp index 357a32b4ecb..553f7644b64 100644 --- a/src/game/TemporarySummon.cpp +++ b/src/game/TemporarySummon.cpp @@ -172,9 +172,9 @@ void TemporarySummon::Summon(TempSummonType type, uint32 lifetime) void TemporarySummon::UnSummon() { - CombatStop(); + RemoveCharmedOrPossessedBy(NULL); - UnpossessSelf(false); + CombatStop(); CleanupsBeforeDelete(); AddObjectToRemoveList(); diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 85f13097a14..0bf8faa5bb2 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -233,7 +233,6 @@ Unit::Unit() m_removedAuras = 0; m_charmInfo = NULL; m_unit_movement_flags = 0; - m_isPossessed = false; m_reducedThreatPercent = 0; m_misdirectionTargetGUID = 0; @@ -8380,7 +8379,8 @@ 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); } void Unit::AddPlayerToVision(Player* plr) @@ -8423,21 +8423,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) @@ -10239,7 +10224,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); @@ -11098,7 +11083,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 @@ -12929,22 +12914,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; } diff --git a/src/game/Unit.h b/src/game/Unit.h index 3cba888eb01..da85bd53d1a 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -350,27 +350,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 @@ -1058,35 +1059,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()) @@ -1104,7 +1094,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); @@ -1450,7 +1439,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; diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp index f2e08969a96..eb2612a1543 100644 --- a/src/game/WorldSession.cpp +++ b/src/game/WorldSession.cpp @@ -249,6 +249,12 @@ 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); + if (uint64 lguid = GetPlayer()->GetLootGUID()) DoLootRelease(lguid); @@ -370,13 +376,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 |