/* WadArchive::detectMaps * Searches for any maps in the wad and adds them to the map list *******************************************************************/ vector<Archive::mapdesc_t> WadArchive::detectMaps() { vector<mapdesc_t> maps; // Go through all lumps ArchiveEntry* entry = getEntry(0); bool lastentryismapentry = false; while (entry) { // UDMF format map check ******************************************************** // Check for UDMF format map lump (TEXTMAP lump) if (entry->getName() == "TEXTMAP" && entry->prevEntry()) { // Get map info mapdesc_t md = getMapInfo(entry->prevEntry()); // Add to map list if (md.head != NULL) { entry = md.end; maps.push_back(md); } // Current index is ENDMAP, we don't want to check for a doom/hexen format // map so just go to the next index and continue the loop entry = entry->nextEntry(); continue; } // Doom/Hexen format map check ************************************************** // TODO maybe get rid of code duplication by calling getMapInfo() here too? // Array to keep track of what doom/hexen map lumps have been found uint8_t existing_map_lumps[NUMMAPLUMPS]; memset(existing_map_lumps, 0, NUMMAPLUMPS); // Check if the current lump is a doom/hexen map lump bool maplump_found = false; for (int a = 0; a < 5; a++) { // Compare with all base map lump names if (S_CMP(entry->getName(), map_lumps[a])) { maplump_found = true; existing_map_lumps[a] = 1; break; } } // If we've found what might be a map if (maplump_found && entry->prevEntry()) { // Save map header entry ArchiveEntry* header_entry = entry->prevEntry(); // Check off map lumps until we find a non-map lump bool done = false; while (!done) { // Loop will end if no map lump is found done = true; // Compare with all map lump names for (int a = 0; a < NUMMAPLUMPS; a++) { // Compare with all base map lump names if (S_CMP(entry->getName(), map_lumps[a])) { existing_map_lumps[a] = 1; done = false; break; } } // If we're at the end of the wad, exit the loop if (!entry->nextEntry()) { lastentryismapentry = true; break; } // Go to next lump if there is one if (!lastentryismapentry) entry = entry->nextEntry(); } // Go back to the lump just after the last map lump found, but only if we actually moved if (!lastentryismapentry) entry = entry->prevEntry(); // Check that we have all the required map lumps: VERTEXES, LINEDEFS, SIDEDEFS, THINGS & SECTORS if (!memchr(existing_map_lumps, 0, 5)) { // Get map info mapdesc_t md; md.head = header_entry; // Header lump md.name = header_entry->getName(); // Map title md.end = lastentryismapentry ? // End lump entry : entry->prevEntry(); // If BEHAVIOR lump exists, it's a hexen format map if (existing_map_lumps[LUMP_BEHAVIOR]) md.format = MAP_HEXEN; // If LEAFS, LIGHTS and MACROS exist, it's a doom 64 format map else if (existing_map_lumps[LUMP_LEAFS] && existing_map_lumps[LUMP_LIGHTS] && existing_map_lumps[LUMP_MACROS]) md.format = MAP_DOOM64; // Otherwise it's doom format else md.format = MAP_DOOM; // Add map info to the maps list maps.push_back(md); } } // Embedded WAD check (for Doom 64) if (entry->getType()->getFormat() == "archive_wad") { // Detect map format (probably kinda slow but whatever, no better way to do it really) Archive* tempwad = new WadArchive(); tempwad->open(entry); vector<mapdesc_t> emaps = tempwad->detectMaps(); if (emaps.size() > 0) { mapdesc_t md; md.head = entry; md.end = entry; md.archive = true; md.name = entry->getName(true).Upper(); md.format = emaps[0].format; maps.push_back(md); } delete tempwad; entry->unlock(); } // Not a UDMF or Doom/Hexen map lump, go to next lump entry = entry->nextEntry(); } // Set all map header entries to ETYPE_MAP type for (size_t a = 0; a < maps.size(); a++) if (!maps[a].archive) maps[a].head->setType(EntryType::mapMarkerType()); // Update entry map format hints for (unsigned a = 0; a < maps.size(); a++) { string format; if (maps[a].format == MAP_DOOM) format = "doom"; else if (maps[a].format == MAP_DOOM64) format = "doom64"; else if (maps[a].format == MAP_HEXEN) format = "hexen"; else format = "udmf"; ArchiveEntry* entry = maps[a].head; while (entry && entry != maps[a].end->nextEntry()) { entry->exProp("MapFormat") = format; entry = entry->nextEntry(); } } return maps; }