Skip to content

Instantly share code, notes, and snippets.

@Emtec
Created August 13, 2015 20:17
Show Gist options
  • Save Emtec/ddb34c77794966bbe05b to your computer and use it in GitHub Desktop.
Save Emtec/ddb34c77794966bbe05b to your computer and use it in GitHub Desktop.

Revisions

  1. Emtec created this gist Aug 13, 2015.
    70 changes: 70 additions & 0 deletions .cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,70 @@
    template<>
    bool RandomMovementGenerator<Creature>::GeneratePosition(Creature* creature, float& x, float& y, float& z)
    {
    float respX, respY, respZ, destX, destY, destZ, travelDistZ;
    creature->GetCreatureMovementPath().GetCurrentPath()->position.GetPosition(respX, respY, respZ);

    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 = float(rand_norm()) * static_cast<float>(M_PI*2.0f);
    const float range = float(rand_norm()) * wander_distance;
    const float distanceX = range * std::cos(angle);
    const float distanceY = range * std::sin(angle);

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

    Trinity::NormalizeMapCoord(destX);
    Trinity::NormalizeMapCoord(destY);

    travelDistZ = range; // sin^2+cos^2=1, so travelDistZ=range^2; no need for sqrt below

    if (is_air_ok) // 3D system above ground and above water (flying mode)
    {
    // Limit height change
    const float distanceZ = float(rand_norm()) * travelDistZ / 2.0f;
    destZ = respZ + distanceZ;
    float levelZ = map->GetWaterOrGroundLevel(creature->GetPhaseMask(), 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 false;
    }
    //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 >= 10.0f ? 10.0f : 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(creature->GetPhaseMask(), destX, destY, respZ + travelDistZ - 2.0f, false);

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

    if (std::fabs(destZ - respZ) > travelDistZ)
    {
    // Vmap Higher
    destZ = map->GetHeight(creature->GetPhaseMask(), 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 (std::fabs(destZ - respZ) > travelDistZ)
    return false;
    }
    }
    }

    x = destX;
    y = destY;
    z = destZ;

    return true;
    }