/** * 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); }
/** * 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); }
/** * 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. * * 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). */ extern void spread_monsters(char symbol, int depth, int num, int y0, int x0, int dy, int dx) { int i, j; /* Limits on loops */ int count; int y = y0, x = x0; int start_mon_num = m_max; bool dummy; /* Restrict monsters. Allow uniques. */ (void) mon_restrict(symbol, (byte) depth, &dummy, TRUE); /* Set generation level */ monster_level = depth; /* 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 (!in_bounds(y, x)) return; } else { for (j = 0; j < 10; j++) { y = rand_spread(y0, dy); x = rand_spread(x0, dx); if (!in_bounds(y, x)) { if (j < 9) continue; else return; } break; } } /* Require "empty" floor grids */ if (!cave_empty_bold(y, x)) continue; /* Place the monster (sleeping, allow groups, quickly) */ (void) place_monster(y, x, TRUE, TRUE, TRUE); /* Rein in monster groups and escorts a little. */ if (m_max - start_mon_num > num * 2) break; /* Count the monster(s), reset the loop count */ count++; i = 0; } /* Remove monster restrictions. */ (void) mon_restrict('\0', (byte) depth, &dummy, TRUE); /* Reset monster generation level. */ monster_level = p_ptr->danger; }
extern void get_chamber_monsters(int y1, int x1, int y2, int x2) { bool dummy; int i, y, x; s16b monsters_left, depth; char symbol; /* Description of monsters in room */ char *name; /* Get a legal depth. */ depth = p_ptr->danger + randint0(11) - 5; if (depth > 60) depth = 60; if (depth < 5) depth = 5; /* Choose a monster type, using that depth. */ symbol = mon_symbol_at_depth[depth / 5 - 1][randint0(13)]; /* Allow (slightly) tougher monsters. */ depth = p_ptr->danger + (p_ptr->danger < 60 ? p_ptr->danger / 12 : 5); /* Set monster generation restrictions. Describe the monsters. */ name = mon_restrict(symbol, (byte) depth, &dummy, TRUE); /* A default description probably means trouble, so stop. */ if (streq(name, "misc") || !name[0]) return; /* Build the monster probability table. */ if (!get_mon_num(depth)) return; /* No normal monsters. */ generate_mark(y1, x1, y2, x2, CAVE_TEMP); /* Usually, we want 35 monsters. */ monsters_left = 35; /* Fewer monsters near the surface. */ if (p_ptr->danger < 45) monsters_left = 5 + 2 * p_ptr->danger / 3; /* More monsters of kinds that tend to be weak. */ if (strstr("abciBCFKRS", d_char_req)) monsters_left += 15; /* 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 floor square with no monster in it already. */ if (!cave_naked_bold(y, x)) continue; /* Place a single monster. Sleeping 2/3rds of the time. */ place_monster_aux(y, x, get_mon_num_quick(depth), (randint0(3) != 0), FALSE); /* One less monster to place. */ monsters_left--; } /* Remove our restrictions. */ (void) mon_restrict('\0', (byte) depth, &dummy, FALSE); /* Describe */ if (OPT(cheat_room)) { /* Room type */ msg("Room of chambers (%s)", name); } }
/** * Town logic flow for generation of new town * * We start with a fully wiped cave of normal floors. * * Note that town_gen_hack() plays games with the R.N.G. * * This function does NOT do anything about the owners of the stores, * nor the contents thereof. It only handles the physical layout. * * We place the player on the stairs at the same time we make them. * * Hack -- since the player always leaves the dungeon by the stairs, * he is always placed on the stairs, even if he left the dungeon via * word of recall or teleport level. */ static void town_gen(void) { int i, y, x; int residents; int stage = p_ptr->stage; int qy = 0; int qx = 0; int width = DUNGEON_WID / 3; bool dummy; /* Hack - smaller for minor towns */ if ((stage < KHAZAD_DUM_TOWN) && !MAP(DUNGEON) && !MAP(FANILLA)) width /= 2; /* Day time */ if (is_daylight) { /* Number of residents */ residents = MIN_M_ALLOC_TD; } /* Night time or cave */ else { /* Number of residents */ residents = MIN_M_ALLOC_TN; } /* Start with solid walls */ for (y = 0; y < DUNGEON_HGT; y++) { for (x = 0; x < DUNGEON_WID; x++) { /* Create "solid" perma-wall */ cave_set_feat(y, x, FEAT_PERM_SOLID); } } /* Boundary walls (see town_illuminate() */ for (x = qx; x < qx + width; x++) { cave_set_feat(qy, x, FEAT_PERM_INNER); cave_set_feat(qy + (DUNGEON_HGT / 3) - 1, x, FEAT_PERM_INNER); } /* Boundary walls (see town_illuminate() */ for (y = qy; y < qy + (DUNGEON_HGT / 3); y++) { cave_set_feat(y, qx, FEAT_PERM_INNER); cave_set_feat(y, qx + width - 1, FEAT_PERM_INNER); } /* Then place some floors */ for (y = qy + 1; y < qy + (DUNGEON_HGT / 3) - 1; y++) { for (x = qx + 1; x < qx + width - 1; x++) { /* Create empty floor */ cave_set_feat(y, x, FEAT_FLOOR); } } /* Build stuff */ town_gen_hack(); /* Remove restrictions */ (void) mon_restrict('\0', 0, &dummy, FALSE); /* Make some residents */ for (i = 0; i < residents; i++) { /* Make a resident */ (void) alloc_monster(3, TRUE, FALSE); } }