/* fill the grid, starting from the origin until we reach the destination */ static void TCOD_path_set_cells(TCOD_path_data_t *path, int cutoff) { int stepstaken = 0; while ( path->grid[path->dx + path->dy * path->w ] == 0 && ! TCOD_list_is_empty(path->heap) ) { stepstaken++; if (stepstaken > cutoff) break; int x,y,i,imax; float distance; TCOD_path_get_cell(path,&x,&y,&distance); imax= ( path->diagonalCost == 0.0f ? 4 : 8) ; for (i=0; i < imax; i++ ) { /* convert i to dx,dy */ static int idirx[]={0,-1,1,0,-1,1,-1,1}; static int idiry[]={-1,0,0,1,-1,-1,1,1}; /* convert i to direction */ static dir_t prevdirs[] = { NORTH, WEST, EAST, SOUTH, NORTH_WEST, NORTH_EAST,SOUTH_WEST,SOUTH_EAST }; /* coordinate of the adjacent cell */ int cx=x+idirx[i]; int cy=y+idiry[i]; if ( cx >= 0 && cy >= 0 && cx < path->w && cy < path->h ) { float walk_cost = TCOD_path_walk_cost(path,x,y,cx,cy); if ( walk_cost > 0.0f ) { /* in of the map and walkable */ float covered=distance + walk_cost * (i>=4 ? path->diagonalCost : 1.0f); float previousCovered = path->grid[cx + cy * path->w ]; if ( previousCovered == 0 ) { /* put a new cell in the heap */ int offset=cx + cy * path->w; /* A* heuristic : remaining distance */ float remaining=(float)sqrt((cx-path->dx)*(cx-path->dx)+(cy-path->dy)*(cy-path->dy)); path->grid[ offset ] = covered; path->heur[ offset ] = covered + remaining; path->prev[ offset ] = prevdirs[i]; TCOD_path_push_cell(path,cx,cy); } else if ( previousCovered > covered ) { /* we found a better path to a cell already in the heap */ int offset=cx + cy * path->w; path->grid[ offset ] = covered; path->heur[ offset ] -= (previousCovered - covered); /* fix the A* score */ path->prev[ offset ] = prevdirs[i]; /* reorder the heap */ heap_reorder(path,offset); } } } } } }
bool TCOD_path_walk(TCOD_path_t p, int *x, int *y, bool recalculate_when_needed) { int newx,newy; float can_walk; int d; TCOD_path_data_t *path=(TCOD_path_data_t *)p; TCOD_IFNOT(p != NULL) return false; if ( TCOD_path_is_empty(path) ) return false; d=(int)(uintptr)TCOD_list_pop(path->path); newx=path->ox + dirx[d]; newy=path->oy + diry[d]; /* check if the path is still valid */ can_walk = TCOD_path_walk_cost(path,path->ox,path->oy,newx,newy); if ( can_walk == 0.0f ) { if (! recalculate_when_needed ) return false; /* don't walk */ /* calculate a new path */ if (! TCOD_path_compute(path, path->ox,path->oy, path->dx,path->dy) ) return false ; /* cannot find a new path */ return TCOD_path_walk(p,x,y,true); /* walk along the new path */ } if ( x ) *x=newx; if ( y ) *y=newy; path->ox=newx; path->oy=newy; return true; }