Пример #1
0
void calculateDistances(short **distanceMap,
						short destinationX, short destinationY,
						unsigned long blockingTerrainFlags,
						creature *traveler,
						boolean canUseSecretDoors,
						boolean eightWays) {
	creature *monst;
    static pdsMap map;

	short i, j;
	
	for (i=0; i<DCOLS; i++) {
		for (j=0; j<DROWS; j++) {
			char cost;
            monst = monsterAtLoc(i, j);
            if (monst
                && (monst->info.flags & (MONST_IMMUNE_TO_WEAPONS | MONST_INVULNERABLE))
                && (monst->info.flags & (MONST_IMMOBILE | MONST_GETS_TURN_ON_ACTIVATION))) {
                
                // Always avoid damage-immune stationary monsters.
                cost = PDS_FORBIDDEN;
            } else if (canUseSecretDoors
                && cellHasTMFlag(i, j, TM_IS_SECRET)
                && cellHasTerrainFlag(i, j, T_OBSTRUCTS_PASSABILITY)
                && !(discoveredTerrainFlagsAtLoc(i, j) & T_OBSTRUCTS_PASSABILITY)) {
                
				cost = 1;
			} else if (cellHasTerrainFlag(i, j, T_OBSTRUCTS_PASSABILITY)
					   || (traveler && traveler == &player && !(pmap[i][j].flags & (DISCOVERED | MAGIC_MAPPED)))) {
                
				cost = cellHasTerrainFlag(i, j, T_OBSTRUCTS_DIAGONAL_MOVEMENT) ? PDS_OBSTRUCTION : PDS_FORBIDDEN;
			} else if ((traveler && monsterAvoids(traveler, i, j)) || cellHasTerrainFlag(i, j, blockingTerrainFlags)) {
				cost = PDS_FORBIDDEN;
			} else {
				cost = 1;
			}
			
			PDS_CELL(&map, i, j)->cost = cost;
		}
	}
	
	pdsClear(&map, 30000, eightWays);
	pdsSetDistance(&map, destinationX, destinationY, 0);
	pdsBatchOutput(&map, distanceMap);
}
Пример #2
0
// Fills grid locations with the given value if they match any terrain flags or map flags.
// Otherwise does not change the grid location.
void getTerrainGrid(short **grid, short value, unsigned long terrainFlags, unsigned long mapFlags) {
    short i, j;
	for(i = 0; i < DCOLS; i++) {
		for(j = 0; j < DROWS; j++) {
            if (grid[i][j] != value && cellHasTerrainFlag(i, j, terrainFlags) || (pmap[i][j].flags & mapFlags)) {
                grid[i][j] = value;
            }
        }
    }
}
Пример #3
0
// This is a custom implementation of recursive shadowcasting.
void scanOctantFOV(char grid[VIEWWIDTH][VIEWHEIGHT], short xLoc, short yLoc, short octant, float maxRadius,
				   short columnsRightFromOrigin, long startSlope, long endSlope, unsigned long forbiddenTerrain,
				   unsigned long forbiddenFlags, boolean cautiousOnWalls) {
	
	if (columnsRightFromOrigin >= maxRadius) return;
	
	short i, a, b, iStart, iEnd, x, y, x2, y2; // x and y are temporary variables on which we do the octant transform
	long newStartSlope, newEndSlope;
	boolean cellObstructed;
	
	newStartSlope = startSlope;
	
	a = ((LOS_SLOPE_GRANULARITY / -2 + 1) + startSlope * columnsRightFromOrigin) / LOS_SLOPE_GRANULARITY;
	b = ((LOS_SLOPE_GRANULARITY / -2 + 1) + endSlope * columnsRightFromOrigin) / LOS_SLOPE_GRANULARITY;
	
	iStart = min(a, b);
	iEnd = max(a, b);
	
	// restrict vision to a circle of radius maxRadius
	if ((columnsRightFromOrigin*columnsRightFromOrigin + iEnd*iEnd) >= maxRadius*maxRadius) {
		return;
	}
	if ((columnsRightFromOrigin*columnsRightFromOrigin + iStart*iStart) >= maxRadius*maxRadius) {
		iStart = (int) (-1 * sqrt(maxRadius*maxRadius - columnsRightFromOrigin*columnsRightFromOrigin) + FLOAT_FUDGE);
	}
	
	x = xLoc + columnsRightFromOrigin;
	y = yLoc + iStart;
	betweenOctant1andN(&x, &y, xLoc, yLoc, octant);
	boolean currentlyLit = coordinatesAreInMap(x, y) && !(cellHasTerrainFlag(x, y, forbiddenTerrain) ||
														  (pmap[x][y].flags & forbiddenFlags));
	for (i = iStart; i <= iEnd; i++) {
		x = xLoc + columnsRightFromOrigin;
		y = yLoc + i;
		betweenOctant1andN(&x, &y, xLoc, yLoc, octant);
		if (!coordinatesAreInMap(x, y)) {
			// We're off the map -- here there be memory corruption.
			continue;
		}
		cellObstructed = (cellHasTerrainFlag(x, y, forbiddenTerrain) || (pmap[x][y].flags & forbiddenFlags));
		// if we're cautious on walls and this is a wall:
		if (cautiousOnWalls && cellObstructed) {
			// (x2, y2) is the tile one space closer to the origin from the tile we're on:
			x2 = xLoc + columnsRightFromOrigin - 1;
			y2 = yLoc + i;
			if (i < 0) {
				y2++;
			} else if (i > 0) {
				y2--;
			}
			betweenOctant1andN(&x2, &y2, xLoc, yLoc, octant);
			
			if (pmap[x2][y2].flags & IN_FIELD_OF_VIEW) {
				// previous tile is visible, so illuminate
				grid[x][y] = 1;
			}
		} else {
			// illuminate
			grid[x][y] = 1;
		}
		if (!cellObstructed && !currentlyLit) { // next column slope starts here
			newStartSlope = (long int) ((LOS_SLOPE_GRANULARITY * (i) - LOS_SLOPE_GRANULARITY / 2) / (columnsRightFromOrigin + 0.5));
			currentlyLit = true;
		} else if (cellObstructed && currentlyLit) { // next column slope ends here
			newEndSlope = (long int) ((LOS_SLOPE_GRANULARITY * (i) - LOS_SLOPE_GRANULARITY / 2)
							/ (columnsRightFromOrigin - 0.5));
			if (newStartSlope <= newEndSlope) {
				// run next column
				scanOctantFOV(grid, xLoc, yLoc, octant, maxRadius, columnsRightFromOrigin + 1, newStartSlope, newEndSlope,
							  forbiddenTerrain, forbiddenFlags, cautiousOnWalls);
			}
			currentlyLit = false;
		}
	}
	if (currentlyLit) { // got to the bottom of the scan while lit
		newEndSlope = endSlope;
		if (newStartSlope <= newEndSlope) {
			// run next column
			scanOctantFOV(grid, xLoc, yLoc, octant, maxRadius, columnsRightFromOrigin + 1, newStartSlope, newEndSlope,
						  forbiddenTerrain, forbiddenFlags, cautiousOnWalls);
		}
	}
}
Пример #4
0
boolean getQualifyingPathLocNear(short *retValX, short *retValY,
                                 short x, short y,
                                 boolean hallwaysAllowed,
                                 unsigned long blockingTerrainFlags,
                                 unsigned long blockingMapFlags,
                                 unsigned long forbiddenTerrainFlags,
                                 unsigned long forbiddenMapFlags,
                                 boolean deterministic) {
    short **grid, **costMap;
    short loc[2];
    
    // First check the given location to see if it works, as an optimization.
    if (!cellHasTerrainFlag(x, y, blockingTerrainFlags | forbiddenTerrainFlags)
        && !(pmap[x][y].flags & (blockingMapFlags | forbiddenMapFlags))
        && (hallwaysAllowed || passableArcCount(x, y) <= 1)) {
        
        *retValX = x;
        *retValY = y;
        return true;
    }
    
    // Allocate the grids.
    grid = allocGrid();
    costMap = allocGrid();
    
    // Start with a base of a high number everywhere.
    fillGrid(grid, 30000);
    fillGrid(costMap, 1);
    
    // Block off the pathing blockers.
    getTerrainGrid(costMap, PDS_FORBIDDEN, blockingTerrainFlags, blockingMapFlags);
    if (blockingTerrainFlags & (T_OBSTRUCTS_DIAGONAL_MOVEMENT | T_OBSTRUCTS_PASSABILITY)) {
        getTerrainGrid(costMap, PDS_OBSTRUCTION, T_OBSTRUCTS_DIAGONAL_MOVEMENT, 0);
    }
    
    // Run the distance scan.
    grid[x][y] = 1;
    costMap[x][y] = 1;
    dijkstraScan(grid, costMap, true);
    findReplaceGrid(grid, 30000, 30000, 0);
    
    // Block off invalid targets that aren't pathing blockers.
    getTerrainGrid(grid, 0, forbiddenTerrainFlags, forbiddenMapFlags);
    if (!hallwaysAllowed) {
        getPassableArcGrid(grid, 2, 10, 0);
    }
    
    // Get the solution.
    randomLeastPositiveLocationInGrid(grid, retValX, retValY, deterministic);
    
//    dumpLevelToScreen();
//    displayGrid(grid);
//    if (coordinatesAreInMap(*retValX, *retValY)) {
//        hiliteCell(*retValX, *retValY, &yellow, 100, true);
//    }
//    temporaryMessage("Qualifying path selected:", true);
    
    freeGrid(grid);
    freeGrid(costMap);
    
    // Fall back to a pathing-agnostic alternative if there are no solutions.
    if (*retValX == -1 && *retValY == -1) {
        if (getQualifyingLocNear(loc, x, y, hallwaysAllowed, NULL,
                                 (blockingTerrainFlags | forbiddenTerrainFlags),
                                 (blockingMapFlags | forbiddenMapFlags),
                                 false, deterministic)) {
            *retValX = loc[0];
            *retValY = loc[1];
            return true; // Found a fallback solution.
        } else {
            return false; // No solutions.
        }
    } else {
        return true; // Found a primary solution.
    }
}
Пример #5
0
void pdsBatchInput(pdsMap *map, short **distanceMap, short **costMap, short maxDistance, boolean eightWays) {
	short i, j;
	pdsLink *left, *right;

	map->eightWays = eightWays;

	left = NULL;
	right = NULL;

	map->front.right = NULL;
	for (i=0; i<DCOLS; i++) {
		for (j=0; j<DROWS; j++) {
			pdsLink *link = PDS_CELL(map, i, j);

			if (distanceMap != NULL) {
				link->distance = distanceMap[i][j];
			} else {
				if (costMap != NULL) {
					// totally hackish; refactor
					link->distance = maxDistance;
				}
			}

			int cost;

			if (i == 0 || j == 0 || i == DCOLS - 1 || j == DROWS - 1) {
				cost = PDS_OBSTRUCTION;
			} else if (costMap == NULL) {
				if (cellHasTerrainFlag(i, j, T_OBSTRUCTS_PASSABILITY) && cellHasTerrainFlag(i, j, T_OBSTRUCTS_DIAGONAL_MOVEMENT)) cost = PDS_OBSTRUCTION;
				else cost = PDS_FORBIDDEN;
			} else {
				cost = costMap[i][j];
			}

			link->cost = cost;

			if (cost > 0) {
				if (link->distance < maxDistance) {
					if (right == NULL || right->distance > link->distance) {
						// left and right are used to traverse the list; if many cells have similar values,
						// some time can be saved by not clearing them with each insertion.  this time,
						// sadly, we have to start from the front.

						left = &map->front;
						right = map->front.right;
					}

					while (right != NULL && right->distance < link->distance) {
						left = right;
						right = right->right;
					}

					link->right = right;
					link->left = left;
					left->right = link;
					if (right != NULL) right->left = link;

					left = link;
				} else {
					link->right = NULL;
					link->left = NULL;
				}
			} else {
				link->right = NULL;
				link->left = NULL;
			}
		}
	}
}