Crowd Control handling improvements by Ono(Warlockbugs)

This commit is contained in:
Blumfield 2017-01-17 19:44:48 +01:00 committed by Antz
parent 45432f4f8c
commit 087d00960c
5 changed files with 142 additions and 99 deletions

View File

@ -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);

View File

@ -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; }

View File

@ -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)

View File

@ -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); }

View File

@ -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()); }
}
}