/* Places a trap. All traps are untyped until discovered. */ public static void place_trap(Cave c, int y, int x) { Misc.assert(Cave.cave_in_bounds(c, y, x)); Misc.assert(Cave.cave_isempty(c, y, x)); /* Place an invisible trap */ Cave.cave_set_feat(c, y, x, Cave.FEAT_INVIS); }
/** * Create a tunnel connecting a region to one of its nearest neighbors. */ static void join_region(Cave c, int[] colors, int[] counts, int color) { int i; int h = c.height; int w = c.width; int size = h * w; //struct queue *queue = q_new(size); Queue<int> queue = new Queue<int>(); int[] previous = new int[size];//C_ZNEW(size, int); //array_filler(previous, -1, size); for (i = 0; i < size; i++) { previous[i] = -1; if (colors[i] == color) { queue.Enqueue(i); previous[i] = i; } } while (queue.Count() > 0) { int n = queue.Dequeue(); int color2 = colors[n]; if (color2 != 0 && color2 != color) { while (colors[n] != color) { int x, y; lab_toyx(n, w, out y, out x); colors[n] = color; if (!cave_isperm(c, y, x) && !cave_isvault(c, y, x)) { cave_set_feat(c, y, x, FEAT_FLOOR); } n = previous[n]; } fix_colors(colors, counts, color2, color, size); break; } for (i = 0; i < 4; i++) { int y, x, y2, x2, n2; lab_toyx(n, w, out y, out x); y2 = y + yds[i]; x2 = x + xds[i]; /* make sure we stay inside the boundaries */ if (y2 < 0 || y2 >= h) continue; if (x2 < 0 || x2 >= w) continue; /* permanent walls and vault squares should not be handled */ //Nick: the below two were commented out... Did I do that? if (cave_isperm(c, y2, x2)) continue; if (cave_isvault(c, y2, x2)) continue; n2 = lab_toi(y2, x2, w); if (previous[n2] >= 0) continue; queue.Enqueue(n2); previous[n2] = n; } } //q_free(queue); //FREE(previous); }
/** * Build a greater vaults. * * Since Greater Vaults are so large (4x6 blocks, in a 6x18 dungeon) there is * a 63% chance that a randomly chosen quadrant to start a GV on won't work. * To balance this, we give Greater Vaults an artificially high probability * of being attempted, and then in this function use a depth check to cancel * vault creation except at deep depths. * * The following code should make a greater vault with frequencies: * dlvl freq * 100+ 18.0% * 90-99 16.0 - 18.0% * 80-89 10.0 - 11.0% * 70-79 5.7 - 6.5% * 60-69 3.3 - 3.8% * 50-59 1.8 - 2.1% * 0-49 0.0 - 1.0% */ static bool build_greater_vault(Cave c, int y0, int x0) { throw new NotImplementedException(); //int i; //int numerator = 2; //int denominator = 3; ///* Only try to build a GV as the first room. */ //if (dun.cent_n > 0) return false; ///* Level 90+ has a 2/3 chance, level 80-89 has 4/9, ... */ //for(i = 90; i > c.depth; i -= 10) { // numerator *= 2; // denominator *= 3; //} ///* Attempt to pass the depth check and build a GV */ //if (randint0(denominator) >= numerator) return false; //return build_vault_type(c, y0, x0, 8, "Greater vault"); }
//#if 0 /* XXX d_m - is this meant to be in use? */ //static void glow_point(Cave c, int y, int x) { // int i, j; // for (i = -1; i <= -1; i++) // for (j = -1; j <= -1; j++) // c.info[y + i][x + j] |= CAVE_GLOW; //} //#endif /** * Color a particular point, and all adjacent points. */ static void build_color_point(Cave c, int[] colors, int[] counts, int y, int x, int color, bool diagonal) { int h = c.height; int w = c.width; int size = h * w; //struct queue *queue = q_new(size); Queue<int> queue = new Queue<int>(); int dslimit = diagonal ? 8 : 4; int[] added = new int[size];//C_ZNEW(size, int); for(int i = 0; i < added.Length; i++) { added[i] = 0; } //array_filler(added, 0, size); queue.Enqueue(lab_toi(y, x, w)); counts[color] = 0; while (queue.Count() > 0) { int i, y2, x2; int n2 = queue.Dequeue(); lab_toyx(n2, w, out y2, out x2); if (ignore_point(cave, colors, y2, x2)) continue; colors[n2] = color; counts[color]++; /*if (lit) glow_point(c, y2, x2);*/ for (i = 0; i < dslimit; i++) { int y3 = y2 + yds[i]; int x3 = x2 + xds[i]; int n3 = lab_toi(y3, x3, w); if (ignore_point(cave, colors, y3, x3)) continue; if (added[n3] != 0) continue; queue.Enqueue(n3); added[n3] = 1; } } //FREE(added); //q_free(queue); }
//static void fill_xrange(Cave c, int y, int x1, int x2, int feat, int info) { // int x; // for (x = x1; x <= x2; x++) { // cave_set_feat(c, y, x, feat); // c.info[y][x] |= info; // } //} //static void fill_yrange(Cave c, int x, int y1, int y2, int feat, int info) { // int y; // for (y = y1; y <= y2; y++) { // cave_set_feat(c, y, x, feat); // c.info[y][x] |= info; // } //} //static void fill_circle(Cave c, int y0, int x0, int radius, int border, int feat, int info) { // int i, last = 0; // int r2 = radius * radius; // for(i = 0; i <= radius; i++) { // double j = sqrt(r2 - (i * i)); // int k = (int)(j + 0.5); // int b = border; // if (border && last > k) b++; // fill_xrange(c, y0 - i, x0 - k - b, x0 + k + b, feat, info); // fill_xrange(c, y0 + i, x0 - k - b, x0 + k + b, feat, info); // fill_yrange(c, x0 - i, y0 - k - b, y0 + k + b, feat, info); // fill_yrange(c, x0 + i, y0 - k - b, y0 + k + b, feat, info); // last = k; // } //} ///** // * Fill the lines of a cross/plus with a feature. // * // * The boundaries (y1, x1, y2, x2) are inclusive. When combined with // * draw_rectangle() this will generate a large rectangular room which is split // * into four sub-rooms. // */ //static void generate_plus(Cave c, int y1, int x1, int y2, int x2, int feat) { // int y, x; // /* Find the center */ // int y0 = (y1 + y2) / 2; // int x0 = (x1 + x2) / 2; // assert(c); // for (y = y1; y <= y2; y++) cave_set_feat(c, y, x0, feat); // for (x = x1; x <= x2; x++) cave_set_feat(c, y0, x, feat); //} ///** // * Generate helper -- open all sides of a rectangle with a feature // */ //static void generate_open(Cave c, int y1, int x1, int y2, int x2, int feat) { // int y0, x0; // /* Center */ // y0 = (y1 + y2) / 2; // x0 = (x1 + x2) / 2; // /* Open all sides */ // cave_set_feat(c, y1, x0, feat); // cave_set_feat(c, y0, x1, feat); // cave_set_feat(c, y2, x0, feat); // cave_set_feat(c, y0, x2, feat); //} ///** // * Generate helper -- open one side of a rectangle with a feature // */ //static void generate_hole(Cave c, int y1, int x1, int y2, int x2, int feat) { // /* Find the center */ // int y0 = (y1 + y2) / 2; // int x0 = (x1 + x2) / 2; // assert(c); // /* Open random side */ // switch (randint0(4)) { // case 0: cave_set_feat(c, y1, x0, feat); break; // case 1: cave_set_feat(c, y0, x1, feat); break; // case 2: cave_set_feat(c, y2, x0, feat); break; // case 3: cave_set_feat(c, y0, x2, feat); break; // } //} /** * Build a circular room (interior radius 4-7). */ static bool build_circular(Cave c, int y0, int x0) { throw new NotImplementedException(); ///* Pick a room size */ //int radius = 2 + Random.randint1(2) + Random.randint1(3); ///* Occasional light */ //bool light = c.depth <= Random.randint1(25) ? true : false; ///* Mark interior squares as being in a room (optionally lit) */ //int info = CAVE_ROOM | (light ? CAVE_GLOW : 0); ///* Generate outer walls and inner floors */ //fill_circle(c, y0, x0, radius + 1, 1, FEAT_WALL_OUTER, info); //fill_circle(c, y0, x0, radius, 0, FEAT_FLOOR, info); ///* Especially large circular rooms will have a middle chamber */ //if (radius - 4 > 0 && Random.randint0(4) < radius - 4) { // /* choose a random direction */ // int cd, rd; // Random.rand_dir(&rd, &cd); // /* draw a room with a secret door on a random side */ // draw_rectangle(c, y0 - 2, x0 - 2, y0 + 2, x0 + 2, FEAT_WALL_INNER); // cave_set_feat(c, y0 + cd * 2, x0 + rd * 2, FEAT_SECRET); // /* Place a treasure in the vault */ // vault_objects(c, y0, x0, c.depth, Random.randint0(2)); // /* create some monsterss */ // vault_monsters(c, y0, x0, c.depth + 1, Random.randint0(3)); //} //return true; }
/** * Allocates 'num' random objects in the dungeon. * * See alloc_object() for more information. */ static void alloc_objects(Cave c, int set, int typ, int num, int depth, Origin origin) { int k; int l = 0; for (k = 0; k < num; k++) { bool ok = alloc_object(c, set, typ, depth, origin); if (!ok) l++; } }
/** * Place a random door at (x, y). * * The door generated could be closed, open, broken, or secret. */ public static void place_random_door(Cave c, int y, int x) { int tmp = Random.randint0(100); if (tmp < 30) cave_set_feat(c, y, x, FEAT_OPEN); else if (tmp < 40) cave_set_feat(c, y, x, FEAT_BROKEN); else if (tmp < 60) cave_set_feat(c, y, x, FEAT_SECRET); else place_closed_door(c, y, x); }
/** * Place a random amount of gold at (x, y). */ public static void place_gold(Cave c, int y, int x, int level, Origin origin) { Object.Object i_ptr; //object_type object_type_body; Misc.assert(cave_in_bounds(c, y, x)); if (!cave_canputitem(c, y, x)) return; //i_ptr = &object_type_body; //object_wipe(i_ptr); i_ptr = new Object.Object(); Object.Object.make_gold(ref i_ptr, level, (int)SVal.sval_gold.SV_GOLD_ANY); i_ptr.origin = origin; i_ptr.origin_depth = (byte)level; Object.Object.floor_carry(c, y, x, i_ptr); }
/** * Place rubble at (x, y). */ static void place_rubble(Cave c, int y, int x) { cave_set_feat(c, y, x, FEAT_RUBBLE); }
/** * Place hidden squares that will be used to generate feeling */ static void place_feeling(Cave c) { int y,x,i,j; int tries = 500; for (i = 0; i < FEELING_TOTAL; i++){ for(j = 0; j < tries; j++){ /* Pick a random dungeon coordinate */ y = Random.randint0(DUNGEON_HGT); x = Random.randint0(DUNGEON_WID); /* Check to see if it is not a wall */ if (cave_iswall(c,y,x)) continue; /* Check to see if it is already marked */ if (cave_isfeel(c,y,x)) continue; /* Set the cave square appropriately */ c.info2[y][x] |= CAVE2_FEEL; break; } } /* Reset number of feeling squares */ c.feeling_squares = 0; }
/** * Return how many cardinal directions around (x, y) contain walls. */ static int next_to_walls(Cave c, int y, int x) { int k = 0; Misc.assert(cave_in_bounds(c, y, x)); if (cave_iswall(c, y + 1, x)) k++; if (cave_iswall(c, y - 1, x)) k++; if (cave_iswall(c, y, x + 1)) k++; if (cave_iswall(c, y, x - 1)) k++; return k; }
/** * Count the number of corridor grids adjacent to the given grid. * * This routine currently only counts actual "empty floor" grids which are not * in rooms. * * TODO: count stairs, open doors, closed doors? */ static int next_to_corr(Cave c, int y1, int x1) { int i, k = 0; Misc.assert(cave_in_bounds(c, y1, x1)); /* Scan adjacent grids */ for (i = 0; i < 4; i++) { /* Extract the location */ int y = y1 + Misc.ddy_ddd[i]; int x = x1 + Misc.ddx_ddd[i]; /* Count only floors which aren't part of rooms */ if (cave_isfloor(c, y, x) && !cave_isroom(c, y, x)) k++; } /* Return the number of corridors */ return k; }
/** * Place the player at a random starting location. */ static void new_player_spot(Cave c, Player.Player p) { int y, x; /* Try to find a good place to put the player */ cave_find_in_range(c, out y, 0, c.height, out x, 0, c.width, cave_isstart); /* Create stairs the player came down if allowed and necessary */ if (Option.birth_no_stairs.value) { } else if (p.create_down_stair) { cave_set_feat(c, y, x, FEAT_MORE); p.create_down_stair = false; } else if (p.create_up_stair) { cave_set_feat(c, y, x, FEAT_LESS); p.create_up_stair = false; } Monster_Make.player_place(c, p, y, x); }
///** // * Given an adjoining wall (a wall which separates two labyrinth cells) // * set a and b to point to the cell indices which are separated. Used by // * labyrinth_gen(). // */ //static void lab_get_adjoin(int i, int w, int *a, int *b) { // int y, x; // lab_toyx(i, w, &y, &x); // if (x % 2 == 0) { // *a = lab_toi(y - 1, x, w); // *b = lab_toi(y + 1, x, w); // } else { // *a = lab_toi(y, x - 1, w); // *b = lab_toi(y, x + 1, w); // } //} ///** // * Return whether (x, y) is in a tunnel. // * // * For our purposes a tunnel is a horizontal or vertical path, not an // * intersection. Thus, we want the squares on either side to walls in one // * case (e.g. up/down) and open in the other case (e.g. left/right). We don't // * want a square that represents an intersection point. // * // * The high-level idea is that these are squares which can't be avoided (by // * walking diagonally around them). // */ //static bool lab_is_tunnel(Cave c, int y, int x) { // bool west = cave_isopen(c, y, x - 1); // bool east = cave_isopen(c, y, x + 1); // bool north = cave_isopen(c, y - 1, x); // bool south = cave_isopen(c, y + 1, x); // return north == south && west == east && north != west; //} /** * Build a labyrinth level. * * Note that if the function returns false, a level wasn't generated. * Labyrinths use the dungeon level's number to determine whether to generate * themselves (which means certain level numbers are more likely to generate * labyrinths than others). */ static bool labyrinth_gen(Cave c, Player.Player p) { int i, j, k, y, x; /* Size of the actual labyrinth part must be odd. */ /* NOTE: these are not the actual dungeon size, but rather the size of the * area we're genearting a labyrinth in (which doesn't count theh enclosing * outer walls. */ int h = 15 + Random.randint0(c.depth / 10) * 2; int w = 51 + Random.randint0(c.depth / 10) * 2; /* This is the number of squares in the labyrinth */ int n = h * w; /* NOTE: 'sets' and 'walls' are too large... we only need to use about * 1/4 as much memory. However, in that case, the addressing math becomes * a lot more complicated, so let's just stick with this because it's * easier to read. */ /* 'sets' tracks connectedness; if sets[i] == sets[j] then cells i and j * are connected to each other in the maze. */ int[] sets; /* 'walls' is a list of wall coordinates which we will randomize */ int[] walls; /* Most labyrinths are lit */ bool lit = Random.randint0(c.depth) < 25 || Random.randint0(2) < 1; /* Many labyrinths are known */ bool known = lit && Random.randint0(c.depth) < 25; /* Most labyrinths have soft (diggable) walls */ bool soft = Random.randint0(c.depth) < 35 || Random.randint0(3) < 2; /* There's a base 1 in 100 to accept the labyrinth */ int chance = 1; /* If we're too shallow then don't do it */ if (c.depth < 13) return false; /* Don't try this on quest levels, kids... */ if (is_quest(c.depth)) return false; /* Certain numbers increase the chance of having a labyrinth */ if (c.depth % 3 == 0) chance += 1; if (c.depth % 5 == 0) chance += 1; if (c.depth % 7 == 0) chance += 1; if (c.depth % 11 == 0) chance += 1; if (c.depth % 13 == 0) chance += 1; /* Only generate the level if we pass a check */ /* NOTE: This test gets performed after we pass the test to use the * labyrinth cave profile. */ if (Random.randint0(100) >= chance) return false; /* allocate our arrays */ sets = new int[n]; walls = new int[n]; /* This is the dungeon size, which does include the enclosing walls */ set_cave_dimensions(c, h + 2, w + 2); /* Fill whole level with perma-rock */ fill_rectangle(c, 0, 0, DUNGEON_HGT - 1, DUNGEON_WID - 1, FEAT_PERM_SOLID); /* Fill the labyrinth area with rock */ fill_rectangle(c, 1, 1, h, w, soft ? FEAT_WALL_SOLID : FEAT_PERM_SOLID); /* Initialize each wall. */ for (i = 0; i < n; i++) { walls[i] = i; sets[i] = -1; } /* Cut out a grid of 1x1 rooms which we will call "cells" */ for (y = 0; y < h; y += 2) { for (x = 0; x < w; x += 2) { int k2 = lab_toi(y, x, w); sets[k2] = k2; cave_set_feat(c, y + 1, x + 1, FEAT_FLOOR); if (lit) c.info[y + 1][x + 1] |= CAVE_GLOW; } } throw new NotImplementedException(); ///* Shuffle the walls, using Knuth's shuffle. */ //shuffle(walls, n); ///* For each adjoining wall, look at the cells it divides. If they aren't // * in the same set, remove the wall and join their sets. // * // * This is a randomized version of Kruskal's algorithm. */ //for (i = 0; i < n; i++) { // int a, b, x, y; // j = walls[i]; // /* If this cell isn't an adjoining wall, skip it */ // lab_toyx(j, w, &y, &x); // if ((x < 1 && y < 1) || (x > w - 2 && y > h - 2)) continue; // if (x % 2 == y % 2) continue; // /* Figure out which cells are separated by this wall */ // lab_get_adjoin(j, w, &a, &b); // /* If the cells aren't connected, kill the wall and join the sets */ // if (sets[a] != sets[b]) { // int sa = sets[a]; // int sb = sets[b]; // cave_set_feat(c, y + 1, x + 1, FEAT_FLOOR); // if (lit) c.info[y + 1][x + 1] |= CAVE_GLOW; // for (k = 0; k < n; k++) { // if (sets[k] == sb) sets[k] = sa; // } // } //} ///* Determine the character location */ //new_player_spot(c, p); ///* The level should have exactly one down and one up staircase */ //if (OPT(birth_no_stairs)) { // /* new_player_spot() won't have created stairs, so make both*/ // alloc_stairs(c, FEAT_MORE, 1, 3); // alloc_stairs(c, FEAT_LESS, 1, 3); //} else if (p.create_down_stair) { // /* new_player_spot() will have created down, so only create up */ // alloc_stairs(c, FEAT_LESS, 1, 3); //} else { // /* new_player_spot() will have created up, so only create down */ // alloc_stairs(c, FEAT_MORE, 1, 3); //} ///* Generate a door for every 100 squares in the labyrinth */ //for (i = n / 100; i > 0; i--) { // /* Try 10 times to find a useful place for a door, then place it */ // for (j = 0; j < 10; j++) { // find_empty(c, &y, &x); // if (lab_is_tunnel(c, y, x)) break; // } // place_closed_door(c, y, x); //} ///* General some rubble, traps and monsters */ //k = MAX(MIN(c.depth / 3, 10), 2); ///* Scale number of monsters items by labyrinth size */ //k = (3 * k * (h * w)) / (DUNGEON_HGT * DUNGEON_WID); ///* Put some rubble in corridors */ //alloc_objects(c, SET_BOTH, TYP_RUBBLE, randint1(k), c.depth, 0); ///* Place some traps in the dungeon */ //alloc_objects(c, SET_BOTH, TYP_TRAP, randint1(k), c.depth, 0); ///* Put some monsters in the dungeon */ //for (i = MIN_M_ALLOC_LEVEL + randint1(8) + k; i > 0; i--) // pick_and_place_distant_monster(c, loc(p.px, p.py), 0, true, c.depth); ///* Put some objects/gold in the dungeon */ //alloc_objects(c, SET_BOTH, TYP_OBJECT, Rand_normal(6, 3), c.depth, // ORIGIN_LABYRINTH); //alloc_objects(c, SET_BOTH, TYP_GOLD, Rand_normal(6, 3), c.depth, // ORIGIN_LABYRINTH); //alloc_objects(c, SET_BOTH, TYP_GOOD, randint0(2), c.depth, // ORIGIN_LABYRINTH); ///* Unlit labyrinths will have some good items */ //if (!lit) // alloc_objects(c, SET_BOTH, TYP_GOOD, Rand_normal(3, 2), c.depth, // ORIGIN_LABYRINTH); ///* Hard (non-diggable) labyrinths will have some great items */ //if (!soft) // alloc_objects(c, SET_BOTH, TYP_GREAT, Rand_normal(2, 1), c.depth, // ORIGIN_LABYRINTH); ///* If we want the players to see the maze layout, do that now */ //if (known) wiz_light(); ///* Deallocate our lists */ //FREE(sets); //FREE(walls); //return true; }
/** * Start connecting regions, stopping when the cave is entirely connected. */ static void join_regions(Cave c, int[] colors, int[] counts) { int h = c.height; int w = c.width; int size = h * w; int num = count_colors(counts, size); while (num > 1) { int color = first_color(counts, size); join_region(c, colors, counts, color); num--; } }
/** * Locate a square in y1 <= y < y2, x1 <= x < x2 which satisfies the given * predicate. */ static void _find_in_range(Cave c, out int y, int y1, int y2, out int x, int x1, int x2, int[] squares, cave_predicate_func pred) { int yd = y2 - y1; int xd = x2 - x1; int i, n = yd * xd; bool done = false; x = 0; y = 0; /* Test each square in (random) order for openness */ for (i = 0; i < n && !done; i++) { int j = Random.randint0(n - i) + i; int k = squares[j]; squares[j] = squares[i]; squares[i] = k; y = (k / xd) + y1; x = (k % xd) + x1; if (pred(c, y, x)) done = true; } /* Deallocate memory, make sure we found an empty square, and return */ Misc.assert(done); }
///** // * Place a secret door at (x, y). // */ //void place_secret_door(Cave c, int y, int x) { // cave_set_feat(c, y, x, FEAT_SECRET); //} /** * Place a closed door at (x, y). */ public static void place_closed_door(Cave c, int y, int x) { int tmp = Random.randint0(400); if (tmp < 300) cave_set_feat(c, y, x, FEAT_DOOR_HEAD + 0x00); else if (tmp < 399) cave_set_feat(c, y, x, FEAT_DOOR_HEAD + Random.randint1(7)); else cave_set_feat(c, y, x, FEAT_DOOR_HEAD + 0x08 + Random.randint0(8)); }
/** * Place stairs (of the requested type 'feat' if allowed) at (x, y). * * All stairs from town go down. All stairs on an unfinished quest level go up. */ static void place_stairs(Cave c, int y, int x, int feat) { if (c.depth == 0) cave_set_feat(c, y, x, FEAT_MORE); else if (is_quest(c.depth) || c.depth >= Misc.MAX_DEPTH - 1) cave_set_feat(c, y, x, FEAT_LESS); else cave_set_feat(c, y, x, feat); }
///** // * Place random stairs at (x, y). // */ //static void place_random_stairs(Cave c, int y, int x) { // int feat = randint0(100) < 50 ? FEAT_LESS : FEAT_MORE; // if (cave_canputitem(c, y, x)) // place_stairs(c, y, x, feat); //} /** * Place a random object at (x, y). */ public static void place_object(Cave c, int y, int x, int level, bool good, bool great, Origin origin) { int rating = 0; Object.Object otype; Misc.assert(cave_in_bounds(c, y, x)); if (!cave_canputitem(c, y, x)) return; otype = new Object.Object(); //object_wipe(&otype); if (!Object.Object.make_object(c, ref otype, level, good, great, ref rating)) return; otype.origin = origin; otype.origin_depth = (byte)c.depth; /* Give it to the floor */ /* XXX Should this be done in floor_carry? */ if (Object.Object.floor_carry(c, y, x, otype) == 0) { if (otype.artifact != null) otype.artifact.created = false; return; } else { if (otype.artifact != null) c.good_item = true; c.obj_rating += (uint)rating; } }
/** * Returns whether a doorway can be built in a space. * * To have a doorway, a space must be adjacent to at least two corridors and be * between two walls. */ static bool possible_doorway(Cave c, int y, int x) { Misc.assert(cave_in_bounds(c, y, x)); if (next_to_corr(c, y, x) < 2) return false; if (cave_isstrongwall(c, y - 1, x) && cave_isstrongwall(c, y + 1, x)) return true; if (cave_isstrongwall(c, y, x - 1) && cave_isstrongwall(c, y, x + 1)) return true; return false; }
/** * Allocates a single random object in the dungeon. * * 'set' controls where the object is placed (corridor, room, either). * 'typ' conrols the kind of object (rubble, trap, gold, item). */ static bool alloc_object(Cave c, int set, int typ, int depth, Origin origin) { int x = 0, y = 0; int tries = 0; bool room; /* Pick a "legal" spot */ while (tries < 2000) { tries++; find_empty(c, out y, out x); /* See if our spot is in a room or not */ room = (c.info[y][x] & CAVE_ROOM) != 0 ? true : false; /* If we are ok with a corridor and we're in one, we're done */ if ((set & SET_CORR) != 0 && !room) break; /* If we are ok with a room and we're in one, we're done */ if ((set & SET_ROOM) != 0 && room) break; } if (tries == 2000) return false; /* Place something */ switch (typ) { case TYP_RUBBLE: place_rubble(c, y, x); break; case TYP_TRAP: Trap.place_trap(c, y, x); break; case TYP_GOLD: place_gold(c, y, x, depth, origin); break; case TYP_OBJECT: place_object(c, y, x, depth, false, false, origin); break; case TYP_GOOD: place_object(c, y, x, depth, true, false, origin); break; case TYP_GREAT: place_object(c, y, x, depth, true, true, origin); break; } return true; }
/** * Attempt to build a room of the given type at the given block * * Note that we restrict the number of "crowded" rooms to reduce * the chance of overflowing the monster list during level creation. */ static bool room_build(Cave c, int by0, int bx0, room_profile profile) { /* Extract blocks */ int by1 = by0; int bx1 = bx0; int by2 = by0 + profile.height; int bx2 = bx0 + profile.width; int allocated; int y, x; int by, bx; /* Enforce the room profile's minimum depth */ if (c.depth < profile.level) return false; /* Only allow one crowded room per level */ if (dun.crowded && profile.crowded) return false; /* Never run off the screen */ if (by1 < 0 || by2 >= dun.row_rooms) return false; if (bx1 < 0 || bx2 >= dun.col_rooms) return false; /* Verify open space */ for (by = by1; by <= by2; by++) { for (bx = bx1; bx <= bx2; bx++) { if (true) { /* previous rooms prevent new ones */ if (dun.room_map[by, bx]) return false; } else { return false; /* XYZ */ } } } /* Get the location of the room */ y = ((by1 + by2 + 1) * BLOCK_HGT) / 2; x = ((bx1 + bx2 + 1) * BLOCK_WID) / 2; /* Try to build a room */ if (!profile.builder(c, y, x)) return false; /* Save the room location */ if (dun.cent_n < CENT_MAX) { dun.cent[dun.cent_n] = new Loc(); dun.cent[dun.cent_n].y = y; dun.cent[dun.cent_n].x = x; dun.cent_n++; } /* Reserve some blocks */ allocated = 0; for (by = by1; by < by2; by++) { for (bx = bx1; bx < bx2; bx++) { dun.room_map[by, bx] = true; allocated++; } } /* Count "crowded" rooms */ if (profile.crowded) dun.crowded = true; /* Success */ return true; }
///** // * Chooses a vault of a particular kind at random. // * // * Each vault has equal probability of being chosen. One weird thing is that // * currently the v.typ indices are one off from the room type indices, which // * means that build_greater_vault will call this function with "typ=8". // * // * TODO: Fix the weird type-off-by-one issue. // */ //struct vault *random_vault(int typ) { // struct vault *v = vaults; // struct vault *r = null; // int n = 1; // do { // if (v.typ == typ) { // if (one_in_(n)) r = v; // n++; // } // v = v.next; // } while(v); // return r; //} /** * Place some staircases near walls. */ static void alloc_stairs(Cave c, int feat, int num, int walls) { int y, x, i, j; bool done; /* Place "num" stairs */ for (i = 0; i < num; i++) { /* Place some stairs */ for (done = false; !done; ) { /* Try several times, then decrease "walls" */ for (j = 0; !done && j <= 1000; j++) { find_empty(c, out y, out x); if (next_to_walls(c, y, x) < walls) continue; place_stairs(c, y, x, feat); done = true; } /* Require fewer walls */ if (walls != 0) walls--; } } }
static void set_cave_dimensions(Cave c, int h, int w) { int i, n = h * w; c.height = h; c.width = w; if(cave_squares != null) cave_squares = null; cave_squares = new int[n]; for (i = 0; i < n; i++) cave_squares[i] = i; }
/** * Create a color for each "NESW contiguous" region of the dungeon. */ static void build_colors(Cave c, int[] colors, int[] counts, bool diagonal) { int y, x; int h = c.height; int w = c.width; int color = 1; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { if (ignore_point(cave, colors, y, x)) continue; build_color_point(cave, colors, counts, y, x, color, diagonal); color++; } } }
/** * Town logic flow for generation of new town. * * We start with a fully wiped cave of normal floors. This function does NOT do * anything about the owners of the stores, nor the contents thereof. It only * handles the physical layout. */ static bool town_gen(Cave c, Player.Player p) { int i; bool daytime = Misc.turn % (10 * TOWN_DAWN) < (10 * TOWN_DUSK); int residents = daytime ? MIN_M_ALLOC_TD : MIN_M_ALLOC_TN; Misc.assert(c != null); set_cave_dimensions(c, TOWN_HGT, TOWN_WID); /* NOTE: We can't use c.height and c.width here because then there'll be * a bunch of empty space in the level that monsters might spawn in (or * teleport might take you to, or whatever). * * TODO: fix this to use c.height and c.width when all the 'choose * random location' things honor them. */ /* Start with solid walls, and then create some floor in the middle */ fill_rectangle(c, 0, 0, DUNGEON_HGT - 1, DUNGEON_WID - 1, FEAT_PERM_SOLID); fill_rectangle(c, 1, 1, c.height -2, c.width - 2, FEAT_FLOOR); /* Build stuff */ town_gen_hack(c, p); /* Apply illumination */ cave_illuminate(c, daytime); /* Make some residents */ for (i = 0; i < residents; i++) Monster_Make.pick_and_place_distant_monster(c, new Loc(p.px, p.py), 3, true, c.depth); return true; }
/** * Builds a cross-shaped room. * * Room "a" runs north/south, and Room "b" runs east/east * So a "central pillar" would run from x1a,y1b to x2a,y2b. * * Note that currently, the "center" is always 3x3, but I think that the code * below will work for 5x5 (and perhaps even for unsymetric values like 4x3 or * 5x3 or 3x4 or 3x5). */ static bool build_crossed(Cave c, int y0, int x0) { throw new NotImplementedException(); //int y, x; //int y1a, x1a, y2a, x2a; //int y1b, x1b, y2b, x2b; //int dy, dx, wy, wx; //int light = false; ///* Occasional light */ //if (c.depth <= randint1(25)) light = true; ///* Pick inner dimension */ //wy = 1; //wx = 1; ///* Pick outer dimension */ //dy = rand_range(3, 4); //dx = rand_range(3, 11); ///* Determine extents of room (a) */ //y1a = y0 - dy; //x1a = x0 - wx; //y2a = y0 + dy; //x2a = x0 + wx; ///* Determine extents of room (b) */ //y1b = y0 - wy; //x1b = x0 - dx; //y2b = y0 + wy; //x2b = x0 + dx; ///* Generate new room (a) */ //generate_room(c, y1a-1, x1a-1, y2a+1, x2a+1, light); ///* Generate new room (b) */ //generate_room(c, y1b-1, x1b-1, y2b+1, x2b+1, light); ///* Generate outer walls (a) */ //draw_rectangle(c, y1a-1, x1a-1, y2a+1, x2a+1, FEAT_WALL_OUTER); ///* Generate outer walls (b) */ //draw_rectangle(c, y1b-1, x1b-1, y2b+1, x2b+1, FEAT_WALL_OUTER); ///* Generate inner floors (a) */ //fill_rectangle(c, y1a, x1a, y2a, x2a, FEAT_FLOOR); ///* Generate inner floors (b) */ //fill_rectangle(c, y1b, x1b, y2b, x2b, FEAT_FLOOR); ///* Special features */ //switch (randint1(4)) { // /* Nothing */ // case 1: break; // /* Large solid middle pillar */ // case 2: { // fill_rectangle(c, y1b, x1a, y2b, x2a, FEAT_WALL_INNER); // break; // } // /* Inner treasure vault */ // case 3: { // /* Generate a small inner vault */ // draw_rectangle(c, y1b, x1a, y2b, x2a, FEAT_WALL_INNER); // /* Open the inner vault with a secret door */ // generate_hole(c, y1b, x1a, y2b, x2a, FEAT_SECRET); // /* Place a treasure in the vault */ // place_object(c, y0, x0, c.depth, false, false, ORIGIN_SPECIAL); // /* Let's guard the treasure well */ // vault_monsters(c, y0, x0, c.depth + 2, randint0(2) + 3); // /* Traps naturally */ // vault_traps(c, y0, x0, 4, 4, randint0(3) + 2); // break; // } // /* Something else */ // case 4: { // if (one_in_(3)) { // /* Occasionally pinch the center shut */ // /* Pinch the east/west sides */ // for (y = y1b; y <= y2b; y++) { // if (y == y0) continue; // cave_set_feat(c, y, x1a - 1, FEAT_WALL_INNER); // cave_set_feat(c, y, x2a + 1, FEAT_WALL_INNER); // } // /* Pinch the north/south sides */ // for (x = x1a; x <= x2a; x++) { // if (x == x0) continue; // cave_set_feat(c, y1b - 1, x, FEAT_WALL_INNER); // cave_set_feat(c, y2b + 1, x, FEAT_WALL_INNER); // } // /* Open sides with secret doors */ // if (one_in_(3)) // generate_open(c, y1b-1, x1a-1, y2b+1, x2a+1, FEAT_SECRET); // } else if (one_in_(3)) { // /* Occasionally put a "plus" in the center */ // generate_plus(c, y1b, x1a, y2b, x2a, FEAT_WALL_INNER); // } else if (one_in_(3)) { // /* Occasionally put a "pillar" in the center */ // cave_set_feat(c, y0, x0, FEAT_WALL_INNER); // } // break; // } //} //return true; }
/** * Generate the "consistent" town features, and place the player * * HACK: We seed the simple RNG, so we always get the same town layout, * including the size and shape of the buildings, the locations of the * doorways, and the location of the stairs. This means that if any of the * functions used to build the town change the way they use the RNG, the * town layout will be generated differently. * * XXX: Remove this gross hack when this piece of code is fully reentrant - * i.e., when all we need to do is swing a pointer to change caves, we just * need to generate the town once (we will also need to save/load the town). */ static void town_gen_hack(Cave c, Player.Player p) { int y, x, n, k; int[] rooms = new int[(int)STORE.MAX_STORES]; int n_rows = 2; int n_cols = ((int)STORE.MAX_STORES + 1) / n_rows; /* Switch to the "simple" RNG and use our original town seed */ Random.Rand_quick = true; Random.Rand_value = (uint)Misc.seed_town; /* Prepare an Array of "remaining stores", and count them */ for (n = 0; n < (int)STORE.MAX_STORES; n++) rooms[n] = n; /* Place rows of stores */ for (y = 0; y < n_rows; y++) { for (x = 0; x < n_cols; x++) { if (n < 1) break; /* Pick a remaining store */ k = Random.randint0(n); /* Build that store at the proper location */ build_store(c, rooms[k], y, x); /* Shift the stores down, remove one store */ rooms[k] = rooms[--n]; } } /* Place the stairs */ find_empty_range(c, out y, 3, TOWN_HGT - 3, out x, 3, TOWN_WID - 3); /* Clear previous contents, add down stairs */ cave_set_feat(c, y, x, FEAT_MORE); /* Place the player */ Monster_Make.player_place(c, p, y, x); /* go back to using the "complex" RNG */ Random.Rand_quick = false; }
/** * Build a large room with an inner room. * * Possible sub-types: * 1 - An inner room * 2 - An inner room with a small inner room * 3 - An inner room with a pillar or pillars * 4 - An inner room with a checkerboard * 5 - An inner room with four compartments */ static bool build_large(Cave c, int y0, int x0) { throw new NotImplementedException(); //int y, x, y1, x1, y2, x2; //int light = false; ///* Occasional light */ //if (c.depth <= randint1(25)) light = true; ///* Large room */ //y1 = y0 - 4; //y2 = y0 + 4; //x1 = x0 - 11; //x2 = x0 + 11; ///* Generate new room */ //generate_room(c, y1-1, x1-1, y2+1, x2+1, light); ///* Generate outer walls */ //draw_rectangle(c, y1-1, x1-1, y2+1, x2+1, FEAT_WALL_OUTER); ///* Generate inner floors */ //fill_rectangle(c, y1, x1, y2, x2, FEAT_FLOOR); ///* The inner room */ //y1 = y1 + 2; //y2 = y2 - 2; //x1 = x1 + 2; //x2 = x2 - 2; ///* Generate inner walls */ //draw_rectangle(c, y1-1, x1-1, y2+1, x2+1, FEAT_WALL_INNER); ///* Inner room variations */ //switch (randint1(5)) { // /* An inner room */ // case 1: { // /* Open the inner room with a secret door and place a monster */ // generate_hole(c, y1-1, x1-1, y2+1, x2+1, FEAT_SECRET); // vault_monsters(c, y0, x0, c.depth + 2, 1); // break; // } // /* An inner room with a small inner room */ // case 2: { // /* Open the inner room with a secret door */ // generate_hole(c, y1-1, x1-1, y2+1, x2+1, FEAT_SECRET); // /* Place another inner room */ // draw_rectangle(c, y0-1, x0-1, y0+1, x0+1, FEAT_WALL_INNER); // /* Open the inner room with a locked door */ // generate_hole(c, y0-1, x0-1, y0+1, x0+1, FEAT_DOOR_HEAD + randint1(7)); // /* Monsters to guard the treasure */ // vault_monsters(c, y0, x0, c.depth + 2, randint1(3) + 2); // /* Object (80%) or Stairs (20%) */ // if (randint0(100) < 80) // place_object(c, y0, x0, c.depth, false, false, ORIGIN_SPECIAL); // else // place_random_stairs(c, y0, x0); // /* Traps to protect the treasure */ // vault_traps(c, y0, x0, 4, 10, 2 + randint1(3)); // break; // } // /* An inner room with an inner pillar or pillars */ // case 3: { // /* Open the inner room with a secret door */ // generate_hole(c, y1-1, x1-1, y2+1, x2+1, FEAT_SECRET); // /* Inner pillar */ // fill_rectangle(c, y0-1, x0-1, y0+1, x0+1, FEAT_WALL_INNER); // /* Occasionally, two more Large Inner Pillars */ // if (one_in_(2)) { // if (one_in_(2)) { // fill_rectangle(c, y0-1, x0-7, y0+1, x0-5, FEAT_WALL_INNER); // fill_rectangle(c, y0-1, x0+5, y0+1, x0+7, FEAT_WALL_INNER); // } else { // fill_rectangle(c, y0-1, x0-6, y0+1, x0-4, FEAT_WALL_INNER); // fill_rectangle(c, y0-1, x0+4, y0+1, x0+6, FEAT_WALL_INNER); // } // } // /* Occasionally, some Inner rooms */ // if (one_in_(3)) { // /* Inner rectangle */ // draw_rectangle(c, y0-1, x0-5, y0+1, x0+5, FEAT_WALL_INNER); // /* Secret doors (random top/bottom) */ // place_secret_door(c, y0 - 3 + (randint1(2) * 2), x0 - 3); // place_secret_door(c, y0 - 3 + (randint1(2) * 2), x0 + 3); // /* Monsters */ // vault_monsters(c, y0, x0 - 2, c.depth + 2, randint1(2)); // vault_monsters(c, y0, x0 + 2, c.depth + 2, randint1(2)); // /* Objects */ // if (one_in_(3)) // place_object(c, y0, x0 - 2, c.depth, false, false, // ORIGIN_SPECIAL); // if (one_in_(3)) // place_object(c, y0, x0 + 2, c.depth, false, false, // ORIGIN_SPECIAL); // } // break; // } // /* An inner room with a checkerboard */ // case 4: { // /* Open the inner room with a secret door */ // generate_hole(c, y1-1, x1-1, y2+1, x2+1, FEAT_SECRET); // /* Checkerboard */ // for (y = y1; y <= y2; y++) // for (x = x1; x <= x2; x++) // if ((x + y) & 0x01) // cave_set_feat(c, y, x, FEAT_WALL_INNER); // /* Monsters just love mazes. */ // vault_monsters(c, y0, x0 - 5, c.depth + 2, randint1(3)); // vault_monsters(c, y0, x0 + 5, c.depth + 2, randint1(3)); // /* Traps make them entertaining. */ // vault_traps(c, y0, x0 - 3, 2, 8, randint1(3)); // vault_traps(c, y0, x0 + 3, 2, 8, randint1(3)); // /* Mazes should have some treasure too. */ // vault_objects(c, y0, x0, c.depth, 3); // break; // } // /* Four small rooms. */ // case 5: { // /* Inner "cross" */ // generate_plus(c, y1, x1, y2, x2, FEAT_WALL_INNER); // /* Doors into the rooms */ // if (randint0(100) < 50) { // int i = randint1(10); // place_secret_door(c, y1 - 1, x0 - i); // place_secret_door(c, y1 - 1, x0 + i); // place_secret_door(c, y2 + 1, x0 - i); // place_secret_door(c, y2 + 1, x0 + i); // } else { // int i = randint1(3); // place_secret_door(c, y0 + i, x1 - 1); // place_secret_door(c, y0 - i, x1 - 1); // place_secret_door(c, y0 + i, x2 + 1); // place_secret_door(c, y0 - i, x2 + 1); // } // /* Treasure, centered at the center of the cross */ // vault_objects(c, y0, x0, c.depth, 2 + randint1(2)); // /* Gotta have some monsters */ // vault_monsters(c, y0 + 1, x0 - 4, c.depth + 2, randint1(4)); // vault_monsters(c, y0 + 1, x0 + 4, c.depth + 2, randint1(4)); // vault_monsters(c, y0 - 1, x0 - 4, c.depth + 2, randint1(4)); // vault_monsters(c, y0 - 1, x0 + 4, c.depth + 2, randint1(4)); // break; // } //} //return true; }
/** * Places door at y, x position if at least 2 walls found */ static void try_door(Cave c, int y, int x) { Misc.assert(cave_in_bounds(c, y, x)); if (cave_isstrongwall(c, y, x)) return; if (cave_isroom(c, y, x)) return; if (Random.randint0(100) < dun.profile.tun.jct && possible_doorway(c, y, x)) place_random_door(c, y, x); }