[8147] Some fixes and cleanups in mind control and charmed code. Mind control stil not finished.

* Allow command to mind controlled unit attack target at client. Rename related flag to UNIT_FLAG_PLAYER_CONTROLLED.
* Move code for pet action bar remove at client side to new function Player::RemovePetActionBar
* Not allow cast spells with SPELL_AURA_MOD_POSSESS and SPELL_AURA_MOD_POSSESS_PET by non-players and simplify related code base at this.
This commit is contained in:
VladimirMangos 2009-07-08 17:50:02 +04:00
parent 1ad013e25b
commit 3bfe549a2b
7 changed files with 153 additions and 125 deletions

View file

@ -335,4 +335,4 @@ void PetAI::AttackedBy(Unit *attacker)
if(!m_creature->getVictim() && m_creature->GetCharmInfo() && !m_creature->GetCharmInfo()->HasReactState(REACT_PASSIVE) && if(!m_creature->getVictim() && m_creature->GetCharmInfo() && !m_creature->GetCharmInfo()->HasReactState(REACT_PASSIVE) &&
(!m_creature->GetCharmInfo()->HasCommandState(COMMAND_STAY) || m_creature->canReachWithAttack(attacker))) (!m_creature->GetCharmInfo()->HasCommandState(COMMAND_STAY) || m_creature->canReachWithAttack(attacker)))
AttackStart(attacker); AttackStart(attacker);
} }

View file

@ -16359,9 +16359,7 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent)
if(pet->isControlled()) if(pet->isControlled())
{ {
WorldPacket data(SMSG_PET_SPELLS, 8); RemovePetActionBar();
data << uint64(0);
GetSession()->SendPacket(&data);
if(GetGroup()) if(GetGroup())
SetGroupUpdateFlag(GROUP_UPDATE_PET); SetGroupUpdateFlag(GROUP_UPDATE_PET);
@ -16623,6 +16621,13 @@ void Player::CharmSpellInitialize()
GetSession()->SendPacket(&data); GetSession()->SendPacket(&data);
} }
void Player::RemovePetActionBar()
{
WorldPacket data(SMSG_PET_SPELLS, 8);
data << uint64(0);
SendDirectMessage(&data);
}
bool Player::IsAffectedBySpellmod(SpellEntry const *spellInfo, SpellModifier *mod, Spell const* spell) bool Player::IsAffectedBySpellmod(SpellEntry const *spellInfo, SpellModifier *mod, Spell const* spell)
{ {
if (!mod || !spellInfo) if (!mod || !spellInfo)
@ -19380,7 +19385,7 @@ void Player::EnterVehicle(Vehicle *vehicle)
vehicle->SetCharmerGUID(GetGUID()); vehicle->SetCharmerGUID(GetGUID());
vehicle->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); vehicle->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
vehicle->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_24); vehicle->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
vehicle->setFaction(getFaction()); vehicle->setFaction(getFaction());
SetCharm(vehicle); // charm SetCharm(vehicle); // charm
@ -19432,7 +19437,7 @@ void Player::ExitVehicle(Vehicle *vehicle)
{ {
vehicle->SetCharmerGUID(0); vehicle->SetCharmerGUID(0);
vehicle->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); vehicle->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
vehicle->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_24); vehicle->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
vehicle->setFaction((GetTeam() == ALLIANCE) ? vehicle->GetCreatureInfo()->faction_A : vehicle->GetCreatureInfo()->faction_H); vehicle->setFaction((GetTeam() == ALLIANCE) ? vehicle->GetCreatureInfo()->faction_A : vehicle->GetCreatureInfo()->faction_H);
SetCharm(NULL); SetCharm(NULL);
@ -19454,9 +19459,7 @@ void Player::ExitVehicle(Vehicle *vehicle)
data << uint32(0); // fall time data << uint32(0); // fall time
GetSession()->SendPacket(&data); GetSession()->SendPacket(&data);
data.Initialize(SMSG_PET_SPELLS, 8); RemovePetActionBar();
data << uint64(0);
GetSession()->SendPacket(&data);
// maybe called at dummy aura remove? // maybe called at dummy aura remove?
// CastSpell(this, 45472, true); // Parachute // CastSpell(this, 45472, true); // Parachute

View file

