Esempio n. 1
0
/**
 * Attempts to place a monster of the given race at the given location.
 *
 * Note that certain monsters are placed with a large group of
 * identical or similar monsters. However, if `group_okay` is false,
 * then such monsters are placed by themselves.
 *
 * If `sleep` is true, the monster is placed with its default sleep value,
 * which is given in monster.txt.
 *
 * `origin` is the item origin to use for any monster drops (e.g. ORIGIN_DROP,
 * ORIGIN_DROP_PIT, etc.)
 */
bool place_new_monster(struct chunk *c, int y, int x, struct monster_race *race,
					   bool sleep, bool group_okay, byte origin)
{
	struct monster_friends *friends;
	struct monster_friends_base *friends_base;
	int total;

	assert(c);
	assert(race);

	/* Place one monster, or fail */
	if (!place_new_monster_one(c, y, x, race, sleep, origin)) return (false);

	/* We're done unless the group flag is set */
	if (!group_okay) return (true);

	/* Go through friends flags */
	for (friends = race->friends; friends; friends = friends->next) {
		if ((unsigned int)randint0(100) >= friends->percent_chance)
			continue;

		/* Calculate the base number of monsters to place */
		total = damroll(friends->number_dice, friends->number_side);

		place_friends(c, y, x, race, friends->race, total, sleep, origin);

	}

	/* Go through the friends_base flags */
	for (friends_base = race->friends_base; friends_base;
			friends_base = friends_base->next){
		struct monster_race *friends_race;

		/* Check if we pass chance for the monster appearing */
		if ((unsigned int)randint0(100) >= friends_base->percent_chance)
			continue;

		total = damroll(friends_base->number_dice, friends_base->number_side);

		/* Set the escort index base*/
		place_monster_base = friends_base->base;

		/* Prepare allocation table */
		get_mon_num_prep(place_monster_base_okay);

		/* Pick a random race */
		friends_race = get_mon_num(race->level);

		/* Reset allocation table */
		get_mon_num_prep(NULL);

		/* Handle failure */
		if (!friends_race) break;

		place_friends(c, y, x, race, friends_race, total, sleep, origin);
	}

	/* Success */
	return (true);
}
Esempio n. 2
0
/** 
 * Helper function to place monsters that appear as friends or escorts
 */
 bool place_friends(struct cave *c, int y, int x, monster_race *race, 
		monster_race *friends_race, int total, bool sleep, byte origin)
 {
	int level_difference, extra_chance, nx, ny;
	bool is_unique, success = TRUE;
	
	/* Find the difference between current dungeon depth and monster level */
	level_difference = p_ptr->depth - friends_race->level + 5;
	
	/* Handle unique monsters */
	is_unique = rf_has(friends_race->flags, RF_UNIQUE);
	
	/* Make sure the unique hasn't been killed already */
	if (is_unique){
		total = friends_race->cur_num < friends_race->max_num ? 1 : 0;
	}
	
	/* More than 4 levels OoD, no groups allowed */
	if (level_difference <= 0 && !is_unique){
		return FALSE;
	}
	
	/* Reduce group size within 5 levels of natural depth*/
	if (level_difference < 10 && !is_unique){
		extra_chance = (total * level_difference) % 10;
		total = total * level_difference / 10;
		
		/* Instead of flooring the group value, we use the decimal place
		   as a chance of an extra monster */
		if (randint0(10) > extra_chance){
			total += 1;
		}
	}
	
	/* No monsters in this group */
	if (total <= 0){
		return FALSE;
	}
	
	/* Handle friends same as original monster */
	if (race->ridx == friends_race->ridx){
		place_new_monster_group(c, y, x, race, sleep, total, origin);
	}
	
	/* Find a nearby place to put the other groups */
	for (int j = 0; j < 50; j++){
		scatter(&ny, &nx, y, x, GROUP_DISTANCE, FALSE);
		if (cave_isopen(cave, ny, nx)) break;
	}
		
	/* Place the monsters */
	success = place_new_monster_one(ny, nx, friends_race, sleep, origin);
	if (total > 1){
		success = place_new_monster_group(c, ny, nx, friends_race, sleep, total, origin);
	}
	
	return success;
	
}
Esempio n. 3
0
/**
 * Attempts to place a group of monsters of race `r_idx` around
 * the given location. The number of monsters to place is `total`.
 *
 * If `sleep` is true, the monster is placed with its default sleep value,
 * which is given in monster.txt.
 *
 * `origin` is the item origin to use for any monster drops (e.g. ORIGIN_DROP,
 * ORIGIN_DROP_PIT, etc.)
 */
