Beispiel #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;
}
Beispiel #2
0
/* WadArchive::findLast
 * Returns the last entry matching the search criteria in [options],
 * or NULL if no matching entry was found
 *******************************************************************/
ArchiveEntry* WadArchive::findLast(search_options_t& options)
{
	// Init search variables
	ArchiveEntry* start = getEntry(numEntries()-1);
	ArchiveEntry* end = NULL;
	options.match_name = options.match_name.Lower();

	// "graphics" namespace is the global namespace in a wad
	if (options.match_namespace == "graphics")
		options.match_namespace = "";

	// "global" namespace has no name, by the way
	if (options.match_namespace == "global")
		options.match_namespace = "";

	// Check for namespace to search
	if (!options.match_namespace.IsEmpty())
	{
		// Find matching namespace
		bool ns_found = false;
		for (unsigned a = 0; a < namespaces.size(); a++)
		{
			if (namespaces[a].name == options.match_namespace)
			{
				start = namespaces[a].end->prevEntry();
				end = namespaces[a].start;
				ns_found = true;
				break;
			}
		}

		// Return none if namespace not found
		if (!ns_found)
			return NULL;
	}

	// Begin search
	ArchiveEntry* entry = start;
	while (entry != end)
	{
		// Check type
		if (options.match_type)
		{
			if (entry->getType() == EntryType::unknownType())
			{
				if (!options.match_type->isThisType(entry))
				{
					entry = entry->prevEntry();
					continue;
				}
			}
			else if (options.match_type != entry->getType())
			{
				entry = entry->prevEntry();
				continue;
			}
		}

		// Check name
		if (!options.match_name.IsEmpty())
		{
			if (!options.match_name.Matches(entry->getName().Lower()))
			{
				entry = entry->prevEntry();
				continue;
			}
		}

		// Entry passed all checks so far, so we found a match
		return entry;
	}

	// No match found
	return NULL;
}
Beispiel #3
0
/* WadArchive::getMapInfo
 * Returns the mapdesc_t information about the map beginning at
 * [maphead]. If [maphead] is not really a map header entry, an
 * invalid mapdesc_t will be returned (mapdesc_t::head == NULL)
 *******************************************************************/
Archive::mapdesc_t WadArchive::getMapInfo(ArchiveEntry* maphead)
{
	mapdesc_t map;

	if (!maphead)
		return map;

	// Check for embedded wads (e.g., Doom 64 maps)
	if (maphead->getType()->getFormat() == "archive_wad")
	{
		map.archive = true;
		map.head = maphead;
		map.end = maphead;
		map.name = maphead->getName();
		return map;
	}

	// Check for UDMF format map
	if (S_CMPNOCASE(maphead->nextEntry()->getName(), "TEXTMAP"))
	{
		// Get map info
		map.head = maphead;
		map.name = maphead->getName();
		map.format = MAP_UDMF;

		// All entries until we find ENDMAP
		ArchiveEntry* entry = maphead->nextEntry();
		while (true)
		{
			if (!entry || S_CMPNOCASE(entry->getName(), "ENDMAP"))
				break;

			// Check for unknown map lumps
			bool known = false;
			for (unsigned a = 0; a < NUMMAPLUMPS; a++)
			{
				if (S_CMPNOCASE(entry->getName(), map_lumps[a]))
				{
					known = true;
					a = NUMMAPLUMPS;
				}
			}
			if (!known)
				map.unk.push_back(entry);

			// Next entry
			entry = entry->nextEntry();
		}

		// If we got to the end before we found ENDMAP, something is wrong
		if (!entry)
			return mapdesc_t();

		// Set end entry
		map.end = entry;

		return map;
	}

	// Check for doom/hexen format map
	uint8_t existing_map_lumps[NUMMAPLUMPS];
	memset(existing_map_lumps, 0, NUMMAPLUMPS);
	ArchiveEntry* entry = maphead->nextEntry();
	while (entry)
	{
		// Check that the entry is a valid map-related entry
		bool mapentry = false;
		for (unsigned a = 0; a < NUMMAPLUMPS; a++)
		{
			if (S_CMPNOCASE(entry->getName(), map_lumps[a]))
			{
				mapentry = true;
				existing_map_lumps[a] = 1;
				break;
			}
			else if (a == LUMP_GL_HEADER)
			{
				string name = maphead->getName(true);
				name.Prepend("GL_");
				if (S_CMPNOCASE(entry->getName(), name))
				{
					mapentry = true;
					existing_map_lumps[a] = 1;
					break;
				}
			}
		}

		// If it wasn't a map entry, exit this loop
		if (!mapentry)
		{
			entry = entry->prevEntry();
			break;
		}

		// If we've reached the end of the archive, exit this loop
		if (!entry->nextEntry())
			break;

		// Go to next entry
		entry = entry->nextEntry();
	}

	// Check for the required map entries
	for (unsigned a = 0; a < 5; a++)
	{
		if (existing_map_lumps[a] == 0)
			return mapdesc_t();
	}

	// Setup map info
	map.head = maphead;
	map.end = entry;
	map.name = maphead->getName();

	// If BEHAVIOR lump exists, it's a hexen format map
	if (existing_map_lumps[LUMP_BEHAVIOR])
		map.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])
		map.format = MAP_DOOM64;
	// Otherwise it's doom format
	else
		map.format = MAP_DOOM;

	return map;
}
Beispiel #4
0
/* MapEditorWindow::saveMap
 * Saves the current map to its archive, or opens the 'save as'
 * dialog if it doesn't currently belong to one
 *******************************************************************/
bool MapEditorWindow::saveMap()
{
	// Check for newly created map
	if (!mdesc_current.head)
		return saveMapAs();

	// Write map to temp wad
	WadArchive* wad = writeMap();
	if (!wad)
		return false;

	// Check for map archive
	Archive* tempwad = NULL;
	Archive::mapdesc_t map = mdesc_current;
	if (mdesc_current.archive && mdesc_current.head)
	{
		tempwad = new WadArchive();
		tempwad->open(mdesc_current.head);
		vector<Archive::mapdesc_t> amaps = tempwad->detectMaps();
		if (amaps.size() > 0)
			map = amaps[0];
		else
			return false;
	}

	// Unlock current map entries
	lockMapEntries(false);

	// Delete current map entries
	ArchiveEntry* entry = map.end;
	Archive* archive = map.head->getParent();
	while (entry && entry != map.head)
	{
		ArchiveEntry* prev = entry->prevEntry();
		archive->removeEntry(entry);
		entry = prev;
	}

	// Create backup
	if (!backup_manager->writeBackup(map_data, map.head->getTopParent()->getFilename(false), map.head->getName(true)))
		LOG_MESSAGE(1, "Warning: Failed to backup map data");

	// Add new map entries
	for (unsigned a = 1; a < wad->numEntries(); a++)
		entry = archive->addEntry(wad->getEntry(a), archive->entryIndex(map.head) + a, NULL, true);

	// Clean up
	delete wad;
	if (tempwad)
	{
		tempwad->save();
		delete tempwad;
	}
	else
	{
		// Update map description
		mdesc_current.end = entry;
	}

	// Finish
	lockMapEntries();
	editor.getMap().setOpenedTime();

	return true;
}