89 auto dungeon_id_opt = parser.
GetString(
"dungeon");
90 bool list_only = parser.
HasFlag(
"list");
92 int dungeon_filter = -1;
93 if (dungeon_id_opt.has_value()) {
94 if (!ParseHexString(dungeon_id_opt.value(), &dungeon_filter)) {
95 return absl::InvalidArgumentError(
96 "Invalid dungeon ID format. Must be hex (e.g., 0x02).");
101 std::map<int, DungeonInfo> dungeons;
104 for (
int i = 0; i < kNumberOfDungeons; ++i) {
107 info.name = GetDungeonName(i);
110 info.start_room = rom->
data()[kDungeonsStartRooms + i];
113 uint16_t boss_room_addr = kDungeonsBossRooms + (i * 2);
115 rom->
data()[boss_room_addr] | (rom->
data()[boss_room_addr + 1] << 8);
118 if (info.boss_room == 0xFFFF) {
126 std::map<int, int> room_to_dungeon;
127 for (
int entrance_id = 0; entrance_id < kNumberOfEntrances; ++entrance_id) {
133 int room_id = entrance.
room_;
136 room_to_dungeon[room_id] = dungeon_id;
139 if (dungeons.find(dungeon_id) == dungeons.end()) {
142 info.id = dungeon_id;
143 info.name = GetDungeonName(dungeon_id);
144 info.start_room = -1;
146 dungeons[dungeon_id] = info;
148 dungeons[dungeon_id].rooms.insert(room_id);
155 if (!spawn_or.ok()) {
156 return spawn_or.status();
158 const auto& spawn = spawn_or.value();
160 int dungeon_id = spawn.dungeon_id;
161 int room_id = spawn.room_id;
163 room_to_dungeon[room_id] = dungeon_id;
165 if (dungeons.find(dungeon_id) != dungeons.end()) {
166 dungeons[dungeon_id].rooms.insert(room_id);
171 std::set<int> unassigned_rooms;
173 if (room_to_dungeon.find(room_id) == room_to_dungeon.end()) {
174 unassigned_rooms.insert(room_id);
184 for (
const auto& [
id, info] : dungeons) {
185 if (dungeon_filter >= 0 &&
id != dungeon_filter) {
189 formatter.
AddField(
"id", absl::StrFormat(
"0x%02X",
id));
190 formatter.
AddField(
"name", info.name);
191 formatter.
AddField(
"room_count",
static_cast<int>(info.rooms.size()));
198 for (
const auto& [
id, info] : dungeons) {
199 if (dungeon_filter >= 0 &&
id != dungeon_filter) {
204 if (info.rooms.empty() && dungeon_filter < 0) {
209 formatter.
AddField(
"id", absl::StrFormat(
"0x%02X",
id));
210 formatter.
AddField(
"name", info.name);
212 if (info.start_room >= 0) {
214 absl::StrFormat(
"0x%02X", info.start_room));
216 formatter.
AddField(
"start_room",
"null");
219 if (info.boss_room >= 0) {
221 absl::StrFormat(
"0x%02X", info.boss_room));
223 formatter.
AddField(
"boss_room",
"null");
228 for (
int room_id : info.rooms) {
230 formatter.
AddField(
"id", absl::StrFormat(
"0x%02X", room_id));
232 if (room_id >= 0 && room_id < 297) {
235 formatter.
AddField(
"name", absl::StrFormat(
"Room 0x%02X", room_id));
246 if (dungeon_filter < 0 && !unassigned_rooms.empty()) {
248 for (
int room_id : unassigned_rooms) {
249 formatter.
AddArrayItem(absl::StrFormat(
"0x%02X", room_id));
257 int total_assigned = 0;
258 for (
const auto& [
id, info] : dungeons) {
259 total_assigned +=
static_cast<int>(info.rooms.size());
261 formatter.
AddField(
"total_dungeons",
static_cast<int>(dungeons.size()));
262 formatter.
AddField(
"assigned_rooms", total_assigned);
263 formatter.
AddField(
"unassigned_rooms",
264 static_cast<int>(unassigned_rooms.size()));
269 return absl::OkStatus();