static bool place_new_monster_group(struct chunk *c, int y, int x,
									struct monster_race *race, bool sleep,
									int total, byte origin)
{
	int n, i;

	int hack_n;

	/* x and y coordinates of the placed monsters */
	byte hack_y[GROUP_MAX];
	byte hack_x[GROUP_MAX];

	assert(race);

	/* Start on the monster */
	hack_n = 1;
	hack_x[0] = x;
	hack_y[0] = y;

	/* Puddle monsters, breadth first, up to total */
	for (n = 0; (n < hack_n) && (hack_n < total); n++) {
		/* Grab the location */
		int hx = hack_x[n];
		int hy = hack_y[n];

		/* Check each direction, up to total */
		for (i = 0; (i < 8) && (hack_n < total); i++) {
			int mx = hx + ddx_ddd[i];
			int my = hy + ddy_ddd[i];

			/* Walls and Monsters block flow */
			if (!square_isempty(c, my, mx)) continue;

			/* Attempt to place another monster */
			if (place_new_monster_one(c, my, mx, race, sleep, origin)) {
				/* Add it to the "hack" set */
				hack_y[hack_n] = my;
				hack_x[hack_n] = mx;
				hack_n++;
			}
		}
	}

	/* Success */
	return (true);
}
Esempio n. 4
0
/**
 * Attempts to place a monster of the given race at the given location.
 *
 * Note that certain monsters are placed with a large group of
 * identical or similar monsters. However, if `group_okay` is false,
 * then such monsters are placed by themselves.
 *
 * If `sleep` is true, the monster is placed with its default sleep value,
 * which is given in monster.txt.
 *
 * `origin` is the item origin to use for any monster drops (e.g. ORIGIN_DROP,
 * ORIGIN_DROP_PIT, etc.) 
 *
 * Note the "bizarre" use of non-recursion to prevent annoying output
 * when running a code profiler.
 *
 * Note the use of the "monster allocation table" to restrict
 * the "get_mon_num()" function to "legal" escort types.
 */
bool place_new_monster(struct cave *c, int y, int x, int r_idx, bool sleep,
	bool group_okay, byte origin)
{
	int i;

	monster_race *r_ptr;

	assert(c);
	
	assert(r_idx > 0);
	r_ptr = &r_info[r_idx];
	
	/* Place one monster, or fail */
	if (!place_new_monster_one(y, x, r_ptr, sleep, origin)) return (FALSE);

	/* We're done unless the group flag is set */
	if (!group_okay) return (TRUE);

	/* Friends for certain monsters */
	if (rf_has(r_ptr->flags, RF_FRIEND)) {
		int total = group_size_2(r_ptr);
		(void)place_new_monster_group(c, y, x, r_ptr, sleep, total, origin);
	}

	/* Friends for certain monsters */
	if (rf_has(r_ptr->flags, RF_FRIENDS)) {
		int total = group_size_1(r_ptr);
		(void)place_new_monster_group(c, y, x, r_ptr, sleep, total, origin);
	}

	/* Escorts for certain monsters */
	if (rf_has(r_ptr->flags, RF_ESCORT)) {
		/* Try to place several "escorts" */
		for (i = 0; i < 50; i++) {
			int nx, ny, z, d = 3;
			monster_race *z_ptr;

			/* Pick a location */
			scatter(&ny, &nx, y, x, d, 0);

			/* Require empty grids */
			if (!cave_empty_bold(ny, nx)) continue;

			/* Set the escort index */
			place_monster_idx = r_idx;

			/* Set the escort hook */
			get_mon_num_hook = place_monster_okay;

			/* Prepare allocation table */
			get_mon_num_prep();

			/* Pick a random race */
			z = get_mon_num(r_ptr->level);

			/* Remove restriction */
			get_mon_num_hook = NULL;

			/* Prepare allocation table */
			get_mon_num_prep();

			/* Handle failure */
			if (!z) break;

			/* Place a single escort */
			z_ptr = &r_info[z];
			(void)place_new_monster_one(ny, nx, z_ptr, sleep, origin);

			/* Place a "group" of escorts if needed */
			if (rf_has(z_ptr->flags, RF_FRIEND)) {
				int total = group_size_2(z_ptr);
				(void)place_new_monster_group(c, ny, nx, z_ptr, sleep, total, origin);
			}
			
			if (rf_has(z_ptr->flags, RF_FRIENDS) || rf_has(r_ptr->flags, RF_ESCORTS)) {
				int total = group_size_1(z_ptr);
				(void)place_new_monster_group(c, ny, nx, z_ptr, sleep, total, origin);
			}
		}
	}

	/* Success */
	return (TRUE);
}