/** * Place 'num' sleeping monsters near (x, y). * \param c the current chunk * \param y1 co-ordinates to place the monsters near * \param x1 co-ordinates to place the monsters near * \param depth generation depth * \param num number of monsters to place */ void vault_monsters(struct chunk *c, int y1, int x1, int depth, int num) { int k, i, y, x; /* If the starting location is illegal, don't even start */ if (!square_in_bounds(c, y1, x1)) return; /* Try to summon "num" monsters "near" the given location */ for (k = 0; k < num; k++) { /* Try nine locations */ for (i = 0; i < 9; i++) { int d = 1; /* Pick a nearby location */ scatter(c, &y, &x, y1, x1, d, true); /* Require "empty" floor grids */ if (!square_isempty(c, y, x)) continue; /* Place the monster (allow groups) */ pick_and_place_monster(c, y, x, depth, true, true, ORIGIN_DROP_SPECIAL); break; } } }
/** * Place monsters, up to the number asked for, in a rectangle centered on * y0, x0. Accept values for monster depth, symbol, and maximum vertical * and horizontal displacement. Call monster restriction functions if * needed. * \param c the current chunk being generated * \param type the type of monster (see comments to mon_restrict()) * \param depth selection depth * \param num the number of monsters to try and place - inexact due to groups * \param y0 * \param x0 the centre of the rectangle for monster placement * \param dy * \param dx the dimensions of the rectangle * \param origin the origin for monster drops * * Return prematurely if the code starts looping too much (this may happen * if y0 or x0 are out of bounds, or the area is already occupied). */ void spread_monsters(struct chunk *c, const char *type, int depth, int num, int y0, int x0, int dy, int dx, byte origin) { int i, j; /* Limits on loops */ int count; int y = y0, x = x0; int start_mon_num = c->mon_max; /* Restrict monsters. Allow uniques. Leave area empty if none found. */ if (!mon_restrict(type, depth, true)) return; /* Build the monster probability table. */ if (!get_mon_num(depth)) return; /* Try to summon monsters within our rectangle of effect. */ for (count = 0, i = 0; ((count < num) && (i < 50)); i++) { /* Get a location */ if ((dy == 0) && (dx == 0)) { y = y0; x = x0; if (!square_in_bounds(c, y, x)) return; } else { for (j = 0; j < 10; j++) { y = rand_spread(y0, dy); x = rand_spread(x0, dx); if (!square_in_bounds(c, y, x)) { if (j < 9) continue; else return; } break; } } /* Require "empty" floor grids */ if (!square_isempty(c, y, x)) continue; /* Place the monster (sleeping, allow groups) */ pick_and_place_monster(c, y, x, depth, true, true, origin); /* Rein in monster groups and escorts a little. */ if (c->mon_max - start_mon_num > num * 2) break; /* Count the monster(s), reset the loop count */ count++; i = 0; } /* Remove monster restrictions. */ (void) mon_restrict(NULL, depth, true); }
/** * To avoid rebuilding the monster list too often (which can quickly * get expensive), we handle monsters of a specified race separately. * * \param c the current chunk being generated * \param racial_symbol the allowable monster_base symbols * \param vault_type the type of vault, which affects monster selection depth * \param data the vault text description, which contains the racial symbol * \param y1 the limits of the vault * \param y2 the limits of the vault * \param x1 the limits of the vault * \param x2 the limits of the vault */ void get_vault_monsters(struct chunk *c, char racial_symbol[], char *vault_type, const char *data, int y1, int y2, int x1, int x2) { int i, y, x, depth; const char *t; for (i = 0; racial_symbol[i] != '\0'; i++) { /* Require correct race, allow uniques. */ allow_unique = true; my_strcpy(base_d_char, format("%c", racial_symbol[i]), sizeof(base_d_char)); /* Determine level of monster */ if (strstr(vault_type, "Lesser vault")) depth = player->depth + 2; else if (strstr(vault_type, "Medium vault")) depth = player->depth + 4; else if (strstr(vault_type, "Greater vault")) depth = player->depth + 6; else depth = player->depth; /* Prepare allocation table */ get_mon_num_prep(mon_select); /* Build the monster probability table. */ if (!get_mon_num(depth)) continue; /* Place the monsters */ for (t = data, y = y1; y <= y2; y++) { for (x = x1; x <= x2; x++, t++) { if (*t == racial_symbol[i]) { /* Place a monster */ pick_and_place_monster(c, y, x, depth, false, false, ORIGIN_DROP_SPECIAL); } } } } /* Clear any current monster restrictions. */ get_mon_num_prep(NULL); }
/** * Picks a monster race, makes a new monster of that race, then attempts to * place it in the dungeon at least `dis` away from the player. The monster * race chosen will be appropriate for dungeon level equal to `depth`. * * If `sleep` is true, the monster is placed with its default sleep value, * which is given in monster.txt. * * Returns true if we successfully place a monster. */ bool pick_and_place_distant_monster(struct chunk *c, struct loc loc, int dis, bool sleep, int depth) { int py = loc.y; int px = loc.x; int y = 0, x = 0; int attempts_left = 10000; assert(c); /* Find a legal, distant, unoccupied, space */ while (--attempts_left) { /* Pick a location */ y = randint0(c->height); x = randint0(c->width); /* Require "naked" floor grid */ if (!square_isempty(c, y, x)) continue; /* Do not put random monsters in marked rooms. */ if ((!character_dungeon) && square_ismon_restrict(c, y, x)) continue; /* Accept far away grids */ if (distance(y, x, py, px) > dis) break; } if (!attempts_left) { if (OPT(cheat_xtra) || OPT(cheat_hear)) msg("Warning! Could not allocate a new monster."); return false; } /* Attempt to place the monster, allow groups */ if (pick_and_place_monster(c, y, x, depth, sleep, true, ORIGIN_DROP)) return (true); /* Nope */ return (false); }
/** * Picks a monster race, makes a new monster of that race, then attempts to * place it in the dungeon at least `dis` away from the player. The monster * race chosen will be appropriate for dungeon level equal to `depth`. * * If `sleep` is true, the monster is placed with its default sleep value, * which is given in monster.txt. * * Returns TRUE if we successfully place a monster. */ bool pick_and_place_distant_monster(struct cave *c, struct loc loc, int dis, bool sleep, int depth) { int py = loc.y; int px = loc.x; int y = 0, x = 0; int attempts_left = 10000; assert(c); /* Find a legal, distant, unoccupied, space */ while (--attempts_left) { /* Pick a location */ y = randint0(c->height); x = randint0(c->width); /* Require "naked" floor grid */ if (!cave_isempty(c, y, x)) continue; /* Accept far away grids */ if (distance(y, x, py, px) > dis) break; } if (!attempts_left) { if (OPT(cheat_xtra) || OPT(cheat_hear)) msg("Warning! Could not allocate a new monster."); return FALSE; } /* Attempt to place the monster, allow groups */ if (pick_and_place_monster(c, y, x, depth, sleep, TRUE, ORIGIN_DROP)) return (TRUE); /* Nope */ return (FALSE); }
/** * Funtion for placing appropriate monsters in a room of chambers * * \param c the current chunk being generated * \param y1 the limits of the vault * \param x1 the limits of the vault * \param y2 the limits of the vault * \param x2 the limits of the vault * \param name the name of the monster type for use in mon_select() * \param area the total room area, used for scaling monster quantity */ void get_chamber_monsters(struct chunk *c, int y1, int x1, int y2, int x2, char *name, int area) { int i, y, x; s16b monsters_left, depth; bool random = one_in_(20); /* Get a legal depth. */ depth = c->depth + randint0(11) - 5; /* Choose a pit profile, using that depth. */ if (!random) set_pit_type(depth, 0); /* Allow (slightly) tougher monsters. */ depth = c->depth + (c->depth < 60 ? c->depth / 12 : 5); /* Set monster generation restrictions. Occasionally random. */ if (random) { if (!mon_restrict("random", depth, true)) return; my_strcpy(name, "random", sizeof(name)); } else { if (!mon_restrict(dun->pit_type->name, depth, true)) return; my_strcpy(name, dun->pit_type->name, sizeof(name)); } /* Build the monster probability table. */ if (!get_mon_num(depth)) { (void) mon_restrict(NULL, depth, false); name = NULL; return; } /* No normal monsters. */ generate_mark(c, y1, x1, y2, x2, SQUARE_MON_RESTRICT); /* Allow about a monster every 20-30 grids. */ monsters_left = area / (30 - c->depth / 10); /* Place the monsters. */ for (i = 0; i < 300; i++) { /* Check for early completion. */ if (!monsters_left) break; /* Pick a random in-room square. */ y = y1 + randint0(1 + ABS(y2 - y1)); x = x1 + randint0(1 + ABS(x2 - x1)); /* Require a passable square with no monster in it already. */ if (!square_isempty(c, y, x)) continue; /* Place a single monster. Sleeping 2/3rds of the time. */ pick_and_place_monster(c, y, x, c->depth, (randint0(3) != 0), false, ORIGIN_DROP_SPECIAL); /* One less monster to place. */ monsters_left--; } /* Remove our restrictions. */ (void) mon_restrict(NULL, depth, false); }