429 std::set<int> scoped_room_ids;
430 std::map<int, const core::DungeonRoom*> scoped_rooms_by_id;
431 if (
const auto* dungeon =
434 for (
const auto& dungeon_room : dungeon->rooms) {
438 scoped_room_ids.insert(dungeon_room.id);
439 scoped_rooms_by_id[dungeon_room.id] = &dungeon_room;
442 if (!dungeon_room.floor.empty() &&
450 std::map<std::pair<int, int>,
int> occupied_slots;
451 std::queue<int> to_visit;
452 std::set<std::tuple<int, int, DungeonConnectedLinkType, int, int16_t>>
455 auto track_room_bounds = [&](
int room_id) {
456 const auto& placement = graph.
room_positions[
static_cast<size_t>(room_id)];
463 auto registry_placement_for =
464 [&](
int room_id) -> std::optional<std::pair<int, int>> {
465 const auto it = scoped_rooms_by_id.find(room_id);
466 if (it == scoped_rooms_by_id.end() || !it->second->has_grid_position) {
469 return std::make_pair(it->second->grid_col, it->second->grid_row);
472 auto place_room = [&](
int room_id, std::pair<int, int> desired_placement,
473 bool connected_to_start) {
477 const size_t index =
static_cast<size_t>(room_id);
479 if (connected_to_start &&
487 std::pair<int, int> placement = desired_placement;
488 const auto occupied = occupied_slots.find(placement);
489 if (occupied != occupied_slots.end() && occupied->second != room_id) {
490 placement = FindConnectedTransportPlacement(
491 occupied_slots, desired_placement.first, desired_placement.second);
495 graph.
room_positions[index] = {placement.first, placement.second,
true,
497 occupied_slots[placement] = room_id;
499 if (!connected_to_start) {
506 track_room_bounds(room_id);
510 auto in_dungeon_scope = [&](
int candidate_room_id) {
514 return scoped_room_ids.find(candidate_room_id) != scoped_room_ids.end();
519 registry_placement_for(start_room_id).value_or(std::make_pair(0, 0)),
521 to_visit.push(start_room_id);
523 while (!to_visit.empty()) {
524 const int room_id = to_visit.front();
532 const auto outgoing_diagnostics =
538 for (
const auto& issue : outgoing_diagnostics.staircase_issues) {
541 const auto& outgoing_links = outgoing_diagnostics.links;
543 for (
const auto& link : outgoing_links) {
552 if (!in_dungeon_scope(link.to_room_id)) {
553 if (seen_links.insert(MakeConnectedLinkKey(link)).second) {
563 if (seen_links.insert(MakeConnectedLinkKey(link)).second) {
564 graph.
links.push_back(link);
567 if (!graph.
room_mask[
static_cast<size_t>(link.to_room_id)]) {
568 const auto& source_placement =
570 const std::pair<int, int> placement =
571 registry_placement_for(link.to_room_id)
573 ? FindConnectedDoorPlacement(
574 occupied_slots, source_placement.col,
575 source_placement.row, link.direction)
576 : FindConnectedTransportPlacement(
577 occupied_slots, source_placement.col,
578 source_placement.row));
579 place_room(link.to_room_id, placement,
true);
580 to_visit.push(link.to_room_id);
590 const auto start_placement =
592 for (
int room_id : scoped_room_ids) {
593 if (graph.
room_mask[
static_cast<size_t>(room_id)]) {
602 const std::pair<int, int> placement =
603 registry_placement_for(room_id).value_or(
604 FindConnectedTransportPlacement(
605 occupied_slots, start_placement.col, start_placement.row));
606 place_room(room_id, placement,
false);