Core/Unit: Some charm fixes:

* Properly restore react state after possession expires. Closes #20769.
* Possessed creatures now don't override player control with random/waypoint motion
* SmartAI creatures now properly re-aggress charmer after charm expires
This commit is contained in:
Treeston
2018-08-28 12:52:50 +02:00
parent bf8c6f220c
commit da21ca80fc
5 changed files with 41 additions and 47 deletions

View File

@@ -679,8 +679,13 @@ void SmartAI::OnCharmed(bool /*isNew*/)
else
me->SetWalk(!mRun);
if (Unit* charmer = me->GetCharmer())
AttackStart(charmer);
if (me->LastCharmerGUID)
{
if (!me->HasReactState(REACT_PASSIVE))
if (Unit* lastCharmer = ObjectAccessor::GetUnit(*me, me->LastCharmerGUID))
me->EngageWithTarget(lastCharmer);
me->LastCharmerGUID.Clear();
}
}
GetScript()->ProcessEventsFor(SMART_EVENT_CHARMED, nullptr, 0, 0, charmed);

View File

@@ -9573,10 +9573,10 @@ CharmInfo::CharmInfo(Unit* unit)
for (uint8 i = 0; i < MAX_SPELL_CHARM; ++i)
_charmspells[i].SetActionAndType(0, ACT_DISABLED);
if (_unit->GetTypeId() == TYPEID_UNIT)
if (Creature* creature = _unit->ToCreature())
{
_oldReactState = _unit->ToCreature()->GetReactState();
_unit->ToCreature()->SetReactState(REACT_PASSIVE);
_oldReactState = creature->GetReactState();
creature->SetReactState(REACT_PASSIVE);
}
}
@@ -11358,26 +11358,12 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au
GetMotionMaster()->Clear(MOTION_PRIORITY_NORMAL);
StopMoving();
// AI will schedule its own change if appropriate
if (UnitAI* ai = GetAI())
ai->OnCharmed(false);
else
ScheduleAIChange();
}
else if (Player* player = ToPlayer())
{
if (player->isAFK())
player->ToggleAFK();
if (charmer->GetTypeId() == TYPEID_UNIT) // we are charmed by a creature
{
// change AI to charmed AI on next Update tick
if (UnitAI* ai = GetAI())
ai->OnCharmed(false);
else
player->ScheduleAIChange();
}
player->SetClientControl(this, false);
}
@@ -11438,6 +11424,15 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au
}
AddUnitState(UNIT_STATE_CHARMED);
if ((GetTypeId() != TYPEID_PLAYER) || (charmer->GetTypeId() != TYPEID_PLAYER))
{
// AI will schedule its own change if appropriate
if (UnitAI* ai = GetAI())
ai->OnCharmed(false);
else
ScheduleAIChange();
}
return true;
}
@@ -11446,15 +11441,12 @@ void Unit::RemoveCharmedBy(Unit* charmer)
if (!IsCharmed())
return;
if (!charmer)
if (charmer)
ASSERT(charmer == GetCharmer());
else
charmer = GetCharmer();
if (charmer != GetCharmer()) // one aura overrides another?
{
// TC_LOG_FATAL("entities.unit", "Unit::RemoveCharmedBy: this: " UI64FMTD " true charmer: " UI64FMTD " false charmer: " UI64FMTD,
// GetGUID(), GetCharmerGUID(), charmer->GetGUID());
// ABORT();
return;
}
ASSERT(charmer);
CharmType type;
if (HasUnitState(UNIT_STATE_POSSESSED))
@@ -11480,11 +11472,7 @@ void Unit::RemoveCharmedBy(Unit* charmer)
// Vehicle should not attack its passenger after he exists the seat
if (type != CHARM_TYPE_VEHICLE)
LastCharmerGUID = ASSERT_NOTNULL(charmer)->GetGUID();
// If charmer still exists
if (!charmer)
return;
LastCharmerGUID = charmer->GetGUID();
ASSERT(type != CHARM_TYPE_POSSESS || charmer->GetTypeId() == TYPEID_PLAYER);
ASSERT(type != CHARM_TYPE_VEHICLE || (GetTypeId() == TYPEID_UNIT && IsVehicle()));
@@ -11527,6 +11515,19 @@ void Unit::RemoveCharmedBy(Unit* charmer)
}
}
if (Player* player = ToPlayer())
player->SetClientControl(this, true);
if (playerCharmer && this != charmer->GetFirstControlled())
playerCharmer->SendRemoveControlBar();
// a guardian should always have charminfo
if (!IsGuardian())
DeleteCharmInfo();
// reset confused movement for example
ApplyControlStatesIfNeeded();
if (GetTypeId() != TYPEID_PLAYER || charmer->GetTypeId() == TYPEID_UNIT)
{
if (UnitAI* charmedAI = GetAI())
@@ -11534,18 +11535,6 @@ void Unit::RemoveCharmedBy(Unit* charmer)
else
ScheduleAIChange();
}
if (Player* player = ToPlayer())
player->SetClientControl(this, true);
// a guardian should always have charminfo
if (playerCharmer && this != charmer->GetFirstControlled())
playerCharmer->SendRemoveControlBar();
else if (GetTypeId() == TYPEID_PLAYER || (GetTypeId() == TYPEID_UNIT && !IsGuardian()))
DeleteCharmInfo();
// reset confused movement for example
ApplyControlStatesIfNeeded();
}
void Unit::RestoreFaction()

View File

@@ -340,7 +340,7 @@ enum ReactStates
REACT_DEFENSIVE = 1,
REACT_AGGRESSIVE = 2
};
static char const* DescribeReactState(ReactStates state) {
static char const* TC_GAME_API DescribeReactState(ReactStates state) {
switch (state)
{
case REACT_PASSIVE: return "PASSIVE";

View File

@@ -86,7 +86,7 @@ void RandomMovementGenerator<Creature>::SetRandomLocation(Creature* owner)
if (!owner)
return;
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting())
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE | UNIT_STATE_LOST_CONTROL) || owner->IsMovementPreventedByCasting())
{
AddFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED);
owner->StopMoving();

View File

@@ -139,7 +139,7 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* owner, uint32 diff)
if (HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED | MOVEMENTGENERATOR_FLAG_PAUSED) || !_path || _path->nodes.empty())
return true;
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting())
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE | UNIT_STATE_LOST_CONTROL) || owner->IsMovementPreventedByCasting())
{
AddFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED);
owner->StopMoving();