Exemplo n.º 1
0
/*
 * Choose the best direction for "flowing".
 *
 * Note that ghosts and rock-eaters generally don't flow because they can move
 * through obstacles.
 *
 * Monsters first try to use up-to-date distance information ('sound') as
 * saved in cave->squares[y][x].cost.  Failing that, they'll try using scent
 * ('when') which is just old cost information.
 *
 * Tracking by 'scent' means that monsters end up near enough the player to
 * switch to 'sound' (cost), or they end up somewhere the player left via 
 * teleport.  Teleporting away from a location will cause the monsters who
 * were chasing the player to converge on that location as long as the player
 * is still near enough to "annoy" them without being close enough to chase
 * directly.
 */
static bool get_moves_flow(struct chunk *c, struct monster *m_ptr)
{
	int i;

	int best_when = 0;
	int best_cost = 999;
	int best_direction = 0;

	int py = player->py, px = player->px;
	int my = m_ptr->fy, mx = m_ptr->fx;

	/* Only use this algorithm for passwall monsters if near permanent walls,
	 * to avoid getting snagged */
	if (flags_test(m_ptr->race->flags, RF_SIZE, RF_PASS_WALL, RF_KILL_WALL,
				   FLAG_END) && !near_permwall(m_ptr, c))
		return (FALSE);

	/* If the player has never been near this grid, abort */
	if (c->squares[my][mx].when == 0) return FALSE;

	/* Monster is too far away to notice the player */
	if (c->squares[my][mx].cost > z_info->max_flow_depth) return FALSE;
	if (c->squares[my][mx].cost > m_ptr->race->aaf) return FALSE;

	/* If the player can see monster, run towards them */
	if (player_has_los_bold(my, mx)) return FALSE;

	/* Check nearby grids, diagonals first */
	/* This gives preference to the cardinal directions */
	for (i = 7; i >= 0; i--)
	{
		/* Get the location */
		int y = my + ddy_ddd[i];
		int x = mx + ddx_ddd[i];

		/* Ignore unvisited/unpassable locations */
		if (c->squares[y][x].when == 0) continue;

		/* Ignore locations whose data is more stale */
		if (c->squares[y][x].when < best_when) continue;

		/* Ignore locations which are farther away */
		if (c->squares[y][x].cost > best_cost) continue;

		/* Save the cost and time */
		best_when = c->squares[y][x].when;
		best_cost = c->squares[y][x].cost;
		best_direction = i;
	}

	/* Save the location to flow toward */
 	/* We multiply by 16 to angle slightly toward the player's actual location */
	if (best_direction) {
		m_ptr->ty = py + 16 * ddy_ddd[best_direction];
		m_ptr->tx = px + 16 * ddx_ddd[best_direction];
		return TRUE;
	}

	return FALSE;
}
Exemplo n.º 2
0
/**
 * Choose the best direction for "flowing".
 *
 * Note that ghosts and rock-eaters generally don't flow because they can move
 * through obstacles.
 *
 * Monsters first try to use up-to-date distance information ('sound') as
 * saved in cave->squares[y][x].noise.  Failing that, they'll try using scent
 * ('scent') which is just old noise information.
 *
 * Tracking by 'scent' means that monsters end up near enough the player to
 * switch to 'sound' (noise), or they end up somewhere the player left via 
 * teleport.  Teleporting away from a location will cause the monsters who
 * were chasing the player to converge on that location as long as the player
 * is still near enough to "annoy" them without being close enough to chase
 * directly.
 */
static bool get_moves_flow(struct chunk *c, struct monster *mon)
{
	int i;

	int best_scent = 0;
	int best_noise = 999;
	int best_direction = 0;
	bool found_direction = false;

	int py = player->py, px = player->px;
	int my = mon->fy, mx = mon->fx;

	/* Only use this algorithm for passwall monsters if near permanent walls,
	 * to avoid getting snagged */
	if (flags_test(mon->race->flags, RF_SIZE, RF_PASS_WALL, RF_KILL_WALL,
				   FLAG_END) && !near_permwall(mon, c))
		return (false);

	/* The player is not currently near the monster grid */
	if (c->squares[my][mx].scent < c->squares[py][px].scent)
		/* If the player has never been near this grid, abort */
		if (c->squares[my][mx].scent == 0) return false;

	/* Monster is too far away to notice the player */
	if (c->squares[my][mx].noise > z_info->max_flow_depth) return false;
	if (c->squares[my][mx].noise > mon->race->aaf) return false;

	/* If the player can see monster, set target and run towards them */
	if (square_isview(c, my, mx)) {
		mon->ty = player->py;
		mon->tx = player->px;
		return false;
	}

	/* Check nearby grids, diagonals first */
	/* This gives preference to the cardinal directions */
	for (i = 7; i >= 0; i--) {
		/* Get the location */
		int y = my + ddy_ddd[i];
		int x = mx + ddx_ddd[i];

		/* Bounds check */
		if (!square_in_bounds(c, y, x)) continue;

		/* Ignore unvisited/unpassable locations */
		if (c->squares[y][x].scent == 0) continue;

		/* Ignore locations whose data is more stale */
		if (c->squares[y][x].scent < best_scent) continue;

		/* Ignore locations which are farther away */
		if (c->squares[y][x].noise > best_noise) continue;

		/* Ignore lava if they can't handle the heat */
		if (square_isfiery(c, y, x) && !rf_has(mon->race->flags, RF_IM_FIRE))
			continue;

		/* Save the noise and time */
		best_scent = c->squares[y][x].scent;
		best_noise = c->squares[y][x].noise;
		best_direction = i;
		found_direction = true;
	}

	/* Save the location to flow toward */
	/* Multiply by 16 to angle slightly toward the player's actual location */
	if (found_direction) {
		int dy = 0, dx = 0;

		/* Ridiculous - actually multiply by whatever doesn't underflow the 
		 * byte for ty and tx.  Really should do a better solution - NRM */
		for (i = 0; i < 16; i++)
			if ((py + dy > 0) && (px + dx > 0)) {
				dy += ddy_ddd[best_direction];
				dx += ddx_ddd[best_direction];
			}

		mon->ty = py + dy;
		mon->tx = px + dx;
		return true;
	}

	return false;
}