void WaypointMovementGenerator<Creature>::Initialize(Creature &u)
{
    u.StopMoving();
    //i_currentNode = -1; // uint32, become 0 in the first update
    //i_nextMoveTime.Reset(0);
    StopedByPlayer = false;
    if (!path_id)
        path_id = u.GetWaypointPath();
    waypoints = sWaypointMgr->GetPath(path_id);
    i_currentNode = 0;
    if (waypoints && waypoints->size())
    {
        node = waypoints->front();
        Traveller<Creature> traveller(u);
        InitTraveller(u, *node);
        MoveToNextNode(traveller);

        //Call for creature formation update
        if (u.GetFormation() && u.GetFormation()->getLeader() == &u)
            u.GetFormation()->LeaderMoveTo(node->x, node->y, node->z);
    }
    else
        node = NULL;
}
Example #2
0
std::string parse (const anta::Node<M_>& entry, const std::string& text,
		const anta::uint_t state_pool_capacity = 1024)
{
	std::stringstream out;

	// prepare traveller
	anta::Traveller<M_> traveller(entry);
	traveller. set_capacity(state_pool_capacity);
#if defined(DEBUG_PRINT)
	traveller. get_observer(). link(& std::cout);
#endif

	// perform parsing
	out << traveller. run(
			&* text. begin(), &* text. begin() + text. size());

	// extract traces
	anta::aux::Tracer<M_> tracer(traveller);
	while (tracer. next())
	{
		out << " |";
		while (tracer. step())
		{
			const int label = tracer -> get_arc(). get_label(). get();
			if (label != 0)
				out << ' ' << label;
		}
	}

	// cleanup [not really necessary]
	tracer. rewind();
	traveller. reset();

	// return fingerprint
	return out. str();
}
bool
RandomMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff)
{
    if (creature.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
    {
        i_nextMoveTime.Update(i_nextMoveTime.GetExpiry());    // Expire the timer
        creature.ClearUnitState(UNIT_STAT_ROAMING);
        return true;
    }

    i_nextMoveTime.Update(diff);

    if (i_destinationHolder.HasArrived() && !creature.IsStopped() && !creature.canFly())
        creature.ClearUnitState(UNIT_STAT_ROAMING | UNIT_STAT_MOVE);

    if (!i_destinationHolder.HasArrived() && creature.IsStopped())
        creature.AddUnitState(UNIT_STAT_ROAMING);

    CreatureTraveller traveller(creature);

    if (i_destinationHolder.UpdateTraveller(traveller, diff, true))
    {
        if (i_nextMoveTime.Passed())
        {
            if (irand(0,RUNNING_CHANCE_RANDOMMV) > 0)
                creature.AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
            _setRandomLocation(creature);
        }
        else if (creature.isPet() && creature.GetOwner() && !creature.IsWithinDist(creature.GetOwner(),PET_FOLLOW_DIST+2.5f))
        {
           creature.RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
           _setRandomLocation(creature);
        }
    }
    return true;
}
bool FleeingMovementGenerator<T>::Update(T &owner, const uint32 & time_diff)
{
    if( !&owner || !owner.isAlive() )
        return false;

    // ignore in case other no reaction state
    if (owner.hasUnitState(UNIT_STAT_CAN_NOT_REACT & ~UNIT_STAT_FLEEING))
    {
        owner.clearUnitState(UNIT_STAT_FLEEING_MOVE);
        return true;
    }

    Traveller<T> traveller(owner);

    i_nextCheckTime.Update(time_diff);

    if( (owner.IsStopped() && !i_destinationHolder.HasArrived()) || !i_destinationHolder.HasDestination() )
    {
        _setTargetLocation(owner);
        return true;
    }

    if (i_destinationHolder.UpdateTraveller(traveller, time_diff, false))
    {
        if (!IsActive(owner))                               // force stop processing (movement can move out active zone with cleanup movegens list)
            return true;                                    // not expire now, but already lost

        i_destinationHolder.ResetUpdate(50);
        if(i_nextCheckTime.Passed() && i_destinationHolder.HasArrived())
        {
            _setTargetLocation(owner);
            return true;
        }
    }
    return true;
}
void FlightPathMovementGenerator::Initialize(Player &player)
{
    player.getHostilRefManager().setOnlineOfflineState(false);
    player.addUnitState(UNIT_STAT_IN_FLIGHT);
    player.SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
    LoadPath(player);
    Traveller<Player> traveller(player);
    // do not send movement, it was sent already
    i_destinationHolder.SetDestination(traveller, i_path[i_currentNode].x, i_path[i_currentNode].y, i_path[i_currentNode].z, false);

    player.SendMonsterMoveByPath(GetPath(),GetCurrentNode(),GetPathAtMapEnd());

	// Storage to preload flightmaster grid at end of flight. For multi-stop flights, this will
	// be reinitialized for each flightmaster at the end of each spline (or stop) in the flight.

	uint32 nodeCount = i_mapIds.size();		// Get the number of nodes in the path. i_path and i_mapIds are the
											//  same size when loaded in ObjectMgr::GetTaxiPathNodes, called from LoadPath()

	m_endMapId = i_mapIds[nodeCount -1];	// Get the map ID from the last node
	m_preloadTargetNode = nodeCount / 2;	// Split the number of nodes in half to preload the flightmaster half-way through the flight
	m_endGridX = i_path[nodeCount -1].x;	// Get the X position from the last node
	m_endGridY = i_path[nodeCount -1].y;	// Get tye Y position from the last node

}
Example #6
0
void
RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
{
    float X, Y, Z, z, nx, ny, nz, ori, dist;

    creature.GetHomePosition(X, Y, Z, ori);

    z = creature.GetPositionZ();
    Map const* map = creature.GetBaseMap();

    // For 2D/3D system selection
    //bool is_land_ok  = creature.canWalk();
    //bool is_water_ok = creature.canSwim();
    bool is_air_ok   = creature.canFly();

    for (uint32 i = 0; ; ++i)
    {
        const float angle = (float)rand_norm()*static_cast<float>(M_PI*2);
        const float range = (float)rand_norm()*wander_distance;
        const float distanceX = range * cos(angle);
        const float distanceY = range * sin(angle);

        nx = X + distanceX;
        ny = Y + distanceY;

        // prevent invalid coordinates generation
        Trillium::NormalizeMapCoord(nx);
        Trillium::NormalizeMapCoord(ny);

        dist = (nx - X)*(nx - X) + (ny - Y)*(ny - Y);

        if (i == 5)
        {
            nz = Z;
            break;
        }

        if (is_air_ok) // 3D system above ground and above water (flying mode)
        {
            const float distanceZ = (float)(rand_norm()) * sqrtf(dist)/2; // Limit height change
            nz = Z + distanceZ;
            float tz = map->GetHeight(nx, ny, nz-2.0f, false); // Map check only, vmap needed here but need to alter vmaps checks for height.
            float wz = map->GetWaterLevel(nx, ny);
            if (tz >= nz || wz >= nz)
                continue; // Problem here, we must fly above the ground and water, not under. Let's try on next tick
        }
        //else if (is_water_ok) // 3D system under water and above ground (swimming mode)
        else // 2D only
        {
            dist = dist >= 100.0f ? 10.0f : sqrtf(dist); // 10.0 is the max that vmap high can check (MAX_CAN_FALL_DISTANCE)

            // The fastest way to get an accurate result 90% of the time.
            // Better result can be obtained like 99% accuracy with a ray light, but the cost is too high and the code is too long.
            nz = map->GetHeight(nx, ny, Z+dist-2.0f, false); // Map check
            if (fabs(nz-Z)>dist)
            {
                nz = map->GetHeight(nx, ny, Z-2.0f, true); // Vmap Horizontal or above
                if (fabs(nz-Z)>dist)
                {
                    nz = map->GetHeight(nx, ny, Z+dist-2.0f, true); // Vmap Higher
                    if (fabs(nz-Z)>dist)
                        continue; // let's forget this bad coords where a z cannot be find and retry at next tick
                }
            }
        }
        break;
    }

    Traveller<Creature> traveller(creature);
    creature.SetOrientation(creature.GetAngle(nx, ny));
    i_destinationHolder.SetDestination(traveller, nx, ny, nz);
    creature.AddUnitState(UNIT_STAT_ROAMING);
    if (is_air_ok)
    {
        i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
    }
    //else if (is_water_ok) // Swimming mode to be done with more than this check
    else
    {
        i_nextMoveTime.Reset(urand(500+i_destinationHolder.GetTotalTravelTime(), 5000+i_destinationHolder.GetTotalTravelTime()));
        creature.AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
    }

    //Call for creature group update
    if (creature.GetFormation() && creature.GetFormation()->getLeader() == &creature)
    {
        creature.GetFormation()->LeaderMoveTo(nx, ny, nz);
    }
}
Example #7
0
bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff)
{
    if (!&creature)
        return true;

    // Waypoint movement can be switched on/off
    // This is quite handy for escort quests and other stuff
    if (creature.hasUnitState(UNIT_STAT_NOT_MOVE))
    {
        creature.clearUnitState(UNIT_STAT_ROAMING_MOVE);
        return true;
    }

    // prevent a crash at empty waypoint path.
    if (!i_path || i_path->empty())
    {
        creature.clearUnitState(UNIT_STAT_ROAMING_MOVE);
        return true;
    }

    if (i_currentNode >= i_path->size())
        i_currentNode = 0;

    CreatureTraveller traveller(creature);

    i_nextMoveTime.Update(diff);
    if (i_destinationHolder.UpdateTraveller(traveller, diff, false, true))
    {
        if (!IsActive(creature))                            // force stop processing (movement can move out active zone with cleanup movegens list)
            return true;                                    // not expire now, but already lost
    }

    // creature has been stopped in middle of the waypoint segment
    if (!i_destinationHolder.HasArrived() && creature.IsStopped())
    {
        // Timer has elapsed, meaning this part controlled it
        if (i_nextMoveTime.Passed())
        {
            SetStoppedByPlayer(false);

            creature.addUnitState(UNIT_STAT_ROAMING_MOVE);

            if (creature.canFly())
                creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7);

            // Now we re-set destination to same node and start travel
            const WaypointNode &node = i_path->at(i_currentNode);
            i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z);
            i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
        }
        else // if( !i_nextMoveTime.Passed())
        {
            // unexpected end of timer && creature stopped && not at end of segment
            if (!IsStoppedByPlayer())
            {
                // Put 30 seconds delay
                i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER);
                i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER);
                SetStoppedByPlayer(true);                   // Mark we did it
            }
        }
        return true;                                        // Abort here this update
    }

    if (creature.IsStopped() && !i_hasDone) // creature is waiting on a waypoint and hasn't done the behavior yet
    {
        uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1;

        if (i_path->at(idx).orientation != 100)
            creature.SetOrientation(i_path->at(idx).orientation);

        if (WaypointBehavior *behavior = i_path->at(idx).behavior)
        {
            if (behavior->emote != 0)
                creature.HandleEmote(behavior->emote);

            if (behavior->spell != 0)
            {
                creature.CastSpell(&creature, behavior->spell, false);

                if (!IsActive(creature))                // force stop processing (cast can change movegens list)
                    return true;                        // not expire now, but already lost
            }

            if (behavior->model1 != 0)
                creature.SetDisplayId(behavior->model1);

            if (behavior->textid[0])
            {
                // Not only one text is set
                if (behavior->textid[1])
                {
                    // Select one from max 5 texts (0 and 1 already checked)
                    int i = 2;
                    for(; i < MAX_WAYPOINT_TEXT; ++i)
                    {
                        if (!behavior->textid[i])
                            break;
                    }

                    creature.Say(behavior->textid[rand() % i], 0, 0);
                }
                else
                    creature.Say(behavior->textid[0], 0, 0);
            }
        } // behavior done

        i_hasDone = true;
        MovementInform(creature);

        if (!IsActive(creature))                        // force stop processing (movement can move out active zone with cleanup movegens list)
            return true;                                // not expire now, but already lost

        // prevent a crash at empty waypoint path.
        if (!i_path || i_path->empty() || i_currentNode >= i_path->size())
        {
            creature.clearUnitState(UNIT_STAT_ROAMING_MOVE);
            return true;
        }
    }                                                       // i_creature.IsStopped()

    // This is at the end of waypoint segment or has been stopped by player
    if (i_nextMoveTime.Passed())
    {
        // If stopped then begin a new move segment
        if (creature.IsStopped())
        {
            creature.addUnitState(UNIT_STAT_ROAMING_MOVE);

            if (creature.canFly())
                creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7);

            const WaypointNode &node = i_path->at(i_currentNode);
            i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z);
            i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());

            uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1;

            if (i_path->at(idx).orientation != 100)
                creature.SetOrientation(i_path->at(idx).orientation);

            if (WaypointBehavior *behavior = i_path->at(idx).behavior)
            {
                if (behavior->model2 != 0)
                    creature.SetDisplayId(behavior->model2);

                creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
            }
        }
        else
        {
            // If not stopped then stop it and set the reset of TimeTracker to waittime
            creature.StopMoving();
            SetStoppedByPlayer(false);

            i_nextMoveTime.Reset(i_path->at(i_currentNode).delay);
            ++i_currentNode;

            i_hasDone = false;

            if (i_currentNode >= i_path->size())
                i_currentNode = 0;
        }
    }
    return true;
}
bool TargetedMovementGenerator<T>::Update(T &owner, const uint32 & time_diff)
{
    if (!i_target.isValid() || !i_target->IsInWorld())
        return false;

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

    if (owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_DISTRACTED))
        return true;

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

    // prevent crash after creature killed pet
    if (!owner.hasUnitState(UNIT_STAT_FOLLOW) && owner.getVictim() != i_target.getTarget())
        return true;

    if (i_path && (i_path->getPathType() & PATHFIND_NOPATH))
        return true;

    Traveller<T> traveller(owner);

    if (!i_destinationHolder.HasDestination())
        _setTargetLocation(owner);

    if (i_destinationHolder.UpdateTraveller(traveller, time_diff, i_recalculateTravel || owner.IsStopped()))
    {
        // put targeted movement generators on a higher priority
        if (owner.GetObjectSize())
            i_destinationHolder.ResetUpdate(100);

        float dist = owner.GetCombatReach() + sWorld.getRate(RATE_TARGET_POS_RECALCULATION_RANGE);

        float x,y,z;
        i_target->GetPosition(x, y, z);
        PathNode next_point(x, y, z);

        bool targetMoved = false, needNewDest = false;
        if (i_path)
        {
            PathNode end_point = i_path->getEndPosition();
            next_point = i_path->getNextPosition();

            needNewDest = i_destinationHolder.HasArrived() && !inRange(next_point, i_path->getActualEndPosition(), dist, dist);

            // GetClosePoint() will always return a point on the ground, so we need to
            // handle the difference in elevation when the creature is flying
            if (owner.GetTypeId() == TYPEID_UNIT && owner.ToCreature()->canFly())
                targetMoved = i_target->GetDistanceSqr(end_point.x, end_point.y, end_point.z) >= dist * dist;
            else
                targetMoved = i_target->GetDistance2d(end_point.x, end_point.y) >= dist;
        }

        // target moved
		if (!i_path || targetMoved || needNewDest || i_recalculateTravel || owner.IsStopped())
        {
            // (re)calculate path
            _setTargetLocation(owner);

            next_point = i_path->getNextPosition();

            // Set new Angle For Map::
            owner.SetOrientation(owner.GetAngle(next_point.x, next_point.y));
         }
        // Update the Angle of the target only for Map::, no need to send packet for player
        else if (!i_angle && !owner.HasInArc(0.01f, next_point.x, next_point.y))
           owner.SetOrientation(owner.GetAngle(next_point.x, next_point.y));

        if ((owner.IsStopped() && !i_destinationHolder.HasArrived()) || i_recalculateTravel)
        {
            i_recalculateTravel = false;
            //Angle update will take place into owner.StopMoving()
	    owner.SetOrientation(owner.GetAngle(next_point.x, next_point.y));

            owner.StopMoving();
            if (owner.IsWithinMeleeRange(i_target.getTarget()) && !owner.hasUnitState(UNIT_STAT_FOLLOW))
                owner.Attack(i_target.getTarget(), true);
        }
    }

    // Implemented for PetAI to handle resetting flags when pet owner reached
    if (i_destinationHolder.HasArrived())
        MovementInform(owner);

    return true;
}
bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff)
{
    if (!&creature)
        return true;

    // Waypoint movement can be switched on/off
    // This is quite handy for escort quests and other stuff
    if (creature.hasUnitState(UNIT_STAT_NOT_MOVE))
    {
        creature.clearUnitState(UNIT_STAT_ROAMING_MOVE);
        return true;
    }

    // prevent a crash at empty waypoint path.
    if (!i_path || i_path->empty())
    {
        creature.clearUnitState(UNIT_STAT_ROAMING_MOVE);
        return true;
    }

    if (i_currentNode >= i_path->size())
    {
        sLog.outError("WaypointMovement currentNode (%u) is equal or bigger than path size (creature entry %u)", i_currentNode, creature.GetEntry());
        i_currentNode = 0;
    }

    CreatureTraveller traveller(creature);

    i_nextMoveTime.Update(diff);

    if (i_destinationHolder.UpdateTraveller(traveller, diff, false, true))
    {
        if (!IsActive(creature))                            // force stop processing (movement can move out active zone with cleanup movegens list)
            return true;                                    // not expire now, but already lost
    }

    // creature has been stopped in middle of the waypoint segment
    if (!i_destinationHolder.HasArrived() && creature.IsStopped())
    {
        // Timer has elapsed, meaning this part controlled it
        if (i_nextMoveTime.Passed())
        {
            SetStoppedByPlayer(false);

            creature.addUnitState(UNIT_STAT_ROAMING_MOVE);

            if (creature.canFly())
                creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7);

            // Now we re-set destination to same node and start travel
            const WaypointNode &node = i_path->at(i_currentNode);
            i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z);
            i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
        }
        else // if( !i_nextMoveTime.Passed())
        {
            // unexpected end of timer && creature stopped && not at end of segment
            if (!IsStoppedByPlayer())
            {
                // Put 30 seconds delay
                i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER);
                i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER);
                SetStoppedByPlayer(true);                   // Mark we did it
            }
        }
        return true;                                        // Abort here this update
    }

    if (creature.IsStopped())
    {
        if (!m_isArrivalDone)
        {
            if (i_path->at(i_currentNode).orientation != 100)
                creature.SetOrientation(i_path->at(i_currentNode).orientation);

            if (i_path->at(i_currentNode).script_id)
            {
                DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Creature movement start script %u at point %u for creature %u (entry %u).", i_path->at(i_currentNode).script_id, i_currentNode, creature.GetDBTableGUIDLow(), creature.GetEntry());
                creature.GetMap()->ScriptsStart(sCreatureMovementScripts, i_path->at(i_currentNode).script_id, &creature, &creature);
            }

            // We have reached the destination and can process behavior
            if (WaypointBehavior *behavior = i_path->at(i_currentNode).behavior)
            {
                if (behavior->emote != 0)
                    creature.HandleEmote(behavior->emote);

                if (behavior->spell != 0)
                {
                    creature.CastSpell(&creature, behavior->spell, false);

                    if (!IsActive(creature))                // force stop processing (cast can change movegens list)
                        return true;                        // not expire now, but already lost
                }

                if (behavior->model1 != 0)
                    creature.SetDisplayId(behavior->model1);

                if (behavior->textid[0])
                {
                    // Not only one text is set
                    if (behavior->textid[1])
                    {
                        // Select one from max 5 texts (0 and 1 already checked)
                        int i = 2;
                        for(; i < MAX_WAYPOINT_TEXT; ++i)
                        {
                            if (!behavior->textid[i])
                                break;
                        }

                        creature.Say(behavior->textid[rand() % i], 0, 0);
                    }
                    else
                        creature.Say(behavior->textid[0], 0, 0);
                }
            }                                               // wpBehaviour found

            // Can only do this once for the node
            m_isArrivalDone = true;

            // Inform script
            MovementInform(creature);

            if (!IsActive(creature))                        // force stop processing (movement can move out active zone with cleanup movegens list)
                return true;                                // not expire now, but already lost

            // prevent a crash at empty waypoint path.
            if (!i_path || i_path->empty() || i_currentNode >= i_path->size())
            {
                creature.clearUnitState(UNIT_STAT_ROAMING_MOVE);
                return true;
            }
        }
    }                                                       // i_creature.IsStopped()

    // This is at the end of waypoint segment (incl. was previously stopped by player, extending the time)
    if (i_nextMoveTime.Passed())
    {
        // If stopped then begin a new move segment
        if (creature.IsStopped())
        {
            creature.addUnitState(UNIT_STAT_ROAMING_MOVE);

            if (creature.canFly())
                creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7);

            if (WaypointBehavior *behavior = i_path->at(i_currentNode).behavior)
            {
                if (behavior->model2 != 0)
                    creature.SetDisplayId(behavior->model2);

                creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
            }

            // behavior for "departure" of the current node is done
            m_isArrivalDone = false;

            // Proceed with increment current node and then send to the next destination
            ++i_currentNode;

            // Oops, end of the line so need to start from the beginning
            if (i_currentNode >= i_path->size())
                i_currentNode = 0;

            if (i_path->at(i_currentNode).orientation != 100)
                creature.SetOrientation(i_path->at(i_currentNode).orientation);

            const WaypointNode &node = i_path->at(i_currentNode);
            i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z);
            i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
        }
        else
        {
            // If not stopped then stop it
            creature.clearUnitState(UNIT_STAT_ROAMING_MOVE);

            SetStoppedByPlayer(false);

            // Set TimeTracker to waittime for the current node
            i_nextMoveTime.Reset(i_path->at(i_currentNode).delay);
        }
    }

    return true;
}
bool
TargetedMovementGenerator<T>::Update(T &owner, const uint32 & time_diff)
{
    if (!i_target.isValid() || !i_target->IsInWorld())
        return false;

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

    if (owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_DISTRACTED))
        return true;

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

    // prevent crash after creature killed pet
    if (!owner.hasUnitState(UNIT_STAT_FOLLOW) && owner.getVictim() != i_target.getTarget())
        return true;

    Traveller<T> traveller(owner);

    if (!i_destinationHolder.HasDestination())
        _setTargetLocation(owner);
    else if (owner.IsStopped() && !i_destinationHolder.HasArrived())
    {
        owner.addUnitState(UNIT_STAT_CHASE);
        i_destinationHolder.StartTravel(traveller);
        return true;
    }

    if (i_destinationHolder.UpdateTraveller(traveller, time_diff))
    {
        // put targeted movement generators on a higher priority
        //if (owner.GetObjectSize())
        //i_destinationHolder.ResetUpdate(50);

        // target moved
        if (i_targetX != i_target->GetPositionX() || i_targetY != i_target->GetPositionY()
            || i_targetZ != i_target->GetPositionZ())
        {
            if (_setTargetLocation(owner) || !owner.hasUnitState(UNIT_STAT_FOLLOW))
                owner.SetInFront(i_target.getTarget());
            i_target->GetPosition(i_targetX, i_targetY, i_targetZ);
        }

        if ((owner.IsStopped() && !i_destinationHolder.HasArrived()) || i_recalculateTravel)
        {
            i_recalculateTravel = false;
            //Angle update will take place into owner.StopMoving()
            owner.SetInFront(i_target.getTarget());

            owner.StopMoving();
            if (owner.IsWithinMeleeRange(i_target.getTarget()) && !owner.hasUnitState(UNIT_STAT_FOLLOW))
                owner.Attack(i_target.getTarget(),true);
        }
    }

    // Implemented for PetAI to handle resetting flags when pet owner reached
    if (i_destinationHolder.HasArrived())
        MovementInform(owner);

    return true;
}
bool ConfusedMovementGenerator<T>::Update(T &unit, const uint32 &diff)
{
    if(!&unit)
        return true;

    // ignore in case other no reaction state
    if (unit.hasUnitState(UNIT_STAT_CAN_NOT_REACT & ~UNIT_STAT_CONFUSED))
        return true;

    if (i_nextMoveTime.Passed())
    {
        // currently moving, update location
        unit.addUnitState(UNIT_STAT_CONFUSED_MOVE);
        Traveller<T> traveller(unit);
        if (i_destinationHolder.UpdateTraveller(traveller, diff, false))
        {
            if (!IsActive(unit))                            // force stop processing (movement can move out active zone with cleanup movegens list)
                return true;                                // not expire now, but already lost

            if (i_destinationHolder.HasArrived())
            {
                // arrived, stop and wait a bit
                unit.StopMoving();

                i_nextMoveTime.Reset(urand(800, 1500));
            }
        }
    }
    else
    {
        // waiting for next move
        i_nextMoveTime.Update(diff);
        if(i_nextMoveTime.Passed())
        {
            // start moving
            unit.addUnitState(UNIT_STAT_CONFUSED_MOVE);
            
            float x = i_x + 10.0f*(rand_norm_f() - 0.5f);
            float y = i_y + 10.0f*(rand_norm_f() - 0.5f);
            float z = i_z;

            unit.UpdateAllowedPositionZ(x, y, z);

            Traveller<T> traveller(unit);

            PathInfo path(&unit, x, y, z);
            if(!(path.getPathType() & PATHFIND_NORMAL))
            {
                i_nextMoveTime.Reset(urand(800, 1000));
                return true;
            }

            PointPath pointPath = path.getFullPath();

            float speed = traveller.Speed() * 0.001f; // in ms
            uint32 traveltime = uint32(pointPath.GetTotalLength() / speed);
            SplineFlags flags = (unit.GetTypeId() == TYPEID_UNIT) ? ((Creature*)&unit)->GetSplineFlags() : SPLINEFLAG_WALKMODE;
            unit.SendMonsterMoveByPath(pointPath, 1, std::min<uint32>(pointPath.size(), 5), flags, traveltime);

            PathNode p = pointPath[std::min<uint32>(pointPath.size()-1, 4)];
            // we do not really need it with mmaps active
            unit.UpdateAllowedPositionZ(p.x, p.y, p.z);
            i_destinationHolder.SetDestination(traveller, p.x, p.y, p.z, false);
        }
    }
    return true;
}
void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T &owner)
{
    if (!i_target.isValid() || !i_target->IsInWorld())
        return;

    if (owner.hasUnitState(UNIT_STAT_NOT_MOVE))
        return;

    float x, y, z;

    // prevent redundant micro-movement for pets, other followers.
    if (i_offset && i_target->IsWithinDistInMap(&owner,2*i_offset))
    {
        if (i_destinationHolder.HasDestination())
            return;

        owner.GetPosition(x, y, z);
    }
    else if (!i_offset)
    {
        // to nearest contact position
        i_target->GetContactPoint( &owner, x, y, z );
    }
    else
    {
        // to at i_offset distance from target and i_angle from target facing
        i_target->GetClosePoint(x, y, z, owner.GetObjectBoundingRadius(), i_offset, i_angle, &owner);
    }

    /*
        We MUST not check the distance difference and avoid setting the new location for smaller distances.
        By that we risk having far too many GetContactPoint() calls freezing the whole system.
        In TargetedMovementGenerator<T>::Update() we check the distance to the target and at
        some range we calculate a new position. The calculation takes some processor cycles due to vmaps.
        If the distance to the target it too large to ignore,
        but the distance to the new contact point is short enough to be ignored,
        we will calculate a new contact point each update loop, but will never move to it.
        The system will freeze.
        ralf

        //We don't update Mob Movement, if the difference between New destination and last destination is < BothObjectSize
        float  bothObjectSize = i_target->GetObjectBoundingRadius() + owner.GetObjectBoundingRadius() + CONTACT_DISTANCE;
        if( i_destinationHolder.HasDestination() && i_destinationHolder.GetDestinationDiff(x,y,z) < bothObjectSize )
            return;
    */

    //ACE_High_Res_Timer timer = ACE_High_Res_Timer();
    //ACE_hrtime_t elapsed;
    //timer.start();

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

    bool newPathCalculated = true;
    if(!i_path)
        i_path = new PathInfo(&owner, x, y, z, false, forceDest);
    else
        newPathCalculated = i_path->Update(x, y, z, false, forceDest);

    //timer.stop();
    //timer.elapsed_microseconds(elapsed);
    //sLog.outDebug("Path found in %llu microseconds", elapsed);

    // nothing we can do here ...
    if(i_path->getPathType() & PATHFIND_NOPATH)
        return;

    PointPath pointPath = i_path->getFullPath();

    if (i_destinationHolder.HasArrived() && m_pathPointsSent)
        --m_pathPointsSent;

    Traveller<T> traveller(owner);
    i_path->getNextPosition(x, y, z);
    i_destinationHolder.SetDestination(traveller, x, y, z, false);

    // send the path if:
    //    we have brand new path
    //    we have visited almost all of the previously sent points
    //    movespeed has changed
    //    the owner is stopped (caused by some movement effects)
    if (newPathCalculated || m_pathPointsSent < 2 || i_recalculateTravel || owner.IsStopped())
    {
        // send 10 nodes, or send all nodes if there are less than 10 left
        m_pathPointsSent = std::min<uint32>(10, pointPath.size() - 1);
        uint32 endIndex = m_pathPointsSent + 1;

        // dist to next node + world-unit length of the path
        x -= owner.GetPositionX();
        y -= owner.GetPositionY();
        z -= owner.GetPositionZ();
        float dist = sqrt(x*x + y*y + z*z) + pointPath.GetTotalLength(1, endIndex);

        // calculate travel time, set spline, then send path
        uint32 traveltime = uint32(dist / (traveller.Speed()*0.001f));
        SplineFlags flags = (owner.GetTypeId() == TYPEID_UNIT) ? ((Creature*)&owner)->GetSplineFlags() : SPLINEFLAG_WALKMODE;
        owner.SendMonsterMoveByPath(pointPath, 1, endIndex, flags, traveltime);
    }

    D::_addUnitStateMove(owner);
    if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->CanFly())
        ((Creature&)owner).AddSplineFlag(SPLINEFLAG_FLYING);
}
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;
    }

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

    if (i_path && (i_path->getPathType() & PATHFIND_NOPATH))
        return true;

    Traveller<T> traveller(owner);

    if (!i_destinationHolder.HasDestination())
        _setTargetLocation(owner);

    if (owner.IsStopped() && !i_destinationHolder.HasArrived())
    {
        D::_addUnitStateMove(owner);
        if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->CanFly())
            ((Creature&)owner).AddSplineFlag(SPLINEFLAG_FLYING);

        i_destinationHolder.StartTravel(traveller);
        return true;
    }

    if (i_destinationHolder.UpdateTraveller(traveller, time_diff, i_recalculateTravel || owner.IsStopped()))
    {
        if (!IsActive(owner))                               // force stop processing (movement can move out active zone with cleanup movegens list)
            return true;                                    // not expire now, but already lost

        // put targeted movement generators on a higher priority
        if (owner.GetObjectBoundingRadius())
            i_destinationHolder.ResetUpdate(100);

        //More distance let have better performance, less distance let have more sensitive reaction at target move.
        float dist = i_target->GetObjectBoundingRadius() + owner.GetObjectBoundingRadius() + sWorld.getConfig(CONFIG_FLOAT_RATE_TARGET_POS_RECALCULATION_RANGE);

        float x,y,z;
        i_target->GetPosition(x, y, z);
        PathNode next_point(x, y, z);

        bool targetMoved = false, needNewDest = false;
        if (i_path)
        {
            PathNode end_point = i_path->getEndPosition();
            next_point = i_path->getNextPosition();

            needNewDest = i_destinationHolder.HasArrived() && !inRange(next_point, i_path->getActualEndPosition(), dist, dist);

            // GetClosePoint() will always return a point on the ground, so we need to
            // handle the difference in elevation when the creature is flying
            if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->CanFly())
                targetMoved = i_target->GetDistanceSqr(end_point.x, end_point.y, end_point.z) >= dist*dist;
            else
                targetMoved = i_target->GetDistance2d(end_point.x, end_point.y) >= dist;
        }

        if (!i_path || targetMoved || needNewDest || i_recalculateTravel || owner.IsStopped())
        {
            // (re)calculate path
            _setTargetLocation(owner);

            next_point = i_path->getNextPosition();

            // Set new Angle For Map::
            owner.SetOrientation(owner.GetAngle(next_point.x, next_point.y));
        }
        // Update the Angle of the target only for Map::, no need to send packet for player
        else if (!i_angle && !owner.HasInArc(0.01f, next_point.x, next_point.y))
            owner.SetOrientation(owner.GetAngle(next_point.x, next_point.y));

        if ((owner.IsStopped() && !i_destinationHolder.HasArrived()) || i_recalculateTravel)
        {
            i_recalculateTravel = false;

            //Angle update will take place into owner.StopMoving()
            owner.SetOrientation(owner.GetAngle(next_point.x, next_point.y));

            owner.StopMoving();
            static_cast<D*>(this)->_reachTarget(owner);
        }
    }
    return true;
}
Example #14
0
void
RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
{
    float X,Y,Z,z,nx,ny,nz,wander_distance,ori,dist;

    creature.GetRespawnCoord(X, Y, Z, &ori, &wander_distance);

    z = creature.GetPositionZ();
    Map const* map = creature.GetBaseMap();

    // For 2D/3D system selection
    //bool is_land_ok  = creature.canWalk();                // not used?
    //bool is_water_ok = creature.canSwim();                // not used?
    bool is_air_ok   = creature.canFly();

    const float angle = rand_norm_f()*(M_PI_F*2.0f);
    const float range = rand_norm_f()*wander_distance;
    const float distanceX = range * cos(angle);
    const float distanceY = range * sin(angle);

    nx = X + distanceX;
    ny = Y + distanceY;

    // prevent invalid coordinates generation
    MaNGOS::NormalizeMapCoord(nx);
    MaNGOS::NormalizeMapCoord(ny);

    dist = distanceX*distanceX + distanceY*distanceY;

    if (is_air_ok)                                          // 3D system above ground and above water (flying mode)
    {
        // Limit height change
        const float distanceZ = rand_norm_f() * sqrtf(dist)/2.0f;
        nz = Z + distanceZ;
        float tz = map->GetHeight(nx, ny, nz-2.0f, false);  // Map check only, vmap needed here but need to alter vmaps checks for height.
        float wz = map->GetWaterLevel(nx, ny);

        // Problem here, we must fly above the ground and water, not under. Let's try on next tick
        if (tz >= nz || wz >= nz)
            return;
    }
    //else if (is_water_ok)                                 // 3D system under water and above ground (swimming mode)
    else                                                    // 2D only
    {
        nz = Z;
        if (!map->IsNextZcoordOK(nx, ny, nz, dist))
            return;                                         // let's forget this bad coords where a z cannot be find and retry at next tick
        creature.UpdateGroundPositionZ(nx, ny, nz, dist);
    }

    Traveller<Creature> traveller(creature);

    creature.SetOrientation(creature.GetAngle(nx, ny));
    i_destinationHolder.SetDestination(traveller, nx, ny, nz);
    creature.addUnitState(UNIT_STAT_ROAMING_MOVE);

    if (is_air_ok && !(creature.canWalk() && creature.IsAtGroundLevel(nx, ny, nz)))
    {
        i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
        creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7);
    }
    //else if (is_water_ok)                                 // Swimming mode to be done with more than this check
    else
    {
        i_nextMoveTime.Reset(urand(500+i_destinationHolder.GetTotalTravelTime(), 10000+i_destinationHolder.GetTotalTravelTime()));
        creature.AddSplineFlag(SPLINEFLAG_WALKMODE);
    }
}
bool
WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff)
{
    if(!&creature)
        return true;

    // Waypoint movement can be switched on/off
    // This is quite handy for escort quests and other stuff

    if(creature.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED))
        return true;

    // prevent crash at empty waypoint path.
    if(i_path.Empty())
    {
        return true;
    }

    CreatureTraveller traveller(creature);

    /*
    if( npcIsStopped[creature.GetGUID()] )
    {
        i_nextMoveTime.Update(40000);
        i_destinationHolder.UpdateTraveller(traveller, ((diff)-40000), false);
        npcIsStopped[creature.GetGUID()] = false;
        return true;
    }
    */
    i_nextMoveTime.Update(diff);
    i_destinationHolder.UpdateTraveller(traveller, diff, false);

    if( creature.IsStopped() )
    {
        uint32 wpB = i_currentNode > 0 ? i_currentNode-1 : i_wpBehaviour.size()-1;

        if( i_wpBehaviour[wpB] != NULL )
        {
            struct WaypointBehavior *tmpBehavior = i_wpBehaviour[wpB];

            if (!tmpBehavior->HasDone)
            {
                if(tmpBehavior->emote != 0)
                {
                    creature.SetUInt32Value(UNIT_NPC_EMOTESTATE,tmpBehavior->emote);
                }
                if(tmpBehavior->aiscript != "")
                {
                    WPAIScript(creature, tmpBehavior->aiscript);
                }
                //sLog.outDebug("DEBUG: tmpBehavior->text[0] TEST");
                if(tmpBehavior->text[0] != "")
                {
                    //sLog.outDebug("DEBUG: tmpBehavior->text[0] != \"\"");
                    // Only one text is set
                    if( tmpBehavior->text[1] == "" )
                    {
                        //sLog.outDebug("DEBUG: tmpBehavior->text[1] == NULL");
                        creature.Say(tmpBehavior->text[0].c_str(), 0, 0);
                    }
                    else
                    {
                        // Select one from max 5 texts
                        for( int i = 0; i < 4; ++i )
                        {
                            if( tmpBehavior->text[i] == "" )
                            {
                                //sLog.outDebug("DEBUG: tmpBehavior->text[i] == \"\": %d", i);
                                //sLog.outDebug("DEBUG: rand() % (i): %d", rand() % (i));

                                creature.Say(tmpBehavior->text[rand() % i].c_str(), 0, 0);
                                break;
                            }
                        }
                    }
                }
                if(tmpBehavior->spell != 0)
                {
                    //sLog.outDebug("DEBUG: wpSys - spell");
                    creature.CastSpell(&creature,tmpBehavior->spell, false);
                }
                if (tmpBehavior->orientation !=100)
                {
                    //sLog.outDebug("DEBUG: wpSys - orientation");
                    creature.SetOrientation(tmpBehavior->orientation);
                }
                if(tmpBehavior->model1 != 0)
                {
                    //sLog.outDebug("DEBUG: wpSys - model1");
                    creature.SetUInt32Value(UNIT_FIELD_DISPLAYID, tmpBehavior->model1);
                }
                tmpBehavior->HasDone = true;
            }                                               // HasDone == false
        }                                                   // wpBehaviour found
    }                                                       // i_creature.IsStopped()

    if( i_nextMoveTime.Passed() )
    {
        if( creature.IsStopped() )
        {
            assert( i_currentNode < i_path.Size() );
            creature.addUnitState(UNIT_STAT_ROAMING);
            const Path::PathNode &node(i_path(i_currentNode));
            i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z);
            i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
            uint32 wpB = i_currentNode > 0 ? i_currentNode-1 : i_wpBehaviour.size()-1;

            if( i_wpBehaviour[wpB] != NULL )
            {
                struct WaypointBehavior *tmpBehavior = i_wpBehaviour[wpB];
                tmpBehavior->HasDone = false;
                if(tmpBehavior->model2 != 0)
                {
                    creature.SetUInt32Value(UNIT_FIELD_DISPLAYID, tmpBehavior->model2);
                }
                if (tmpBehavior->orientation !=100)
                {
                    creature.SetOrientation(tmpBehavior->orientation);
                }
                creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
            }
        }
        else
        {
            creature.StopMoving();
            i_nextMoveTime.Reset(i_delays[i_currentNode]);
            ++i_currentNode;
            if( i_currentNode >= i_path.Size() )
                i_currentNode = 0;
        }
    }
    return true;
}
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;
    }

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

    Traveller<T> traveller(owner);

    if (!i_destinationHolder.HasDestination())
        _setTargetLocation(owner);
    if (owner.IsStopped() && !i_destinationHolder.HasArrived())
    {
        D::_addUnitStateMove(owner);
        if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->canFly())
            ((Creature&)owner).AddSplineFlag(SPLINEFLAG_UNKNOWN7);

        i_destinationHolder.StartTravel(traveller);
        return true;
    }

    if (i_destinationHolder.UpdateTraveller(traveller, time_diff, false))
    {
        if (!IsActive(owner))                               // force stop processing (movement can move out active zone with cleanup movegens list)
            return true;                                    // not expire now, but already lost

        // put targeted movement generators on a higher priority
        if (owner.GetObjectBoundingRadius())
            i_destinationHolder.ResetUpdate(50);

        float dist = i_target->GetObjectBoundingRadius() + owner.GetObjectBoundingRadius() + sWorld.getConfig(CONFIG_FLOAT_RATE_TARGET_POS_RECALCULATION_RANGE);

        //More distance let have better performance, less distance let have more sensitive reaction at target move.

        // try to counter precision differences
        if (i_destinationHolder.GetDistance3dFromDestSq(*i_target.getTarget()) >= dist * dist)
        {
            owner.SetInFront(i_target.getTarget());         // Set new Angle For Map::
            _setTargetLocation(owner);                      //Calculate New Dest and Send data To Player
        }
        // Update the Angle of the target only for Map::, no need to send packet for player
        else if (!i_angle && !owner.HasInArc(0.01f, i_target.getTarget()))
            owner.SetInFront(i_target.getTarget());

        if ((owner.IsStopped() && !i_destinationHolder.HasArrived()) || i_recalculateTravel)
        {
            i_recalculateTravel = false;
            //Angle update will take place into owner.StopMoving()
            owner.SetInFront(i_target.getTarget());

            owner.StopMoving();
            static_cast<D*>(this)->_reachTarget(owner);
        }
    }
    return true;
}
void
RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
{
    float respX, respY, respZ, respO, currZ, destX, destY, destZ, wander_distance, travelDistZ;

    creature.GetRespawnCoord(respX, respY, respZ, &respO, &wander_distance);

    currZ = creature.GetPositionZ();
    TerrainInfo const* map = creature.GetTerrain();

    // For 2D/3D system selection
    //bool is_land_ok  = creature.CanWalk();                // not used?
    //bool is_water_ok = creature.CanSwim();                // not used?
    bool is_air_ok = creature.CanFly();

    const float angle = rand_norm_f() * (M_PI_F*2.0f);
    const float range = rand_norm_f() * wander_distance;
    const float distanceX = range * cos(angle);
    const float distanceY = range * sin(angle);

    destX = respX + distanceX;
    destY = respY + distanceY;

    // prevent invalid coordinates generation
    MaNGOS::NormalizeMapCoord(destX);
    MaNGOS::NormalizeMapCoord(destY);

    travelDistZ = distanceX*distanceX + distanceY*distanceY;

    if (is_air_ok)                                          // 3D system above ground and above water (flying mode)
    {
        // Limit height change
        const float distanceZ = rand_norm_f() * sqrtf(travelDistZ)/2.0f;
        destZ = respZ + distanceZ;
        float levelZ = map->GetWaterOrGroundLevel(destX, destY, destZ-2.0f);

        // Problem here, we must fly above the ground and water, not under. Let's try on next tick
        if (levelZ >= destZ)
            return;
    }
    //else if (is_water_ok)                                 // 3D system under water and above ground (swimming mode)
    else                                                    // 2D only
    {
        // 10.0 is the max that vmap high can check (MAX_CAN_FALL_DISTANCE)
        travelDistZ = travelDistZ >= 100.0f ? 10.0f : sqrtf(travelDistZ);

        // The fastest way to get an accurate result 90% of the time.
        // Better result can be obtained like 99% accuracy with a ray light, but the cost is too high and the code is too long.
        destZ = map->GetHeight(destX, destY, respZ+travelDistZ-2.0f, false);

        if (fabs(destZ - respZ) > travelDistZ)              // Map check
        {
            // Vmap Horizontal or above
            destZ = map->GetHeight(destX, destY, respZ - 2.0f, true);

            if (fabs(destZ - respZ) > travelDistZ)
            {
                // Vmap Higher
                destZ = map->GetHeight(destX, destY, respZ+travelDistZ-2.0f, true);

                // let's forget this bad coords where a z cannot be find and retry at next tick
                if (fabs(destZ - respZ) > travelDistZ)
                    return;
            }
        }
    }

    Traveller<Creature> traveller(creature);

    creature.SetOrientation(creature.GetAngle(destX, destY));
    i_destinationHolder.SetDestination(traveller, destX, destY, destZ);
    creature.addUnitState(UNIT_STAT_ROAMING_MOVE);

    if (is_air_ok)
    {
        i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
        creature.AddSplineFlag(SPLINEFLAG_FLYING);
    }
    //else if (is_water_ok)                                 // Swimming mode to be done with more than this check
    else
    {
        i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime() + urand(500, 10000));
        creature.AddSplineFlag(SPLINEFLAG_WALKMODE);
    }
}
bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff)
{
    if(!&creature)
        return true;

    // Waypoint movement can be switched on/off
    // This is quite handy for escort quests and other stuff
    if(creature.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
        return true;

    // prevent a crash at empty waypoint path.
    if(!i_path || i_path->empty())
        return true;

    // i_path was modified by chat commands for example
    if(i_path->size() != i_hasDone.size())
        i_hasDone.resize(i_path->size());
    if(i_currentNode >= i_path->size())
        i_currentNode = 0;

    CreatureTraveller traveller(creature);

    i_nextMoveTime.Update(diff);
    i_destinationHolder.UpdateTraveller(traveller, diff, false, true);

    // creature has been stopped in middle of the waypoint segment
    if (!i_destinationHolder.HasArrived() && creature.IsStopped())
    {
        if( i_nextMoveTime.Passed()) // Timer has elapsed, meaning this part controlled it
        {
            SetStopedByPlayer(false);
            // Now we re-set destination to same node and start travel
            creature.addUnitState(UNIT_STAT_ROAMING);
            if (creature.canFly())
                creature.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2);
            const WaypointNode &node = i_path->at(i_currentNode);
            i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z);
            i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
        }
        else // if( !i_nextMoveTime.Passed())
        {   // unexpected end of timer && creature stopped && not at end of segment
            if (!IsStopedByPlayer())
            {   // Put 30 seconds delay
                i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER);
                i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER);
                SetStopedByPlayer(true);                        // Mark we did it
            }
        }
        return true;    // Abort here this update
    }

    if( creature.IsStopped())
    {
        uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1;

        if (!i_hasDone[idx])
        {
            if (i_path->at(idx).orientation !=100)
                creature.SetOrientation(i_path->at(idx).orientation);

            if(WaypointBehavior *behavior = i_path->at(idx).behavior)
            {
                if(behavior->emote != 0)
                    creature.SetUInt32Value(UNIT_NPC_EMOTESTATE,behavior->emote);
                if(behavior->spell != 0)
                    creature.CastSpell(&creature,behavior->spell, false);
                if(behavior->model1 != 0)
                    creature.SetDisplayId(behavior->model1);
                if(behavior->textid[0])
                {
                    // Not only one text is set
                    if( behavior->textid[1] )
                    {
                        // Select one from max 5 texts (0 and 1 laready checked)
                        int i = 2;
                        for( ; i < MAX_WAYPOINT_TEXT; ++i )
                            if( !behavior->textid[i] )
                                break;

                        creature.Say(behavior->textid[rand() % i], 0, 0);
                    }
                    else
                        creature.Say(behavior->textid[0], 0, 0);
                }

                i_hasDone[idx] = true;
                MovementInform(creature);
            }                                               // wpBehaviour found
        }                                                   // HasDone == false
    }                                                       // i_creature.IsStopped()

    if( i_nextMoveTime.Passed() ) // This is at the end of waypoint segment or has been stopped by player
    {
        if( creature.IsStopped() ) // If stopped then begin a new move segment
        {
            creature.addUnitState(UNIT_STAT_ROAMING);
            if (creature.canFly())
                creature.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2);
            const WaypointNode &node = i_path->at(i_currentNode);
            i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z);
            i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
            uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1;

            if (i_path->at(idx).orientation !=100)
                creature.SetOrientation(i_path->at(idx).orientation);

            if(WaypointBehavior *behavior = i_path->at(idx).behavior )
            {
                i_hasDone[idx] = false;
                if(behavior->model2 != 0)
                    creature.SetDisplayId(behavior->model2);

                creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
            }
        }
        else // If not stopped then stop it and set the reset of TimeTracker to waittime
        {
            creature.StopMoving();
            SetStopedByPlayer(false);
            i_nextMoveTime.Reset(i_path->at(i_currentNode).delay);
            ++i_currentNode;
            if( i_currentNode >= i_path->size() )
                i_currentNode = 0;
        }
    }
    return true;
}
bool
TargetedMovementGenerator<T>::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_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_DISTRACTED | UNIT_STAT_DIED))
        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 (!owner.hasUnitState(UNIT_STAT_FOLLOW) && owner.getVictim() != i_target.getTarget())
        return true;

    Traveller<T> traveller(owner);

    if (!i_destinationHolder.HasDestination())
        _setTargetLocation(owner);
    if (owner.IsStopped() && !i_destinationHolder.HasArrived())
    {
        owner.addUnitState(UNIT_STAT_CHASE);
        if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->canFly())
            ((Creature&)owner).AddMonsterMoveFlag(MONSTER_MOVE_FLY);

        i_destinationHolder.StartTravel(traveller);
        return true;
    }

    if (i_destinationHolder.UpdateTraveller(traveller, time_diff, false))
    {
        // put targeted movement generators on a higher priority
        if (owner.GetObjectSize())
            i_destinationHolder.ResetUpdate(50);

        float dist = i_target->GetObjectSize() + owner.GetObjectSize() + sWorld.getRate(RATE_TARGET_POS_RECALCULATION_RANGE);

        //More distance let have better performance, less distance let have more sensitive reaction at target move.

        // try to counter precision differences
        if (i_destinationHolder.GetDistance3dFromDestSq(*i_target.getTarget()) >= dist * dist)
        {
            owner.SetInFront(i_target.getTarget());         // Set new Angle For Map::
            _setTargetLocation(owner);                      //Calculate New Dest and Send data To Player
        }
        // Update the Angle of the target only for Map::, no need to send packet for player
        else if (!i_angle && !owner.HasInArc(0.01f, i_target.getTarget()))
            owner.SetInFront(i_target.getTarget());

        if ((owner.IsStopped() && !i_destinationHolder.HasArrived()) || i_recalculateTravel)
        {
            i_recalculateTravel = false;
            //Angle update will take place into owner.StopMoving()
            owner.SetInFront(i_target.getTarget());

            owner.StopMoving();
            if(owner.canReachWithAttack(i_target.getTarget()) && !owner.hasUnitState(UNIT_STAT_FOLLOW))
                owner.Attack(i_target.getTarget(),true);
        }
    }
    return true;
}
bool
TargetedMovementGenerator<T>::_setTargetLocation(T &owner)
{
    if (!i_target.isValid() || !i_target->IsInWorld())
        return false;

    if (owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
        return false;

    float x, y, z;
    Traveller<T> traveller(owner);
    if (i_destinationHolder.HasDestination())
    {
        if (i_destinationHolder.HasArrived())
        {
            // prevent redundant micro-movement
            if (!i_offset)
            {
                if (i_target->IsWithinMeleeRange(&owner))
                    return false;
            }
            else if (!i_angle && !owner.hasUnitState(UNIT_STAT_FOLLOW))
            {
                if (i_target->IsWithinDistInMap(&owner, i_offset))
                    return false;
            }
            else
            {
                if (i_target->IsWithinDistInMap(&owner, i_offset + 1.0f))
                    return false;
            }
        }
        else
        {
            bool stop = false;
            if (!i_offset)
            {
                if (i_target->IsWithinMeleeRange(&owner, 0))
                    stop = true;
            }
            else if (!i_angle && !owner.hasUnitState(UNIT_STAT_FOLLOW))
            {
                if (i_target->IsWithinDist(&owner, i_offset * 0.8f))
                    stop = true;
            }

            if (stop)
            {
                owner.GetPosition(x, y, z);
                i_destinationHolder.SetDestination(traveller, x, y, z);
                i_destinationHolder.StartTravel(traveller, false);
                owner.StopMoving();
                return false;
            }
        }

        if (i_target->GetExactDistSq(i_targetX, i_targetY, i_targetZ) < 0.01f)
            return false;
    }

    if (!i_offset)
    {
        // to nearest random contact position
        i_target->GetRandomContactPoint(&owner, x, y, z, 0, MELEE_RANGE - 0.5f);
    }
    else if (!i_angle && !owner.hasUnitState(UNIT_STAT_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);
    }

    /*
        We MUST not check the distance difference and avoid setting the new location for smaller distances.
        By that we risk having far too many GetContactPoint() calls freezing the whole system.
        In TargetedMovementGenerator<T>::Update() we check the distance to the target and at
        some range we calculate a new position. The calculation takes some processor cycles due to vmaps.
        If the distance to the target it too large to ignore,
        but the distance to the new contact point is short enough to be ignored,
        we will calculate a new contact point each update loop, but will never move to it.
        The system will freeze.
        ralf

        //We don't update Mob Movement, if the difference between New destination and last destination is < BothObjectSize
        float  bothObjectSize = i_target->GetObjectSize() + owner.GetObjectSize() + CONTACT_DISTANCE;
        if (i_destinationHolder.HasDestination() && i_destinationHolder.GetDestinationDiff(x,y,z) < bothObjectSize)
            return;
    */
    i_destinationHolder.SetDestination(traveller, x, y, z);
    owner.addUnitState(UNIT_STAT_CHASE);
    i_destinationHolder.StartTravel(traveller);
    return true;
}
bool TargetedMovementGenerator<T>::Update(T &owner, const uint32 & time_diff)
{
    if (!i_target.isValid() || !i_target->IsInWorld())
        return false;

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

    if (owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_DISTRACTED))
        return true;

    // prevent movement while casting spells with cast time or channel time
    if (owner.IsNonMeleeSpellCasted(false, false,  true) || owner.hasUnitState(UNIT_STAT_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_STAT_FOLLOW) && owner.getVictim() != i_target.getTarget())
        return true;

    if (m_usePathfinding)
    {
        if (i_path && (i_path->getPathType() & PATHFIND_NOPATH))
            return true;

        Traveller<T> traveller(owner);

        if (!i_destinationHolder.HasDestination())
            _setTargetLocation(owner);

        if (i_destinationHolder.UpdateTraveller(traveller, time_diff, i_recalculateTravel || owner.IsStopped()))
        {
            // put targeted movement generators on a higher priority
            if (owner.GetCombatReach())
                i_destinationHolder.ResetUpdate(100);

            float x,y,z;
            i_target->GetPosition(x, y, z);
            PathNode next_point(x, y, z);

            bool targetMoved = false, needNewDest = false;
            bool forceRecalc = i_recalculateTravel || owner.IsStopped();
            if (i_path && !forceRecalc)
            {
                PathNode end_point = i_path->getEndPosition();
                next_point = i_path->getNextPosition();

                //More distance let have better performance, less distance let have more sensitive reaction at target move.
                float dist = owner.GetCombatReach() + sWorld.getRate(RATE_TARGET_POS_RECALCULATION_RANGE);

                needNewDest = i_destinationHolder.HasArrived() && (!i_path->inRange(next_point, i_path->getActualEndPosition(), dist, dist) || !owner.IsWithinLOSInMap(i_target.getTarget()));

                if(!needNewDest)
                {
                    // GetClosePoint() will always return a point on the ground, so we need to
                    // handle the difference in elevation when the creature is flying
                    if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->canFly())
                        targetMoved = i_target->GetDistanceSqr(end_point.x, end_point.y, end_point.z) > dist*dist;
                    else
                        targetMoved = i_target->GetDistance2d(end_point.x, end_point.y) > dist;
                }
            }

            // target moved
            if (!i_path || targetMoved || needNewDest || forceRecalc)
            {
                // (re)calculate path
                _setTargetLocation(owner);

                next_point = i_path->getNextPosition();

                // Set new Angle For Map::
                owner.SetOrientation(owner.GetAngle(next_point.x, next_point.y));
            }
            // Update the Angle of the target only for Map::, no need to send packet for player
            else if (!i_angle && !owner.HasInArc(0.01f, next_point.x, next_point.y))
                owner.SetOrientation(owner.GetAngle(next_point.x, next_point.y));

            if ((owner.IsStopped() && !i_destinationHolder.HasArrived()) || i_recalculateTravel)
            {
                i_recalculateTravel = false;
                //Angle update will take place into owner.StopMoving()
                owner.SetInFront(i_target.getTarget());

                owner.StopMoving();
                if(owner.IsWithinMeleeRange(i_target.getTarget()) && !owner.hasUnitState(UNIT_STAT_FOLLOW))
                    owner.Attack(i_target.getTarget(), true);
            }
        }
    }

    else
    {
        Traveller<T> traveller(owner);

        if (!i_destinationHolder.HasDestination())
        {
            _setTargetLocation(owner);
        }
        else if (owner.IsStopped() && !i_destinationHolder.HasArrived())
        {
            owner.addUnitState(UNIT_STAT_CHASE);
            i_destinationHolder.StartTravel(traveller);
            return true;
        }

        if (i_destinationHolder.UpdateTraveller(traveller, time_diff))
        {
            // target moved
            if (i_targetX != i_target->GetPositionX() || i_targetY != i_target->GetPositionY()
                    || i_targetZ != i_target->GetPositionZ())
            {
                if(_setTargetLocation(owner) || !owner.hasUnitState(UNIT_STAT_FOLLOW))
                    owner.SetInFront(i_target.getTarget());
                i_target->GetPosition(i_targetX, i_targetY, i_targetZ);
            }

            if ((owner.IsStopped() && !i_destinationHolder.HasArrived()) || i_recalculateTravel)
            {
                i_recalculateTravel = false;
                //Angle update will take place into owner.StopMoving()
                owner.SetInFront(i_target.getTarget());

                owner.StopMoving();
                if(owner.IsWithinMeleeRange(i_target.getTarget()) && !owner.hasUnitState(UNIT_STAT_FOLLOW))
                    owner.Attack(i_target.getTarget(),true);
            }
        }
    }

    // Implemented for PetAI to handle resetting flags when pet owner reached
    if (i_destinationHolder.HasArrived())
        MovementInform(owner);

    return true;
}
bool
WaypointMovementGenerator<Creature>::Update(Creature &unit, const uint32 &diff)
{
    if (!&unit)
        return true;

    if (!path_id)
        return false;

    // Waypoint movement can be switched on/off
    // This is quite handy for escort quests and other stuff
    if (unit.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
        return true;

    // Clear the generator if the path doesn't exist
    if (!waypoints || !waypoints->size())
        return false;

    Traveller<Creature> traveller(unit);

    i_nextMoveTime.Update(diff);
    i_destinationHolder.UpdateTraveller(traveller, diff, true);

    if (i_nextMoveTime.GetExpiry() < TIMEDIFF_NEXT_WP)
    {
        if (unit.IsStopped())
        {
            if (StopedByPlayer)
            {
                ASSERT(node);
                InitTraveller(unit, *node);
                i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z);
                i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
                StopedByPlayer = false;
                return true;
            }

            if (i_currentNode == waypoints->size() - 1) // If that's our last waypoint
            {
                if (repeating)         // If the movement is repeating
                    i_currentNode = 0; // Start moving all over again
                else
                {
                    unit.SetHomePosition(node->x, node->y, node->z, unit.GetOrientation());
                    unit.GetMotionMaster()->Initialize();
                    return false; // Clear the waypoint movement
                }
            }
            else
                ++i_currentNode;

            node = waypoints->at(i_currentNode);
            InitTraveller(unit, *node);
            i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z);
            i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());

            //Call for creature group update
            if (unit.GetFormation() && unit.GetFormation()->getLeader() == &unit)
                unit.GetFormation()->LeaderMoveTo(node->x, node->y, node->z);
        }
        else
        {
            //Determine waittime
            if (node->delay)
                i_nextMoveTime.Reset(node->delay);

            //note: disable "start" for mtmap
            if (node->event_id && urand(0,99) < node->event_chance)
                unit.GetMap()->ScriptsStart(sWaypointScripts, node->event_id, &unit, NULL/*, false*/);

            i_destinationHolder.ResetTravelTime();
            MovementInform(unit);
            unit.UpdateWaypointID(i_currentNode);
            unit.ClearUnitState(UNIT_STAT_ROAMING);
            unit.Relocate(node->x, node->y, node->z);
        }
    }
    else
    {
        if (unit.IsStopped() && !i_destinationHolder.HasArrived())
        {
            if (!StopedByPlayer)
            {
                i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER);
                i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER);
                StopedByPlayer = true;
            }
        }
    }
    return true;
}
bool
TargetedMovementGenerator::Update(Creature &owner, const uint32 & time_diff)
{
    if( !&owner || !owner.isAlive() || !&i_target )
        return true;
    if( owner.hasUnitState(UNIT_STAT_ROOT) || owner.hasUnitState(UNIT_STAT_STUNDED) || owner.hasUnitState(UNIT_STAT_FLEEING))
        return true;
    if( !owner.isInCombat() && !owner.hasUnitState(UNIT_STAT_FOLLOW) )
    {
        //owner.AIM_Initialize();   This case must be the one, when a creature aggroed you. By Initalized a new AI, we prevented to Ai::_stopAttack() to be executed properly.
        return true;
    }

    // prevent crash after creature killed pet
    if (!owner.hasUnitState(UNIT_STAT_FOLLOW) && owner.getVictim() != &i_target)
        return true;

    Traveller<Creature> traveller(owner);

    if (i_destinationHolder.UpdateTraveller(traveller, time_diff, false))
    {
        // put targeted movement generators on a higher priority
        if (owner.GetObjectSize())
            i_destinationHolder.ResetUpdate(50);

        float  dist = i_target.GetObjectSize() + owner.GetObjectSize() + OBJECT_CONTACT_DISTANCE;

        // try to counter precision differences
        if( i_destinationHolder.GetDistanceFromDestSq(i_target) > dist * dist + 0.1)
            _setTargetLocation(owner, 0);
        else if ( !owner.HasInArc( 0.1f, &i_target ) )
        {
            owner.SetInFront(&i_target);
            if( i_target.GetTypeId() == TYPEID_PLAYER )
                owner.SendUpdateToPlayer( (Player*)&i_target );
        }
        if( !owner.IsStopped() && i_destinationHolder.HasArrived())
        {
            owner.StopMoving();
            if(owner.canReachWithAttack(&i_target) && !owner.hasUnitState(UNIT_STAT_FOLLOW))
                owner.Attack(&i_target);
        }
    }
    /*

         //SpellEntry* spellInfo;
        if( reach )
        {
            if( owner.GetDistance2dSq( &i_target ) > 0.0f )
            {
                DEBUG_LOG("MOVEMENT : Distance = %f",owner.GetDistance2dSq( &i_target ));
                owner.addUnitState(UNIT_STAT_CHASE);
                _setTargetLocation(owner, 0);
            }
            else if ( !owner.HasInArc( 0.0f, &i_target ) )
            {
                DEBUG_LOG("MOVEMENT : Orientation = %f",owner.GetAngle(&i_target));
                owner.SetInFront(&i_target);
                if( i_target.GetTypeId() == TYPEID_PLAYER )
                    owner.SendUpdateToPlayer( (Player*)&i_target );
            }
            if( !owner.isInCombat() )
            {
                owner.AIM_Initialize();
                return;
            }
        }
        else if( i_target.isAlive() )
        {
            if( !owner.hasUnitState(UNIT_STAT_FOLLOW) && owner.isInCombat() )
            {
                if( spellInfo = owner.reachWithSpellAttack( &i_target ) )
                {
                    _spellAtack(owner, spellInfo);
                    return;
                }
            }
            if( owner.GetDistance2dSq( &i_target ) > 0.0f )
            {
                DEBUG_LOG("MOVEMENT : Distance = %f",owner.GetDistance2dSq( &i_target ));
                owner.addUnitState(UNIT_STAT_CHASE);
                _setTargetLocation(owner, 0);
            }
        }
        else if( !i_targetedHome )
        {
            if( !owner.hasUnitState(UNIT_STAT_FOLLOW) && owner.isInCombat() && (spellInfo = owner.reachWithSpellAttack(&i_target)) )
            {
                _spellAtack(owner, spellInfo);
                return;
            }
            _setTargetLocation(owner, 0);
            if(reach)
            {
                if( reach && owner.canReachWithAttack(&i_target) )
                {
                    owner.StopMoving();
                    if(!owner.hasUnitState(UNIT_STAT_FOLLOW))
                        owner.Attack(&i_target);
                    owner.clearUnitState(UNIT_STAT_CHASE);
                    DEBUG_LOG("UNIT IS THERE");
                }
                else
                {
                    _setTargetLocation(owner, 0);
                    DEBUG_LOG("Continue to chase");
                }
            }
        }*/
    return true;
}
void PointMovementGenerator<T>::Initialize(T &unit)
{
    unit.StopMoving();
    Traveller<T> traveller(unit);
    i_destinationHolder.SetDestination(traveller,x,y,z);
}
Example #25
0
void
RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
{
    float X,Y,Z,z,nx,ny,nz,wander_distance,ori,dist;

    creature.GetRespawnCoord(X, Y, Z, &ori, &wander_distance);

    z = creature.GetPositionZ();
    uint32 mapid=creature.GetMapId();
    Map const* map = MapManager::Instance().GetBaseMap(mapid);

    // For 2D/3D system selection
    //bool is_land_ok  = creature.canWalk();                // not used?
    //bool is_water_ok = creature.canSwim();                // not used?
    bool is_air_ok   = creature.canFly();

    const float angle = rand_norm()*(M_PI*2);
    const float range = rand_norm()*wander_distance;
    const float distanceX = range * cos(angle);
    const float distanceY = range * sin(angle);

    nx = X + distanceX;
    ny = Y + distanceY;

    // prevent invalid coordinates generation
    MaNGOS::NormalizeMapCoord(nx);
    MaNGOS::NormalizeMapCoord(ny);

    dist = distanceX*distanceX + distanceY*distanceY;

    if (is_air_ok) // 3D system above ground and above water (flying mode)
    {
        const float distanceZ = rand_norm() * sqrtf(dist)/2; // Limit height change
        nz = Z + distanceZ;
        float tz = map->GetHeight(nx, ny, nz-2.0f, false); // Map check only, vmap needed here but need to alter vmaps checks for height.
        float wz = map->GetWaterLevel(nx, ny);
        if (tz >= nz || wz >= nz)
            return; // Problem here, we must fly above the ground and water, not under. Let's try on next tick
    }
    //else if (is_water_ok) // 3D system under water and above ground (swimming mode)
    else // 2D only
    {
        dist = dist>=100.0f ? 10.0f : sqrtf(dist); // 10.0 is the max that vmap high can check (MAX_CAN_FALL_DISTANCE)
        // The fastest way to get an accurate result 90% of the time.
        // Better result can be obtained like 99% accuracy with a ray light, but the cost is too high and the code is too long.
        nz = map->GetHeight(nx,ny,Z+dist-2.0f,false); // Map check
        if (fabs(nz-Z)>dist)
        {
            nz = map->GetHeight(nx,ny,Z-2.0f,true); // Vmap Horizontal or above
            if (fabs(nz-Z)>dist)
            {
                nz = map->GetHeight(nx,ny,Z+dist-2.0f,true); // Vmap Higher
                if (fabs(nz-Z)>dist)
                    return; // let's forget this bad coords where a z cannot be find and retry at next tick
            }
        }
    }

    Traveller<Creature> traveller(creature);
    creature.SetOrientation(creature.GetAngle(nx,ny));
    i_destinationHolder.SetDestination(traveller, nx, ny, nz);
    creature.addUnitState(UNIT_STAT_ROAMING);
    if (is_air_ok)
    {
        i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
        creature.AddUnitMovementFlag(MONSTER_MOVE_FLY);
    }
    //else if (is_water_ok) // Swimming mode to be done with more than this check
    else
    {
        i_nextMoveTime.Reset(urand(500+i_destinationHolder.GetTotalTravelTime(),5000+i_destinationHolder.GetTotalTravelTime()));
        creature.SetUnitMovementFlags(MONSTER_MOVE_WALK);
    }
}
bool TargetedMovementGenerator<T>::_setTargetLocation(T &owner)
{
    if (!i_target.isValid() || !i_target->IsInWorld())
        return false;

    if (owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
        return false;

    float x, y, z;
    Traveller<T> traveller(owner);
    if (i_destinationHolder.HasDestination() && !m_pathPointsSent)
    {
        if (i_destinationHolder.HasArrived())
        {
            // prevent redundant micro-movement
            if (!i_offset)
            {
                if (i_target->IsWithinMeleeRange(&owner))
                    return false;
            }
            else if (!i_angle && !owner.hasUnitState(UNIT_STAT_FOLLOW))
            {
                if (i_target->IsWithinDistInMap(&owner, i_offset))
                    return false;
            }
            else
            {
                if (i_target->IsWithinDistInMap(&owner, i_offset + 1.0f))
                    return false;
            }
        }
        else
        {
            bool stop = false;
            if (!i_offset)
            {
                if (i_target->IsWithinMeleeRange(&owner, 0.0f))
                    stop = true;
            }
            else if (!i_angle && !owner.hasUnitState(UNIT_STAT_FOLLOW))
            {
                if (i_target->IsWithinDist(&owner, i_offset * 0.8f))
                    stop = true;
            }

            if (stop)
            {
                owner.GetPosition(x, y, z);
                if (owner.GetTypeId() == TYPEID_UNIT && (owner.HasUnitMovementFlag(MOVEFLAG_CAN_FLY) || owner.IsInWater() || i_target->IsInWater()))
                    z = i_target->GetPositionZ();

                if(m_usePathfinding)
                {
                    bool newPathCalculated = true;

                    if (!i_path)
                        i_path = new PathInfo(&owner, x, y, z);
                    else
                        newPathCalculated = i_path->Update(x, y, z);

                    // nothing we can do here ...
                    if(i_path->getPathType() & PATHFIND_NOPATH)
                        return true;

                    PointPath pointPath = i_path->getFullPath();

                    if (i_destinationHolder.HasArrived() && m_pathPointsSent)
                        --m_pathPointsSent;

                    i_path->getNextPosition(x, y, z);
                    i_destinationHolder.SetDestination(traveller, x, y, z, false);

                    // send the path if:
                    //    we have brand new path
                    //    we have visited almost all of the previously sent points
                    //    movespeed has changed
                    //    the owner is stopped (caused by some movement effects)
                    if (newPathCalculated || m_pathPointsSent < 2 || i_recalculateTravel || owner.IsStopped())
                    {
                        // send 10 nodes, or send all nodes if there are less than 10 left
                        m_pathPointsSent = std::min<uint32>(10, pointPath.size() - 1);
                        uint32 endIndex = m_pathPointsSent + 1;

                        // dist to next node + world-unit length of the path
                        x -= owner.GetPositionX();
                        y -= owner.GetPositionY();
                        z -= owner.GetPositionZ();
                        float dist = sqrt(x*x + y*y + z*z) + pointPath.GetTotalLength(1, endIndex);

                        // calculate travel time, set spline, then send path
                        uint32 traveltime = uint32(dist / (traveller.Speed()*0.001f));

                        owner.SendMonsterMoveByPath(pointPath, 1, endIndex, traveltime);

                        return false;
                    }
                }
                else
                {
                    i_destinationHolder.SetDestination(traveller, x, y, z);
                    i_destinationHolder.StartTravel(traveller, false);
                    owner.StopMoving();
                    return false;
                }
            }
        }

        if (i_target->GetExactDistSq(i_targetX, i_targetY, i_targetZ) < 0.01f)
            return false;
    }

    if (!i_offset)
    {
        // to nearest random contact position
        i_target->GetRandomContactPoint(&owner, x, y, z, 0, MELEE_RANGE - 0.5f);
    }
    else if (!i_angle && !owner.hasUnitState(UNIT_STAT_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);
    }

    /*
        We MUST not check the distance difference and avoid setting the new location for smaller distances.
        By that we risk having far too many GetContactPoint() calls freezing the whole system.
        In TargetedMovementGenerator<T>::Update() we check the distance to the target and at
        some range we calculate a new position. The calculation takes some processor cycles due to vmaps.
        If the distance to the target it too large to ignore,
        but the distance to the new contact point is short enough to be ignored,
        we will calculate a new contact point each update loop, but will never move to it.
        The system will freeze.
        ralf

        //We don't update Mob Movement, if the difference between New destination and last destination is < BothObjectSize
        float  bothObjectSize = i_target->GetObjectSize() + owner.GetObjectSize() + CONTACT_DISTANCE;
        if (i_destinationHolder.HasDestination() && i_destinationHolder.GetDestinationDiff(x,y,z) < bothObjectSize)
            return;
    */
    //i_destinationHolder.SetDestination(traveller, x, y, z);

    if(m_usePathfinding)
    {

        bool forceDest = false;
        // allow pets to cheat while generating paths as they should ALWAYS be able to reach thier target.
        if (owner.GetTypeId() == TYPEID_UNIT
                && owner.ToCreature()
                && owner.ToCreature()->isPet())
            forceDest = true;

        bool newPathCalculated = true;
        if (!i_path)
            i_path = new PathInfo(&owner, x, y, z, forceDest);
        else
            newPathCalculated = i_path->Update(x, y, z, forceDest);

        // nothing we can do here ...
        if (i_path->getPathType() & PATHFIND_NOPATH)
            return true;

        if (i_destinationHolder.HasArrived() && m_pathPointsSent)
            --m_pathPointsSent;

        i_path->getNextPosition(x, y, z);
        i_destinationHolder.SetDestination(traveller, x, y, z, false);

        // send the path if:
        //    we have brand new path
        //    we have visited almost all of the previously sent points
        //    movespeed has changed
        //    the owner is stopped (caused by some movement effects)
        if (newPathCalculated || m_pathPointsSent < 2 || i_recalculateTravel || owner.IsStopped())
        {
            PointPath pointPath = i_path->getFullPath();
            // send 10 nodes, or send all nodes if there are less than 10 left
            m_pathPointsSent = std::min<uint32>(10, pointPath.size() - 1);
            uint32 endIndex = m_pathPointsSent + 1;

            // dist to next node + world-unit length of the path
            x -= owner.GetPositionX();
            y -= owner.GetPositionY();
            z -= owner.GetPositionZ();
            float dist = sqrt(x*x + y*y + z*z) + pointPath.GetTotalLength(1, endIndex);

            // calculate travel time, set spline, then send path
            uint32 traveltime = uint32(dist / (traveller.Speed()*0.001f));

            owner.SendMonsterMoveByPath(pointPath, 1, endIndex, traveltime);
        }

        owner.addUnitState(UNIT_STAT_CHASE);
    }
    else
    {
        i_destinationHolder.SetDestination(traveller, x, y, z);
        owner.addUnitState(UNIT_STAT_CHASE);
        i_destinationHolder.StartTravel(traveller);
    }

}
void
RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
{
    float respX, respY, respZ, respO, currZ, destX, destY, destZ, wander_distance, travelDistZ;

    creature.GetRespawnCoord(respX, respY, respZ, &respO, &wander_distance);

    currZ = creature.GetPositionZ();
    TerrainInfo const* map = creature.GetTerrain();

    // For 2D/3D system selection
    //bool is_land_ok  = creature.CanWalk();                // not used?
    //bool is_water_ok = creature.CanSwim();                // not used?
    bool is_air_ok = creature.CanFly();

    const float angle = rand_norm_f() * (M_PI_F*2.0f);
    const float range = rand_norm_f() * wander_distance;
    const float distanceX = range * cos(angle);
    const float distanceY = range * sin(angle);

    destX = respX + distanceX;
    destY = respY + distanceY;

    // prevent invalid coordinates generation
    MaNGOS::NormalizeMapCoord(destX);
    MaNGOS::NormalizeMapCoord(destY);

    travelDistZ = distanceX*distanceX + distanceY*distanceY;

    if (is_air_ok)                                          // 3D system above ground and above water (flying mode)
    {
        // Limit height change
        const float distanceZ = rand_norm_f() * sqrtf(travelDistZ)/2.0f;
        destZ = respZ + distanceZ;
        float levelZ = map->GetWaterOrGroundLevel(destX, destY, destZ-2.0f);

        // Problem here, we must fly above the ground and water, not under. Let's try on next tick
        if (levelZ >= destZ)
            return;
    }
    //else if (is_water_ok)                                 // 3D system under water and above ground (swimming mode)
    else                                                    // 2D only
    {
        destZ = respZ;
        if(!map->IsNextZcoordOK(destX, destY, destZ, travelDistZ))
            return;                                         // let's forget this bad coords where a z cannot be find and retry at next tick
        creature.UpdateGroundPositionZ(destX, destY, destZ, travelDistZ);
    }

    Traveller<Creature> traveller(creature);

    creature.SetOrientation(creature.GetAngle(destX, destY));
    i_destinationHolder.SetDestination(traveller, destX, destY, destZ);
    creature.addUnitState(UNIT_STAT_ROAMING_MOVE);

    if (is_air_ok)
    {
        i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
        creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7);
    }
    //else if (is_water_ok)                                 // Swimming mode to be done with more than this check
    else
    {
        i_nextMoveTime.Reset(urand(500+i_destinationHolder.GetTotalTravelTime(), 10000+i_destinationHolder.GetTotalTravelTime()));
        creature.AddSplineFlag(SPLINEFLAG_WALKMODE);
    }
}