void RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
{
    float respX, respY, respZ, respO, wander_distance;
    creature.GetRespawnCoord(respX, respY, respZ, &respO, &wander_distance);

    const float angle = rand_norm_f() * (M_PI_F*2.0f);
    const float range = rand_norm_f() * wander_distance;

    float destX = respX + range * cos(angle);
    float destY = respY + range * sin(angle);
    float destZ = creature.GetPositionZ();
    creature.UpdateAllowedPositionZ(destX, destY, destZ);

    creature.addUnitState(UNIT_STAT_ROAMING_MOVE);

    Movement::MoveSplineInit init(creature);
    init.MoveTo(destX, destY, destZ, true);
    init.SetWalk(true);
    init.Launch();

    if (creature.CanFly())
        i_nextMoveTime.Reset(0);
    else
        i_nextMoveTime.Reset(urand(500, 10000));
}
void RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
{
    const float angle = rand_norm_f() * (M_PI_F*2.0f);
    const float range = rand_norm_f() * i_radius;

    float destX,destY,destZ;
    creature.GetNearPoint(&creature, destX, destY, destZ, creature.GetObjectBoundingRadius(), range, angle);
    creature.UpdateAllowedPositionZ(destX, destY, destZ);

    float dx = i_x - destX;
    float dy = i_y - destY;
    // TODO: Limitation creatutre travel range.
    if (sqrt((dx*dx) + (dy*dy)) > i_radius)
    {
        destX = i_x;
        destY = i_y;
        destZ = i_z;
    }

    creature.addUnitState(UNIT_STAT_ROAMING_MOVE);

    Movement::MoveSplineInit init(creature);
    init.MoveTo(destX, destY, destZ, true);
    init.SetWalk(true);
    init.Launch();

    if (creature.CanFly())
        i_nextMoveTime.Reset(0);
    else
        i_nextMoveTime.Reset(urand(500, 10000));
}
void RandomMovementGenerator<Creature>::_setRandomLocation(Creature& creature)
{
    const float angle = rand_norm_f() * (M_PI_F * 2.0f);
    const float range = rand_norm_f() * i_radius;

    const float maxPathRange = range * 1.5f;

    float destX = i_x + range * cos(angle);
    float destY = i_y + range * sin(angle);
    float destZ = i_z + frand(-1, 1) * i_verticalZ;
    creature.UpdateAllowedPositionZ(destX, destY, destZ);

    creature.addUnitState(UNIT_STAT_ROAMING_MOVE);

    Movement::MoveSplineInit init(creature);
    init.MoveTo(destX, destY, destZ, true, false, maxPathRange);
    init.SetWalk(true);
    init.Launch();

    if (creature.CanFly())
        { i_nextMoveTime.Reset(0); }
    else
    {
        if (roll_chance_i(MOVEMENT_RANDOM_MMGEN_CHANCE_NO_BREAK))
            i_nextMoveTime.Reset(50);
        else
            i_nextMoveTime.Reset(urand(3000, 10000));       // keep a short wait time
    }
}
void
ConfusedMovementGenerator<T>::Initialize(T &unit)
{
    const float wander_distance=11;
    float x,y,z;
    x = unit.GetPositionX();
    y = unit.GetPositionY();
    z = unit.GetPositionZ();

    TerrainInfo const* map = unit.GetTerrain();

    i_nextMove = 1;

    bool is_water_ok, is_land_ok;
    _InitSpecific(unit, is_water_ok, is_land_ok);

    for(unsigned int idx=0; idx < MAX_CONF_WAYPOINTS+1; ++idx)
    {
        const float wanderX=wander_distance*rand_norm_f() - wander_distance/2;
        const float wanderY=wander_distance*rand_norm_f() - wander_distance/2;

        i_waypoints[idx][0] = x + wanderX;
        i_waypoints[idx][1] = y + wanderY;

        // prevent invalid coordinates generation
        MaNGOS::NormalizeMapCoord(i_waypoints[idx][0]);
        MaNGOS::NormalizeMapCoord(i_waypoints[idx][1]);

        // check LOS
        if(!unit.IsWithinLOS(i_waypoints[idx][0], i_waypoints[idx][1], z))
        {
            i_waypoints[idx][0] = idx > 0 ? i_waypoints[idx-1][0] : x;
            i_waypoints[idx][1] = idx > 0 ? i_waypoints[idx-1][1] : y;
        }

        bool is_water = map->IsInWater(i_waypoints[idx][0],i_waypoints[idx][1],z);
        // if generated wrong path just ignore
        if ((is_water && !is_water_ok) || (!is_water && !is_land_ok) ||
            !map->IsNextZcoordOK(i_waypoints[idx][0], i_waypoints[idx][1], z))  // check if not under map
        {
            i_waypoints[idx][0] = idx > 0 ? i_waypoints[idx-1][0] : x;
            i_waypoints[idx][1] = idx > 0 ? i_waypoints[idx-1][1] : y;
        }

        unit.UpdateAllowedPositionZ(i_waypoints[idx][0],i_waypoints[idx][1],z);
        i_waypoints[idx][2] =  z;
    }

    unit.StopMoving();
    unit.addUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_CONFUSED_MOVE);
}
Exemple #5
0
    void SpawnerSummon(Creature* pSummoner)
    {
        if (m_uiRitualPhase > 7)
        {
            pSummoner->SummonCreature(NPC_PLAGUEMAW_THE_ROTTING, pSummoner->GetPositionX(), pSummoner->GetPositionY(), pSummoner->GetPositionZ(), pSummoner->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000);
            return;
        }

        for(int i = 0; i < 4; ++i)
        {
            uint32 uiEntry = 0;

            // ref TARGET_RANDOM_CIRCUMFERENCE_POINT
            float angle = 2.0f * M_PI_F * rand_norm_f();
            float fX, fZ, fY;
            pSummoner->GetClosePoint(fX, fZ, fY, 0.0f, 2.0f, angle);

            switch(i)
            {
                case 0:
                case 1:
                    uiEntry = NPC_WITHERED_BATTLE_BOAR;
                    break;
                case 2:
                    uiEntry = NPC_WITHERED_QUILGUARD;
                    break;
                case 3:
                    uiEntry = NPC_DEATHS_HEAD_GEOMANCER;
                    break;
            }

            pSummoner->SummonCreature(uiEntry, fX, fZ, fY, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000);
        }
    }
