static bool chimney_up_two_levels(struct digger *digger) { struct area *passage = digger_dig_passage(digger, 1, wall_type_none); if (!passage) return false; passage->features |= area_features_chimney_up; digger_move_backward(digger, 1); struct tile *tile = generator_tile_at(digger->generator, digger->point); tile->features |= tile_features_chimney_up; struct digger *digger_up_1 = generator_copy_digger(digger->generator, digger); digger_move_forward(digger, 1); digger_ascend(digger_up_1, 1); if (digger_up_1->point.z < generator_min_level(digger->generator)) { generator_delete_digger(digger_up_1->generator, digger_up_1); return true; } // TODO: random direction? // TODO: random passage/room/chamber? // TODO: add chimney to existing area? passage = digger_dig_passage(digger_up_1, 1, wall_type_solid); if (!passage) return false; passage->features |= area_features_chimney_down | area_features_chimney_up; digger_move_backward(digger_up_1, 1); tile = generator_tile_at(digger_up_1->generator, digger_up_1->point); tile->features |= tile_features_chimney_down | tile_features_chimney_up; struct digger *digger_up_2 = generator_copy_digger(digger_up_1->generator, digger_up_1); digger_move_forward(digger_up_1, 1); digger_ascend(digger_up_2, 1); if (digger_up_2->point.z < generator_min_level(digger->generator)) { generator_delete_digger(digger_up_2->generator, digger_up_2); return true; } // TODO: random direction? // TODO: random passage/room/chamber? // TODO: add chimney to existing area? passage = digger_dig_passage(digger_up_2, 1, wall_type_solid); if (!passage) return false; passage->features |= area_features_chimney_up; digger_move_backward(digger_up_2, 1); tile = generator_tile_at(digger_up_2->generator, digger_up_2->point); tile->features |= tile_features_chimney_down; digger_move_forward(digger_up_2, 1); return true; }
static void check_for_chute_down_one_level(struct digger *digger, struct area *area) { if (digger->point.z == generator_max_level(digger->generator)) return; int score = roll("1d6", digger->generator->rnd); if (score == 1) { area->features |= area_features_chute_entrance; struct digger *chute_digger = generator_copy_digger(digger->generator, digger); digger_move_backward(chute_digger, 1); struct tile *tile = generator_tile_at(chute_digger->generator, chute_digger->point); tile->features |= tile_features_chute_entrance; digger_descend(chute_digger, 1); // TODO: random direction? // TODO: random passage/room/chamber? // TODO: add chute to existing area struct area *passage = digger_dig_passage(chute_digger, 1, wall_type_solid); if (passage) { passage->features |= area_features_chute_exit; digger_move_backward(chute_digger, 1); tile = generator_tile_at(chute_digger->generator, chute_digger->point); tile->features |= tile_features_chute_exit; digger_move_forward(chute_digger, 1); } else { generator_delete_digger(chute_digger->generator, chute_digger); } } }
static void generator_add_digger_test(void) { struct dungeon *dungeon = dungeon_alloc(); struct dungeon_options *dungeon_options = dungeon_options_alloc_default(); struct generator *generator = generator_alloc(dungeon, global_rnd, dungeon_options, NULL, NULL); assert(0 == generator->diggers_count); struct digger *digger1 = generator_add_digger(generator, point_make(1, 1, 1), direction_north); assert(1 == generator->diggers_count); generator_delete_digger(generator, digger1); assert(0 == generator->diggers_count); digger1 = generator_add_digger(generator, point_make(1, 1, 1), direction_north); assert(1 == generator->diggers_count); struct digger *digger2 = generator_add_digger(generator, point_make(2, 2, 2), direction_north); assert(2 == generator->diggers_count); struct digger *digger3 = generator_add_digger(generator, point_make(3, 3, 3), direction_north); assert(3 == generator->diggers_count); generator_delete_digger(generator, digger2); assert(2 == generator->diggers_count); assert(digger1 == generator->diggers[0]); assert(digger3 == generator->diggers[1]); generator_delete_digger(generator, digger1); assert(1 == generator->diggers_count); assert(digger3 == generator->diggers[0]); generator_free(generator); dungeon_options_free(dungeon_options); dungeon_free(dungeon); }
static bool dead_end(struct digger *digger) { digger_move_backward(digger, 1); check_wall_for_secret_door(digger->generator, digger->point, digger->direction); check_wall_for_secret_door(digger->generator, digger->point, direction_90_degrees_left(digger->direction)); check_wall_for_secret_door(digger->generator, digger->point, direction_90_degrees_right(digger->direction)); generator_delete_digger(digger->generator, digger); return true; }
static void check_wall_for_secret_door(struct generator *generator, struct point point, enum direction direction) { struct tile *inside_tile = generator_tile_at(generator, point); struct tile *outside_tile = generator_tile_at(generator, point_move(point, 1, direction)); switch (direction) { case direction_north: if (wall_type_solid != outside_tile->walls.south) return; break; case direction_south: if (wall_type_solid != inside_tile->walls.south) return; break; case direction_east: if (wall_type_solid != outside_tile->walls.west) return; break; case direction_west: if (wall_type_solid != inside_tile->walls.west) return; break; default: fail("Unrecognized direction %i", direction); break; } int score = roll("1d4", generator->rnd); if (score == 1) { if (tile_type_empty == outside_tile->type) { generator_set_wall(generator, inside_tile->point, direction, wall_type_secret_door); } else { struct digger *door_digger = generator_add_digger(generator, point_move(point, 1, direction), direction); if (!space_beyond_door(door_digger, wall_type_secret_door, false)) { generator_delete_digger(generator, door_digger); } } } }
static bool chambers(struct digger *digger, enum wall_type entrance_type) { int length = 0; int width = 0; struct area *chamber = NULL; int score = roll("1d20", digger->generator->rnd); if (score <= 2) { // square 20x20 length = 2; width = 2; } else if (score <= 4) { // square 20x20 length = 2; width = 2; } else if (score <= 6) { // square 30x30 length = 3; width = 3; } else if (score <= 8) { // square 40x40 length = 4; width = 4; } else if (score <= 10) { // rectangular 20x30 length = 2; width = 3; } else if (score <= 13) { // rectangular 20x30 length = 2; width = 3; } else if (score <= 15) { // rectangular 30x50 length = 3; width = 5; } else if (score <= 17) { // rectangular 40x60 length = 4; width = 6; } else { // unusual shape and size return false; } if (length != width) { int orientation = rnd_next_uniform_value(digger->generator->rnd, 2); if (orientation) swap(&length, &width); } int max_left_offsets_count = max(length, width); int left_offsets[max_left_offsets_count]; fill_shuffled(digger->generator->rnd, left_offsets, width); for (int i = 0; i < width; ++i) { chamber = digger_dig_chamber(digger, length, width, left_offsets[i], entrance_type); if (chamber) break; } if (!chamber && length != width) { swap(&length, &width); fill_shuffled(digger->generator->rnd, left_offsets, width); for (int i = 0; i < width; ++i) { chamber = digger_dig_chamber(digger, length, width, left_offsets[i], entrance_type); if (chamber) break; } } if (!chamber) return false; // TODO: try smaller chambers? bool check_for_secret_doors = false; int door_count = 0; int passage_count = 0; number_of_exits(digger->generator->rnd, chamber, &door_count, &passage_count, &check_for_secret_doors); for (int i = 0; i < door_count; ++i) { // TODO: don't fail if no possible exit struct digger *exit_digger = exit_location(digger, chamber); if (!exit_digger) return false; if (!space_beyond_door(exit_digger, wall_type_door, false)) return false; } for (int i = 0; i < passage_count; ++i) { // TODO: don't fail if no possible exit struct digger *exit_digger = exit_location(digger, chamber); if (!exit_digger) return false; // TODO: check exit direction if (!digger_dig_passage(exit_digger, 3, wall_type_none)) return false; } if (check_for_secret_doors) { check_area_for_secret_doors(digger->generator, chamber); } generator_delete_digger(digger->generator, digger); return true; }