Crowd Control handling improvements by Ono(Warlockbugs)
This commit is contained in:
parent
45432f4f8c
commit
087d00960c
@ -18822,6 +18822,14 @@ void Player::ResurectUsingRequestData()
|
||||
SpawnCorpseBones();
|
||||
}
|
||||
|
||||
bool Player::IsClientControl(Unit* target) const
|
||||
{
|
||||
return (target && !target->IsFleeing() && !target->IsConfused() && !target->IsTaxiFlying() &&
|
||||
(target->GetTypeId() != TYPEID_PLAYER ||
|
||||
!((Player*)target)->InBattleGround() || ((Player*)target)->GetBattleGround()->GetStatus() != STATUS_WAIT_LEAVE) &&
|
||||
target->GetCharmerOrOwnerOrOwnGuid() == GetObjectGuid());
|
||||
}
|
||||
|
||||
void Player::SetClientControl(Unit* target, uint8 allowMove)
|
||||
{
|
||||
WorldPacket data(SMSG_CLIENT_CONTROL_UPDATE, target->GetPackGUID().size() + 1);
|
||||
|
@ -2196,6 +2196,7 @@ class Player : public Unit
|
||||
bool IsFlying() const { return false; }
|
||||
bool IsFreeFlying() const { return false; }
|
||||
|
||||
bool IsClientControl(Unit* target) const;
|
||||
void SetClientControl(Unit* target, uint8 allowMove);
|
||||
void SetMover(Unit* target) { m_mover = target ? target : this; }
|
||||
Unit* GetMover() const { return m_mover; }
|
||||
|
@ -8599,98 +8599,132 @@ void Unit::InterruptMoving(bool forceSendStop /*=false*/)
|
||||
StopMoving(forceSendStop || isMoving);
|
||||
}
|
||||
|
||||
void Unit::SetFeared(bool apply, ObjectGuid casterGuid, uint32 spellID, uint32 time)
|
||||
void Unit::SetImmobilizedState(bool apply, bool stun)
|
||||
{
|
||||
const uint32 immobilized = (UNIT_STAT_ROOT | UNIT_STAT_STUNNED);
|
||||
const uint32 state = stun ? UNIT_STAT_STUNNED : UNIT_STAT_ROOT;
|
||||
if (apply)
|
||||
{
|
||||
if (HasAuraType(SPELL_AURA_PREVENTS_FLEEING))
|
||||
{ return; }
|
||||
|
||||
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
|
||||
|
||||
StopMoving(GetTypeId() == TYPEID_PLAYER);
|
||||
GetMotionMaster()->MovementExpired(false);
|
||||
|
||||
CastStop(GetObjectGuid() == casterGuid ? spellID : 0);
|
||||
|
||||
if (GetTypeId() == TYPEID_UNIT)
|
||||
SetTargetGuid(ObjectGuid()); // creature feared loose its target
|
||||
|
||||
Unit* caster = IsInWorld() ? GetMap()->GetUnit(casterGuid) : NULL;
|
||||
|
||||
GetMotionMaster()->MoveFleeing(caster, time); // caster==NULL processed in MoveFleeing
|
||||
addUnitState(state);
|
||||
if (GetTypeId() != TYPEID_PLAYER)
|
||||
StopMoving();
|
||||
else
|
||||
{
|
||||
// Clear unit movement flags
|
||||
((Player*)this)->m_movementInfo.SetMovementFlags(MOVEFLAG_NONE);
|
||||
if (stun)
|
||||
SetStandState(UNIT_STAND_STATE_STAND); // in 1.5 client
|
||||
SetRoot(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
|
||||
|
||||
GetMotionMaster()->MovementExpired(GetTypeId() == TYPEID_PLAYER);
|
||||
if (GetTypeId() == TYPEID_PLAYER)
|
||||
StopMoving(true);
|
||||
|
||||
if (GetTypeId() != TYPEID_PLAYER && IsAlive())
|
||||
{
|
||||
Creature* c = ((Creature*)this);
|
||||
// restore appropriate movement generator
|
||||
if (getVictim())
|
||||
{
|
||||
SetTargetGuid(getVictim()->GetObjectGuid()); // restore target
|
||||
GetMotionMaster()->MoveChase(getVictim());
|
||||
}
|
||||
else
|
||||
{ GetMotionMaster()->Initialize(); }
|
||||
|
||||
// attack caster if can
|
||||
if (Unit* caster = IsInWorld() ? GetMap()->GetUnit(casterGuid) : NULL)
|
||||
{ c->AttackedBy(caster); }
|
||||
}
|
||||
clearUnitState(state);
|
||||
// Prevent giving ability to move if more immobilizers are active
|
||||
if (!hasUnitState(immobilized) && (GetTypeId() == TYPEID_PLAYER))
|
||||
SetRoot(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (GetTypeId() == TYPEID_PLAYER)
|
||||
{ ((Player*)this)->SetClientControl(this, !apply); }
|
||||
void Unit::SetFeared(bool apply, ObjectGuid casterGuid, uint32 spellID, uint32 time)
|
||||
{
|
||||
SetIncapacitatedState(apply, UNIT_FLAG_FLEEING, casterGuid, spellID, time);
|
||||
}
|
||||
|
||||
void Unit::SetConfused(bool apply, ObjectGuid casterGuid, uint32 spellID)
|
||||
{
|
||||
SetIncapacitatedState(apply, UNIT_FLAG_CONFUSED, casterGuid, spellID);
|
||||
}
|
||||
|
||||
void Unit::SetStunned(bool apply)
|
||||
{
|
||||
SetIncapacitatedState(apply, UNIT_FLAG_STUNNED);
|
||||
}
|
||||
|
||||
void Unit::SetIncapacitatedState(bool apply, uint32 state, ObjectGuid casterGuid, uint32 spellID, uint32 time)
|
||||
{
|
||||
// We are interested only in a particular subset of flags:
|
||||
const uint32 filter = (UNIT_FLAG_STUNNED | UNIT_FLAG_CONFUSED | UNIT_FLAG_FLEEING);
|
||||
if (!state || !(state & filter) || (state & ~filter))
|
||||
return;
|
||||
|
||||
Player* controller = GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
const bool control = controller ? controller->IsClientControl(this) : false;
|
||||
const bool movement = (state != UNIT_FLAG_STUNNED);
|
||||
const bool stun = (state & UNIT_FLAG_STUNNED);
|
||||
const bool fleeing = (state & UNIT_FLAG_FLEEING);
|
||||
|
||||
if (apply)
|
||||
{
|
||||
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
|
||||
|
||||
StopMoving(GetTypeId() == TYPEID_PLAYER);
|
||||
GetMotionMaster()->MovementExpired(false);
|
||||
|
||||
CastStop(GetObjectGuid() == casterGuid ? spellID : 0);
|
||||
|
||||
if (GetTypeId() == TYPEID_UNIT)
|
||||
SetTargetGuid(ObjectGuid());
|
||||
|
||||
GetMotionMaster()->MoveConfused();
|
||||
if (fleeing && HasAuraType(SPELL_AURA_PREVENTS_FLEEING))
|
||||
{
|
||||
if (state == UNIT_FLAG_FLEEING)
|
||||
return;
|
||||
else
|
||||
state &= ~UNIT_FLAG_FLEEING;
|
||||
}
|
||||
SetFlag(UNIT_FIELD_FLAGS, state);
|
||||
}
|
||||
else
|
||||
RemoveFlag(UNIT_FIELD_FLAGS, state);
|
||||
|
||||
if (movement)
|
||||
GetMotionMaster()->MovementExpired(false);
|
||||
if (apply)
|
||||
CastStop(GetObjectGuid() == casterGuid ? spellID : 0);
|
||||
|
||||
if (GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
|
||||
|
||||
GetMotionMaster()->MovementExpired(GetTypeId() == TYPEID_PLAYER);
|
||||
if (GetTypeId() == TYPEID_PLAYER)
|
||||
StopMoving(true);
|
||||
|
||||
if (GetTypeId() != TYPEID_PLAYER && IsAlive())
|
||||
if (HasFlag(UNIT_FIELD_FLAGS, filter))
|
||||
{
|
||||
// restore appropriate movement generator
|
||||
if (getVictim())
|
||||
if (!GetTargetGuid().IsEmpty()) // Incapacitated creature loses its target
|
||||
SetTargetGuid(ObjectGuid());
|
||||
}
|
||||
else if (IsAlive())
|
||||
{
|
||||
if (Unit* victim = getVictim())
|
||||
{
|
||||
SetTargetGuid(getVictim()->GetObjectGuid());
|
||||
GetMotionMaster()->MoveChase(getVictim());
|
||||
SetTargetGuid(victim->GetObjectGuid()); // Restore target
|
||||
if (movement)
|
||||
GetMotionMaster()->MoveChase(victim); // Restore movement generator
|
||||
}
|
||||
else if (movement)
|
||||
GetMotionMaster()->Initialize(); // Reset movement generator
|
||||
|
||||
if (!apply && fleeing)
|
||||
{
|
||||
// Attack the caster if can on fear expiration
|
||||
if (Unit* caster = IsInWorld() ? GetMap()->GetUnit(casterGuid) : nullptr)
|
||||
((Creature*)this)->AttackedBy(caster);
|
||||
}
|
||||
else
|
||||
{ GetMotionMaster()->Initialize(); }
|
||||
}
|
||||
}
|
||||
|
||||
if (GetTypeId() == TYPEID_PLAYER)
|
||||
{ ((Player*)this)->SetClientControl(this, !apply); }
|
||||
// Update stun if required:
|
||||
if (stun)
|
||||
SetImmobilizedState(apply, true);
|
||||
|
||||
if (!movement)
|
||||
return;
|
||||
|
||||
// Check if we should return or remove player control after change
|
||||
if (controller)
|
||||
{
|
||||
const bool remove = !controller->IsClientControl(this);
|
||||
if (control && remove)
|
||||
controller->SetClientControl(this, 0);
|
||||
else if (!control && !remove)
|
||||
controller->SetClientControl(this, 1);
|
||||
}
|
||||
|
||||
// Update incapacitated movement if required:
|
||||
if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED))
|
||||
GetMotionMaster()->MoveConfused();
|
||||
else if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING))
|
||||
GetMotionMaster()->MoveFleeing(IsInWorld() ? GetMap()->GetUnit(casterGuid) : nullptr, time);
|
||||
}
|
||||
|
||||
|
||||
void Unit::SetFeignDeath(bool apply, ObjectGuid casterGuid /*= ObjectGuid()*/)
|
||||
{
|
||||
if (apply)
|
||||
|
@ -451,7 +451,7 @@ enum UnitState
|
||||
UNIT_STAT_CONFUSED | UNIT_STAT_FLEEING,
|
||||
|
||||
// AI disabled by some reason
|
||||
UNIT_STAT_LOST_CONTROL = UNIT_STAT_FLEEING | UNIT_STAT_CONTROLLED,
|
||||
UNIT_STAT_LOST_CONTROL = UNIT_STAT_CONFUSED | UNIT_STAT_FLEEING | UNIT_STAT_CONTROLLED,
|
||||
|
||||
// above 2 state cases
|
||||
UNIT_STAT_CAN_NOT_REACT_OR_LOST_CONTROL = UNIT_STAT_CAN_NOT_REACT | UNIT_STAT_LOST_CONTROL,
|
||||
@ -3627,8 +3627,23 @@ class Unit : public WorldObject
|
||||
void StopMoving(bool forceSendStop = false);
|
||||
void InterruptMoving(bool forceSendStop = false);
|
||||
|
||||
///----------Various crowd control methods-----------------
|
||||
bool IsImmobilized() const { return hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED); }
|
||||
void SetImmobilizedState(bool apply, bool stun = false);
|
||||
|
||||
// These getters operate on unit flags set by IncapacitatedState and are meant for formal usage in conjunction with spell effects only
|
||||
// For actual internal movement states use UnitState flags
|
||||
// TODO: The UnitState thing needs to be rewriten at some point, this kind of duality is bad
|
||||
bool IsFleeing() const { return HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING); }
|
||||
bool IsConfused() const { return HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); }
|
||||
bool IsStunned() const { return HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); }
|
||||
bool IsIncapacitated() const { return (IsFleeing() || IsConfused() || IsStunned()); }
|
||||
|
||||
void SetFeared(bool apply, ObjectGuid casterGuid = ObjectGuid(), uint32 spellID = 0, uint32 time = 0);
|
||||
void SetConfused(bool apply, ObjectGuid casterGuid = ObjectGuid(), uint32 spellID = 0);
|
||||
void SetStunned(bool apply);
|
||||
void SetIncapacitatedState(bool apply, uint32 state = 0, ObjectGuid casterGuid = ObjectGuid(), uint32 spellID = 0, uint32 time = 0);
|
||||
///----------End of crowd control methods----------
|
||||
void SetFeignDeath(bool apply, ObjectGuid casterGuid = ObjectGuid());
|
||||
|
||||
void AddComboPointHolder(uint32 lowguid) { m_ComboPointHolders.insert(lowguid); }
|
||||
|
@ -2343,6 +2343,10 @@ void Aura::HandleModConfuse(bool apply, bool Real)
|
||||
if (!Real)
|
||||
{ return; }
|
||||
|
||||
// Do not remove it yet if more effects are up, do it for the last effect
|
||||
if (!apply && GetTarget()->HasAuraType(SPELL_AURA_MOD_CONFUSE))
|
||||
return;
|
||||
|
||||
GetTarget()->SetConfused(apply, GetCasterGuid(), GetId());
|
||||
}
|
||||
|
||||
@ -2351,6 +2355,10 @@ void Aura::HandleModFear(bool apply, bool Real)
|
||||
if (!Real)
|
||||
{ return; }
|
||||
|
||||
// Do not remove it yet if more effects are up, do it for the last effect
|
||||
if (!apply && GetTarget()->HasAuraType(SPELL_AURA_MOD_FEAR))
|
||||
return;
|
||||
|
||||
GetTarget()->SetFeared(apply, GetCasterGuid(), GetId());
|
||||
}
|
||||
|
||||
@ -2402,21 +2410,7 @@ void Aura::HandleAuraModStun(bool apply, bool Real)
|
||||
if (GetSpellSchoolMask(GetSpellProto()) & SPELL_SCHOOL_MASK_FROST)
|
||||
{ target->ModifyAuraState(AURA_STATE_FROZEN, apply); }
|
||||
|
||||
target->addUnitState(UNIT_STAT_STUNNED);
|
||||
target->SetTargetGuid(ObjectGuid());
|
||||
|
||||
target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
|
||||
target->CastStop(target->GetObjectGuid() == GetCasterGuid() ? GetId() : 0);
|
||||
|
||||
// Creature specific
|
||||
if (target->GetTypeId() != TYPEID_PLAYER)
|
||||
{ target->StopMoving(); }
|
||||
else
|
||||
{
|
||||
((Player*)target)->m_movementInfo.SetMovementFlags(MOVEFLAG_NONE);
|
||||
target->SetStandState(UNIT_STAND_STATE_STAND);// in 1.5 client
|
||||
target->SetRoot(true);
|
||||
}
|
||||
target->SetStunned(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2447,16 +2441,7 @@ void Aura::HandleAuraModStun(bool apply, bool Real)
|
||||
if (target->HasAuraType(SPELL_AURA_MOD_STUN))
|
||||
{ return; }
|
||||
|
||||
target->clearUnitState(UNIT_STAT_STUNNED);
|
||||
target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
|
||||
|
||||
if (!target->hasUnitState(UNIT_STAT_ROOT)) // prevent allow move if have also root effect
|
||||
{
|
||||
if (target->getVictim() && target->IsAlive())
|
||||
{ target->SetTargetGuid(target->getVictim()->GetObjectGuid()); }
|
||||
|
||||
target->SetRoot(false);
|
||||
}
|
||||
target->SetStunned(false);
|
||||
|
||||
// Wyvern Sting
|
||||
if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_HUNTER && GetSpellProto()->SpellFamilyFlags & UI64LIT(0x00010000))
|
||||
@ -2691,11 +2676,9 @@ void Aura::HandleAuraModRoot(bool apply, bool Real)
|
||||
if (target->HasAuraType(SPELL_AURA_MOD_ROOT))
|
||||
{ return; }
|
||||
|
||||
target->clearUnitState(UNIT_STAT_ROOT);
|
||||
|
||||
if (!target->hasUnitState(UNIT_STAT_STUNNED) && (target->GetTypeId() == TYPEID_PLAYER)) // prevent allow move if have also stun effect
|
||||
{ target->SetRoot(false); }
|
||||
}
|
||||
|
||||
target->SetImmobilizedState(apply);
|
||||
}
|
||||
|
||||
void Aura::HandleAuraModSilence(bool apply, bool Real)
|
||||
@ -4851,10 +4834,12 @@ void Aura::HandlePreventFleeing(bool apply, bool Real)
|
||||
Unit::AuraList const& fearAuras = GetTarget()->GetAurasByType(SPELL_AURA_MOD_FEAR);
|
||||
if (!fearAuras.empty())
|
||||
{
|
||||
const Aura *first = fearAuras.front();
|
||||
|
||||
if (apply)
|
||||
{ GetTarget()->SetFeared(false, fearAuras.front()->GetCasterGuid()); }
|
||||
{ GetTarget()->SetFeared(false, first->GetCasterGuid()); }
|
||||
else
|
||||
{ GetTarget()->SetFeared(true); }
|
||||
{ GetTarget()->SetFeared(true, first->GetCasterGuid(), first->GetId()); }
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user