Esempio n. 1
0
/* 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;
}