Ejemplo n.º 1
0
// Check that we are still close to the start of the A* path,
// and the end of the path is close to our goal
static int AStarCloseToPath(
    AIGotoContext *c, Vec2i currentTile, Vec2i goalTile)
{
    Vec2i *pathTile;
    Vec2i *pathEnd;
    if (!c ||
            c->PathIndex >= (int)ASPathGetCount(c->Path) - 1) // at end of path
    {
        return 0;
    }
    // Check if we're too far from the current start of the path
    pathTile = ASPathGetNode(c->Path, c->PathIndex);
    if (CHEBYSHEV_DISTANCE(
                currentTile.x, currentTile.y, pathTile->x, pathTile->y) > 2)
    {
        return 0;
    }
    // Check if we're too far from the end of the path
    pathEnd = ASPathGetNode(c->Path, ASPathGetCount(c->Path) - 1);
    if (CHEBYSHEV_DISTANCE(
                goalTile.x, goalTile.y, pathEnd->x, pathEnd->y) > 0)
    {
        return 0;
    }
    return 1;
}
Ejemplo n.º 2
0
int AIGoto(TActor *actor, Vec2i p, bool ignoreObjects)
{
    Vec2i a = Vec2iFull2Real(actor->Pos);
    Vec2i currentTile = Vec2iToTile(a);
    Vec2i goalTile = Vec2iToTile(p);
    AIGotoContext *c = &actor->aiContext->Goto;

    // If we are already there, bail
    // This can happen if AI is trying to track the player,
    // but the player has died, for example.
    if (Vec2iEqual(currentTile, goalTile))
    {
        return 0;
    }

    // If we are currently following an A* path,
    // and it is still valid, keep following it until
    // we have reached a new tile
    if (c && c->IsFollowing && AStarCloseToPath(c, currentTile, goalTile))
    {
        return AStarFollow(c, currentTile, &actor->tileItem, a);
    }
    else if (AIHasClearPath(a, p, ignoreObjects))
    {
        // Simple case: if there's a clear line between AI and target,
        // walk straight towards it
        return AIGotoDirect(a, p);
    }
    else
    {
        // We need to recalculate A*

        AStarContext ac;
        ac.Map = &gMap;
        ac.IsTileOk =
            ignoreObjects ? IsTileWalkable : IsTileWalkableAroundObjects;
        // First, if the goal tile is blocked itself,
        // find a nearby tile that can be walked to
        c->Goal = MapSearchTileAround(ac.Map, goalTile, ac.IsTileOk);

        c->PathIndex = 1;	// start navigating to the next path node
        ASPathDestroy(c->Path);
        c->Path = ASPathCreate(
                      &cPathNodeSource, &ac, &currentTile, &c->Goal);

        // In case we can't calculate A* for some reason,
        // try simple navigation again
        if (ASPathGetCount(c->Path) <= 1)
        {
            debug(
                D_MAX,
                "Error: can't calculate path from {%d, %d} to {%d, %d}",
                currentTile.x, currentTile.y,
                goalTile.x, goalTile.y);
            return AIGotoDirect(a, p);
        }

        return AStarFollow(c, currentTile, &actor->tileItem, a);
    }
}
Ejemplo n.º 3
0
// Use pathfinding to check that there is a path between
// source and destination tiles
bool AIHasPath(const Vec2i from, const Vec2i to, const bool ignoreObjects)
{
    // Quick first test: check there is a clear path
    if (AIHasClearPath(from, to, ignoreObjects))
    {
        return true;
    }
    // Pathfind
    AStarContext ac;
    ac.Map = &gMap;
    ac.IsTileOk = ignoreObjects ? IsTileWalkable : IsTileWalkableAroundObjects;
    Vec2i fromTile = Vec2iToTile(from);
    Vec2i toTile = MapSearchTileAround(ac.Map, Vec2iToTile(to), ac.IsTileOk);
    ASPath path = ASPathCreate(&cPathNodeSource, &ac, &fromTile, &toTile);
    size_t pathCount = ASPathGetCount(path);
    ASPathDestroy(path);
    return pathCount > 1;
}
Ejemplo n.º 4
0
int getEdgeCount(ASPath path) {
	return ASPathGetCount(path) - 1;
}