@ -1442,6 +1442,8 @@ class MANGOS_DLL_SPEC Player : public Unit
void PetSpellInitialize(); void PetSpellInitialize();
void CharmSpellInitialize(); void CharmSpellInitialize();
void PossessSpellInitialize(); void PossessSpellInitialize();
void RemovePetActionBar();
bool HasSpell(uint32 spell) const; bool HasSpell(uint32 spell) const;
bool HasActiveSpell(uint32 spell) const; // show in spellbook bool HasActiveSpell(uint32 spell) const; // show in spellbook
TrainerSpellState GetTrainerSpellState(TrainerSpell const* trainer_spell) const; TrainerSpellState GetTrainerSpellState(TrainerSpell const* trainer_spell) const;

View file

@ -4383,8 +4383,38 @@ SpellCastResult Spell::CheckCast(bool strict)
break; break;
} }
case SPELL_AURA_MOD_POSSESS: case SPELL_AURA_MOD_POSSESS:
{
if(m_caster->GetTypeId() != TYPEID_PLAYER)
return SPELL_FAILED_UNKNOWN;
if(m_targets.getUnitTarget() == m_caster)
return SPELL_FAILED_BAD_TARGETS;
if(m_caster->GetPetGUID())
return SPELL_FAILED_ALREADY_HAVE_SUMMON;
if(m_caster->GetCharmGUID())
return SPELL_FAILED_ALREADY_HAVE_CHARM;
if(m_caster->GetCharmerGUID())
return SPELL_FAILED_CHARMED;
if(!m_targets.getUnitTarget())
return SPELL_FAILED_BAD_IMPLICIT_TARGETS;
if(m_targets.getUnitTarget()->GetCharmerGUID())
return SPELL_FAILED_CHARMED;
if(int32(m_targets.getUnitTarget()->getLevel()) > CalculateDamage(i,m_targets.getUnitTarget()))
return SPELL_FAILED_HIGHLEVEL;
break;
}
case SPELL_AURA_MOD_CHARM: case SPELL_AURA_MOD_CHARM:
{ {
if(m_targets.getUnitTarget() == m_caster)
return SPELL_FAILED_BAD_TARGETS;
if(m_caster->GetPetGUID()) if(m_caster->GetPetGUID())
return SPELL_FAILED_ALREADY_HAVE_SUMMON; return SPELL_FAILED_ALREADY_HAVE_SUMMON;
@ -4407,6 +4437,9 @@ SpellCastResult Spell::CheckCast(bool strict)
} }
case SPELL_AURA_MOD_POSSESS_PET: case SPELL_AURA_MOD_POSSESS_PET:
{ {
if(m_caster->GetTypeId() != TYPEID_PLAYER)
return SPELL_FAILED_UNKNOWN;
if(m_caster->GetCharmGUID()) if(m_caster->GetCharmGUID())
return SPELL_FAILED_ALREADY_HAVE_CHARM; return SPELL_FAILED_ALREADY_HAVE_CHARM;

View file

@ -3074,33 +3074,33 @@ void Aura::HandleModPossess(bool apply, bool Real)
if(!Real) if(!Real)
return; return;
if(m_target->getLevel() > m_modifier.m_amount)
return;
// not possess yourself // not possess yourself
if(GetCasterGUID() == m_target->GetGUID()) if(GetCasterGUID() == m_target->GetGUID())
return; return;
Unit* caster = GetCaster(); Unit* caster = GetCaster();
if(!caster) if(!caster || caster->GetTypeId() != TYPEID_PLAYER)
return; return;
Player* p_caster = (Player*)caster;
if( apply ) if( apply )
{ {
m_target->SetCharmerGUID(GetCasterGUID()); m_target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
m_target->setFaction(caster->getFaction());
caster->SetCharm(m_target); m_target->SetCharmerGUID(p_caster->GetGUID());
m_target->setFaction(p_caster->getFaction());
if(caster->GetTypeId() == TYPEID_PLAYER) p_caster->SetCharm(m_target);
{
((Player*)caster)->SetFarSightGUID(m_target->GetGUID()); p_caster->SetFarSightGUID(m_target->GetGUID());
((Player*)caster)->SetClientControl(m_target, 1); p_caster->SetClientControl(m_target, 1);
((Player*)caster)->SetMover(m_target); p_caster->SetMover(m_target);
}
m_target->CombatStop(); m_target->CombatStop();
m_target->DeleteThreatList(); m_target->DeleteThreatList();
if(m_target->GetTypeId() == TYPEID_UNIT) if(m_target->GetTypeId() == TYPEID_UNIT)
{ {
m_target->StopMoving(); m_target->StopMoving();
@ -3115,13 +3115,14 @@ void Aura::HandleModPossess(bool apply, bool Real)
if(CharmInfo *charmInfo = m_target->InitCharmInfo(m_target)) if(CharmInfo *charmInfo = m_target->InitCharmInfo(m_target))
charmInfo->InitPossessCreateSpells(); charmInfo->InitPossessCreateSpells();
if(caster->GetTypeId() == TYPEID_PLAYER) p_caster->PossessSpellInitialize();
((Player*)caster)->PossessSpellInitialize();
} }
else else
{ {
m_target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
m_target->SetCharmerGUID(0); m_target->SetCharmerGUID(0);
caster->InterruptSpell(CURRENT_CHANNELED_SPELL); // the spell is not automatically canceled when interrupted, do it now p_caster->InterruptSpell(CURRENT_CHANNELED_SPELL); // the spell is not automatically canceled when interrupted, do it now
if(m_target->GetTypeId() == TYPEID_PLAYER) if(m_target->GetTypeId() == TYPEID_PLAYER)
{ {
@ -3134,18 +3135,13 @@ void Aura::HandleModPossess(bool apply, bool Real)
m_target->setFaction(cinfo->faction_A); m_target->setFaction(cinfo->faction_A);
} }
caster->SetCharm(NULL); p_caster->SetCharm(NULL);
if(caster->GetTypeId() == TYPEID_PLAYER) p_caster->SetFarSightGUID(0);
{ p_caster->SetClientControl(m_target, 0);
((Player*)caster)->SetFarSightGUID(0); p_caster->SetMover(NULL);
((Player*)caster)->SetClientControl(m_target, 0);
((Player*)caster)->SetMover(NULL);
WorldPacket data(SMSG_PET_SPELLS, 8); p_caster->RemovePetActionBar();
data << uint64(0);
((Player*)caster)->GetSession()->SendPacket(&data);
}
if(m_target->GetTypeId() == TYPEID_UNIT) if(m_target->GetTypeId() == TYPEID_UNIT)
{ {
@ -3170,14 +3166,16 @@ void Aura::HandleModPossessPet(bool apply, bool Real)
if(!pet || pet != m_target) if(!pet || pet != m_target)
return; return;
if(apply) Player* p_caster = (Player*)caster;
pet->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_24);
else
pet->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_24);
((Player*)caster)->SetFarSightGUID(apply ? pet->GetGUID() : 0); if(apply)
((Player*)caster)->SetCharm(apply ? pet : NULL); pet->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
((Player*)caster)->SetClientControl(pet, apply ? 1 : 0); else
pet->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
p_caster->SetFarSightGUID(apply ? pet->GetGUID() : 0);
p_caster->SetCharm(apply ? pet : NULL);
p_caster->SetClientControl(pet, apply ? 1 : 0);
((Player*)caster)->SetMover(apply ? pet : NULL); ((Player*)caster)->SetMover(apply ? pet : NULL);
if(apply) if(apply)
@ -3217,100 +3215,92 @@ void Aura::HandleModCharm(bool apply, bool Real)
if(!caster) if(!caster)
return; return;
if(int32(m_target->getLevel()) <= m_modifier.m_amount) if( apply )
{ {
if( apply ) m_target->SetCharmerGUID(GetCasterGUID());
m_target->setFaction(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)
{ {
m_target->SetCharmerGUID(GetCasterGUID()); ((Creature*)m_target)->AIM_Initialize();
m_target->setFaction(caster->getFaction()); CharmInfo *charmInfo = m_target->InitCharmInfo(m_target);
m_target->CastStop(m_target == caster ? GetId() : 0); charmInfo->InitCharmCreateSpells();
caster->SetCharm(m_target); charmInfo->SetReactState( REACT_DEFENSIVE );
m_target->CombatStop(); if(caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK)
m_target->DeleteThreatList();
if(m_target->GetTypeId() == TYPEID_UNIT)
{
((Creature*)m_target)->AIM_Initialize();
CharmInfo *charmInfo = 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)
{
//does not appear to have relevance. Why code added initially? See note below at !apply
//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();
}
}
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(); CreatureInfo const *cinfo = ((Creature*)m_target)->GetCreatureInfo();
if(cinfo && cinfo->type == CREATURE_TYPE_DEMON)
// restore faction
if(((Creature*)m_target)->isPet())
{ {
if(Unit* owner = m_target->GetOwner()) //does not appear to have relevance. Why code added initially? See note below at !apply
m_target->setFaction(owner->getFaction()); //to prevent client crash
else if(cinfo) //m_target->SetFlag(UNIT_FIELD_BYTES_0, 2048);
m_target->setFaction(cinfo->faction_A); //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));
} }
else if(cinfo) // normal creature }
}
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();
// restore faction
if(((Creature*)m_target)->isPet())
{
if(Unit* owner = m_target->GetOwner())
m_target->setFaction(owner->getFaction());
else if(cinfo)
m_target->setFaction(cinfo->faction_A); m_target->setFaction(cinfo->faction_A);
// restore UNIT_FIELD_BYTES_0
if(cinfo && caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK && cinfo->type == CREATURE_TYPE_DEMON)
{
//does not appear to have relevance. Why code added initially? Class, gender, powertype should be same.
//db field removed and replaced with better way to set class, restore using this if problems
/*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 (GUID: %u TypeId: %u) has a charm aura but no charm info!", m_target->GetGUIDLow(), m_target->GetTypeId());
}
} }
else if(cinfo) // normal creature
m_target->setFaction(cinfo->faction_A);
caster->SetCharm(NULL); // restore UNIT_FIELD_BYTES_0
if(cinfo && caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK && cinfo->type == CREATURE_TYPE_DEMON)
if(caster->GetTypeId() == TYPEID_PLAYER)
{ {
WorldPacket data(SMSG_PET_SPELLS, 8); //does not appear to have relevance. Why code added initially? Class, gender, powertype should be same.
data << uint64(0); //db field removed and replaced with better way to set class, restore using this if problems
((Player*)caster)->GetSession()->SendPacket(&data); /*CreatureDataAddon const *cainfo = ((Creature*)m_target)->GetCreatureAddon();
} if(cainfo && cainfo->bytes0 != 0)
if(m_target->GetTypeId() == TYPEID_UNIT) m_target->SetUInt32Value(UNIT_FIELD_BYTES_0, cainfo->bytes0);
{ else
((Creature*)m_target)->AIM_Initialize(); m_target->RemoveFlag(UNIT_FIELD_BYTES_0, 2048);*/
if (((Creature*)m_target)->AI())
((Creature*)m_target)->AI()->AttackedBy(caster); if(m_target->GetCharmInfo())
m_target->GetCharmInfo()->SetPetNumber(0, true);
else
sLog.outError("Aura::HandleModCharm: target (GUID: %u TypeId: %u) has a charm aura but no charm info!", m_target->GetGUIDLow(), m_target->GetTypeId());
} }
} }
caster->SetCharm(NULL);
if(caster->GetTypeId() == TYPEID_PLAYER)
((Player*)caster)->RemovePetActionBar();
if(m_target->GetTypeId() == TYPEID_UNIT)
{
((Creature*)m_target)->AIM_Initialize();
if (((Creature*)m_target)->AI())
((Creature*)m_target)->AI()->AttackedBy(caster);
}
} }
} }

View file

@ -514,7 +514,7 @@ enum UnitFlags
UNIT_FLAG_DISARMED = 0x00200000, // 3.0.3, disable melee spells casting..., "Required melee weapon" added to melee spells tooltip. UNIT_FLAG_DISARMED = 0x00200000, // 3.0.3, disable melee spells casting..., "Required melee weapon" added to melee spells tooltip.
UNIT_FLAG_CONFUSED = 0x00400000, UNIT_FLAG_CONFUSED = 0x00400000,
UNIT_FLAG_FLEEING = 0x00800000, UNIT_FLAG_FLEEING = 0x00800000,
UNIT_FLAG_UNK_24 = 0x01000000, // used in spell Eyes of the Beast for pet... UNIT_FLAG_PLAYER_CONTROLLED= 0x01000000, // used in spell Eyes of the Beast for pet... let attack by controlled creature
UNIT_FLAG_NOT_SELECTABLE = 0x02000000, UNIT_FLAG_NOT_SELECTABLE = 0x02000000,
UNIT_FLAG_SKINNABLE = 0x04000000, UNIT_FLAG_SKINNABLE = 0x04000000,
UNIT_FLAG_MOUNT = 0x08000000, UNIT_FLAG_MOUNT = 0x08000000,

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "8146" #define REVISION_NR "8147"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__