コード例 #1
0
bool TargetedMovementGeneratorMedium<T, D>::Update(T& owner, const uint32& time_diff)
{
    if (!i_target.isValid() || !i_target->IsInWorld())
        return false;

    if (!owner.isAlive())
        return true;

    if (owner.hasUnitState(UNIT_STAT_NOT_MOVE))
    {
        D::_clearUnitStateMove(owner);
        return true;
    }

    if (this->GetMovementGeneratorType() == CHASE_MOTION_TYPE && owner.hasUnitState(UNIT_STAT_NO_COMBAT_MOVEMENT))
    {
        D::_clearUnitStateMove(owner);
        return true;
    }

    // prevent movement while casting spells with cast time or channel time
    if (owner.IsNonMeleeSpellCasted(false, false,  true))
    {
        if (!owner.IsStopped())
            owner.StopMoving();
        return true;
    }

    // prevent crash after creature killed pet
    if (static_cast<D*>(this)->_lostTarget(owner))
    {
        D::_clearUnitStateMove(owner);
        return true;
    }

    bool targetMoved = false;
    i_recheckDistance.Update(time_diff);
    if (i_recheckDistance.Passed())
    {
        i_recheckDistance.Reset(this->GetMovementGeneratorType() == FOLLOW_MOTION_TYPE ? 50 : 100);
        G3D::Vector3 dest = owner.movespline->FinalDestination();
        targetMoved = RequiresNewPosition(owner, dest.x, dest.y, dest.z);
    }

    if (m_speedChanged || targetMoved)
        _setTargetLocation(owner, targetMoved);

    if (owner.movespline->Finalized())
    {
        if (i_angle == 0.f && !owner.HasInArc(0.01f, i_target.getTarget()))
            owner.SetInFront(i_target.getTarget());

        if (!i_targetReached)
        {
            i_targetReached = true;
            static_cast<D*>(this)->_reachTarget(owner);
        }
    }
    return true;
}
コード例 #2
0
bool TargetedMovementGeneratorMedium<T, D>::Update(T& owner, const uint32& time_diff)
{
    if (!i_target.isValid() || !i_target->IsInWorld())
        return false;

    if (!owner.isAlive())
        return true;

    if (owner.hasUnitState(UNIT_STAT_NOT_MOVE))
    {
        D::_clearUnitStateMove(owner);
        return true;
    }

    if (this->GetMovementGeneratorType() == CHASE_MOTION_TYPE && owner.hasUnitState(UNIT_STAT_NO_COMBAT_MOVEMENT))
    {
        D::_clearUnitStateMove(owner);
        return true;
    }

    // prevent movement while casting spells with cast time or channel time
    if (owner.IsNonMeleeSpellCasted(false, false,  true))
    {
        if (!owner.IsStopped())
            owner.StopMoving();
        return true;
    }

    // prevent crash after creature killed pet
    if (static_cast<D*>(this)->_lostTarget(owner))
    {
        D::_clearUnitStateMove(owner);
        return true;
    }

    bool targetMoved = false;
    i_recheckDistance.Update(time_diff);
    if (i_recheckDistance.Passed())
    {
        i_recheckDistance.Reset(this->GetMovementGeneratorType() == FOLLOW_MOTION_TYPE ? 50 : 100);
        G3D::Vector3 dest = owner.movespline->FinalDestination();
        targetMoved = RequiresNewPosition(owner, dest.x, dest.y, dest.z);
        if (!targetMoved)
        {
            // This unit is in hitbox of target
            // howewer we have to check if the target not moved a bit to update the orientation
            // client do it automatically 'visually' but it need this new orientation send or it will retrieve old orientation in some case (like stun)
            G3D::Vector3 currTargetPos;
            i_target->GetPosition(currTargetPos.x, currTargetPos.y, currTargetPos.z);
            if (owner.movespline->Finalized() && currTargetPos != m_prevTargetPos)
            {
                // position changed we need to adjust owner orientation to continue facing it
                m_prevTargetPos = currTargetPos;
                owner.SetInFront(i_target.getTarget());         // set movementinfo orientation, needed for next movement if any

                float angle = owner.GetAngle(i_target.getTarget());
                owner.SetFacingTo(angle);                       // inform client that orientation changed
                //sLog.outString("Updating facing to with angle (%3.3f)!!!", angle);
            }
        }
    }

    if (m_speedChanged || targetMoved)
        _setTargetLocation(owner, targetMoved);

    if (owner.movespline->Finalized())
    {
        if (!i_targetReached)
        {
            i_targetReached = true;
            static_cast<D*>(this)->_reachTarget(owner);
        }
    }
    return true;
}
コード例 #3
0
void TargetedMovementGeneratorMedium<T, D>::_setTargetLocation(T& owner, bool updateDestination)
{
    if (!i_target.isValid() || !i_target->IsInWorld())
        return;

    if (owner.hasUnitState(UNIT_STAT_NOT_MOVE))
        return;

    float x, y, z;

    // i_path can be nullptr in case this is the first call for this MMGen (via Update)
    // Can happen for example if no path was created on MMGen-Initialize because of the owner being stunned
    if (updateDestination || !i_path)
    {
        owner.GetPosition(x, y, z);

        // prevent redundant micro-movement for pets, other followers.
        if (!RequiresNewPosition(owner, x, y, z))
        {
            if (!owner.movespline->Finalized())
                return;
        }
        // Chase Movement and angle == 0 case: Chase to current angle
        else if (this->GetMovementGeneratorType() == CHASE_MOTION_TYPE && i_angle == 0.0f)
        {
            i_target->GetNearPoint(&owner, x, y, z, owner.GetObjectBoundingRadius(), this->GetDynamicTargetDistance(owner, false), i_target->GetAngle(&owner));
        }
        // Targeted movement to at i_offset distance from target and i_angle from target facing
        else
        {
            i_target->GetNearPoint(&owner, x, y, z, owner.GetObjectBoundingRadius(), this->GetDynamicTargetDistance(owner, false), i_target->GetOrientation() + i_angle);
        }
    }
    else
    {
        // the destination has not changed, we just need to refresh the path (usually speed change)
        G3D::Vector3 end = i_path->getEndPosition();
        x = end.x;
        y = end.y;
        z = end.z;
    }

    if (!i_path)
        i_path = new PathFinder(&owner);

    // allow pets following their master to cheat while generating paths
    bool forceDest = (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->IsPet()
                      && owner.hasUnitState(UNIT_STAT_FOLLOW));
    i_path->calculate(x, y, z, forceDest);
    if (i_path->getPathType() & PATHFIND_NOPATH)
        return;

    D::_addUnitStateMove(owner);
    i_targetReached = false;
    m_speedChanged = false;

    Movement::MoveSplineInit init(owner);
    init.MovebyPath(i_path->getPath());
    init.SetWalk(((D*)this)->EnableWalking());
    init.Launch();
}
コード例 #4
0
void TargetedMovementGeneratorMedium<T, D>::_setTargetLocation(T& owner, bool updateDestination)
{
    if (!m_target.isValid() || !m_target->IsInWorld())
        return;

    if (owner.hasUnitState(UNIT_STAT_NOT_MOVE))
        return;

    if (!IsAbleMoveWhenCast(owner.GetEntry()) && owner.IsNonMeleeSpellCasted(false))
        return;

    if (!m_target->isInAccessablePlaceFor(&owner))
        return;

    float x, y, z;

    // m_path can be nullptr in case this is the first call for this MMGen (via Update)
    // Can happen for example if no path was created on MMGen-Initialize because of the owner being stunned
    if (updateDestination || !m_path)
    {
        owner.GetPosition(x, y, z);

        // Prevent redundant micro-movement for pets, other followers.
        if (!RequiresNewPosition(owner, x, y, z))
        {
            if (!owner.movespline->Finalized())
                return;
        }
        else
        {
            float absAngle;

            // Chase Movement and angle == 0 case: Chase to current angle
            if (this->GetMovementGeneratorType() == CHASE_MOTION_TYPE && m_angle == 0.0f)
                absAngle = m_target->GetAngle(&owner);
            // Targeted movement to at m_offset distance from target and m_angle from target facing
            else
                absAngle = m_target->GetOrientation() + m_angle;

            m_target->GetNearPoint(&owner, x, y, z, owner.GetObjectBoundingRadius(),
                                   static_cast<D*>(this)->GetDynamicTargetDistance(owner, false), absAngle);

            // Add hover height
            if (owner.IsLevitating())
                z += owner.GetFloatValue(UNIT_FIELD_HOVERHEIGHT);
        }
    }
    else
    {
        // the destination has not changed, we just need to refresh the path (usually speed change)
        G3D::Vector3 endPos = m_path->getEndPosition();
        x = endPos.x;
        y = endPos.y;
        z = endPos.z;
    }

    if (!m_path)
        m_path = new PathFinder(&owner);

    // allow pets following their master to cheat while generating paths
    bool forceDest = (owner.GetTypeId() == TYPEID_UNIT &&
                      ((Creature*)&owner)->IsPet() && owner.hasUnitState(UNIT_STAT_FOLLOW));

    m_path->calculate(x, y, z, forceDest);

    m_speedChanged = false;

    // don't move if path points equivalent
    if (m_path->getStartPosition() == m_path->getEndPosition())
    {
        owner.StopMoving(true);
        return;
    }

    if (m_path->getPathType() & PATHFIND_NOPATH)
    {
        DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS,"TargetedMovementGeneratorMedium::  unit %s cannot find path to %s (%f, %f, %f),  gained PATHFIND_NOPATH! Owerride used.",
                         owner.GetGuidStr().c_str(),
                         m_target.isValid() ? m_target->GetObjectGuid().GetString().c_str() : "<none>",
                         x, y, z);
        //return;
    }

    D::_addUnitStateMove(owner);
    m_targetReached = false;

    Movement::MoveSplineInit<Unit*> init(owner);
    init.MovebyPath(m_path->getPath());
    init.SetSmooth(); // fix broken fly movement for old creatures
    init.SetWalk(
        ((D*)this)->EnableWalking() ||
        // hack for old creatures with bugged fly animation
        (owner.GetTypeId() == TYPEID_UNIT && owner.IsLevitating() && owner.GetFloatValue(UNIT_FIELD_HOVERHEIGHT) == 0.0f));
    init.Launch();
}
コード例 #5
0
bool TargetedMovementGeneratorMedium<T, D>::update(T& owner, const uint32& time_diff)
{
    if (!m_target.isValid() || !m_target->IsInWorld())
        return false;

    if (!owner.isAlive())
        return true;

    if (owner.hasUnitState(UNIT_STAT_NOT_MOVE) || (owner.IsInUnitState(UNIT_ACTION_CHASE) && owner.hasUnitState(UNIT_STAT_NO_COMBAT_MOVEMENT)))
    {
        D::_clearUnitStateMove(owner);
        return true;
    }

    // prevent movement while casting spells with cast time or channel time
    if (!IsAbleMoveWhenCast(owner.GetEntry()) && owner.IsNonMeleeSpellCasted(false, false, true))
    {
        owner.StopMoving();
        return true;
    }

    // prevent crash after creature killed pet
    if (static_cast<D*>(this)->_lostTarget(owner))
    {
        D::_clearUnitStateMove(owner);
        if (m_waitTargetTimer >= TARGET_NOT_ACCESSIBLE_MAX_TIMER)
            return false;
        else
        {
            m_waitTargetTimer += 5 * time_diff;
            return true;
        }
    }

    if (!m_target->isInAccessablePlaceFor(&owner))
        return true;

    bool moveToTarget = false;

    m_recheckDistanceTimer.Update(time_diff);
    if (m_recheckDistanceTimer.Passed())
    {
        m_recheckDistanceTimer.Reset(this->GetMovementGeneratorType() == FOLLOW_MOTION_TYPE
                                     ? RECHECK_DISTANCE_TIMER_FOLLOW
                                     : RECHECK_DISTANCE_TIMER);

        G3D::Vector3 dest = owner.movespline->FinalDestination();
        moveToTarget = dest == Vector3() ? true : RequiresNewPosition(owner, dest.x, dest.y, dest.z);

        if (owner.GetTypeId() == TYPEID_UNIT && !((Creature*)&owner)->IsPet())
        {
            Unit* pVictim = owner.getVictim();
            if (pVictim && pVictim->GetObjectGuid() == m_target->GetObjectGuid())
            {
                if (!pVictim->isAlive() && owner.movespline->Finalized())
                    return false;

                if (!m_offset && owner.movespline->Finalized() && !owner.CanReachWithMeleeAttack(pVictim) &&
                        !m_target->m_movementInfo.HasMovementFlag(MOVEFLAG_PENDINGSTOP))
                {
                    if (m_waitTargetTimer < TARGET_NOT_ACCESSIBLE_MAX_TIMER)
                        m_waitTargetTimer += m_recheckDistanceTimer.GetExpiry();
                    else
                        return false;
                }
                else
                    m_waitTargetTimer = 0;
            }
        }
    }

    if (m_speedChanged || moveToTarget)
        _setTargetLocation(owner, moveToTarget);

    if (owner.movespline->Finalized())
    {
        if (fabs(m_angle) < M_NULL_F && !owner.HasInArc(0.01f, m_target.getTarget()))
            owner.SetInFront(m_target.getTarget());

        if (!m_targetReached)
        {
            m_targetReached = true;
            static_cast<D*>(this)->_reachTarget(owner);
        }
    }
    return true;
}
コード例 #6
0
void TargetedMovementGeneratorMedium<T, D>::_setTargetLocation(T& owner, bool updateDestination)
{
    if (!i_target.isValid() || !i_target->IsInWorld())
        return;

    if (owner.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED) || owner.isDead())
        return;

    if (owner.GetTypeId() == TYPEID_UNIT && !i_target->isInAccessiblePlaceFor(owner.ToCreature()))
        return;

    float x, y, z;
    
    // i_path can be NULL in case this is the first call for this MMGen (via Update)
    // Can happen for example if no path was created on MMGen-Initialize because of the owner being stunned
    if (updateDestination || !i_path)
    {
        owner.GetPosition(x, y, z);

        // prevent redundant micro-movement for pets, other followers.
        if (!RequiresNewPosition(owner, x, y, z))
        {
            if (!owner.movespline->Finalized())
                return;
        }
        else
        {
            if (!i_offset)
            {
                // to nearest random contact position
                i_target->GetRandomContactPoint(&owner, x, y, z, 0, CONTACT_DISTANCE);

                // Sometimes target is available only from certain angles
                // in that case we use the exact location (blizzlike hahavior)
                if (fabsf(i_target->GetPositionZ() - z) > owner.GetObjectSize())
                    i_target->GetPosition(x, y, z);
            }
            else if (!i_angle && !owner.HasUnitState(UNIT_STATE_FOLLOW))
            {
                // caster chase
                i_target->GetContactPoint(&owner, x, y, z, i_offset * urand(80, 95) * 0.01f);
            }
            else
            {
                // to at i_offset distance from target and i_angle from target facing
                i_target->GetClosePoint(x, y, z, owner.GetObjectSize(), i_offset, i_angle);

                // Sometimes target is available only from certain angles
                // in that case we use the exact location (blizzlike hahavior)
                if (fabsf(i_target->GetPositionZ() - z) > (owner.GetObjectSize() + i_offset))
                    i_target->GetPosition(x, y, z);
            }
        }
    }
    else
    {
        // the destination has not changed, we just need to refresh the path (usually speed change)
        G3D::Vector3 end = i_path->getEndPosition();
        x = end.x;
        y = end.y;
        z = end.z;
    }

    if (!i_path)
        i_path = new PathInfo(&owner);

    // allow pets following their master to cheat while generating paths
    bool forceDest = (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->HasUnitTypeMask(UNIT_MASK_MINION) &&
        owner.HasUnitState(UNIT_STATE_FOLLOW));

    bool result = i_path->Update(x, y, z, forceDest);
    if (!result || (i_path->getPathType() & PATHFIND_NOPATH))
    {
        // Cant reach target
        m_speedChanged = true;
        return;
    }

    i_targetReached = false;
    m_speedChanged = false;
    owner.AddUnitState(UNIT_STATE_CHASE);

    Movement::MoveSplineInit init(owner);
    init.MovebyPath(i_path->getFullPath());
    init.SetWalk(((D*)this)->EnableWalking(owner));
    static_cast<D*>(this)->_updateSpeed(owner);

    init.Launch();
}
コード例 #7
0
bool TargetedMovementGeneratorMedium<T, D>::Update(T& owner, const uint32& time_diff)
{
    if (!i_target.isValid() || !i_target->IsInWorld())
        return false;

    if (!owner.IsAlive())
        return true;

    if (owner.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_FLEEING | UNIT_STATE_DISTRACTED))
        return true;

    // prevent movement while casting spells with cast time or channel time
    if (owner.IsNonMeleeSpellCast(false, false,  true) || owner.HasUnitState(UNIT_STATE_CASTING))
    {
        if (!owner.IsStopped())
            owner.StopMoving();
        return true;
    }

    if (!owner.HasAuraType(SPELL_AURA_MOD_INVISIBILITY) && !owner.CanSeeOrDetect(i_target.getTarget(), true))
    {
        owner.AttackStop();
        if (owner.GetOwner())
            owner.GetMotionMaster()->MoveFollow(owner.GetOwner(), PET_FOLLOW_DIST, owner.GetFollowAngle());
        else
            owner.StopMoving();

        return true;
    }

    // prevent crash after creature killed pet
    if (!owner.HasUnitState(UNIT_STATE_FOLLOW) && owner.GetVictim() != i_target.getTarget())
        return true;

    if (i_path && i_path->getPathType() & PATHFIND_NOPATH)
    {
        if (Creature* me = owner.ToCreature())
        {
            if (m_evadeTimer <= time_diff)
            {
                if (me->AI())
                    me->AI()->EnterEvadeMode();
            }
            else
                m_evadeTimer -= time_diff;
        }
        return true;
    }

    bool targetMoved = false;
    i_recheckDistance.Update(time_diff);
    if (i_recheckDistance.Passed())
    {
        i_recheckDistance.Reset(this->GetMovementGeneratorType() == FOLLOW_MOTION_TYPE ? 50 : 100);
        G3D::Vector3 dest = owner.movespline->FinalDestination();
        targetMoved = RequiresNewPosition(owner, dest.x, dest.y, dest.z);
    }

    if (m_speedChanged || targetMoved)
        _setTargetLocation(owner, targetMoved);

    if (owner.movespline->Finalized())
    {
        if (i_angle == 0.f && !owner.HasInArc(0.01f, i_target.getTarget()))
            owner.SetInFront(i_target.getTarget());

        if (!i_targetReached)
        {
            i_targetReached = true;
            static_cast<D*>(this)->_reachTarget(owner);
        }
    }

    // Implemented for PetAI to handle resetting flags when pet owner reached
    if (owner.movespline->Finalized())
        MovementInform(owner);

    return true;
}
コード例 #8
0
void TargetedMovementGeneratorMedium<T, D>::_setTargetLocation(T& owner, bool updateDestination)
{
    if (!i_target.isValid() || !i_target->IsInWorld())
        return;

    if (owner.hasUnitState(UNIT_STAT_NOT_MOVE))
        return;

    float x, y, z;

    // i_path can be nullptr in case this is the first call for this MMGen (via Update)
    // Can happen for example if no path was created on MMGen-Initialize because of the owner being stunned
    if (updateDestination || !i_path)
    {
        owner.GetPosition(x, y, z);

        // prevent redundant micro-movement for pets, other followers.
        if (!RequiresNewPosition(owner, x, y, z))
        {
            if (!owner.movespline->Finalized())
                return;
        }
        // Chase Movement and angle == 0 case: Chase to current angle
        else if (this->GetMovementGeneratorType() == CHASE_MOTION_TYPE && i_angle == 0.0f)
        {
            i_target->GetNearPoint(&owner, x, y, z, owner.GetObjectBoundingRadius(), this->GetDynamicTargetDistance(owner, false), i_target->GetAngle(&owner));
        }
        // Targeted movement to at i_offset distance from target and i_angle from target facing
        else
        {
            i_target->GetNearPoint(&owner, x, y, z, owner.GetObjectBoundingRadius(), this->GetDynamicTargetDistance(owner, false), i_target->GetOrientation() + i_angle);
        }
    }
    else
    {
        // the destination has not changed, we just need to refresh the path (usually speed change)
        G3D::Vector3 end = i_path->getEndPosition();
        x = end.x;
        y = end.y;
        z = end.z;
    }

    if (!i_path)
        i_path = new PathFinder(&owner);

    // allow pets following their master to cheat while generating paths
    bool forceDest = (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->IsPet()
                      && owner.hasUnitState(UNIT_STAT_FOLLOW));
    i_path->calculate(x, y, z, forceDest);
    if (i_path->getPathType() & PATHFIND_NOPATH)
        return;

    auto& path = i_path->getPath();

    if (this->GetMovementGeneratorType() == CHASE_MOTION_TYPE)
    {
        if (float offset = this->i_offset) // need to cut path until most distant viable point
        {
            float dist = this->i_offset * CHASE_MOVE_CLOSER_FACTOR + CHASE_DEFAULT_RANGE_FACTOR * this->i_target->GetCombinedCombatReach(&owner);
            float tarX, tarY, tarZ;
            i_target->GetPosition(tarX, tarY, tarZ);
            auto iter = std::next(path.begin(), 1); // need to start at index 1, index 0 is start position and filled in init.Launch()
            for (; iter != path.end(); ++iter)
            {
                G3D::Vector3 data = (*iter);
                if (!i_target->IsWithinDist3d(data.x, data.y, data.z, dist))
                    continue;
                if (!owner.GetMap()->IsInLineOfSight(tarX, tarY, tarZ + 2.0f, data.x, data.y, data.z + 2.0f, IGNORE_M2))
                    continue;
                // both in LOS and in range - advance to next and stop
                ++iter;
                break;
            }
            if (iter != path.end())
                path.erase(iter, path.end());
        }
    }

    D::_addUnitStateMove(owner);
    i_targetReached = false;
    m_speedChanged = false;

    Movement::MoveSplineInit init(owner);
    init.MovebyPath(i_path->getPath());
    init.SetWalk(((D*)this)->EnableWalking());
    init.Launch();
}