bool ConfusedMovementGenerator<T>::Update(T& unit, const uint32& diff)
{
    // 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);

        if (unit.movespline->Finalized())
            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);

            PathFinder path(&unit);
            path.setPathLengthLimit(30.0f);
            path.calculate(x, y, z);
            if (path.getPathType() & PATHFIND_NOPATH)
            {
                i_nextMoveTime.Reset(urand(800, 1000));
                return true;
            }

            Movement::MoveSplineInit init(unit);
            init.MovebyPath(path.getPath());
            init.SetWalk(true);
            init.Launch();
        }
    }

    return true;
}
void RandomMovementGenerator<Creature>::_setRandomLocation(Creature& creature)
{
    const float angle = rand_norm_f() * (M_PI_F * 2.0f);
    const float range = rand_norm_f() * i_radius;

    float destX = i_x + range * cos(angle);
    float destY = i_y + range * sin(angle);
    float destZ = i_z + frand(-1, 1) * i_verticalZ;
    creature.UpdateAllowedPositionZ(destX, destY, destZ);

    creature.addUnitState(UNIT_STAT_ROAMING_MOVE);

    Movement::MoveSplineInit init(creature);
    init.MoveTo(destX, destY, destZ, true);
    init.SetWalk(true);
    init.Launch();

    if (creature.CanFly())
        i_nextMoveTime.Reset(0);
    else
        i_nextMoveTime.Reset(urand(500, 10000));
}
bool ConfusedMovementGenerator<T>::Update(T& unit, const uint32& diff)
{
    // 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);

        if (unit.movespline->Finalized())
            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);

           WorldLocation destLoc;
           unit.GetFirstCollisionPosition(destLoc, 10.0f*(rand_norm_f() - 0.5f), unit.GetOrientation());



            PathFinder path(&unit);
            path.setPathLengthLimit(30.0f);
            path.calculate(destLoc.coord_x, destLoc.coord_y, (destLoc.coord_z + unit.GetObjectScale()));
            if (path.getPathType() & PATHFIND_NOPATH)
            {
                i_nextMoveTime.Reset(urand(800, 1000));
                return true;
            }

            Movement::MoveSplineInit init(unit);
            init.MovebyPath(path.getPath());
            init.SetWalk(true);
            init.Launch();
        }
    }

    return true;
}
Exemple #9
0
bool
FleeingMovementGenerator<T>::_setMoveData(T& owner)
{
    float cur_dist_xyz = owner.GetDistance(i_caster_x, i_caster_y, i_caster_z);

    if (i_to_distance_from_caster > 0.0f)
    {
        if ((i_last_distance_from_caster > i_to_distance_from_caster && cur_dist_xyz < i_to_distance_from_caster)   ||
                // if we reach lower distance
                (i_last_distance_from_caster > i_to_distance_from_caster && cur_dist_xyz > i_last_distance_from_caster) ||
                // if we can't be close
                (i_last_distance_from_caster < i_to_distance_from_caster && cur_dist_xyz > i_to_distance_from_caster)   ||
                // if we reach bigger distance
                (cur_dist_xyz > MAX_QUIET_DISTANCE) ||           // if we are too far
                (i_last_distance_from_caster > MIN_QUIET_DISTANCE && cur_dist_xyz < MIN_QUIET_DISTANCE))
            // if we leave 'quiet zone'
        {
            // we are very far or too close, stopping
            i_to_distance_from_caster = 0.0f;
            i_nextCheckTime.Reset(urand(500, 1000));
            return false;
        }
        else
        {
            // now we are running, continue
            i_last_distance_from_caster = cur_dist_xyz;
            return true;
        }
    }

    float cur_dist;
    float angle_to_caster;

    if (Unit* fright = owner.GetMap()->GetUnit(i_frightGuid))
    {
        cur_dist = fright->GetDistance(&owner);
        if (cur_dist < cur_dist_xyz)
        {
            i_caster_x = fright->GetPositionX();
            i_caster_y = fright->GetPositionY();
            i_caster_z = fright->GetPositionZ();
            angle_to_caster = fright->GetAngle(&owner);
        }
        else
        {
            cur_dist = cur_dist_xyz;
            angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + M_PI_F;
        }
    }
    else
    {
        cur_dist = cur_dist_xyz;
        angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + M_PI_F;
    }

    // if we too close may use 'path-finding' else just stop
    i_only_forward = cur_dist >= MIN_QUIET_DISTANCE / 3;

    //get angle and 'distance from caster' to run
    float angle;

    if (i_cur_angle == 0.0f && i_last_distance_from_caster == 0.0f) //just started, first time
    {
        angle = rand_norm_f() * (1.0f - cur_dist / MIN_QUIET_DISTANCE) * M_PI_F / 3 + rand_norm_f() * M_PI_F * 2 / 3;
        i_to_distance_from_caster = MIN_QUIET_DISTANCE;
        i_only_forward = true;
    }
    else if (cur_dist < MIN_QUIET_DISTANCE)
    {
        angle = M_PI_F / 6 + rand_norm_f() * M_PI_F * 2 / 3;
        i_to_distance_from_caster = cur_dist * 2 / 3 + rand_norm_f() * (MIN_QUIET_DISTANCE - cur_dist * 2 / 3);
    }
    else if (cur_dist > MAX_QUIET_DISTANCE)
    {
        angle = rand_norm_f() * M_PI_F / 3 + M_PI_F * 2 / 3;
        i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + rand_norm_f() * (MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f);
    }
    else
    {
        angle = rand_norm_f() * M_PI_F;
        i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + rand_norm_f() * (MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f);
    }

    int8 sign = rand_norm_f() > 0.5f ? 1 : -1;
    i_cur_angle = sign * angle + angle_to_caster;

    // current distance
    i_last_distance_from_caster = cur_dist;

    return true;
}
Exemple #10
0
/// Calculate the new weather
bool Weather::ReGenerate()
{
    if (!m_weatherChances)
    {
        m_type = WEATHER_TYPE_FINE;
        m_grade = 0.0f;
        return false;
    }

    /// Weather statistics:
    ///- 30% - no change
    ///- 30% - weather gets better (if not fine) or change weather type
    ///- 30% - weather worsens (if not fine)
    ///- 10% - radical change (if not fine)
    uint32 u = urand(0, 99);

    if (u < 30)
        return false;

    // remember old values
    WeatherType old_type = m_type;
    float old_grade = m_grade;

    //78 days between January 1st and March 20nd; 365/4=91 days by season
    // season source http://aa.usno.navy.mil/data/docs/EarthSeasons.html
    time_t gtime = sWorld.GetGameTime();
    struct tm * ltime = localtime(&gtime);
    uint32 season = ((ltime->tm_yday - 78 + 365)/91)%4;

    static char const* seasonName[WEATHER_SEASONS] = { "spring", "summer", "fall", "winter" };

    DEBUG_FILTER_LOG(LOG_FILTER_WEATHER, "Generating a change in %s weather for zone %u.", seasonName[season], m_zone);

    if ((u < 60) && (m_grade < 0.33333334f))                // Get fair
    {
        m_type = WEATHER_TYPE_FINE;
        m_grade = 0.0f;
    }

    if ((u < 60) && (m_type != WEATHER_TYPE_FINE))          // Get better
    {
        m_grade -= 0.33333334f;
        return true;
    }

    if ((u < 90) && (m_type != WEATHER_TYPE_FINE))          // Get worse
    {
        m_grade += 0.33333334f;
        return true;
    }

    if (m_type != WEATHER_TYPE_FINE)
    {
        /// Radical change:
        ///- if light -> heavy
        ///- if medium -> change weather type
        ///- if heavy -> 50% light, 50% change weather type

        if (m_grade < 0.33333334f)
        {
            m_grade = 0.9999f;                              // go nuts
            return true;
        }
        else
        {
            if (m_grade > 0.6666667f)
            {
                                                            // Severe change, but how severe?
                uint32 rnd = urand(0,99);
                if (rnd < 50)
                {
                    m_grade -= 0.6666667f;
                    return true;
                }
            }
            m_type = WEATHER_TYPE_FINE;                     // clear up
            m_grade = 0;
        }
    }

    // At this point, only weather that isn't doing anything remains but that have weather data
    uint32 chance1 =          m_weatherChances->data[season].rainChance;
    uint32 chance2 = chance1+ m_weatherChances->data[season].snowChance;
    uint32 chance3 = chance2+ m_weatherChances->data[season].stormChance;

    uint32 rnd = urand(0, 99);
    if (rnd <= chance1)
        m_type = WEATHER_TYPE_RAIN;
    else if (rnd <= chance2)
        m_type = WEATHER_TYPE_SNOW;
    else if (rnd <= chance3)
        m_type = WEATHER_TYPE_STORM;
    else
        m_type = WEATHER_TYPE_FINE;

    /// New weather statistics (if not fine):
    ///- 85% light
    ///- 7% medium
    ///- 7% heavy
    /// If fine 100% sun (no fog)

    if (m_type == WEATHER_TYPE_FINE)
    {
        m_grade = 0.0f;
    }
    else if (u < 90)
    {
        m_grade = rand_norm_f() * 0.3333f;
    }
    else
    {
        // Severe change, but how severe?
        rnd = urand(0, 99);
        if (rnd < 50)
            m_grade = rand_norm_f() * 0.3333f + 0.3334f;
        else
            m_grade = rand_norm_f() * 0.3333f + 0.6667f;
    }

    // return true only in case weather changes
    return m_type != old_type || m_grade != old_grade;
}
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);
    }
}
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
    {
        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);

        if (fabs(nz-Z) > dist)                              // Map check
        {
            nz = map->GetHeight(nx, ny, Z-2.0f, true);      // Vmap Horizontal or above

            if (fabs(nz-Z) > dist)
            {
                // Vmap Higher
                nz = map->GetHeight(nx, ny, Z+dist-2.0f, true);

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

    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);
    }
}
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 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
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);
    }
}
void
ConfusedMovementGenerator<T>::Initialize(T &unit)
{
    const float wander_distance=11;
    float x,y,z;
    unit.GetPosition(x,y,z);
    //Get the nearest point
    i_nextMove = urand(1,MAX_CONF_WAYPOINTS);
    i_nextMoveTime.Reset(1);

    bool is_water_ok, is_land_ok;
    _InitSpecific(unit, is_water_ok, is_land_ok);

    uint32 mapId = unit.GetMapId();
    if (MMAP::MMapFactory::IsPathfindingEnabled(mapId))
    {
        MMAP::MMapManager* mmap = MMAP::MMapFactory::createOrGetMMapManager();

        float ox=x;
        float oy=y;
        float oz=z;

        dtPolyRef originPoly;
        mmap->GetNearestValidPosition(&unit,3,3,5,ox,oy,oz,&originPoly);

        i_waypoints[0][0] = ox;
        i_waypoints[0][1] = oy;
        i_waypoints[0][2] = oz;

        for (int i = 1; i < MAX_CONF_WAYPOINTS+1;i++)
        {
            const float wanderX=wander_distance*rand_norm_f() - wander_distance/2;
            const float wanderY=wander_distance*rand_norm_f() - wander_distance/2;
            float toX = ox + wanderX;
            float toY = oy + wanderY;
            float toZ = oz;

            if (mmap->DrawRay(&unit,originPoly,ox,oy,oz,toX,toY,toZ))
            {
                i_waypoints[i][0] = toX;
                i_waypoints[i][1] = toY;
                i_waypoints[i][2] = toZ;
            } else
            {
                i_waypoints[i][0] = ox;
                i_waypoints[i][1] = oy;
                i_waypoints[i][2] = oz;
            }
        }
    } else
    {
        TerrainInfo const* map = unit.GetTerrain();
        for(unsigned int idx=0; idx < MAX_CONF_WAYPOINTS+1; ++idx)
        {
            const float wanderX=wander_distance*rand_norm_f() - wander_distance/2;
            const float wanderY=wander_distance*rand_norm_f() - wander_distance/2;

            i_waypoints[idx][0] = x + wanderX;
            i_waypoints[idx][1] = y + wanderY;

            // prevent invalid coordinates generation
            MaNGOS::NormalizeMapCoord(i_waypoints[idx][0]);
            MaNGOS::NormalizeMapCoord(i_waypoints[idx][1]);

            bool is_water = map->IsInWater(i_waypoints[idx][0],i_waypoints[idx][1],z);
            // if generated wrong path just ignore
            if ((is_water && !is_water_ok) || (!is_water && !is_land_ok))
            {
                i_waypoints[idx][0] = idx > 0 ? i_waypoints[idx-1][0] : x;
                i_waypoints[idx][1] = idx > 0 ? i_waypoints[idx-1][1] : y;
            }

            unit.UpdateAllowedPositionZ(i_waypoints[idx][0],i_waypoints[idx][1],z);
            i_waypoints[idx][2] =  z;
        }
    }

    unit.StopMoving();
    unit.addUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_CONFUSED_MOVE);
}